Para me ajudar a desenhar e manter as funções para o tratamento dos registros do SPED PIS/COFINS, criei a tabela PISCO.DBF que tem todos os registros e torna fácil a alteração ou inclusão de campos.
download
Ao executar o programa ele irá gerar o codigo fonte necessário para o trabalho pesado.
A saber:
PISCOT.txt - Funcoes para geracao das tabelas/registro com campos
PISCOTC.txt - Funcoes para geracao de todas as tabelas em demanda
PISCOS.txt - Funcoes para geracao do salvamento de dados de cada registro
PISCOR.txt - Funcoes para geracao das linhas formatadas
PISCORG.txt - Funcoes para geracao do conteudo do arquivo digital
Uma biblioteca poderá ser gerada para manter os arquivos acima, já que deverão ser ligados ao corpo principal da geração do arquivo digital.
O corpo principal deverá iniciar mais ou menos como a seguir:
Código: Selecionar todos
FUNCTION GeraSPEDPisCofins(cPath,dDATAINI,dDATAFIM)
public cPath := "c:\sistema"
public SPEDPath := "c:\sistema\sped"
public SPEDFile := "spedpc.txt"
dbCloseAll()
// Gera todas as tabelas de registros
GeraPISCOTabelas()
dbCloseAll()
// Abre tabelas acessorias necessarias
USE &(cPath+"\IBGE") SHARED NEW INDEX &(cPath+"\IBGE")
USE &(cPath+"\CLIENTES") SHARED NEW INDEX &(cPath+"\CLIENTES")
USE &(cPath+"\FORNEC") SHARED NEW INDEX &(cPath+"\FORNEC")
USE &(cPath+"\PEDIDOS") SHARED NEW INDEX &(cPath+"\PN")
USE &(cPath+"\ITENS") SHARED NEW INDEX &(cPath+"\ES")
USE &(cPath+"\UNIDADES") SHARED NEW INDEX &(cPath+"\UNIDADES")
USE &(cPath+"\NATUREZA") SHARED NEW INDEX &(cPath+"\NATUREZA")
USE &(SPEDPath+"\R9001") SHARED NEW
USE &(SPEDPath+"\R9900") SHARED NEW
USE &(SPEDPath+"\R9990") SHARED NEW
USE &(SPEDPath+"\R9999") SHARED NEW
// Monta blocos
GeraPISCOBloco0()
GeraPISCOBlocoA()
GeraPISCOBlocoC()
GeraPISCOBlocoD()
GeraPISCOBlocoF()
GeraPISCOBlocoM()
GeraPISCOBlocoP()
GeraPISCOBloco1()
GeraPISCOBloco9()
SPEDhandle := fCreate( SPEDFile )
GeraPISCORegistros(SPEDhandle)
fClose( SPEDhandle )
return .t.
Código: Selecionar todos
FUNCTION GeraPISCOBloco0()
******************************************************************************************************
******************************************************************************************************
// BLOCO 0: ABERTURA, IDENTIFICAÇÃO E REFERÊNCIAS.
******************************************************************************************************
******************************************************************************************************
USE &(SPEDPath+"\R0000") SHARED NEW
USE &(SPEDPath+"\R0001") SHARED NEW
USE &(SPEDPath+"\R0100") SHARED NEW
USE &(SPEDPath+"\R0110") SHARED NEW
USE &(SPEDPath+"\R0111") SHARED NEW
USE &(SPEDPath+"\R0140") SHARED NEW
USE &(SPEDPath+"\R0150") SHARED NEW
USE &(SPEDPath+"\R0190") SHARED NEW
USE &(SPEDPath+"\R0200") SHARED NEW
USE &(SPEDPath+"\R0205") SHARED NEW
USE &(SPEDPath+"\R0206") SHARED NEW
USE &(SPEDPath+"\R0208") SHARED NEW
USE &(SPEDPath+"\R0400") SHARED NEW
USE &(SPEDPath+"\R0450") SHARED NEW
USE &(SPEDPath+"\R0500") SHARED NEW
USE &(SPEDPath+"\R0600") SHARED NEW
USE &(SPEDPath+"\R0990") SHARED NEW
// ************************ INICIO DA CRITICA DE GERACAO DE BLOCO ************************ //
// Hierarquia
/* 1 2 3 4
R0000
R0001
R0100
R0110
R0111 O (se no registro 0110 o Campo “COD_INC_TRIB” = 1 ou 3 e o Campo “IND_APRO_CRED” = 2) N (se no registro 0110 o Campo “COD_INC_TRIB” = 2 ou o Campo “IND_APRO_CRED” = 1)
R0140
R0150
R0190
R0200
R0205
R0206
R0208
R0400
R0450
R0500
R0600
R0990
*/
******************************************************************************************************
* Carrega as variaveis que serão imputadas na tabela pela função PISCOSalvaR0000()
* Formato da linha que sera gerada pela função PISCORegistroR0000
// |0000|002|0|0||01012012|31012012|LIMPEZA E CONSERVACAO PEMA LTDA|03040285000182||4107207||00|2|
M->REG := '0000' // 01 - Texto fixo contendo ?0000?.
M->COD_VER := '002' // 02 - Código da versão do leiaute conforme a tabela 3.1.1.
M->TIPO_ESCRIT := '0' // 03 - Tipo de escrituração:
// 0 - Original;
// 1 – Retificadora.
M->IND_SIT_ESP := '0' // 04 - Indicador de situação especial:
// 0 - Abertura
// 1 - Cisão
// 2 - Fusão
// 3 - Incorporação
// 4 – Encerramento
M->NUM_REC_ANTERIOR := '' // 05 - Número do Recibo da Escrituração anterior a ser retificada, utilizado quando TIPO_ESCRIT for igual a
M->DT_INI := CharRem( '/', DtoC( dDATAINI ) ) // 06 - Data inicial das informações contidas no arquivo.
M->DT_FIN := CharRem( '/', DtoC( dDATAFIM ) ) // 07 - Data final das informações contidas no arquivo.
M->NOME := ClNome // 08 - Nome empresarial da pessoa jurídica
M->CNPJ := CharRem( './-', ClCNPJ ) // 09 - Número de inscrição do estabelecimento matriz da pessoa jurídica no CNPJ.
M->UF := ClUF // 10 - Sigla da Unidade da Federação da pessoa jurídica.
M->COD_MUN := ClCodMun // 11 - Código do município do domicílio fiscal da pessoa jurídica, conforme a tabela IBGE
M->SUFRAMA := '' // 12 - Inscrição da pessoa jurídica na Suframa
M->IND_NAT_PJ := '00' // 13 - Indicador da natureza da pessoa jurídica:
// 00 – Sociedade empresária em geral
// 01 – Sociedade cooperativa
// 02 – Entidade sujeita ao PIS/Pasep exclusivamente com base na Folha de Salários
M->IND_ATIV := '0' // 14 - Indicador de tipo de atividade preponderante:
// 0 – Industrial ou equiparado a industrial;
// 1 – Prestador de serviços;
// 2 - Atividade de comércio;
// 3 – Atividade financeira;
// 4 – Atividade imobiliária;
// 9 – Outros
* Salva o registro R0000 com dados das variáveis acima
PISCOSalvaR0000() // REGISTRO 0000: ABERTURA DO ARQUIVO DIGITAL E IDENTIFICAÇÃO DA PESSOA JURÍDICA
******************************************************************************************************
cEstado := 'SP'
cCidade := 'SAO PAULO'
******************************************************************************************************
* Carrega as variaveis que serão imputadas na tabela pela função PISCOSalvaR0001()
* Formato da linha que sera gerada pela função PISCORegistroR0001
// |0001|0|
M->REG := '0001' // 01 - Texto fixo contendo ?0001?.
M->IND_MOV := '0' // 02 - Indicador de movimento
// 0 - Bloco com dados informados;
// 1 - Bloco sem dados informados
* Salva o registro R0001 com dados das variáveis acima
PISCOSalvaR0001() // REGISTRO 0001: ABERTURA DO BLOCO 0
******************************************************************************************************
IF M->IND_MOV = '0'
/* *********** INICIO DOS REGISTROS DO BLOCO *********** */
// |0100|Nome do contabilista|00000000000|Numero de Inscr|00000000000000|0|Logradouro e Endereço do Imóvel|Numero do Imovel|Dados Complementares do Endereco|Bairro em que o Imovel esta Situado|Numero do|Numero do|Endereço do Correio Eletronico|0|
...
PISCOSalvaR0100() // REGISTRO 0100: DADOS DO CONTABILISTA
******************************************************************************************************
// |0110|2|2|1|
...
PISCOSalvaR0110() // REGISTRO 0110: REGIMES DE APURAÇÃO DA CONTRIBUIÇÃO SOCIAL E DE APROPRIAÇÃO DE CRÉDITO
******************************************************************************************************
...
/* *********** FINAL DOS REGISTROS DO BLOCO *********** */
ENDIF // IF M->IND_MOV = '0'
// ************************ INICIO DA CRITICA DE GERACAO DE BLOCO ************************ //
******************************************************************************************************
* Gera registro finalizador deste bloco
// |0990|11|
M->REG := '0990' // 01 - Texto fixo contendo "0990"
M->REG_BLC := '0990' // 01 - Texto fixo contendo "0990"
M->QTD_LIN_0 := '1' // 02 - Quantidade total de linhas do Bloco 0
* Salva o registro R0990
PISCOSalvaR0990() // ENCERRAMENTO DO BLOCO 0
******************************************************************************************************
return .t.
******************************************************************************************************
Abaixo um exemplo das funções finalizadoras:
Código: Selecionar todos
FUNCTION GeraPISCOBloco9()
******************************************************************************************************
******************************************************************************************************
// BLOCO 9: CONTROLE E ENCERRAMENTO DO ARQUIVO DIGITAL
******************************************************************************************************
******************************************************************************************************
//USE &(SPEDPath+"\R9001") SHARED NEW
//USE &(SPEDPath+"\R9900") SHARED NEW
//USE &(SPEDPath+"\R9990") SHARED NEW
//USE &(SPEDPath+"\R9999") SHARED NEW
/* 1 2
R9001
R9900
R9990
R9999
*/
//
M->REG := '9001' // 01 - Texto fixo contendo ?9001?.
M->IND_MOV := '0' // 02 - Indicador de movimento:
// 0 - Bloco com dados informados;
// 1 - Bloco sem dados informados
PISCOSalvaR9001() // ENCERRAMENTO DO BLOCO 1
******************************************************************************************************
//
M->REG := '9900' // 01 - Texto fixo contendo ?9900?.
M->REG_BLC := '9900' // 02 - Registro que será totalizado no próximo campo.
M->QTD_REG_BLC := '' // 03 - Total de registros do tipo informado no campo anterior.
//
dbSelectArea('R9900')
M->QTD_REG_BLC := str(recco() + 1 + 2) // Somei 1 porque entra os registros 9990/9999
//
PISCOSalvaR9900() // REGISTROS DO ARQUIVO
******************************************************************************************************
//
dbSelectArea('R9900')
R9900->( dbAppend() )
R9900->CAMPO01 := '9900' // 01 - Texto fixo contendo ?9900?.
R9900->CAMPO02 := '9990' // 02 - Registro que será totalizado no próximo campo.
R9900->CAMPO03 := '1' // 03 - Total de registros do tipo informado no campo anterior.
R9900->( dbCommit() )
//
M->REG := '9990' // 01 - Texto fixo contendo ?9990?.
M->QTD_LIN_9 := '' // 02 - Quantidade total de linhas do Bloco 9.
PISCOSalvaR9990() // ENCERRAMENTO DO BLOCO 9
******************************************************************************************************
//
dbSelectArea('R9900')
R9900->( dbAppend() )
R9900->CAMPO01 := '9900' // 01 - Texto fixo contendo ?9900?.
R9900->CAMPO02 := '9999' // 02 - Registro que será totalizado no próximo campo.
R9900->CAMPO03 := '1' // 03 - Total de registros do tipo informado no campo anterior.
R9900->( dbCommit() )
//
M->REG := '9999' // 01 - Texto fixo contendo ?9999?.
M->QTD_LIN := alltrim(str(MLCount(MemoRead(SPEDFile),500))) // 02 - Quantidade total de linhas do arquivo digital.
PISCOSalvaR9999() // ENCERRAMENTO DO ARQUIVO DIGITAL
******************************************************************************************************
return .t.
******************************************************************************************************
STATIC FUNCTION PISCOSalvaR9001()
// *** Estrutura do Registro R9001 ***
R9001->( dbAppend() )
R9001->CAMPO01 := '9001' // 01 - Texto fixo contendo ?9001?.
R9001->CAMPO02 := M->IND_MOV // 02 - Indicador de movimento:
R9001->( dbCommit() )
//
M->AREA9001 := Select()
M->REG_BLC := '9001'
M->QTD_LIN_9 := ''
M->QTD_REG_BLC := '1'
dbSelectArea('R9900')
PISCOSalvaR9900()
dbSelectArea('R9990')
PISCOSalvaR9990()
dbSelectArea(M->AREA9001)
RETURN nil
FUNCTION PISCOSalvaR9900()
// *** Estrutura do Registro R9900 ***
locate for (R9900->CAMPO02 = M->REG_BLC)
if .not. found()
M->QTD_REG_BLC := '1'
R9900->( dbAppend() )
else
if M->REG_BLC = "0990" .or. M->REG_BLC = "A990" .or. M->REG_BLC = "C990" .or. M->REG_BLC = "D990" .or. ;
M->REG_BLC = "F990" .or. M->REG_BLC = "M990" .or. M->REG_BLC = "1990"
M->QTD_REG_BLC := '1'
else
M->QTD_REG_BLC := alltrim(str(val(R9900->CAMPO03) + 1,6))
endif
R9900->( dbRLock() )
endif
R9900->CAMPO01 := '9900' // 01 - Texto fixo contendo ?9900?.
R9900->CAMPO02 := M->REG_BLC // 02 - Registro que será totalizado no próximo campo.
R9900->CAMPO03 := alltrim(M->QTD_REG_BLC) // 03 - Total de registros do tipo informado no campo anterior.
R9900->( dbCommit() )
//
nR9900 := recco()
locate for (R9900->CAMPO02 = '9900')
if .not. found()
R9900->( dbAppend() )
else
R9900->( dbRLock() )
endif
R9900->CAMPO01 := '9900' // 01 - Texto fixo contendo ?9900?.
R9900->CAMPO02 := '9900' // 02 - Registro que será totalizado no próximo campo.
R9900->CAMPO03 := alltrim(str(nR9900+2,6)) // 03 - Total de registros do tipo informado no campo anterior.
R9900->( dbCommit() )
//
M->AREA9900 := Select()
//M->REG_BLC := '9900'
M->QTD_LIN_9 := ''
M->QTD_REG_BLC := '1'
dbSelectArea('R9990')
PISCOSalvaR9990()
dbSelectArea(M->AREA9900)
RETURN nil
STATIC FUNCTION PISCOSalvaR9990()
// *** Estrutura do Registro R9990 ***
dbSelectArea('R9900')
nR9990 := recco()
M->QTD_LIN_9 := alltrim(str(nR9990+1+2,6)) // Somei 2 porque entra os registros 9990
dbSelectArea('R9990')
if recco() = 0
R9990->( dbAppend() )
else
R9990->( dbRLock() )
endif
R9990->CAMPO01 := '9990' // 01 - Texto fixo contendo ?9990?.
R9990->CAMPO02 := M->QTD_LIN_9 // 02 - Quantidade total de linhas do Bloco 9.
R9990->( dbCommit() )
RETURN nil
STATIC FUNCTION PISCOSalvaR9999()
// *** Estrutura do Registro R9999 ***
R9999->( dbAppend() )
R9999->CAMPO01 := '9999' // 01 - Texto fixo contendo ?9999?.
R9999->CAMPO02 := M->QTD_LIN // 02 - Quantidade total de linhas do arquivo digital.
R9999->( dbCommit() )
//
M->AREA9999 := Select()
M->REG_BLC := '9999'
M->QTD_LIN_9 := ''
M->QTD_REG_BLC := ''
dbSelectArea('R9990')
PISCOSalvaR9990()
dbSelectArea(M->AREA9999)
RETURN nil
Espero que sirva de idéia.

