diff --git a/br_account_einvoice/models/invoice_eletronic.py b/br_account_einvoice/models/invoice_eletronic.py
index 4335ca2c7..e5ff86e86 100644
--- a/br_account_einvoice/models/invoice_eletronic.py
+++ b/br_account_einvoice/models/invoice_eletronic.py
@@ -87,7 +87,7 @@ class InvoiceEletronic(models.Model):
partner_shipping_id = fields.Many2one(
'res.partner', string=u'Entrega', readonly=True, states=STATE)
payment_term_id = fields.Many2one(
- 'account.payment.term', string=u'Forma pagamento',
+ 'account.payment.term', string=u'Condição pagamento',
readonly=True, states=STATE)
fiscal_position_id = fields.Many2one(
'account.fiscal.position', string=u'Posição Fiscal',
@@ -436,7 +436,7 @@ def unlink(self):
def log_exception(self, exc):
self.codigo_retorno = -1
- self.mensagem_retorno = exc.message
+ self.mensagem_retorno = str(exc)
def _get_state_to_send(self):
return ('draft',)
diff --git a/br_base/models/res_partner.py b/br_base/models/res_partner.py
index 48e90e5a7..66113dd08 100644
--- a/br_base/models/res_partner.py
+++ b/br_base/models/res_partner.py
@@ -198,47 +198,41 @@ def action_check_sefaz(self):
resposta = consulta_cadastro(certificado, obj=obj, ambiente=1,
estado=self.state_id.ibge_code)
- obj = resposta['object']
- if "Body" in dir(obj) and \
- "consultaCadastro2Result" in dir(obj.Body):
- info = obj.Body.consultaCadastro2Result.retConsCad.infCons
- if info.cStat == 111 or info.cStat == 112:
- if not self.inscr_est:
- self.inscr_est = info.infCad.IE
- if not self.cnpj_cpf:
- self.cnpj_cpf = info.infCad.IE
-
- def get_value(obj, prop):
- if prop not in dir(obj):
- return None
- return getattr(obj, prop)
- self.legal_name = get_value(info.infCad, 'xNome')
- if "ender" not in dir(info.infCad):
- return
- cep = get_value(info.infCad.ender, 'CEP') or ''
- self.zip = str(cep).zfill(8) if cep else ''
- self.street = get_value(info.infCad.ender, 'xLgr')
- self.number = get_value(info.infCad.ender, 'nro')
- self.street2 = get_value(info.infCad.ender, 'xCpl')
- self.district = get_value(info.infCad.ender, 'xBairro')
- cMun = get_value(info.infCad.ender, 'cMun')
- xMun = get_value(info.infCad.ender, 'xMun')
- city = None
- if cMun:
- city = self.env['res.state.city'].search(
- [('ibge_code', '=', str(cMun)[2:]),
- ('state_id', '=', self.state_id.id)])
- if not city and xMun:
- city = self.env['res.state.city'].search(
- [('name', 'ilike', xMun),
- ('state_id', '=', self.state_id.id)])
- if city:
- self.city_id = city.id
- else:
- msg = "%s - %s" % (info.cStat, info.xMotivo)
- raise UserError(msg)
+ info = resposta['object'].getchildren()[0].infCons
+ if info.cStat == 111 or info.cStat == 112:
+ if not self.inscr_est:
+ self.inscr_est = info.infCad.IE.text
+ if not self.cnpj_cpf:
+ self.cnpj_cpf = info.infCad.IE.text
+
+ def get_value(obj, prop):
+ if prop not in dir(obj):
+ return None
+ return getattr(obj, prop)
+ self.legal_name = get_value(info.infCad, 'xNome')
+ if "ender" not in dir(info.infCad):
+ return
+ cep = get_value(info.infCad.ender, 'CEP') or ''
+ self.zip = str(cep).zfill(8) if cep else ''
+ self.street = get_value(info.infCad.ender, 'xLgr')
+ self.number = get_value(info.infCad.ender, 'nro')
+ self.street2 = get_value(info.infCad.ender, 'xCpl')
+ self.district = get_value(info.infCad.ender, 'xBairro')
+ cMun = get_value(info.infCad.ender, 'cMun')
+ xMun = get_value(info.infCad.ender, 'xMun')
+ city = None
+ if cMun:
+ city = self.env['res.state.city'].search(
+ [('ibge_code', '=', str(cMun)[2:]),
+ ('state_id', '=', self.state_id.id)])
+ if not city and xMun:
+ city = self.env['res.state.city'].search(
+ [('name', 'ilike', xMun),
+ ('state_id', '=', self.state_id.id)])
+ if city:
+ self.city_id = city.id
else:
- raise UserError(u"Nenhuma resposta - verificou se seu \
- certificado é válido?")
+ msg = "%s - %s" % (info.cStat, info.xMotivo)
+ raise UserError(msg)
else:
raise UserError(u'Preencha o estado e o CNPJ para pesquisar')
diff --git a/br_base/tests/xml/consulta_cadastro.xml b/br_base/tests/xml/consulta_cadastro.xml
index 5a5c1c957..df99f3805 100644
--- a/br_base/tests/xml/consulta_cadastro.xml
+++ b/br_base/tests/xml/consulta_cadastro.xml
@@ -1,46 +1,35 @@
-
-
-
-
- 42
- 2.00
-
-
-
-
-
-
- SC_NFE_PL_008i2
- 111
- Consulta cadastro com uma ocorrencia
- SC
- 22814429000155
- 2016-11-03T08:33:34-02:00
- 35
-
- 112632165
- 22814429000155
- SC
- 1
- 1
- 4
- Empresa de Teste SC
- SIMPLES NACIONAL
- 4789099
- 2014-11-03
- 2014-11-03
-
- RUA PADRE JOAO
- 000
- SL
- Centro
- 4205407
- FLORIANOPOLIS
- 88032050
-
-
-
-
-
-
-
+
+
+
+ SC_NFE_PL_008i2
+ 111
+ Consulta cadastro com uma ocorrencia
+ SC
+ 22814429000155
+ 2016-11-03T08:33:34-02:00
+ 35
+
+ 112632165
+ 22814429000155
+ SC
+ 1
+ 1
+ 4
+ Empresa de Teste SC
+ SIMPLES NACIONAL
+ 4789099
+ 2014-11-03
+ 2014-11-03
+
+ RUA PADRE JOAO
+ 000
+ SL
+ Centro
+ 4205407
+ FLORIANOPOLIS
+ 88032050
+
+
+
+
+
diff --git a/br_nfe/__manifest__.py b/br_nfe/__manifest__.py
index f3edcbd80..b9814f78b 100644
--- a/br_nfe/__manifest__.py
+++ b/br_nfe/__manifest__.py
@@ -17,6 +17,7 @@
],
'depends': [
'br_account_einvoice',
+ 'br_account_payment'
],
'external_dependencies': {
'python': [
@@ -34,6 +35,7 @@
'views/invoice_eletronic_item.xml',
'views/inutilized_nfe.xml',
'views/br_nfe.xml',
+ 'views/payment_mode.xml',
'reports/br_nfe_reports.xml',
'wizard/cancel_nfe.xml',
'wizard/carta_correcao_eletronica.xml',
diff --git a/br_nfe/models/__init__.py b/br_nfe/models/__init__.py
index d6a5fee59..6549f108f 100644
--- a/br_nfe/models/__init__.py
+++ b/br_nfe/models/__init__.py
@@ -11,3 +11,4 @@
from . import res_partner
from . import invoice_eletronic_item
from . import inutilized_nfe
+from . import payment_mode
diff --git a/br_nfe/models/account_fiscal_position.py b/br_nfe/models/account_fiscal_position.py
index 53bbaa62d..c7cc05c36 100644
--- a/br_nfe/models/account_fiscal_position.py
+++ b/br_nfe/models/account_fiscal_position.py
@@ -19,6 +19,7 @@ class AccountFiscalPositionTemplate(models.Model):
('2', u'Operação não presencial, pela Internet'),
('3', u'Operação não presencial, Teleatendimento'),
('4', u'NFC-e em operação com entrega em domicílio'),
+ ('5', u'Operação presencial, fora do estabelecimento'),
('9', u'Operação não presencial, outros'),
], u'Tipo de operação',
help=u'Indicador de presença do comprador no\n'
@@ -48,6 +49,7 @@ class AccountFiscalPosition(models.Model):
('2', u'Operação não presencial, pela Internet'),
('3', u'Operação não presencial, Teleatendimento'),
('4', u'NFC-e em operação com entrega em domicílio'),
+ ('5', u'Operação presencial, fora do estabelecimento'),
('9', u'Operação não presencial, outros'),
], u'Tipo de operação',
help=u'Indicador de presença do comprador no\n'
diff --git a/br_nfe/models/account_invoice.py b/br_nfe/models/account_invoice.py
index 3963c76b3..1cd79f2cc 100644
--- a/br_nfe/models/account_invoice.py
+++ b/br_nfe/models/account_invoice.py
@@ -96,6 +96,7 @@ def _return_pdf_invoice(self, doc):
def _prepare_edoc_vals(self, inv):
res = super(AccountInvoice, self)._prepare_edoc_vals(inv)
+ res['payment_mode_id'] = inv.payment_mode_id.id
res['ind_pres'] = inv.fiscal_position_id.ind_pres
res['finalidade_emissao'] = inv.fiscal_position_id.finalidade_emissao
res['informacoes_legais'] = inv.fiscal_comment
@@ -148,7 +149,7 @@ def _prepare_edoc_vals(self, inv):
count = 1
for parcela in inv.receivable_move_line_ids.sorted(lambda x: x.name):
duplicatas.append((0, None, {
- 'numero_duplicata': "%s/%02d" % (inv.internal_number, count),
+ 'numero_duplicata': "%03d" % count,
'data_vencimento': parcela.date_maturity,
'valor': parcela.credit or parcela.debit,
}))
diff --git a/br_nfe/models/inutilized_nfe.py b/br_nfe/models/inutilized_nfe.py
index 66f460c71..3c3a21924 100644
--- a/br_nfe/models/inutilized_nfe.py
+++ b/br_nfe/models/inutilized_nfe.py
@@ -44,6 +44,8 @@ class InutilizedNfe(models.Model):
string=u'Modelo', required=True, readonly=True, states=STATE)
serie = fields.Many2one('br_account.document.serie', string=u'Série',
required=True, readonly=True, states=STATE)
+ code = fields.Char(string="Código", size=10)
+ motive = fields.Char(string="Motivo", size=300)
@api.model
def create(self, vals):
@@ -105,21 +107,22 @@ def _prepare_obj(self, company, estado, ambiente):
'justificativa': self.justificativa,
}
- def _handle_resposta(self, resposta):
- self._create_attachment('inutilizacao-envio', self,
- resposta['sent_xml'])
- self._create_attachment('inutilizacao-recibo', self,
- resposta['received_xml'])
- if hasattr(resposta['object'].Body, 'Fault'):
- raise UserError(u'Não foi possível concluir a operação.')
- inf_inut = resposta['object'].Body.nfeInutilizacaoNF2Result.\
- retInutNFe.infInut
+ def _handle_response(self, response):
+ self._create_attachment(
+ 'inutilizacao-envio', self, response['sent_xml'])
+ self._create_attachment(
+ 'inutilizacao-recibo', self, response['received_xml'])
+ inf_inut = response['object'].getchildren()[0].infInut
status = inf_inut.cStat
if status == 102:
- self.state = 'done'
+ self.write({
+ 'state': 'done',
+ 'code': inf_inut.cStat,
+ 'motive': inf_inut.xMotivo
+ })
else:
- self.state = 'error'
- self.erro = inf_inut.xMotivo
+ msg = '%s - %s' % (inf_inut.cStat, inf_inut.xMotivo)
+ raise UserError(msg)
def send_sefaz(self):
company = self.env.user.company_id
@@ -134,8 +137,8 @@ def send_sefaz(self):
certificado = Certificado(cert_pfx, company.nfe_a1_password)
resposta = inutilizar_nfe(certificado, obj=obj, estado=estado,
- ambiente=int(ambiente))
- self._handle_resposta(resposta=resposta)
+ ambiente=int(ambiente), modelo=obj['modelo'])
+ self._handle_response(response=resposta)
@api.multi
def action_send_inutilization(self):
diff --git a/br_nfe/models/invoice_eletronic.py b/br_nfe/models/invoice_eletronic.py
index caf0210a5..a4605a569 100644
--- a/br_nfe/models/invoice_eletronic.py
+++ b/br_nfe/models/invoice_eletronic.py
@@ -52,6 +52,9 @@ def generate_correction_letter(self):
"context": {'default_eletronic_doc_id': self.id},
}
+ payment_mode_id = fields.Many2one(
+ 'payment.mode', string='Modo de Pagamento',
+ readonly=True, states=STATE)
state = fields.Selection(selection_add=[('denied', 'Denegado')])
ambiente_nfe = fields.Selection(
string=u"Ambiente NFe", related="company_id.tipo_ambiente",
@@ -67,6 +70,7 @@ def generate_correction_letter(self):
('2', u'Operação não presencial, pela Internet'),
('3', u'Operação não presencial, Teleatendimento'),
('4', u'NFC-e em operação com entrega em domicílio'),
+ ('5', u'Operação presencial, fora do estabelecimento'),
('9', u'Operação não presencial, outros'),
], u'Indicador de Presença', readonly=True, states=STATE, required=False,
help=u'Indicador de presença do comprador no\n'
@@ -98,10 +102,12 @@ def generate_correction_letter(self):
# Transporte
modalidade_frete = fields.Selection(
- [('0', u'0 - Emitente'),
- ('1', u'1 - Destinatário'),
- ('2', u'2 - Terceiros'),
- ('9', u'9 - Sem Frete')],
+ [('0', u'0 - Contratação do Frete por conta do Remetente (CIF)'),
+ ('1', u'1 - Contratação do Frete por conta do Destinatário (FOB)'),
+ ('2', u'2 - Contratação do Frete por conta de Terceiros'),
+ ('3', u'3 - Transporte Próprio por conta do Remetente'),
+ ('4', u'4 - Transporte Próprio por conta do Destinatário'),
+ ('9', u'9 - Sem Ocorrência de Transporte')],
string=u'Modalidade do frete', default="9",
readonly=True, states=STATE)
transportadora_id = fields.Many2one(
@@ -249,7 +255,7 @@ def _prepare_eletronic_invoice_item(self, item, invoice):
product_uom_format = '{0:.' + str(product_uom_precision) + 'f}'
prod = {
'cProd': item.product_id.default_code,
- 'cEAN': item.product_id.barcode or '',
+ 'cEAN': item.product_id.barcode or 'SEM GTIN',
'xProd': item.product_id.with_context(
display_default_code=False).name_get()[0][1],
'NCM': re.sub('[^0-9]', '', item.ncm or '')[:8],
@@ -259,7 +265,7 @@ def _prepare_eletronic_invoice_item(self, item, invoice):
'qCom': product_uom_format.format(item.quantidade),
'vUnCom': product_price_format.format(item.preco_unitario),
'vProd': "%.02f" % (item.preco_unitario * item.quantidade),
- 'cEANTrib': item.product_id.barcode or '',
+ 'cEANTrib': item.product_id.barcode or 'SEM GTIN',
'uTrib': '{:.6}'.format(item.uom_id.name or ''),
'qTrib': product_uom_format.format(item.quantidade),
'vUnTrib': product_price_format.format(item.preco_unitario),
@@ -526,14 +532,18 @@ def _prepare_eletronic_invoice_values(self):
'vBC': "%.02f" % self.valor_bc_icms,
'vICMS': "%.02f" % self.valor_icms,
'vICMSDeson': '0.00',
+ 'vFCP': '0.00',
'vBCST': "%.02f" % self.valor_bc_icmsst,
'vST': "%.02f" % self.valor_icmsst,
+ 'vFCPST': '0.00',
+ 'vFCPSTRet': '0.00',
'vProd': "%.02f" % self.valor_bruto,
'vFrete': "%.02f" % self.valor_frete,
'vSeg': "%.02f" % self.valor_seguro,
'vDesc': "%.02f" % self.valor_desconto,
'vII': "%.02f" % self.valor_ii,
'vIPI': "%.02f" % self.valor_ipi,
+ 'vIPIDevol': '0.00',
'vPIS': "%.02f" % self.valor_pis,
'vCOFINS': "%.02f" % self.valor_cofins,
'vOutro': "%.02f" % self.valor_despesas,
@@ -612,15 +622,18 @@ def _prepare_eletronic_invoice_values(self):
cobr = {
'fat': {
'nFat': self.numero_fatura or '',
- 'vOrig': "%.02f" % self.fatura_bruto
- if self.fatura_bruto else '',
- 'vDesc': "%.02f" % self.fatura_desconto
- if self.fatura_desconto else '',
- 'vLiq': "%.02f" % self.fatura_liquido
- if self.fatura_liquido else '',
+ 'vOrig': "%.02f" % (
+ self.fatura_liquido + self.fatura_desconto),
+ 'vDesc': "%.02f" % self.fatura_desconto,
+ 'vLiq': "%.02f" % self.fatura_liquido,
},
'dup': duplicatas
}
+ pag = [{
+ 'indPag': self.payment_term_id.indPag or '0',
+ 'tPag': self.payment_mode_id.tipo_pagamento or '15',
+ 'vPag': "%.02f" % self.valor_final
+ }]
if self.informacoes_complementares:
self.informacoes_complementares = self.informacoes_complementares.\
replace('\n', '
')
@@ -646,6 +659,7 @@ def _prepare_eletronic_invoice_values(self):
'autXML': autorizados,
'detalhes': eletronic_items,
'total': total,
+ 'pag': pag,
'transp': transp,
'infAdic': infAdic,
'exporta': exporta,
@@ -662,6 +676,7 @@ def _prepare_lote(self, lote, nfe_values):
'indSinc': 0,
'estado': self.company_id.partner_id.state_id.ibge_code,
'ambiente': 1 if self.ambiente == 'producao' else 2,
+ 'modelo': self.model,
'NFes': [{
'infNFe': nfe_values
}]
@@ -752,12 +767,12 @@ def action_send_eletronic_invoice(self):
resposta_recibo = None
resposta = autorizar_nfe(certificado, **lote)
- retorno = resposta['object'].Body.nfeAutorizacaoLoteResult
- retorno = retorno.getchildren()[0]
+ retorno = resposta['object'].getchildren()[0]
if retorno.cStat == 103:
obj = {
'estado': self.company_id.partner_id.state_id.ibge_code,
'ambiente': 1 if self.ambiente == 'producao' else 2,
+ 'modelo': '55',
'obj': {
'ambiente': 1 if self.ambiente == 'producao' else 2,
'numero_recibo': retorno.infRec.nRec
@@ -768,8 +783,7 @@ def action_send_eletronic_invoice(self):
while True:
time.sleep(2)
resposta_recibo = retorno_autorizar_nfe(certificado, **obj)
- retorno = resposta_recibo['object'].Body.\
- nfeRetAutorizacaoLoteResult.retConsReciNFe
+ retorno = resposta_recibo['object'].getchildren()[0]
if retorno.cStat != 105:
break
@@ -867,72 +881,51 @@ def action_cancel_document(self, context=None, justificativa=None):
cert_pfx = base64.decodestring(cert)
certificado = Certificado(cert_pfx, self.company_id.nfe_a1_password)
- consulta = {
+ tz = pytz.timezone(self.env.user.partner_id.tz) or pytz.utc
+ dt_evento = datetime.utcnow()
+ dt_evento = pytz.utc.localize(dt_evento).astimezone(tz)
+
+ id_canc = "ID110111%s%02d" % (
+ self.chave_nfe, self.sequencial_evento)
+ cancelamento = {
+ 'idLote': self.id,
'estado': self.company_id.state_id.ibge_code,
'ambiente': 2 if self.ambiente == 'homologacao' else 1,
- 'chave_nfe': self.chave_nfe,
+ 'eventos': [{
+ 'Id': id_canc,
+ 'cOrgao': self.company_id.state_id.ibge_code,
+ 'tpAmb': 2 if self.ambiente == 'homologacao' else 1,
+ 'CNPJ': re.sub('[^0-9]', '', self.company_id.cnpj_cpf),
+ 'chNFe': self.chave_nfe,
+ 'dhEvento': dt_evento.strftime('%Y-%m-%dT%H:%M:%S-03:00'),
+ 'nSeqEvento': self.sequencial_evento,
+ 'nProt': self.protocolo_nfe,
+ 'xJust': justificativa,
+ 'tpEvento': '110111',
+ 'descEvento': 'Cancelamento',
+ }],
+ 'modelo': self.model,
}
-
- resp = consultar_protocolo_nfe(certificado, **consulta)
- # Retorno específico para o estado da Bahia
- if self.company_id.state_id.ibge_code == '29':
- retorno_consulta = \
- resp['object'].Body.nfeConsultaNFResult.retConsSitNFe
- else:
- retorno_consulta = \
- resp['object'].Body.nfeConsultaNF2Result.retConsSitNFe
- if retorno_consulta.cStat == 101:
+ resp = recepcao_evento_cancelamento(certificado, **cancelamento)
+ resposta = resp['object'].getchildren()[0]
+ if resposta.cStat == 128 and \
+ resposta.retEvento.infEvento.cStat in (135, 136, 155):
self.state = 'cancel'
- self.codigo_retorno = retorno_consulta.cStat
- self.mensagem_retorno = retorno_consulta.xMotivo
+ self.codigo_retorno = resposta.retEvento.infEvento.cStat
+ self.mensagem_retorno = resposta.retEvento.infEvento.xMotivo
self.sequencial_evento += 1
- # Retorno específico para o estado da Bahia
- if self.company_id.state_id.ibge_code == '29':
- resp['received_xml'] = etree.tostring(
- retorno_consulta.procEventoNFe.retEvento)
- else:
- resp['received_xml'] = etree.tostring(
- retorno_consulta.retCancNFe)
- resp['sent_xml'] = etree.tostring(retorno_consulta.procEventoNFe)
else:
- tz = pytz.timezone(self.env.user.partner_id.tz) or pytz.utc
- dt_evento = datetime.utcnow()
- dt_evento = pytz.utc.localize(dt_evento).astimezone(tz)
-
- id_canc = "ID110111%s%02d" % (
- self.chave_nfe, self.sequencial_evento)
- cancelamento = {
- 'idLote': self.id,
- 'estado': self.company_id.state_id.ibge_code,
- 'ambiente': 2 if self.ambiente == 'homologacao' else 1,
- 'eventos': [{
- 'Id': id_canc,
- 'cOrgao': self.company_id.state_id.ibge_code,
- 'tpAmb': 2 if self.ambiente == 'homologacao' else 1,
- 'CNPJ': re.sub('[^0-9]', '', self.company_id.cnpj_cpf),
- 'chNFe': self.chave_nfe,
- 'dhEvento': dt_evento.strftime('%Y-%m-%dT%H:%M:%S-03:00'),
- 'nSeqEvento': self.sequencial_evento,
- 'nProt': self.protocolo_nfe,
- 'xJust': justificativa
- }]
- }
- resp = recepcao_evento_cancelamento(certificado, **cancelamento)
- resposta = resp['object'].Body.nfeRecepcaoEventoResult.retEnvEvento
- if resposta.cStat == 128 and \
- resposta.retEvento.infEvento.cStat in (135, 136, 155):
- self.state = 'cancel'
- self.codigo_retorno = resposta.retEvento.infEvento.cStat
- self.mensagem_retorno = resposta.retEvento.infEvento.xMotivo
- self.sequencial_evento += 1
+ code, motive = None, None
+ if resposta.cStat == 128:
+ code = resposta.retEvento.infEvento.cStat
+ motive = resposta.retEvento.infEvento.xMotivo
else:
- if resposta.cStat == 128:
- self.codigo_retorno = resposta.retEvento.infEvento.cStat
- self.mensagem_retorno = \
- resposta.retEvento.infEvento.xMotivo
- else:
- self.codigo_retorno = resposta.cStat
- self.mensagem_retorno = resposta.xMotivo
+ code = resposta.cStat
+ motive = resposta.xMotivo
+ if code == 573: # Duplicidade, já cancelado
+ return self.action_get_status()
+ return self._create_response_cancel(
+ code, motive, resp, justificativa)
self.env['invoice.eletronic.event'].create({
'code': self.codigo_retorno,
@@ -946,3 +939,65 @@ def action_cancel_document(self, context=None, justificativa=None):
resp['received_xml'])
self.nfe_processada = base64.encodestring(nfe_proc_cancel)
self.nfe_processada_name = "NFe%08d.xml" % self.numero
+
+ def action_get_status(self):
+ cert = self.company_id.with_context({'bin_size': False}).nfe_a1_file
+ cert_pfx = base64.decodestring(cert)
+ certificado = Certificado(cert_pfx, self.company_id.nfe_a1_password)
+ consulta = {
+ 'estado': self.company_id.state_id.ibge_code,
+ 'ambiente': 2 if self.ambiente == 'homologacao' else 1,
+ 'modelo': self.model,
+ 'obj': {
+ 'chave_nfe': self.chave_nfe,
+ 'ambiente': 2 if self.ambiente == 'homologacao' else 1,
+ }
+ }
+ resp = consultar_protocolo_nfe(certificado, **consulta)
+ retorno_consulta = resp['object'].getchildren()[0]
+ if retorno_consulta.cStat == 101:
+ self.state = 'cancel'
+ self.codigo_retorno = retorno_consulta.cStat
+ self.mensagem_retorno = retorno_consulta.xMotivo
+ resp['received_xml'] = etree.tostring(
+ retorno_consulta, encoding=str)
+ self.env['invoice.eletronic.event'].create({
+ 'code': self.codigo_retorno,
+ 'name': self.mensagem_retorno,
+ 'invoice_eletronic_id': self.id,
+ })
+ self._create_attachment('canc', self, resp['sent_xml'])
+ self._create_attachment('canc-ret', self, resp['received_xml'])
+ nfe_processada = base64.decodestring(self.nfe_processada)
+ nfe_proc_cancel = gerar_nfeproc_cancel(
+ nfe_processada, resp['received_xml'].encode())
+ if nfe_proc_cancel:
+ self.nfe_processada = base64.encodestring(nfe_proc_cancel)
+ else:
+ message = "%s - %s" % (retorno_consulta.cStat,
+ retorno_consulta.xMotivo)
+ raise UserError(message)
+
+ def _create_response_cancel(self, code, motive, response, justificativa):
+ message = "%s - %s" % (code, motive)
+ wiz = self.env['wizard.cancel.nfe'].create({
+ 'edoc_id': self.id,
+ 'justificativa': justificativa,
+ 'state': 'error',
+ 'message': message,
+ 'sent_xml': base64.b64encode(
+ response['sent_xml'].encode('utf-8')),
+ 'sent_xml_name': 'cancelamento-envio.xml',
+ 'received_xml': base64.b64encode(
+ response['received_xml'].encode('utf-8')),
+ 'received_xml_name': 'cancelamento-retorno.xml',
+ })
+ return {
+ 'name': 'Cancelamento NFe',
+ 'type': 'ir.actions.act_window',
+ 'res_model': 'wizard.cancel.nfe',
+ 'res_id': wiz.id,
+ 'view_type': 'form',
+ 'view_mode': 'form',
+ 'target': 'new',
+ }
diff --git a/br_nfe/models/payment_mode.py b/br_nfe/models/payment_mode.py
new file mode 100644
index 000000000..8ffd09471
--- /dev/null
+++ b/br_nfe/models/payment_mode.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+# © 2018 Danimar Ribeiro, Trustcode
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
+
+from odoo import fields, models
+
+
+class PaymentMode(models.Model):
+ _inherit = "payment.mode"
+
+ tipo_pagamento = fields.Selection(
+ [('01', u'Dinheiro'),
+ ('02', u'Cheque'),
+ ('03', u'Catão de Crédito'),
+ ('04', u'Cartão de Débito'),
+ ('05', u'Crédito Loja'),
+ ('10', u'Vale Alimentação'),
+ ('11', u'Vale Refeição'),
+ ('12', u'Vale Presente'),
+ ('13', u'Vale Combustível'),
+ ('14', u'Duplicata Mercantil'),
+ ('90', u'Sem pagamento'),
+ ('99', u'Outros')],
+ string=u"Forma de Pagamento", default="14")
diff --git a/br_nfe/tests/test_inutilizacao.py b/br_nfe/tests/test_inutilizacao.py
index 91290537b..b0b52916c 100644
--- a/br_nfe/tests/test_inutilizacao.py
+++ b/br_nfe/tests/test_inutilizacao.py
@@ -144,12 +144,12 @@ def tearDown(self):
])
@patch('odoo.addons.br_nfe.models.inutilized_nfe.inutilizar_nfe')
- def test_inutilizacao_ok(self, inutilizar):
+ def test_inutilizacao_falha_schema(self, inutilizar):
with open(os.path.join(self.caminho,
'xml/inutilizacao_sent_xml.xml')) as f:
sent_xml = f.read()
with open(os.path.join(self.caminho,
- 'xml/inutilizacao_received_xml.xml')) as f:
+ 'xml/inutilizacao_falha_schema.xml')) as f:
received_xml = f.read()
_, obj = sanitize_response(received_xml)
inutilizar.return_value = {'received_xml': received_xml,
@@ -163,24 +163,8 @@ def test_inutilizacao_ok(self, inutilizar):
modelo='55',
justificativa=justif
))
- wizard.action_inutilize_nfe()
- inut_inv = self.env['invoice.eletronic.inutilized'].search([])
- self.assertEqual(len(inut_inv), 1)
- self.assertEqual(inut_inv.numeration_start, 0)
- self.assertEqual(inut_inv.numeration_end, 5)
- self.assertEqual(inut_inv.serie, self.serie)
- self.assertEqual(inut_inv.name, u'Série Inutilizada 0 - 5')
- self.assertEqual(inut_inv.justificativa, justif)
- self.assertEqual(inut_inv.state, 'error')
- invoice = self.env['account.invoice'].create(dict(
- self.default_invoice.items(),
- partner_id=self.partner_fisica.id,
- document_serie_id=self.serie.id
- ))
- invoice.action_invoice_open()
- inv_eletr = self.env['invoice.eletronic'].search(
- [('invoice_id', '=', invoice.id)])
- self.assertEqual(inv_eletr.numero, 6)
+ with self.assertRaises(UserError):
+ wizard.action_inutilize_nfe()
@patch('odoo.addons.br_nfe.models.inutilized_nfe.inutilizar_nfe')
def test_inutilizacao_2_sequences(self, inutilizar):
@@ -188,7 +172,7 @@ def test_inutilizacao_2_sequences(self, inutilizar):
'xml/inutilizacao_sent_xml.xml')) as f:
sent_xml = f.read()
with open(os.path.join(self.caminho,
- 'xml/inutilizacao_received_xml.xml')) as f:
+ 'xml/inutilizacao_received_ok_xml.xml')) as f:
received_xml = f.read()
_, obj = sanitize_response(received_xml)
inutilizar.return_value = {'received_xml': received_xml,
diff --git a/br_nfe/tests/test_nfe.py b/br_nfe/tests/test_nfe.py
index e1cc1feff..457783685 100644
--- a/br_nfe/tests/test_nfe.py
+++ b/br_nfe/tests/test_nfe.py
@@ -328,39 +328,6 @@ def test_send_nfe(self):
with self.assertRaises(Exception):
invoice_eletronic.action_send_eletronic_invoice()
- @patch('odoo.addons.br_nfe.models.invoice_eletronic.retorno_autorizar_nfe')
- @patch('odoo.addons.br_nfe.models.invoice_eletronic.autorizar_nfe')
- def test_wrong_xml_schema(self, autorizar, ret_autorizar):
- for invoice in self.invoices:
- # Confirmando a fatura deve gerar um documento eletrônico
- invoice.action_invoice_open()
-
- # Lote recebido com sucesso
- xml_recebido = open(os.path.join(
- self.caminho, 'xml/lote-recebido-sucesso.xml'), 'r').read()
- resp = sanitize_response(xml_recebido)
- autorizar.return_value = {
- 'object': resp[1],
- 'sent_xml': '',
- 'received_xml': xml_recebido
- }
-
- # Consultar recibo com erro 225
- xml_recebido = open(os.path.join(
- self.caminho, 'xml/recibo-erro-schema-225.xml'), 'r').read()
- resp_ret = sanitize_response(xml_recebido)
- ret_autorizar.return_value = {
- 'object': resp_ret[1],
- 'sent_xml': '',
- 'received_xml': xml_recebido
- }
-
- invoice_eletronic = self.env['invoice.eletronic'].search(
- [('invoice_id', '=', invoice.id)])
- invoice_eletronic.action_send_eletronic_invoice()
- self.assertEquals(invoice_eletronic.state, 'error')
- self.assertEquals(invoice_eletronic.codigo_retorno, '225')
-
@patch('odoo.addons.br_nfe.models.invoice_eletronic.retorno_autorizar_nfe')
@patch('odoo.addons.br_nfe.models.invoice_eletronic.autorizar_nfe')
def test_nfe_with_concept_error(self, autorizar, ret_autorizar):
@@ -432,6 +399,6 @@ def test_nfe_cancelamento_ok(self, cancelar, consulta):
justificativa="Cancelamento de teste")
self.assertEquals(invoice_eletronic.state, 'cancel')
- self.assertEquals(invoice_eletronic.codigo_retorno, "155")
+ self.assertEquals(invoice_eletronic.codigo_retorno, "135")
self.assertEquals(invoice_eletronic.mensagem_retorno,
- "Cancelamento homologado fora de prazo")
+ "Evento registrado e vinculado a NF-e")
diff --git a/br_nfe/tests/xml/cancelamento-sucesso.xml b/br_nfe/tests/xml/cancelamento-sucesso.xml
index 02c0ac7af..7c8e29fbe 100644
--- a/br_nfe/tests/xml/cancelamento-sucesso.xml
+++ b/br_nfe/tests/xml/cancelamento-sucesso.xml
@@ -1,36 +1,25 @@
-
-
-
-
-
- 33
- 2
- SP_EVENTOS_PL_100
- 35
- 128
- Lote de Evento Processado
-
-
- 2
- SP_EVENTOS_PL_100
- 35
- 155
- Cancelamento homologado fora de prazo
- 35161021332917000163550010000000321243582205
- 110111
- Cancelamento registrado
- 1
- 06621204930
- 2016-11-03T20:11:37-02:00
- 135160008042297
-
-
-
-
-
-
+
+
+ 30
+ 2
+ SVRS201806290759
+ 42
+ 128
+ Lote de Evento Processado
+
+
+ 2
+ SVRS201806290759
+ 42
+ 135
+ Evento registrado e vinculado a NF-e
+ 42180780164221000215550010000006071576626530
+ 110111
+ 1
+ 00010349910944
+ 2018-07-31T11:12:28-03:00
+ 342180004306498
+
+
+
+
diff --git a/br_nfe/tests/xml/cce-retorno.xml b/br_nfe/tests/xml/cce-retorno.xml
index 577ed39e3..1a24f4532 100644
--- a/br_nfe/tests/xml/cce-retorno.xml
+++ b/br_nfe/tests/xml/cce-retorno.xml
@@ -1,37 +1,25 @@
-
-
-
-
- 35
- 1.00
-
-
-
-
-
- 15
- 2
- SP_EVENTOS_PL_100
- 35
- 128
- Lote de Evento Processado
-
-
- 2
- SP_EVENTOS_PL_100
- 35
- 135
- Evento registrado e vinculado a NF-e
- 35161221332917000163550010000000041158176721
- 110110
- Carta de Correcao registrada
- 3
- 14452933000124
- 2016-12-19T12:50:49-02:00
- 135160008802236
-
-
-
-
-
-
+
+
+ 1
+ 2
+ SVRS201806290759
+ 42
+ 128
+ Lote de Evento Processado
+
+
+ 2
+ SVRS201806290759
+ 42
+ 135
+ Evento registrado e vinculado a NF-e
+ 42180780164221000215550010000006071576626530
+ 110110
+ 1
+ 00010349910944
+ 2018-07-31T11:05:58-03:00
+ 135160008802236
+
+
+
+
diff --git a/br_nfe/tests/xml/inutilizacao_falha_schema.xml b/br_nfe/tests/xml/inutilizacao_falha_schema.xml
new file mode 100644
index 000000000..f3c6359e9
--- /dev/null
+++ b/br_nfe/tests/xml/inutilizacao_falha_schema.xml
@@ -0,0 +1,12 @@
+
+
+
+ 2
+ SVRS201806282144
+ 215
+ Rejeicao: Falha no schema XML
+ 42
+ 2018-07-31T10:06:33-03:00
+
+
+
diff --git a/br_nfe/tests/xml/inutilizacao_received_ok_xml.xml b/br_nfe/tests/xml/inutilizacao_received_ok_xml.xml
index 5d42159e1..4cd40aa1f 100644
--- a/br_nfe/tests/xml/inutilizacao_received_ok_xml.xml
+++ b/br_nfe/tests/xml/inutilizacao_received_ok_xml.xml
@@ -1 +1,19 @@
-113.102SVRS201601161002102Rejeicao: Falha no schema XML112017-01-17T17:32:18-04:00
+
+
+
+ 2
+ SVRS201806282144
+ 102
+ Inutilizacao de numero homologado
+ 42
+ 18
+ 80164221006215
+ 55
+ 1
+ 600
+ 601
+ 2018-07-31T10:00:38-03:00
+ 342180004306034
+
+
+
diff --git a/br_nfe/tests/xml/inutilizacao_received_xml.xml b/br_nfe/tests/xml/inutilizacao_received_xml.xml
deleted file mode 100644
index be69eb582..000000000
--- a/br_nfe/tests/xml/inutilizacao_received_xml.xml
+++ /dev/null
@@ -1 +0,0 @@
-113.102SVRS201601161002215Rejeicao: Falha no schema XML112017-01-17T17:32:18-04:00
diff --git a/br_nfe/tests/xml/lote-recebido-sucesso.xml b/br_nfe/tests/xml/lote-recebido-sucesso.xml
index 202544ac5..4f198947f 100644
--- a/br_nfe/tests/xml/lote-recebido-sucesso.xml
+++ b/br_nfe/tests/xml/lote-recebido-sucesso.xml
@@ -1,25 +1,14 @@
-
-
-
-
- 42
- 3.10
-
-
-
-
-
- 2
- SP_NFE_PL_008i2
- 103
- Lote recebido com sucesso
- 42
- 2016-10-12T11:46:08-03:00
-
- 351000104734849
- 1
-
-
-
-
-
+
+
+ 2
+ SVRS201807191353
+ 103
+ Lote recebido com sucesso
+ 42
+ 2018-07-31T10:53:25-03:00
+
+ 423002181689172
+ 1
+
+
+
diff --git a/br_nfe/tests/xml/recibo-erro-694.xml b/br_nfe/tests/xml/recibo-erro-694.xml
index 3a129255f..5e23b18c9 100644
--- a/br_nfe/tests/xml/recibo-erro-694.xml
+++ b/br_nfe/tests/xml/recibo-erro-694.xml
@@ -1,32 +1,24 @@
-
-
-
-
- 42
- 3.10
-
-
-
-
-
- 2
- SP_NFE_PL_008i2
- 351000104734849
- 104
- Lote processado
- 42
- 2016-10-12T11:46:08-03:00
-
-
- 2
- SP_NFE_PL_008i2
- 35161021332917000163550010000000011178586888
- 2016-10-12T11:46:08-03:00
- 694
- Rejeicao: Nao informado o grupo de ICMS para a UF de destino [nItem:1]
-
-
-
-
-
-
+
+
+ 2
+ SVRS201807240822
+ 423002181690719
+ 104
+ Lote processado
+ 42
+ 2018-07-31T11:28:59-03:00
+
+
+ 2
+ SVRS201807240822
+ 42180780164221000215550010000006081271576374
+ 2018-07-31T11:28:59-03:00
+ oIIfUW/HcKFT2tZAaqI17rSBzmU=
+ 694
+
+ Rejeicao: CFOP de operacao interestadual e idDest diferente de 2
+
+
+
+
+
diff --git a/br_nfe/tests/xml/recibo-erro-schema-225.xml b/br_nfe/tests/xml/recibo-erro-schema-225.xml
deleted file mode 100644
index 917ec9518..000000000
--- a/br_nfe/tests/xml/recibo-erro-schema-225.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
- 42
- 3.10
-
-
-
-
-
- 2
- SP_NFE_PL_008i2
- 351000105223918
- 225
- Rejeicao: Falha no Schema XML do lote de NFe
- 42
- 2016-10-22T08:18:04-02:00
-
-
-
-
diff --git a/br_nfe/views/inutilized_nfe.xml b/br_nfe/views/inutilized_nfe.xml
index 1c442ea3c..de985f13a 100644
--- a/br_nfe/views/inutilized_nfe.xml
+++ b/br_nfe/views/inutilized_nfe.xml
@@ -43,6 +43,10 @@
+
+
+
+
diff --git a/br_nfe/views/invoice_eletronic.xml b/br_nfe/views/invoice_eletronic.xml
index 5d67e2daf..cc208e1d6 100644
--- a/br_nfe/views/invoice_eletronic.xml
+++ b/br_nfe/views/invoice_eletronic.xml
@@ -18,6 +18,9 @@
string="Carta de Correção" attrs="{'invisible': ['|', ('state', '!=', 'done'), ('model', 'not in', ('55', '65'))]}">
+
+
+
diff --git a/br_nfe/views/payment_mode.xml b/br_nfe/views/payment_mode.xml
new file mode 100644
index 000000000..5e6b8636e
--- /dev/null
+++ b/br_nfe/views/payment_mode.xml
@@ -0,0 +1,15 @@
+
+
+
+
+ view.br.nfe.payment.mode.form
+ payment.mode
+
+
+
+
+
+
+
+
+
diff --git a/br_nfe/wizard/cancel_nfe.py b/br_nfe/wizard/cancel_nfe.py
index acb42b8e4..b364194db 100644
--- a/br_nfe/wizard/cancel_nfe.py
+++ b/br_nfe/wizard/cancel_nfe.py
@@ -11,11 +11,19 @@ class CancelNFe(models.TransientModel):
edoc_id = fields.Many2one('invoice.eletronic', string="Documento")
justificativa = fields.Text('Justificativa', size=255, required=True)
+ state = fields.Selection([('drat', u'Provisório'), ('error', u'Erro')],
+ string="Situação")
+ message = fields.Char(string=u"Mensagem", size=300, readonly=True)
+ sent_xml = fields.Binary(string="Xml Envio", readonly=True)
+ sent_xml_name = fields.Char(string=u"Xml Envio", size=30, readonly=True)
+ received_xml = fields.Binary(string=u"Xml Recebimento", readonly=True)
+ received_xml_name = fields.Char(
+ string=u"Xml Recebimento", size=30, readonly=True)
@api.multi
def action_cancel_nfe(self):
if self.edoc_id and len(self.justificativa) > 15:
- self.edoc_id.action_cancel_document(
+ return self.edoc_id.action_cancel_document(
justificativa=self.justificativa)
else:
raise UserError(u"Justificativa deve ter mais de 15 caracteres")
diff --git a/br_nfe/wizard/cancel_nfe.xml b/br_nfe/wizard/cancel_nfe.xml
index 6edab6a03..55ee025d3 100644
--- a/br_nfe/wizard/cancel_nfe.xml
+++ b/br_nfe/wizard/cancel_nfe.xml
@@ -6,9 +6,17 @@