Código fonte para l10n_br_account_product.models.account_invoice

# -*- coding: utf-8 -*-
# Copyright (C) 2013  Renato Lima - Akretion
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html

import datetime

from openerp import models, fields, api, _, tools
from openerp.addons import decimal_precision as dp
from openerp.exceptions import (RedirectWarning,
                                ValidationError,
                                Warning as UserError)

from .l10n_br_account_product import (
    PRODUCT_FISCAL_TYPE,
    PRODUCT_FISCAL_TYPE_DEFAULT)
from .product import PRODUCT_ORIGIN
from openerp.addons.l10n_br_account_product.sped.nfe.validator import txt


[documentos]class AccountInvoice(models.Model): _inherit = 'account.invoice' _order = 'date_hour_invoice DESC, internal_number DESC' @api.one @api.depends('invoice_line', 'tax_line.amount') def _compute_amount(self): self.icms_base = 0.0 self.icms_base_other = 0.0 self.icms_value = 0.0 self.icms_st_base = 0.0 self.icms_st_value = 0.0 self.ipi_base = sum(line.ipi_base for line in self.invoice_line) self.ipi_base_other = sum( line.ipi_base_other for line in self.invoice_line) self.ipi_value = sum(line.ipi_value for line in self.invoice_line) self.pis_base = sum(line.pis_base for line in self.invoice_line) self.pis_value = sum(line.pis_value for line in self.invoice_line) self.cofins_base = sum(line.cofins_base for line in self.invoice_line) self.cofins_value = sum( line.cofins_value for line in self.invoice_line) self.ii_value = sum(line.ii_value for line in self.invoice_line) self.icms_fcp_value = sum( line.icms_fcp_value for line in self.invoice_line) self.icms_dest_value = sum( line.icms_dest_value for line in self.invoice_line) self.icms_origin_value = sum( line.icms_origin_value for line in self.invoice_line) self.amount_discount = sum( line.discount_value for line in self.invoice_line) self.amount_insurance = sum( line.insurance_value for line in self.invoice_line) self.amount_costs = sum( line.other_costs_value for line in self.invoice_line) self.amount_freight = sum( line.freight_value for line in self.invoice_line) self.amount_total_taxes = sum( line.total_taxes for line in self.invoice_line) self.amount_gross = sum(line.price_gross for line in self.invoice_line) self.amount_tax_discount = 0.0 self.amount_untaxed = sum( line.price_subtotal for line in self.invoice_line) self.amount_tax = sum(tax.amount for tax in self.tax_line if not tax.tax_code_id.tax_discount) self.amount_total = self.amount_tax + self.amount_untaxed for line in self.invoice_line: if line.icms_cst_id.code not in ( '101', '102', '201', '202', '300', '500'): self.icms_base += line.icms_base self.icms_base_other += line.icms_base_other self.icms_value += line.icms_value else: self.icms_base += 0.00 self.icms_base_other += 0.00 self.icms_value += 0.00 if line.icms_cst_id.code in ('10', '30', '60', '90'): self.icms_st_base += line.icms_st_base self.icms_st_value += line.icms_st_value else: self.icms_st_base += 0.00 self.icms_st_value += 0.00 @api.model @api.returns('l10n_br_account.fiscal_category') def _default_fiscal_category(self): DEFAULT_FCATEGORY_PRODUCT = { 'in_invoice': 'in_invoice_fiscal_category_id', 'out_invoice': 'out_invoice_fiscal_category_id', 'in_refund': 'in_refund_fiscal_category_id', 'out_refund': 'out_refund_fiscal_category_id' } default_fo_category = {'product': DEFAULT_FCATEGORY_PRODUCT} invoice_type = self._context.get('type', 'out_invoice') invoice_fiscal_type = self._context.get('fiscal_type', 'product') company = self.env['res.company'].browse(self.env.user.company_id.id) return company[default_fo_category[invoice_fiscal_type][invoice_type]] @api.model def _default_fiscal_document(self): if self.env.context.get('fiscal_document_code'): company = self.env['res.company'].browse( self.env.user.company_id.id) return company.product_invoice_id @api.model def _default_nfe_version(self): if self.env.context.get('fiscal_document_code'): company = self.env['res.company'].browse( self.env.user.company_id.id) return company.nfe_version @api.model def _default_fiscal_document_serie(self): result = self.env['l10n_br_account.document.serie'] if self.env.context.get('fiscal_document_code'): company = self.env['res.company'].browse( self.env.user.company_id.id) fiscal_document_series = [doc_serie for doc_serie in company.document_serie_product_ids if doc_serie.fiscal_document_id.id == company.product_invoice_id.id and doc_serie.active] if fiscal_document_series: result = fiscal_document_series[0] return result @api.model def _default_nfe_purpose(self): nfe_purpose_default = { 'in_invoice': '1', 'out_invoice': '1', 'in_refund': '4', 'out_refund': '4' } invoice_type = self.env.context.get('type', 'out_invoice') return nfe_purpose_default.get(invoice_type) @api.one @api.depends('invoice_line.cfop_id') def _compute_cfops(self): lines = self.env['l10n_br_account_product.cfop'] for line in self.invoice_line: if line.cfop_id: lines |= line.cfop_id self.cfop_ids = (lines).sorted() issuer = fields.Selection( [('0', u'Emissão própria'), ('1', 'Terceiros')], 'Emitente', default='0', readonly=True, states={'draft': [('readonly', False)]} ) # FIXME internal_number = fields.Char( 'Invoice Number', size=32, readonly=True, states={'draft': [('readonly', False)]}, help="""Unique number of the invoice, computed automatically when the invoice is created.""") type = fields.Selection( states={'draft': [('readonly', False)]} ) vendor_serie = fields.Char( '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')], u'Versão NFe', readonly=True, default=_default_nfe_version, states={'draft': [('readonly', False)]}) date_hour_invoice = fields.Datetime( u'Data e hora de emissão', readonly=True, states={'draft': [('readonly', False)]}, select=True, help="Deixe em branco para usar a data atual") ind_final = fields.Selection( [('0', u'Não'), ('1', u'Sim')], u'Consumidor final', readonly=True, related='fiscal_position.ind_final', states={'draft': [('readonly', False)]}, required=False, help=u'Indica operação com Consumidor final.') ind_pres = fields.Selection([ ('0', u'Não se aplica'), ('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, help=u'Indicador de presença do comprador no\n' u'estabelecimento comercial no momento\n' u'da operação.', default='0') fiscal_document_id = fields.Many2one( 'l10n_br_account.fiscal.document', 'Documento', readonly=True, states={'draft': [('readonly', False)]}, default=_default_fiscal_document) fiscal_document_electronic = fields.Boolean( related='fiscal_document_id.electronic') document_serie_id = fields.Many2one( 'l10n_br_account.document.serie', u'Série', domain="[('fiscal_document_id', '=', fiscal_document_id),\ ('company_id','=',company_id)]", readonly=True, states={'draft': [('readonly', False)]}, default=_default_fiscal_document_serie) fiscal_category_id = fields.Many2one( 'l10n_br_account.fiscal.category', 'Categoria Fiscal', readonly=True, states={'draft': [('readonly', False)]}, default=_default_fiscal_category, ) date_in_out = fields.Datetime( u'Data de Entrada/Saida', readonly=True, states={ 'draft': [ ('readonly', False)]}, select=True, copy=False, help="Deixe em branco para usar a data atual") partner_shipping_id = fields.Many2one( 'res.partner', 'Delivery Address', readonly=True, required=True, states={'draft': [('readonly', False)]}, help="Delivery address for current sales order.") fiscal_type = fields.Selection( PRODUCT_FISCAL_TYPE, 'Tipo Fiscal', default=PRODUCT_FISCAL_TYPE_DEFAULT) partner_shipping_id = fields.Many2one( 'res.partner', u'Endereço de Entrega', readonly=True, states={'draft': [('readonly', False)]}, help="Shipping address for current sales order.") shipping_state_id = fields.Many2one( 'res.country.state', 'Estado de Embarque') shipping_location = fields.Char('Local de Embarque', size=32) expedition_location = fields.Char('Local de Despacho', size=32) nfe_purpose = fields.Selection( [('1', 'Normal'), ('2', 'Complementar'), ('3', 'Ajuste'), ('4', u'Devolução de Mercadoria')], u'Finalidade da Emissão', readonly=True, states={'draft': [('readonly', False)]}, default=_default_nfe_purpose) nfe_access_key = fields.Char( 'Chave de Acesso NFE', size=44, readonly=True, states={'draft': [('readonly', False)]}, copy=False) nfe_protocol_number = fields.Char( 'Protocolo', size=15, readonly=True, copy=False, states={'draft': [('readonly', False)]}) nfe_status = fields.Char('Status na Sefaz', size=44, readonly=True, copy=False) nfe_date = fields.Datetime('Data do Status NFE', readonly=True, copy=False) nfe_export_date = fields.Datetime(u'Exportação NFE', readonly=True) cfop_ids = fields.Many2many( 'l10n_br_account_product.cfop', string='CFOP', copy=False, compute='_compute_cfops') fiscal_document_related_ids = fields.One2many( 'l10n_br_account_product.document.related', 'invoice_id', 'Fiscal Document Related', readonly=True, states={'draft': [('readonly', False)]}) carrier_name = fields.Char('Nome Transportadora', size=32) vehicle_plate = fields.Char(u'Placa do Veículo', size=7) vehicle_state_id = fields.Many2one('res.country.state', 'UF da Placa') vehicle_l10n_br_city_id = fields.Many2one( 'l10n_br_base.city', u'Município', domain="[('state_id', '=', vehicle_state_id)]") amount_untaxed = fields.Float( string='Untaxed', store=True, digits=dp.get_precision('Account'), compute='_compute_amount') amount_tax = fields.Float( string='Tax', store=True, digits=dp.get_precision('Account'), compute='_compute_amount') amount_total = fields.Float( string='Total', store=True, digits=dp.get_precision('Account'), compute='_compute_amount') amount_gross = fields.Float( string='Vlr. Bruto', store=True, digits=dp.get_precision('Account'), compute='_compute_amount', readonly=True) amount_discount = fields.Float( string='Desconto', store=True, digits=dp.get_precision('Account'), compute='_compute_amount') icms_base = fields.Float( string='Base ICMS', store=True, digits=dp.get_precision('Account'), compute='_compute_amount') icms_base_other = fields.Float( string='Base ICMS Outras', store=True, digits=dp.get_precision('Account'), compute='_compute_amount', readonly=True) icms_value = fields.Float( string='Valor ICMS', digits=dp.get_precision('Account'), compute='_compute_amount', store=True) icms_st_base = fields.Float( string='Base ICMS ST', store=True, digits=dp.get_precision('Account'), compute='_compute_amount') icms_st_value = fields.Float( string='Valor ICMS ST', store=True, digits=dp.get_precision('Account'), compute='_compute_amount') ipi_base = fields.Float( string='Base IPI', store=True, digits=dp.get_precision('Account'), compute='_compute_amount') ipi_base_other = fields.Float( string="Base IPI Outras", store=True, digits=dp.get_precision('Account'), compute='_compute_amount') ipi_value = fields.Float( string='Valor IPI', store=True, digits=dp.get_precision('Account'), compute='_compute_amount') pis_base = fields.Float( string='Base PIS', store=True, digits=dp.get_precision('Account'), compute='_compute_amount') pis_value = fields.Float( string='Valor PIS', store=True, digits=dp.get_precision('Account'), compute='_compute_amount') cofins_base = fields.Float( string='Base COFINS', store=True, digits=dp.get_precision('Account'), compute='_compute_amount') cofins_value = fields.Float( string='Valor COFINS', store=True, digits=dp.get_precision('Account'), compute='_compute_amount', readonly=True) ii_value = fields.Float( string='Valor II', store=True, digits=dp.get_precision('Account'), compute='_compute_amount', readonly=True) icms_fcp_value = fields.Float( string='Valor total do Fundo de Combate à Pobreza (FCP)', store=True, digits=dp.get_precision('Account'), compute='_compute_amount', readonly=True) icms_dest_value = fields.Float( string='Valor total do ICMS Interestadual para a UF de destino', store=True, digits=dp.get_precision('Account'), compute='_compute_amount', readonly=True) icms_origin_value = fields.Float( string='Valor total do ICMS Interestadual para a UF do remetente', store=True, digits=dp.get_precision('Account'), compute='_compute_amount', readonly=True) weight = fields.Float( string='Gross weight', states={'draft': [('readonly', False)]}, help="The gross weight in Kg.", readonly=True) weight_net = fields.Float( 'Net weight', help="The net weight in Kg.", readonly=True, states={'draft': [('readonly', False)]}) number_of_packages = fields.Integer( 'Volume', readonly=True, states={'draft': [('readonly', False)]}) kind_of_packages = fields.Char( u'Espécie', size=60, readonly=True, states={ 'draft': [ ('readonly', False)]}) brand_of_packages = fields.Char( 'Brand', size=60, readonly=True, states={ 'draft': [ ('readonly', False)]}) notation_of_packages = fields.Char( u'Numeração', size=60, readonly=True, states={ 'draft': [ ('readonly', False)]}) amount_insurance = fields.Float( string='Valor do Seguro', store=True, digits=dp.get_precision('Account'), compute='_compute_amount') amount_freight = fields.Float( string='Valor do Frete', store=True, digits=dp.get_precision('Account'), compute='_compute_amount') amount_costs = fields.Float( string='Outros Custos', store=True, digits=dp.get_precision('Account'), compute='_compute_amount') amount_total_taxes = fields.Float( string='Total de Tributos', store=True, digits=dp.get_precision('Account'), compute='_compute_amount') @api.one @api.constrains('number') def _check_invoice_number(self): domain = [] if self.number: fiscal_document = self.fiscal_document_id and\ self.fiscal_document_id.id or False domain.extend([('internal_number', '=', self.number), ('fiscal_type', '=', self.fiscal_type), ('fiscal_document_id', '=', fiscal_document) ]) if self.issuer == '0': domain.extend([ ('company_id', '=', self.company_id.id), ('internal_number', '=', self.number), ('fiscal_document_id', '=', self.fiscal_document_id.id), ('issuer', '=', '0')]) else: domain.extend([ ('partner_id', '=', self.partner_id.id), ('vendor_serie', '=', self.vendor_serie), ('issuer', '=', '1')]) invoices = self.env['account.invoice'].search(domain) if len(invoices) > 1: raise UserError(u'Não é possível registrar documentos\ fiscais com números repetidos.') def _fiscal_position_map(self, result, **kwargs): ctx = dict(self._context) ctx.update({'use_domain': ('use_invoice', '=', True)}) if ctx.get('fiscal_category_id'): kwargs['fiscal_category_id'] = ctx.get('fiscal_category_id') if not kwargs.get('fiscal_category_id'): return result company = self.env['res.company'].browse(kwargs.get('company_id')) fcategory = self.env['l10n_br_account.fiscal.category'].browse( kwargs.get('fiscal_category_id')) result['value']['journal_id'] = fcategory.property_journal.id if not result['value'].get('journal_id', False): raise UserError( _('Nenhum Diário !'), _("Categoria fiscal: '%s', não tem um diário contábil para a \ empresa %s") % (fcategory.name, company.name)) return self.env['account.fiscal.position.rule'].with_context( ctx).apply_fiscal_mapping(result, **kwargs) @api.model
[documentos] def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False): context = self.env.context fiscal_document_code = context.get('fiscal_document_code') active_id = context.get('active_id') nfe_form = 'l10n_br_account_product.l10n_br_account_product_nfe_form' nfe_tree = 'l10n_br_account_product.l10n_br_account_product_nfe_tree' nfe_views = {'form': nfe_form, 'tree': nfe_tree} if active_id and not fiscal_document_code: invoice = self.browse(active_id) fiscal_document_code = invoice.fiscal_document_id.code if nfe_views.get(view_type) and fiscal_document_code == u'55': view_id = self.env.ref(nfe_views.get(view_type)).id return super(AccountInvoice, self).fields_view_get( view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu)
# TODO Imaginar em não apagar o internal number para nao ter a necessidade # de voltar a numeracão @api.multi
[documentos] def action_cancel_draft(self): result = super(AccountInvoice, self).action_cancel_draft() self.write({ 'internal_number': False, 'nfe_access_key': False, 'nfe_status': False, 'nfe_date': False, 'nfe_export_date': False}) return result
[documentos] def nfe_check(self, cr, uid, ids, context=None): if context.get('fiscal_document_code', '') == '55': result = txt.validate(cr, uid, ids, context) return result
@api.multi
[documentos] def action_number(self): # TODO: not correct fix but required a fresh values before reading it. self.write({}) for invoice in self: if invoice.issuer == '0': sequence_obj = self.env['ir.sequence'] sequence = sequence_obj.browse( invoice.document_serie_id.internal_sequence_id.id) invalid_number = self.env[ 'l10n_br_account.invoice.invalid.number'].search( [('number_start', '<=', sequence.number_next), ('number_end', '>=', sequence.number_next), ('document_serie_id', '=', invoice.document_serie_id.id), ('state', '=', 'done')]) if invalid_number: raise UserError( _(u'Número Inválido !'), _("O número: %s da série: %s, esta inutilizado") % ( sequence.number_next, invoice.document_serie_id.name)) seq_number = sequence_obj.get_id( invoice.document_serie_id.internal_sequence_id.id) date_time_invoice = (invoice.date_hour_invoice or fields.datetime.now()) date_in_out = invoice.date_in_out or fields.datetime.now() self.write( {'internal_number': seq_number, 'number': seq_number, 'date_hour_invoice': date_time_invoice, 'date_in_out': date_in_out} ) return True
@api.onchange('type')
[documentos] def onchange_type(self): ctx = dict(self.env.context) ctx.update({'type': self.type}) self.fiscal_category_id = (self.with_context(ctx). _default_fiscal_category())
@api.onchange('fiscal_document_id')
[documentos] def onchange_fiscal_document_id(self): if self.fiscal_type == 'product': if self.issuer == '0': series = [doc_serie for doc_serie in self.company_id.document_serie_product_ids if doc_serie.fiscal_document_id.id == self.fiscal_document_id.id and doc_serie.active] if not series: action = self.env.ref( 'l10n_br_account.' 'action_l10n_br_account_document_serie_form') msg = _(u'Você deve ser uma série de documento fiscal' u'para este documento fiscal.') raise RedirectWarning( msg, action.id, _(u'Criar uma nova série')) self.document_serie_id = series[0]
@api.onchange('fiscal_category_id', 'fiscal_position')
[documentos] def onchange_fiscal(self): 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, 'partner_invoice_id': self.partner_id.id, 'fiscal_category_id': self.fiscal_category_id.id, 'context': self.env.context } result = self._fiscal_position_map(result, **kwargs) self.update(result['value'])
@api.multi
[documentos] def action_date_assign(self): for inv in self: if not inv.date_hour_invoice: date_hour_invoice = fields.Datetime.context_timestamp( self, datetime.datetime.now()) else: if inv.issuer == '1': date_move = inv.date_in_out else: date_move = inv.date_hour_invoice date_hour_invoice = fields.Datetime.context_timestamp( self, datetime.datetime.strptime( date_move, tools.DEFAULT_SERVER_DATETIME_FORMAT ) ) date_invoice = date_hour_invoice.strftime( tools.DEFAULT_SERVER_DATE_FORMAT) res = self.onchange_payment_term_date_invoice( inv.payment_term.id, date_invoice) if res and res['value']: res['value'].update({ 'date_invoice': date_invoice }) date_time_now = fields.datetime.now() if not inv.date_hour_invoice: res['value'].update({'date_hour_invoice': date_time_now}) if not inv.date_in_out: res['value'].update({'date_in_out': date_time_now}) inv.write(res['value']) return True
@api.multi
[documentos] def open_fiscal_document(self): """return action to open NFe form""" result = super(AccountInvoice, self).open_fiscal_document() result['name'] = _('NF-e') return result
[documentos]class AccountInvoiceLine(models.Model): _inherit = 'account.invoice.line' @api.one @api.depends('price_unit', 'discount', 'invoice_line_tax_id', 'quantity', 'product_id', 'invoice_id.partner_id', 'freight_value', 'insurance_value', 'other_costs_value', 'invoice_id.currency_id') def _compute_price(self): price = self.price_unit * (1 - (self.discount or 0.0) / 100.0) taxes = self.invoice_line_tax_id.compute_all( price, self.quantity, product=self.product_id, partner=self.invoice_id.partner_id, fiscal_position=self.fiscal_position, insurance_value=self.insurance_value, freight_value=self.freight_value, other_costs_value=self.other_costs_value) self.price_tax_discount = 0.0 self.price_subtotal = 0.0 self.price_gross = 0.0 self.discount_value = 0.0 if self.invoice_id: self.price_tax_discount = self.invoice_id.currency_id.round( taxes['total'] - taxes['total_tax_discount']) self.price_subtotal = self.invoice_id.currency_id.round( taxes['total']) self.price_gross = self.invoice_id.currency_id.round( self.price_unit * self.quantity) self.discount_value = self.invoice_id.currency_id.round( self.price_gross - taxes['total']) code = fields.Char( u'Código do Produto', size=60) date_invoice = fields.Datetime( 'Invoice Date', readonly=True, states={'draft': [('readonly', False)]}, select=True, help="Keep empty to use the current date") fiscal_category_id = fields.Many2one( 'l10n_br_account.fiscal.category', 'Categoria Fiscal') fiscal_position = fields.Many2one( 'account.fiscal.position', u'Posição Fiscal', ) cfop_id = fields.Many2one('l10n_br_account_product.cfop', 'CFOP') fiscal_classification_id = fields.Many2one( 'account.product.fiscal.classification', u'Classificação Fiscal') cest = fields.Char( string="CEST", related='fiscal_classification_id.cest') fci = fields.Char('FCI do Produto', size=36) import_declaration_ids = fields.One2many( 'l10n_br_account_product.import.declaration', 'invoice_line_id', u'Declaração de Importação') product_type = fields.Selection( [('product', 'Produto'), ('service', u'Serviço')], 'Tipo do Produto', required=True, default='product') discount_value = fields.Float( string='Vlr. desconto', store=True, compute='_compute_price', digits=dp.get_precision('Account')) price_gross = fields.Float( string='Vlr. Bruto', store=True, compute='_compute_price', digits=dp.get_precision('Account')) price_tax_discount = fields.Float( string='Vlr. s/ Impostos', store=True, compute='_compute_price', digits=dp.get_precision('Account')) total_taxes = fields.Float( string='Total de Tributos', requeried=True, default=0.00, digits=dp.get_precision('Account')) icms_manual = fields.Boolean('ICMS Manual?', default=False) icms_origin = fields.Selection(PRODUCT_ORIGIN, 'Origem', default='0') icms_base_type = fields.Selection( [('0', 'Margem Valor Agregado (%)'), ('1', 'Pauta (valor)'), ('2', u'Preço Tabelado Máximo (valor)'), ('3', u'Valor da Operação')], 'Tipo Base ICMS', required=True, default='0') icms_base = fields.Float('Base ICMS', required=True, digits=dp.get_precision('Account'), default=0.00) icms_base_other = fields.Float( 'Base ICMS Outras', required=True, digits=dp.get_precision('Account'), default=0.00) icms_value = fields.Float( 'Valor ICMS', required=True, digits=dp.get_precision('Account'), default=0.00) icms_percent = fields.Float( 'Perc ICMS', digits=dp.get_precision('Discount'), default=0.00) icms_percent_reduction = fields.Float( u'Perc Redução de Base ICMS', digits=dp.get_precision('Discount'), default=0.00) icms_st_base_type = fields.Selection( [('0', u'Preço tabelado ou máximo sugerido'), ('1', 'Lista Negativa (valor)'), ('2', 'Lista Positiva (valor)'), ('3', 'Lista Neutra (valor)'), ('4', 'Margem Valor Agregado (%)'), ('5', 'Pauta (valor)')], 'Tipo Base ICMS ST', required=True, default='4') icms_st_value = fields.Float( 'Valor ICMS ST', required=True, digits=dp.get_precision('Account'), default=0.00) icms_st_base = fields.Float( 'Base ICMS ST', required=True, digits=dp.get_precision('Account'), default=0.00) icms_st_percent = fields.Float( 'Percentual ICMS ST', digits=dp.get_precision('Discount'), default=0.00) icms_st_percent_reduction = fields.Float( u'Perc Redução de Base ICMS ST', digits=dp.get_precision('Discount'), default=0.00) icms_st_mva = fields.Float( 'MVA Ajustado ICMS ST', digits=dp.get_precision('Discount'), default=0.00) icms_st_base_other = fields.Float( 'Base ICMS ST Outras', required=True, digits=dp.get_precision('Account'), default=0.00) icms_cst_id = fields.Many2one( 'account.tax.code', 'CST ICMS', domain=[('domain', '=', 'icms')]) icms_relief_id = fields.Many2one( 'l10n_br_account_product.icms_relief', string=u'Desoneração ICMS') issqn_manual = fields.Boolean('ISSQN Manual?', default=False) issqn_type = fields.Selection( [('N', 'Normal'), ('R', 'Retida'), ('S', 'Substituta'), ('I', 'Isenta')], 'Tipo do ISSQN', required=True, default='N') service_type_id = fields.Many2one( 'l10n_br_account.service.type', u'Tipo de Serviço') issqn_base = fields.Float( 'Base ISSQN', required=True, digits=dp.get_precision('Account'), default=0.00) issqn_percent = fields.Float( 'Perc ISSQN', required=True, digits=dp.get_precision('Discount'), default=0.00) issqn_value = fields.Float( 'Valor ISSQN', required=True, digits=dp.get_precision('Account'), default=0.00) ipi_manual = fields.Boolean('IPI Manual?', default=False) ipi_type = fields.Selection( [('percent', 'Percentual'), ('quantity', 'Em Valor')], 'Tipo do IPI', required=True, default='percent') ipi_base = fields.Float( 'Base IPI', required=True, digits=dp.get_precision('Account'), default=0.00) ipi_base_other = fields.Float( 'Base IPI Outras', required=True, digits=dp.get_precision('Account'), default=0.00) ipi_value = fields.Float( 'Valor IPI', required=True, digits=dp.get_precision('Account'), default=0.00) ipi_percent = fields.Float( 'Perc IPI', required=True, digits=dp.get_precision('Discount'), default=0.00) ipi_cst_id = fields.Many2one( 'account.tax.code', 'CST IPI', domain=[('domain', '=', 'ipi')]) ipi_guideline_id = fields.Many2one( 'l10n_br_account_product.ipi_guideline', string=u'Enquadramento Legal IPI') pis_manual = fields.Boolean('PIS Manual?', default=False) pis_type = fields.Selection( [('percent', 'Percentual'), ('quantity', 'Em Valor')], 'Tipo do PIS', required=True, default='percent') pis_base = fields.Float('Base PIS', required=True, digits=dp.get_precision('Account'), default=0.00) pis_base_other = fields.Float( 'Base PIS Outras', required=True, digits=dp.get_precision('Account'), default=0.00) pis_value = fields.Float( 'Valor PIS', required=True, digits=dp.get_precision('Account'), default=0.00) pis_percent = fields.Float( 'Perc PIS', required=True, digits=dp.get_precision('Discount'), default=0.00) pis_cst_id = fields.Many2one( 'account.tax.code', 'CST PIS', domain=[('domain', '=', 'pis')]) pis_st_type = fields.Selection( [('percent', 'Percentual'), ('quantity', 'Em Valor')], 'Tipo do PIS ST', required=True, default='percent') pis_st_base = fields.Float( 'Base PIS ST', required=True, digits=dp.get_precision('Account'), default=0.00) pis_st_percent = fields.Float( 'Perc PIS ST', required=True, digits=dp.get_precision('Account'), default=0.00) pis_st_value = fields.Float( 'Valor PIS ST', required=True, digits=dp.get_precision('Account'), default=0.00) cofins_manual = fields.Boolean('COFINS Manual?', default=False) cofins_type = fields.Selection( [('percent', 'Percentual'), ('quantity', 'Em Valor')], 'Tipo do COFINS', required=True, default='percent') cofins_base = fields.Float( 'Base COFINS', required=True, digits=dp.get_precision('Account'), default=0.00) cofins_base_other = fields.Float( 'Base COFINS Outras', required=True, digits=dp.get_precision('Account'), default=0.00) cofins_value = fields.Float( 'Valor COFINS', required=True, digits=dp.get_precision('Account'), default=0.00) cofins_percent = fields.Float( 'Perc COFINS', required=True, digits=dp.get_precision('Discount'), default=0.00) cofins_cst_id = fields.Many2one( 'account.tax.code', 'CST PIS', domain=[('domain', '=', 'cofins')]) cofins_st_type = fields.Selection( [('percent', 'Percentual'), ('quantity', 'Em Valor')], 'Tipo do COFINS ST', required=True, default='percent') cofins_st_base = fields.Float( 'Base COFINS ST', required=True, digits=dp.get_precision('Account'), default=0.00) cofins_st_percent = fields.Float( 'Perc COFINS ST', required=True, digits=dp.get_precision('Discount'), default=0.00) cofins_st_value = fields.Float( 'Valor COFINS ST', required=True, digits=dp.get_precision('Account'), default=0.00) ii_base = fields.Float( 'Base II', required=True, digits=dp.get_precision('Account'), default=0.00) ii_value = fields.Float( 'Valor II', required=True, digits=dp.get_precision('Account'), default=0.00) ii_iof = fields.Float( 'Valor IOF', required=True, digits=dp.get_precision('Account'), default=0.00) ii_customhouse_charges = fields.Float( 'Despesas Aduaneiras', required=True, digits=dp.get_precision('Account'), default=0.00) insurance_value = fields.Float( 'Valor do Seguro', digits=dp.get_precision('Account'), default=0.00) other_costs_value = fields.Float( 'Outros Custos', digits=dp.get_precision('Account'), default=0.00) freight_value = fields.Float( 'Frete', digits=dp.get_precision('Account'), default=0.00) fiscal_comment = fields.Text(u'Observação Fiscal') icms_dest_base = fields.Float( string=u'Valor da BC do ICMS na UF de destino', digits=dp.get_precision('Account'), default=0.00) icms_fcp_percent = fields.Float( string=u'% Fundo de Combate à Pobreza (FCP)', digits=dp.get_precision('Account'), default=0.00) icms_origin_percent = fields.Float( string=u'Alíquota interna da UF de destino', digits=dp.get_precision('Account'), default=0.00) icms_dest_percent = fields.Float( string=u'Alíquota interestadual das UF envolvidas', digits=dp.get_precision('Account'), default=0.00) icms_part_percent = fields.Float( string=u'Percentual provisório de partilha do ICMS Interestadual', digits=dp.get_precision('Account'), default=0.00) icms_fcp_value = fields.Float( string=(u'Valor do ICMS relativo ao Fundo de Combate à Pobreza (FCP)' u' da UF de destino'), digits=dp.get_precision('Account'), default=0.00) icms_dest_value = fields.Float( string=u'Valor do ICMS Interestadual para a UF de destino', digits=dp.get_precision('Account'), default=0.00) icms_origin_value = fields.Float( string=u'Valor do ICMS Interno para a UF do remetente', digits=dp.get_precision('Account'), default=0.00) partner_order = fields.Char( string=u"Código do Pedido (xPed)", size=15, ) partner_order_line = fields.Char( string=u"Item do Pedido (nItemPed)", size=6, ) @api.onchange("partner_order_line") def _check_partner_order_line(self): if (self.partner_order_line and not self.partner_order_line.isdigit()): raise ValidationError( _(u"Customer Order Line must " "be a number with up to six digits") ) def _amount_tax_icms(self, tax=None): result = { 'icms_base': tax.get('total_base', 0.0), 'icms_base_other': tax.get('total_base_other', 0.0), 'icms_value': tax.get('amount', 0.0), 'icms_percent': tax.get('percent', 0.0) * 100, 'icms_percent_reduction': tax.get('base_reduction') * 100, 'icms_base_type': tax.get('icms_base_type', '0'), } return result def _amount_tax_icmsinter(self, tax=None): result = { 'icms_dest_base': tax.get('total_base', 0.0), 'icms_dest_percent': tax.get('percent', 0.0) * 100, 'icms_origin_percent': tax.get('icms_origin_percent', 0.0) * 100, 'icms_part_percent': tax.get('icms_part_percent', 0.0) * 100, 'icms_dest_value': tax.get('icms_dest_value', 0.0), 'icms_origin_value': tax.get('icms_origin_value', 0.0), } return result def _amount_tax_icmsfcp(self, tax=None): result = { 'icms_fcp_percent': tax.get('percent', 0.0) * 100, 'icms_fcp_value': tax.get('amount', 0.0), } return result def _amount_tax_icmsst(self, tax=None): result = { 'icms_st_value': tax.get('amount', 0.0), 'icms_st_base': tax.get('total_base', 0.0), 'icms_st_percent': tax.get('icms_st_percent', 0.0) * 100, 'icms_st_percent_reduction': tax.get( 'icms_st_percent_reduction', 0.0) * 100, 'icms_st_mva': tax.get('amount_mva', 0.0) * 100, 'icms_st_base_other': tax.get('icms_st_base_other', 0.0), 'icms_st_base_type': tax.get('icms_st_base_type', '4') } return result def _amount_tax_ipi(self, tax=None): result = { 'ipi_type': tax.get('type'), 'ipi_base': tax.get('total_base', 0.0), 'ipi_value': tax.get('amount', 0.0), 'ipi_percent': tax.get('percent', 0.0) * 100, } return result def _amount_tax_cofins(self, tax=None): result = { 'cofins_base': tax.get('total_base', 0.0), 'cofins_base_other': tax.get('total_base_other', 0.0), 'cofins_value': tax.get('amount', 0.0), 'cofins_percent': tax.get('percent', 0.0) * 100, } return result def _amount_tax_cofinsst(self, tax=None): result = { 'cofins_st_type': 'percent', 'cofins_st_base': 0.0, 'cofins_st_percent': 0.0, 'cofins_st_value': 0.0, } return result def _amount_tax_pis(self, tax=None): result = { 'pis_base': tax.get('total_base', 0.0), 'pis_base_other': tax.get('total_base_other', 0.0), 'pis_value': tax.get('amount', 0.0), 'pis_percent': tax.get('percent', 0.0) * 100, } return result def _amount_tax_pisst(self, tax=None): result = { 'pis_st_type': 'percent', 'pis_st_base': 0.0, 'pis_st_percent': 0.0, 'pis_st_value': 0.0, } return result def _amount_tax_ii(self, tax=None): result = { 'ii_base': 0.0, 'ii_value': 0.0, } return result def _amount_tax_issqn(self, tax=None): # TODO deixar dinamico a definição do tipo do ISSQN # assim como todos os impostos issqn_type = 'N' if not tax.get('amount'): issqn_type = 'I' result = { 'issqn_type': issqn_type, 'issqn_base': tax.get('total_base', 0.0), 'issqn_percent': tax.get('percent', 0.0) * 100, 'issqn_value': tax.get('amount', 0.0), } return result @api.multi def _get_tax_codes(self, product_id, fiscal_position, taxes): result = {} ctx = dict(self.env.context) ctx.update({'use_domain': ('use_invoice', '=', True)}) ctx.update({'product_id': product_id}) if fiscal_position.fiscal_category_id.journal_type in ( 'sale', 'sale_refund'): ctx.update({'type_tax_use': 'sale'}) else: ctx.update({'type_tax_use': 'purchase'}) product = self.env['product.product'].browse(product_id) ctx.update({'fiscal_type': product.fiscal_type}) result['cfop_id'] = fiscal_position.cfop_id.id tax_codes = fiscal_position.with_context( ctx).map_tax_code(product_id, taxes) result['icms_cst_id'] = tax_codes.get('icms') result['ipi_cst_id'] = tax_codes.get('ipi') result['pis_cst_id'] = tax_codes.get('pis') result['cofins_cst_id'] = tax_codes.get('cofins') result['icms_relief_id'] = tax_codes.get('icms_relief') result['ipi_guideline_id'] = tax_codes.get('ipi_guideline') return result # TODO @api.multi def _validate_taxes(self, values): """Verifica se o valor dos campos dos impostos estão sincronizados com os impostos do Odoo""" context = self.env.context price_unit = values.get('price_unit', 0.0) or self.price_unit discount = values.get('discount', 0.0) or self.discount insurance_value = values.get( 'insurance_value', 0.0) or self.insurance_value freight_value = values.get( 'freight_value', 0.0) or self.freight_value other_costs_value = values.get( 'other_costs_value', 0.0) or self.other_costs_value tax_ids = [] if values.get('invoice_line_tax_id'): tax_ids = values.get('invoice_line_tax_id', [[6, 0, []]])[ 0][2] or self.invoice_line_tax_id.ids partner_id = values.get('partner_id') or self.partner_id.id product_id = values.get('product_id') or self.product_id.id quantity = values.get('quantity') or self.quantity fiscal_position = values.get( 'fiscal_position') or self.fiscal_position.id if not product_id or not quantity or not fiscal_position: return {} result = { 'code': None, 'product_type': 'product', 'service_type_id': None, 'fiscal_classification_id': None, 'fci': None, } if self: partner = self.invoice_id.partner_id else: partner = self.env['res.partner'].browse(partner_id) taxes = self.env['account.tax'].browse(tax_ids) fiscal_position = self.env['account.fiscal.position'].browse( fiscal_position) price = price_unit * (1 - discount / 100.0) if product_id: product = self.pool.get('product.product').browse( self._cr, self._uid, product_id, context=context) if product.type == 'service': result['product_type'] = 'service' result['service_type_id'] = product.service_type_id.id else: result['product_type'] = 'product' if product.fiscal_classification_id: result['fiscal_classification_id'] = \ product.fiscal_classification_id.id if product.fci: result['fci'] = product.fci result['fiscal_comment'] = u'Res. Senado Fed. ' \ u'nº13/12 FCI: ' + product.fci result['code'] = product.default_code result['icms_origin'] = product.origin taxes_calculed = taxes.compute_all( price, quantity, product=product, partner=partner, fiscal_position=fiscal_position, insurance_value=insurance_value, freight_value=freight_value, other_costs_value=other_costs_value) result['total_taxes'] = taxes_calculed['total_taxes'] for tax in taxes_calculed['taxes']: try: amount_tax = getattr( self, '_amount_tax_%s' % tax.get('domain', '')) result.update(amount_tax(tax)) except AttributeError: # Caso não exista campos especificos dos impostos # no documento fiscal, os mesmos são calculados. continue taxes_dict = self._get_tax_codes(product_id, fiscal_position, taxes) for key in taxes_dict: result[key] = values.get(key) or taxes_dict[key] return result # TODO não foi migrado por causa do bug github.com/odoo/odoo/issues/1711
[documentos] def fields_view_get(self, cr, uid, view_id=None, view_type=False, context=None, toolbar=False, submenu=False): result = super(AccountInvoiceLine, self).fields_view_get( cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=submenu) return result
@api.model def _fiscal_position_map(self, result, **kwargs): ctx = dict(self.env.context) ctx.update({'use_domain': ('use_invoice', '=', True)}) ctx.update({'partner_id': kwargs.get('partner_id')}) ctx.update({'product_id': kwargs.get('product_id')}) account_obj = self.env['account.account'] obj_fp_rule = self.env['account.fiscal.position.rule'] partner = self.env['res.partner'].browse(kwargs.get('partner_id')) product_fiscal_category_id = obj_fp_rule.with_context( ctx).product_fiscal_category_map( kwargs.get('product_id'), kwargs.get('fiscal_category_id'), partner.state_id.id) if product_fiscal_category_id: kwargs['fiscal_category_id'] = product_fiscal_category_id result_rule = obj_fp_rule.with_context(ctx).apply_fiscal_mapping( result, **kwargs) result_rule['value']['fiscal_category_id'] = \ kwargs.get('fiscal_category_id') if result_rule['value'].get('fiscal_position'): fp = self.env['account.fiscal.position'].browse( result_rule['value']['fiscal_position']) if kwargs.get('product_id'): product = self.env['product.product'].browse( kwargs['product_id']) taxes = self.env['account.tax'] ctx['fiscal_type'] = product.fiscal_type if ctx.get('type') in ('out_invoice', 'out_refund'): ctx['type_tax_use'] = 'sale' if product.taxes_id: taxes |= product.taxes_id elif kwargs.get('account_id'): account_id = kwargs['account_id'] taxes |= account_obj.browse(account_id).tax_ids else: ctx['type_tax_use'] = 'purchase' if product.supplier_taxes_id: taxes |= product.supplier_taxes_id elif kwargs.get('account_id'): account_id = kwargs['account_id'] taxes |= account_obj.browse(account_id).tax_ids tax_ids = fp.with_context(ctx).map_tax(taxes) result_rule['value']['invoice_line_tax_id'] = tax_ids.ids result['value'].update(self._get_tax_codes( kwargs['product_id'], fp, tax_ids)) return result_rule @api.multi
[documentos] def product_id_change(self, product, uom_id, qty=0, name='', type='out_invoice', partner_id=False, fposition_id=False, price_unit=False, currency_id=False, company_id=None): ctx = dict(self.env.context) if type in ('out_invoice', 'out_refund'): ctx.update({'type_tax_use': 'sale'}) else: ctx.update({'type_tax_use': 'purchase'}) result = super(AccountInvoiceLine, self).product_id_change( product, uom_id, qty, name, type, partner_id, fposition_id, price_unit, currency_id, company_id) fiscal_category_id = ctx.get('parent_fiscal_category_id') if not fiscal_category_id or not product: return result product_obj = self.env['product.product'].browse(product) result['value']['name'] = product_obj.display_name result = self.with_context(ctx)._fiscal_position_map( result, partner_id=partner_id, partner_invoice_id=partner_id, company_id=company_id, product_id=product, fiscal_category_id=fiscal_category_id, account_id=result['value']['account_id']) return result
@api.onchange('fiscal_category_id', 'fiscal_position', 'invoice_line_tax_id', 'quantity', 'price_unit', 'discount', 'insurance_value', 'freight_value', 'other_costs_value')
[documentos] def onchange_fiscal(self): ctx = dict(self.env.context) if self.invoice_id.type in ('out_invoice', 'out_refund'): ctx.update({'type_tax_use': 'sale'}) else: ctx.update({'type_tax_use': 'purchase'}) partner_id = self.invoice_id.partner_id.id or ctx.get('partner_id') company_id = self.invoice_id.company_id.id or ctx.get('company_id') if company_id and partner_id and self.fiscal_category_id: result = {'value': {}} kwargs = { 'company_id': company_id, 'partner_id': partner_id, 'partner_invoice_id': self.invoice_id.partner_id.id, 'product_id': self.product_id.id, 'fiscal_category_id': self.fiscal_category_id.id, 'context': ctx } result = self.with_context(ctx)._fiscal_position_map( result, **kwargs) kwargs.update({ 'invoice_line_tax_id': [ (6, 0, self.invoice_line_tax_id.ids)], 'quantity': self.quantity, 'price_unit': self.price_unit, 'discount': self.discount, 'fiscal_position': self.fiscal_position.id, 'insurance_value': self.insurance_value, 'freight_value': self.freight_value, 'other_costs_value': self.other_costs_value, }) result['value'].update(self._validate_taxes(kwargs)) self.update(result['value'])
@api.model
[documentos] def tax_exists(self, domain=None): result = False tax = self.env['account.tax'].search(domain, limit=1) if tax: result = tax return result
@api.multi
[documentos] def update_invoice_line_tax_id(self, tax_id, taxes, domain): new_taxes = [(6, 0, [tax_id])] for tax in self.env['account.tax'].browse(taxes[0][2]): if not tax.domain == domain: new_taxes[0][2].append(tax.id) return new_taxes
@api.multi
[documentos] def onchange_tax_icms(self, icms_base_type, icms_base, icms_base_other, icms_value, icms_percent, icms_percent_reduction, icms_cst_id, price_unit, discount, quantity, partner_id, product_id, fiscal_position_id, insurance_value, freight_value, other_costs_value, invoice_line_tax_id): result = {'value': {}} # ctx = dict(self.env.context) # Search if exists the tax # domain = [('domain', '=', 'icms')] # # domain.append(('icms_base_type', '=', icms_base_type)) # # percent_decimal = icms_percent / 100 # domain.append(('amount', '=', percent_decimal)) # # reduction_percent = icms_percent_reduction / 100 # domain.append(('base_reduction', '=', reduction_percent)) # # tax = self.tax_exists(domain) # # # If not exists create a new tax # if not tax: # tax_template = self.env['account.tax'].search([ # ('type_tax_use', '=', DEFAULT_TAX_TYPE[ctx.get( # 'type_tax_use', 'out_invoice')]), # ('domain', '=', 'icms'), # ('amount', '=', '0.0'), # ('company_id', '=', self.env.user.company_id.id), # ]) # # if not tax_template: # raise except_orm(_('Alerta', u'Não existe imposto\ # do domínio ICMS com aliquita 0%!')) # # tax_name = 'ICMS Interno Saída {:.2f}%'.format(icms_percent) # # if icms_percent_reduction: # tax_name = 'ICMS Interno Saída {:.2f}% Red \ # {:.2f}%'.format(icms_percent, # icms_percent_reduction) # # tax_values = { # 'name': tax_name, # 'description': tax_name, # 'type_tax_use': tax_template[0].type_tax_use, # 'company_id': tax_template[0].company_id.id, # 'active': True, # 'type': 'percent', # 'amount': icms_percent / 100, # 'tax_discount': True, # 'base_reduction': icms_percent_reduction / 100, # 'applicable_type': 'true', # 'icms_base_type': icms_base_type, # 'domain': 'icms', # 'account_collected_id': (tax_template[0] # .account_collected_id.id), # 'account_paid_id': tax_template[0].account_paid_id.id, # 'base_code_id': tax_template[0].base_code_id.id, # 'base_sign': 1.0, # 'ref_base_code_id': tax_template[0].ref_base_code_id.id, # 'ref_base_sign': 1.0, # 'tax_code_id': tax_template[0].tax_code_id.id, # 'tax_sign': 1.0, # 'ref_tax_code_id': tax_template[0].ref_tax_code_id.id, # 'ref_tax_sign': 1.0, # } # tax = self.env['account.tax'].create(tax_values) # # # Compute the tax # partner = self.env['res.partner'].browse(partner_id) # product = self.env['product.product'].browse(partner_id) # fiscal_position = self.env['account.fiscal.position'].browse( # fiscal_position_id) # price = price_unit * (1 - discount / 100.0) # tax_compute = tax.compute_all( # price, quantity, product, partner, # fiscal_position=fiscal_position, # insurance_value=insurance_value, # freight_value=freight_value, # other_costs_value=other_costs_value, # base_tax=icms_base) # # # Update tax values to new values # result['value'].update(self._amount_tax_icms( # tax_compute['taxes'][0])) # # # Update invoice_line_tax_id # # Remove all taxes with domain ICMS # result['value']['invoice_line_tax_id'] = (self # .update_invoice_line_tax_id(tax.id, invoice_line_tax_id, # tax.domain)) return result
@api.multi
[documentos] def onchange_tax_icms_st( self, icms_st_base_type, icms_st_base, icms_st_percent, icms_st_percent_reduction, icms_st_mva, icms_st_base_other, price_unit, discount, insurance_value, freight_value, other_costs_value): return {'value': {}}
@api.multi
[documentos] def onchange_tax_ipi(self, ipi_type, ipi_base, ipi_base_other, ipi_value, ipi_percent, ipi_cst_id, price_unit, discount, insurance_value, freight_value, other_costs_value): return {'value': {}}
@api.multi
[documentos] def onchange_tax_pis(self, pis_type, pis_base, pis_base_other, pis_value, pis_percent, pis_cst_id, price_unit, discount, insurance_value, freight_value, other_costs_value): return {'value': {}}
@api.multi
[documentos] def onchange_tax_pis_st( self, pis_st_type, pis_st_base, pis_st_percent, pis_st_value, price_unit, discount, insurance_value, freight_value, other_costs_value): return {'value': {}}
@api.multi
[documentos] def onchange_tax_cofins( self, cofins_st_type, cofins_st_base, cofins_st_percent, cofins_st_value, price_unit, discount, insurance_value, freight_value, other_costs_value): return {'value': {}}
@api.multi
[documentos] def onchange_tax_cofins_st( self, cofins_st_type, cofins_st_base, cofins_st_percent, cofins_st_value, price_unit, discount, insurance_value, freight_value, other_costs_value): return {'value': {}}
@api.model
[documentos] def create(self, vals): vals.update(self._validate_taxes(vals)) return super(AccountInvoiceLine, self).create(vals)
# TODO comentado por causa deste bug # https://github.com/odoo/odoo/issues/2197 # @api.multi # def write(self, vals): # vals.update(self._validate_taxes(vals)) # return super(AccountInvoiceLine, self).write(vals)
[documentos]class AccountInvoiceTax(models.Model): _inherit = 'account.invoice.tax' @api.v8
[documentos] def compute(self, invoice): tax_grouped = {} currency = invoice.currency_id.with_context( date=invoice.date_invoice or fields.Date.context_today(invoice)) company_currency = invoice.company_id.currency_id for line in invoice.invoice_line: taxes = line.invoice_line_tax_id.compute_all( (line.price_unit * (1 - (line.discount or 0.0) / 100.0)), line.quantity, product=line.product_id, partner=invoice.partner_id, fiscal_position=line.fiscal_position, insurance_value=line.insurance_value, freight_value=line.freight_value, other_costs_value=line.other_costs_value)['taxes'] for tax in taxes: val = { 'invoice_id': invoice.id, 'name': tax['name'], 'amount': tax['amount'], 'manual': False, 'sequence': tax['sequence'], 'base': currency.round( tax.get('total_base', tax.get('price_unit', 0.00) * line['quantity'])), } if invoice.type in ('out_invoice', 'in_invoice'): val['base_code_id'] = tax['base_code_id'] val['tax_code_id'] = tax['tax_code_id'] val['base_amount'] = currency.compute( val['base'] * tax['base_sign'], company_currency, round=False) val['tax_amount'] = currency.compute( val['amount'] * tax['tax_sign'], company_currency, round=False) val['account_id'] = tax[ 'account_collected_id'] or line.account_id.id val['account_analytic_id'] = tax[ 'account_analytic_collected_id'] else: val['base_code_id'] = tax['ref_base_code_id'] val['tax_code_id'] = tax['ref_tax_code_id'] val['base_amount'] = currency.compute( val['base'] * tax['ref_base_sign'], company_currency, round=False) val['tax_amount'] = currency.compute( val['amount'] * tax['ref_tax_sign'], company_currency, round=False) val['account_id'] = tax[ 'account_paid_id'] or line.account_id.id val['account_analytic_id'] = tax[ 'account_analytic_paid_id'] # If the taxes generate moves on the same financial account # as the invoice line and no default analytic account is # defined at the tax level, propagate the analytic account # from the invoice line to the tax line. This is necessary # in situations were (part of) the taxes cannot be reclaimed, # to ensure the tax move is allocated to the proper analytic # account. if not val.get('account_analytic_id') and\ line.account_analytic_id and\ val['account_id'] == line.account_id.id: val['account_analytic_id'] = line.account_analytic_id.id key = (val['tax_code_id'], val[ 'base_code_id'], val['account_id']) if key not in tax_grouped: tax_grouped[key] = val else: tax_grouped[key]['base'] += val['base'] tax_grouped[key]['amount'] += val['amount'] tax_grouped[key]['base_amount'] += val['base_amount'] tax_grouped[key]['tax_amount'] += val['tax_amount'] for t in tax_grouped.values(): t['base'] = currency.round(t['base']) t['amount'] = currency.round(t['amount']) t['base_amount'] = currency.round(t['base_amount']) t['tax_amount'] = currency.round(t['tax_amount']) return tax_grouped