openerp-brazil-team team mailing list archive
-
openerp-brazil-team team
-
Mailing list archive
-
Message #01398
[Merge] lp:~g-joao-p/openerp.pt-br-localiz/vanzuita into lp:openerp.pt-br-localiz
João Vanzuita has proposed merging lp:~g-joao-p/openerp.pt-br-localiz/vanzuita into lp:openerp.pt-br-localiz.
Requested reviews:
OpenERP Brazil Core Team (openerp-brazil-core-team)
For more details, see:
https://code.launchpad.net/~g-joao-p/openerp.pt-br-localiz/vanzuita/+merge/116177
O tratamento p/ CST 101 mesmo configurando as regras fiscais ainda não consegui deixa-la 100%, portanto gostaria que esse tratamento não fosse incluído no merge.
--
https://code.launchpad.net/~g-joao-p/openerp.pt-br-localiz/vanzuita/+merge/116177
Your team OpenERP Brazil Team is subscribed to branch lp:openerp.pt-br-localiz.
=== modified file 'l10n_br_account/account_invoice.py'
--- l10n_br_account/account_invoice.py 2012-06-08 22:38:40 +0000
+++ l10n_br_account/account_invoice.py 2012-07-23 00:53:18 +0000
@@ -26,7 +26,7 @@
import re
import string
from unicodedata import normalize
-
+from itertools import cycle
from osv import fields, osv
from tools.translate import _
import decimal_precision as dp
@@ -222,7 +222,7 @@
\n* The \'Pro-forma\' when invoice is in Pro-forma state,invoice does not have an invoice number. \
\n* The \'Open\' state is used when user create invoice,a invoice number is generated.Its in open state till user does not pay invoice. \
\n* The \'Paid\' state is set automatically when invoice is paid.\
- \n* The \'sefaz_out\' Gerado aquivo de exportação para sistema daReceita.\
+ \n* The \'sefaz_out\' Gerado aquivo de exportação para sistema da Receita.\
\n* The \'sefaz_aut\' Recebido arquivo de autolização da Receita.\
\n* The \'Cancelled\' state is used when user cancel invoice.'),
'partner_shipping_id': fields.many2one('res.partner.address', 'Endereço de Entrega', readonly=True, states={'draft': [('readonly', False)]}, help="Shipping address for current sales order."),
@@ -419,9 +419,19 @@
i -= 1
return result
- def nfe_dv(self, key):
- #Testing
- return '2'
+ #
+ # Calcula dígito verificador da NFe (módulo 11)
+ #
+ def nfe_digito_verificador(self, key):
+
+ numeros = reversed(map(int, key))
+ soma = sum(n * m for n, m in zip(numeros, cycle(range(2,10))))
+ resto = soma % 11
+
+ if resto < 2:
+ return '0'
+ else:
+ return str(11 - resto)
def nfe_check(self, cr, uid, ids, context=None):
strErro = u''
@@ -660,7 +670,7 @@
'tpAmb': nfe_environment,
'finNFe': '1',
'procEmi': '0',
- 'VerProc': '2.0.9',
+ 'VerProc': '2.2.0',
'dhCont': '',
'xJust': '',
}
@@ -799,14 +809,35 @@
StrFile += StrG0
+ total_discount = 0
i = 0
for inv_line in inv.invoice_line:
i += 1
+
+ total_discount += inv_line.discount
StrH = 'H|%s||\n' % (i)
StrFile += StrH
-
+
+ #
+ # Se frete por conta do receptor (1, 2)
+ # divide o valor total do frete pelo número de produtos
+ #
+ if inv.incoterm.freight_responsibility in ('1', '2') and inv.amount_freight > 0:
+ product_freight_price = ("%.2f" % (inv.amount_freight / len(inv.invoice_line)))
+ else:
+ product_freight_price = ''
+
+ total_untaxed = inv_line.price_unit * inv_line.quantity
+ product_discount_value = total_untaxed - inv_line.price_total
+
+ # Se não houver desconto, deixa campo vaziu
+ if (product_discount_value > 0):
+ product_discount_value = ("%.2f" % product_discount_value)
+ else:
+ product_discount_value = ''
+
StrRegI = {
'CProd': normalize('NFKD',unicode(inv_line.product_id.code or '',)).encode('ASCII','ignore'),
'CEAN': inv_line.product_id.ean13 or '',
@@ -816,15 +847,15 @@
'CFOP': inv_line.cfop_id.code,
'UCom': normalize('NFKD',unicode(inv_line.uos_id.name or '',)).encode('ASCII','ignore'),
'QCom': str("%.4f" % inv_line.quantity),
- 'VUnCom': str("%.2f" % (inv_line.price_unit * (1-(inv_line.discount or 0.0)/100.0))),
- 'VProd': str("%.2f" % inv_line.price_total),
+ 'VUnCom': str("%.2f" % inv_line.price_unit),
+ 'VProd': str("%.2f" % total_untaxed),
'CEANTrib': inv_line.product_id.ean13 or '',
'UTrib': inv_line.uos_id.name,
'QTrib': str("%.4f" % inv_line.quantity),
'VUnTrib': str("%.2f" % inv_line.price_unit),
- 'VFrete': '',
+ 'VFrete': product_freight_price,
'VSeg': '',
- 'VDesc': '',
+ 'VDesc': product_discount_value,
'vOutro': '',
'indTot': '1',
'xPed': '',
@@ -956,6 +987,39 @@
StrFile += StrN09
+ #
+ # implementação para CST 101 no Simples Nacional
+ #
+ if inv_line.icms_cst in ('101'):
+
+ StrRegN10c = {
+ 'Orig': inv_line.product_id.origin or '0',
+ 'CSOSN': inv_line.icms_cst,
+ 'pCredSN': str("%.2f" % 2.87),
+ 'vCredICMSSN': str("%.2f" % (inv_line.price_subtotal * 0.0287)),
+ }
+
+ StrN10c = 'N10c|%s|%s|%s|%s|\n' % (StrRegN10c['Orig'],
+ StrRegN10c['CSOSN'],
+ StrRegN10c['pCredSN'],
+ StrRegN10c['vCredICMSSN'])
+ StrFile += StrN10c
+
+ #
+ # implementação para CST 102, 103, 300 e 400 no Simples Nacional
+ #
+ if inv_line.icms_cst in ('102', '103', '300', '400'):
+
+ StrRegN10d = {
+ 'Orig': inv_line.product_id.origin or '0',
+ 'CSOSN': inv_line.icms_cst,
+ }
+
+ StrN10d = 'N10d|%s|%s|\n' % (StrRegN10d['Orig'],
+ StrRegN10d['CSOSN'])
+
+ StrFile += StrN10d
+
if inv_line.icms_cst in ('90', '900'):
StrRegN10h = {
'Orig': inv_line.product_id.origin or '0',
@@ -1134,22 +1198,62 @@
StrW = 'W|\n'
StrFile += StrW
+
+ #
+ # Tratamento para notas fiscais com desconto
+ #
+ # Configura os valores para o valor total da NFe e valor com desconto
+ #
+ if total_discount > 0:
+ # porcentagem de desconto total
+ total_percent_discount = total_discount / i
+
+ # total sem desconto (vNF)
+ aux_amount_total = inv.amount_total / (100 - total_percent_discount) * 100
+
+ # valor do desconto (vDesc)
+ discount_value = aux_amount_total - inv.amount_total
+ else:
+ aux_amount_total = inv.amount_total
+ discount_value = '0.00'
+
+ #
+ # Se frete por conta do receptor (1, 2),
+ # adiciona valor do frete no valor total da NFe
+ #
+ if inv.incoterm.freight_responsibility in ('1', '2') and total_discount == 0:
+ product_freight_price = inv.amount_freight + aux_amount_total
+ elif inv.incoterm.freight_responsibility in ('1', '2') and total_discount > 0:
+ product_freight_price = (aux_amount_total - discount_value) + inv.amount_freight
+ elif inv.incoterm.freight_responsibility not in ('1', '2') and total_discount > 0:
+ product_freight_price = aux_amount_total - discount_value
+ else:
+ product_freight_price = aux_amount_total
+
+ if inv.amount_freight == 0:
+ inv.amount_freight = '0.00'
+ else:
+ inv.amount_freight = str("%.2f" % inv.amount_freight)
+
+ # valor do desconto
+ discount_value = aux_amount_total - inv.amount_total,
+
StrRegW02 = {
'vBC': str("%.2f" % inv.icms_base),
'vICMS': str("%.2f" % inv.icms_value),
'vBCST': str("%.2f" % inv.icms_st_base),
'vST': str("%.2f" % inv.icms_st_value),
- 'vProd': str("%.2f" % inv.amount_untaxed),
- 'vFrete': str("%.2f" % inv.amount_freight),
+ 'vProd': str("%.2f" % aux_amount_total),
+ 'vFrete': inv.amount_freight,
'vSeg': str("%.2f" % inv.amount_insurance),
- 'vDesc': '0.00',
+ 'vDesc': str("%.2f" % discount_value),
'vII': '0.00',
'vIPI': str("%.2f" % inv.ipi_value),
'vPIS': str("%.2f" % inv.pis_value),
'vCOFINS': str("%.2f" % inv.cofins_value),
'vOutro': str("%.2f" % inv.amount_costs),
- 'vNF': str("%.2f" % inv.amount_total),
+ 'vNF': str("%.2f" % product_freight_price),
}
StrW02 = 'W02|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|\n' % (StrRegW02['vBC'], StrRegW02['vICMS'], StrRegW02['vBCST'], StrRegW02['vST'], StrRegW02['vProd'],
@@ -1158,7 +1262,13 @@
StrFile += StrW02
- # Modo do Frete: 0- Por conta do emitente; 1- Por conta do destinatário/remetente; 2- Por conta de terceiros; 9- Sem frete (v2.0)
+ #
+ # Modalidade do Frete:
+ # 0 - Por conta do emitente
+ # 1 - Por conta do destinatário/remetente
+ # 2 - Por conta de terceiros
+ # 9 - Sem frete
+ #
if not inv.incoterm:
StrRegX0 = '9'
else:
@@ -1168,12 +1278,16 @@
StrFile += StrX
+ #
+ # Transportador / Volumes Transportados
+ #
+
StrRegX03 = {
- 'XNome': '',
+ 'xNome': '',
'IE': '',
- 'XEnder': '',
+ 'xEnder': '',
'UF': '',
- 'XMun': '',
+ 'xMun': '',
}
StrX0 = ''
@@ -1185,9 +1299,9 @@
carrier_addr_default = self.pool.get('res.partner.address').browse(cr, uid, [carrier_addr['default']])[0]
if inv.carrier_id.partner_id.legal_name:
- StrRegX03['XNome'] = normalize('NFKD', unicode(inv.carrier_id.partner_id.legal_name or '')).encode('ASCII', 'ignore')
+ StrRegX03['xNome'] = normalize('NFKD', unicode(inv.carrier_id.partner_id.legal_name or '')).encode('ASCII', 'ignore')
else:
- StrRegX03['XNome'] = normalize('NFKD', unicode(inv.carrier_id.partner_id.name or '')).encode('ASCII', 'ignore')
+ StrRegX03['xNome'] = normalize('NFKD', unicode(inv.carrier_id.partner_id.name or '')).encode('ASCII', 'ignore')
StrRegX03['IE'] = inv.carrier_id.partner_id.inscr_est or ''
StrRegX03['XEnder'] = normalize('NFKD', unicode(carrier_addr_default.street or '')).encode('ASCII', 'ignore')
@@ -1200,9 +1314,9 @@
StrX0 = 'X04|%s|\n' % (re.sub('[%s]' % re.escape(string.punctuation), '', inv.carrier_id.partner_id.cnpj_cpf or ''))
else:
StrX0 = 'X05|%s|\n' % (re.sub('[%s]' % re.escape(string.punctuation), '', inv.carrier_id.partner_id.cnpj_cpf or ''))
-
- StrX03 = 'X03|%s|%s|%s|%s|%s|\n' % (StrRegX03['XNome'], StrRegX03['IE'], StrRegX03['XEnder'], StrRegX03['UF'], StrRegX03['XMun'])
-
+
+ StrX03 = 'X03|%s|%s|%s|%s|%s|\n' % (StrRegX03['xNome'], StrRegX03['IE'], StrRegX03['xEnder'], StrRegX03['UF'], StrRegX03['xMun'])
+
StrFile += StrX03
StrFile += StrX0
@@ -1212,15 +1326,16 @@
'RNTC': '',
}
+ #
+ # Adiciona informações do veículo se ela existir
+ #
if inv.vehicle_id:
StrRegX18['Placa'] = inv.vehicle_id.plate or ''
StrRegX18['UF'] = inv.vehicle_id.plate.state_id.code or ''
StrRegX18['RNTC'] = inv.vehicle_id.rntc_code or ''
-
-
- StrX18 = 'X18|%s|%s|%s|\n' % (StrRegX18['Placa'], StrRegX18['UF'], StrRegX18['RNTC'])
-
- StrFile += StrX18
+
+ StrX18 = 'X18|%s|%s|%s|\n' % (StrRegX18['Placa'], StrRegX18['UF'], StrRegX18['RNTC'])
+ StrFile += StrX18
StrRegX26 = {
'QVol': '',
@@ -1283,17 +1398,34 @@
company_addr = self.pool.get('res.partner').address_get(cr, uid, [inv.company_id.partner_id.id], ['default'])
company_addr_default = self.pool.get('res.partner.address').browse(cr, uid, [company_addr['default']], context={'lang': 'pt_BR'})[0]
- #MontaChave da Nota Fiscal Eletronica
- nfe_key = unicode(company_addr_default.state_id.ibge_code).strip().rjust(2, u'0')
- nfe_key += unicode(datetime.strptime(inv.date_invoice, '%Y-%m-%d').strftime(u'%y%m')).strip().rjust(4, u'0')
- nfe_key += '08478495000170' # unicode(inv.company_id.partner_id.cnpj_cpf).strip().rjust(14, u'0')
- nfe_key += inv.fiscal_document_id.code
- nfe_key += unicode(inv.document_serie_id.code).strip().rjust(3, u'0')
- nfe_key += unicode(inv.internal_number).strip().rjust(9, u'0')
- nfe_key += unicode('1').strip().rjust(1, u'0') # Homologação
- nfe_key += unicode(inv.internal_number).strip().rjust(8, u'0')
- nfe_key += unicode(self.nfe_dv(nfe_key)).strip().rjust(1, u'0')
-
+ #
+ # Monta Chave de Acesso da NFe
+ #
+
+ chave_de_acesso_nfe = self.nfe_chave_de_acesso(company_addr_default.state_id.ibge_code, inv.date_invoice, inv.company_id.partner_id.cnpj_cpf, inv.fiscal_document_id.code, inv.document_serie_id.code, inv.internal_number)
+
+ nfe_key = company_addr_default.state_id.ibge_code # código IBGE
+ nfe_key += inv.date_invoice[2:4] + inv.date_invoice[5:7] # data no formato AAMM
+ nfe_key += self.clean_string(inv.company_id.partner_id.cnpj_cpf) # CNPJ
+ nfe_key += inv.fiscal_document_id.code # modelo
+ nfe_key += inv.document_serie_id.code.zfill(3) #série
+ nfe_key += str(inv.internal_number).zfill(9) # nr. da NFe
+ nfe_key += '1' # tipo de emissão 1=normal
+ nfe_key += str(inv.internal_number).zfill(8) # código numérico
+
+ # remove pontuação da string
+ nfe_key = self.clean_string(nfe_key)
+
+ # calcula digito verificador
+ aux_cod_verificador = self.nfe_digito_verificador(nfe_key)
+ nfe_key += aux_cod_verificador
+
+ # adiciona string NFe ao inicio da chave
+ nfe_key = "".join(('NFe', nfe_key))
+
+ #
+ # Inicio das tags do XML
+ #
NFe = SubElement(nfeProc, 'NFe', { 'xmlns': 'http://www.portalfiscal.inf.br/nfe' })
infNFe = SubElement(NFe, 'infNFe', {'versao': '2.00', 'Id': nfe_key })
@@ -1308,7 +1440,7 @@
ide_cNF.text = unicode(inv.internal_number).strip().rjust(8, u'0')
ide_natOp = SubElement(ide, 'natOp')
- ide_natOp.text = inv.cfop_ids[0].name
+ ide_natOp.text = self.clean_string(inv.cfop_ids[0].name)
ide_indPag = SubElement(ide, 'indPag')
ide_indPag.text = "2"
@@ -1329,7 +1461,8 @@
ide_dSaiEnt.text = inv.date_invoice
ide_tpNF = SubElement(ide, 'tpNF')
- if inv.type in ("out_invoice", "in_refuld"):
+
+ if inv.cfop_ids[0].type in ("input"):
ide_tpNF.text = '0'
else:
ide_tpNF.text = '1'
@@ -1344,11 +1477,11 @@
ide_tpEmis.text = "1"
ide_cDV = SubElement(ide, 'cDV')
- ide_cDV.text = self.nfe_dv(nfe_key)
+ ide_cDV.text = aux_cod_verificador
#Tipo de ambiente: 1 - Produção; 2 - Homologação
ide_tpAmb = SubElement(ide, 'tpAmb')
- ide_tpAmb.text = "2"
+ ide_tpAmb.text = nfe_environment
#Finalidade da emissão da NF-e: 1 - NFe normal 2 - NFe complementar 3 - NFe de ajuste
ide_finNFe = SubElement(ide, 'finNFe')
@@ -1363,10 +1496,10 @@
emit = SubElement(infNFe, 'emit')
emit_CNPJ = SubElement(emit, 'CNPJ')
- emit_CNPJ.text = inv.company_id.partner_id.cnpj_cpf
+ emit_CNPJ.text = self.clean_string(inv.company_id.partner_id.cnpj_cpf)
emit_xNome = SubElement(emit, 'xNome')
- emit_xNome.text = inv.company_id.partner_id.legal_name
+ emit_xNome.text = self.clean_string(inv.company_id.partner_id.legal_name)
emit_xFant = SubElement(emit, 'xFant')
emit_xFant.text = inv.company_id.partner_id.name
@@ -1392,7 +1525,7 @@
enderEmit_UF.text = company_addr_default.state_id.code
enderEmit_CEP = SubElement(enderEmit, 'CEP')
- enderEmit_CEP.text = company_addr_default.zip
+ enderEmit_CEP.text = self.clean_string(company_addr_default.zip)
enderEmit_cPais = SubElement(enderEmit, 'cPais')
enderEmit_cPais.text = company_addr_default.country_id.bc_code
@@ -1400,8 +1533,11 @@
enderEmit_xPais = SubElement(enderEmit, 'xPais')
enderEmit_xPais.text = company_addr_default.country_id.name
- enderEmit_fone = SubElement(enderEmit, 'fone')
- enderEmit_fone.text = company_addr_default.phone
+ # adiciona telefone se ele existir
+
+ if company_addr_default.phone:
+ enderEmit_fone = SubElement(enderEmit, 'fone')
+ enderEmit_fone.text = str(company_addr_default.phone)
emit_IE = SubElement(emit, 'IE')
emit_IE.text = inv.company_id.partner_id.inscr_est
@@ -1416,15 +1552,18 @@
emit_CNAE.text = '0111301' #FIXME
emit_CRT = SubElement(emit, 'CRT')
- emit_CRT.text = '3' #FIXME
+ emit_CRT.text = inv.company_id.fiscal_type
dest = SubElement(infNFe, 'dest')
dest_CNPJ = SubElement(dest, 'CNPJ')
- dest_CNPJ.text = inv.partner_id.cnpj_cpf
+ dest_CNPJ.text = self.clean_string(inv.partner_id.cnpj_cpf)
dest_xNome = SubElement(dest, 'xNome')
- dest_xNome.text = inv.partner_id.legal_name
+ if nfe_environment == 1:
+ dest_xNome.text = inv.partner_id.legal_name
+ else:
+ dest_xNome.text = 'NF-E EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL'
enderDest = SubElement(dest, 'enderDest')
@@ -1447,7 +1586,7 @@
enderDest_UF.text = inv.address_invoice_id.state_id.code
enderDest_CEP = SubElement(enderDest, 'CEP')
- enderDest_CEP.text = inv.address_invoice_id.zip
+ enderDest_CEP.text = self.clean_string(inv.address_invoice_id.zip)
enderDest_cPais = SubElement(enderDest, 'cPais')
enderDest_cPais.text = inv.address_invoice_id.country_id.bc_code
@@ -1455,15 +1594,22 @@
enderDest_xPais = SubElement(enderDest, 'xPais')
enderDest_xPais.text = inv.address_invoice_id.country_id.name
- enderDest_fone = SubElement(enderDest, 'fone')
- enderDest_fone.text = inv.address_invoice_id.phone
+ # adiciona fone se ele estiver cadastrado
+
+ if inv.address_invoice_id.phone:
+ enderDest_fone = SubElement(enderDest, 'fone')
+ enderDest_fone.text = str(inv.address_invoice_id.phone)
dest_IE = SubElement(dest, 'IE')
- dest_IE.text = inv.partner_id.inscr_est
+ dest_IE.text = self.clean_string(inv.partner_id.inscr_est)
- i = 0
+ total_discount = 0
+ i = 0
for inv_line in inv.invoice_line:
i += 1
+
+ total_discount += inv_line.discount
+
det = SubElement(infNFe, 'det', {'nItem': str(i)})
det_prod = SubElement(det, 'prod')
@@ -1475,7 +1621,10 @@
prod_cProd.text = unicode(i).strip().rjust(4, u'0')
prod_cEAN = SubElement(det_prod, 'cEAN')
- prod_cEAN.text = inv_line.product_id.ean13
+ if inv_line.product_id.ean13:
+ prod_cEAN.text = str(inv_line.product_id.ean13)
+ else:
+ prod_cEAN.text = ''
prod_xProd = SubElement(det_prod, 'xProd')
prod_xProd.text = inv_line.product_id.name
@@ -1484,7 +1633,7 @@
prod_NCM.text = inv_line.product_id.property_fiscal_classification.name
prod_CFOP = SubElement(det_prod, 'CFOP')
- prod_CFOP.text = inv_line.cfop_ids[0].code
+ prod_CFOP.text = inv_line.cfop_id.code
prod_uCom = SubElement(det_prod, 'uCom')
prod_uCom.text = inv_line.uos_id.name
@@ -1505,22 +1654,37 @@
prod_uTrib.text = inv_line.uos_id.name
prod_qTrib = SubElement(det_prod, 'qTrib')
- prod_qTrib.text = '0.0000' #TODO
+ prod_qTrib.text = str("%.4f" % inv_line.quantity)
prod_vUnTrib = SubElement(det_prod, 'vUnTrib')
- prod_vUnTrib.text = '0.00' #TODO
-
- prod_vFrete = SubElement(det_prod, 'vFrete')
- prod_vFrete.text = '0.00' #TODO - Valor do Frete
-
- prod_vSeg = SubElement(det_prod, 'vSeg')
- prod_vSeg.text = '0.00' #TODO - Valor do seguro
-
- prod_vDesc = SubElement(det_prod, 'vDesc')
- prod_vDesc.text = str("%.2f" % inv_line.discount) #TODO
-
- prod_vOutro = SubElement(det_prod, 'vOutro')
- prod_vOutro.text = '0.0000' #TODO
+ prod_vUnTrib.text = str("%.2f" % inv_line.price_unit)
+
+ #
+ # Se frete por conta do receptor (1, 2)
+ # divide o valor total do frete pelo número de produtos
+ #
+ if inv.incoterm.freight_responsibility in ('1', '2') and inv.amount_freight > 0:
+ product_freight_price = str("%.2f" % (inv.amount_freight / len(inv.invoice_line)))
+ # @todo testar quando nao há frete mas valor declarado
+ prod_vFrete = SubElement(det_prod, 'vFrete')
+ prod_vFrete.text = str(product_freight_price)
+ else:
+ product_freight_price = ''
+
+ total_untaxed = inv_line.price_unit * inv_line.quantity
+ product_discount_value = total_untaxed - inv_line.price_total
+
+ # Se não houver desconto, deixa campo vaziu
+ if (product_discount_value > 0):
+ product_discount_value = str("%.2f" % product_discount_value)
+ prod_vDesc = SubElement(det_prod, 'vDesc')
+ prod_vDesc.text = product_discount_value
+
+ #prod_vSeg = SubElement(det_prod, 'vSeg')
+ #prod_vSeg.text = '' #TODO - Valor do seguro
+
+ #prod_vOutro = SubElement(det_prod, 'vOutro')
+ #prod_vOutro.text = '0.0000' #TODO
prod_indTot = SubElement(det_prod, 'indTot')
prod_indTot.text = '1' #TODO
@@ -1529,25 +1693,39 @@
imposto_icms = SubElement(prod_imposto, 'ICMS' ) # + inv_line.icms_cst)
- imposto_icms_cst = SubElement(imposto_icms, 'ICMS%s' % (inv_line.icms_cst))
+ # @todo: verificar se é simples nacional
+ imposto_icms_cst = SubElement(imposto_icms, 'ICMSSN%s' % (inv_line.icms_cst))
icms_orig = SubElement(imposto_icms_cst, 'orig')
icms_orig.text = inv_line.product_id.origin
- icms_CST = SubElement(imposto_icms_cst, 'CST')
+ # @todo: verificar se é simples nacional
+ icms_CST = SubElement(imposto_icms_cst, 'CSOSN')
icms_CST.text = inv_line.icms_cst
- icms_modBC = SubElement(imposto_icms_cst, 'modBC')
- icms_modBC.text = '0' # TODO
-
- icms_vBC = SubElement(imposto_icms_cst, 'vBC')
- icms_vBC.text = str("%.2f" % inv_line.icms_base)
-
- icms_pICMS = SubElement(imposto_icms_cst, 'pICMS')
- icms_pICMS.text = str("%.2f" % inv_line.icms_percent)
-
- icms_vICMS = SubElement(imposto_icms_cst, 'vICMS')
- icms_vICMS.text = str("%.2f" % inv_line.icms_value)
+ #icms_modBC = SubElement(imposto_icms_cst, 'modBC')
+ #icms_modBC.text = '0' # TODO
+
+ # @todo: pegar o valor do lugar certo
+ icms_pCredSN = SubElement(imposto_icms_cst, 'pCredSN')
+ icms_pCredSN.text = '2.87'
+
+ # @todo: pegar o valor do lugar certo
+ icms_pCredSN = SubElement(imposto_icms_cst, 'vCredICMSSN')
+ icms_pCredSN.text = str("%.2f" % (inv_line.price_subtotal * 0.0287))
+
+ # @todo: isso é necessário ?
+ if inv_line.icms_base:
+ icms_vBC = SubElement(imposto_icms_cst, 'vBC')
+ icms_vBC.text = str("%.2f" % inv_line.icms_base)
+
+ if inv_line.icms_percent:
+ icms_pICMS = SubElement(imposto_icms_cst, 'pICMS')
+ icms_pICMS.text = str("%.2f" % inv_line.icms_percent)
+
+ if inv_line.icms_value:
+ icms_vICMS = SubElement(imposto_icms_cst, 'vICMS')
+ icms_vICMS.text = str("%.2f" % inv_line.icms_value)
imposto_ipi = SubElement(prod_imposto, 'IPI')
@@ -1555,17 +1733,29 @@
icms_cEnq.text = '999'
#Imposto Não Tributado
- ipi_IPINT = SubElement(imposto_ipi, 'IPINT')
-
- ipi_CST = SubElement(ipi_IPINT, 'CST')
- ipi_CST.text = inv_line.ipi_cst
+ #ipi_IPINT = SubElement(imposto_ipi, 'IPINT')
+ ipi_IPITrib = SubElement(imposto_ipi, 'IPITrib')
+
+ #ipi_CST = SubElement(ipi_IPINT, 'CST')
+ ipi_CST = SubElement(ipi_IPITrib, 'CST')
+ ipi_CST.text = str(inv_line.ipi_cst)
+
+ ipi_vBC = SubElement(ipi_IPITrib, 'vBC')
+ ipi_vBC.text = '0.00' # @todo: chamar do local certo
+
+ ipi_pIPI = SubElement(ipi_IPITrib, 'pIPI')
+ ipi_pIPI.text = '0.00' # @todo: chamar do local certo
+
+ ipi_vIPI = SubElement(ipi_IPITrib, 'vIPI')
+ ipi_vIPI.text = '0.00' # @todo: chamar do local certo
imposto_pis = SubElement(prod_imposto, 'PIS')
- pis_PISAliq = SubElement(imposto_pis, 'PISAliq')
+ #pis_PISAliq = SubElement(imposto_pis, 'PISAliq')
+ pis_PISAliq = SubElement(imposto_pis, 'PISOutr')
pis_CST = SubElement(pis_PISAliq, 'CST')
- pis_CST.text = inv_line.pis_cst
+ pis_CST.text = str(inv_line.pis_cst)
pis_vBC = SubElement(pis_PISAliq, 'vBC')
pis_vBC.text = str("%.2f" % inv_line.pis_base)
@@ -1578,10 +1768,11 @@
imposto_cofins = SubElement(prod_imposto, 'COFINS')
- cofins_COFINSAliq = SubElement(imposto_cofins, 'COFINSAliq')
+ #cofins_COFINSAliq = SubElement(imposto_cofins, 'COFINSAliq')
+ cofins_COFINSAliq = SubElement(imposto_cofins, 'COFINSOutr')
cofins_CST = SubElement(cofins_COFINSAliq, 'CST')
- cofins_CST.text = inv_line.pis_cst
+ cofins_CST.text = str(inv_line.pis_cst)
cofins_vBC = SubElement(cofins_COFINSAliq, 'vBC')
cofins_vBC.text = str("%.2f" % inv_line.cofins_base)
@@ -1592,6 +1783,48 @@
cofins_vCOFINS = SubElement(cofins_COFINSAliq, 'vCOFINS')
cofins_vCOFINS.text = str("%.2f" % inv_line.cofins_value)
+ #
+ # Valores totais da NFe
+ #
+
+ # Tratamento para notas fiscais com desconto
+ #
+ # Configura os valores para o valor total da NFe e valor com desconto
+ #
+ if total_discount > 0:
+ # porcentagem de desconto total
+ total_percent_discount = total_discount / i
+
+ # total sem desconto (vNF)
+ aux_amount_total = inv.amount_total / (100 - total_percent_discount) * 100
+
+ # valor do desconto (vDesc)
+ discount_value = aux_amount_total - inv.amount_total
+ else:
+ aux_amount_total = inv.amount_total
+ discount_value = '0.00'
+
+ #
+ # Se frete por conta do receptor (1, 2),
+ # adiciona valor do frete no valor total da NFe
+ #
+ if inv.incoterm.freight_responsibility in ('1', '2') and total_discount == 0:
+ product_freight_price = inv.amount_freight + aux_amount_total
+ elif inv.incoterm.freight_responsibility in ('1', '2') and total_discount > 0:
+ product_freight_price = (aux_amount_total - discount_value) + inv.amount_freight
+ elif inv.incoterm.freight_responsibility not in ('1', '2') and total_discount > 0:
+ product_freight_price = aux_amount_total - discount_value
+ else:
+ product_freight_price = aux_amount_total
+
+ if inv.amount_freight == 0:
+ inv.amount_freight = '0.00'
+ else:
+ inv.amount_freight = str("%.2f" % inv.amount_freight)
+
+ # valor do desconto
+ discount_value = aux_amount_total - inv.amount_total,
+
total = SubElement(infNFe, 'total')
total_ICMSTot = SubElement(total, 'ICMSTot')
@@ -1602,22 +1835,22 @@
ICMSTot_vICMS.text = str("%.2f" % inv.icms_value)
ICMSTot_vBCST = SubElement(total_ICMSTot, 'vBCST')
- ICMSTot_vBCST.text = '0.00' # TODO
+ ICMSTot_vBCST.text = str("%.2f" % inv.icms_st_base)
ICMSTot_vST = SubElement(total_ICMSTot, 'vST')
- ICMSTot_vST.text = '0.00' # TODO
+ ICMSTot_vST.text = str("%.2f" % inv.icms_st_value)
ICMSTot_vProd = SubElement(total_ICMSTot, 'vProd')
ICMSTot_vProd.text = str("%.2f" % inv.amount_untaxed)
ICMSTot_vFrete = SubElement(total_ICMSTot, 'vFrete')
- ICMSTot_vFrete.text = '0.00' # TODO
+ ICMSTot_vFrete.text = inv.amount_freight
ICMSTot_vSeg = SubElement(total_ICMSTot, 'vSeg')
ICMSTot_vSeg.text = str("%.2f" % inv.amount_insurance)
ICMSTot_vDesc = SubElement(total_ICMSTot, 'vDesc')
- ICMSTot_vDesc.text = '0.00' # TODO
+ ICMSTot_vDesc.text = str("%.2f" % discount_value)
ICMSTot_II = SubElement(total_ICMSTot, 'vII')
ICMSTot_II.text = '0.00' # TODO
@@ -1635,7 +1868,7 @@
ICMSTot_vOutro.text = str("%.2f" % inv.amount_costs)
ICMSTot_vNF = SubElement(total_ICMSTot, 'vNF')
- ICMSTot_vNF.text = str("%.2f" % inv.amount_total)
+ ICMSTot_vNF.text = str("%.2f" %product_freight_price)
transp = SubElement(infNFe, 'transp')
@@ -1654,10 +1887,10 @@
if inv.carrier_id.partner_id.tipo_pessoa == 'J':
transporta_CNPJ = SubElement(transp_transporta, 'CNPJ')
- transporta_CNPJ.text = inv.carrier_id.partner_id.cnpj_cpf
+ transporta_CNPJ.text = self.clean_string(inv.carrier_id.partner_id.cnpj_cpf)
else:
transporta_CPF = SubElement(transp_transporta, 'CPF')
- transporta_CPF.text = inv.carrier_id.partner_id.cnpj_cpf
+ transporta_CPF.text = self.clean_string(inv.carrier_id.partner_id.cnpj_cpf)
transporta_xNome = SubElement(transp_transporta, 'xNome')
if inv.carrier_id.partner_id.legal_name:
@@ -1682,18 +1915,18 @@
transp_vol = SubElement(transp, 'vol')
vol_qVol = SubElement(transp_vol, 'qVol')
- vol_qVol.text = inv.number_of_packages
+ vol_qVol.text = str(inv.number_of_packages)
vol_esp = SubElement(transp_vol, 'esp')
vol_esp.text = 'volume' #TODO
vol_pesoL = SubElement(transp_vol, 'pesoL')
- vol_pesoL.text = inv.weight_net
+ vol_pesoL.text = str("%.3f" % inv.weight_net)
vol_pesoB = SubElement(transp_vol, 'pesoB')
- vol_pesoB.text = inv.weight
-
- xml_string = ElementTree.tostring(nfeProc, 'utf-8')
+ vol_pesoB.text = str("%.3f" % inv.weight)
+
+ xml_string = etree.tostring(nfeProc, encoding="utf-8")
return xml_string
def _fiscal_position_map(self, cr, uid, ids, partner_id, partner_invoice_id, company_id, fiscal_operation_category_id):
@@ -1769,6 +2002,36 @@
line.cfop_id = obj_foperation.cfop_id.id
return result
+
+ #
+ # Remove acentuação
+ #
+ def clean_string(self, dirty_string):
+ dirty_string = normalize('NFKD', unicode(dirty_string)).encode('ASCII','ignore')
+ return "".join(c for c in dirty_string if c not in "./-")
+
+ def nfe_chave_de_acesso(self, ibge_code, date_invoice, cnpj_cpf, fiscal_document_id, document_serie_id, internal_number):
+ #
+ # Monta Chave de Acesso da NFe
+ #
+ chave = ibge_code # código IBGE
+ chave += date_invoice[2:4] + date_invoice[5:7] # data no formato AAMM
+ chave += self.clean_string(cnpj_cpf) # CNPJ
+ chave += fiscal_document_id # modelo
+ chave += document_serie_id.zfill(3) #série
+ chave += str(internal_number).zfill(9) # nr. da NFe
+ chave += '1' # tipo de emissão 1=normal
+ chave += str(internal_number).zfill(8) # código numérico
+
+ # remove pontuação da string
+ chave = self.clean_string(chave)
+
+ # calcula digito verificador
+ aux_cod_verificador = self.nfe_digito_verificador(chave)
+ chave += aux_cod_verificador
+
+ # adiciona string NFe ao inicio da chave
+ return "".join(('NFe', chave))
account_invoice()
=== modified file 'l10n_br_account/wizard/nfe_export_from_invoice.py'
--- l10n_br_account/wizard/nfe_export_from_invoice.py 2012-05-15 21:21:36 +0000
+++ l10n_br_account/wizard/nfe_export_from_invoice.py 2012-07-23 00:53:18 +0000
@@ -37,6 +37,7 @@
('done', 'done')], 'state', readonly=True),
'nfe_environment': fields.selection([('1', 'Produção'),
('2', 'Homologação')], 'Ambiente'),
+ 'file_name': fields.char('File Name', size=30),
}
_defaults = {
'state': 'init',
@@ -70,9 +71,14 @@
if export_inv_ids:
if data['file_type'] == 'xml':
nfe_file = inv_obj.nfe_export_xml(cr, uid, export_inv_ids, data['nfe_environment'])
+ nfe_number = str(ids[0])
+ file_name = 'openerp_'+nfe_number+'-nfe.xml'
else:
nfe_file = inv_obj.nfe_export_txt(cr, uid, export_inv_ids, data['nfe_environment'])
- self.write(cr, uid, ids, {'file': base64.b64encode(nfe_file), 'state': 'done'}, context=context)
+ nfe_number = str(ids[0])
+ file_name = 'openerp_'+nfe_number+'-nfe.txt'
+
+ self.write(cr, uid, ids, {'file': base64.b64encode(nfe_file), 'state': 'done', 'file_name': file_name}, context=context)
if err_msg:
raise osv.except_osv(_('Error !'), _("'%s'") % (err_msg, ))
=== modified file 'l10n_br_account/wizard/nfe_export_from_invoice_view.xml'
--- l10n_br_account/wizard/nfe_export_from_invoice_view.xml 2012-05-09 23:34:50 +0000
+++ l10n_br_account/wizard/nfe_export_from_invoice_view.xml 2012-07-23 00:53:18 +0000
@@ -26,7 +26,8 @@
<field colspan="4" name="nfe_environment" />
</group>
<group states="done" colspan="4">
- <field name="file" width="250" colspan="4"/>
+ <field name="file" width="250" colspan="4" filename="file_name"/>
+ <field name="file_name" invisible="1"/>
</group>
</group>
<group colspan="8" col="8" states="init">
Follow ups