From 9c0fed19b3a80c070be9a2b1d912d1dae41427dd Mon Sep 17 00:00:00 2001 From: Magno Date: Tue, 5 Jun 2018 12:30:31 -0300 Subject: [PATCH 01/34] Included option to select new NFe 4.00 layout. --- l10n_br_account_product/models/account_invoice.py | 5 +++-- l10n_br_account_product/models/res_company.py | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/l10n_br_account_product/models/account_invoice.py b/l10n_br_account_product/models/account_invoice.py index ce3e83a21a9d..333c99c29c38 100644 --- a/l10n_br_account_product/models/account_invoice.py +++ b/l10n_br_account_product/models/account_invoice.py @@ -161,8 +161,9 @@ def _compute_cfops(self): 'Série NF Entrada', size=12, readonly=True, states={'draft': [('readonly', False)]}, help=u"Série do número da Nota Fiscal do Fornecedor") - nfe_version = fields.Selection( - [('1.10', '1.10'), ('2.00', '2.00'), ('3.10', '3.10')], + nfe_version = fields.Selection([ + ('1.10', '1.10'), ('2.00', '2.00'), + ('3.10', '3.10'), ('4.00', '4.00')], u'Versão NFe', readonly=True, default=_default_nfe_version, states={'draft': [('readonly', False)]}) date_hour_invoice = fields.Datetime( diff --git a/l10n_br_account_product/models/res_company.py b/l10n_br_account_product/models/res_company.py index 65c673dcad29..719eadbdfc43 100644 --- a/l10n_br_account_product/models/res_company.py +++ b/l10n_br_account_product/models/res_company.py @@ -28,9 +28,10 @@ def _compute_taxes(self): 'document_serie_product_id', 'Série de Documentos Fiscais', domain="[('company_id', '=', active_id),('active','=',True)," "('fiscal_type','=','product')]") - nfe_version = fields.Selection( - [('1.10', '1.10'), ('2.00', '2.00'), ('3.10', '3.10')], u'Versão NFe', - required=True, default='3.10') + nfe_version = fields.Selection([ + ('1.10', '1.10'), ('2.00', '2.00'), + ('3.10', '3.10'), ('4.00', '4.00')], + u'Versão NFe', required=True, default='4.00') nfe_import_folder = fields.Char('Pasta de Importação', size=254) nfe_export_folder = fields.Char('Pasta de Exportação', size=254) nfe_backup_folder = fields.Char('Pasta de Backup', size=254) From 3297d4478f1fdc1b43f90e36b3c09679737cbffa Mon Sep 17 00:00:00 2001 From: Magno Date: Tue, 5 Jun 2018 16:57:34 -0300 Subject: [PATCH 02/34] Included NFe 4.00 PySPED imports. --- l10n_br_account_product/sped/nfe/document.py | 87 +++++++++++++++++++ .../sped/nfe/serializer/xml.py | 5 +- 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/l10n_br_account_product/sped/nfe/document.py b/l10n_br_account_product/sped/nfe/document.py index f5b8b02f4013..d26d635232a2 100644 --- a/l10n_br_account_product/sped/nfe/document.py +++ b/l10n_br_account_product/sped/nfe/document.py @@ -80,6 +80,13 @@ def _serializer(self, cr, uid, ids, nfe_environment, context=None): except AttributeError: pass + self.pag = self._get_Pag() + self._details_pag(invoice) + + self.detPag = self._get_DetPag() + self._details_pag_data(invoice) + self.nfe.infNFe.pag.detPag.append(self.detPag) + self.vol = self._get_Vol() self._weight_data(invoice) self.nfe.infNFe.transp.vol.append(self.vol) @@ -818,3 +825,83 @@ def _get_AutXML(self): raise UserError( _(u'Erro!'), _(u"Biblioteca PySPED não instalada!")) return AutXML_310() + + +class NFe400(NFe310): + def __init__(self): + super(NFe400, self).__init__() + + def _details_pag(self, invoice): + # TODO + self.pag.vTroco.valor = '' + + def _details_pag_data(self, invoice): + # TODO + self.detPag.tPag.valor = '14' + self.detPag.vPag.valor = '0' + + def get_NFe(self): + try: + from pysped.nfe.leiaute import NFe_400 + except ImportError: + raise UserError( + _(u'Erro!'), _(u"Biblioteca PySPED não instalada!")) + + return NFe_400() + + def _get_NFRef(self): + try: + from pysped.nfe.leiaute import NFRef_400 + except ImportError: + raise UserError( + _(u'Erro!'), _(u"Biblioteca PySPED não instalada!")) + + return NFRef_400() + + def _get_Det(self): + try: + from pysped.nfe.leiaute import Det_400 + except ImportError: + raise UserError( + _(u'Erro!'), _(u"Biblioteca PySPED não instalada!")) + return Det_400() + + def _get_Dup(self): + try: + from pysped.nfe.leiaute import Dup_400 + except ImportError: + raise UserError( + _(u'Erro!'), _(u"Biblioteca PySPED não instalada!")) + return Dup_400() + + def _get_DI(self): + try: + from pysped.nfe.leiaute import DI_400 + except ImportError: + raise UserError( + _(u'Erro!'), _(u"Biblioteca PySPED não instalada!")) + return DI_400() + + def _get_Pag(self): + try: + from pysped.nfe.leiaute import Pag_400 + except ImportError: + raise UserError( + _(u'Erro!'), _(u"Biblioteca PySPED não instalada!")) + return Pag_400() + + def _get_DetPag(self): + try: + from pysped.nfe.leiaute import DetPag_400 + except ImportError: + raise UserError( + _(u'Erro!'), _(u"Biblioteca PySPED não instalada!")) + return DetPag_400() + + def _get_AutXML(self): + try: + from pysped.nfe.leiaute import AutXML_400 + except ImportError: + raise UserError( + _(u'Erro!'), _(u"Biblioteca PySPED não instalada!")) + return AutXML_400() diff --git a/l10n_br_account_product/sped/nfe/serializer/xml.py b/l10n_br_account_product/sped/nfe/serializer/xml.py index e1b2de635c7b..577cf3633857 100644 --- a/l10n_br_account_product/sped/nfe/serializer/xml.py +++ b/l10n_br_account_product/sped/nfe/serializer/xml.py @@ -4,12 +4,15 @@ from ..document import NFe200 from ..document import NFe310 +from ..document import NFe400 def nfe_export(cr, uid, ids, nfe_environment='1', nfe_version='2.00', context=None): - if nfe_version == '3.10': + if nfe_version == '4.00': + NFe = NFe400() + elif nfe_version == '3.10': NFe = NFe310() else: NFe = NFe200() From 69696610b119ef76f81c681578c47bf36e7967cb Mon Sep 17 00:00:00 2001 From: Magno Date: Tue, 5 Jun 2018 17:51:50 -0300 Subject: [PATCH 03/34] Normalize filds with non ASCII characters. --- l10n_br_account_product/sped/nfe/document.py | 60 +++++++++++++------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/l10n_br_account_product/sped/nfe/document.py b/l10n_br_account_product/sped/nfe/document.py index d26d635232a2..b4e46d80cc20 100644 --- a/l10n_br_account_product/sped/nfe/document.py +++ b/l10n_br_account_product/sped/nfe/document.py @@ -233,18 +233,24 @@ def _emmiter(self, invoice, company): self.nfe.infNFe.emit.CNPJ.valor = punctuation_rm( invoice.company_id.partner_id.cnpj_cpf) - self.nfe.infNFe.emit.xNome.valor = ( - invoice.company_id.partner_id.legal_name[:60]) + self.nfe.infNFe.emit.xNome.valor = (normalize( + 'NFKD', unicode( + invoice.company_id.partner_id.legal_name[:60])).encode( + 'ASCII', 'ignore')) self.nfe.infNFe.emit.xFant.valor = invoice.company_id.partner_id.name - self.nfe.infNFe.emit.enderEmit.xLgr.valor = company.street or '' + self.nfe.infNFe.emit.enderEmit.xLgr.valor = (normalize( + 'NFKD', unicode(company.street or '')).encode('ASCII', 'ignore')) self.nfe.infNFe.emit.enderEmit.nro.valor = company.number or '' - self.nfe.infNFe.emit.enderEmit.xCpl.valor = company.street2 or '' - self.nfe.infNFe.emit.enderEmit.xBairro.valor = ( - company.district or 'Sem Bairro') + self.nfe.infNFe.emit.enderEmit.xCpl.valor = (normalize( + 'NFKD', unicode(company.street2 or '')).encode('ASCII', 'ignore')) + self.nfe.infNFe.emit.enderEmit.xBairro.valor = (normalize( + 'NFKD', unicode( + company.district or 'Sem Bairro')).encode('ASCII', 'ignore')) self.nfe.infNFe.emit.enderEmit.cMun.valor = '%s%s' % ( company.state_id.ibge_code, company.l10n_br_city_id.ibge_code) - self.nfe.infNFe.emit.enderEmit.xMun.valor = ( - company.l10n_br_city_id.name or '') + self.nfe.infNFe.emit.enderEmit.xMun.valor = (normalize( + 'NFKD', unicode( + company.l10n_br_city_id.name or '')).encode('ASCII', 'ignore')) self.nfe.infNFe.emit.enderEmit.UF.valor = company.state_id.code or '' self.nfe.infNFe.emit.enderEmit.CEP.valor = punctuation_rm( company.zip or '') @@ -282,8 +288,10 @@ def _receiver(self, invoice, company, nfe_environment): address_invoice_city_code = '9999999' else: address_invoice_state_code = invoice.partner_id.state_id.code - address_invoice_city = ( - invoice.partner_id.l10n_br_city_id.name or '') + address_invoice_city = (normalize( + 'NFKD', unicode( + invoice.partner_id.l10n_br_city_id.name or '')).encode( + 'ASCII', 'ignore')) address_invoice_city_code = ('%s%s') % ( invoice.partner_id.state_id.ibge_code, invoice.partner_id.l10n_br_city_id.ibge_code) @@ -295,8 +303,10 @@ def _receiver(self, invoice, company, nfe_environment): self.nfe.infNFe.dest.xNome.valor = ( 'NF-E EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL') else: - self.nfe.infNFe.dest.xNome.valor = ( - invoice.partner_id.legal_name[:60] or '') + self.nfe.infNFe.dest.xNome.valor = (normalize( + 'NFKD', unicode( + invoice.partner_id.legal_name[:60] or '') + ).encode('ASCII', 'ignore')) if invoice.partner_id.is_company: self.nfe.infNFe.dest.IE.valor = punctuation_rm( @@ -314,14 +324,17 @@ def _receiver(self, invoice, company, nfe_environment): self.nfe.infNFe.dest.indIEDest.valor = \ invoice.partner_id.partner_fiscal_type_id.ind_ie_dest - self.nfe.infNFe.dest.enderDest.xLgr.valor = ( - invoice.partner_id.street or '') + self.nfe.infNFe.dest.enderDest.xLgr.valor = (normalize( + 'NFKD', unicode( + invoice.partner_id.street or '')).encode('ASCII', 'ignore')) self.nfe.infNFe.dest.enderDest.nro.valor = ( invoice.partner_id.number or '') - self.nfe.infNFe.dest.enderDest.xCpl.valor = ( - invoice.partner_id.street2 or '') - self.nfe.infNFe.dest.enderDest.xBairro.valor = ( - invoice.partner_id.district or 'Sem Bairro') + self.nfe.infNFe.dest.enderDest.xCpl.valor = (normalize( + 'NFKD', unicode( + invoice.partner_id.street2 or '')).encode('ASCII', 'ignore')) + self.nfe.infNFe.dest.enderDest.xBairro.valor = (normalize( + 'NFKD', unicode( + invoice.partner_id.district or 'Sem Bairro')).encode('ASCII', 'ignore')) self.nfe.infNFe.dest.enderDest.cMun.valor = address_invoice_city_code self.nfe.infNFe.dest.enderDest.xMun.valor = address_invoice_city self.nfe.infNFe.dest.enderDest.UF.valor = address_invoice_state_code @@ -342,11 +355,16 @@ def _details(self, invoice, invoice_line, index): self.det.prod.cProd.valor = invoice_line.product_id.code or '' self.det.prod.cEAN.valor = invoice_line.product_id.ean13 or '' self.det.prod.cEANTrib.valor = invoice_line.product_id.ean13 or '' - self.det.prod.xProd.valor = ( - invoice_line.product_id.name[:120] or '') + self.det.prod.xProd.valor = (normalize( + 'NFKD', unicode( + invoice_line.product_id.name[:120] or '') + ).encode('ASCII', 'ignore')) else: self.det.prod.cProd.valor = invoice_line.code or '' - self.det.prod.xProd.valor = invoice_line.name[:120] or '' + self.det.prod.xProd.valor = (normalize( + 'NFKD', unicode( + invoice_line.name[:120] or '') + ).encode('ASCII', 'ignore')) self.det.prod.NCM.valor = punctuation_rm( invoice_line.fiscal_classification_id.code or '')[:8] From abd7376f11c85e99264d8e6cac44a6153bf796cb Mon Sep 17 00:00:00 2001 From: Magno Date: Wed, 6 Jun 2018 13:58:36 -0300 Subject: [PATCH 04/34] =?UTF-8?q?Included=20fields=20refer=20to=20'Informa?= =?UTF-8?q?=C3=A7=C3=B5es=20de=20Pagamento'=20to=20the=20new=20layout=20of?= =?UTF-8?q?=20NFe=204.00=20.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- l10n_br_account_product/__openerp__.py | 2 ++ l10n_br_account_product/models/__init__.py | 1 + .../models/account_invoice.py | 27 ++++++++++++++++ .../models/account_payment.py | 31 +++++++++++++++++++ l10n_br_account_product/sped/nfe/document.py | 10 +++--- .../views/account_invoice_view.xml | 0 .../views/account_payment_view.xml | 17 ++++++++++ .../views/nfe/account_invoice_nfe_view.xml | 2 ++ 8 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 l10n_br_account_product/models/account_payment.py mode change 100755 => 100644 l10n_br_account_product/views/account_invoice_view.xml create mode 100644 l10n_br_account_product/views/account_payment_view.xml diff --git a/l10n_br_account_product/__openerp__.py b/l10n_br_account_product/__openerp__.py index 08603dd5860f..21c135035747 100644 --- a/l10n_br_account_product/__openerp__.py +++ b/l10n_br_account_product/__openerp__.py @@ -13,6 +13,7 @@ 'depends': [ 'l10n_br_data_account', 'account_product_fiscal_classification', + 'account_payment', ], 'data': [ 'l10n_br_account_product_sequence.xml', @@ -35,6 +36,7 @@ 'views/account_product_fiscal_classification_view.xml', 'views/product_view.xml', 'views/res_country_view.xml', + 'views/account_payment_view.xml', 'wizard/l10n_br_account_nfe_export_invoice_view.xml', 'wizard/l10n_br_account_nfe_export_view.xml', 'wizard/l10n_br_account_document_status_sefaz_view.xml', diff --git a/l10n_br_account_product/models/__init__.py b/l10n_br_account_product/models/__init__.py index b91f40389794..c5b3284d5b99 100644 --- a/l10n_br_account_product/models/__init__.py +++ b/l10n_br_account_product/models/__init__.py @@ -11,3 +11,4 @@ from . import account from . import product from . import res_country +from . import account_payment diff --git a/l10n_br_account_product/models/account_invoice.py b/l10n_br_account_product/models/account_invoice.py index 333c99c29c38..fc7ff64bc1b8 100644 --- a/l10n_br_account_product/models/account_invoice.py +++ b/l10n_br_account_product/models/account_invoice.py @@ -390,6 +390,26 @@ def _compute_cfops(self): store=True, digits=dp.get_precision('Account'), compute='_compute_amount') + type_nf_payment = fields.Selection([ + ('01', u'01 - Dinheiro'), + ('02', u'02 - Cheque'), + ('03', u'03 - Cartão de Crédito'), + ('04', u'04 - Cartão de Débito'), + ('06', u'05 - Crédito Loja'), + ('10', u'10 - Vale Alimentação'), + ('11', u'11 - Vale Refeição'), + ('12', u'12 - Vale Presente'), + ('13', u'13 - Vale Combustível'), + ('14', u'14 - Duplicata Mercantil'), + ('15', u'15 - Boleto Bancário'), + ('90', u'90 - Sem pagamento'), + ('99', u'99 - Outros') + ], string='Tipo de Pagamento da NF', required=True, + help=u'Obrigatório o preenchimento do Grupo Informações de Pagamento' + u' para NF-e e NFC-e. Para as notas com finalidade de Ajuste' + u' ou Devolução o campo Forma de Pagamento deve ser preenchido' + u' com 90 - Sem Pagamento.' + ) @api.one @api.constrains('number') @@ -640,6 +660,13 @@ def open_fiscal_document(self): result['name'] = _('NF-e') return result + @api.onchange('payment_mode_id') + def onchange_payment_mode(self): + for record in self: + if record.payment_mode_id: + record.type_nf_payment = \ + record.payment_mode_id.type_nf_payment + class AccountInvoiceLine(models.Model): _inherit = 'account.invoice.line' diff --git a/l10n_br_account_product/models/account_payment.py b/l10n_br_account_product/models/account_payment.py new file mode 100644 index 000000000000..ee847493762b --- /dev/null +++ b/l10n_br_account_product/models/account_payment.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# @ 2018 Akretion - www.akretion.com.br - +# Magno Costa +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) + +from openerp import models, api, fields + + +class PaymentMode(models.Model): + _inherit = 'payment.mode' + + type_nf_payment = fields.Selection([ + ('01', u'01 - Dinheiro'), + ('02', u'02 - Cheque'), + ('03', u'03 - Cartão de Crédito'), + ('04', u'04 - Cartão de Débito'), + ('06', u'05 - Crédito Loja'), + ('10', u'10 - Vale Alimentação'), + ('11', u'11 - Vale Refeição'), + ('12', u'12 - Vale Presente'), + ('13', u'13 - Vale Combustível'), + ('14', u'14 - Duplicata Mercantil'), + ('15', u'15 - Boleto Bancário'), + ('90', u'90 - Sem pagamento'), + ('99', u'99 - Outros') + ], string='Tipo de Pagamento da NF', required=True, + help=u'Obrigatório o preenchimento do Grupo Informações de Pagamento' + u' para NF-e e NFC-e. Para as notas com finalidade de Ajuste' + u' ou Devolução o campo Forma de Pagamento deve ser preenchido' + u' com 90 - Sem Pagamento.' + ) diff --git a/l10n_br_account_product/sped/nfe/document.py b/l10n_br_account_product/sped/nfe/document.py index b4e46d80cc20..017e56d2c26b 100644 --- a/l10n_br_account_product/sped/nfe/document.py +++ b/l10n_br_account_product/sped/nfe/document.py @@ -850,13 +850,15 @@ def __init__(self): super(NFe400, self).__init__() def _details_pag(self, invoice): - # TODO + # TODO - implementar campo self.pag.vTroco.valor = '' def _details_pag_data(self, invoice): - # TODO - self.detPag.tPag.valor = '14' - self.detPag.vPag.valor = '0' + # TODO - existe a possibilidade de pagar uma parte + # em uma forma de pagto e outra parte em outra + # ex.: metade em dinheiro e metade boleto + self.detPag.tPag.valor = invoice.type_nf_payment + self.detPag.vPag.valor = invoice.amount_total def get_NFe(self): try: diff --git a/l10n_br_account_product/views/account_invoice_view.xml b/l10n_br_account_product/views/account_invoice_view.xml old mode 100755 new mode 100644 diff --git a/l10n_br_account_product/views/account_payment_view.xml b/l10n_br_account_product/views/account_payment_view.xml new file mode 100644 index 000000000000..d9a716a5d807 --- /dev/null +++ b/l10n_br_account_product/views/account_payment_view.xml @@ -0,0 +1,17 @@ + + + + + + l10n_br_account_product.payment.mode.form + payment.mode + + + + + + + + + + diff --git a/l10n_br_account_product/views/nfe/account_invoice_nfe_view.xml b/l10n_br_account_product/views/nfe/account_invoice_nfe_view.xml index 151525ed4679..3add7816812d 100755 --- a/l10n_br_account_product/views/nfe/account_invoice_nfe_view.xml +++ b/l10n_br_account_product/views/nfe/account_invoice_nfe_view.xml @@ -172,6 +172,8 @@ + + From 89cb11c505bf250df5c00acb84832e9774e9c84d Mon Sep 17 00:00:00 2001 From: Magno Date: Thu, 7 Jun 2018 12:55:08 -0300 Subject: [PATCH 05/34] Update field indPres to the new layout of NFe 4.00 . --- l10n_br_account_product/models/account_invoice.py | 4 +++- l10n_br_sale_product/models/res_company.py | 4 +++- l10n_br_sale_product/models/sale.py | 10 ++++++---- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/l10n_br_account_product/models/account_invoice.py b/l10n_br_account_product/models/account_invoice.py index fc7ff64bc1b8..c3ef7c531429 100644 --- a/l10n_br_account_product/models/account_invoice.py +++ b/l10n_br_account_product/models/account_invoice.py @@ -178,11 +178,13 @@ def _compute_cfops(self): states={'draft': [('readonly', False)]}, required=False, help=u'Indica operação com Consumidor final.') ind_pres = fields.Selection([ - ('0', u'Não se aplica'), + ('0', u'Não se aplica (por exemplo,' + u' Nota Fiscal complementar ou de ajuste)'), ('1', u'Operação presencial'), ('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', readonly=True, states={'draft': [('readonly', False)]}, required=False, diff --git a/l10n_br_sale_product/models/res_company.py b/l10n_br_sale_product/models/res_company.py index 88f630a8f164..77bed8907105 100644 --- a/l10n_br_sale_product/models/res_company.py +++ b/l10n_br_sale_product/models/res_company.py @@ -9,11 +9,13 @@ class ResCompany(models.Model): _inherit = 'res.company' default_ind_pres = fields.Selection([ - ('0', u'Não se aplica'), + ('0', u'Não se aplica (por exemplo,' + u' Nota Fiscal complementar ou de ajuste)'), ('1', u'Operação presencial'), ('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 \ diff --git a/l10n_br_sale_product/models/sale.py b/l10n_br_sale_product/models/sale.py index f3a5ff0521c1..5a0eee6f6ff7 100644 --- a/l10n_br_sale_product/models/sale.py +++ b/l10n_br_sale_product/models/sale.py @@ -138,14 +138,16 @@ def _set_amount_costs(self): return True ind_pres = fields.Selection([ - ('0', u'Não se aplica'), + ('0', u'Não se aplica (por exemplo,' + u' Nota Fiscal complementar ou de ajuste)'), ('1', u'Operação presencial'), ('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'), - ('9', u'Operação não presencial, outros')], u'Tipo de operação', - readonly=True, states={'draft': [('readonly', False)]}, - required=False, + ('5', u'Operação presencial, fora do estabelecimento'), + ('9', u'Operação não presencial, outros') + ], u'Tipo de operação', readonly=True, + states={'draft': [('readonly', False)]}, required=False, help=u'Indicador de presença do comprador no estabelecimento \ comercial no momento da operação.', default=_default_ind_pres) amount_untaxed = fields.Float( From 822177aecf67734c9b61dc3035a856e23e429f50 Mon Sep 17 00:00:00 2001 From: Magno Date: Wed, 17 Jan 2018 18:31:11 -0200 Subject: [PATCH 06/34] =?UTF-8?q?Included=20field=20to=20allow=20inform=20?= =?UTF-8?q?Inscri=C3=A7=C3=B5es=20Estaduais=20to=20other=20states=20differ?= =?UTF-8?q?ent=20from=20the=20partner=20state.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- l10n_br_base/models/res_company.py | 20 ++++++++++ l10n_br_base/models/res_partner.py | 50 +++++++++++++++++++++++++ l10n_br_base/views/res_company_view.xml | 7 ++++ l10n_br_base/views/res_partner_view.xml | 10 +++++ 4 files changed, 87 insertions(+) diff --git a/l10n_br_base/models/res_company.py b/l10n_br_base/models/res_company.py index 09c20b1df40f..5d7260deae0f 100644 --- a/l10n_br_base/models/res_company.py +++ b/l10n_br_base/models/res_company.py @@ -28,6 +28,10 @@ def _get_l10n_br_data(self): obj.inscr_est = obj.partner_id.inscr_est obj.inscr_mun = obj.partner_id.inscr_mun obj.suframa = obj.partner_id.suframa + other_inscr_est_lines = self.env['other.inscricoes.estaduais'] + for inscr_est_line in obj.partner_id.other_inscr_est_lines: + other_inscr_est_lines |= inscr_est_line + obj.other_inscr_est_lines = other_inscr_est_lines @api.multi def _set_l10n_br_legal_name(self): @@ -59,6 +63,15 @@ def _set_l10n_br_inscr_est(self): self.ensure_one() self.partner_id.inscr_est = self.inscr_est + @api.multi + def _set_l10n_br_other_inscr_est(self): + """ Write the l10n_br specific functional fields. """ + for record in self: + other_inscr_est_lines = self.env['other.inscricoes.estaduais'] + for inscr_est_line in record.other_inscr_est_lines: + other_inscr_est_lines |= inscr_est_line + record.partner_id.other_inscr_est_lines = other_inscr_est_lines + @api.multi def _set_l10n_br_inscr_mun(self): """ Write the l10n_br specific functional fields. """ @@ -97,6 +110,12 @@ def _set_l10n_br_suframa(self): compute=_get_l10n_br_data, inverse=_set_l10n_br_inscr_est, size=16, string='Inscr. Estadual') + other_inscr_est_lines = fields.One2many( + 'other.inscricoes.estaduais', 'partner_id', + compute=_get_l10n_br_data, inverse=_set_l10n_br_other_inscr_est, + string=u'Outras Inscrições Estaduais', ondelete='cascade' + ) + inscr_mun = fields.Char( compute=_get_l10n_br_data, inverse=_set_l10n_br_inscr_mun, size=18, string='Inscr. Municipal') @@ -139,3 +158,4 @@ def _onchange_zip(self): val = re.sub('[^0-9]', '', self.zip) if len(val) == 8: self.zip = "%s-%s" % (val[0:5], val[5:8]) + diff --git a/l10n_br_base/models/res_partner.py b/l10n_br_base/models/res_partner.py index 6770c50088e3..8e72c22eed8e 100644 --- a/l10n_br_base/models/res_partner.py +++ b/l10n_br_base/models/res_partner.py @@ -55,6 +55,10 @@ def _display_address(self, address, without_company=False): cnpj_cpf = fields.Char('CNPJ/CPF', size=18) inscr_est = fields.Char('Inscr. Estadual/RG', size=16) + other_inscr_est_lines = fields.One2many( + 'other.inscricoes.estaduais', 'partner_id', + string=u'Outras Inscrições Estaduais', ondelete='cascade' + ) inscr_mun = fields.Char('Inscr. Municipal', size=18) @@ -191,6 +195,34 @@ def _address_fields(self, cr, uid, context=None): cr, uid, context=context) return list(address_fields + ['l10n_br_city_id', 'number', 'district']) + @api.multi + @api.constrains('other_inscr_est_lines') + def _check_other_ie_lines(self): + """Checks if field other insc_est is valid, + this method call others methods because this validation is State wise + :Return: True or False. + """ + for record in self: + for inscr_est_line in record.other_inscr_est_lines: + valid_ie = True + state_code = inscr_est_line.state_id.code or '' + uf = state_code.lower() + valid_ie = fiscal.validate_ie(uf, inscr_est_line.inscr_est) + if not valid_ie: + raise ValidationError(u"Inscrição Estadual Invalida!") + if inscr_est_line.state_id.id == record.state_id.id: + raise ValidationError( + u"Somente pode existir uma Inscrição" + u" Estadual por estado para cada Parceiro!") + duplicate_ie = record.search([ + ('state_id', '=', inscr_est_line.state_id.id), + ('inscr_est', '=', inscr_est_line.inscr_est) + ]) + if duplicate_ie: + raise ValidationError( + u"Inscrição Estadual já usada" + u" por %s" % duplicate_ie.name) + class ResPartnerBank(models.Model): """ Adiciona campos necessários para o cadastramentos de contas @@ -232,3 +264,21 @@ def onchange_partner_id(self, partner_id): result['value']['district'] = partner.district result['value']['l10n_br_city_id'] = partner.l10n_br_city_id.id return result + + +class OtherInscricoesEstaduais(models.Model): + _name = 'other.inscricoes.estaduais' + + partner_id = fields.Many2one('res.partner') + inscr_est = fields.Char( + size=16, string='Inscr. Estadual', required=True + ) + state_id = fields.Many2one( + 'res.country.state', 'Estado', required=True + ) + + _sql_constraints = [ + ('other_inscricoes_estaduais_id_uniq', + 'unique (inscr_est, state_id)', + u'Inscrição Estadual já usada dentro do Estado!') + ] diff --git a/l10n_br_base/views/res_company_view.xml b/l10n_br_base/views/res_company_view.xml index 9564c75a7ca2..46a01a4e020a 100644 --- a/l10n_br_base/views/res_company_view.xml +++ b/l10n_br_base/views/res_company_view.xml @@ -38,6 +38,13 @@ + + + + + + + diff --git a/l10n_br_base/views/res_partner_view.xml b/l10n_br_base/views/res_partner_view.xml index 4ee1e0839ae3..efdaa934cc60 100644 --- a/l10n_br_base/views/res_partner_view.xml +++ b/l10n_br_base/views/res_partner_view.xml @@ -87,6 +87,16 @@ + + + + + + + + + + From 6df665fb1c899a6a8fc94a68d94aed17e785fd3d Mon Sep 17 00:00:00 2001 From: Magno Date: Wed, 17 Jan 2018 18:31:45 -0200 Subject: [PATCH 07/34] Configure tag IEST to NFe. --- l10n_br_account_product/sped/nfe/document.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/l10n_br_account_product/sped/nfe/document.py b/l10n_br_account_product/sped/nfe/document.py index 017e56d2c26b..666bfe71b229 100644 --- a/l10n_br_account_product/sped/nfe/document.py +++ b/l10n_br_account_product/sped/nfe/document.py @@ -261,7 +261,13 @@ def _emmiter(self, invoice, company): str(company.phone or '').replace(' ', '')) self.nfe.infNFe.emit.IE.valor = punctuation_rm( invoice.company_id.partner_id.inscr_est) - self.nfe.infNFe.emit.IEST.valor = '' + for inscr_est_line in\ + invoice.company_id.partner_id.other_inscr_est_lines: + if inscr_est_line.state_id.id == invoice.partner_id.state_id.id: + self.nfe.infNFe.emit.IEST.valor = punctuation_rm( + inscr_est_line.inscr_est) + else: + self.nfe.infNFe.emit.IEST.valor = '' self.nfe.infNFe.emit.IM.valor = punctuation_rm( invoice.company_id.partner_id.inscr_mun or '') self.nfe.infNFe.emit.CRT.valor = invoice.company_id.fiscal_type or '' From e592811e99bd7daedd7e03efabd8c2eb7f97e5bc Mon Sep 17 00:00:00 2001 From: Magno Date: Fri, 19 Jan 2018 11:37:55 -0200 Subject: [PATCH 08/34] Included access rules for object other.inscricoes.estaduais . --- l10n_br_base/security/ir.model.access.csv | 2 ++ 1 file changed, 2 insertions(+) diff --git a/l10n_br_base/security/ir.model.access.csv b/l10n_br_base/security/ir.model.access.csv index cea56b4834f9..a0a62c484209 100644 --- a/l10n_br_base/security/ir.model.access.csv +++ b/l10n_br_base/security/ir.model.access.csv @@ -1,3 +1,5 @@ "id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" "l10n_br_base_city_user","l10n_br_base.city","model_l10n_br_base_city","base.group_user",1,0,0,0 "l10n_br_base_city_manager","l10n_br_base.city","model_l10n_br_base_city","base.group_system",1,1,1,1 +"l10n_br_base_other_ie_user","l10n_br_base_other_ie","model_other_inscricoes_estaduais","base.group_user",1,0,0,0 +"l10n_br_base_other_ie_manager","l10n_br_base_other_ie","model_other_inscricoes_estaduais","base.group_system",1,1,1,1 From 34e858fc5cb25e27708bba8e00f3ca833c731f22 Mon Sep 17 00:00:00 2001 From: Magno Date: Fri, 19 Jan 2018 11:39:41 -0200 Subject: [PATCH 09/34] [FIX] SQL constraint and code for other.inscricoes.estaduais . --- l10n_br_base/models/res_company.py | 1 - l10n_br_base/models/res_partner.py | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/l10n_br_base/models/res_company.py b/l10n_br_base/models/res_company.py index 5d7260deae0f..d1224ea7c09d 100644 --- a/l10n_br_base/models/res_company.py +++ b/l10n_br_base/models/res_company.py @@ -158,4 +158,3 @@ def _onchange_zip(self): val = re.sub('[^0-9]', '', self.zip) if len(val) == 8: self.zip = "%s-%s" % (val[0:5], val[5:8]) - diff --git a/l10n_br_base/models/res_partner.py b/l10n_br_base/models/res_partner.py index 8e72c22eed8e..0ee1d44ade67 100644 --- a/l10n_br_base/models/res_partner.py +++ b/l10n_br_base/models/res_partner.py @@ -204,7 +204,6 @@ def _check_other_ie_lines(self): """ for record in self: for inscr_est_line in record.other_inscr_est_lines: - valid_ie = True state_code = inscr_est_line.state_id.code or '' uf = state_code.lower() valid_ie = fiscal.validate_ie(uf, inscr_est_line.inscr_est) @@ -279,6 +278,6 @@ class OtherInscricoesEstaduais(models.Model): _sql_constraints = [ ('other_inscricoes_estaduais_id_uniq', - 'unique (inscr_est, state_id)', - u'Inscrição Estadual já usada dentro do Estado!') + 'unique (state_id, partner_id)', + u'O Parceiro já possui uma Inscrição Estadual para esse Estado!') ] From 6d91ef7f919aab9f538702e015da57910fd7e778 Mon Sep 17 00:00:00 2001 From: Magno Date: Fri, 19 Jan 2018 11:40:37 -0200 Subject: [PATCH 10/34] Included tests for object other.inscricoes.estaduais . --- l10n_br_base/tests/__init__.py | 2 + l10n_br_base/tests/test_other_ie.py | 105 ++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 l10n_br_base/tests/test_other_ie.py diff --git a/l10n_br_base/tests/__init__.py b/l10n_br_base/tests/__init__.py index c53cb0919f3a..f7c08cf27090 100644 --- a/l10n_br_base/tests/__init__.py +++ b/l10n_br_base/tests/__init__.py @@ -7,3 +7,5 @@ from . import test_amount_to_text from . import test_tools_fiscal +from . import test_other_ie + diff --git a/l10n_br_base/tests/test_other_ie.py b/l10n_br_base/tests/test_other_ie.py new file mode 100644 index 000000000000..aa445a52536e --- /dev/null +++ b/l10n_br_base/tests/test_other_ie.py @@ -0,0 +1,105 @@ +# -*- coding: utf-8 -*- +# @ 2018 Akretion - www.akretion.com.br - +# Magno Costa +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + + +import openerp.tests.common as common +import logging + +_logger = logging.getLogger(__name__) + + +class OtherIETest(common.TransactionCase): + + def setUp(self): + super(OtherIETest, self).setUp() + self.company_model = self.env['res.company'] + self.company = self.company_model.create({ + 'name': 'Akretion Sao Paulo', + 'legal_name': 'Akretion Sao Paulo', + 'cnpj_cpf': '26.905.703/0001-52', + 'inscr_est': '932.446.119.086', + 'street': 'Rua Paulo Dias', + 'number': '586', + 'district': 'Alumínio', + 'state_id': self.ref('l10n_br_base.br_sp'), + 'l10n_br_city_id': self.ref('l10n_br_base.city_3501152'), + 'country_id': self.ref('base.br'), + 'city': 'Alumínio', + 'zip': '18125-000', + 'phone': '+55 (21) 3010 9965', + 'email': 'contact@companytest.com.br', + 'website': 'www.companytest.com.br' + }) + + def test_included_valid_ie_in_company(self): + result = self.company.write({ + 'other_inscr_est_lines': [(0, 0, { + 'state_id': self.ref('l10n_br_base.br_ba'), + 'inscr_est': 41902653, + })] + }) + self.assertTrue(result, "Error to included valid IE.") + for line in self.company.partner_id.other_inscr_est_lines: + result = False + if line.inscr_est == '41902653': + result = True + self.assertTrue( + result, "Error in method to update other IE(s) on partner.") + line_id = False + for line in self.company.partner_id.other_inscr_est_lines: + line_id = line.id + try: + result = self.company.write({ + 'other_inscr_est_lines': [(1, line_id, { + 'state_id': self.ref('l10n_br_base.br_ba'), + 'inscr_est': 67729139, + })] + }) + except: + result = False + self.assertFalse( + result, "Error to check included other" + " IE to State already informed.") + + def test_included_invalid_ie(self): + try: + result = self.company.write({ + 'other_inscr_est_lines': [(0, 0, { + 'state_id': self.ref('l10n_br_base.br_ba'), + 'inscr_est': 41902652, + })] + }) + except: + result = False + self.assertFalse(result, "Error to check included invalid IE.") + + def test_included_other_valid_ie_to_same_state_of_company(self): + try: + result = self.company.write({ + 'other_inscr_est_lines': [(0, 0, { + 'state_id': self.ref('l10n_br_base.br_sp'), + 'inscr_est': 692015742119, + })] + }) + except: + result = False + self.assertFalse( + result, "Error to check included other valid IE " + " in to same state of Company.") + + def test_included_valid_ie_on_partner(self): + result = self.company.partner_id.write({ + 'other_inscr_est_lines': [(0, 0, { + 'state_id': self.ref('l10n_br_base.br_ba'), + 'inscr_est': 41902653, + })] + }) + self.assertTrue(result, "Error to included valid IE.") + for line in self.company.other_inscr_est_lines: + result = False + if line.inscr_est == '41902653': + result = True + self.assertTrue( + result, "Error in method to update other IE(s) on Company.") From 34afa3863dc1bd0282264d90c801ab0aa4b7c2b0 Mon Sep 17 00:00:00 2001 From: Luis Felipe Mileo Date: Mon, 23 Jul 2018 15:02:42 -0300 Subject: [PATCH 11/34] [IMP] Melhorias na forma de pagamento p/ nf-e 4.0 Signed-off-by: Luis Felipe Mileo --- l10n_br_account_product/__openerp__.py | 2 + .../data/account_payment_term_data.xml | 28 +++ l10n_br_account_product/models/__init__.py | 1 + .../models/account_invoice_term.py | 167 ++++++++++++++++++ .../views/account_payment_term_view.xml | 50 ++++++ 5 files changed, 248 insertions(+) create mode 100644 l10n_br_account_product/data/account_payment_term_data.xml create mode 100644 l10n_br_account_product/models/account_invoice_term.py create mode 100644 l10n_br_account_product/views/account_payment_term_view.xml diff --git a/l10n_br_account_product/__openerp__.py b/l10n_br_account_product/__openerp__.py index 21c135035747..13a989a312ff 100644 --- a/l10n_br_account_product/__openerp__.py +++ b/l10n_br_account_product/__openerp__.py @@ -24,6 +24,7 @@ 'data/l10n_br_account_product_data.xml', 'data/l10n_br_tax.icms_partition.csv', 'data/ir_cron.xml', + 'data/account_payment_term_data.xml', 'views/l10n_br_account_product_view.xml', 'views/l10n_br_account_view.xml', 'views/l10n_br_account_product_view.xml', @@ -37,6 +38,7 @@ 'views/product_view.xml', 'views/res_country_view.xml', 'views/account_payment_view.xml', + 'views/account_payment_term_view.xml', 'wizard/l10n_br_account_nfe_export_invoice_view.xml', 'wizard/l10n_br_account_nfe_export_view.xml', 'wizard/l10n_br_account_document_status_sefaz_view.xml', diff --git a/l10n_br_account_product/data/account_payment_term_data.xml b/l10n_br_account_product/data/account_payment_term_data.xml new file mode 100644 index 000000000000..3ad680956fb5 --- /dev/null +++ b/l10n_br_account_product/data/account_payment_term_data.xml @@ -0,0 +1,28 @@ + + + + + + + + 0 + + + + 1 + + + + 1 + + + + Sem pagamento + Sem pagamento + 2 + 90 + + + + diff --git a/l10n_br_account_product/models/__init__.py b/l10n_br_account_product/models/__init__.py index c5b3284d5b99..b3a90f296043 100644 --- a/l10n_br_account_product/models/__init__.py +++ b/l10n_br_account_product/models/__init__.py @@ -12,3 +12,4 @@ from . import product from . import res_country from . import account_payment +from . import account_invoice_term diff --git a/l10n_br_account_product/models/account_invoice_term.py b/l10n_br_account_product/models/account_invoice_term.py new file mode 100644 index 000000000000..de2e9addc735 --- /dev/null +++ b/l10n_br_account_product/models/account_invoice_term.py @@ -0,0 +1,167 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 KMEE INFORMATICA LTDA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from __future__ import division, print_function, unicode_literals + +from openerp import api, fields, models, _ + +BANDEIRA_CARTAO = ( + ('01', 'Visa'), + ('02', 'Mastercard'), + ('03', 'American Express'), + ('04', 'Sorocred'), + ('05', 'Diners Club'), + ('06', 'Elo'), + ('07', 'Hipercard'), + ('08', 'Aura'), + ('09', 'Cabal'), + ('99', 'Outros'), +) +BANDEIRA_CARTAO_DICT = dict(BANDEIRA_CARTAO) + +BANDEIRA_CARTAO_VISA = '01' +BANDEIRA_CARTAO_MASTERCARD = '02' +BANDEIRA_CARTAO_AMERICAN_EXPRESS = '03' +BANDEIRA_CARTAO_SOROCRED = '04' +BANDEIRA_CARTAO_DINERS_CLUB = '05' +BANDEIRA_CARTAO_ELO = '06' +BANDEIRA_CARTAO_HIPERCARD = '07' +BANDEIRA_CARTAO_AURA = '08' +BANDEIRA_CARTAO_CABAL = '09' +BANDEIRA_CARTAO_OUTROS = '99' + +INTEGRACAO_CARTAO = ( + ('1', 'Integrado'), + ('2', 'Não integrado'), +) +INTEGRACAO_CARTAO_INTEGRADO = '1' +INTEGRACAO_CARTAO_NAO_INTEGRADO = '2' + +FORMA_PAGAMENTO = ( + ('01', 'Dinheiro'), + ('02', 'Cheque'), + ('03', 'Cartão de crédito'), + ('04', 'Cartão de débito'), + ('05', 'Crédito na loja'), + ('10', 'Vale alimentação'), + ('11', 'Vale refeição'), + ('12', 'Vale presente'), + ('13', 'Vale combustível'), + ('14', 'Duplicata mercantil'), + ('15', 'Boleto bancário'), + ('90', 'Sem pagamento'), + ('99', 'Outros'), +) + +FORMA_PAGAMENTO_DICT = dict(FORMA_PAGAMENTO) + +FORMA_PAGAMENTO_DINHEIRO = '01' +FORMA_PAGAMENTO_CHEQUE = '02' +FORMA_PAGAMENTO_CARTAO_CREDITO = '03' +FORMA_PAGAMENTO_CARTAO_DEBITO = '04' +FORMA_PAGAMENTO_CREDITO_LOJA = '05' +FORMA_PAGAMENTO_VALE_ALIMENTACAO = '10' +FORMA_PAGAMENTO_VALE_REFEICAO = '11' +FORMA_PAGAMENTO_VALE_PRESENTE = '12' +FORMA_PAGAMENTO_VALE_COMBUSTIVEL = '13' +FORMA_PAGAMENTO_DUPLICATA_MERCANTIL = '14' +FORMA_PAGAMENTO_BOLETO = '15' +FORMA_PAGAMENTO_SEM_PAGAMENTO = '90' +FORMA_PAGAMENTO_OUTROS = '99' + +FORMA_PAGAMENTO_CARTOES = ( + FORMA_PAGAMENTO_CARTAO_CREDITO, + FORMA_PAGAMENTO_CARTAO_DEBITO, +) + +IND_FORMA_PAGAMENTO = ( + ('0', 'À vista'), + ('1', 'A prazo'), + ('2', 'Outros/sem pagamento'), +) +IND_FORMA_PAGAMENTO_DICT = dict(IND_FORMA_PAGAMENTO) + + +class AccountPaymentTerm(models.Model): + + _inherit = b'account.payment.term' + _order = 'display_name' + + @api.depends('forma_pagamento', 'name') + def _compute_display_name(self): + return super(AccountPaymentTerm, self)._compute_display_name() + + display_name = fields.Char( + string='Condição da pagamento', + store=True, + compute='_compute_display_name', + ) + # + # Campos para NF-e e SPED + # + ind_forma_pagamento = fields.Selection( + selection=IND_FORMA_PAGAMENTO, + string='Indicador da Forma de Pagamento', + ) + forma_pagamento = fields.Selection( + selection=FORMA_PAGAMENTO, + string='Forma de pagamento', + default=FORMA_PAGAMENTO_OUTROS, + required=True, + ) + card_brand = fields.Selection( + selection=BANDEIRA_CARTAO, + string='Bandeira do cartão', + ) + card_integration = fields.Selection( + selection=INTEGRACAO_CARTAO, + string='Integração do cartão', + default=INTEGRACAO_CARTAO_NAO_INTEGRADO, + ) + partner_id = fields.Many2one( + comodel_name='res.partner', + string='Operadora do cartão', + ondelete='restrict', + ) + + @api.multi + def name_get(self): + res = [] + + for payment_term in self: + display_name = '' + if payment_term.forma_pagamento in FORMA_PAGAMENTO_CARTOES: + if payment_term.forma_pagamento == \ + FORMA_PAGAMENTO_CARTAO_CREDITO: + display_name += '[Crédito ' + elif payment_term.forma_pagamento == \ + FORMA_PAGAMENTO_CARTAO_DEBITO: + display_name += '[Débito ' + + display_name += \ + BANDEIRA_CARTAO_DICT[payment_term.card_brand] + display_name += '] ' + + elif payment_term.forma_pagamento: + display_name += '[' + display_name += \ + FORMA_PAGAMENTO_DICT[payment_term.forma_pagamento] + display_name += '] ' + + display_name += payment_term.name + res.append((payment_term.id, display_name)) + + return res + + @api.model + def name_search(self, name, args=None, operator='ilike', limit=100): + args = args or [] + recs = self.browse() + + if not recs: + recs = self.search( + [ + ('display_name', operator, name), + ] + args, limit=limit) + return recs.name_get() diff --git a/l10n_br_account_product/views/account_payment_term_view.xml b/l10n_br_account_product/views/account_payment_term_view.xml new file mode 100644 index 000000000000..72c5c87b43fb --- /dev/null +++ b/l10n_br_account_product/views/account_payment_term_view.xml @@ -0,0 +1,50 @@ + + + + + + + + account.payment.tree.form (in l10n_br_account_product) + account.payment.term + + + + + + + + + account.payment.term.search (in l10n_br_account_product) + account.payment.term + + + + + + + + + + account.payment.term.form (in l10n_br_account_product) + account.payment.term + + + + + + + + + + + + + + + + + + + From 46788ade05fc4a05b98ddab434070affb38671c9 Mon Sep 17 00:00:00 2001 From: Luis Felipe Mileo Date: Mon, 23 Jul 2018 15:14:04 -0300 Subject: [PATCH 12/34] [REM] type_nf_payment do account.invoice Signed-off-by: Luis Felipe Mileo --- .../models/account_invoice.py | 26 ------------------- .../views/nfe/account_invoice_nfe_view.xml | 1 - 2 files changed, 27 deletions(-) mode change 100755 => 100644 l10n_br_account_product/views/nfe/account_invoice_nfe_view.xml diff --git a/l10n_br_account_product/models/account_invoice.py b/l10n_br_account_product/models/account_invoice.py index c3ef7c531429..48d0d2d48877 100644 --- a/l10n_br_account_product/models/account_invoice.py +++ b/l10n_br_account_product/models/account_invoice.py @@ -392,25 +392,6 @@ def _compute_cfops(self): store=True, digits=dp.get_precision('Account'), compute='_compute_amount') - type_nf_payment = fields.Selection([ - ('01', u'01 - Dinheiro'), - ('02', u'02 - Cheque'), - ('03', u'03 - Cartão de Crédito'), - ('04', u'04 - Cartão de Débito'), - ('06', u'05 - Crédito Loja'), - ('10', u'10 - Vale Alimentação'), - ('11', u'11 - Vale Refeição'), - ('12', u'12 - Vale Presente'), - ('13', u'13 - Vale Combustível'), - ('14', u'14 - Duplicata Mercantil'), - ('15', u'15 - Boleto Bancário'), - ('90', u'90 - Sem pagamento'), - ('99', u'99 - Outros') - ], string='Tipo de Pagamento da NF', required=True, - help=u'Obrigatório o preenchimento do Grupo Informações de Pagamento' - u' para NF-e e NFC-e. Para as notas com finalidade de Ajuste' - u' ou Devolução o campo Forma de Pagamento deve ser preenchido' - u' com 90 - Sem Pagamento.' ) @api.one @@ -662,13 +643,6 @@ def open_fiscal_document(self): result['name'] = _('NF-e') return result - @api.onchange('payment_mode_id') - def onchange_payment_mode(self): - for record in self: - if record.payment_mode_id: - record.type_nf_payment = \ - record.payment_mode_id.type_nf_payment - class AccountInvoiceLine(models.Model): _inherit = 'account.invoice.line' diff --git a/l10n_br_account_product/views/nfe/account_invoice_nfe_view.xml b/l10n_br_account_product/views/nfe/account_invoice_nfe_view.xml old mode 100755 new mode 100644 index 3add7816812d..0e7e64669865 --- a/l10n_br_account_product/views/nfe/account_invoice_nfe_view.xml +++ b/l10n_br_account_product/views/nfe/account_invoice_nfe_view.xml @@ -173,7 +173,6 @@ - From 70be82a54c8ff912f4f7f8c749a2bacade014a12 Mon Sep 17 00:00:00 2001 From: Luis Felipe Mileo Date: Mon, 23 Jul 2018 15:15:17 -0300 Subject: [PATCH 13/34] =?UTF-8?q?[REF]=20Do=20campo=20indPag=20para=20form?= =?UTF-8?q?ata=C3=A7=C3=A3o=20snake=20case?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Luis Felipe Mileo --- l10n_br_account_product/models/account.py | 8 -------- l10n_br_account_product/views/account_view.xml | 11 ----------- 2 files changed, 19 deletions(-) diff --git a/l10n_br_account_product/models/account.py b/l10n_br_account_product/models/account.py index 527984360a26..d2743f8583ea 100644 --- a/l10n_br_account_product/models/account.py +++ b/l10n_br_account_product/models/account.py @@ -8,14 +8,6 @@ from openerp.tools import DEFAULT_SERVER_DATE_FORMAT -class AccountPaymentTerm(models.Model): - _inherit = 'account.payment.term' - - indPag = fields.Selection( - [('0', u'Pagamento à Vista'), ('1', u'Pagamento à Prazo'), - ('2', 'Outros')], 'Indicador de Pagamento', default='1') - - class AccountTaxTemplate(models.Model): """Implement computation method in taxes""" _inherit = 'account.tax.template' diff --git a/l10n_br_account_product/views/account_view.xml b/l10n_br_account_product/views/account_view.xml index 0e9f18e6773b..349fb9ad47ca 100644 --- a/l10n_br_account_product/views/account_view.xml +++ b/l10n_br_account_product/views/account_view.xml @@ -3,17 +3,6 @@ - - l10n_br_account_product.payment.term.form - account.payment.term - - - - - - - - l10n_br_account_product.tax.template.form account.tax.template From 136e3d45480f8f1f7e53e5007a0ca3d3cb5b89fb Mon Sep 17 00:00:00 2001 From: Luis Felipe Mileo Date: Mon, 23 Jul 2018 15:19:09 -0300 Subject: [PATCH 14/34] [NEW] Dados de pagamento e cobranca Signed-off-by: Luis Felipe Mileo --- l10n_br_account_product/__openerp__.py | 2 + l10n_br_account_product/models/__init__.py | 2 + .../models/account_invoice_payment.py | 115 ++++++++++++++++++ .../models/account_invoice_payment_line.py | 46 +++++++ .../views/account_invoice_payment.xml | 51 ++++++++ .../views/account_invoice_payment_line.xml | 22 ++++ 6 files changed, 238 insertions(+) create mode 100644 l10n_br_account_product/models/account_invoice_payment.py create mode 100644 l10n_br_account_product/models/account_invoice_payment_line.py create mode 100644 l10n_br_account_product/views/account_invoice_payment.xml create mode 100644 l10n_br_account_product/views/account_invoice_payment_line.xml diff --git a/l10n_br_account_product/__openerp__.py b/l10n_br_account_product/__openerp__.py index 13a989a312ff..f9ea7db9aac1 100644 --- a/l10n_br_account_product/__openerp__.py +++ b/l10n_br_account_product/__openerp__.py @@ -39,6 +39,8 @@ 'views/res_country_view.xml', 'views/account_payment_view.xml', 'views/account_payment_term_view.xml', + 'views/account_invoice_payment.xml', + 'views/account_invoice_payment_line.xml', 'wizard/l10n_br_account_nfe_export_invoice_view.xml', 'wizard/l10n_br_account_nfe_export_view.xml', 'wizard/l10n_br_account_document_status_sefaz_view.xml', diff --git a/l10n_br_account_product/models/__init__.py b/l10n_br_account_product/models/__init__.py index b3a90f296043..1efa8fc9948e 100644 --- a/l10n_br_account_product/models/__init__.py +++ b/l10n_br_account_product/models/__init__.py @@ -13,3 +13,5 @@ from . import res_country from . import account_payment from . import account_invoice_term +from . import account_invoice_payment +from . import account_invoice_payment_line diff --git a/l10n_br_account_product/models/account_invoice_payment.py b/l10n_br_account_product/models/account_invoice_payment.py new file mode 100644 index 000000000000..cae7da66c865 --- /dev/null +++ b/l10n_br_account_product/models/account_invoice_payment.py @@ -0,0 +1,115 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 KMEE INFORMATICA LTDA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from __future__ import division, print_function, unicode_literals + +from openerp import api, fields, models, _ + +from .account_invoice_term import ( + FORMA_PAGAMENTO, + BANDEIRA_CARTAO, + FORMA_PAGAMENTO_CARTOES, + IND_FORMA_PAGAMENTO, + INTEGRACAO_CARTAO, + INTEGRACAO_CARTAO_NAO_INTEGRADO, +) + + +class AccountInvoicePayment(models.Model): + _name = b'account.invoice.payment' + _description = 'Dados de pagamento' + _order = 'invoice_id, sequence, payment_term_id' + + sequence = fields.Integer( + default=10, + ) + payment_term_id = fields.Many2one( + comodel_name='account.payment.term', + string='Condição de pagamento', + ondelete='restrict', + domain=[('forma_pagamento', '!=', False)], + ) + currency_id = fields.Many2one( + comodel_name='res.currency', + string='Currency', + ) + amount = fields.Float( + string='Amount', + ) + autorizacao = fields.Char( + string='Autorização nº', + size=20, + ) + nsu = fields.Char( + string='NSU', + help='Numero sequencial unico', + ) + ind_forma_pagamento = fields.Selection( + related='payment_term_id.ind_forma_pagamento', + store=True, + ) + forma_pagamento = fields.Selection( + related='payment_term_id.forma_pagamento', + store=True, + ) + card_brand = fields.Selection( + related='payment_term_id.card_brand', + store=True, + ) + card_integration = fields.Selection( + related='payment_term_id.card_integration', + store=True, + ) + partner_id = fields.Many2one( + related='payment_term_id.partner_id', + store=True, + ondelete='restrict', + ) + cnpj_cpf = fields.Char( + string='CNPJ/CPF', + size=18, + related='partner_id.cnpj_cpf', + readonly=True, + ) + invoice_id = fields.Many2one( + comodel_name='account.invoice', + string='Invoice', + ondelete='set null', # Allow use the same model in sale and purchase + ) + item_ids = fields.One2many( + comodel_name='account.invoice.payment.line', + inverse_name='payment_id', + string='Duplicatas', + ) + + @api.onchange('payment_term_id', 'amount', 'item_ids') + def _onchange_payment_term_id(self): + + if not (self.payment_term_id and self.amount and + self.env.context.get('field_parent')): + return + + field_parent = self.env.context.get('field_parent') + field_parent_id = getattr(self, field_parent) + + if field_parent == 'invoice_id': + date = field_parent_id.date_invoice + self.invoice_id = field_parent_id + # TODO: Implementar para vendas e compras + + pterm_list = self.payment_term_id.compute(self.amount, date)[0] + + self.forma_pagameto = self.payment_term_id.forma_pagamento + + item_ids = [] + + for term in pterm_list: + item_ids.append( + (0, 0, { + 'payment_id': self.id, + 'date_due': term[0], + 'amount': term[1], + }) + ) + self.item_ids = item_ids diff --git a/l10n_br_account_product/models/account_invoice_payment_line.py b/l10n_br_account_product/models/account_invoice_payment_line.py new file mode 100644 index 000000000000..f82217db40e3 --- /dev/null +++ b/l10n_br_account_product/models/account_invoice_payment_line.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 KMEE INFORMATICA LTDA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from __future__ import division, print_function, unicode_literals + +from openerp import api, fields, models, _ + + +class AccountInvoicePaymentLine(models.Model): + + _name = b'account.invoice.payment.line' + _description = 'Dados de cobrança' + _order = 'invoice_id, date_due, payment_id' + _rec_name = 'number' + + payment_id = fields.Many2one( + comodel_name='account.invoice.payment', + string='Pagamento', + ondelete='cascade', + ) + invoice_id = fields.Many2one( + comodel_name='account.invoice', + related='payment_id.invoice_id', + store=True, + ) + number = fields.Char( + string='Número', + size=60, + readonly=True, + ) + date_due = fields.Date( + string='Data de vencimento', + required=True, + ) + currency_id = fields.Many2one( + comodel_name='res.currency', + string='Currency', + # related='payment_id.currency_id', + store=True, + ) + amount = fields.Float( + string='Valor', + digits=(18, 2), + required=True, + ) diff --git a/l10n_br_account_product/views/account_invoice_payment.xml b/l10n_br_account_product/views/account_invoice_payment.xml new file mode 100644 index 000000000000..06cb7da5cb00 --- /dev/null +++ b/l10n_br_account_product/views/account_invoice_payment.xml @@ -0,0 +1,51 @@ + + + + + + + + account.invoice.payment.tree (in l10n_br_account) + account.invoice.payment + + + + + + + + + + + + account.invoice.payment.form (in l10n_br_account) + account.invoice.payment + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ +
+
diff --git a/l10n_br_account_product/views/account_invoice_payment_line.xml b/l10n_br_account_product/views/account_invoice_payment_line.xml new file mode 100644 index 000000000000..cd74c10c63bd --- /dev/null +++ b/l10n_br_account_product/views/account_invoice_payment_line.xml @@ -0,0 +1,22 @@ + + + + + + + + account.invoice.payment.line.tree (in l10n_br_account) + account.invoice.payment.line + + + + + + + + + + + + From 4edb19da2b03fb66a0e98ea6a02a08bd63ef8c98 Mon Sep 17 00:00:00 2001 From: Luis Felipe Mileo Date: Mon, 23 Jul 2018 15:20:26 -0300 Subject: [PATCH 15/34] =?UTF-8?q?[NEW]=20Dados=20de=20pagamento=20e=20cobr?= =?UTF-8?q?an=C3=A7a=20na=20invoice?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Luis Felipe Mileo --- .../models/account_invoice.py | 18 ++++++++++++++++++ .../views/nfe/account_invoice_nfe_view.xml | 11 ++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/l10n_br_account_product/models/account_invoice.py b/l10n_br_account_product/models/account_invoice.py index 48d0d2d48877..c92de6bd7d34 100644 --- a/l10n_br_account_product/models/account_invoice.py +++ b/l10n_br_account_product/models/account_invoice.py @@ -392,6 +392,15 @@ def _compute_cfops(self): store=True, digits=dp.get_precision('Account'), compute='_compute_amount') + account_payment_ids = fields.One2many( + string='Dados de Pagamento', + comodel_name='account.invoice.payment', + inverse_name='invoice_id', + ) + account_payment_line_ids = fields.One2many( + string='Dados da cobrança', + comodel_name='account.invoice.payment.line', + inverse_name='invoice_id', ) @api.one @@ -519,6 +528,15 @@ def action_number(self): 'date_hour_invoice': date_time_invoice, 'date_in_out': date_in_out} ) + + if not invoice.account_payment_ids and invoice.nfe_version == '4.00': + raise UserError( + _(u'A nota fiscal deve conter dados de pagamento') + ) + + for item, payment in enumerate(invoice.account_payment_line_ids): + payment.number = str(item + 1).zfill(3) + return True @api.onchange('type') diff --git a/l10n_br_account_product/views/nfe/account_invoice_nfe_view.xml b/l10n_br_account_product/views/nfe/account_invoice_nfe_view.xml index 0e7e64669865..a6566a299db6 100644 --- a/l10n_br_account_product/views/nfe/account_invoice_nfe_view.xml +++ b/l10n_br_account_product/views/nfe/account_invoice_nfe_view.xml @@ -171,9 +171,8 @@ - - - + + @@ -181,6 +180,12 @@ + + + + + + From f17d57b9b3294ae57cf9c5b2e74c809fc0362339 Mon Sep 17 00:00:00 2001 From: Luis Felipe Mileo Date: Mon, 23 Jul 2018 16:00:00 -0300 Subject: [PATCH 16/34] [NEW] Troco dos pagamentos Signed-off-by: Luis Felipe Mileo --- .../models/account_invoice.py | 17 ++++++++++++++++- .../views/nfe/account_invoice_nfe_view.xml | 1 + 2 files changed, 17 insertions(+), 1 deletion(-) mode change 100644 => 100755 l10n_br_account_product/views/nfe/account_invoice_nfe_view.xml diff --git a/l10n_br_account_product/models/account_invoice.py b/l10n_br_account_product/models/account_invoice.py index c92de6bd7d34..d8972b4d6747 100644 --- a/l10n_br_account_product/models/account_invoice.py +++ b/l10n_br_account_product/models/account_invoice.py @@ -22,7 +22,7 @@ class AccountInvoice(models.Model): _order = 'date_hour_invoice DESC, internal_number DESC' @api.one - @api.depends('invoice_line', 'tax_line.amount') + @api.depends('invoice_line', 'tax_line.amount', 'account_payment_ids.amount') def _compute_amount(self): self.icms_base = 0.0 self.icms_base_other = 0.0 @@ -77,6 +77,11 @@ def _compute_amount(self): self.icms_st_base += line.icms_st_base self.icms_st_value += line.icms_st_value + # Calculando o troco + amount_payments = sum(p.amount for p in self.account_payment_ids) + if amount_payments: + self.amount_change = amount_payments - self.amount_total + @api.model @api.returns('l10n_br_account.fiscal_category') def _default_fiscal_category(self): @@ -392,6 +397,11 @@ def _compute_cfops(self): store=True, digits=dp.get_precision('Account'), compute='_compute_amount') + amount_change = fields.Float( + string='Troco', + store=True, + digits=dp.get_precision('Account'), + compute='_compute_amount') account_payment_ids = fields.One2many( string='Dados de Pagamento', comodel_name='account.invoice.payment', @@ -533,6 +543,11 @@ def action_number(self): raise UserError( _(u'A nota fiscal deve conter dados de pagamento') ) + elif invoice.amount_change < 0: + raise UserError( + _(u'O total de pagamentos deve ser maior ou igual ao total da nota.\n'), + _(u'Resta realizar o pagamento de %0.2f' % invoice.amount_change) + ) for item, payment in enumerate(invoice.account_payment_line_ids): payment.number = str(item + 1).zfill(3) diff --git a/l10n_br_account_product/views/nfe/account_invoice_nfe_view.xml b/l10n_br_account_product/views/nfe/account_invoice_nfe_view.xml old mode 100644 new mode 100755 index a6566a299db6..16a5e811b230 --- a/l10n_br_account_product/views/nfe/account_invoice_nfe_view.xml +++ b/l10n_br_account_product/views/nfe/account_invoice_nfe_view.xml @@ -166,6 +166,7 @@ + From 5f9f9387e3902c1f5102928637fa9716e313460f Mon Sep 17 00:00:00 2001 From: Luis Felipe Mileo Date: Mon, 23 Jul 2018 16:00:27 -0300 Subject: [PATCH 17/34] =?UTF-8?q?[NEW]=20Serializa=C3=A7=C3=A3o=20multiplo?= =?UTF-8?q?s=20pagamentos,=20cobran=C3=A7as=20e=20troco?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Luis Felipe Mileo --- l10n_br_account_product/sped/nfe/document.py | 85 +++++++++++++++----- 1 file changed, 63 insertions(+), 22 deletions(-) diff --git a/l10n_br_account_product/sped/nfe/document.py b/l10n_br_account_product/sped/nfe/document.py index 666bfe71b229..552d14088541 100644 --- a/l10n_br_account_product/sped/nfe/document.py +++ b/l10n_br_account_product/sped/nfe/document.py @@ -12,6 +12,10 @@ from openerp.addons.l10n_br_account.sped.document import FiscalDocument from openerp.addons.l10n_br_base.tools.misc import punctuation_rm +from ...models.account_invoice_term import ( + FORMA_PAGAMENTO_CARTOES, +) + class NFe200(FiscalDocument): def __init__(self): @@ -69,23 +73,14 @@ def _serializer(self, cr, uid, ids, nfe_environment, context=None): self.nfe.infNFe.det.append(self.det) - if invoice.journal_id.revenue_expense: - for move_line in invoice.move_line_receivable_id: - self.dup = self._get_Dup() - self._encashment_data(invoice, move_line) - self.nfe.infNFe.cobr.dup.append(self.dup) + self._encashment_data(invoice, self.nfe.infNFe.cobr) try: self._carrier_data(invoice) except AttributeError: pass - self.pag = self._get_Pag() - self._details_pag(invoice) - - self.detPag = self._get_DetPag() - self._details_pag_data(invoice) - self.nfe.infNFe.pag.detPag.append(self.detPag) + self._details_pag(invoice, self.nfe.infNFe.pag) self.vol = self._get_Vol() self._weight_data(invoice) @@ -359,7 +354,7 @@ def _details(self, invoice, invoice_line, index): if invoice_line.product_id: self.det.prod.cProd.valor = invoice_line.product_id.code or '' - self.det.prod.cEAN.valor = invoice_line.product_id.ean13 or '' + self.det.prod.cEAN.valor = invoice_line.product_id.ean13 or 'SEM GTIN' self.det.prod.cEANTrib.valor = invoice_line.product_id.ean13 or '' self.det.prod.xProd.valor = (normalize( 'NFKD', unicode( @@ -552,9 +547,26 @@ def _addition(self, invoice_line_di): self.di_line.vDescDI.valor = str( "%.2f" % invoice_line_di.amount_discount) - def _encashment_data(self, invoice, move_line): + def _encashment_data(self, invoice, cobr): """Dados de Cobrança""" + if invoice.journal_id.revenue_expense: + for move_line in invoice.move_line_receivable_id: + + if invoice.type in ('out_invoice', 'in_refund'): + value = move_line.debit + else: + value = move_line.credit + + dup = self._get_Dup() + + dup.nDup.valor = move_line.name + dup.dVenc.valor = (move_line.date_maturity or + invoice.date_due or + invoice.date_invoice) + dup.vDup.valor = str("%.2f" % value) + cobr.dup.append(dup) + if invoice.type in ('out_invoice', 'in_refund'): value = move_line.debit else: @@ -855,16 +867,45 @@ class NFe400(NFe310): def __init__(self): super(NFe400, self).__init__() - def _details_pag(self, invoice): - # TODO - implementar campo - self.pag.vTroco.valor = '' + def _details_pag(self, invoice, pag): + + for pagamento in invoice.account_payment_ids: + pag.detPag.append(self._payment_date(pagamento)) + + pag.vTroco.valor = invoice.amount_change + + def _payment_date(self, pagamento): + + pag = self._get_DetPag() + + # Somente no/ PL_009_V4_2016_002_v160b + # pag.indPag.valor = pagamento.payment_term_id.ind_forma_pagamento or '' + + pag.tPag.valor = pagamento.forma_pagamento + pag.vPag.valor = str(pagamento.amount) + + if pagamento.forma_pagamento in FORMA_PAGAMENTO_CARTOES: + pag.card.tpIntegra.valor = pagamento.card_integration + pag.card.CNPJ.valor = punctuation_rm(pagamento.cnpj_cpf or '') + pag.card.tBand.valor = pagamento.card_brand + pag.card.cAut.valor = pagamento.autorizacao + + return pag + + def _encashment_data(self, invoice, cobr): + """Dados de Cobrança""" - def _details_pag_data(self, invoice): - # TODO - existe a possibilidade de pagar uma parte - # em uma forma de pagto e outra parte em outra - # ex.: metade em dinheiro e metade boleto - self.detPag.tPag.valor = invoice.type_nf_payment - self.detPag.vPag.valor = invoice.amount_total + cobr.fat.nFat.valor = invoice.number + cobr.fat.vOrig.valor = str("%.2f" % invoice.amount_total) + cobr.fat.vDesc.valor = str("%.2f" % invoice.amount_discount) + cobr.fat.vLiq.valor = str("%.2f" % invoice.amount_total) + + for payment_line in invoice.account_payment_line_ids: + dup = self._get_Dup() + dup.nDup.valor = payment_line.number + dup.dVenc.valor = payment_line.date_due + dup.vDup.valor = str("%.2f" % payment_line.amount) + cobr.dup.append(dup) def get_NFe(self): try: From 1506cebdea24370665b4ee2ac0d6998dfd9312ac Mon Sep 17 00:00:00 2001 From: Luis Felipe Mileo Date: Wed, 1 Aug 2018 21:59:58 -0300 Subject: [PATCH 18/34] [REF] Melhorias nos campos do vOrig vDesc vLiq Signed-off-by: Luis Felipe Mileo --- .../models/account_invoice.py | 30 +++++++++++++++++-- .../models/account_invoice_payment.py | 4 ++- .../models/account_invoice_payment_line.py | 14 +++++++-- l10n_br_account_product/sped/nfe/document.py | 14 +++++---- .../views/account_invoice_payment_line.xml | 4 ++- .../views/nfe/account_invoice_nfe_view.xml | 13 ++++++-- 6 files changed, 64 insertions(+), 15 deletions(-) diff --git a/l10n_br_account_product/models/account_invoice.py b/l10n_br_account_product/models/account_invoice.py index d8972b4d6747..ce749e42b358 100644 --- a/l10n_br_account_product/models/account_invoice.py +++ b/l10n_br_account_product/models/account_invoice.py @@ -77,10 +77,13 @@ def _compute_amount(self): self.icms_st_base += line.icms_st_base self.icms_st_value += line.icms_st_value + # Calculando o grupo fatura + self.amount_payment_original = sum(p.amount_original for p in self.account_payment_line_ids) + self.amount_payment_discount = sum(p.amount_discount for p in self.account_payment_line_ids) + self.amount_payment_net = sum(p.amount_net for p in self.account_payment_line_ids) # Calculando o troco - amount_payments = sum(p.amount for p in self.account_payment_ids) - if amount_payments: - self.amount_change = amount_payments - self.amount_total + if self.amount_payment_net: + self.amount_change = self.amount_payment_net - self.amount_total @api.model @api.returns('l10n_br_account.fiscal_category') @@ -412,6 +415,27 @@ def _compute_cfops(self): comodel_name='account.invoice.payment.line', inverse_name='invoice_id', ) + amount_payment_original = fields.Float( + string='Vr Original', + store=True, + digits=dp.get_precision('Account'), + compute='_compute_amount', + help='vOrig' + ) + amount_payment_discount = fields.Float( + string='Vr Desconto', + store=True, + digits=dp.get_precision('Account'), + compute='_compute_amount', + help='vDesc', + ) + amount_payment_net = fields.Float( + string='Vr Liquido', + store=True, + digits=dp.get_precision('Account'), + compute='_compute_amount', + help='vLiq', + ) @api.one @api.constrains('number') diff --git a/l10n_br_account_product/models/account_invoice_payment.py b/l10n_br_account_product/models/account_invoice_payment.py index cae7da66c865..874f3c3c2690 100644 --- a/l10n_br_account_product/models/account_invoice_payment.py +++ b/l10n_br_account_product/models/account_invoice_payment.py @@ -109,7 +109,9 @@ def _onchange_payment_term_id(self): (0, 0, { 'payment_id': self.id, 'date_due': term[0], - 'amount': term[1], + 'amount_original': term[1], + 'amount_discount': 0.00, + 'amount_net': term[1], }) ) self.item_ids = item_ids diff --git a/l10n_br_account_product/models/account_invoice_payment_line.py b/l10n_br_account_product/models/account_invoice_payment_line.py index f82217db40e3..403b47815fc4 100644 --- a/l10n_br_account_product/models/account_invoice_payment_line.py +++ b/l10n_br_account_product/models/account_invoice_payment_line.py @@ -39,8 +39,18 @@ class AccountInvoicePaymentLine(models.Model): # related='payment_id.currency_id', store=True, ) - amount = fields.Float( - string='Valor', + amount_original = fields.Float( + string='Vr Original', + digits=(18, 2), + required=True, + ) + amount_discount = fields.Float( + string='Vr desconto', + digits=(18, 2), + required=True, + ) + amount_net = fields.Float( + string='Vr Liquido', digits=(18, 2), required=True, ) diff --git a/l10n_br_account_product/sped/nfe/document.py b/l10n_br_account_product/sped/nfe/document.py index 552d14088541..30780b57a482 100644 --- a/l10n_br_account_product/sped/nfe/document.py +++ b/l10n_br_account_product/sped/nfe/document.py @@ -14,6 +14,7 @@ from ...models.account_invoice_term import ( FORMA_PAGAMENTO_CARTOES, + FORMA_PAGAMENTO_SEM_PAGAMENTO, ) @@ -872,7 +873,7 @@ def _details_pag(self, invoice, pag): for pagamento in invoice.account_payment_ids: pag.detPag.append(self._payment_date(pagamento)) - pag.vTroco.valor = invoice.amount_change + pag.vTroco.valor = str("%.2f" % invoice.amount_change) def _payment_date(self, pagamento): @@ -895,16 +896,19 @@ def _payment_date(self, pagamento): def _encashment_data(self, invoice, cobr): """Dados de Cobrança""" + if FORMA_PAGAMENTO_SEM_PAGAMENTO in invoice.account_payment_ids.mapped('forma_pagamento'): + return + cobr.fat.nFat.valor = invoice.number - cobr.fat.vOrig.valor = str("%.2f" % invoice.amount_total) - cobr.fat.vDesc.valor = str("%.2f" % invoice.amount_discount) - cobr.fat.vLiq.valor = str("%.2f" % invoice.amount_total) + cobr.fat.vOrig.valor = str("%.2f" % invoice.amount_payment_original) + cobr.fat.vDesc.valor = str("%.2f" % invoice.amount_payment_discount) + cobr.fat.vLiq.valor = str("%.2f" % invoice.amount_payment_net) for payment_line in invoice.account_payment_line_ids: dup = self._get_Dup() dup.nDup.valor = payment_line.number dup.dVenc.valor = payment_line.date_due - dup.vDup.valor = str("%.2f" % payment_line.amount) + dup.vDup.valor = str("%.2f" % payment_line.amount_net) cobr.dup.append(dup) def get_NFe(self): diff --git a/l10n_br_account_product/views/account_invoice_payment_line.xml b/l10n_br_account_product/views/account_invoice_payment_line.xml index cd74c10c63bd..f9d6b85c287f 100644 --- a/l10n_br_account_product/views/account_invoice_payment_line.xml +++ b/l10n_br_account_product/views/account_invoice_payment_line.xml @@ -13,7 +13,9 @@ - + + +
diff --git a/l10n_br_account_product/views/nfe/account_invoice_nfe_view.xml b/l10n_br_account_product/views/nfe/account_invoice_nfe_view.xml index 16a5e811b230..878db8ecd323 100755 --- a/l10n_br_account_product/views/nfe/account_invoice_nfe_view.xml +++ b/l10n_br_account_product/views/nfe/account_invoice_nfe_view.xml @@ -166,23 +166,30 @@ -
+ - - + + + + + + + + + From 24533aea9b422b56614f4b7711d402bd70376c96 Mon Sep 17 00:00:00 2001 From: Luis Felipe Mileo Date: Thu, 2 Aug 2018 01:36:13 -0300 Subject: [PATCH 19/34] =?UTF-8?q?[NEW]=20Motor=20de=20lan=C3=A7amento=20co?= =?UTF-8?q?nt=C3=A1bil=20baseado=20nos=20pagamentos=20da=20nf-e=204.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../models/account_invoice.py | 173 ++++++++++++++++++ 1 file changed, 173 insertions(+) diff --git a/l10n_br_account_product/models/account_invoice.py b/l10n_br_account_product/models/account_invoice.py index ce749e42b358..396327b65eed 100644 --- a/l10n_br_account_product/models/account_invoice.py +++ b/l10n_br_account_product/models/account_invoice.py @@ -700,6 +700,179 @@ def open_fiscal_document(self): result['name'] = _('NF-e') return result + @api.multi + def action_move_create(self): + """ Creates invoice related analytics and financial move lines """ + account_invoice_tax = self.env['account.invoice.tax'] + account_move = self.env['account.move'] + + for inv in self: + if not inv.journal_id.sequence_id: + raise UserError(_('Error!'), _('Please define sequence on the journal related to this invoice.')) + if not inv.invoice_line: + raise UserError(_('No Invoice Lines!'), _('Please create some invoice lines.')) + if inv.move_id: + continue + + ctx = dict(self._context, lang=inv.partner_id.lang) + + if not inv.date_invoice: + inv.with_context(ctx).write({'date_invoice': fields.Date.context_today(self)}) + date_invoice = inv.date_invoice + + company_currency = inv.company_id.currency_id + # create the analytical lines, one move line per invoice line + iml = inv._get_analytic_lines() + # check if taxes are all computed + compute_taxes = account_invoice_tax.compute(inv.with_context(lang=inv.partner_id.lang)) + inv.check_tax_lines(compute_taxes) + + # I disabled the check_total feature + if self.env.user.has_group('account.group_supplier_inv_check_total'): + if inv.type in ('in_invoice', 'in_refund') and abs(inv.check_total - inv.amount_total) >= (inv.currency_id.rounding / 2.0): + raise UserError(_('Bad Total!'), _('Please verify the price of the invoice!\nThe encoded total does not match the computed total.')) + + # if inv.payment_term: + # total_fixed = total_percent = 0 + # for line in inv.payment_term.line_ids: + # if line.value == 'fixed': + # total_fixed += line.value_amount + # if line.value == 'procent': + # total_percent += line.value_amount + # total_fixed = (total_fixed * 100) / (inv.amount_total or 1.0) + # if (total_fixed + total_percent) > 100: + # raise except_orm(_('Error!'), _("Cannot create the invoice.\nThe related payment term is probably misconfigured as it gives a computed amount greater than the total invoiced amount. In order to avoid rounding issues, the latest line of your payment term must be of type 'balance'.")) + + # one move line per tax line + iml += account_invoice_tax.move_line_get(inv.id) + + if inv.type in ('in_invoice', 'in_refund'): + ref = inv.reference + else: + ref = inv.number + + diff_currency = inv.currency_id != company_currency + # create one move line for the total and possibly adjust the other lines amount + total, total_currency, iml = inv.with_context(ctx).compute_invoice_totals(company_currency, ref, iml) + + name = inv.supplier_invoice_number or inv.name or '/' + totlines = [] + + res_amount_currency = total_currency + ctx['date'] = date_invoice + + for i, t in enumerate(inv.account_payment_line_ids): + + if inv.currency_id != company_currency: + amount_currency = company_currency.with_context(ctx).compute(t.amount_net, inv.currency_id) + else: + amount_currency = False + + # last line: add the diff + res_amount_currency -= amount_currency or 0 + if i + 1 == len(totlines): + amount_currency += res_amount_currency + + iml.append({ + 'type': 'dest', + 'name': name, + 'price': t.amount_net, + 'account_id': inv.account_id.id, + 'date_maturity': t.date_due, + 'amount_currency': diff_currency and amount_currency, + 'currency_id': diff_currency and inv.currency_id.id, + 'ref': ref + '/' + t.number, + }) + + if not inv.account_payment_line_ids: + iml.append({ + 'type': 'dest', + 'name': name, + 'price': total, + 'account_id': inv.account_id.id, + 'date_maturity': inv.date_due, + 'amount_currency': diff_currency and total_currency, + 'currency_id': diff_currency and inv.currency_id.id, + 'ref': ref + }) + + + # if inv.payment_term: + # totlines = inv.with_context(ctx).payment_term.compute(total, date_invoice)[0] + # if totlines: + # res_amount_currency = total_currency + # ctx['date'] = date_invoice + # for i, t in enumerate(totlines): + # if inv.currency_id != company_currency: + # amount_currency = company_currency.with_context(ctx).compute(t[1], inv.currency_id) + # else: + # amount_currency = False + # + # # last line: add the diff + # res_amount_currency -= amount_currency or 0 + # if i + 1 == len(totlines): + # amount_currency += res_amount_currency + # + # iml.append({ + # 'type': 'dest', + # 'name': name, + # 'price': t[1], + # 'account_id': inv.account_id.id, + # 'date_maturity': t[0], + # 'amount_currency': diff_currency and amount_currency, + # 'currency_id': diff_currency and inv.currency_id.id, + # 'ref': ref, + # }) + + date = date_invoice + + part = self.env['res.partner']._find_accounting_partner(inv.partner_id) + + line = [(0, 0, self.line_get_convert(l, part.id, date)) for l in iml] + line = inv.group_lines(iml, line) + + journal = inv.journal_id.with_context(ctx) + if journal.centralisation: + raise UserError(_('User Error!'), + _('You cannot create an invoice on a centralized journal. Uncheck the centralized counterpart box in the related journal from the configuration menu.')) + + line = inv.finalize_invoice_move_lines(line) + + move_vals = { + 'ref': inv.reference or inv.supplier_invoice_number or inv.name, + 'line_id': line, + 'journal_id': journal.id, + 'date': inv.date_invoice, + 'narration': inv.comment, + 'company_id': inv.company_id.id, + } + ctx['company_id'] = inv.company_id.id + period = inv.period_id + if not period: + period = period.with_context(ctx).find(date_invoice)[:1] + if period: + move_vals['period_id'] = period.id + for i in line: + i[2]['period_id'] = period.id + + ctx['invoice'] = inv + ctx_nolang = ctx.copy() + ctx_nolang.pop('lang', None) + move = account_move.with_context(ctx_nolang).create(move_vals) + + # make the invoice point to that move + vals = { + 'move_id': move.id, + 'period_id': period.id, + 'move_name': move.name, + } + inv.with_context(ctx).write(vals) + # Pass invoice in context in method post: used if you want to get the same + # account move reference when creating the same invoice after a cancelled one: + move.post() + self._log_event() + return True + class AccountInvoiceLine(models.Model): _inherit = 'account.invoice.line' From 1dd6c5d79f6791c2058af13c830aacd921c4819c Mon Sep 17 00:00:00 2001 From: Daniel Sadamo Hirayama Date: Thu, 2 Aug 2018 03:06:20 -0300 Subject: [PATCH 20/34] =?UTF-8?q?[NEW]Adicao=20de=20condi=C3=A7=C3=A3o=20d?= =?UTF-8?q?e=20pagamento=20na=20categoria=20fiscal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- l10n_br_account_product/models/l10n_br_account.py | 4 ++++ l10n_br_account_product/views/l10n_br_account_view.xml | 1 + 2 files changed, 5 insertions(+) diff --git a/l10n_br_account_product/models/l10n_br_account.py b/l10n_br_account_product/models/l10n_br_account.py index 9ecad816d912..44795eaabfcb 100644 --- a/l10n_br_account_product/models/l10n_br_account.py +++ b/l10n_br_account_product/models/l10n_br_account.py @@ -19,6 +19,10 @@ class L10nBrAccountFiscalCategory(models.Model): PRODUCT_FISCAL_TYPE, 'Tipo Fiscal', required=True, default=PRODUCT_FISCAL_TYPE_DEFAULT) + account_payment_term_id = fields.Many2one( + comodel_name='account.payment.term', + string=u'Condição de pagamento' + ) class L10nBrAccountDocumentSerie(models.Model): _inherit = 'l10n_br_account.document.serie' diff --git a/l10n_br_account_product/views/l10n_br_account_view.xml b/l10n_br_account_product/views/l10n_br_account_view.xml index 07295578f8a8..39f30b1de12a 100644 --- a/l10n_br_account_product/views/l10n_br_account_view.xml +++ b/l10n_br_account_product/views/l10n_br_account_view.xml @@ -10,6 +10,7 @@ 0 + From 19a3ede75d895d9f859fb695efca02bc2fb0ad11 Mon Sep 17 00:00:00 2001 From: Daniel Sadamo Hirayama Date: Thu, 2 Aug 2018 03:11:33 -0300 Subject: [PATCH 21/34] [NEW]Permissions for account.invoice.payment model --- l10n_br_account_product/security/ir.model.access.csv | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/l10n_br_account_product/security/ir.model.access.csv b/l10n_br_account_product/security/ir.model.access.csv index 87528af2a0db..fbe13b07259c 100644 --- a/l10n_br_account_product/security/ir.model.access.csv +++ b/l10n_br_account_product/security/ir.model.access.csv @@ -38,3 +38,7 @@ "l10n_br_tax_icms_partition_user","l10n_br_tax.icms_partition","model_l10n_br_tax_icms_partition","account.group_account_invoice",1,0,0,0 "l10n_br_account_product_cest_user","l10n_br_account_product.cest","model_l10n_br_account_product_cest","base.group_user",1,0,0,0 "l10n_br_account_product_cest_manager","l10n_br_account_product.cest","model_l10n_br_account_product_cest","account.group_account_manager",1,1,1,1 +"access_account_invoice_payments_base_user","account.invoice.payment.base.user","model_account_invoice_payment","base.group_user",1,0,0,0 +"access_account_invoice_payments_user","account.invoice.payment.user","model_account_invoice_payment","account.group_account_user",1,1,1,1 +"access_account_invoice_payments_invoice","account.invoice.payment.invoice","model_account_invoice_payment","account.group_account_invoice",1,1,1,1 +"access_account_invoice_payments_manager","account.invoice.payment.manager","model_account_invoice_payment","account.group_account_manager",1,1,1,1 \ No newline at end of file From 597417cbb7aa609ed227720a4aa4a28f2f388814 Mon Sep 17 00:00:00 2001 From: Daniel Sadamo Hirayama Date: Thu, 2 Aug 2018 03:12:26 -0300 Subject: [PATCH 22/34] =?UTF-8?q?[WIP]Cria=C3=A7=C3=A3o=20automatica=20de?= =?UTF-8?q?=20dados=20do=20pagamento?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../models/account_invoice.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/l10n_br_account_product/models/account_invoice.py b/l10n_br_account_product/models/account_invoice.py index 396327b65eed..5f8144743c84 100644 --- a/l10n_br_account_product/models/account_invoice.py +++ b/l10n_br_account_product/models/account_invoice.py @@ -616,6 +616,25 @@ def onchange_fiscal(self): 'context': self.env.context } result = self._fiscal_position_map(result, **kwargs) + if (self.fiscal_category_id and + self.fiscal_category_id.account_payment_term_id) and \ + not self.account_payment_ids: + account_payments = self.env['account.invoice.payment'] + values = { + 'payment_term_id': + self.fiscal_category_id.account_payment_term_id, + 'amount': self.amount_total, + } + specs = account_payments._onchange_spec() + updates = account_payments.onchange(values, [], specs) + value = updates.get('value', {}) + for name, val in value.iteritems(): + if isinstance(val, tuple): + value[name] = val[0] + values.update(value) + + kwargs.update( + {'account_payment_ids':[0,0, values]}) self.update(result['value']) @api.multi From 3be0ff6411271c3c331b233210d3914b6b8a3a00 Mon Sep 17 00:00:00 2001 From: Luis Felipe Mileo Date: Thu, 2 Aug 2018 04:25:22 -0300 Subject: [PATCH 23/34] =?UTF-8?q?[NEW]=20Permiss=C3=B5es=20de=20acesso=20d?= =?UTF-8?q?o=20acccount.invoice.payment.line?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Luis Felipe Mileo --- l10n_br_account_product/security/ir.model.access.csv | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/l10n_br_account_product/security/ir.model.access.csv b/l10n_br_account_product/security/ir.model.access.csv index fbe13b07259c..3d0d514e10cd 100644 --- a/l10n_br_account_product/security/ir.model.access.csv +++ b/l10n_br_account_product/security/ir.model.access.csv @@ -41,4 +41,8 @@ "access_account_invoice_payments_base_user","account.invoice.payment.base.user","model_account_invoice_payment","base.group_user",1,0,0,0 "access_account_invoice_payments_user","account.invoice.payment.user","model_account_invoice_payment","account.group_account_user",1,1,1,1 "access_account_invoice_payments_invoice","account.invoice.payment.invoice","model_account_invoice_payment","account.group_account_invoice",1,1,1,1 -"access_account_invoice_payments_manager","account.invoice.payment.manager","model_account_invoice_payment","account.group_account_manager",1,1,1,1 \ No newline at end of file +"access_account_invoice_payments_manager","account.invoice.payment.manager","model_account_invoice_payment","account.group_account_manager",1,1,1,1 +"access_account_invoice_payment_line_base_user","account.invoice.payment.line.base.user","model_account_invoice_payment_line","base.group_user",1,0,0,0 +"access_account_invoice_payment_line_user","account.invoice.payment.line.user","model_account_invoice_payment_line","account.group_account_user",1,1,1,1 +"access_account_invoice_payment_line_invoice","account.invoice.payment.line.invoice","model_account_invoice_payment_line","account.group_account_invoice",1,1,1,1 +"access_account_invoice_payment_line_manager","account.invoice.payment.line.manager","model_account_invoice_payment_line","account.group_account_manager",1,1,1,1 From 1aa6225e7b858e57783c98d4a67d29882d365d36 Mon Sep 17 00:00:00 2001 From: Luis Felipe Mileo Date: Thu, 2 Aug 2018 04:26:09 -0300 Subject: [PATCH 24/34] [FIX] Onchange fiscal ref a pagamento Signed-off-by: Luis Felipe Mileo --- .../models/account_invoice.py | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/l10n_br_account_product/models/account_invoice.py b/l10n_br_account_product/models/account_invoice.py index 5f8144743c84..ebfdf0c5640e 100644 --- a/l10n_br_account_product/models/account_invoice.py +++ b/l10n_br_account_product/models/account_invoice.py @@ -606,8 +606,9 @@ def onchange_fiscal_document_id(self): @api.onchange('fiscal_category_id', 'fiscal_position') def onchange_fiscal(self): + result = {'value': {}} if self.company_id and self.partner_id and self.fiscal_category_id: - result = {'value': {}} + kwargs = { 'company_id': self.company_id.id, 'partner_id': self.partner_id.id, @@ -616,26 +617,25 @@ def onchange_fiscal(self): 'context': self.env.context } result = self._fiscal_position_map(result, **kwargs) - if (self.fiscal_category_id and - self.fiscal_category_id.account_payment_term_id) and \ - not self.account_payment_ids: - account_payments = self.env['account.invoice.payment'] - values = { - 'payment_term_id': - self.fiscal_category_id.account_payment_term_id, - 'amount': self.amount_total, - } - specs = account_payments._onchange_spec() - updates = account_payments.onchange(values, [], specs) - value = updates.get('value', {}) - for name, val in value.iteritems(): - if isinstance(val, tuple): - value[name] = val[0] - values.update(value) - - kwargs.update( - {'account_payment_ids':[0,0, values]}) - self.update(result['value']) + + if (self.fiscal_category_id and + self.fiscal_category_id.account_payment_term_id) and \ + not self.account_payment_ids: + account_payments = self.env['account.invoice.payment'] + values = { + 'payment_term_id': + self.fiscal_category_id.account_payment_term_id.id, + 'amount': self.amount_total, + } + specs = account_payments._onchange_spec() + updates = account_payments.onchange(values, [], specs) + value = updates.get('value', {}) + for name, val in value.iteritems(): + if isinstance(val, tuple): + value[name] = val[0] + values.update(value) + result['value']['account_payment_ids'] = [(0, 0, values)] + self.update(result['value']) @api.multi def action_date_assign(self): From 47f25c5714c4bc890e385c41c82696fb7b58d25c Mon Sep 17 00:00:00 2001 From: Luis Felipe Mileo Date: Thu, 2 Aug 2018 04:26:38 -0300 Subject: [PATCH 25/34] =?UTF-8?q?[NEW]=20Cria=C3=A7=C3=A3o=20de=20pagament?= =?UTF-8?q?os=20ao=20confirmar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Luis Felipe Mileo --- .../models/account_invoice.py | 48 +++++++++++++++---- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/l10n_br_account_product/models/account_invoice.py b/l10n_br_account_product/models/account_invoice.py index ebfdf0c5640e..556937bbc4e8 100644 --- a/l10n_br_account_product/models/account_invoice.py +++ b/l10n_br_account_product/models/account_invoice.py @@ -15,6 +15,7 @@ PRODUCT_FISCAL_TYPE_DEFAULT) from .product import PRODUCT_ORIGIN from openerp.addons.l10n_br_account_product.sped.nfe.validator import txt +from .account_invoice_term import FORMA_PAGAMENTO_SEM_PAGAMENTO class AccountInvoice(models.Model): @@ -564,17 +565,44 @@ def action_number(self): ) if not invoice.account_payment_ids and invoice.nfe_version == '4.00': - raise UserError( - _(u'A nota fiscal deve conter dados de pagamento') - ) - elif invoice.amount_change < 0: - raise UserError( - _(u'O total de pagamentos deve ser maior ou igual ao total da nota.\n'), - _(u'Resta realizar o pagamento de %0.2f' % invoice.amount_change) - ) - for item, payment in enumerate(invoice.account_payment_line_ids): - payment.number = str(item + 1).zfill(3) + if (invoice.fiscal_category_id and + invoice.fiscal_category_id.account_payment_term_id): + + account_payments = self.env['account.invoice.payment'] + + amount = 0.00 + if not (invoice.fiscal_category_id.account_payment_term_id.forma_pagamento == + FORMA_PAGAMENTO_SEM_PAGAMENTO): + amount = invoice.amount_total + + values = { + 'payment_term_id': + invoice.fiscal_category_id.account_payment_term_id.id, + 'amount': amount, + } + specs = account_payments._onchange_spec() + updates = account_payments.onchange(values, [], specs) + value = updates.get('value', {}) + for name, val in value.iteritems(): + if isinstance(val, tuple): + value[name] = val[0] + values.update(value) + + invoice.account_payment_ids = [(0, 0, values)] + + if not invoice.account_payment_ids: + raise UserError( + _(u'A nota fiscal deve conter dados de pagamento') + ) + elif invoice.amount_change < 0: + raise UserError( + _(u'O total de pagamentos deve ser maior ou igual ao total da nota.\n'), + _(u'Resta realizar o pagamento de %0.2f' % invoice.amount_change) + ) + + for item, payment in enumerate(invoice.account_payment_line_ids): + payment.number = str(item + 1).zfill(3) return True From e4dc62448eb67ad640b73a95f8b326eb629bdaf4 Mon Sep 17 00:00:00 2001 From: Atilla Silva Date: Tue, 7 Aug 2018 10:41:37 -0300 Subject: [PATCH 26/34] [FIX] correcao account_product --- .../models/account_invoice.py | 76 +++++++++---------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/l10n_br_account_product/models/account_invoice.py b/l10n_br_account_product/models/account_invoice.py index 556937bbc4e8..555c2a831360 100644 --- a/l10n_br_account_product/models/account_invoice.py +++ b/l10n_br_account_product/models/account_invoice.py @@ -564,45 +564,45 @@ def action_number(self): 'date_in_out': date_in_out} ) - if not invoice.account_payment_ids and invoice.nfe_version == '4.00': - - if (invoice.fiscal_category_id and - invoice.fiscal_category_id.account_payment_term_id): - - account_payments = self.env['account.invoice.payment'] - - amount = 0.00 - if not (invoice.fiscal_category_id.account_payment_term_id.forma_pagamento == - FORMA_PAGAMENTO_SEM_PAGAMENTO): - amount = invoice.amount_total - - values = { - 'payment_term_id': - invoice.fiscal_category_id.account_payment_term_id.id, - 'amount': amount, - } - specs = account_payments._onchange_spec() - updates = account_payments.onchange(values, [], specs) - value = updates.get('value', {}) - for name, val in value.iteritems(): - if isinstance(val, tuple): - value[name] = val[0] - values.update(value) - - invoice.account_payment_ids = [(0, 0, values)] - + if invoice.nfe_version == '4.00': if not invoice.account_payment_ids: - raise UserError( - _(u'A nota fiscal deve conter dados de pagamento') - ) - elif invoice.amount_change < 0: - raise UserError( - _(u'O total de pagamentos deve ser maior ou igual ao total da nota.\n'), - _(u'Resta realizar o pagamento de %0.2f' % invoice.amount_change) - ) - - for item, payment in enumerate(invoice.account_payment_line_ids): - payment.number = str(item + 1).zfill(3) + if (invoice.fiscal_category_id and + invoice.fiscal_category_id.account_payment_term_id): + + account_payments = self.env['account.invoice.payment'] + + amount = 0.00 + if not (invoice.fiscal_category_id.account_payment_term_id.forma_pagamento == + FORMA_PAGAMENTO_SEM_PAGAMENTO): + amount = invoice.amount_total + + values = { + 'payment_term_id': + invoice.fiscal_category_id.account_payment_term_id.id, + 'amount': amount, + } + specs = account_payments._onchange_spec() + updates = account_payments.onchange(values, [], specs) + value = updates.get('value', {}) + for name, val in value.iteritems(): + if isinstance(val, tuple): + value[name] = val[0] + values.update(value) + + invoice.account_payment_ids = [(0, 0, values)] + + if not invoice.account_payment_ids: + raise UserError( + _(u'A nota fiscal deve conter dados de pagamento') + ) + elif invoice.amount_change < 0: + raise UserError( + _(u'O total de pagamentos deve ser maior ou igual ao total da nota.\n'), + _(u'Resta realizar o pagamento de %0.2f' % invoice.amount_change) + ) + else: + for item, payment in enumerate(invoice.account_payment_line_ids): + payment.number = str(item + 1).zfill(3) return True From 24b5c071f8e0c1bd1a46d85dcbf665a9ce4bd5af Mon Sep 17 00:00:00 2001 From: Luis Felipe Mileo Date: Wed, 8 Aug 2018 20:31:36 -0300 Subject: [PATCH 27/34] [FIX] view account_payment_term_id Signed-off-by: Luis Felipe Mileo --- l10n_br_account_product/views/l10n_br_account_view.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/l10n_br_account_product/views/l10n_br_account_view.xml b/l10n_br_account_product/views/l10n_br_account_view.xml index 39f30b1de12a..07e523c3bda0 100644 --- a/l10n_br_account_product/views/l10n_br_account_view.xml +++ b/l10n_br_account_product/views/l10n_br_account_view.xml @@ -10,7 +10,10 @@ 0 + + + From b8d8c05559665c33788c18667d27aac2022c5e58 Mon Sep 17 00:00:00 2001 From: Luis Felipe Mileo Date: Wed, 8 Aug 2018 20:33:23 -0300 Subject: [PATCH 28/34] [REM] Modelagem obsoleta Signed-off-by: Luis Felipe Mileo --- l10n_br_account_product/__openerp__.py | 1 - l10n_br_account_product/models/__init__.py | 1 - .../models/account_payment.py | 31 ------------------- .../views/account_payment_view.xml | 17 ---------- 4 files changed, 50 deletions(-) delete mode 100644 l10n_br_account_product/models/account_payment.py delete mode 100644 l10n_br_account_product/views/account_payment_view.xml diff --git a/l10n_br_account_product/__openerp__.py b/l10n_br_account_product/__openerp__.py index f9ea7db9aac1..8f1a3fddc5fd 100644 --- a/l10n_br_account_product/__openerp__.py +++ b/l10n_br_account_product/__openerp__.py @@ -37,7 +37,6 @@ 'views/account_product_fiscal_classification_view.xml', 'views/product_view.xml', 'views/res_country_view.xml', - 'views/account_payment_view.xml', 'views/account_payment_term_view.xml', 'views/account_invoice_payment.xml', 'views/account_invoice_payment_line.xml', diff --git a/l10n_br_account_product/models/__init__.py b/l10n_br_account_product/models/__init__.py index 1efa8fc9948e..1950f5eae562 100644 --- a/l10n_br_account_product/models/__init__.py +++ b/l10n_br_account_product/models/__init__.py @@ -11,7 +11,6 @@ from . import account from . import product from . import res_country -from . import account_payment from . import account_invoice_term from . import account_invoice_payment from . import account_invoice_payment_line diff --git a/l10n_br_account_product/models/account_payment.py b/l10n_br_account_product/models/account_payment.py deleted file mode 100644 index ee847493762b..000000000000 --- a/l10n_br_account_product/models/account_payment.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- coding: utf-8 -*- -# @ 2018 Akretion - www.akretion.com.br - -# Magno Costa -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) - -from openerp import models, api, fields - - -class PaymentMode(models.Model): - _inherit = 'payment.mode' - - type_nf_payment = fields.Selection([ - ('01', u'01 - Dinheiro'), - ('02', u'02 - Cheque'), - ('03', u'03 - Cartão de Crédito'), - ('04', u'04 - Cartão de Débito'), - ('06', u'05 - Crédito Loja'), - ('10', u'10 - Vale Alimentação'), - ('11', u'11 - Vale Refeição'), - ('12', u'12 - Vale Presente'), - ('13', u'13 - Vale Combustível'), - ('14', u'14 - Duplicata Mercantil'), - ('15', u'15 - Boleto Bancário'), - ('90', u'90 - Sem pagamento'), - ('99', u'99 - Outros') - ], string='Tipo de Pagamento da NF', required=True, - help=u'Obrigatório o preenchimento do Grupo Informações de Pagamento' - u' para NF-e e NFC-e. Para as notas com finalidade de Ajuste' - u' ou Devolução o campo Forma de Pagamento deve ser preenchido' - u' com 90 - Sem Pagamento.' - ) diff --git a/l10n_br_account_product/views/account_payment_view.xml b/l10n_br_account_product/views/account_payment_view.xml deleted file mode 100644 index d9a716a5d807..000000000000 --- a/l10n_br_account_product/views/account_payment_view.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - l10n_br_account_product.payment.mode.form - payment.mode - - - - - - - - - - From 55438a8435ebc07ff2875aef3a6953e21a3b30fd Mon Sep 17 00:00:00 2001 From: Luis Felipe Mileo Date: Thu, 9 Aug 2018 07:49:08 -0300 Subject: [PATCH 29/34] [FIX] Compute dos totais dos pagamentos --- l10n_br_account_product/models/account_invoice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/l10n_br_account_product/models/account_invoice.py b/l10n_br_account_product/models/account_invoice.py index 555c2a831360..b0435bf16460 100644 --- a/l10n_br_account_product/models/account_invoice.py +++ b/l10n_br_account_product/models/account_invoice.py @@ -23,7 +23,7 @@ class AccountInvoice(models.Model): _order = 'date_hour_invoice DESC, internal_number DESC' @api.one - @api.depends('invoice_line', 'tax_line.amount', 'account_payment_ids.amount') + @api.depends('invoice_line', 'tax_line.amount', 'account_payment_line_ids') def _compute_amount(self): self.icms_base = 0.0 self.icms_base_other = 0.0 From 67d90c4abed2c90e34473be98e7aacb4ef911a81 Mon Sep 17 00:00:00 2001 From: Luis Felipe Mileo Date: Fri, 10 Aug 2018 10:48:21 -0300 Subject: [PATCH 30/34] =?UTF-8?q?[REF]=20SEM=20GTIN=20s=C3=B3=20esta=20dis?= =?UTF-8?q?pon=C3=ADvel=20no=20pr=C3=B3ximo=20pacote=20de=20libera=C3=A7?= =?UTF-8?q?=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- l10n_br_account_product/sped/nfe/document.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/l10n_br_account_product/sped/nfe/document.py b/l10n_br_account_product/sped/nfe/document.py index 30780b57a482..5e3bc3f85736 100644 --- a/l10n_br_account_product/sped/nfe/document.py +++ b/l10n_br_account_product/sped/nfe/document.py @@ -355,7 +355,7 @@ def _details(self, invoice, invoice_line, index): if invoice_line.product_id: self.det.prod.cProd.valor = invoice_line.product_id.code or '' - self.det.prod.cEAN.valor = invoice_line.product_id.ean13 or 'SEM GTIN' + self.det.prod.cEAN.valor = invoice_line.product_id.ean13 or '' self.det.prod.cEANTrib.valor = invoice_line.product_id.ean13 or '' self.det.prod.xProd.valor = (normalize( 'NFKD', unicode( From dd6b685683454414ce16c8b2cdadad57bb40c638 Mon Sep 17 00:00:00 2001 From: Luis Felipe Mileo Date: Wed, 15 Aug 2018 20:30:56 -0300 Subject: [PATCH 31/34] [REF] date and parent field of account invoice payment Signed-off-by: Luis Felipe Mileo --- .../models/account_invoice_payment.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/l10n_br_account_product/models/account_invoice_payment.py b/l10n_br_account_product/models/account_invoice_payment.py index 874f3c3c2690..9d379fef9b52 100644 --- a/l10n_br_account_product/models/account_invoice_payment.py +++ b/l10n_br_account_product/models/account_invoice_payment.py @@ -83,6 +83,14 @@ class AccountInvoicePayment(models.Model): string='Duplicatas', ) + def _set_parent(self, field_parent, field_parent_id): + date = False + + if field_parent == 'invoice_id': + date = field_parent_id.date_invoice + self.invoice_id = field_parent_id + return date + @api.onchange('payment_term_id', 'amount', 'item_ids') def _onchange_payment_term_id(self): @@ -93,12 +101,9 @@ def _onchange_payment_term_id(self): field_parent = self.env.context.get('field_parent') field_parent_id = getattr(self, field_parent) - if field_parent == 'invoice_id': - date = field_parent_id.date_invoice - self.invoice_id = field_parent_id - # TODO: Implementar para vendas e compras + date = self._set_parent(field_parent, field_parent_id) - pterm_list = self.payment_term_id.compute(self.amount, date)[0] + pterm_list = self.payment_term_id.compute(self.amount, date[:10])[0] self.forma_pagameto = self.payment_term_id.forma_pagamento From 0051a9e8cb93083e90a04c7d3ac0ff9af7d288f5 Mon Sep 17 00:00:00 2001 From: Luis Felipe Mileo Date: Wed, 15 Aug 2018 20:35:41 -0300 Subject: [PATCH 32/34] [NEW] Forma de pagamento na venda Signed-off-by: Luis Felipe Mileo --- l10n_br_sale_product/__openerp__.py | 2 ++ l10n_br_sale_product/models/__init__.py | 2 ++ .../models/account_invoice_payment.py | 25 +++++++++++++++++++ .../models/account_invoice_payment_line.py | 16 ++++++++++++ l10n_br_sale_product/models/sale.py | 10 ++++++++ l10n_br_sale_product/views/sale_view.xml | 11 ++++++++ 6 files changed, 66 insertions(+) create mode 100644 l10n_br_sale_product/models/account_invoice_payment.py create mode 100644 l10n_br_sale_product/models/account_invoice_payment_line.py diff --git a/l10n_br_sale_product/__openerp__.py b/l10n_br_sale_product/__openerp__.py index f49e0de24081..25c672e52919 100644 --- a/l10n_br_sale_product/__openerp__.py +++ b/l10n_br_sale_product/__openerp__.py @@ -14,6 +14,8 @@ 'l10n_br_account_product', ], 'data': [ + 'views/account_invoice_payment_line.xml', + 'views/account_invoice_payment.xml', 'views/sale_view.xml', 'views/res_company_view.xml', 'data/l10n_br_sale_product_data.xml', diff --git a/l10n_br_sale_product/models/__init__.py b/l10n_br_sale_product/models/__init__.py index 48c4bea2f44a..84080487d024 100644 --- a/l10n_br_sale_product/models/__init__.py +++ b/l10n_br_sale_product/models/__init__.py @@ -4,3 +4,5 @@ from . import res_company from . import sale +from . import account_invoice_payment +from . import account_invoice_payment_line diff --git a/l10n_br_sale_product/models/account_invoice_payment.py b/l10n_br_sale_product/models/account_invoice_payment.py new file mode 100644 index 000000000000..43c46735ec8a --- /dev/null +++ b/l10n_br_sale_product/models/account_invoice_payment.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 KMEE INFORMATICA LTDA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp import api, fields, models, _ + + +class AccountInvoicePayment(models.Model): + + _inherit = 'account.invoice.payment' + + sale_id = fields.Many2one( + comodel_name='sale.order', + string='Sale Order', + ondelete='set null', + ) + + def _set_parent(self, field_parent, field_parent_id): + date = super(AccountInvoicePayment, self)._set_parent( + field_parent, field_parent_id + ) + if field_parent == 'sale_id': + date = field_parent_id.date_order + self.sale_id = field_parent_id + return date diff --git a/l10n_br_sale_product/models/account_invoice_payment_line.py b/l10n_br_sale_product/models/account_invoice_payment_line.py new file mode 100644 index 000000000000..20ddbc0b704a --- /dev/null +++ b/l10n_br_sale_product/models/account_invoice_payment_line.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 KMEE INFORMATICA LTDA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp import api, fields, models, _ + + +class AccountInvoicePaymentLine(models.Model): + + _inherit = 'account.invoice.payment.line' + + sale_id = fields.Many2one( + comodel_name='sale.order', + related='payment_id.sale_id', + store=True, + ) diff --git a/l10n_br_sale_product/models/sale.py b/l10n_br_sale_product/models/sale.py index 5a0eee6f6ff7..df7dbe2a7781 100644 --- a/l10n_br_sale_product/models/sale.py +++ b/l10n_br_sale_product/models/sale.py @@ -185,6 +185,16 @@ def _set_amount_costs(self): compute=_get_costs_value, inverse=_set_amount_insurance, string='Seguro', default=0.00, digits=dp.get_precision('Account'), readonly=True, states={'draft': [('readonly', False)]}) + account_payment_ids = fields.One2many( + string='Dados de Pagamento', + comodel_name='account.invoice.payment', + inverse_name='sale_id', + ) + account_payment_line_ids = fields.One2many( + string='Dados da cobrança', + comodel_name='account.invoice.payment.line', + inverse_name='sale_id', + ) def _fiscal_comment(self, cr, uid, order, context=None): fp_comment = [] diff --git a/l10n_br_sale_product/views/sale_view.xml b/l10n_br_sale_product/views/sale_view.xml index c5d1a74decf6..d50dcb0b7e32 100644 --- a/l10n_br_sale_product/views/sale_view.xml +++ b/l10n_br_sale_product/views/sale_view.xml @@ -33,6 +33,17 @@ + + + + + + + + + + + From 947edfb3c964bf93b4372bf50736866ec4ccec93 Mon Sep 17 00:00:00 2001 From: Luis Felipe Mileo Date: Fri, 17 Aug 2018 15:35:09 -0300 Subject: [PATCH 33/34] [REF] Dados de pagamento da invoice Signed-off-by: Luis Felipe Mileo --- .../models/account_invoice.py | 139 ++++++++++-------- .../models/account_invoice_payment.py | 47 ++++-- 2 files changed, 112 insertions(+), 74 deletions(-) diff --git a/l10n_br_account_product/models/account_invoice.py b/l10n_br_account_product/models/account_invoice.py index b0435bf16460..ea0e9dd135a9 100644 --- a/l10n_br_account_product/models/account_invoice.py +++ b/l10n_br_account_product/models/account_invoice.py @@ -528,6 +528,54 @@ def nfe_check(self, cr, uid, ids, context=None): result = txt.validate(cr, uid, ids, context) return result + def action_payment(self): + """ Processa informações dos pagamentos""" + for invoice in self: + if invoice.nfe_version == '4.00': + if invoice.issuer == '0': + # Preenche a forma de pagamento padrão caso ainda não + # Tenha sido preenchida pelo usuário, mesma funcionalidade + # da venda e compras, mas lá é aplicado através de um + # onchange + # + # Não da pra fazer com onchange na invoice pois a ST e + # outros impostos são calculados somente quando salvamos. + # + if (invoice.payment_term and invoice.amount_total and + not invoice.account_payment_ids): + date_invoice = invoice.date_invoice + + if not date_invoice: + date_invoice = fields.Date.context_today(invoice) + + payment_id = invoice.account_payment_ids.new() + payment_id.payment_term_id = invoice.payment_term + payment_id.amount = invoice.amount_total + payment_id.date = date_invoice + payment_id.onchange_payment_term_id() + invoice.account_payment_ids |= payment_id + + if not invoice.account_payment_ids: + raise UserError( + _(u'A nota fiscal deve conter dados de pagamento') + ) + elif invoice.amount_change < 0: + # + # TODO: Implementar lançamento contábil com troco + # + raise UserError( + _(u'O total de pagamentos deve ser maior ou igual ' + u'ao total da nota.\n'), + _(u'Resta realizar o pagamento de %0.2f' + % invoice.amount_change) + ) + else: + for item, payment in enumerate( + invoice.account_payment_line_ids): + if payment.number: + continue + payment.number = str(item + 1).zfill(3) + @api.multi def action_number(self): # TODO: not correct fix but required a fresh values before reading it. @@ -563,47 +611,7 @@ def action_number(self): 'date_hour_invoice': date_time_invoice, 'date_in_out': date_in_out} ) - - if invoice.nfe_version == '4.00': - if not invoice.account_payment_ids: - if (invoice.fiscal_category_id and - invoice.fiscal_category_id.account_payment_term_id): - - account_payments = self.env['account.invoice.payment'] - - amount = 0.00 - if not (invoice.fiscal_category_id.account_payment_term_id.forma_pagamento == - FORMA_PAGAMENTO_SEM_PAGAMENTO): - amount = invoice.amount_total - - values = { - 'payment_term_id': - invoice.fiscal_category_id.account_payment_term_id.id, - 'amount': amount, - } - specs = account_payments._onchange_spec() - updates = account_payments.onchange(values, [], specs) - value = updates.get('value', {}) - for name, val in value.iteritems(): - if isinstance(val, tuple): - value[name] = val[0] - values.update(value) - - invoice.account_payment_ids = [(0, 0, values)] - - if not invoice.account_payment_ids: - raise UserError( - _(u'A nota fiscal deve conter dados de pagamento') - ) - elif invoice.amount_change < 0: - raise UserError( - _(u'O total de pagamentos deve ser maior ou igual ao total da nota.\n'), - _(u'Resta realizar o pagamento de %0.2f' % invoice.amount_change) - ) - else: - for item, payment in enumerate(invoice.account_payment_line_ids): - payment.number = str(item + 1).zfill(3) - + self.action_payment() return True @api.onchange('type') @@ -645,24 +653,6 @@ def onchange_fiscal(self): 'context': self.env.context } result = self._fiscal_position_map(result, **kwargs) - - if (self.fiscal_category_id and - self.fiscal_category_id.account_payment_term_id) and \ - not self.account_payment_ids: - account_payments = self.env['account.invoice.payment'] - values = { - 'payment_term_id': - self.fiscal_category_id.account_payment_term_id.id, - 'amount': self.amount_total, - } - specs = account_payments._onchange_spec() - updates = account_payments.onchange(values, [], specs) - value = updates.get('value', {}) - for name, val in value.iteritems(): - if isinstance(val, tuple): - value[name] = val[0] - values.update(value) - result['value']['account_payment_ids'] = [(0, 0, values)] self.update(result['value']) @api.multi @@ -920,6 +910,37 @@ def action_move_create(self): self._log_event() return True + @api.multi + def onchange_partner_id(self, type, partner_id, date_invoice=False, + payment_term=False, partner_bank_id=False, company_id=False): + result = super(AccountInvoice, self).onchange_partner_id( + type, partner_id, date_invoice, payment_term, + partner_bank_id, company_id + ) + # Sobrescreve o compartamento padrão do core de aplicar a forma de pagamento + # verificar metodo: onchange_fiscal_payment_term + if result.get('value'): + result['value'].pop('payment_term', None) + return result + + @api.onchange('fiscal_category_id', 'fiscal_position_id') + def onchange_fiscal_payment_term(self): + """ Quando a posição fiscal for preenchida temos os dados da categoria e do partner + e então podemos tomar decidir qual o payment_term adequado + :return: + """ + partner_id = self.partner_id + + payment_term = self.env['account.payment.term'] + # Busca do partner + if partner_id and partner_id.property_payment_term: + payment_term = partner_id.property_payment_term + # Sobrecreve a opção do parceiro caso a categoria fiscal tenha uma opção definida + + if self.fiscal_category_id and self.fiscal_category_id.account_payment_term_id: + payment_term = self.fiscal_category_id.account_payment_term_id + self.payment_term = payment_term + class AccountInvoiceLine(models.Model): _inherit = 'account.invoice.line' diff --git a/l10n_br_account_product/models/account_invoice_payment.py b/l10n_br_account_product/models/account_invoice_payment.py index 9d379fef9b52..410184b8587f 100644 --- a/l10n_br_account_product/models/account_invoice_payment.py +++ b/l10n_br_account_product/models/account_invoice_payment.py @@ -7,15 +7,11 @@ from openerp import api, fields, models, _ from .account_invoice_term import ( - FORMA_PAGAMENTO, - BANDEIRA_CARTAO, - FORMA_PAGAMENTO_CARTOES, - IND_FORMA_PAGAMENTO, - INTEGRACAO_CARTAO, - INTEGRACAO_CARTAO_NAO_INTEGRADO, + FORMA_PAGAMENTO_SEM_PAGAMENTO, ) + class AccountInvoicePayment(models.Model): _name = b'account.invoice.payment' _description = 'Dados de pagamento' @@ -24,6 +20,10 @@ class AccountInvoicePayment(models.Model): sequence = fields.Integer( default=10, ) + date = fields.Date( + string='Data de referência', + readonly=True, + ) payment_term_id = fields.Many2one( comodel_name='account.payment.term', string='Condição de pagamento', @@ -89,25 +89,27 @@ def _set_parent(self, field_parent, field_parent_id): if field_parent == 'invoice_id': date = field_parent_id.date_invoice self.invoice_id = field_parent_id - return date + return date or fields.Date.context_today(field_parent_id) - @api.onchange('payment_term_id', 'amount', 'item_ids') - def _onchange_payment_term_id(self): + @api.onchange('payment_term_id', 'amount', 'item_ids', 'date') + def onchange_payment_term_id(self): - if not (self.payment_term_id and self.amount and - self.env.context.get('field_parent')): + if not (self.payment_term_id and self.amount): return field_parent = self.env.context.get('field_parent') - field_parent_id = getattr(self, field_parent) - date = self._set_parent(field_parent, field_parent_id) + if field_parent: + field_parent_id = getattr(self, field_parent) + self.date = self._set_parent(field_parent, field_parent_id)[:10] - pterm_list = self.payment_term_id.compute(self.amount, date[:10])[0] + pterm_list = self.payment_term_id.compute(self.amount, self.date)[0] self.forma_pagameto = self.payment_term_id.forma_pagamento - item_ids = [] + item_ids = [ + (5, 0, {}) + ] for term in pterm_list: item_ids.append( @@ -120,3 +122,18 @@ def _onchange_payment_term_id(self): }) ) self.item_ids = item_ids + + def default_payment_term(self, payment_term_id, amount=0.00, object=False, date=False): + + if not (payment_term_id.forma_pagamento == + FORMA_PAGAMENTO_SEM_PAGAMENTO): + + values = { + 'payment_term_id': payment_term_id.id, + 'amount': amount, + 'date': fields.Date.today(self), + } + term = self.create(values) + term._onchange_payment_term_id() + + return term From 5f645eb02adffabceedc57076ee251420681f1ea Mon Sep 17 00:00:00 2001 From: Luis Felipe Mileo Date: Fri, 17 Aug 2018 15:37:57 -0300 Subject: [PATCH 34/34] =?UTF-8?q?[IMP]=20Melhorias=20no=20parcelamento=20n?= =?UTF-8?q?o=20m=C3=B3dulo=20de=20vendas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Luis Felipe Mileo --- l10n_br_sale_product/models/sale.py | 48 +++++++++++++++++++++++- l10n_br_sale_product/views/sale_view.xml | 7 +++- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/l10n_br_sale_product/models/sale.py b/l10n_br_sale_product/models/sale.py index df7dbe2a7781..e54cf9164919 100644 --- a/l10n_br_sale_product/models/sale.py +++ b/l10n_br_sale_product/models/sale.py @@ -221,9 +221,55 @@ def _make_invoice(self, order, lines): self.env.user.company_id.id) context.update( {'fiscal_document_code': company.product_invoice_id.code}) - return super(SaleOrder, + inv_id = super(SaleOrder, self.with_context(context))._make_invoice(order, lines) + # TODO: Verificar o que deve ser feito com multiplas faturas para uma série de pagamentos + # Devemos mesclar as parcelas? E se o faturamento não for 100%? + # Mantemos a proporção / condição e refazemos as parcelas? + order.account_payment_ids.write({'invoice_id': inv_id}) + return inv_id + + @api.multi + def onchange_partner_id(self, part): + result = super(SaleOrder, self).onchange_partner_id(part) + # Sobrescreve o compartamento padrão do core de aplicar a forma de pagamento + # verificar metodo: onchange_fiscal_payment_term + if result.get('value'): + result['value'].pop('payment_term', None) + return result + + @api.onchange('fiscal_category_id', 'fiscal_position_id') + def onchange_fiscal_payment_term(self): + """ Quando a posição fiscal for preenchida temos os dados da categoria e do partner + e então podemos tomar decidir qual o payment_term adequado + :return: + """ + partner_id = self.partner_invoice_id or self.partner_id + + payment_term = self.env['account.payment.term'] + # Busca do partner + if partner_id and partner_id.property_payment_term: + payment_term = partner_id.property_payment_term + # Sobrecreve a opção do parceiro caso a categoria fiscal tenha uma opção definida + + if self.fiscal_category_id and self.fiscal_category_id.account_payment_term_id: + payment_term = self.fiscal_category_id.account_payment_term_id + self.payment_term = payment_term + + @api.onchange('payment_term', 'amount_total', 'date_order') + def onchange_default_payment_term(self): + """ Preenche a forma de pagamento padrão mantendo compatibilidade com o campo do core + :return: + """ + if (self.payment_term and self.amount_total and + self.date_order and not self.account_payment_ids): + payment_id = self.account_payment_ids.new() + payment_id.payment_term_id = self.payment_term + payment_id.amount = self.amount_total + payment_id.date = self.date_order[:10] + payment_id.onchange_payment_term_id() + self.account_payment_ids |= payment_id class SaleOrderLine(models.Model): diff --git a/l10n_br_sale_product/views/sale_view.xml b/l10n_br_sale_product/views/sale_view.xml index d50dcb0b7e32..b2ee8cf529c7 100644 --- a/l10n_br_sale_product/views/sale_view.xml +++ b/l10n_br_sale_product/views/sale_view.xml @@ -16,6 +16,9 @@ + + 1 + @@ -35,10 +38,10 @@ - + - +