← Back to team overview

openerp-brazil-team team mailing list archive

[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