Add configurable fiscal invoice defaults
Publicar paquete PyPI / publish (push) Successful in 1m18s

This commit is contained in:
José Arturo García
2026-09-30 23:34:18 -04:00
parent 3b5d900221
commit 9acb5142b9
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.modules.company.model import CompanyValueMixin
from trytond.pool import PoolMeta, Pool from trytond.pool import PoolMeta, Pool
from trytond.transaction import Transaction 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 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." 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 @classmethod
def multivalue_model(cls, field): def multivalue_model(cls, field):
pool = Pool() 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 pool.get('account.configuration.default_ncf_type')
return super(Configuration, cls).multivalue_model(field) return super(Configuration, cls).multivalue_model(field)
@@ -60,6 +89,24 @@ class DefaultNcfType(ModelSQL, CompanyValueMixin):
sort=False 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 @classmethod
def __register__(cls, module_name): 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.exceptions import UserError
from trytond.i18n import gettext from trytond.i18n import gettext
from trytond.modules.ncf_manager.ncf_manager import NCF_TYPE 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 from trytond.modules.currency.fields import Monetary
import logging import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -25,43 +27,6 @@ def _backend_name():
return name() if callable(name) else 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 = [ _ISR_WITHHOLDING_TYPE = [
('', ''), ('', ''),
('01', "01 - Alquileres"), ('01', "01 - Alquileres"),
@@ -230,7 +195,7 @@ class Invoice(metaclass=PoolMeta):
"Amount Invoiced in Goods", currency='currency', digits='currency'), "Amount Invoiced in Goods", currency='currency', digits='currency'),
'get_amount_invoiced_goods', searcher='search_amount_invoiced_goods') '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={ states={
'readonly': Eval('state').in_(['posted', 'paid', 'cancelled']), 'readonly': Eval('state').in_(['posted', 'paid', 'cancelled']),
'invisible': Eval('type') == 'in', 'invisible': Eval('type') == 'in',
@@ -239,7 +204,7 @@ class Invoice(metaclass=PoolMeta):
revenue_type_string = revenue_type.translated('revenue_type') 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={ states={
'readonly': Eval('state').in_(['posted', 'paid', 'cancelled']), 'readonly': Eval('state').in_(['posted', 'paid', 'cancelled']),
'invisible': Eval('type') == 'out', 'invisible': Eval('type') == 'out',
@@ -248,7 +213,7 @@ class Invoice(metaclass=PoolMeta):
expense_type_string = expense_type.translated('expense_type') 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={ states={
'readonly': Eval('state').in_(['posted', 'paid', 'cancelled']), 'readonly': Eval('state').in_(['posted', 'paid', 'cancelled']),
}, },
@@ -323,6 +288,32 @@ class Invoice(metaclass=PoolMeta):
}, },
depends=['state', 'type', 'ncf_number']) 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 @classmethod
def __setup__(cls): def __setup__(cls):
super().__setup__() super().__setup__()
@@ -804,6 +795,39 @@ class Invoice(metaclass=PoolMeta):
else: else:
self.expiration_date = None 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( @fields.depends(
'party', 'party',
'company', 'company',
@@ -811,6 +835,9 @@ class Invoice(metaclass=PoolMeta):
'ncf_type', 'ncf_type',
'ncf_sequence', 'ncf_sequence',
'expiration_date', 'expiration_date',
'revenue_type',
'expense_type',
'payment_method',
'_parent_party.customer_ncf_type', '_parent_party.customer_ncf_type',
'_parent_party.supplier_ncf_type', '_parent_party.supplier_ncf_type',
) )
@@ -827,9 +854,19 @@ class Invoice(metaclass=PoolMeta):
""" """
super().on_change_party() super().on_change_party()
self._ncf_apply_party_default_ncf_type() 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): def on_change_company(self):
if self.ncf_type: if self.ncf_type:
sequence = self._ncf_get_active_sequence() sequence = self._ncf_get_active_sequence()
@@ -841,6 +878,7 @@ class Invoice(metaclass=PoolMeta):
self.ncf_sequence = sequence self.ncf_sequence = sequence
if sequence.ncf_sequences: if sequence.ncf_sequences:
self.expiration_date = sequence.ncf_sequences.expiration_date self.expiration_date = sequence.ncf_sequences.expiration_date
self._ncf_apply_configuration_invoice_defaults()
@fields.depends( @fields.depends(
'company', 'company',
@@ -854,6 +892,9 @@ class Invoice(metaclass=PoolMeta):
'ncf_type', 'ncf_type',
'ncf_sequence', 'ncf_sequence',
'expiration_date', 'expiration_date',
'revenue_type',
'expense_type',
'payment_method',
methods=['set_journal', 'on_change_party'], methods=['set_journal', 'on_change_party'],
) )
def on_change_type(self): def on_change_type(self):
@@ -870,6 +911,7 @@ class Invoice(metaclass=PoolMeta):
the new invoice type. the new invoice type.
""" """
super().on_change_type() super().on_change_type()
self._ncf_apply_configuration_invoice_defaults()
if not self.ncf_sequence: if not self.ncf_sequence:
self.ncf_type = None self.ncf_type = None
+10 -1
View File
@@ -9,5 +9,14 @@ this repository contains the full copyright notices and license terms. -->
<label name="default_supplier_ncf_type"/> <label name="default_supplier_ncf_type"/>
<field name="default_supplier_ncf_type"/> <field name="default_supplier_ncf_type"/>
<newline/> <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> </xpath>
</data> </data>