diff --git a/l10n_do_accounting/__manifest__.py b/l10n_do_accounting/__manifest__.py
index e8698541c..f46343b22 100644
--- a/l10n_do_accounting/__manifest__.py
+++ b/l10n_do_accounting/__manifest__.py
@@ -9,6 +9,7 @@
"license": "LGPL-3",
"website": "https://github.com/odoo-dominicana",
"version": "17.0.1.0.0",
+ "countries": ["do"],
# any module necessary for this one to work correctly
"depends": ["l10n_latam_invoice_document", "l10n_do"],
# always loaded
diff --git a/l10n_do_accounting/data/l10n_latam.document.type.csv b/l10n_do_accounting/data/l10n_latam.document.type.csv
index 87d0794b4..6863f5695 100644
--- a/l10n_do_accounting/data/l10n_latam.document.type.csv
+++ b/l10n_do_accounting/data/l10n_latam.document.type.csv
@@ -1,23 +1,23 @@
-id,sequence,code,name,report_name,internal_type,l10n_do_ncf_type,doc_code_prefix,country_id/id,is_vat_required,active
-ncf_fiscal_client,10,B,Crédito Fiscal,Factura de Crédito Fiscal,invoice,01,B01,base.do,True,TRUE
-ncf_consumer_supplier,30,B,Consumo,Factura de Consumo,invoice,02,B02,base.do,False,TRUE
-ncf_debit_note_client,40,B,Nota de Débito,Nota de Débito,debit_note,03,B03,base.do,True,TRUE
-ncf_credit_note_client,60,B,Nota de Crédito,Nota de Crédito,credit_note,04,B04,base.do,False,TRUE
-ncf_informal_supplier,80,B,Comprobante de Compra,Factura de Compra,invoice,11,B11,base.do,True,TRUE
-ncf_unique_client,90,B,Único Ingreso,Factura de Único Ingreso,invoice,12,B12,base.do,False,TRUE
-ncf_minor_supplier,100,B,Gasto Menor,Gasto Menor,invoice,13,B13,base.do,False,TRUE
-ncf_special_client,110,B,Régimen Especial,Factura de Régimen Especial,invoice,14,B14,base.do,True,TRUE
-ncf_gov_client,120,B,Factura Gubernamental,Factura Gubernamental,invoice,15,B15,base.do,True,TRUE
-ncf_export_client,130,B,Exportación,Factura de Exportación,invoice,16,B16,base.do,True,TRUE
-ncf_exterior_supplier,140,B,Pago al Exterior,Factura de Pago al Exterior,invoice,17,B17,base.do,False,TRUE
-non_fiscal_import_supplier,150,N,Importación,Factura de Importación,invoice,,IMP,base.do,False,FALSE
-ecf_fiscal_client,160,E,Crédito Fiscal Electrónica,Factura de Crédito Fiscal Electrónica,invoice,31,E31,base.do,True,TRUE
-ecf_consumer_supplier,170,E,Consumo Electrónica,Factura de Consumo Electrónica,invoice,32,E32,base.do,False,TRUE
-ecf_debit_note_client,180,E,Nota de Débito Electrónica,Nota de Débito Electrónica,debit_note,33,E33,base.do,True,TRUE
-ecf_credit_note_client,190,E,Nota de Crédito Electrónica,Nota de Crédito Electrónica,credit_note,34,E34,base.do,True,TRUE
-ecf_informal_supplier,200,E,Compras Electrónica,Factura de Compra Electrónica,invoice,41,E41,base.do,True,TRUE
-ecf_minor_supplier,220,E,Gasto Menor Electrónica,Factura Gasto Menor Electrónica,invoice,43,E43,base.do,False,TRUE
-ecf_special_client,230,E,Régimen Especial Electrónica,Factura de Régimen Especial Electrónica,invoice,44,E44,base.do,True,TRUE
-ecf_gov_client,240,E,Factura Gubernamental Electrónica,Factura Gubernamental Electrónica,invoice,45,E45,base.do,True,TRUE
-ecf_export_client,250,E,Exportación Electrónica,Factura de Exportación Electrónica,invoice,46,E46,base.do,True,TRUE
-ecf_exterior_supplier,260,E,Pago al Exterior Electrónica,Factura de Pago al Exterior Electrónica,invoice,47,E47,base.do,False,TRUE
+id,sequence,code,name@es,name,report_name,internal_type,l10n_do_ncf_type,doc_code_prefix,country_id/id,is_vat_required,active
+ncf_fiscal_client,10,B,Crédito Fiscal,Fiscal Credit,Factura de Crédito Fiscal,invoice,1,B01,base.do,TRUE,TRUE
+ncf_consumer_supplier,30,B,Consumo,Consumer,Factura de Consumo,invoice,2,B02,base.do,FALSE,TRUE
+ncf_debit_note_client,40,B,Nota de Débito,Debit Note,Nota de Débito,debit_note,3,B03,base.do,TRUE,TRUE
+ncf_credit_note_client,60,B,Nota de Crédito,Credit Note,Nota de Crédito,credit_note,4,B04,base.do,FALSE,TRUE
+ncf_informal_supplier,80,B,Comprobante de Compra,Purchase receipt,Factura de Compra,invoice,11,B11,base.do,TRUE,TRUE
+ncf_unique_client,90,B,Único Ingreso,Single Income,Factura de Único Ingreso,invoice,12,B12,base.do,FALSE,TRUE
+ncf_minor_supplier,100,B,Gasto Menor,Minor Expense,Gasto Menor,invoice,13,B13,base.do,FALSE,TRUE
+ncf_special_client,110,B,Régimen Especial,Special Regime,Factura de Régimen Especial,invoice,14,B14,base.do,TRUE,TRUE
+ncf_gov_client,120,B,Factura Gubernamental,Government Invoice,Factura Gubernamental,invoice,15,B15,base.do,TRUE,TRUE
+ncf_export_client,130,B,Exportación,Export,Factura de Exportación,invoice,16,B16,base.do,TRUE,TRUE
+ncf_exterior_supplier,140,B,Pago al Exterior,Foreign Payment,Factura de Pago al Exterior,invoice,17,B17,base.do,FALSE,TRUE
+non_fiscal_import_supplier,150,N,Importación,Import,Factura de Importación,invoice,,IMP,base.do,FALSE,FALSE
+ecf_fiscal_client,160,E,Crédito Fiscal Electrónica,Electronic Fiscal Credit,Factura de Crédito Fiscal Electrónica,invoice,31,E31,base.do,TRUE,TRUE
+ecf_consumer_supplier,170,E,Consumo Electrónica,Electronic Consumer,Factura de Consumo Electrónica,invoice,32,E32,base.do,FALSE,TRUE
+ecf_debit_note_client,180,E,Nota de Débito Electrónica,Electronic Debit Note,Nota de Débito Electrónica,debit_note,33,E33,base.do,TRUE,TRUE
+ecf_credit_note_client,190,E,Nota de Crédito Electrónica,Electronic Credit Note,Nota de Crédito Electrónica,credit_note,34,E34,base.do,TRUE,TRUE
+ecf_informal_supplier,200,E,Compras Electrónica,Electronic Purchase,Factura de Compra Electrónica,invoice,41,E41,base.do,TRUE,TRUE
+ecf_minor_supplier,220,E,Gasto Menor Electrónica,Electronic Minor Expense,Factura Gasto Menor Electrónica,invoice,43,E43,base.do,FALSE,TRUE
+ecf_special_client,230,E,Régimen Especial Electrónica,Electronic Special Regime,Factura de Régimen Especial Electrónica,invoice,44,E44,base.do,TRUE,TRUE
+ecf_gov_client,240,E,Factura Gubernamental Electrónica,Electronic Government Invoice,Factura Gubernamental Electrónica,invoice,45,E45,base.do,TRUE,TRUE
+ecf_export_client,250,E,Exportación Electrónica,Electronic Export,Factura de Exportación Electrónica,invoice,46,E46,base.do,TRUE,TRUE
+ecf_exterior_supplier,260,E,Pago al Exterior Electrónica,Electronic Foreign Payment,Factura de Pago al Exterior Electrónica,invoice,47,E47,base.do,FALSE,TRUE
\ No newline at end of file
diff --git a/l10n_do_accounting/models/account_journal.py b/l10n_do_accounting/models/account_journal.py
index 567f85cab..7810c9171 100644
--- a/l10n_do_accounting/models/account_journal.py
+++ b/l10n_do_accounting/models/account_journal.py
@@ -199,7 +199,7 @@ def create(self, vals_list):
def write(self, values):
to_check = {"type", "l10n_latam_use_documents"}
- res = super().write(values)
+ res = super(AccountJournal, self).write(values)
if to_check.intersection(set(values.keys())):
for rec in self:
rec._l10n_do_create_document_types()
diff --git a/l10n_do_accounting/models/account_move.py b/l10n_do_accounting/models/account_move.py
index 2c70da5d2..83b5efbc6 100644
--- a/l10n_do_accounting/models/account_move.py
+++ b/l10n_do_accounting/models/account_move.py
@@ -1,10 +1,10 @@
import re
-from psycopg2 import sql
from werkzeug import urls
from odoo import models, fields, api, _
from odoo.osv import expression
from odoo.exceptions import ValidationError, UserError, AccessError
+from odoo.tools.sql import column_exists, create_column, drop_index, index_exists
class AccountMove(models.Model):
@@ -124,36 +124,79 @@ def _get_l10n_do_income_type(self):
"manually because a new expiration date was set on journal",
)
- def init(self):
- super(AccountMove, self).init()
-
- if not self._abstract and self._sequence_index:
- index_name = self._table + "_l10n_do_sequence_index"
+ _sql_constraints = [
+ (
+ "unique_l10n_do_fiscal_number_sales",
+ "",
+ "Another document with the same fiscal number already exists.",
+ ),
+ (
+ "unique_l10n_do_fiscal_number_purchase_manual",
+ "",
+ "Another document for the same partner with the same fiscal number already exists.",
+ ),
+ (
+ "unique_l10n_do_fiscal_number_purchase_internal",
+ "",
+ "Another document for the same partner with the same fiscal number already exists.",
+ ),
+ ]
+
+ # def init(self):
+ # super(AccountMove, self).init()
+ #
+ # if not self._abstract and self._sequence_index:
+ # index_name = self._table + "_l10n_do_sequence_index"
+ # self.env.cr.execute(
+ # "SELECT indexname FROM pg_indexes WHERE indexname = %s", (index_name,)
+ # )
+ # if not self.env.cr.fetchone():
+ # self.env.cr.execute(
+ # sql.SQL(
+ # """
+ # CREATE INDEX {index_name} ON {table}
+ # ({sequence_index},
+ # l10n_do_sequence_prefix desc,
+ # l10n_do_sequence_number desc,
+ # {field});
+ # CREATE INDEX {index2_name} ON {table}
+ # ({sequence_index},
+ # id desc,
+ # l10n_do_sequence_prefix);
+ # """
+ # ).format(
+ # sequence_index=sql.Identifier(self._sequence_index),
+ # index_name=sql.Identifier(index_name),
+ # index2_name=sql.Identifier(index_name + "2"),
+ # table=sql.Identifier(self._table),
+ # field=sql.Identifier(self._l10n_do_sequence_field),
+ # )
+ # )
+
+ def _auto_init(self):
+ if not index_exists(self.env.cr, "account_move_unique_l10n_do_fiscal_number_sales"):
+ drop_index(self.env.cr, "unique_l10n_do_fiscal_number_purchase_manual", self._table)
+ drop_index(self.env.cr, "unique_l10n_do_fiscal_number_purchase_internal", self._table)
self.env.cr.execute(
- "SELECT indexname FROM pg_indexes WHERE indexname = %s", (index_name,)
+ """
+ CREATE UNIQUE INDEX account_move_unique_l10n_do_fiscal_number_sales
+ ON account_move(l10n_do_fiscal_number, company_id)
+ WHERE (state = 'posted'
+ AND (l10n_latam_document_type_id IS NOT NULL
+ AND move_type NOT IN ('in_invoice', 'in_refund', 'in_receipt')));
+ CREATE UNIQUE INDEX unique_l10n_do_fiscal_number_purchase_manual
+ ON account_move(l10n_do_fiscal_number, commercial_partner_id, company_id)
+ WHERE (state = 'posted'
+ AND (l10n_latam_document_type_id IS NOT NULL AND move_type IN ('in_invoice', 'in_refund', 'in_receipt')
+ AND l10n_latam_manual_document_number = 't'));
+ CREATE UNIQUE INDEX unique_l10n_do_fiscal_number_purchase_internal
+ ON account_move(l10n_do_fiscal_number, company_id)
+ WHERE (state = 'posted'
+ AND (l10n_latam_document_type_id IS NOT NULL AND move_type IN ('in_invoice', 'in_refund', 'in_receipt')
+ AND l10n_latam_manual_document_number = 'f'));
+ """
)
- if not self.env.cr.fetchone():
- self.env.cr.execute(
- sql.SQL(
- """
- CREATE INDEX {index_name} ON {table}
- ({sequence_index},
- l10n_do_sequence_prefix desc,
- l10n_do_sequence_number desc,
- {field});
- CREATE INDEX {index2_name} ON {table}
- ({sequence_index},
- id desc,
- l10n_do_sequence_prefix);
- """
- ).format(
- sequence_index=sql.Identifier(self._sequence_index),
- index_name=sql.Identifier(index_name),
- index2_name=sql.Identifier(index_name + "2"),
- table=sql.Identifier(self._table),
- field=sql.Identifier(self._l10n_do_sequence_field),
- )
- )
+ return super()._auto_init()
@api.model
def _name_search(
@@ -204,7 +247,9 @@ def _compute_l10n_do_show_expiration_date_msg(self):
and not inv.l10n_latam_manual_document_number
)
for invoice in l10n_do_internal_invoices:
- invoice.l10n_do_show_expiration_date_msg = invoice._l10n_do_is_new_expiration_date()
+ invoice.l10n_do_show_expiration_date_msg = (
+ invoice._l10n_do_is_new_expiration_date()
+ )
(self - l10n_do_internal_invoices).l10n_do_show_expiration_date_msg = False
@@ -226,21 +271,24 @@ def _compute_l10n_do_enable_first_sequence(self):
and not inv.l10n_latam_manual_document_number
)
for invoice in l10n_do_internal_invoices:
- invoice.l10n_do_enable_first_sequence = not bool(
- self.search_count(
- [
- ("company_id", "=", invoice.company_id.id),
- ("move_type", "=", invoice.move_type),
- (
- "l10n_latam_document_type_id",
- "=",
- invoice.l10n_latam_document_type_id.id,
- ),
- ("posted_before", "=", True),
- ("id", "!=", invoice.id or invoice._origin.id),
- ],
+ invoice.l10n_do_enable_first_sequence = (
+ not bool(
+ self.search_count(
+ [
+ ("company_id", "=", invoice.company_id.id),
+ ("move_type", "=", invoice.move_type),
+ (
+ "l10n_latam_document_type_id",
+ "=",
+ invoice.l10n_latam_document_type_id.id,
+ ),
+ ("posted_before", "=", True),
+ ("id", "!=", invoice.id or invoice._origin.id),
+ ],
+ )
)
- ) or invoice.l10n_do_show_expiration_date_msg
+ or invoice.l10n_do_show_expiration_date_msg
+ )
(self - l10n_do_internal_invoices).l10n_do_enable_first_sequence = False
@@ -350,39 +398,39 @@ def _compute_l10n_do_electronic_stamp(self):
(self - l10n_do_ecf_invoice).l10n_do_electronic_stamp = False
- @api.constrains("name", "journal_id", "state", "l10n_do_fiscal_number")
- def _check_unique_sequence_number(self):
- l10n_do_invoices = self.filtered(
- lambda inv: inv.l10n_latam_use_documents
- and inv.country_code == "DO"
- and inv.is_sale_document()
- and inv.state == "posted"
- )
- if l10n_do_invoices:
- self.flush_model(
- ["name", "journal_id", "move_type", "state", "l10n_do_fiscal_number"]
- )
- self._cr.execute(
- """
- SELECT move2.id, move2.l10n_do_fiscal_number
- FROM account_move move
- INNER JOIN account_move move2 ON
- move2.l10n_do_fiscal_number = move.l10n_do_fiscal_number
- AND move2.journal_id = move.journal_id
- AND move2.move_type = move.move_type
- AND move2.id != move.id
- WHERE move.id IN %s AND move2.state = 'posted'
- """,
- [tuple(l10n_do_invoices.ids)],
- )
- res = self._cr.fetchone()
- if res:
- raise ValidationError(
- _("There is already a sale invoice with fiscal number %s")
- % self.l10n_do_fiscal_number
- )
-
- super(AccountMove, (self - l10n_do_invoices))._check_unique_sequence_number()
+ # @api.constrains("name", "journal_id", "state", "l10n_do_fiscal_number")
+ # def _check_unique_sequence_number(self):
+ # l10n_do_invoices = self.filtered(
+ # lambda inv: inv.l10n_latam_use_documents
+ # and inv.country_code == "DO"
+ # and inv.is_sale_document()
+ # and inv.state == "posted"
+ # )
+ # if l10n_do_invoices:
+ # self.flush_model(
+ # ["name", "journal_id", "move_type", "state", "l10n_do_fiscal_number"]
+ # )
+ # self._cr.execute(
+ # """
+ # SELECT move2.id, move2.l10n_do_fiscal_number
+ # FROM account_move move
+ # INNER JOIN account_move move2 ON
+ # move2.l10n_do_fiscal_number = move.l10n_do_fiscal_number
+ # AND move2.journal_id = move.journal_id
+ # AND move2.move_type = move.move_type
+ # AND move2.id != move.id
+ # WHERE move.id IN %s AND move2.state = 'posted'
+ # """,
+ # [tuple(l10n_do_invoices.ids)],
+ # )
+ # res = self._cr.fetchone()
+ # if res:
+ # raise ValidationError(
+ # _("There is already a sale invoice with fiscal number %s")
+ # % self.l10n_do_fiscal_number
+ # )
+ #
+ # super(AccountMove, (self - l10n_do_invoices))._check_unique_sequence_number()
@api.constrains(
"l10n_do_fiscal_number", "partner_id", "company_id", "posted_before"
diff --git a/l10n_do_accounting/models/account_move_line.py b/l10n_do_accounting/models/account_move_line.py
index a297cd664..84fa173ab 100644
--- a/l10n_do_accounting/models/account_move_line.py
+++ b/l10n_do_accounting/models/account_move_line.py
@@ -14,7 +14,7 @@ class AccountMoveLine(models.Model):
@api.depends("quantity", "discount", "price_unit", "tax_ids", "currency_id")
def _compute_totals(self):
- super()._compute_totals()
+ super(AccountMoveLine, self)._compute_totals()
for line in self:
if line.display_type != "product":
line.l10n_do_itbis_amount = False
diff --git a/l10n_do_accounting/models/monkey_patch.py b/l10n_do_accounting/models/monkey_patch.py
index 6038d33b1..057787432 100644
--- a/l10n_do_accounting/models/monkey_patch.py
+++ b/l10n_do_accounting/models/monkey_patch.py
@@ -1,96 +1,15 @@
-from collections import defaultdict
from odoo import models, api
-from odoo.exceptions import ValidationError
class AccountMove(models.Model):
_inherit = "account.move"
- @api.depends("posted_before", "state", "journal_id", "date")
+ @api.depends(
+ "posted_before", "state", "journal_id", "date", "move_type", "payment_id"
+ )
def _compute_name(self):
- def journal_key(move):
- return (move.journal_id, move.journal_id.refund_sequence and move.move_type)
- def date_key(move):
- return (move.date.year, move.date.month)
-
- grouped = defaultdict( # key: journal_id, move_type
- lambda: defaultdict( # key: first adjacent (date.year, date.month)
- lambda: {
- "records": self.env["account.move"],
- "format": False,
- "format_values": False,
- "reset": False,
- }
- )
- )
- self = self.sorted(lambda m: (m.date, m.ref or "", m.id))
- highest_name = self[0]._get_last_sequence(lock=False) if self else False
-
- # Group the moves by journal and month
- for move in self:
- if (
- not highest_name
- and move == self[0]
- and not move.posted_before
- and move.date
- ):
- # In the form view, we need to compute a default sequence so that the user can edit
- # it. We only check the first move as an approximation (enough for new in form view)
- pass
- elif (move.name and move.name != "/") or move.state != "posted":
- try:
- if not move.posted_before:
- move._constrains_date_sequence()
- # Has already a name or is not posted, we don't add to a batch
- continue
- except ValidationError:
- # Has never been posted and the name doesn't match the date: recompute it
- pass
- group = grouped[journal_key(move)][date_key(move)]
- if not group["records"]:
- # Compute all the values needed to sequence this whole group
- move._set_next_sequence()
- (
- group["format"],
- group["format_values"],
- ) = move._get_sequence_format_param(move.name)
- group["reset"] = move._deduce_sequence_number_reset(move.name)
- group["records"] += move
-
- # Fusion the groups depending on the sequence reset and the format used because `seq` is
- # the same counter for multiple groups that might be spread in multiple months.
- final_batches = []
- for journal_group in grouped.values():
- journal_group_changed = True
- for date_group in journal_group.values():
- if (
- journal_group_changed
- or final_batches[-1]["format"] != date_group["format"]
- or dict(final_batches[-1]["format_values"], seq=0)
- != dict(date_group["format_values"], seq=0)
- ):
- final_batches += [date_group]
- journal_group_changed = False
- elif date_group["reset"] == "never":
- final_batches[-1]["records"] += date_group["records"]
- elif (
- date_group["reset"] == "year"
- and final_batches[-1]["records"][0].date.year
- == date_group["records"][0].date.year
- ):
- final_batches[-1]["records"] += date_group["records"]
- else:
- final_batches += [date_group]
-
- # Give the name based on previously computed values
- for batch in final_batches:
- for move in batch["records"]:
- move.name = batch["format"].format(**batch["format_values"])
- batch["format_values"]["seq"] += 1
- batch["records"]._compute_split_sequence()
-
- self.filtered(lambda m: not m.name).name = "/"
+ super(AccountMove, self)._compute_name()
for move in self.filtered(
lambda x: x.country_code == "DO"
diff --git a/l10n_do_accounting/views/res_config_settings_view.xml b/l10n_do_accounting/views/res_config_settings_view.xml
index 77b5d6535..f27605bf2 100644
--- a/l10n_do_accounting/views/res_config_settings_view.xml
+++ b/l10n_do_accounting/views/res_config_settings_view.xml
@@ -7,10 +7,10 @@
-
+
Dominican Localization
-