Jump to content
Fivewin Brasil

Jorge Andrade

Membros
  • Posts

    843
  • Joined

  • Last visited

  • Days Won

    77

Posts posted by Jorge Andrade

  1.  

    Bom dia amigos...

    Este é um tema, que acredito perturbar a maioria de nós.

    Por sermos "Lobos Solitários", sem querer, acabamos por colocar a saúde financeira dos nossos familiares em risco, pois não temos perspectivas de continuidade do nosso trabalho ao partimos.

    Poucos conseguiram montar uma estrutura que dê essa tranquilidade, porém, sem a nossa presença, nossas famílias dificilmente ficarão totalmente protegidas.

    Diante disto, só nos resta uma pergunta:

    O que fazer ?

    Há alguns anos, o nosso grande amigo Vagner Wirts defendia a criação de um Grupo de Profissionais que seriam parceiros no apoio técnico e na continuidade dos nossos trabalhos.

    Na época, até tentamos nos unir, porém sem sucesso.

    Hoje acredito que este tema deva ser novamente abordado, pois se passaram vários anos sem nenhuma mudança nestas condições e estamos caminhando para o mesmo fim.

    Com o objetivo de nos conhecer melhor e formarmos parcerias visando o nosso futuro e de nossos familiares, gostaria de convidar os amigos para divulgarem suas respectivas áreas de atuação e assim alinhar aqueles que terão condições técnicas de nos substituir em caso de ficarmos impossibilitados de trabalhar.

    No meu caso, seria isso:

    Área de Atuação : Chão de Fábrica -> Fabricação em Série, Fabricação por Encomenda, Usinagem, Ferramentaria, Caldeiraria, Vendas de Produtos e Serviços.

    Região: Jundiaí-SP.,  Várzea Paulista-SP, Campo Limpo Paulista-SP, Valinhos-SP, Vinhedo-SP, Itatiba-SP e Bragança Paulista-SP.

    Módulos do Sistema: Gestão de Clientes, Gestão de Fornecedores, Gestão de Colaboradores, Gestão de Máquinas e Equipamentos(Depreciações), Gestão de Encargos Sociais sobre Folha de Pagamentos, Plano de Contas Financeira, Plano de Centros de Custos, Mapa de Custos Operacionais, Gestão Fiscal, Sped Fiscal, Logistica (Compras e Movimentações de Entradas), Gestão do Estoque, Ponto de Vendas, Ordem de Serviços, PCP, Metrologia, Apontamento de Mão de Obra e Máquinas, Gestão de Notas Fiscais Eletrônicas, Gestão Financeira e Relatórios Gerenciais.

    Acredito que os amigos que trabalharem na mesma área que a minha, entenderão as funcionalidades básicas do meu Sistema e já terão 50% de capacidade de me substituir no caso de haver necessidade.

    Não sei se todos concordam, más acho que seria uma saída.

    Por favor, opinem.

    Abraços.

     

     

     

     

     

     

    Bela atitude Valdir, melhor a gente realmente ir divulgando. No meu caso, sou meio eclético. Indústria de confecções, varejo de confecções, varejo produtos de limpeza, indústria de pranchas de surf, distribuições de vacinas humanas, e varejo em geral. Sobre os locais de atuação: São Paulo, capital e interior, Belo Horizonte, Goiânia e Salvador.

  2. Aê galera! Tô gostando de ver as manifestações de vcs. Vamos esperar o levantamento das informações pelo Mário Guará do grupo Windev e também do nosso amigo Marcelo (Marca), por ser da região dele, o contato direto com os pais será mais fácil e também com os clientes, que  é extremamente necessário pra certificar que eles não estarão desamparados, e haverá continuidade no sistema.

    Acredito que após essas confirmações e até por ideia de um colega aqui do grupo, alguém assumir de vez e ter participação nos recebimentos, desde de que não prejudique e comprometa demais os ganhos das outras partes (Pais e  esposa e filho).

    Agradeço as boas  intenções de todos.

     

    []s,

     

  3.  

    O ideal seria algum assumir os clientes, negociando com a familia... De graça, por mais boa vontade que a pessoa tem, ela vai ajudar por um tempo, o sistema vai ficar meia boca e logo o cliente troca e todos perdem.

    Seria importante alguem da região que tem empresa negociar com a familia essa situação, remunerar a familia em uma espécie de royalties pelo sistema e atender os clientes resolvendo os problemas e fazendo melhorias.

    É apenas minha sugestão e até repetindo o que já foi dito por vc tb Jorge.

    Aqui em minha região aconteceu algo parecido a um tempo atrás. O cara que me ensinou a programar faleceu e eu ajudei a esposa dele a atender os clientes inicialmente, no meu caso foi sem remuneração pois já era amigo da familia. Mas como falei, ela conseguiu atender por um tempo pois melhorias não eram feitas, apenas resolvia os problemas conforme iam acontecendo. Eu a ajudei na parte de clipper e um outro rapaz na parte do VFP pois ele tinha sistema em ambas as linguagens na época.

     

     

     

    Toda sugestão é bem vinda. O Marcelo deverá contatar o Mário e a família e assim, achar uma solução que atenda bem a família e a quem vai ajudar.

    []s,

     

  4.  

    Que situação terrivel... Ninguem gosta de pensar nisso mas é importante que todos tenham um seguro de vida para pelo menos dar um respeito financeiro a familia em um momento como esse. Não podemos partir e deixar nossa familia desestruturada.

    Portanto fica a dica, um seguro de vida que não é nada caro e que pelo menos em um momento dificil como a morte não vai deixar a familia desamparada logo de cara.

    Sou do interior de SP, não sei como poderia ajudar mas se tiver algo me chamem no skype live:eduardo_107

    Que Deus conforte a familia

     

    Edú como frisei, se a gente ajudar de alguma forma tecnicamente, e tentar manter os sistemas dele funcionando, acredito que será uma grande ajuda.

  5.  

    Jorge. Sou de Petrópolis, região serrana do Rio. Eu tenho o celular do Alexandre e tentei contato algumas vezes sem sucesso.

    Me disponho a ajudar nesta parte técnica sendo que não tenho nenhum contato com a família. Se quiser me chame no Skype marcelomarca pra ver se conseguimos de alguma maneira ajudar

    Amigo, já te adicionei no skype e aqueles que quiserem participar de alguma forma é só me incluir fnlinf ou fnlinf@hotmail.com.

     

    []s,

  6. Pessoal

    Boa noite

     

    Como vcs sabem, muitos trabalham sozinho e as vezes nem a família tem acesso aos nossos códigos para alguém não dar continuidade ao pequeno legado que deixamos. Não foi diferente para o nosso amigo Alexandre e as vezes a família depende exclusivamente ou boa parte dos recursos oriundos no nosso trabalho.

    Essa semana no grupo de Windev, tivemos uma notícia que a esposa dele está passando por necessidades e com isso já pensaram em fazer uma força tarefa para ajudar financeiramente.

    Após o seu falecimento, tentei contato com os pais dele e com a sua esposa sem sucesso, porém, essa semana consegui falar com eles e estes me passaram uma situação complicada, embora sem entrar no âmbito familiar, este me informou que um colega nosso (Mário Guará) do grupo de Windev entrou em  contato, esteve na casa deles, onde ele teve acesso as informações relativas aos projetos Windev.

    Conversei com o Mário que me relatou a situação. Além da dificuldades em contatar os clientes para que ele dê continuidade aos projetos e os pais e a esposa recebam as mensalidades,  porém o Mário não tem conhecimento de Fivewin e para tal, irá necessitar da ajuda dos colegas que estiverem interessados em contribuir tecnicamente.

    Seria interessante se algum colega do grupo que mora no RJ, de preferência em Nova Iguaçu (Onde ele residia), para facilitar contatos ou visitas aos clientes, afim de dar esta força para a família.

    Vejam que não estou pedindo para ajudar financeiramente e sim dispor da capacidade técnica profissional em ajudar nos projetos relativos a Fivewin. Aqueles que tiverem tempo e desejarem ajudar, manifestem-se

    []s,

  7.  

    Olá,

    Alguem sabe como no Terminal server nao aparecer a tela desktop do servidor windows server?

    estou precisando que ao fazer o logon no windows server com o TS,

    ele abra o sistema, e nao mostre a tela desktop do servidor,

    e após sair do sistema ele feche o terminal server,

    ou seja o TS vai ser so para acessar o sistema.

    Desde já agradeço a quem puder me ajudar

    Narlem

    BH/MG

     

    Se entendi, vc loga o TS, mas a tela da área de trabalho não aparece, bom, isso deve ser pq, na última sessão ficou alguma pendência, mas vc pode começar do zero. Independente se vc utilizar Calls para acesso ou somente os dois acessos padrão. Na sua cpu no (Regedit) registro existe um carinha de nome MSLICENSING, neste registro existe um contador de acesso, e tem duas pastas HARDWAREID e STORE. Delete as duas pastas na sua cpu e tente conectar novamente,  que o contador irá iniciar do zero, isso pode liberar a pendência.

    []s,

  8.  

    Boa tarde pessoal

    Estou com um problema com o update no postgresql, ocorreram poucas vezes este ano, mas causa um grande estrago.

    o cliente altera um cadastro e no momento de salvar o postgresql salva todos os registros da tabela com o mesmo dado

    eu estou usando o postgre 9.5 com sqlrdd, e costumo usar assim:

    clSql  := UPDATE "sup0007" SET ;
                CodEmp = ::avCarrega[1]:cCodEmp ,;
                NomEmp = ::avCarrega[1]:cNomEmp ,;
                FanEmp = ::avCarrega[1]:cFanEmp ,;
                EndEmp = ::avCarrega[1]:cEndEmp ,;
                RedEmp = ::avCarrega[1]:cRedEmp ,;
                NumCep = ::avCarrega[1]:cNumCep ,;
                Bairro = ::avCarrega[1]:cBairro ,;
                TelEmp = ::avCarrega[1]:cTelEmp ,;
                TelEm2 = ::avCarrega[1]:cTelEm2 ,;
                Ativar = clAtivar ,;
                UltUsu = oCarVar:cUser ,;
                UltMod = date()        ,;
                Operad = oCarVar:cUser ,;
                Updated= date()         ;
                WHERE sr_recno = ? 

                  alParam := {::avCarrega[1]:SR_RECNO}
            SR_BeginTransaction()
            
            Try
            
                oSql := SR_GetConnection()
                 
                apCode := SR_SQLParse( clSql, @nErr, @nPos )
                cResu := SR_SQLCodeGen( apCode, alParam, oSql:nSystemID )
                nErr := oSql:Exec( cResu )

    este é um exemplo usando a sqlrdd pra converter o codigo, mas tenho outro caso que uso o comando direto no oSql:Exec sem passar pelo sr_sqlcodegen e também deu o problema.

    este comando acima, gera o comando abaixo para o postgre

    UPDATE 
      "sup0007"
     SET
      "codemp" = E'3000286',
      "nomemp" = E'CONTE COMIGO',
      "fanemp" = E'CONTE',
      "endemp" = E'RUA BEABA,98',
      "redemp" = ' ',
      "numcep" = E'89837-000',
      "bairro" = E'CENTRO',
      "telemp" = E'3999999',
      "telem2" = E'89999427',
      "ativar" = E'FF',
      "ultusu" = E'AUGUSTO',
      "ultmod" = E'2019-10-01',
      "operad" = E'AUGUSTO',
      "updated" = E'2019-10-01' WHERE "sr_recno" = 1595

    Não vejo erro no comando, isto ocorre muitas vezes em todo meu sistema, mas este erro ocorreu poucas vezes.

    Alguém tem ideia do que pode ser? Algo na Tabela, no banco, etc.

    Puts, sem erro fica dificil, mas substitui todos os dados ou cria vários registros iguais?

  9. As Dlls, estão disponíveis para clientes Sac. Para ser cliente Sac, basta se cadastrar no ACBR, pagar uma mensalidade (R$120,00)  e vc poderá baixar tudo o que existe nas áreas de downloads disponíveis para usuários Sac, mas não é obrigado a pagar todos os meses, somente quando vc precisar e querer atualizar, diferentemente de outros que tem que pagar mensalmente e por CNPJ.

    Nada contra, mas sempre preferi ser de certa forma independente e isso não significa que daqui há alguns anos o ACBR não passe a ser taxado também.

    []s,

  10.  

    ola a todos

     

    alguem ja criou o registro E115 do Sped Fiscal e Pis/Cofins, q poderia postar em demo, por favor ?

     

    desde ja agradeco a ajuda: MUITO OBRIGADO !!!

     

    Gilberto

    Giba, este registro é mesmo do contribuições? Qual data e versão do layout?

    Ah! Agora entendi, registro E115 do IPI/ICMS.

    Esse abaixo:

    1) Introdução ao Registro E115:

    Veremos neste capítulo do Guia Prático o layout do Registro E115 do Sped-Fiscal, que tem o objetivo de informar os valores declaratórios relativos ao ICMS, conforme definição da legislação Estadual pertinente.

    Base Legal: Guia Prático da Escrituração Fiscal Digital - EFD-ICMS/IPI da Receita Federal do Brasil (Checado pela Valor Consulting em 19/01/16).

    2) Layout:

    Este Registro tem o objetivo de informar os valores declaratórios relativos ao ICMS, conforme definição da legislação Estadual pertinente. Esses valores são meramente declaratórios e não são computados na apuração do ICMS.

    Campo Descrição Tipo Tam. Dec. Obrig.
    01 REG Texto fixo contendo "E115". C 004 - O
    02 COD_INF_ADIC Código da informação adicional conforme Tabela a ser definida pelas Secretarias da Fazenda (Sefaz). C 008* - O
    03 VL_INF_ADIC Valor referente à informação adicional. N - 02 O
    04 DESCR_COMPL_AJ Descrição complementar do ajuste. C - - OC

    Observações:

    1. Nível hierárquico: 4;
    2. Ocorrência: 1:N;
    3. Coluna Entrada e/ou Saída: O "O" significa que o campo deve ser sempre preenchido (ou apresentado). Já o "OC" significa que o campo deve ser preenchido (ou apresentado) sempre que houver a informação a ser apresentada. Por fim, o "N" significa que o registro não pode ser preenchido (ou apresentado).

    Base Legal: Guia Prático da Escrituração Fiscal Digital - EFD-ICMS/IPI da Receita Federal do Brasil.

    2.1) Observações sobre o preenchimento:

    * Campo 01 (REG): Valor Válido: [E115].

     

    * Campo 02 (COD_INF_ADIC): Preenchimento: o código da informação adicional deve obedecer à Tabela definida pelas Sefazs dos Estados. Caso não haja publicação da referida Tabela, o Registro não deve ser apresentado.

    Base Legal: Guia Prático da Escrituração Fiscal Digital - EFD-ICMS/IPI da Receita Federal do Brasil.

    2.2) Alterações do layout:

    Até a última atualização desta publicação no Portal Valor Consulting, foram processadas as seguintes alterações no layout do Registro E115 da EFD-ICMS/IPI (Sped-Fiscal), conforme Guia Prático EFD-ICMS/IPI publicado no Portal do Sistema Público de Escrituração Digital (Sped). É a Equipe Valor Consulting trazendo o que há de melhor para vocês, nossos estimados leitores.

    Precisou de assessoria e/ou consultoria em EFD-ICMS/IPI, entre em contato com nossa equipe comercial através do nosso Fale Conosco. Faça como outras empresas e profissionais, seja um cliente de valor você também!

    Versão Vigente a partir de Alteração
    Data
    2.0.10 06/2012 01/10/2012 Dispensa de preenchimento dos campos PIS e Cofins em toda a EFD-ICMS/IPI.
    2.0.11 09/2012 10/10/2012 Os contribuintes que entregarem a EFD-Contribuições relativa ao mesmo período de apuração do registro 0000 estão dispensados do preenchimento dos campos referentes às contribuições para PIS/COFINS.
    2.0.11 09/2012 10/10/2012 Inclusão da obrigatoriedade dos registros por perfis.

    Base Legal: Equipe Valor Consulting.

    Informações Adicionais:

    Este material foi escrito no dia 05/12/2013 pela Equipe Técnica da Valor Consulting e está atualizado até a legislação vigente em 09/07/2019 (data da sua última atualização), sujeitando-se, portanto, às mudanças em decorrência das alterações legais.

    Não é permitido a utilização dos materiais publicados pela Valor Consulting para fins comerciais, pois os mesmos estão protegidos por direitos autorais. Também não é permitido copiar os artigos, materias e arquivos do Portal Valor Consulting para outro site, sistema ou banco de dados para fins de divulgação em sites, revistas, jornais, etc de terceiros sem a autorização escrita dos proprietários do Portal Valor Consulting.

    A utilização para fins exclusivamente educacionais é permitida desde que indicada a fonte:

    []s,

  11. Ah! Pensei que vc gerava e tinha todo controle e não do banco, que por sinal não ia deixar de ganhar, pq ele ganha na baixa e na próxima liquidação do novo boleto., embora, se for realmente um novo boleto com outro vencimento, o banco está certo, pq mesmo que vc faça a prorrogação, é feita a baixa e uma nova emissão de boleto.

    []s,

  12.  

    Boa tarde, Pessoal

    Tenho um cliente que gera o boleto do Itau pelo meu sistema e no final do dia mando a remessa para registro

    Tudo funcionando perfeitamente

    Agora o cliente quer fazer a 2 via do boleto pelo sistema 

    Eu percebi que quando vc gera a 2 via pelo site do itau ele gera outro boleto com outra Numeração 

    Alguem poderia me dar alguma dica de como gerar essa 2 via pelo sistema e se tambem tenho que registrar 2 via do boleto.

     

     

    Edú, bom dia

     

    Eu não entendi? Vc não emite o boleto pelo seu sistema? E pq ele não não mantêm o mesmo número?

     

    []s,

  13.  

    Jorge eh que não entendi essa frase. por isso perguntei:

    O ACBr lançará oficialmente amanhã uma biblioteca que pode ser agregada ao sistema sem a necessidade do uso do monitor. Acredito que, com ela, será possível o próprio sistema configurar as pastas dos arquivos e certificado digital que será utilizado por cada empresa sem a necessidade de se instalar vários monitores ACBrs.

    e continuo sem entender

    Te explico amigo. A partir do momento que vc passar a usar as DLL's, não será mais necessário vc ativar o monitor, pq ficará por sua conta enviar os comandos para a dll, então em tempo de execução ou dinamicamente vc invoca/carrega/load na dll e envia os comandos conforme a sua necessidade, como se estivesse enviando para o monitor e ela fizesse parte do seu sistema. 

    Os exemplos acima da dll sat, o Rafael Dias (Acbr) criou um classe em Harbour/Xharbour para facilitar o uso da dll, eu deixei uns exemplos acima de envio de comandos e ele fez um exemplo de geração e envio de uma venda sat,  como se estivesse gerando um arquivo INI para o monitor.

    Se quiser mais informações me chame no skype: fnlinf

     

  14. Classe do Sat:

     

    #include "hbclass.ch"
    #include "error.ch"

    #define DC_CALL_CDECL          0x0010      // __cdecl
    #define DC_CALL_STD            0x0020      // __stdcall

    #ifdef __XHARBOUR__
       #define ACBrLIBSat "ACBrSAT32.dll"
       #define DLL_OSAPI DC_CALL_STD
    #else
       #ifdef __PLATFORM__WINDOWS ///#if defined( __PLATFORM__WINDOWS )
          #define ACBrLIBSat "ACBrSAT32.dll"
          #define DLL_OSAPI DC_CALL_STD
       #else
          #define ACBrLIBSat "ACBrSAT32.dll"

     

     

    A classe da Nfe ainda não tenho.
          #define DLL_OSAPI DC_CALL_STD
       #endif
    #endif

    #define STR_LEN 256

    CREATE CLASS ACBrSat
    HIDDEN:
        VAR hHandle

        METHOD CheckResult(hResult)
        METHOD ProcessResult(buffer, bufferLen)

    VISIBLE:
        METHOD New() CONSTRUCTOR
        METHOD New(eArqConfig, eChaveCrypt) CONSTRUCTOR
        DESTRUCTOR  Destroy

        METHOD Nome
        METHOD Versao

        METHOD ConfigLer(eArqConfig)
        METHOD ConfigGravar(eArqConfig)
        METHOD ConfigLerValor(eSessao, eChave)
        METHOD ConfigGravarValor(eSessao, eChave, eValor)

        METHOD Inicializar
        METHOD DesInicializar

        METHOD AssociarAssinatura(CNPJvalue, assinaturaCNPJs)
        METHOD BloquearSAT()
        METHOD DesbloquearSAT()
        METHOD TrocarCodigoDeAtivacao(codigoDeAtivacaoOuEmergencia, opcao, novoCodigo)
        METHOD ConsultarSAT()
        METHOD ConsultarStatusOperacional()
        METHOD ConsultarNumeroSessao(cNumeroDeSessao)
        METHOD AtualizarSoftwareSAT()
        METHOD ComunicarCertificadoICPBRASIL(certificado)
        METHOD ExtrairLogs(eArquivo)
        METHOD TesteFimAFim(eArquivoXmlVenda)
        METHOD GerarAssinaturaSAT(eCNPJSHW, eCNPJEmitente)

        METHOD CriarCFe(eArquivoIni)
        METHOD CriarEnviarCFe(eArquivoIni)
        METHOD EnviarCFe(eArquivoXml)
        METHOD CancelarCFe(eArquivoXml)

        METHOD ImprimirExtratoVenda(eArqXMLVenda, eNomeImpressora)
        METHOD ImprimirExtratoResumido(eArqXMLVenda, eNomeImpressora)
        METHOD ImprimirExtratoCancelamento(eArqXMLVenda, eArqXMLCancelamento, eNomeImpressora)
        METHOD GerarImpressaoFiscalMFe(eArqXMLVenda)
        METHOD GerarPDFExtratoVenda(eArqXMLVenda, eNomeArquivo)
        METHOD GerarPDFCancelamento(eArqXMLVenda, eArqXMLCancelamento, eNomeArquivo)
        METHOD EnviarEmail(eArqXMLVenda, sPara, sAssunto, eNomeArquivo, sMensagem, sCC, eAnexos)
    END CLASS

    METHOD New(eArqConfig, eChaveCrypt) CLASS ACBrSat
        local hResult, buffer, bufferLen, oErr

        ::hHandle := DllLoad(ACBrLIBSat)
        if ::hHandle = nil
            oErr := ErrorNew()
            oErr:Severity := ES_ERROR        
            oErr:Description := "Erro a carregar a dll [" + ACBrLIBSat + "]"
            Throw(oErr)
        endif
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_Inicializar", hb_StrToUTF8(eArqConfig), hb_StrToUTF8(eChaveCrypt))
        ::CheckResult(hResult)
        RETURN Self

    PROCEDURE Destroy CLASS ACBrSat
        DllCall(::hHandle, DLL_OSAPI, "SAT_Finalizar")
        DllUnload(::hHandle)
        RETURN

    METHOD CheckResult(hResult) CLASS ACBrSat
        local buffer, bufferLen, oErr
        if hResult >= 0
           RETURN nil
        endif    

        bufferLen := STR_LEN
        buffer := Space(bufferLen)

        DllCall(::hHandle, DLL_OSAPI, "SAT_UltimoRetorno", @buffer, @bufferLen)
        if bufferLen > STR_LEN
            buffer := Space(bufferLen)
            DllCall(::hHandle, DLL_OSAPI, "SAT_UltimoRetorno", @buffer, @bufferLen)        
        endif    

        oErr := ErrorNew()
        oErr:Severity := ES_ERROR
        oErr:Description := hb_UTF8ToStr(buffer)
        Throw(oErr)
        RETURN nil

    METHOD ProcessResult(buffer, bufferLen) CLASS ACBrSat
        if bufferLen > STR_LEN
            buffer := Space(bufferLen)
            DllCall(::hHandle, DLL_OSAPI, "SAT_UltimoRetorno", @buffer, @bufferLen)        
        endif
        RETURN buffer

    METHOD Nome CLASS ACBrSat
        local hResult, buffer, bufferLen, ret
        bufferLen := STR_LEN
        buffer := Space(bufferLen)
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_Nome", @buffer, @bufferLen)
        ::CheckResult(hResult)
        RETURN ::ProcessResult(buffer, bufferLen)

    METHOD Versao CLASS ACBrSat
        local hResult, buffer, bufferLen
        bufferLen := STR_LEN
        buffer := Space(bufferLen)
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_Versao", @buffer, @bufferLen)
        ::CheckResult(hResult)
        RETURN ::ProcessResult(buffer, bufferLen)

    METHOD ConfigLer(eArqConfig) CLASS ACBrSat
        local hResult    
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_ConfigLer", hb_StrToUTF8(eArqConfig))
        ::CheckResult(hResult)
        RETURN nil

    METHOD ConfigGravar(eArqConfig) CLASS ACBrSat
            local hResult    
            hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_ConfigGravar", hb_StrToUTF8(eArqConfig))
            ::CheckResult(hResult)
            RETURN nil

    METHOD ConfigLerValor(eSessao, eChave) CLASS ACBrSat
        local hResult, buffer, bufferLen
        bufferLen := STR_LEN
        buffer := Space(bufferLen)   
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_ConfigLerValor", hb_StrToUTF8(eSessao), hb_StrToUTF8(eChave), @buffer, @bufferLen)
        ::CheckResult(hResult)
        RETURN ::ProcessResult(buffer, bufferLen)

    METHOD ConfigGravarValor(eSessao, eChave, eValor) CLASS ACBrSat
        local hResult
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_ConfigGravarValor", hb_StrToUTF8(eSessao), hb_StrToUTF8(eChave), hb_StrToUTF8(eValor))
        ::CheckResult(hResult)
        RETURN nil

    METHOD Inicializar CLASS ACBrSat
        local hResult
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_InicializarSAT")
        ::CheckResult(hResult)
        RETURN nil

    METHOD DesInicializar CLASS ACBrSat
        local hResult
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_DesInicializar")
        ::CheckResult(hResult)
        RETURN nil

    METHOD AssociarAssinatura(CNPJvalue, assinaturaCNPJs) CLASS ACBrSat
        local hResult, buffer, bufferLen
        bufferLen := STR_LEN
        buffer := Space(bufferLen)   
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_AssociarAssinatura", hb_StrToUTF8(CNPJvalue), hb_StrToUTF8(assinaturaCNPJs), @buffer, @bufferLen)
        ::CheckResult(hResult)
        RETURN ::ProcessResult(buffer, bufferLen)

    METHOD BloquearSAT() CLASS ACBrSat
        local hResult, buffer, bufferLen
        bufferLen := STR_LEN
        buffer := Space(bufferLen)   
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_BloquearSAT", @buffer, @bufferLen)
        ::CheckResult(hResult)
        RETURN ::ProcessResult(buffer, bufferLen)

    METHOD DesbloquearSAT() CLASS ACBrSat
        local hResult, buffer, bufferLen
        bufferLen := STR_LEN
        buffer := Space(bufferLen)   
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_DesbloquearSAT", @buffer, @bufferLen)
        ::CheckResult(hResult)
        RETURN ::ProcessResult(buffer, bufferLen)

    METHOD TrocarCodigoDeAtivacao(codigoDeAtivacaoOuEmergencia, opcao, novoCodigo)
        local hResult, buffer, bufferLen
        bufferLen := STR_LEN
        buffer := Space(bufferLen)   
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_TrocarCodigoDeAtivacao", hb_StrToUTF8(codigoDeAtivacaoOuEmergencia), opcao, hb_StrToUTF8(novoCodigo), @buffer, @bufferLen)
        ::CheckResult(hResult)
        RETURN ::ProcessResult(buffer, bufferLen)

    METHOD ConsultarSAT() CLASS ACBrSat
        local hResult, buffer, bufferLen
        bufferLen := STR_LEN
        buffer := Space(bufferLen)   
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_ConsultarSAT", @buffer, @bufferLen)
        ::CheckResult(hResult)
        RETURN ::ProcessResult(buffer, bufferLen)

    METHOD ConsultarStatusOperacional() CLASS ACBrSat
        local hResult, buffer, bufferLen
        bufferLen := STR_LEN
        buffer := Space(bufferLen)   
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_ConsultarStatusOperacional", @buffer, @bufferLen)
        ::CheckResult(hResult)
        RETURN ::ProcessResult(buffer, bufferLen)

    METHOD ConsultarNumeroSessao(cNumeroDeSessao) CLASS ACBrSat
        local hResult, buffer, bufferLen
        bufferLen := STR_LEN
        buffer := Space(bufferLen)   
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_ConsultarNumeroSessao", cNumeroDeSessao, @buffer, @bufferLen)
        ::CheckResult(hResult)
        RETURN ::ProcessResult(buffer, bufferLen)

    METHOD AtualizarSoftwareSAT() CLASS ACBrSat
        local hResult, buffer, bufferLen
        bufferLen := STR_LEN
        buffer := Space(bufferLen)   
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_AtualizarSoftwareSAT", @buffer, @bufferLen)
        ::CheckResult(hResult)
        RETURN ::ProcessResult(buffer, bufferLen)

    METHOD ComunicarCertificadoICPBRASIL(certificado) CLASS ACBrSat
        local hResult, buffer, bufferLen
        bufferLen := STR_LEN
        buffer := Space(bufferLen)   
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_ComunicarCertificadoICPBRASIL", hb_StrToUTF8(certificado), @buffer, @bufferLen)
        ::CheckResult(hResult)
        RETURN ::ProcessResult(buffer, bufferLen)

    METHOD ExtrairLogs(eArquivo) CLASS ACBrSat
        local hResult
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_ExtrairLogs", hb_StrToUTF8(eArquivo))
        ::CheckResult(hResult)
        RETURN nil

    METHOD TesteFimAFim(eArquivoXmlVenda) CLASS ACBrSat
        local hResult, buffer, bufferLen
        bufferLen := STR_LEN
        buffer := Space(bufferLen)   
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_TesteFimAFim", hb_StrToUTF8(eArquivoXmlVenda), @buffer, @bufferLen)
        ::CheckResult(hResult)
        RETURN ::ProcessResult(buffer, bufferLen)

    METHOD GerarAssinaturaSAT(eCNPJSHW, eCNPJEmitente) CLASS ACBrSat
        local hResult, buffer, bufferLen
        bufferLen := STR_LEN
        buffer := Space(bufferLen)   
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_GerarAssinaturaSAT", hb_StrToUTF8(eCNPJSHW), hb_StrToUTF8(eCNPJEmitente), @buffer, @bufferLen)
        ::CheckResult(hResult)
        RETURN ::ProcessResult(buffer, bufferLen)

    METHOD CriarCFe(eArquivoIni) CLASS ACBrSat
        local hResult, buffer, bufferLen
        bufferLen := STR_LEN
        buffer := Space(bufferLen)   
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_CriarCFe", hb_StrToUTF8(eArquivoIni), @buffer, @bufferLen)
        ::CheckResult(hResult)
        RETURN ::ProcessResult(buffer, bufferLen)

    METHOD CriarEnviarCFe(eArquivoIni) CLASS ACBrSat
        local hResult, buffer, bufferLen
        bufferLen := STR_LEN
        buffer := Space(bufferLen)   
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_CriarEnviarCFe", hb_StrToUTF8(eArquivoIni), @buffer, @bufferLen)
        ::CheckResult(hResult)
        RETURN ::ProcessResult(buffer, bufferLen)

    METHOD EnviarCFe(eArquivoXml) CLASS ACBrSat
        local hResult, buffer, bufferLen
        bufferLen := STR_LEN
        buffer := Space(bufferLen)   
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_EnviarCFe", hb_StrToUTF8(eArquivoXml), @buffer, @bufferLen)
        ::CheckResult(hResult)
        RETURN ::ProcessResult(buffer, bufferLen)

    METHOD CancelarCFe(eArquivoXml) CLASS ACBrSat
        local hResult, buffer, bufferLen
        bufferLen := STR_LEN
        buffer := Space(bufferLen)   
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_CancelarCFe", hb_StrToUTF8(eArquivoXml), @buffer, @bufferLen)
        ::CheckResult(hResult)
        RETURN ::ProcessResult(buffer, bufferLen)

    METHOD ImprimirExtratoVenda(eArqXMLVenda, eNomeImpressora) CLASS ACBrSat
        local hResult
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_ImprimirExtratoVenda", hb_StrToUTF8(eArqXMLVenda), hb_StrToUTF8(eNomeImpressora))
        ::CheckResult(hResult)
        RETURN nil

    METHOD ImprimirExtratoResumido(eArqXMLVenda, eNomeImpressora) CLASS ACBrSat
        local hResult
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_ImprimirExtratoResumido", hb_StrToUTF8(eArqXMLVenda), hb_StrToUTF8(eNomeImpressora))
        ::CheckResult(hResult)
        RETURN nil

    METHOD ImprimirExtratoCancelamento(eArqXMLVenda, eArqXMLCancelamento, eNomeImpressora) CLASS ACBrSat
        local hResult
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_ImprimirExtratoCancelamento", hb_StrToUTF8(eArqXMLVenda), hb_StrToUTF8(eArqXMLCancelamento), hb_StrToUTF8(eNomeImpressora))
        ::CheckResult(hResult)
        RETURN nil

    METHOD GerarImpressaoFiscalMFe(eArqXMLVenda) CLASS ACBrSat
        local hResult, buffer, bufferLen
        bufferLen := STR_LEN
        buffer := Space(bufferLen)   
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_CancelarCFe", hb_StrToUTF8(eArqXMLVenda), @buffer, @bufferLen)
        ::CheckResult(hResult)
        RETURN ::ProcessResult(buffer, bufferLen)

    METHOD GerarPDFExtratoVenda(eArqXMLVenda, eNomeArquivo) CLASS ACBrSat
        local hResult, buffer, bufferLen
        bufferLen := STR_LEN
        buffer := Space(bufferLen)   
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_GerarPDFExtratoVenda", hb_StrToUTF8(eArqXMLVenda), hb_StrToUTF8(eNomeArquivo), @buffer, @bufferLen)
        ::CheckResult(hResult)
        RETURN ::ProcessResult(buffer, bufferLen)

    METHOD GerarPDFCancelamento(eArqXMLVenda, eArqXMLCancelamento, eNomeArquivo)
        local hResult, buffer, bufferLen
        bufferLen := STR_LEN
        buffer := Space(bufferLen)   
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_GerarPDFCancelamento", hb_StrToUTF8(eArqXMLVenda), hb_StrToUTF8(eArqXMLCancelamento), hb_StrToUTF8(eNomeArquivo), @buffer, @bufferLen)
        ::CheckResult(hResult)
        RETURN ::ProcessResult(buffer, bufferLen)

    METHOD EnviarEmail(eArqXMLVenda, sPara, sAssunto, eNomeArquivo, sMensagem, sCC, eAnexos)
        local hResult
        hResult := DllCall(::hHandle, DLL_OSAPI, "SAT_EnviarEmail", hb_StrToUTF8(eArqXMLVenda), hb_StrToUTF8(sPara), hb_StrToUTF8(sAssunto), hb_StrToUTF8(eNomeArquivo), hb_StrToUTF8(sMensagem), hb_StrToUTF8(sCC), hb_StrToUTF8(eAnexos))
        ::CheckResult(hResult)
        RETURN nil

     

    Demo para quem usar geração em TXT:

     

    Function Main ()
       local sat
       local vendaRetorno, strIniVenda
       local hIni, hIniVenda
       LOCAL cSection
       
       sat := ACBrSat():New("", "")
       //                      Sessão       Chave    Valor
       // Configurações de log da Lib
       sat:ConfigGravarValor("Principal", "LogNivel", "4") // logParanoico     
       sat:ConfigGravarValor("Principal", "LogPath", hb_dirBase())

       //Configurações do Sat
       sat:ConfigGravarValor("SAT", "Modelo", "1") // satDinamico_cdecl
       sat:ConfigGravarValor("SAT", "NomeDLL", "C:\SAT\SAT.dll")
       sat:ConfigGravarValor("SAT", "CodigoDeAtivacao", "sefaz1234")
       sat:ConfigGravarValor("SAT", "SignAC", "111111111111122222222222222111111111111112222222222222211111111111111222222222222221111111111111122222222222222111111111111112222222222222211111111111111222222222222221111111111111122222222222222111111111111112222222222222211111111111111222222222222221111")
       
       // Softhouse   
       sat:ConfigGravarValor("SATConfig", "infCFe_versaoDadosEnt", "0.07")
       sat:ConfigGravarValor("SATConfig", "ide_CNPJ", "16716114000172")
       sat:ConfigGravarValor("SATConfig", "ide_numeroCaixa", "0")

       // Emitente
       sat:ConfigGravarValor("SATConfig", "emit_CNPJ", "14200166000166")
       sat:ConfigGravarValor("SATConfig", "emit_IE", "111111111111")
       sat:ConfigGravarValor("SATConfig", "emit_IM", "")
       sat:ConfigGravarValor("SATConfig", "emit_cRegTrib", "0") // RTSimplesNacional
       sat:ConfigGravarValor("SATConfig", "emit_cRegTribISSQN", "0") // RTISSMicroempresaMunicipal
       sat:ConfigGravarValor("SATConfig", "emit_indRatISSQN", "0") // irSim

       // Extrato
       sat:ConfigGravarValor("Extrato", "Tipo", "0") // teFortes
       sat:ConfigGravarValor("Extrato", "MostraPreview", "1") // True

       // Salvando configurações
       sat:ConfigGravar("")
     
       ?sat:Nome
       ?sat:Versao
       
       sat:Inicializar()

       // Gerando ini venda
       hIniVenda := Hash()
       hIniVenda["infCFe"] := Hash()
       hIniVenda["infCFe"]["versao"] := "0.07"

       hIniVenda["Destinatario"] := Hash()
       hIniVenda["Destinatario"]["CNPJCPF"] := "05481336000137"
       hIniVenda["Destinatario"]["xNome"] := "D.J. SYSTEM"

       hIniVenda["Entrega"] := Hash()
       hIniVenda["Entrega"]["xLgr"] := "Rua Cel. Aureliano de Camargo"
       hIniVenda["Entrega"]["nro"] := "973"
       hIniVenda["Entrega"]["xCpl"] := ""
       hIniVenda["Entrega"]["xBairro"] := "Centro"
       hIniVenda["Entrega"]["xMun"] := "Tatui"
       hIniVenda["Entrega"]["UF"] := "SP"

       hIniVenda["Produto001"] := Hash()
       hIniVenda["Produto001"]["cProd"] := "1189"
       hIniVenda["Produto001"]["infAdProd"] := "Teste de Produto"
       hIniVenda["Produto001"]["cEAN"] := ""
       hIniVenda["Produto001"]["xProd"] := "OVO VERMELHO"
       hIniVenda["Produto001"]["NCM"] := "04072100"
       hIniVenda["Produto001"]["CFOP"] := "5102"
       hIniVenda["Produto001"]["uCom"] := "DZ"
       hIniVenda["Produto001"]["Combustivel"] := "0"
       hIniVenda["Produto001"]["qCom"] := "510"
       hIniVenda["Produto001"]["vUnCom"] := "2,70"
       hIniVenda["Produto001"]["indRegra"] := "A"
       hIniVenda["Produto001"]["vDesc"] := "0"
       hIniVenda["Produto001"]["vOutro"] := "0"
       hIniVenda["Produto001"]["vItem12741"] := "137,00"

       hIniVenda["ObsFiscoDet001001"] := Hash()
       hIniVenda["ObsFiscoDet001001"]["xCampoDet"] := "Teste"
       hIniVenda["ObsFiscoDet001001"]["xTextoDet"] := "Texto Teste"

       hIniVenda["ICMS001"] := Hash()
       hIniVenda["ICMS001"]["Origem"] := "0"
       hIniVenda["ICMS001"]["CSOSN"] := "500"

       hIniVenda["PIS001"] := Hash()
       hIniVenda["PIS001"]["CST"] := "01"

       hIniVenda["COFINS001"] := Hash()
       hIniVenda["COFINS001"]["CST"] := "01"

       hIniVenda["Total"] := Hash()
       hIniVenda["Total"]["vCFeLei12741"] := "137,00"

       hIniVenda["DescAcrEntr"] := Hash()
       hIniVenda["DescAcrEntr"]["vDescSubtot"] := "7,00"

       hIniVenda["Pagto001"] := Hash()
       hIniVenda["Pagto001"]["cMP"] := "01"
       hIniVenda["Pagto001"]["vMP"] := "1400"

       hIniVenda["DadosAdicionais"] := Hash()
       hIniVenda["DadosAdicionais"]["infCpl"] := "Teste emissao CFe/SAT"

       hIniVenda["ObsFisco001"] := Hash()
       hIniVenda["ObsFisco001"]["xCampo"] := "ObsFisco 1"
       hIniVenda["ObsFisco001"]["xTexto"] := "Teste ObsFisco 1"

       strIniVenda := hb_iniWriteStr(hIniVenda)

       // Venda
       ?"Ini Venda"
       ?strIniVenda
       ?""
       ?"-------------------------------------------------------------------------------------------------------------"
       ?""
       vendaRetorno := sat:CriarEnviarCFe(strIniVenda)
       ?vendaRetorno
       ?""
       ?"-------------------------------------------------------------------------------------------------------------"
       ?""
       hIni := hb_iniReadStr(vendaRetorno)
       cSection := hIni["ENVIO"]

       if cSection["CodigoDeRetorno"] != "6000"
          ?cSection["Resultado"]
       else
       ?"Impressão Preview"
       sat:ImprimirExtratoVenda(cSection["XML"], "")
       ?"Impressão PDF"
       ?sat:GerarPDFExtratoVenda(cSection["XML"], "")
       end if

       sat:DesInicializar()
       sat := nil
        
    return NIL

    Exemplos:

       sat := ACBrSat():New("", "")
       sat:ConfigGravarValor("Principal", "LogNivel", "4")
       sat:ConfigGravarValor("SAT", "Modelo", "2")

       sat:ConfigGravarValor("SAT", "ArqLog", "C:\windows\temp\satlog")
       sat:ConfigGravarValor("SAT", "NomeDLL", "C:\ACBrMonitorPLUS\SAT\elgin\dllsat.dll")
       sat:ConfigGravarValor("SAT", "CodigoDeAtivacao", "123456789")
       sat:ConfigGravarValor("SAT", "SignAC", "SGR-SAT SISTEMA DE GESTAO E RETAGUARDA DO SAT")
       sat:ConfigGravarValor("SATConfig", "ide_numeroCaixa", "3") //ide_numeroCaixa Define o numero de caixa padrão da CFe.
       sat:ConfigGravarValor("SATConfig", "ide_tpAmb", "0") //ide_tpAmb  taProducao = 0  taHomologacao = 1
       sat:ConfigGravarValor("SATConfig", "EhUTF8", "") //EhUTF8 Define se devemos utilizar codificação UTF8 ao se comunicar com o SAT.
       sat:ConfigGravarValor("SATConfig", "infCFe_versaoDadosEnt", "0,07") //infCFe_versaoDadosEnt Define qual será a versão do CFe utilizada.Ex.: 0,07 ou 0,08
       sat:ConfigGravarValor("SATConfig", "PaginaDeCodigo", "0") //PaginaDeCodigo Define a pagina de código que se deve utilizar ao se comunicar com o SAT.

       sat:ConfigGravarValor("SATConfigArquivos", "PastaCFeVenda", "X:\acbr\NFESAI\AUTORIZA\59") //PastaCFeVenda Define o caminho onde será salvos os arquivos de venda.
       sat:ConfigGravarValor("SATConfigArquivos", "SalvarCFe","0" ) //SalvarCFe Define se será salvo o arquivo de venda.
       sat:ConfigGravarValor("SATConfigArquivos", "SalvarCFeCanc", "0") //SalvarCFeCanc Define se será salvo o arquivo de cancelamento.
       sat:ConfigGravarValor("SATConfigArquivos", "SalvarEnvio", "0") //SalvarEnvio Define se será salvo o arquivo de envio para o sat.

      //sat:ConfigGravarValor("SATConfigArquivos", "SepararPorCNPJ", "0") //SepararPorCNPJ Define se deverá separar os arquivos por CNPJ.
      //sat:ConfigGravarValor("SATConfigArquivos", "SepararPorModelo", "0") //SepararPorModelo Define se deverá separar os arquivos por modelo.
      //sat:ConfigGravarValor("SATConfigArquivos", "SepararPorAno", "0") //SepararPorAno Define se deverá separar os arquivos por ano.
      //sat:ConfigGravarValor("SATConfigArquivos", "SepararPorMes", "0") //SepararPorMes Define se deverá separar os arquivos por mês.
      //sat:ConfigGravarValor("SATConfigArquivos", "SepararPorDia", "0") //SepararPorDia Define se deverá separar os arquivos por dia.

       sat:ConfigGravarValor("SATConfig", "ide_CNPJ", "14200166000166") //ide_CNPJ Exemplo da elgin: 16716114000172 Define o padrão CNPJ do emitente da CFe.
       sat:ConfigGravarValor("SATConfig", "emit_IE", "144842258111") //emit_IE Define o IE padrão do emitente do CFe.
       //sat:ConfigGravarValor("SATConfig", "emit_IM", "inscricao municipal do emitente") //emit_IM Define o IM padrão do emitente do CFe.
       sat:ConfigGravarValor("SATConfig", "emit_cRegTrib","0") //emit_cRegTrib RTSimplesNacional = 0 RTRegimeNormal = 1
       sat:ConfigGravarValor("SATConfig", "emit_cRegTribISSQN", "6") //emit_cRegTribISSQN RTISS MicroempresaMunicipal = 0
       sat:ConfigGravarValor("SATConfig", "emit_indRatISSQN", "0") //emit_indRatISSQN  Define indicador de rateio do desconto sobre subtotal entre itens sujeitos a

       sat:ConfigGravarValor("SATConfig", "emit_CNPJ", "16716114000172") //emit_CNPJ Exemplo da elgin: 14200166000166 Define o CNPJ padrão do emitente da CFe.

       sat:ConfigGravarValor("SATRede", "tipoInter", "0") //0 = infETHE
       sat:ConfigGravarValor("SATRede", "tipoLan", "0")  
       
       sat:ConfigGravarValor("Extrato", "LarguraBobina", "302") //LarguraBobina Define a largura da bobina.
        sat:ConfigGravarValor("Extrato", "MargemSuperior", "2") //MargemSuperior Define a margem superior da impressão.
       sat:ConfigGravarValor("Extrato", "MargemInferior", "4") //MargemInferior Define a margem inferior da impressão.
        sat:ConfigGravarValor("Extrato", "MargemEsquerda", "2") //MargemEsquerda Define a margem esquerda da impressão.
        sat:ConfigGravarValor("Extrato", "MargemDireita", "2") //MargemDireita Define a margem direita da impressão.
       sat:ConfigGravarValor("Extrato", "Tipo", "0") //TipoDefine o tipo de impressão a ser utilizada.tpFortes = 0 tpEscPos = 1
       //sat:ConfigGravarValor("Extrato", "Impressora", "nome a impressora para emissão do cupom") //Impressora Define o nome da impressora padrão a ser utilizada pela impressão.
       sat:ConfigGravarValor("Extrato", "ImprimeChaveEmUmaLinha", "0") //ImprimeChaveEmUma Define se deve imprimir a chave do CFe em apenas uma linha.

     

     

     

    Dll's Necessárias , a quais podems ser baixadas por qualquer usuário Sac do Acbr.

    ACBrSAT32.dll
    ACBrSAT64.dll

    libeay32.dll
    libexslt.dll
    libiconv.dll
    libxml2.dll
    libxslt.dll
    msvcr120.dll
    ssleay32.dll

     

    Obs: A classe da NF-e ainda não tenho.

    []s, 

     

  15. Jfaguiar, a Tmysql não é uma classe?

     

     /*
     * $Id: tmysql.prg,v 1.17 2007/07/17 21:01:17 andresreyesh Exp $
     */

     /*
     * Harbour Project source code:
     * MySQL DBMS classes.
     * These classes try to emulate clipper dbXXXX functions on a SQL query
     *
     * Copyright 2000 Maurilio Longo <maurilio.longo@libero.it>
     * www - http://www.harbour-project.org
     *
     * This program is free software; you can redistribute it and/or modify
     * it under the terms of the GNU General Public License as published by
     * the Free Software Foundation; either version 2, or (at your option)
     * any later version.
     *
     * This program is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     * GNU General Public License for more details.
     *
     * You should have received a copy of the GNU General Public License
     * along with this software; see the file COPYING.  If not, write to
     * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
     * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
     *
     * As a special exception, the Harbour Project gives permission for
     * additional uses of the text contained in its release of Harbour.
     *
     * The exception is that, if you link the Harbour libraries with other
     * files to produce an executable, this does not by itself cause the
     * resulting executable to be covered by the GNU General Public License.
     * Your use of that executable is in no way restricted on account of
     * linking the Harbour library code into it.
     *
     * This exception does not however invalidate any other reasons why
     * the executable file might be covered by the GNU General Public License.
     *
     * This exception applies only to the code released by the Harbour
     * Project under the name Harbour.  If you copy code from other
     * Harbour Project or Free Software Foundation releases into a copy of
     * Harbour, as the General Public License permits, the exception does
     * not apply to the code that you add in this way.  To avoid misleading
     * anyone as to the status of such modified files, you must delete
     * this exception notice from them.
     *
     * If you write modifications of your own for Harbour, it is your choice
     * whether to permit this exception to apply to your modifications.
     * If you do not wish that, delete this exception notice.
     *
     */

     /*
     2002-01-28 21:30 UTC+0100 Patrick Mast <email@patrickmast.com>
       * contrib/mysql/tmysql
         + Added DateTime field
         * Added more info on Alert message for Unknown type
         * Modified ClipValue2SQL() to process empty strings
     */

     /*
     2002-02-18 07:30 UTC+0100 Srdjan Dragojlovic <digikv@yahoo.com>
       * contrib/mysql/tmysql
         + Bug in GOTO Method
     */


    #include "hbclass.ch"
    #include "common.ch"
    #include "dbstruct.ch"
    #include "mysql.ch"

     

    // Every single row of an answer
    CLASS TMySQLRow

       DATA  aRow              // a single row of answer
       DATA  aDirty            // array of booleans set to .T. if corresponding field of aRow has been changed
       DATA  aOldValue         // If aDirty[n] is .T. aOldValue[n] keeps a copy of changed value if aRow[n] is part of a primary key

       DATA  aFieldStruct      // type of each field
       DATA  cTable            // Name of table containing this row, empty if TMySQLQuery returned this row

       METHOD   New( aRow, aFStruct, cTableName )     // Create a new Row object

       METHOD   FieldGet( cnField )          // Same as clipper ones, but FieldGet() and FieldPut() accept a string as
       METHOD   FieldPut( cnField, Value )   // field identifier, not only a number
       METHOD   FieldName( nNum )
       METHOD   FieldPos( cFieldName )

       METHOD   FieldLen( nNum )             // Length of field N
       METHOD   FieldDec( nNum )             // How many decimals in field N
       METHOD   FieldType( nNum )            // Clipper type of field N

       METHOD   MakePrimaryKeyWhere()        // returns a WHERE x=y statement which uses primary key (if available)

    ENDCLASS


    METHOD New( aRow, aFStruct, cTableName ) CLASS TMySQLRow

       default cTableName to ""
       default aFStruct to {}

       ::aRow         := aRow
       ::aFieldStruct := aFStruct
       ::cTable       := cTableName

       ::aDirty       := Array( Len( ::aRow ) )
       ::aOldValue    := Array( Len( ::aRow ) )

       AFill( ::aDirty, .F. )

    return Self


    METHOD FieldGet( cnField ) CLASS TMySQLRow

       local nNum

       if ValType( cnField ) == "C"
          nNum := ::FieldPos( cnField )
       else
          nNum := cnField
       endif

       if nNum > 0 .AND. nNum <= Len( ::aRow )

          // Char fields are padded with spaces since a real .dbf field would be
          if ::FieldType( nNum ) == "C"
             return PadR( ::aRow[ nNum ], ::aFieldStruct[ nNum ][ MYSQL_FS_LENGTH ])
          else
             return ::aRow[ nNum ]
          endif

       endif

    return nil


    METHOD FieldPut( cnField, Value ) CLASS TMySQLRow

       local nNum

       if ValType( cnField ) == "C"
          nNum := ::FieldPos( cnField )
       else
          nNum := cnField
       endif

       if nNum > 0 .AND. nNum <= Len( ::aRow )

          if Valtype( Value ) == Valtype( ::aRow[ nNum ] ) .OR. ::aRow[ nNum ] == NIL  // .OR. Empty(::aRow[nNum])

             // if it is a char field remove trailing spaces
             if ValType( Value ) == "C"
                Value := RTrim( Value )
             endif

             // Save starting value for this field
             if !::aDirty[ nNum ]
                ::aOldValue[ nNum ] := ::aRow[ nNum ]
                ::aDirty[ nNum ]    := .T.
             endif

             ::aRow[ nNum ] := Value

             return Value
          endif
       endif

    return nil


    // Given a field name returns it's position
    METHOD FieldPos( cFieldName ) CLASS TMySQLRow

       local cUpperName, nPos

       cUpperName := Upper( cFieldName )

       nPos := AScan( ::aFieldStruct, {| aItem | Upper( aItem[ MYSQL_FS_NAME ] ) == cUpperName } )

    return nPos


    // Returns name of field N
    METHOD FieldName( nNum ) CLASS TMySQLRow

       if nNum >= 1 .AND. nNum <= Len( ::aFieldStruct )
          return ::aFieldStruct[ nNum ][ MYSQL_FS_NAME ]
       endif

    return ""


    METHOD FieldLen(nNum) CLASS TMySQLRow

       if nNum >= 1 .AND. nNum <= Len( ::aFieldStruct )
          return ::aFieldStruct[ nNum ][ MYSQL_FS_LENGTH ]
       endif

    return 0


    METHOD FieldDec( nNum ) CLASS TMySQLRow

       if nNum >= 1 .AND. nNum <= Len( ::aFieldStruct )
          return ::aFieldStruct[ nNum ][ MYSQL_FS_DECIMALS ]
       endif

    return 0


    METHOD FieldType( nNum ) CLASS TMySQLRow

       if nNum >= 1 .AND. nNum <= Len( ::aFieldStruct )
          Return SQL2ClipType( ::aFieldStruct[ nNum ][ MYSQL_FS_TYPE ] )
       endif

    return "U"


    // returns a WHERE x=y statement which uses primary key (if available)
    METHOD MakePrimaryKeyWhere() CLASS TMySQLRow

       local cWhere := " WHERE ", aField

       for each aField in ::aFieldStruct

          // search for fields part of a primary key
          if ( sqlAND( aField[ MYSQL_FS_FLAGS ], PRI_KEY_FLAG ) == PRI_KEY_FLAG ) .OR.;
             ( sqlAND( aField[ MYSQL_FS_FLAGS ], MULTIPLE_KEY_FLAG ) == MULTIPLE_KEY_FLAG )

             cWhere += aField[ MYSQL_FS_NAME ] + "="

             // if a part of a primary key has been changed, use original value
             if ::aDirty[ HB_EnumIndex() ]
                cWhere += ClipValue2SQL( ::aOldValue[ HB_EnumIndex() ], SQL2ClipType(aField[ MYSQL_FS_TYPE ]) )
             else
                cWhere += ClipValue2SQL( ::aRow[ HB_EnumIndex() ], SQL2ClipType(aField[ MYSQL_FS_TYPE ]) )
             endif

             cWhere += " AND "
          endif

       next

       // remove last " AND "
       cWhere := Left( cWhere, Len( cWhere ) - 5 )

    return cWhere

    /* ----------------------------------------------------------------------------------------*/

    // Every single query submitted to MySQL server
    CLASS TMySQLQuery

       DATA  nSocket           // connection handle to MySQL server
       DATA  nResultHandle     // result handle received from MySQL

       DATA  cQuery            // copy of query that generated this object

       DATA  nNumRows          // number of rows available on answer NOTE MySQL is 0 based
       DATA  nCurRow           // I'm currently over row number

       DATA  nNumFields        // how many fields per row
       DATA  aFieldStruct      // type of each field, a copy is here a copy inside each row
       DATA  aRow

       DATA  lError            // .T. if last operation failed

       DATA  loRow             // If return oRow in GetRow(),

       METHOD   New( nSocket, cQuery, loRow )  // New query object

       METHOD   Destroy()  INLINE sqlFreeR( ::nResultHandle ), Self
                                               // Free result handle and associated resources
       METHOD   End()      INLINE ::Destroy()

       METHOD   Refresh()                      // ReExecutes the query (cQuery) so that changes to table are visible

       METHOD   GetRow( nRow, loRow, lSkip )   // return Row n of answer

       METHOD   Skip( nRows )                  // Same as clipper ones

       METHOD   Bof()        INLINE ::lBof  // ::nCurRow == 1
       METHOD   Eof()        INLINE ::lEof  // ::nCurRow == ::nNumRows
       METHOD   RecNo()      INLINE ::nCurRow
       METHOD   LastRec()    INLINE ::nNumRows
       METHOD   GoTop()      INLINE ::GetRow( 1 )
       METHOD   GoBottom()   INLINE ::GetRow( ::nNumRows ) //-1 )
       METHOD   GoTo( nRow ) INLINE ::GetRow( nRow )

       METHOD   FCount()     INLINE ::nNumFields

       METHOD   NetErr()     INLINE ::lError      // Returns .T. if something went wrong

       METHOD   Error()      INLINE ::lError := .F., sqlGetErr(::nSocket)
                                                  // Returns textual description of last error and clears ::lError

       METHOD   ErrorNo()    INLINE ::lError := .F., sqlGetErrNo(::nSocket)
                                                  // Returns number of last error and clears ::lError

       METHOD   FieldName( nNum )
       METHOD   FieldPos( cFieldName )
       METHOD   FieldGet( cnField )

       METHOD   FieldLen( nNum )                    // Length of field N
       METHOD   FieldDec( nNum )                    // How many decimals in field N
       METHOD   FieldType( nNum )                   // Clipper type of field N

       METHOD   Locate( cFieldName, Value, bPartialKey, bSoftSeek )

       METHOD   RecCount()   INLINE ::nNumRows

       PROTECTED:

       DATA lEof
       DATA lBof

    ENDCLASS


    METHOD New( nSocket, cQuery, loRow ) CLASS TMySQLQuery

       local nI, aField, rc, bBlock

       Default loRow to .t.

       ::nSocket       := nSocket
       ::cQuery        := cQuery

       ::lError        := .F.
       ::aFieldStruct  := {}
       ::nCurRow       := 1
       ::nResultHandle := nil
       ::nNumFields    := 0
       ::nNumRows      := 0
       ::loRow         := loRow


       if ( rc := sqlQuery( nSocket, cQuery ) ) == 0

          // save result set
          if ( ::nResultHandle := sqlStoreR( nSocket ) ) > 0

             ::nNumRows     := sqlNRows( ::nResultHandle )
             ::nNumFields   := sqlNumFi( ::nResultHandle )

             ::aFieldStruct := Array( ::nNumFields )
             ::aRow         := Array( ::nNumFields )

             if ::nNumRows > 0
                ::lEof      := .f.
                ::lBof      := .f.
             else
                ::lEof      := .t.
                ::lBof      := .t.
             endif

             for each aField in ::aFieldStruct

                aField := sqlFetchF( ::nResultHandle )

                bBlock := ArrayBlock( HB_EnumIndex() )

                __objAddInline( Self,     aField[ MYSQL_FS_NAME ], bBlock )
                __objAddInline( Self, "_"+aField[ MYSQL_FS_NAME ], bBlock )

             next

             ::getRow( ::nCurRow )

          else
             // Should query have returned rows? (Was it a SELECT like query?)

             if ( ::nNumFields := sqlNumFi( nSocket ) ) == 0

                // Was not a SELECT so reset ResultHandle changed by previous sqlStoreR()
                ::nResultHandle := nil
                ::lEof   := .t.
                ::lBof   := .t.
             else
                ::lError := .T.

             endif
          endif

       else
          ::lError := .T.

       endif

    return Self


    METHOD Refresh() CLASS TMySQLQuery

       local rc

       // free present result handle
       sqlFreeR( ::nResultHandle )

       ::lError := .F.

       if ( rc := sqlQuery( ::nSocket, ::cQuery ) ) == 0

          // save result set
          ::nResultHandle := sqlStoreR( ::nSocket )
          ::nNumRows := sqlNRows( ::nResultHandle )

          // NOTE: I presume that number of fields doesn't change (that is nobody alters this table) between
          // successive refreshes of the same

          // But row number could very well change
          if ::nCurRow > ::nNumRows
             ::nCurRow := ::nNumRows
          endif

          ::getRow( ::nCurRow )

       else
          ::lError := .T.

       endif

    return !::lError


    METHOD Skip( nRows ) CLASS TMySQLQuery
    Local nOldrow := ::nCurRow
       // NOTE: MySQL row count starts from 0
       default nRows to 1

       if ::nNumRows > 0
          ::lBof := .f.
          ::lEof := .f.
       else
          ::lBof := .t.
          ::lEof := .t.
       endif

       if nRows == 0
          // No move

       elseif nRows < 0
          // Negative movement
          if (::nCurRow += nRows) < 1
             ::nCurRow := 0
             ::lBof    := .t.
          endif

       else
          // positive movement
          if (::nCurRow += nRows) > ::nNumRows
             ::nCurRow := ::nNumRows + 1
             ::lEof    := .t.
          endif

       endif

       ::getRow( ::nCurRow )

    return ::nCurRow - nOldRow


    // Get row n of a query and return it as a TMySQLRow object
    METHOD GetRow( nRow, loRow, lSkip ) CLASS TMySQLQuery

       local cType, xField
    //   local cDateFormat := Lower( Set( 4 ) )

       default loRow to ::loRow
       default nRow  to ::nCurRow
       default lSkip to .f.

       if ::nResultHandle <> NIL
          if lSkip
             nRow := ::nCurRow + 1
          endif

          do case
          case ::nNumRows == 0
             ::lBof    := .t.
             ::lEof    := .t.
             ::nCurRow := 1
          case nRow < 1
             ::lBof    := .t.
             ::lEof    := .t.
             ::nCurRow := ::nNumRows + 1
          case nRow > 0 .and. nRow <= ::nNumRows //- 1
             ::lBof    := .f.
             ::lEof    := .f.
             ::nCurRow := nRow
          case nRow > ::nNumRows
             ::lBof    := .f.
             ::lEof    := .t.
             ::nCurRow := ::nNumRows + 1
          endcase
          nRow := ::nCurRow

          if nRow > 0 .AND. nRow <= ::nNumRows

             // NOTE: row count starts from 0
             sqlDataS( ::nResultHandle, nRow - 1 )
             ::nCurRow := nRow
             ::aRow := sqlFetchR( ::nResultHandle )

          elseif nRow == ::nNumRows + 1
             ::aRow := Array( Len( ::aFieldStruct ) )
             Afill( ::aRow, "" )

          else
             ::aRow := NIL
          endif


          if ::aRow <> NIL

             // Convert answer from text field to correct clipper types
             for each xField in ::aRow

                cType := SQL2ClipType( ::aFieldStruct[ HB_EnumIndex() ][ MYSQL_FS_TYPE ] )

                switch cType
                   case "L"
                      xField := !( Val( xField ) == 0 )
                      exit

                   case "N"
                   case "I"
                   case "T"
                      xField := Val( xField )
                      exit

                   case "D"
                      if Empty(xField)
                         xField := CToD( "" )
    /*
                      elseif cDateFormat = 'mm-dd-yyyy' // USA
                         xField := ctod(substr(xField,6,2)+"-"+right(xField,2,0)+ "-" + Left(xField, 4))

                      elseif  cDateFormat = 'dd/mm/yyyy' .or. cDateFormat = 'dd/mm/yy' // BRITISH ou FRENCH
                         xField :=  ctod(right(xField,2,0)+ "/"+ substr(xField,6,2)+"/"+ Left(xField, 4))

                      elseif cDateFormat = 'yyyy.mm.dd' // ANSI
                         xField := ctod(Left(xField, 4)+ "."+substr(xField,6,2)+"."+right(xField,2,0))

                      elseif cDateFormat = 'dd.mm.yyyy' //GERMAN
                         xField :=ctod(right(xField,2,0)+ "."+ substr(xField,6,2)+"."+ Left(xField, 4 ))

                      elseif cDateFormat = 'dd-mm-yyyy'  //ITALIAN
                         xField :=ctod(right(xField,2,0)+ "-"+ substr(xField,6,2)+"-"+ Left(xField, 4))

                      elseif cDateFormat = 'yyyy/mm/dd' //JAPAN
                         xField :=  ctod(Left(xField, 4)+ "/"+substr(xField,6,2)+"/"+right(xField,2,0))

                      elseif cDateFormat = 'mm/dd/yyyy' // AMERICAN
                         xField :=  ctod(substr(xField,6,2)+"/"+right(xField,2,0)+ "/" + Left(xField, 4))
                      else
                         xField := "''"
    */
                      else
                         // MySQL Date format YYYY-MM-DD
                         xField := SToD( Left( xField, 4 ) + substr( xField, 6, 2 ) + right( xField, 2 ) )
                      endif
                      exit

                   case "C"
                      xField := PadR( xField , ::aFieldStruct[ HB_EnumIndex() ][ MYSQL_FS_LENGTH ] )
                   case "M"
                   case "B"
                      // Character or Memo field
                      exit

                   default

    //                  Alert("Unknown type from SQL Server Field: " + LTrim(Str(i))+" is type "+LTrim(Str(nType)))

                end

    //            __objsetValuelist(Self,{{::aFieldStruct[MYSQL_FS_NAME],xField}})

             next

             if loRow
                Return TMySQLRow():New( ::aRow, ::aFieldStruct )
             endif

          endif

       endif

    return nil


    // Given a field name returns it's position
    METHOD FieldPos( cFieldName ) CLASS TMySQLQuery

       local cUpperName, nPos := 0

       cUpperName := Upper( cFieldName )

       nPos := AScan( ::aFieldStruct, {| aItem | Upper( aItem[ MYSQL_FS_NAME ] ) == cUpperName } )

    return nPos


    // Returns name of field N
    METHOD FieldName( nNum ) CLASS TMySQLQuery

       if nNum >= 1 .AND. nNum <= Len( ::aFieldStruct )
          return ::aFieldStruct[ nNum ][ MYSQL_FS_NAME ]
       endif

    return ""

    METHOD FieldGet(cnField) CLASS TMySQLQuery

       local nNum, Value

       if ValType( cnField ) == "C"
          nNum := ::FieldPos( cnField )
       else
          nNum := cnField
       endif

       if nNum > 0 .AND. nNum <= ::nNumfields
    //       Value :=  __objsendmsg(Self,::aFieldStruct[nNum][MYSQL_FS_NAME])
          Value := ::aRow[ nNum ]

          // Char fields are padded with spaces since a real .dbf field would be
          if ::FieldType( nNum ) == "C"
             return PadR( Value, ::aFieldStruct[ nNum ][ MYSQL_FS_LENGTH ] )
          else
             return Value
          endif

       endif

    return nil


    METHOD FieldLen(nNum) CLASS TMySQLQuery

       if nNum > 0 .AND. nNum <= ::nNumFields
          return ::aFieldStruct[ nNum ][ MYSQL_FS_LENGTH ]
       endif

    return 0


    METHOD FieldDec( nNum ) CLASS TMySQLQuery

       if nNum > 0 .AND. nNum <= ::nNumFields
          return ::aFieldStruct[ nNum ][ MYSQL_FS_DECIMALS ]
       endif

    return 0


    METHOD FieldType( nNum ) CLASS TMySQLQuery

       local cType := "U"

       if nNum >= 1 .AND. nNum <= ::nNumFields

          cType := SQL2ClipType( ::aFieldStruct[ nNum ][ MYSQL_FS_TYPE ] )

       endif

    return cType


    METHOD Locate( cFieldName, Value, bPartialKey, bSoftSeek ) CLASS TMySQLQuery
    local nRecPrec := ::recno(), bFound := .F.

       //bSoftSeek cause the record pointer to be moved to the next record

       if bSoftSeek   == NIL ; bSoftSeek := .F. ; endif
       if bPartialKey == NIL ; bPartialKey := .T. ; endif

       ::gotop()
       while ! ::eof()
         bFound := (::FieldGet(::FieldPos(cFieldName)) == Value) .or. ((::FieldGet(::FieldPos(cFieldName)) = Value) .and. bPartialKey)

         if !bFound .and. ((::FieldGet(::FieldPos(cFieldName)) > Value) .and. bSoftSeek)
           bFound := .T.
         endif

         if bFound
           exit
         endif

         ::skip()
       enddo

       if !bFound
         ::goto(nRecPrec)
       endif

    return bFound

     

    /* ----------------------------------------------------------------------------------------*/

    // A Table is a query without joins; this way I can Insert() e Delete() rows.
    // NOTE: it's always a SELECT result, so it will contain a full table only if
    //       SELECT * FROM ... was issued
    CLASS TMySQLTable FROM TMySQLQuery

       DATA  cTable               // name of table
       DATA  aOldValue         //  keeps a copy of old value

       METHOD   New( nSocket, cQuery, cTableName, loRow )
       METHOD   GetRow( nRow, loRow, lSkip )
       METHOD   Skip( nRow )

       METHOD   Update( oRow )                // Gets an oRow and updates changed fields
       METHOD   Save( oRow )   INLINE ::Update( oRow )
       METHOD   Delete( oRow )                // Deletes passed row from table
       METHOD   Append( oRow )                // Inserts passed row into table

       METHOD   GetBlankRow( loRow )          // Returns an empty row with all available fields empty
       METHOD   Blank( loRow ) INLINE ::GetBlankRow( loRow )

       METHOD   FieldPut( cnField, Value )    // field identifier, not only a number
       METHOD   Refresh()
       METHOD   MakePrimaryKeyWhere()         // returns a WHERE x=y statement which uses primary key (if available)

    ENDCLASS


    METHOD New(nSocket, cQuery, cTableName, loRow) CLASS TMySQLTable

    Local xValue

       super:New(nSocket, AllTrim(cQuery), loRow)

       ::cTable    := Lower(cTableName)
       ::aOldValue := Array( ::nNumFields )

       for each xValue in ::aOldValue
          xValue := ::fieldget( HB_EnumIndex() )
       next

    return Self


    METHOD GetRow( nRow, loRow, lSkip ) CLASS TMySQLTable

       local oRow := super:GetRow( nRow, loRow, lSkip ), xValue

       if oRow <> NIL
          oRow:cTable := ::cTable
       endif

       ::aOldvalue := Array( ::nNumFields )

       for each xValue in ::aOldValue
          xValue := ::fieldget( HB_EnumIndex() )
       next

    return oRow


    METHOD Skip(nRow) CLASS TMySQLTable
       Local xValue, nSkipRows

         nSkipRows := super:skip(nRow)

         for each xValue in ::aOldValue
            xValue := ::fieldget( HB_EnumIndex() )
         next

    return nSkipRows


    /* Creates an update query for changed fields and submits it to server */
    METHOD Update( oRow ) CLASS TMySQLTable

       local cUpdateQuery := "UPDATE " + ::cTable + " SET "
       local xValue

       ::lError := .F.


              // default Current row
       if oRow == nil

             for each xValue in ::aOldValue
                if xValue == NIL .or. xValue <> ::FieldGet( HB_EnumIndex() )
                   cUpdateQuery += ::aFieldStruct[ HB_EnumIndex() ][MYSQL_FS_NAME] + "=" + ClipValue2SQL(::FieldGet( HB_EnumIndex() ),::FieldType( HB_EnumIndex() )) + ","
                endif
             next

             // no Change
             if right(cUpdateQuery,4)=="SET "; return !::lError; end

             // remove last comma
             cUpdateQuery := Left(cUpdateQuery, Len(cUpdateQuery) -1)


             cUpdateQuery += ::MakePrimaryKeyWhere()

    // alert( cUpdateQuery )

             if sqlQuery( ::nSocket, cUpdateQuery ) == 0

                ::refresh()
                for each xValue in ::aOldValue
                   xValue := ::fieldget( HB_EnumIndex() )
                next

             else
                ::lError := .T.

             endif

       else

          WITH OBJECT oRow

             if :cTable == ::cTable

                for each xValue in :aRow
                   if :aDirty[ HB_EnumIndex() ]
                      cUpdateQuery += :aFieldStruct[ HB_EnumIndex() ][ MYSQL_FS_NAME ] + "=" + ClipValue2SQL( :aRow[ HB_EnumIndex() ], :FieldType( HB_EnumIndex() ) ) + ","
                   endif
                next

                // remove last comma
                cUpdateQuery := Left( cUpdateQuery, Len(cUpdateQuery ) - 1 )

                cUpdateQuery += :MakePrimaryKeyWhere()

    // alert( cUpdateQuery )

                if sqlQuery( ::nSocket, cUpdateQuery ) == 0

                   // All values are commited
                   Afill( :aDirty   , .F. )
                   Afill( :aOldValue, nil )

                else
                   ::lError := .T.

                endif

             endif
          END  // WITH
       endif

    return !::lError


    METHOD Delete( oRow ) CLASS TMySQLTable

       local cDeleteQuery := "DELETE FROM " + ::cTable, xValue

       // is this a row of this table ?

       if oRow == nil

             cDeleteQuery += ::MakePrimaryKeyWhere()

             if sqlQuery( ::nSocket, cDeleteQuery ) == 0
                ::lError := .F.
                // ::nCurRow--
                ::refresh()

                for each xValue in ::aOldValue
                   xValue := ::fieldget( HB_EnumIndex() )
                next

             else
                ::lError := .T.

             endif

       else

          WITH OBJECT oRow
             if :cTable == ::cTable

                cDeleteQuery += :MakePrimaryKeyWhere()

                if sqlQuery( ::nSocket, cDeleteQuery ) == 0
                   ::lError := .F.

                else
                   ::lError := .T.

                endif

              endif
          END  // WITH
      Endif

    return !::lError


    // Adds a row with values passed into oRow
    METHOD Append( oRow ) CLASS TMySQLTable

       local cInsertQuery := "INSERT INTO " + ::cTable + " ("
       local xValue, lResult:= .F.

               // default Current row
       if oRow == nil

                // field names
                for each xValue in ::aFieldStruct
                   if xValue[ MYSQL_FS_FLAGS ] <> AUTO_INCREMENT_FLAG
                      cInsertQuery += xValue[ MYSQL_FS_NAME ] + ","
                   endif
                next

                // remove last comma from list
                cInsertQuery := Left( cInsertQuery, Len( cInsertQuery ) - 1 ) + ") VALUES ("

                // field values
                for each xValue in ::aFieldStruct
                   if xValue[ MYSQL_FS_FLAGS ] <> AUTO_INCREMENT_FLAG
                      cInsertQuery += ClipValue2SQL( ::FieldGet(HB_EnumIndex() ), ::FieldType(HB_EnumIndex()) ) + ","
                   endif
                next

                // remove last comma from list of values and add closing parenthesis
                cInsertQuery := Left( cInsertQuery, Len(cInsertQuery) - 1 ) + ")"

    // alert( cInsertQuery )

                if sqlQuery( ::nSocket, cInsertQuery ) == 0

                   ::refresh()
                   for each xValue in ::aOldValue
                      xValue := ::fieldget( HB_EnumIndex() )
                   next
                   lResult:= .T.
                else
                   ::lError := .T.
                endif


       else

          WITH OBJECT oRow
             if :cTable == ::cTable

                // field names
                for each xValue in :aFieldStruct
                   if xValue[ MYSQL_FS_FLAGS ] <> AUTO_INCREMENT_FLAG
                      cInsertQuery += xValue[ MYSQL_FS_NAME ] + ","
                   endif
                next
                // remove last comma from list
                cInsertQuery := Left( cInsertQuery, Len( cInsertQuery ) - 1 ) + ") VALUES ("

                // field values
                for each xValue in :aRow
                   if :aFieldStruct[ HB_EnumIndex() ][ MYSQL_FS_FLAGS ] <> AUTO_INCREMENT_FLAG
                      cInsertQuery += ClipValue2SQL( xValue, :FieldType(HB_EnumIndex()) ) + ","
                   endif
                next

                // remove last comma from list of values and add closing parenthesis
                cInsertQuery := Left( cInsertQuery, Len( cInsertQuery ) - 1 ) + ")"

    // alert( cInsertQuery )

                if sqlQuery( ::nSocket, cInsertQuery ) == 0
                   lResult:= .T.
                else
                   ::lError := .T.
                endif

             endif
          END  // WITH
       Endif
    return lResult


    METHOD GetBlankRow( loRow ) CLASS TMySQLTable

       local cType
       local xValue

       Default loRow to ::loRow

       for each xValue in ::aRow

          cType := SQL2ClipType( ::aFieldStruct[ HB_EnumIndex() ][ MYSQL_FS_TYPE ] )

          switch cType
          case "C"
             ::aOldValue[ HB_EnumIndex() ] := xValue := SPACE(::aFieldStruct[ HB_EnumIndex() ][ MYSQL_FS_LENGTH ])
             exit
          case "M"
          case "B"
             ::aOldValue[ HB_EnumIndex() ] := xValue := ""
             exit

          case "N"
          case "I"
             ::aOldValue[ HB_EnumIndex() ] := xValue := 0
             exit

          case "L"
             ::aOldValue[ HB_EnumIndex() ] := xValue := .F.
             exit

          case "D"
             ::aOldValue[ HB_EnumIndex() ] := xValue := CToD("")
             exit

          default
             ::aOldValue[ HB_EnumIndex() ] := xValue := nil

          end
       next


       if loRow
          return TMySQLRow():New( ::aRow, ::aFieldStruct, ::cTable )
       endif

    return nil


    METHOD FieldPut( cnField, Value ) CLASS TMySQLTable

       local nNum

       if ValType( cnField ) == "C"
          nNum := ::FieldPos( cnField )
       else
          nNum := cnField
       endif

       if nNum > 0 .AND. nNum <= ::nNumFields

    //      if Valtype( Value ) == Valtype( ::FieldGet( nNum ) ) .OR. ::Fieldget( nNum ) == NIL )
          if Valtype( Value ) == Valtype( ::aRow[ nNum ] ) .OR. ::aRow[ nNum ] == NIL

             // if it is a char field remove trailing spaces
             if ValType( Value ) == "C"
                Value := RTrim( Value )
             endif

             ::aRow[ nNum ] := Value

             return Value
          endif
       endif

    return nil

    METHOD Refresh() CLASS TMySQLTABLE

       local rc

       // free present result handle
       sqlFreeR( ::nResultHandle )

       ::lError := .F.

       if ( rc := sqlQuery( ::nSocket, ::cQuery ) ) == 0

          // save result set
          ::nResultHandle := sqlStoreR( ::nSocket )
          ::nNumRows      := sqlNRows( ::nResultHandle )

          // NOTE: I presume that number of fields doesn't change (that is nobody alters this table) between
          // successive refreshes of the same

          // But row number could very well change
          if ::nCurRow > ::nNumRows
             ::nCurRow := ::nNumRows
          endif

          ::getRow( ::nCurRow )

       else
          ::lError := .T.

       endif

    return !::lError


    // returns a WHERE x=y statement which uses primary key (if available)
    METHOD MakePrimaryKeyWhere() CLASS TMySQLTable

       local ni, cWhere := " WHERE ", aField

       for each aField in ::aFieldStruct

          // search for fields part of a primary key
          if ( sqlAND( aField[ MYSQL_FS_FLAGS ], PRI_KEY_FLAG ) == PRI_KEY_FLAG ) .OR.;
             ( sqlAND( aField[ MYSQL_FS_FLAGS ], MULTIPLE_KEY_FLAG ) == MULTIPLE_KEY_FLAG )

             cWhere += aField[ MYSQL_FS_NAME ] + "="

             // if a part of a primary key has been changed, use original value

                cWhere += ClipValue2SQL( ::aOldValue[ HB_EnumIndex() ], ::FieldType(HB_EnumIndex()) )

             cWhere += " AND "
          endif

       next

       // remove last " AND "
       cWhere := Left( cWhere, Len( cWhere ) - 5 )

    return cWhere

     

    /* ----------------------------------------------------------------------------------------*/

    // Every available MySQL server
    CLASS TMySQLServer

       DATA  nSocket                 // connection handle to server (currently pointer to a MYSQL structure)
       DATA  cServer                 // server name
       DATA  cDBName                 // Selected DB
       DATA  cUser                   // user accessing db
       DATA  cPassword               // his/her password
       DATA  lError                  // .T. if occurred an error
       DATA  nPort
       DATA  nFlags
       DATA  cCreateQuery

       METHOD   New( cServer, cUser, cPassword, nPort, nFlags ) // Opens connection to a server, returns a server object

       METHOD   Destroy()    INLINE sqlClose( ::nSocket ), Self
                                                 // Closes connection to server

       METHOD   SelectDB( cDBName )              // Which data base I will use for subsequent queries

       METHOD   CreateDatabase( cDataBase )      // Create an New Mysql Database

       METHOD   ListDBs()            INLINE sqlListDB(::nSocket)
                                                 // returns an array with list of data bases available

       METHOD   DBExist( cDB )       INLINE ( cDB IN ::ListDBs() )
                                                 // return .T. if cTable exist in the database

       METHOD   CreateTable( cTable, aStruct, cPrimaryKey, cUniqueKey, cAuto)
                                                 // Create new table using the same syntax of dbCreate()

       METHOD   DeleteTable( cTable )            // delete table

       METHOD   TableExist( cTable ) INLINE ( cTable IN ::ListTables() )
                                                 // return .T. if cTable exist in the database

       METHOD   ListTables()         INLINE sqlListTbl(::nSocket)
                                                 // returns an array with list of available tables in current database

       METHOD   TableStruct( cTable )            // returns a structure array compatible with clipper's dbStruct() ones

       METHOD   CreateIndex( cName, cTable, aFNames, lUnique )
                                                 // Create an index (unique) on field name(s) passed as an array of strings aFNames

       METHOD   DeleteIndex( cName, cTable )     // Delete index cName from cTable


       METHOD   Query( cQuery, loRow )           // Gets a textual query and returns a TMySQLQuery or TMySQLTable object

       METHOD   NetErr()             INLINE ::lError
                                                 // Returns .T. if something went wrong

       METHOD   Error()                          // Returns textual description of last error

    ENDCLASS


    METHOD New( cServer, cUser, cPassword, nPort, nFlags ) CLASS TMySQLServer

       ::cServer   := cServer
       ::cUser     := cUser
       ::cPassword := cPassword
       ::nPort     := nPort
       ::nFlags    := nFlags
       ::nSocket   := sqlConnect(cServer, cUser, cPassword, nPort, nFlags )
       ::lError    := .F.

       if ::nSocket == 0
          ::lError := .T.
       endif

    return Self


    METHOD SelectDB( cDBName ) CLASS TMySQLServer

       ::lError := .F.

       if sqlSelectD( ::nSocket, cDBName ) != 0   // table not exist
          ::cDBName :=""
          ::lError  := .T.
       else                                       // table exist
          ::cDBName := cDBName
          ::lError  := .F.
          return .T.
       endif

    return .F.

     

    METHOD CreateDatabase ( cDataBase ) CLASS TMySQLServer
       local cCreateQuery := "CREATE DATABASE "+ lower( cDatabase )

       if sqlQuery( ::nSocket, cCreateQuery ) == 0
          return .T.
       endif

    return .F.


    // NOTE: OS/2 port of MySQL is picky about table names, that is if you create a table with
    // an upper case name you cannot alter it (for example) using a lower case name, this violates
    // OS/2 case insensibility about names
    METHOD CreateTable( cTable, aStruct, cPrimaryKey, cUniqueKey, cAuto ) CLASS TMySQLServer

       /* NOTE: all table names are created with lower case */

       local aField

       // returns NOT NULL if extended structure has DBS_NOTNULL field to true
       local cNN := {| aArr | iif( Len( aArr ) > DBS_DEC, iif( aArr[ DBS_NOTNULL ], " NOT NULL ", "" ), "" ) }


       ::cCreateQuery := "CREATE TABLE " + Lower(cTable) + " ("


       for each aField in aStruct

          switch aField[ DBS_TYPE ]
          case "C"
             ::cCreateQuery += aField[ DBS_NAME ] + " char(" + AllTrim(Str(aField[DBS_LEN])) + ")" + Eval(cNN, aField)+ if(aField[DBS_NAME]==cPrimaryKey," NOT NULL ",'' )+ ","
             exit

          case "M"
             ::cCreateQuery += aField[ DBS_NAME ] + " text" + Eval(cNN, aField) + ","
             exit

          case "N"

             if aField[ DBS_DEC ] == 0 .and. aField[ DBS_LEN ] <= 18

                do case
                   case aField[ DBS_LEN ] <= 4
                      ::cCreateQuery += aField[ DBS_NAME ] + " smallint("  + AllTrim( Str( aField[ DBS_LEN ] ) ) + ")"

                   case aField[ DBS_LEN ] <= 6
                      ::cCreateQuery += aField[ DBS_NAME ] + " mediumint(" + AllTrim( Str( aField[ DBS_LEN ] ) ) + ")"

                   case aField[ DBS_LEN ] <= 9
                      ::cCreateQuery += aField[ DBS_NAME ] + " int("       + AllTrim( Str( aField[ DBS_LEN ] ) ) + ")"

                   otherwise
                      ::cCreateQuery += aField[ DBS_NAME ] + " bigint("    + AllTrim( Str( aField[ DBS_LEN ] ) ) + ")"

                endcase

                ::cCreateQuery += Eval( cNN, aField ) + if( aField[ DBS_NAME ] == cPrimaryKey, " NOT NULL ", "" ) + if( aField[ DBS_NAME ] == cAuto, " auto_increment ", "" ) + ","

             else
                ::cCreateQuery += aField[ DBS_NAME ] + " real(" + AllTrim( Str( aField[ DBS_LEN ] ) ) + "," + AllTrim( Str( aField[ DBS_DEC ] ) ) + ")" + Eval( cNN, aField ) + ","

             endif
             exit

          case "D"
             ::cCreateQuery += aField[ DBS_NAME ] + " date " + Eval( cNN, aField ) + ","
             exit

          case "L"
             ::cCreateQuery += aField[ DBS_NAME ] + " tinyint " + Eval( cNN, aField ) + ","
             exit

          case "B"
             ::cCreateQuery += aField[ DBS_NAME ] + " mediumblob " + Eval( cNN, aField ) + ","
             exit

          case "I"
             ::cCreateQuery += aField[ DBS_NAME ] + " mediumint " + Eval( cNN, aField ) + ","
             exit

          case "T"
             ::cCreateQuery += aField[ DBS_NAME ] + " timestamp(" + AllTrim( Str( aField[ DBS_LEN ] ) ) + ")" + Eval( cNN, aField ) + ","
             exit

          default
             ::cCreateQuery += aField[ DBS_NAME ] + " char(" + AllTrim(Str(aField[DBS_LEN])) + ")" + Eval( cNN, aField ) + ","

          end

       next

       if cPrimarykey != NIL
            ::cCreateQuery += ' PRIMARY KEY (' + cPrimaryKey + '),'
       endif

       if cUniquekey != NIL
            ::cCreateQuery += ' UNIQUE ' + cUniquekey + ' (' + cUniqueKey + '),'
       endif

       // remove last comma from list
       ::cCreateQuery := Left( ::cCreateQuery, Len( ::cCreateQuery ) - 1 ) + ");"

       if sqlQuery( ::nSocket, ::cCreateQuery ) == 0
          return .T.
       else
          ::lError := .T.
       endif

    return .F.


    METHOD CreateIndex( cName, cTable, aFNames, lUnique ) CLASS TMySQLServer

       local cCreateQuery := "CREATE "
       local cField

       default lUnique to .F.

       if lUnique
          cCreateQuery += "UNIQUE INDEX "
       else
          cCreateQuery += "INDEX "
       endif

       cCreateQuery += cName + " ON " + Lower( cTable ) + " ("

       for each cField in aFNames
          cCreateQuery += cField + ","
       next

       // remove last comma from list
       cCreateQuery := Left( cCreateQuery, Len( cCreateQuery ) - 1 ) + ")"

       if sqlQuery( ::nSocket, cCreateQuery ) == 0
          return .T.
       endif

    return .F.


    METHOD DeleteIndex( cName, cTable ) CLASS TMySQLServer

       local cDropQuery := "DROP INDEX " + cName + " FROM " + Lower( cTable )

       if sqlQuery( ::nSocket, cDropQuery ) == 0
          return .T.
       endif

    return .F.


    METHOD DeleteTable( cTable ) CLASS TMySQLServer

       local cDropQuery := "DROP TABLE " + Lower( cTable )

       if sqlQuery( ::nSocket, cDropQuery ) == 0
          return .T.

       endif

    return .F.


    METHOD Query( cQuery, loRow ) CLASS TMySQLServer

       local oQuery, cTableName, i, cUpperQuery, nNumTables, cToken

       default cQuery to ""


       cUpperQuery := Upper( AllTrim( cQuery ) )
       i           := 1
       nNumTables  := 1

       while (cToken := __StrToken( cUpperQuery, i++, " " ) ) <> "FROM" .AND. !Empty( cToken )
       enddo

       // first token after "FROM" is a table name
       // NOTE: SubSelects ?
       cTableName := __StrToken( cUpperQuery, i++, " " )

       while ( cToken := __StrToken( cUpperQuery, i++, " " ) ) <> "WHERE" .AND. !Empty( cToken )
          // do we have more than one table referenced ?
          if cToken == "," .OR. cToken == "JOIN"
             nNumTables++
          endif
       enddo

       if nNumTables == 1
          oQuery := TMySQLTable():New( ::nSocket, cQuery, cTableName, loRow )
       else
          oQuery := TMySQLQuery():New(::nSocket, cQuery, loRow )
       endif

       if oQuery:NetErr()
          ::lError := .T.
       endif

    return oQuery


    METHOD Error() CLASS TMySQLServer

       ::lError := .F.

    return iif(::nSocket > 0, sqlGetErr(::nSocket), "No connection to server")


    /* TOFIX: Conversion creates a .dbf with fields of wrong dimension (often) */
    METHOD TableStruct( cTable ) CLASS TMySQLServer

       local nRes, aField, aStruct, aSField, i


       aStruct := {}

       /* TODO: rewrite for MySQL */
       nRes := sqlListF( ::nSocket, cTable )

       if nRes > 0
          for i := 1 to sqlNumFi( nRes )

             aField  := sqlFetchF( nRes )
             aSField := Array( DBS_DEC )

             // don't count indexes as real fields
    //         if aField[ MYSQL_FS_TYPE ] <= MYSQL_LAST_REAL_TYPE

                aSField[ DBS_NAME ] := Left( aField[ MYSQL_FS_NAME ], 10 )
                aSField[ DBS_DEC  ] := 0

                asField[ DBS_TYPE ] :=  SQL2ClipType( aField[ MYSQL_FS_TYPE ] )

                switch aField[ MYSQL_FS_TYPE ]
                case MYSQL_TINY_TYPE
                   aSField[ DBS_TYPE ] := "L"
                   aSField[ DBS_LEN ]  := 1
                   exit

                case MYSQL_SHORT_TYPE
                   aSField[ DBS_TYPE ] := "N"
                   aSField[ DBS_LEN ]  := Min( 6, aField[ MYSQL_FS_LENGTH ] )
                   exit

                case MYSQL_INT24_TYPE
                   aSField[ DBS_TYPE ] := "N"
                   aSField[ DBS_LEN ]  := Min( 8, aField[ MYSQL_FS_LENGTH ] )
                   exit

                case MYSQL_LONG_TYPE
                   aSField[ DBS_TYPE ] := "N"
                   aSField[ DBS_LEN ]  := Min( 11, aField[ MYSQL_FS_LENGTH ] )
                   exit

                case MYSQL_LONGLONG_TYPE
                   aSField[ DBS_TYPE ] := "N"
                   aSField[ DBS_LEN ]  := Min( 20, aField[ MYSQL_FS_LENGTH ] )
                   exit

                case MYSQL_FLOAT_TYPE
                case MYSQL_DOUBLE_TYPE
                case MYSQL_DECIMAL_TYPE
                   aSField[ DBS_TYPE ] := "N"
                   aSField[ DBS_LEN ] := aField[ MYSQL_FS_LENGTH ]
                   aSFIeld[ DBS_DEC ] := aField[ MYSQL_FS_DECIMALS ]
                   exit

    /*            case FIELD_TYPE_INT24
                   aSField[ DBS_TYPE ] := "I"
                   aSField[ DBS_LEN ] := aField[ MYSQL_FS_LENGTH ]
                   aSFIeld[ DBS_DEC ] := aField[ MYSQL_FS_DECIMALS ]
                   exit  */

                case MYSQL_STRING_TYPE
                case MYSQL_VAR_STRING_TYPE
                case MYSQL_DATETIME_TYPE
                case MYSQL_TIME_TYPE
                   aSField[ DBS_TYPE ] := "C"
                   aSField[ DBS_LEN ] := aField[ MYSQL_FS_LENGTH ]
                   exit

                case MYSQL_DATE_TYPE
                   aSField[ DBS_TYPE ] := "D"
                   aSField[ DBS_LEN ] := 8
                   exit

                case MYSQL_MEDIUM_BLOB_TYPE
                   aSField[ DBS_TYPE ] := "B"
                   aSField[ DBS_LEN ] := aField[ MYSQL_FS_LENGTH ]
                   exit

                case MYSQL_BLOB_TYPE
                   aSField[ DBS_TYPE ] := "M"
                   aSField[ DBS_LEN ] := 10
                   exit

                case MYSQL_TIMESTAMP_TYPE
                   aSField[ DBS_TYPE ] := "N"
                   aSField[ DBS_LEN ]  := aField[ MYSQL_FS_LENGTH ]
                   exit

                default
                   aSField[ DBS_TYPE ] := "C"
                   aSField[ DBS_LEN ] := aField[ MYSQL_FS_LENGTH ]

                end

                AAdd( aStruct, aSField )
    //         endif
          next

          sqlFreeR( nRes )

       endif

    return aStruct


    // Returns an SQL string with clipper value converted ie. Date() -> "'YYYY-MM-DD'"
    static function ClipValue2SQL(Value, cType)

       local cValue := ""
    //   local cDateFormat := Lower( Set( 4 ) )

       Default cType to ValType( Value )

       switch cType
          case "N"
          case "I"
             cValue := AllTrim( Str( Value ) )
             exit

          case "D"
             if !Empty( Value )
                // MySQL dates are like YYYY-MM-DD or YYYYMMDD
                cValue := "'" + Transform( Dtos( Value ), "@R 9999-99-99" ) + "'"
    /*
                if cDateFormat == 'mm-dd-yyyy' // USA
                   cValue := "'"+PadL(Month(Value), 2, "0") + '-'+ PadL(Day(Value), 2, "0") + "-" + Str(Year(Value), 4) + "'"
                elseif  cDateFormat == 'dd/mm/yyyy' // BRITISH ou FRENCH
                   //cValue := "'"+PadL(Day(Value), 2, "0") + "/" + PadL(Month(Value), 2, "0") + "/" + Str(Year(Value), 4) + "'"
                   cValue := "'"+Str(Year(Value), 4) + "-" + PadL(Month(Value), 2, "0") + "-" + PadL(Day(Value), 2, "0") + "'"
                elseif cDateFormat == 'yyyy.mm.dd' // ANSI
                   cValue := "'"+Str(Year(Value), 4)  + "." + PadL(Month(Value), 2, "0") + "." + PadL(Day(Value), 2, "0") + "'"
                elseif cDateFormat == 'dd.mm.yyyy' //GERMAN
                   cValue := "'"+PadL(Day(Value), 2, "0") + "." + PadL(Month(Value), 2, "0") + "." + Str(Year(Value), 4) +  "'"
                elseif cDateFormat == 'dd-mm-yyyy'  //ITALIAN
                   cValue := "'"+PadL(Day(Value), 2, "0") + "-" + PadL(Month(Value), 2, "0") + "-" + Str(Year(Value), 4)  + "'"
                elseif cDateFormat == 'yyyy/mm/dd' //JAPAN
                   cValue := "'"+Str(Year(Value), 4)  + "/" + PadL(Month(Value), 2, "0") + "/" + PadL(Day(Value), 2, "0") + "'"
                elseif cDateFormat == 'mm/dd/yyyy' // AMERICAN
                   cValue := "'"+Str(Year(Value), 4)     + "/" + PadL(Month(Value), 2, "0") + "/" + PadL(Day(Value), 2, "0") + "'"
                endif
    */
             else
                cValue := "''"
             endif
             exit

          case "C"
          case "M"
          case "B"
             IF Empty( Value)
                cValue := "''"
             ELSE
                cValue := "'" + DATATOSQL( value ) + "'"
             ENDIF
             exit

          case "L"
             cValue := AllTrim( Str( iif(Value, 1, 0 ) ) )
             exit

          case "T"
             cValue := iif( Value < 0, "NULL", Alltrim( str( Value ) ) )
             exit

          default
             cValue := "''"       // NOTE: Here we lose values we cannot convert

       end

    return cValue


    static function SQL2ClipType( nType )

       switch nType
          case MYSQL_TINY_TYPE
             Return "L"

          case MYSQL_SHORT_TYPE
          case MYSQL_LONG_TYPE
          case MYSQL_LONGLONG_TYPE
          case MYSQL_FLOAT_TYPE
          case MYSQL_DOUBLE_TYPE
          case MYSQL_DECIMAL_TYPE
             Return "N"

          case MYSQL_DATE_TYPE
             Return "D"

          case MYSQL_BLOB_TYPE
             Return "M"

          case MYSQL_VAR_STRING_TYPE
          case MYSQL_STRING_TYPE
          case MYSQL_DATETIME_TYPE
          case MYSQL_TIME_TYPE
             Return "C"

          case MYSQL_INT24_TYPE
             Return "I"

          case MYSQL_MEDIUM_BLOB_TYPE
             Return "B"

          case MYSQL_TIMESTAMP_TYPE
             Return "T"

       end

    Return "U"


    /* Given a three letter month name gives back month number as two char string (ie. Apr -> 04) */
    static function NMonth(cMonthValue)

       static cMonths := {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dec" }
       local nMonth

       nMonth := AScan(cMonths, cMonthValue)

    return PadL(nMonth, 2, "0")


    static function ARRAYBLOCK( nIndex )
       Local bBlock

       bBlock := {|Self, x | iif( PCount() == 1, ::aRow[ nIndex ], ::aRow[ nIndex ] := x ) }

    return bBlock

     

  16.  

    Novos Códigos de Rejeição – NT 2019.001
    Rejeição 305 : Destinatário bloqueado na UF
    Rejeição 306 : IE do destinatário não está ativa na UF
    Rejeição 922: Contranota de Produtor só pode referenciar NF-e ou NF de Produtor Modelo 4
    Rejeição 923: Referenciado documento de operação interna em operação interestadual ou com o exterior
    Rejeição 924: Informado Cupom Fiscal referenciado.
    Rejeição 925: NF-e com identificação de estrangeiro e inscrição estadual informada para destinatário
    Rejeição 926: Operação com Exterior e país de destino igual a Brasil.
    Rejeição 927: Número do item fora da ordem sequencial.
    Rejeição 928: Informado código de benefício fiscal para CST sem benefício fiscal [nItem: nnn]
    Rejeição 929: Informado CST de diferimento sem as informações de diferimento [nItem: nnn]
    Rejeição 930 : CST com benefício fiscal e não informado o código de benefício fiscal [nItem: nnn]
    Rejeição 931 : CST não corresponde ao tipo de código de benefício fiscal [nItem: nnn]
    Rejeição 932: Informada modalidade de determinação da BC da ST como MVA e não informado o campo pMVAST [nItem: nnn]
    Rejeição 933: Informada modalidade de determinação da BC da ST diferente de MVA e informado o campo pMVAST [nItem: nnn]
    Rejeição 934: Não informado valor do ICMS desonerado ou o Motivo de desoneração [nItem: nnn]
    Rejeição 935: Valor total da Base de Cálculo superior ao valor limite estabelecido [Valor Limite: R$ XXX.XXX,XX] (valor definido pela UF)
    Rejeição 936: Razão Social do emitente diverge do informado no cadastro da SEFAZ.

    Mano, tem rejeição nesta lista que parece coisa de português, uma coisa é rejeitar na validação (Consistência na validação), ou é rejeitar no envio,. Parece até piada. 

    Rejeição 925: NF-e com identificação de estrangeiro e inscrição estadual informada para destinatário

    Rejeição 926: Operação com Exterior e país de destino igual a Brasil.

    Rejeição 936: Razão Social do emitente diverge do informado no cadastro da SEFAZ. - Essa chega a ser um absurdo, pois com tantas informações como Cnpj e IE e ainda vão criticar o nome da empresa.

    []s,

  17.  

    Galera, quem está sabendo sobre este no ítem da NF-e? Pode explanar?

     

    8C2Zj3n.jpg

     

    Obg. abs.

    João, boa noite.

    Este registro eu gerava em MG, quando havia diferença de alíquota (Famoso DIFAL de hoje), como o SPED FISCAL é exclusivo das UF's, então MG, criou há muito tempo a tabela de códigos para essa situação, como não faço mais O sped para o cliente de MG há muito tempo, então não sei como está e como será em relação ao campo cBenef do layout da NF-e 4.0.

    Sei que algumas UF's havia divulgado as suas tabelas para isso, mas SP, até o tempo que eu gerava SPED's para os meus clientes não tinha.

    O resultado deste registro é informado na apuração.

    []s,

     

×
×
  • Create New...