diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
| commit | 3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch) | |
| tree | a44932296ef4a9b71d5f010906253d8c53727726 /addons/l10n_latam_invoice_document/models | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/l10n_latam_invoice_document/models')
8 files changed, 490 insertions, 0 deletions
diff --git a/addons/l10n_latam_invoice_document/models/__init__.py b/addons/l10n_latam_invoice_document/models/__init__.py new file mode 100644 index 00000000..cb7b480f --- /dev/null +++ b/addons/l10n_latam_invoice_document/models/__init__.py @@ -0,0 +1,9 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import res_company +from . import l10n_latam_document_type +from . import account_journal +from . import account_move +from . import account_move_line +from . import account_chart_template +from . import ir_sequence diff --git a/addons/l10n_latam_invoice_document/models/account_chart_template.py b/addons/l10n_latam_invoice_document/models/account_chart_template.py new file mode 100644 index 00000000..a181655d --- /dev/null +++ b/addons/l10n_latam_invoice_document/models/account_chart_template.py @@ -0,0 +1,19 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. +from odoo import models, api, fields, _ + + +class AccountChartTemplate(models.Model): + + _inherit = 'account.chart.template' + + @api.model + def _prepare_all_journals(self, acc_template_ref, company, journals_dict=None): + """ We add use_documents or not depending on the context""" + journal_data = super()._prepare_all_journals(acc_template_ref, company, journals_dict) + + # if chart has localization, then we use documents by default + if company._localization_use_documents(): + for vals_journal in journal_data: + if vals_journal['type'] in ['sale', 'purchase']: + vals_journal['l10n_latam_use_documents'] = True + return journal_data diff --git a/addons/l10n_latam_invoice_document/models/account_journal.py b/addons/l10n_latam_invoice_document/models/account_journal.py new file mode 100644 index 00000000..9ed4e43b --- /dev/null +++ b/addons/l10n_latam_invoice_document/models/account_journal.py @@ -0,0 +1,38 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import fields, models, api, _ +from odoo.exceptions import ValidationError + +class AccountJournal(models.Model): + + _inherit = "account.journal" + + l10n_latam_use_documents = fields.Boolean( + 'Use Documents?', help="If active: will be using for legal invoicing (invoices, debit/credit notes)." + " If not set means that will be used to register accounting entries not related to invoicing legal documents." + " For Example: Receipts, Tax Payments, Register journal entries") + l10n_latam_company_use_documents = fields.Boolean(compute='_compute_l10n_latam_company_use_documents') + + @api.depends('company_id') + def _compute_l10n_latam_company_use_documents(self): + for rec in self: + rec.l10n_latam_company_use_documents = rec.company_id._localization_use_documents() + + @api.onchange('company_id', 'type') + def _onchange_company(self): + self.l10n_latam_use_documents = self.type in ['sale', 'purchase'] and \ + self.l10n_latam_company_use_documents + + @api.constrains('l10n_latam_use_documents') + def check_use_document(self): + for rec in self: + if rec.env['account.move'].search([('journal_id', '=', rec.id), ('posted_before', '=', True)], limit=1): + raise ValidationError(_( + 'You can not modify the field "Use Documents?" if there are validated invoices in this journal!')) + + @api.onchange('type', 'l10n_latam_use_documents') + def _onchange_type(self): + res = super()._onchange_type() + if self.l10n_latam_use_documents: + self.refund_sequence = False + return res diff --git a/addons/l10n_latam_invoice_document/models/account_move.py b/addons/l10n_latam_invoice_document/models/account_move.py new file mode 100644 index 00000000..fb4e7528 --- /dev/null +++ b/addons/l10n_latam_invoice_document/models/account_move.py @@ -0,0 +1,288 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import models, fields, api, _ +from odoo.exceptions import UserError, ValidationError +import re +from odoo.tools.misc import formatLang +from odoo.tools.sql import column_exists, create_column + + +class AccountMove(models.Model): + + _inherit = "account.move" + + def _auto_init(self): + # Skip the computation of the field `l10n_latam_document_type_id` at the module installation + # Without this, at the module installation, + # it would call `_compute_l10n_latam_document_type` on all existing records + # which can take quite a while if you already have a lot of moves. It can even fail with a MemoryError. + # In addition, it sets `_compute_l10n_latam_document_type = False` on all records + # because this field depends on the many2many `l10n_latam_available_document_type_ids`, + # which relies on having records for the model `l10n_latam.document.type` + # which only happens once the according localization module is loaded. + # The localization module is loaded afterwards, because the localization module depends on this module, + # (e.g. `l10n_cl` depends on `l10n_latam_invoice_document`, and therefore `l10n_cl` is loaded after) + # and therefore there are no records for the model `l10n_latam.document.type` at the time this fields + # gets computed on installation. Hence, all records' `_compute_l10n_latam_document_type` are set to `False`. + # In addition, multiple localization module depends on this module (e.g. `l10n_cl`, `l10n_ar`) + # So, imagine `l10n_cl` gets installed first, and then `l10n_ar` is installed next, + # if `l10n_latam_document_type_id` needed to be computed on install, + # the install of `l10n_cl` would call the compute method, + # because `l10n_latam_invoice_document` would be installed at the same time, + # but then `l10n_ar` would miss it, because `l10n_latam_invoice_document` would already be installed. + # Besides, this field is computed only for drafts invoices, as stated in the compute method: + # `for rec in self.filtered(lambda x: x.state == 'draft'):` + # So, if we want this field to be computed on install, it must be done only on draft invoices, and only once + # the localization modules are loaded. + # It should be done in a dedicated post init hook, + # filtering correctly the invoices for which it must be computed. + # Though I don't think this is needed. + # In practical, it's very rare to already have invoices (draft, in addition) + # for a Chilian or Argentian company (`res.company`) before installing `l10n_cl` or `l10n_ar`. + if not column_exists(self.env.cr, "account_move", "l10n_latam_document_type_id"): + create_column(self.env.cr, "account_move", "l10n_latam_document_type_id", "int4") + return super()._auto_init() + + l10n_latam_amount_untaxed = fields.Monetary(compute='_compute_l10n_latam_amount_and_taxes') + l10n_latam_tax_ids = fields.One2many(compute="_compute_l10n_latam_amount_and_taxes", comodel_name='account.move.line') + l10n_latam_available_document_type_ids = fields.Many2many('l10n_latam.document.type', compute='_compute_l10n_latam_available_document_types') + l10n_latam_document_type_id = fields.Many2one( + 'l10n_latam.document.type', string='Document Type', readonly=False, auto_join=True, index=True, + states={'posted': [('readonly', True)]}, compute='_compute_l10n_latam_document_type', store=True) + l10n_latam_document_number = fields.Char( + compute='_compute_l10n_latam_document_number', inverse='_inverse_l10n_latam_document_number', + string='Document Number', readonly=True, states={'draft': [('readonly', False)]}) + l10n_latam_use_documents = fields.Boolean(related='journal_id.l10n_latam_use_documents') + l10n_latam_manual_document_number = fields.Boolean(compute='_compute_l10n_latam_manual_document_number', string='Manual Number') + + @api.depends('l10n_latam_document_type_id') + def _compute_name(self): + """ Change the way that the use_document moves name is computed: + + * If move use document but does not have document type selected then name = '/' to do not show the name. + * If move use document and are numbered manually do not compute name at all (will be set manually) + * If move use document and is in draft state and has not been posted before we restart name to '/' (this is + when we change the document type) """ + without_doc_type = self.filtered(lambda x: x.journal_id.l10n_latam_use_documents and not x.l10n_latam_document_type_id) + manual_documents = self.filtered(lambda x: x.journal_id.l10n_latam_use_documents and x.l10n_latam_manual_document_number) + (without_doc_type + manual_documents.filtered(lambda x: not x.name or x.name and x.state == 'draft' and not x.posted_before)).name = '/' + # if we change document or journal and we are in draft and not posted, we clean number so that is recomputed in super + self.filtered( + lambda x: x.journal_id.l10n_latam_use_documents and x.l10n_latam_document_type_id + and not x.l10n_latam_manual_document_number and x.state == 'draft' and not x.posted_before).name = '/' + super(AccountMove, self - without_doc_type - manual_documents)._compute_name() + + @api.depends('l10n_latam_document_type_id', 'journal_id') + def _compute_l10n_latam_manual_document_number(self): + """ Indicates if this document type uses a sequence or if the numbering is made manually """ + recs_with_journal_id = self.filtered(lambda x: x.journal_id and x.journal_id.l10n_latam_use_documents) + for rec in recs_with_journal_id: + rec.l10n_latam_manual_document_number = self._is_manual_document_number(rec.journal_id) + remaining = self - recs_with_journal_id + remaining.l10n_latam_manual_document_number = False + + def _is_manual_document_number(self, journal): + return True if journal.type == 'purchase' else False + + @api.depends('name') + def _compute_l10n_latam_document_number(self): + recs_with_name = self.filtered(lambda x: x.name != '/') + for rec in recs_with_name: + name = rec.name + doc_code_prefix = rec.l10n_latam_document_type_id.doc_code_prefix + if doc_code_prefix and name: + name = name.split(" ", 1)[-1] + rec.l10n_latam_document_number = name + remaining = self - recs_with_name + remaining.l10n_latam_document_number = False + + @api.onchange('l10n_latam_document_type_id', 'l10n_latam_document_number') + def _inverse_l10n_latam_document_number(self): + for rec in self.filtered(lambda x: x.l10n_latam_document_type_id): + if not rec.l10n_latam_document_number: + rec.name = '/' + else: + l10n_latam_document_number = rec.l10n_latam_document_type_id._format_document_number(rec.l10n_latam_document_number) + if rec.l10n_latam_document_number != l10n_latam_document_number: + rec.l10n_latam_document_number = l10n_latam_document_number + rec.name = "%s %s" % (rec.l10n_latam_document_type_id.doc_code_prefix, l10n_latam_document_number) + + @api.depends('journal_id', 'l10n_latam_document_type_id') + def _compute_highest_name(self): + manual_records = self.filtered('l10n_latam_manual_document_number') + manual_records.highest_name = '' + super(AccountMove, self - manual_records)._compute_highest_name() + + @api.model + def _deduce_sequence_number_reset(self, name): + if self.l10n_latam_use_documents: + return 'never' + return super(AccountMove, self)._deduce_sequence_number_reset(name) + + def _get_starting_sequence(self): + if self.journal_id.l10n_latam_use_documents: + if self.l10n_latam_document_type_id: + return "%s 00000000" % (self.l10n_latam_document_type_id.doc_code_prefix) + # There was no pattern found, propose one + return "" + + return super(AccountMove, self)._get_starting_sequence() + + def _compute_l10n_latam_amount_and_taxes(self): + recs_invoice = self.filtered(lambda x: x.is_invoice()) + for invoice in recs_invoice: + tax_lines = invoice.line_ids.filtered('tax_line_id') + currencies = invoice.line_ids.filtered(lambda x: x.currency_id == invoice.currency_id).mapped('currency_id') + included_taxes = invoice.l10n_latam_document_type_id and \ + invoice.l10n_latam_document_type_id._filter_taxes_included(tax_lines.mapped('tax_line_id')) + if not included_taxes: + l10n_latam_amount_untaxed = invoice.amount_untaxed + not_included_invoice_taxes = tax_lines + else: + included_invoice_taxes = tax_lines.filtered(lambda x: x.tax_line_id in included_taxes) + not_included_invoice_taxes = tax_lines - included_invoice_taxes + if invoice.is_inbound(): + sign = -1 + else: + sign = 1 + amount = 'amount_currency' if len(currencies) == 1 else 'balance' + l10n_latam_amount_untaxed = invoice.amount_untaxed + sign * sum(included_invoice_taxes.mapped(amount)) + invoice.l10n_latam_amount_untaxed = l10n_latam_amount_untaxed + invoice.l10n_latam_tax_ids = not_included_invoice_taxes + remaining = self - recs_invoice + remaining.l10n_latam_amount_untaxed = False + remaining.l10n_latam_tax_ids = [(5, 0)] + + def _post(self, soft=True): + for rec in self.filtered(lambda x: x.l10n_latam_use_documents and (not x.name or x.name == '/')): + if rec.move_type in ('in_receipt', 'out_receipt'): + raise UserError(_('We do not accept the usage of document types on receipts yet. ')) + return super()._post(soft) + + @api.constrains('name', 'journal_id', 'state') + def _check_unique_sequence_number(self): + """ This uniqueness verification is only valid for customer invoices, and vendor bills that does not use + documents. A new constraint method _check_unique_vendor_number has been created just for validate for this purpose """ + vendor = self.filtered(lambda x: x.is_purchase_document() and x.l10n_latam_use_documents) + return super(AccountMove, self - vendor)._check_unique_sequence_number() + + @api.constrains('state', 'l10n_latam_document_type_id') + def _check_l10n_latam_documents(self): + """ This constraint checks that if a invoice is posted and does not have a document type configured will raise + an error. This only applies to invoices related to journals that has the "Use Documents" set as True. + And if the document type is set then check if the invoice number has been set, because a posted invoice + without a document number is not valid in the case that the related journals has "Use Docuemnts" set as True """ + validated_invoices = self.filtered(lambda x: x.l10n_latam_use_documents and x.state == 'posted') + without_doc_type = validated_invoices.filtered(lambda x: not x.l10n_latam_document_type_id) + if without_doc_type: + raise ValidationError(_( + 'The journal require a document type but not document type has been selected on invoices %s.', + without_doc_type.ids + )) + without_number = validated_invoices.filtered( + lambda x: not x.l10n_latam_document_number and x.l10n_latam_manual_document_number) + if without_number: + raise ValidationError(_( + 'Please set the document number on the following invoices %s.', + without_number.ids + )) + + @api.constrains('move_type', 'l10n_latam_document_type_id') + def _check_invoice_type_document_type(self): + for rec in self.filtered('l10n_latam_document_type_id.internal_type'): + internal_type = rec.l10n_latam_document_type_id.internal_type + invoice_type = rec.move_type + if internal_type in ['debit_note', 'invoice'] and invoice_type in ['out_refund', 'in_refund']: + raise ValidationError(_('You can not use a %s document type with a refund invoice', internal_type)) + elif internal_type == 'credit_note' and invoice_type in ['out_invoice', 'in_invoice']: + raise ValidationError(_('You can not use a %s document type with a invoice', internal_type)) + + def _get_l10n_latam_documents_domain(self): + self.ensure_one() + if self.move_type in ['out_refund', 'in_refund']: + internal_types = ['credit_note'] + else: + internal_types = ['invoice', 'debit_note'] + return [('internal_type', 'in', internal_types), ('country_id', '=', self.company_id.country_id.id)] + + @api.depends('journal_id', 'partner_id', 'company_id', 'move_type') + def _compute_l10n_latam_available_document_types(self): + self.l10n_latam_available_document_type_ids = False + for rec in self.filtered(lambda x: x.journal_id and x.l10n_latam_use_documents and x.partner_id): + rec.l10n_latam_available_document_type_ids = self.env['l10n_latam.document.type'].search(rec._get_l10n_latam_documents_domain()) + + @api.depends('l10n_latam_available_document_type_ids', 'debit_origin_id') + def _compute_l10n_latam_document_type(self): + debit_note = self.debit_origin_id + for rec in self.filtered(lambda x: x.state == 'draft'): + document_types = rec.l10n_latam_available_document_type_ids._origin + document_types = debit_note and document_types.filtered(lambda x: x.internal_type == 'debit_note') or document_types + rec.l10n_latam_document_type_id = document_types and document_types[0].id + + def _compute_invoice_taxes_by_group(self): + report_or_portal_view = 'commit_assetsbundle' in self.env.context or \ + not self.env.context.get('params', {}).get('view_type') == 'form' + if not report_or_portal_view: + return super()._compute_invoice_taxes_by_group() + + move_with_doc_type = self.filtered('l10n_latam_document_type_id') + for move in move_with_doc_type: + lang_env = move.with_context(lang=move.partner_id.lang).env + tax_lines = move.l10n_latam_tax_ids + tax_balance_multiplicator = -1 if move.is_inbound(True) else 1 + res = {} + # There are as many tax line as there are repartition lines + done_taxes = set() + for line in tax_lines: + res.setdefault(line.tax_line_id.tax_group_id, {'base': 0.0, 'amount': 0.0}) + res[line.tax_line_id.tax_group_id]['amount'] += tax_balance_multiplicator * (line.amount_currency if line.currency_id else line.balance) + tax_key_add_base = tuple(move._get_tax_key_for_group_add_base(line)) + if tax_key_add_base not in done_taxes: + if line.currency_id and line.company_currency_id and line.currency_id != line.company_currency_id: + amount = line.company_currency_id._convert(line.tax_base_amount, line.currency_id, line.company_id, line.date or fields.Date.today()) + else: + amount = line.tax_base_amount + res[line.tax_line_id.tax_group_id]['base'] += amount + # The base should be added ONCE + done_taxes.add(tax_key_add_base) + + # At this point we only want to keep the taxes with a zero amount since they do not + # generate a tax line. + zero_taxes = set() + for line in move.line_ids: + for tax in line.l10n_latam_tax_ids.flatten_taxes_hierarchy(): + if tax.tax_group_id not in res or tax.id in zero_taxes: + res.setdefault(tax.tax_group_id, {'base': 0.0, 'amount': 0.0}) + res[tax.tax_group_id]['base'] += tax_balance_multiplicator * (line.amount_currency if line.currency_id else line.balance) + zero_taxes.add(tax.id) + + res = sorted(res.items(), key=lambda l: l[0].sequence) + move.amount_by_group = [( + group.name, amounts['amount'], + amounts['base'], + formatLang(lang_env, amounts['amount'], currency_obj=move.currency_id), + formatLang(lang_env, amounts['base'], currency_obj=move.currency_id), + len(res), + group.id + ) for group, amounts in res] + super(AccountMove, self - move_with_doc_type)._compute_invoice_taxes_by_group() + + @api.constrains('name', 'partner_id', 'company_id', 'posted_before') + def _check_unique_vendor_number(self): + """ The constraint _check_unique_sequence_number is valid for customer bills but not valid for us on vendor + bills because the uniqueness must be per partner """ + for rec in self.filtered( + lambda x: x.name and x.name != '/' and x.is_purchase_document() and x.l10n_latam_use_documents + and x.commercial_partner_id): + domain = [ + ('move_type', '=', rec.move_type), + # by validating name we validate l10n_latam_document_type_id + ('name', '=', rec.name), + ('company_id', '=', rec.company_id.id), + ('id', '!=', rec.id), + ('commercial_partner_id', '=', rec.commercial_partner_id.id), + # allow to have to equal if they are cancelled + ('state', '!=', 'cancel'), + ] + if rec.search(domain): + raise ValidationError(_('Vendor bill number must be unique per vendor and company.')) diff --git a/addons/l10n_latam_invoice_document/models/account_move_line.py b/addons/l10n_latam_invoice_document/models/account_move_line.py new file mode 100644 index 00000000..b873dccd --- /dev/null +++ b/addons/l10n_latam_invoice_document/models/account_move_line.py @@ -0,0 +1,55 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import models, api, fields +from odoo.tools.sql import column_exists, create_column + + +class AccountMoveLine(models.Model): + + _inherit = 'account.move.line' + + def _auto_init(self): + # Skip the computation of the field `l10n_latam_document_type_id` at the module installation + # See `_auto_init` in `l10n_latam_invoice_document/models/account_move.py` for more information + if not column_exists(self.env.cr, "account_move_line", "l10n_latam_document_type_id"): + create_column(self.env.cr, "account_move_line", "l10n_latam_document_type_id", "int4") + return super()._auto_init() + + l10n_latam_document_type_id = fields.Many2one( + related='move_id.l10n_latam_document_type_id', auto_join=True, store=True, index=True) + l10n_latam_price_unit = fields.Float(compute='compute_l10n_latam_prices_and_taxes', digits='Product Price') + l10n_latam_price_subtotal = fields.Monetary(compute='compute_l10n_latam_prices_and_taxes') + l10n_latam_price_net = fields.Float(compute='compute_l10n_latam_prices_and_taxes', digits='Product Price') + l10n_latam_tax_ids = fields.One2many(compute="compute_l10n_latam_prices_and_taxes", comodel_name='account.tax') + + @api.depends('price_unit', 'price_subtotal', 'move_id.l10n_latam_document_type_id') + def compute_l10n_latam_prices_and_taxes(self): + for line in self: + invoice = line.move_id + included_taxes = \ + invoice.l10n_latam_document_type_id and invoice.l10n_latam_document_type_id._filter_taxes_included( + line.tax_ids) + # For the unit price, we need the number rounded based on the product price precision. + # The method compute_all uses the accuracy of the currency so, we multiply and divide for 10^(decimal accuracy of product price) to get the price correctly rounded. + price_digits = 10**self.env['decimal.precision'].precision_get('Product Price') + if not included_taxes: + price_unit = line.tax_ids.with_context(round=False, force_sign=invoice._get_tax_force_sign()).compute_all( + line.price_unit * price_digits, invoice.currency_id, 1.0, line.product_id, invoice.partner_id) + l10n_latam_price_unit = price_unit['total_excluded'] / price_digits + l10n_latam_price_subtotal = line.price_subtotal + not_included_taxes = line.tax_ids + l10n_latam_price_net = l10n_latam_price_unit * (1 - (line.discount or 0.0) / 100.0) + else: + not_included_taxes = line.tax_ids - included_taxes + l10n_latam_price_unit = included_taxes.with_context(force_sign=invoice._get_tax_force_sign()).compute_all( + line.price_unit * price_digits, invoice.currency_id, 1.0, line.product_id, invoice.partner_id)['total_included'] / price_digits + l10n_latam_price_net = l10n_latam_price_unit * (1 - (line.discount or 0.0) / 100.0) + price = line.price_unit * (1 - (line.discount or 0.0) / 100.0) + l10n_latam_price_subtotal = included_taxes.with_context(force_sign=invoice._get_tax_force_sign()).compute_all( + price, invoice.currency_id, line.quantity, line.product_id, + invoice.partner_id)['total_included'] + + line.l10n_latam_price_subtotal = l10n_latam_price_subtotal + line.l10n_latam_price_unit = l10n_latam_price_unit + line.l10n_latam_price_net = l10n_latam_price_net + line.l10n_latam_tax_ids = not_included_taxes diff --git a/addons/l10n_latam_invoice_document/models/ir_sequence.py b/addons/l10n_latam_invoice_document/models/ir_sequence.py new file mode 100644 index 00000000..314a8597 --- /dev/null +++ b/addons/l10n_latam_invoice_document/models/ir_sequence.py @@ -0,0 +1,9 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. +from odoo import fields, models + + +class IrSequence(models.Model): + + _inherit = 'ir.sequence' + + l10n_latam_document_type_id = fields.Many2one('l10n_latam.document.type', 'Document Type') #still needed for l10n_cl until next saas diff --git a/addons/l10n_latam_invoice_document/models/l10n_latam_document_type.py b/addons/l10n_latam_invoice_document/models/l10n_latam_document_type.py new file mode 100644 index 00000000..3eb6bd04 --- /dev/null +++ b/addons/l10n_latam_invoice_document/models/l10n_latam_document_type.py @@ -0,0 +1,60 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. +from odoo import fields, models, api +from odoo.osv import expression + + +class L10nLatamDocumentType(models.Model): + + _name = 'l10n_latam.document.type' + _description = 'Latam Document Type' + _order = 'sequence, id' + + active = fields.Boolean(default=True) + sequence = fields.Integer( + default=10, required=True, help='To set in which order show the documents type taking into account the most' + ' commonly used first') + country_id = fields.Many2one( + 'res.country', required=True, index=True, help='Country in which this type of document is valid') + name = fields.Char(required=True, index=True, help='The document name') + doc_code_prefix = fields.Char( + 'Document Code Prefix', help="Prefix for Documents Codes on Invoices and Account Moves. For eg. 'FA ' will" + " build 'FA 0001-0000001' Document Number") + code = fields.Char(help='Code used by different localizations') + report_name = fields.Char('Name on Reports', help='Name that will be printed in reports, for example "CREDIT NOTE"') + internal_type = fields.Selection( + [('invoice', 'Invoices'), ('debit_note', 'Debit Notes'), ('credit_note', 'Credit Notes')], index=True, + help='Analog to odoo account.move.move_type but with more options allowing to identify the kind of document we are' + ' working with. (not only related to account.move, could be for documents of other models like stock.picking)') + + def _format_document_number(self, document_number): + """ Method to be inherited by different localizations. The purpose of this method is to allow: + * making validations on the document_number. If it is wrong it should raise an exception + * format the document_number against a pattern and return it + """ + self.ensure_one() + return document_number + + def name_get(self): + result = [] + for rec in self: + name = rec.name + if rec.code: + name = '(%s) %s' % (rec.code, name) + result.append((rec.id, name)) + return result + + @api.model + def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None): + args = args or [] + if operator == 'ilike' and not (name or '').strip(): + domain = [] + else: + domain = ['|', ('name', 'ilike', name), ('code', 'ilike', name)] + return self._search(expression.AND([domain, args]), limit=limit, access_rights_uid=name_get_uid) + + def _filter_taxes_included(self, taxes): + """ This method is to be inherited by different localizations and must return filter the given taxes recordset + returning the taxes to be included on reports of this document type. All taxes are going to be discriminated + except the one returned by this method. """ + self.ensure_one() + return self.env['account.tax'] diff --git a/addons/l10n_latam_invoice_document/models/res_company.py b/addons/l10n_latam_invoice_document/models/res_company.py new file mode 100644 index 00000000..b37c24ef --- /dev/null +++ b/addons/l10n_latam_invoice_document/models/res_company.py @@ -0,0 +1,12 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. +from odoo import fields, models + + +class ResCompany(models.Model): + + _inherit = "res.company" + + def _localization_use_documents(self): + """ This method is to be inherited by localizations and return True if localization use documents """ + self.ensure_one() + return False |
