Add configurable fiscal invoice defaults
Publicar paquete PyPI / publish (push) Successful in 59s

This commit is contained in:
José Arturo García
2026-09-30 23:34:22 -04:00
parent c7595022c4
commit c7bacddd2d
4 changed files with 179 additions and 43 deletions
+48 -1
View File
@@ -7,6 +7,8 @@ from trytond.model import fields, ModelSQL
from trytond.modules.company.model import CompanyValueMixin
from trytond.pool import PoolMeta, Pool
from trytond.transaction import Transaction
from trytond.modules.ncf_manager.fiscal import (
EXPENSE_TYPE, PAYMENT_METHOD, REVENUE_TYPE)
from trytond.modules.ncf_manager.ncf_manager import NCF_TYPE
@@ -36,10 +38,37 @@ class Configuration(metaclass=PoolMeta):
help="Default supplier NCF type for new parties."
))
default_customer_revenue_type = fields.MultiValue(fields.Selection(
REVENUE_TYPE,
"Default Customer Revenue Type",
sort=False,
help="Default revenue type for new customer invoices."
))
default_supplier_expense_type = fields.MultiValue(fields.Selection(
EXPENSE_TYPE,
"Default Supplier Expense Type",
sort=False,
help="Default expense type for new supplier invoices."
))
default_payment_method = fields.MultiValue(fields.Selection(
PAYMENT_METHOD,
"Default Payment Method",
sort=False,
help="Default payment method for new invoices."
))
@classmethod
def multivalue_model(cls, field):
pool = Pool()
if field in {'default_customer_ncf_type', 'default_supplier_ncf_type'}:
if field in {
'default_customer_ncf_type',
'default_supplier_ncf_type',
'default_customer_revenue_type',
'default_supplier_expense_type',
'default_payment_method',
}:
return pool.get('account.configuration.default_ncf_type')
return super(Configuration, cls).multivalue_model(field)
@@ -60,6 +89,24 @@ class DefaultNcfType(ModelSQL, CompanyValueMixin):
sort=False
)
default_customer_revenue_type = fields.Selection(
REVENUE_TYPE,
"Default Customer Revenue Type",
sort=False
)
default_supplier_expense_type = fields.Selection(
EXPENSE_TYPE,
"Default Supplier Expense Type",
sort=False
)
default_payment_method = fields.Selection(
PAYMENT_METHOD,
"Default Payment Method",
sort=False
)
@classmethod
def __register__(cls, module_name):
"""
+38
View File
@@ -0,0 +1,38 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
REVENUE_TYPE = [
('', ''),
('01', "01 - Ingresos por Operaciones (No Financieros)"),
('02', "02 - Ingresos Financieros"),
('03', "03 - Ingresos Extraordinarios"),
('04', "04 - Ingresos por Arrendamientos"),
('05', "05 - Ingresos por Venta de Activo Depreciable"),
('06', "06 - Otros Ingresos"),
]
EXPENSE_TYPE = [
('', ''),
('01', "01 - Gastos de Personal"),
('02', "02 - Gastos por Trabajos, Suministros y Servicios"),
('03', "03 - Arrendamientos"),
('04', "04 - Gastos de Activos Fijo"),
('05', "05 - Gastos de Representación"),
('06', "06 - Otras Deducciones Admitidas"),
('07', "07 - Gastos Financieros"),
('08', "08 - Gastos Extraordinarios"),
('09', "09 - Compras y Gastos que forman parte del Costo de Venta"),
('10', "10 - Adquisiciones de Activos"),
('11', "11 - Gastos de Seguros"),
]
PAYMENT_METHOD = [
('', ''),
('01', "01 - Efectivo"),
('02', "02 - Cheques/Transferencias/Depósito"),
('03', "03 - Tarjeta Crédito/Débito"),
('04', "04 - Compra a Crédito"),
('05', "05 - Permuta"),
('06', "06 - Nota de Crédito"),
('07', "07 - Mixto"),
]
+83 -41
View File
@@ -15,6 +15,8 @@ from trytond.transaction import Transaction
from trytond.exceptions import UserError
from trytond.i18n import gettext
from trytond.modules.ncf_manager.ncf_manager import NCF_TYPE
from trytond.modules.ncf_manager.fiscal import (
EXPENSE_TYPE, PAYMENT_METHOD, REVENUE_TYPE)
from trytond.modules.currency.fields import Monetary
import logging
logger = logging.getLogger(__name__)
@@ -25,43 +27,6 @@ def _backend_name():
return name() if callable(name) else name
_REVENUE_TYPE = [
('', ''),
('01', "01 - Ingresos por Operaciones (No Financieros)"),
('02', "02 - Ingresos Financieros"),
('03', "03 - Ingresos Extraordinarios"),
('04', "04 - Ingresos por Arrendamientos"),
('05', "05 - Ingresos por Venta de Activo Depreciable"),
('06', "06 - Otros Ingresos"),
]
_EXPENSE_TYPE = [
('', ''),
('01', "01 - Gastos de Personal"),
('02', "02 - Gastos por Trabajos, Suministros y Servicios"),
('03', "03 - Arrendamientos"),
('04', "04 - Gastos de Activos Fijo"),
('05', "05 - Gastos de Representación"),
('06', "06 - Otras Deducciones Admitidas"),
('07', "07 - Gastos Financieros"),
('08', "08 - Gastos Extraordinarios"),
('09', "09 - Compras y Gastos que forman parte del Costo de Venta"),
('10', "10 - Adquisiciones de Activos"),
('11', "11 - Gastos de Seguros"),
]
_PAYMENT_METHOD = [
('', ''),
('01', "01 - Efectivo"),
('02', "02 - Cheques/Transferencias/Depósito"),
('03', "03 - Tarjeta Crédito/Débito"),
('04', "04 - Compra a Crédito"),
('05', "05 - Permuta"),
('06', "06 - Nota de Crédito"),
('07', "07 - Mixto"),
]
_ISR_WITHHOLDING_TYPE = [
('', ''),
('01', "01 - Alquileres"),
@@ -230,7 +195,7 @@ class Invoice(metaclass=PoolMeta):
"Amount Invoiced in Goods", currency='currency', digits='currency'),
'get_amount_invoiced_goods', searcher='search_amount_invoiced_goods')
revenue_type = fields.Selection(_REVENUE_TYPE, 'Revenue Type',
revenue_type = fields.Selection(REVENUE_TYPE, 'Revenue Type',
states={
'readonly': Eval('state').in_(['posted', 'paid', 'cancelled']),
'invisible': Eval('type') == 'in',
@@ -239,7 +204,7 @@ class Invoice(metaclass=PoolMeta):
revenue_type_string = revenue_type.translated('revenue_type')
expense_type = fields.Selection(_EXPENSE_TYPE, 'Expense Type',
expense_type = fields.Selection(EXPENSE_TYPE, 'Expense Type',
states={
'readonly': Eval('state').in_(['posted', 'paid', 'cancelled']),
'invisible': Eval('type') == 'out',
@@ -248,7 +213,7 @@ class Invoice(metaclass=PoolMeta):
expense_type_string = expense_type.translated('expense_type')
payment_method = fields.Selection(_PAYMENT_METHOD, 'Method of Payment',
payment_method = fields.Selection(PAYMENT_METHOD, 'Method of Payment',
states={
'readonly': Eval('state').in_(['posted', 'paid', 'cancelled']),
},
@@ -323,6 +288,32 @@ class Invoice(metaclass=PoolMeta):
},
depends=['state', 'type', 'ncf_number'])
@classmethod
def _ncf_get_configuration_default(cls, field_name, **pattern):
"Return a default value from account configuration."
Configuration = Pool().get('account.configuration')
config = Configuration(1)
return config.get_multivalue(field_name, **pattern) or None
@classmethod
def default_revenue_type(cls, **pattern):
if Transaction().context.get('type') == 'in':
return None
return cls._ncf_get_configuration_default(
'default_customer_revenue_type', **pattern)
@classmethod
def default_expense_type(cls, **pattern):
if Transaction().context.get('type') == 'out':
return None
return cls._ncf_get_configuration_default(
'default_supplier_expense_type', **pattern)
@classmethod
def default_payment_method(cls, **pattern):
return cls._ncf_get_configuration_default(
'default_payment_method', **pattern)
@classmethod
def __setup__(cls):
super().__setup__()
@@ -804,6 +795,39 @@ class Invoice(metaclass=PoolMeta):
else:
self.expiration_date = None
def _ncf_get_configuration_default_invoice_field(self, field_name):
"Return an invoice default configured on account configuration."
Configuration = Pool().get('account.configuration')
config = Configuration(1)
company_id = (
self.company.id if self.company
else Transaction().context.get('company'))
if company_id:
with Transaction().set_context(company=company_id):
return config.get_multivalue(field_name) or None
return config.get_multivalue(field_name) or None
def _ncf_apply_configuration_invoice_defaults(self):
"""
Apply configured fiscal reporting defaults without replacing values
already selected by the user or copied from another invoice.
"""
if self.type == 'out' and not self.revenue_type:
self.revenue_type = (
self._ncf_get_configuration_default_invoice_field(
'default_customer_revenue_type'))
elif self.type == 'in' and not self.expense_type:
self.expense_type = (
self._ncf_get_configuration_default_invoice_field(
'default_supplier_expense_type'))
if not self.payment_method:
self.payment_method = (
self._ncf_get_configuration_default_invoice_field(
'default_payment_method'))
@fields.depends(
'party',
'company',
@@ -811,6 +835,9 @@ class Invoice(metaclass=PoolMeta):
'ncf_type',
'ncf_sequence',
'expiration_date',
'revenue_type',
'expense_type',
'payment_method',
'_parent_party.customer_ncf_type',
'_parent_party.supplier_ncf_type',
)
@@ -827,9 +854,19 @@ class Invoice(metaclass=PoolMeta):
"""
super().on_change_party()
self._ncf_apply_party_default_ncf_type()
self._ncf_apply_configuration_invoice_defaults()
@fields.depends('company', 'type', 'ncf_type', 'ncf_sequence', 'expiration_date')
@fields.depends(
'company',
'type',
'ncf_type',
'ncf_sequence',
'expiration_date',
'revenue_type',
'expense_type',
'payment_method',
)
def on_change_company(self):
if self.ncf_type:
sequence = self._ncf_get_active_sequence()
@@ -841,6 +878,7 @@ class Invoice(metaclass=PoolMeta):
self.ncf_sequence = sequence
if sequence.ncf_sequences:
self.expiration_date = sequence.ncf_sequences.expiration_date
self._ncf_apply_configuration_invoice_defaults()
@fields.depends(
'company',
@@ -854,6 +892,9 @@ class Invoice(metaclass=PoolMeta):
'ncf_type',
'ncf_sequence',
'expiration_date',
'revenue_type',
'expense_type',
'payment_method',
methods=['set_journal', 'on_change_party'],
)
def on_change_type(self):
@@ -870,6 +911,7 @@ class Invoice(metaclass=PoolMeta):
the new invoice type.
"""
super().on_change_type()
self._ncf_apply_configuration_invoice_defaults()
if not self.ncf_sequence:
self.ncf_type = None
+9
View File
@@ -9,5 +9,14 @@ this repository contains the full copyright notices and license terms. -->
<label name="default_supplier_ncf_type"/>
<field name="default_supplier_ncf_type"/>
<newline/>
<separator id="default_fiscal_invoice_fields"
string="Fiscal Invoice Defaults" colspan="4"/>
<label name="default_customer_revenue_type"/>
<field name="default_customer_revenue_type"/>
<label name="default_supplier_expense_type"/>
<field name="default_supplier_expense_type"/>
<label name="default_payment_method"/>
<field name="default_payment_method"/>
<newline/>
</xpath>
</data>