diff --git a/l10n_br_account_product/__openerp__.py b/l10n_br_account_product/__openerp__.py
index 278352c7cb3d..9a265ef09dd6 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',
@@ -23,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',
@@ -35,6 +37,9 @@
'views/account_product_fiscal_classification_view.xml',
'views/product_view.xml',
'views/res_country_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/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 e549a70f4cd8..d43442bd537a 100644
--- a/l10n_br_account_product/models/__init__.py
+++ b/l10n_br_account_product/models/__init__.py
@@ -11,4 +11,7 @@
from . import account
from . import product
from . import res_country
+from . import account_invoice_term
+from . import account_invoice_payment
+from . import account_invoice_payment_line
from . import res_config
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/models/account_invoice.py b/l10n_br_account_product/models/account_invoice.py
index a7a27333fdab..0a072bc65bbe 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):
@@ -22,7 +23,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_line_ids')
def _compute_amount(self):
self.icms_base = 0.0
self.icms_base_other = 0.0
@@ -77,6 +78,14 @@ 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
+ if self.amount_payment_net:
+ self.amount_change = self.amount_payment_net - self.amount_total
+
@api.model
@api.returns('l10n_br_account.fiscal_category')
def _default_fiscal_category(self):
@@ -161,8 +170,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(
@@ -177,11 +187,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,
@@ -389,6 +401,42 @@ 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',
+ 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',
+ )
+ 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')
@@ -480,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.
@@ -515,6 +611,7 @@ def action_number(self):
'date_hour_invoice': date_time_invoice,
'date_in_out': date_in_out}
)
+ self.action_payment()
return True
@api.onchange('type')
@@ -545,8 +642,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,
@@ -555,7 +653,7 @@ def onchange_fiscal(self):
'context': self.env.context
}
result = self._fiscal_position_map(result, **kwargs)
- self.update(result['value'])
+ self.update(result['value'])
@api.multi
def action_date_assign(self):
@@ -648,6 +746,210 @@ 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
+
+ @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
new file mode 100644
index 000000000000..410184b8587f
--- /dev/null
+++ b/l10n_br_account_product/models/account_invoice_payment.py
@@ -0,0 +1,139 @@
+# -*- 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_SEM_PAGAMENTO,
+)
+
+
+
+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,
+ )
+ 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',
+ 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',
+ )
+
+ 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 or fields.Date.context_today(field_parent_id)
+
+ @api.onchange('payment_term_id', 'amount', 'item_ids', 'date')
+ def onchange_payment_term_id(self):
+
+ if not (self.payment_term_id and self.amount):
+ return
+
+ field_parent = self.env.context.get('field_parent')
+
+ 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, self.date)[0]
+
+ self.forma_pagameto = self.payment_term_id.forma_pagamento
+
+ item_ids = [
+ (5, 0, {})
+ ]
+
+ for term in pterm_list:
+ item_ids.append(
+ (0, 0, {
+ 'payment_id': self.id,
+ 'date_due': term[0],
+ 'amount_original': term[1],
+ 'amount_discount': 0.00,
+ 'amount_net': term[1],
+ })
+ )
+ 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
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..403b47815fc4
--- /dev/null
+++ b/l10n_br_account_product/models/account_invoice_payment_line.py
@@ -0,0 +1,56 @@
+# -*- 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_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/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/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/models/res_company.py b/l10n_br_account_product/models/res_company.py
index b6915c57cd21..a5d61a0305ee 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)
diff --git a/l10n_br_account_product/security/ir.model.access.csv b/l10n_br_account_product/security/ir.model.access.csv
index 87528af2a0db..3d0d514e10cd 100644
--- a/l10n_br_account_product/security/ir.model.access.csv
+++ b/l10n_br_account_product/security/ir.model.access.csv
@@ -38,3 +38,11 @@
"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
+"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
diff --git a/l10n_br_account_product/sped/nfe/document.py b/l10n_br_account_product/sped/nfe/document.py
index 415032329fc6..5e3bc3f85736 100644
--- a/l10n_br_account_product/sped/nfe/document.py
+++ b/l10n_br_account_product/sped/nfe/document.py
@@ -12,6 +12,11 @@
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,
+ FORMA_PAGAMENTO_SEM_PAGAMENTO,
+)
+
class NFe200(FiscalDocument):
def __init__(self):
@@ -69,17 +74,15 @@ 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._details_pag(invoice, self.nfe.infNFe.pag)
+
self.vol = self._get_Vol()
self._weight_data(invoice)
self.nfe.infNFe.transp.vol.append(self.vol)
@@ -226,18 +229,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 '')
@@ -281,8 +290,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)
@@ -294,8 +305,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(
@@ -313,14 +326,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
@@ -341,11 +357,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]
@@ -527,9 +548,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:
@@ -824,3 +862,117 @@ 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, pag):
+
+ for pagamento in invoice.account_payment_ids:
+ pag.detPag.append(self._payment_date(pagamento))
+
+ pag.vTroco.valor = str("%.2f" % 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"""
+
+ 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_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_net)
+ cobr.dup.append(dup)
+
+ 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()
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..f9d6b85c287f
--- /dev/null
+++ b/l10n_br_account_product/views/account_invoice_payment_line.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+ account.invoice.payment.line.tree (in l10n_br_account)
+ account.invoice.payment.line
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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_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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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
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..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,6 +10,10 @@
0
+
+
+
+
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..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
@@ -171,15 +171,29 @@
-
-
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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/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..e54cf9164919 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(
@@ -183,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 = []
@@ -209,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 c5d1a74decf6..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
+
@@ -33,6 +36,17 @@
+
+
+
+
+
+
+
+
+
+
+