1
0
forked from Mapan/odoo17e
odoo17e-kedaikipas58/addons/l10n_co_edi/models/account_invoice.py
2024-12-10 09:04:09 +07:00

189 lines
9.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, models, fields, _
from odoo.exceptions import UserError
import textwrap
DESCRIPTION_CREDIT_CODE = [
("1", "Devolución parcial de los bienes y/o no aceptación parcial del servicio"),
("2", "Anulación de factura electrónica"),
("3", "Rebaja total aplicada"),
("4", "Ajuste de precio"),
("5", "Descuento comercial por pronto pago"),
("6", "Descuento comercial por volumen de ventas")
]
DESCRIPTION_DEBIT_CODE = [
('1', 'Intereses'),
('2', 'Gastos por cobrar'),
('3', 'Cambio del valor'),
('4', 'Otros'),
]
class AccountMove(models.Model):
_inherit = 'account.move'
l10n_co_edi_type = fields.Selection([
('1', 'Factura de venta'),
('2', 'Factura de exportación'),
('3', 'Documento electrónico de transmisión tipo 03'),
('4', 'Factura electrónica de Venta - tipo 04'),
('91', 'Nota Crédito'),
('92', 'Nota Débito'),
('96', 'Eventos (Application Response)'),
# TODO: remove 'required' in master
], required=True, default='1', compute='_compute_l10n_co_edi_type', store=True, string='Electronic Invoice Type')
l10n_co_edi_attachment_url = fields.Char('Electronic Invoice Attachment URL',
help='''Will be included in electronic invoice and can point to
e.g. a ZIP containing additional information about the invoice.''', copy=False)
l10n_co_edi_operation_type = fields.Selection([('10', 'Estandar'),
('09', 'AIU'),
('11', 'Mandatos'),
('12', 'Transporte'),
('13', 'Cambiario'),
('15', 'Compra Divisas'),
('16', 'Venta Divisas'),
('20', 'Nota Crédito que referencia una factura electrónica'),
('22', 'Nota Crédito sin referencia a facturas'),
('23', 'Nota Crédito para facturación electrónica V1 (Decreto 2242)'),
('30', 'Nota Débito que referencia una factura electrónica'),
('32', 'Nota Débito sin referencia a facturas'),
('23', 'Inactivo: Nota Crédito para facturación electrónica V1 (Decreto 2242)'),
('33', 'Inactivo: Nota Débito para facturación electrónica V1 (Decreto 2242)')],
string="Operation Type (CO)", compute='_compute_operation_type', default="10", required=True)
# field used to track the status of a submission
l10n_co_edi_transaction = fields.Char('Transaction ID (CO)', copy=False)
l10n_co_edi_cufe_cude_ref = fields.Char(string="CUFE/CUDE", copy=False, help='Unique ID received by the government when the invoice is signed.')
l10n_co_edi_payment_option_id = fields.Many2one('l10n_co_edi.payment.option', string="Payment Option",
default=lambda self: self.env.ref('l10n_co_edi.payment_option_1', raise_if_not_found=False))
l10n_co_edi_is_direct_payment = fields.Boolean("Direct Payment from Colombia", compute="_compute_l10n_co_edi_is_direct_payment")
l10n_co_edi_description_code_credit = fields.Selection(DESCRIPTION_CREDIT_CODE, string="Concepto Nota de Credito")
l10n_co_edi_description_code_debit = fields.Selection(DESCRIPTION_DEBIT_CODE, string="Concepto Nota de Débito")
l10n_co_edi_debit_note = fields.Boolean(related="journal_id.l10n_co_edi_debit_note")
l10n_co_edi_is_support_document = fields.Boolean('Support Document', related='journal_id.l10n_co_edi_is_support_document')
# -------------------------------------------------------------------------
# Compute
# -------------------------------------------------------------------------
@api.depends('move_type', 'l10n_co_edi_debit_note')
def _compute_l10n_co_edi_type(self):
CO_moves = self.filtered(lambda move: move.company_id.account_fiscal_country_id.code == 'CO')
for move in CO_moves:
if move.move_type == 'out_refund':
move.l10n_co_edi_type = '91'
elif move.l10n_co_edi_debit_note:
move.l10n_co_edi_type = '92'
elif not move.l10n_co_edi_type:
move.l10n_co_edi_type = '1'
@api.depends('move_type', 'reversed_entry_id', 'edi_document_ids.state', 'l10n_co_edi_cufe_cude_ref')
def _compute_operation_type(self):
for rec in self:
operation_type = False
if rec.move_type == 'out_refund':
if rec.reversed_entry_id:
operation_type = '20'
else:
operation_type = '22'
else:
if rec.l10n_co_edi_debit_note:
state = rec._get_edi_document(self.env.ref('l10n_co_edi.edi_carvajal')).state
if state == 'sent' and not rec.l10n_co_edi_cufe_cude_ref:
operation_type = '23'
elif rec.debit_origin_id:
operation_type = '30'
else:
operation_type = '32'
rec.l10n_co_edi_operation_type = operation_type or '10'
@api.depends('invoice_date_due', 'date')
def _compute_l10n_co_edi_is_direct_payment(self):
for rec in self:
rec.l10n_co_edi_is_direct_payment = (rec.date == rec.invoice_date_due) and rec.company_id.account_fiscal_country_id.code == 'CO'
# -------------------------------------------------------------------------
# Helpers
# -------------------------------------------------------------------------
def _l10n_co_edi_get_electronic_invoice_type(self):
if self.move_type == 'out_invoice':
return 'ND' if self.l10n_co_edi_debit_note else 'INVOIC'
elif self.move_type == 'in_invoice':
return 'INVOIC'
return 'NC'
def _l10n_co_edi_get_electronic_invoice_type_info(self):
if self.move_type == 'out_invoice':
return 'DIAN 2.1: Nota Débito de Factura Electrónica de Venta' if self.l10n_co_edi_debit_note else 'DIAN 2.1: Factura Electrónica de Venta'
elif self.move_type == 'in_invoice':
return 'DIAN 2.1: documento soporte en adquisiciones efectuadas a no obligados a facturar.'
elif self.move_type == 'in_refund':
return 'DIAN 2.1: Nota de ajuste al documento soporte en adquisiciones efectuadas a sujetos no obligados a expedir factura o documento equivalente'
return 'DIAN 2.1: Nota Crédito de Factura Electrónica de Venta'
# -------------------------------------------------------------------------
# Account_edi OVERRIDE
# -------------------------------------------------------------------------
def _retry_edi_documents_error_hook(self):
# OVERRIDE
# For CO, remove the l10n_co_edi_transaction to force re-send (otherwise this only triggers a check_status)
carvajal = self.env.ref('l10n_co_edi.edi_carvajal')
self.filtered(lambda m: m._get_edi_document(carvajal).blocking_level == 'error').l10n_co_edi_transaction = None
def button_draft(self):
# OVERRIDE
for move in self:
if move.l10n_co_edi_transaction:
raise UserError(_(
"You can't edit the following journal entry %s because an electronic document has already been "
"sent to Carvajal. To edit this entry, you need to create a Credit Note for the invoice and "
"create a new invoice.",
move.display_name))
return super().button_draft()
class AccountMoveLine(models.Model):
_inherit = 'account.move.line'
def _l10n_co_edi_get_product_code(self):
"""
For identifying products, different standards can be used. If there is a barcode, we take that one, because
normally in the GTIN standard it will be the most specific one. Otherwise, we will check the
:return: (standard, product_code)
"""
self.ensure_one()
if self.product_id:
if self.move_id.l10n_co_edi_type == '2':
if not self.product_id.l10n_co_edi_customs_code:
raise UserError(_('Exportation invoices require custom code in all the products, please fill in this information before validating the invoice'))
return (self.product_id.l10n_co_edi_customs_code, '020', 'Partida Alanceraria')
if self.product_id.barcode:
return (self.product_id.barcode, '010', 'GTIN')
elif self.product_id.unspsc_code_id:
return (self.product_id.unspsc_code_id.code, '001', 'UNSPSC')
elif self.product_id.default_code:
return (self.product_id.default_code, '999', 'Estándar de adopción del contribuyente')
return ('1010101', '001', '')
def _l10n_co_edi_get_iae3_value(self, product_code):
value = {
'010': '9',
'001': '10',
}
return value.get(product_code, '')
def _l10n_co_edi_get_line_name(self):
"""
Ensure the text we use for electronic communications follows
Carvajal specifications
"""
self.ensure_one()
return textwrap.shorten(self.name or '', 300)