diff --git a/account_sequence_option/__init__.py b/account_sequence_option/__init__.py new file mode 100644 index 000000000..b7f345e3e --- /dev/null +++ b/account_sequence_option/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2021 Ecosoft Co., Ltd. (http://ecosoft.co.th) +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from . import models diff --git a/account_sequence_option/__manifest__.py b/account_sequence_option/__manifest__.py new file mode 100644 index 000000000..964c60afd --- /dev/null +++ b/account_sequence_option/__manifest__.py @@ -0,0 +1,19 @@ +# Copyright 2021 Ecosoft Co., Ltd. (http://ecosoft.co.th) +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +{ + "name": "Account Sequence Option", + "summary": "Manage sequence options for account.move, i.e., invoice, bill, entry", + "version": "14.0.1.0.0", + "author": "Ecosoft, Odoo Community Association (OCA)", + "development_status": "Alpha", + "website": "https://github.com/OCA/account-financial-tools", + "category": "Accounting", + "depends": ["account", "base_sequence_option"], + "data": ["data/account_sequence_option.xml"], + "demo": ["demo/account_demo_options.xml"], + "maintainers": ["kittiu"], + "license": "LGPL-3", + "installable": True, + "auto_install": False, +} diff --git a/account_sequence_option/data/account_sequence_option.xml b/account_sequence_option/data/account_sequence_option.xml new file mode 100644 index 000000000..6b6fcc4c6 --- /dev/null +++ b/account_sequence_option/data/account_sequence_option.xml @@ -0,0 +1,9 @@ + + + + Invoice / Bill / Refund / Payment + account.move + + + + diff --git a/account_sequence_option/demo/account_demo_options.xml b/account_sequence_option/demo/account_demo_options.xml new file mode 100644 index 000000000..e601b658d --- /dev/null +++ b/account_sequence_option/demo/account_demo_options.xml @@ -0,0 +1,95 @@ + + + + + + Customer Invoice + + CINV/ + + + + Customer Refund + + CREF/ + + + + Vendor Bill + + VBIL/ + + + + Vendor Refund + + VREF/ + + + + Customer Payment + + CPAY/ + + + + Vendor Payment + + VPAY/ + + + + + + + Customer Invoice + [("move_type", "=", "out_invoice")] + + + + + + Customer Refund + [("move_type", "=", "out_refund")] + + + + + + Vendor Bill + [("move_type", "=", "in_invoice")] + + + + + + Vendor Refund + [("move_type", "=", "in_refund")] + + + + + + Customer Payment + [("move_type", "=", "entry"), ("payment_id.payment_type", "=", "inbound")] + + + + + + Vendor Payment + [("move_type", "=", "entry"), ("payment_id.payment_type", "=", "outbound")] + + + + diff --git a/account_sequence_option/models/__init__.py b/account_sequence_option/models/__init__.py new file mode 100644 index 000000000..a46d682dc --- /dev/null +++ b/account_sequence_option/models/__init__.py @@ -0,0 +1,5 @@ +# Copyright 2021 Ecosoft Co., Ltd. (http://ecosoft.co.th) +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from . import account_move +from . import sequence_option diff --git a/account_sequence_option/models/account_move.py b/account_sequence_option/models/account_move.py new file mode 100644 index 000000000..6d6d039ac --- /dev/null +++ b/account_sequence_option/models/account_move.py @@ -0,0 +1,64 @@ +# Copyright 2021 Ecosoft Co., Ltd. (http://ecosoft.co.th) +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from odoo import api, fields, models + + +class AccountMove(models.Model): + _inherit = "account.move" + + sequence_option = fields.Boolean( + compute="_compute_name", + default=False, + copy=False, + store=True, + index=True, + ) + + @api.depends("posted_before", "state", "journal_id", "date") + def _compute_name(self): + # + options = self.env["ir.sequence.option.line"].get_model_options(self._name) + # On post, get the sequence option + if options: + for rec in self.filtered( + lambda l: l.name in (False, "/") and l.state == "posted" + ): + sequence = self.env["ir.sequence.option.line"].get_sequence( + rec, options=options + ) + if sequence: + rec.name = sequence.next_by_id(sequence_date=rec.date) + rec.sequence_option = True + + # Call super() + super()._compute_name() + if options: + for rec in self: + # On create new, odoo may suggest the 1st new number, remove it. + if ( + not rec.create_date + and rec.state == "draft" + and rec.name not in (False, "/") + ): + rec.name = "/" + # On cancel/draft w/o number assigned yet, ensure no odoo number assigned. + if ( + rec.create_date + and rec.state in ("draft", "cancel") + and rec.name not in (False, "/") + and not rec.sequence_option + ): + rec.name = "/" + + # Bypass constrains if sequence is defined + def _constrains_date_sequence(self): + records = self.filtered( + lambda l: self.env["ir.sequence.option.line"].get_sequence(l) + ) + return super(AccountMove, self - records)._constrains_date_sequence() + + def _get_last_sequence_domain(self, relaxed=False): + (where_string, param) = super()._get_last_sequence_domain(relaxed=relaxed) + where_string += " AND coalesce(sequence_option, false) = false " + return where_string, param diff --git a/account_sequence_option/models/sequence_option.py b/account_sequence_option/models/sequence_option.py new file mode 100644 index 000000000..441b1a5e8 --- /dev/null +++ b/account_sequence_option/models/sequence_option.py @@ -0,0 +1,13 @@ +# Copyright 2021 Ecosoft Co., Ltd. (http://ecosoft.co.th) +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from odoo import fields, models + + +class IrSequenceOption(models.Model): + _inherit = "ir.sequence.option" + + model = fields.Selection( + selection_add=[("account.move", "account.move")], + ondelete={"account.move": "cascade"}, + ) diff --git a/account_sequence_option/readme/CONTRIBUTORS.rst b/account_sequence_option/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..6ce956d96 --- /dev/null +++ b/account_sequence_option/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Kitti U. diff --git a/account_sequence_option/readme/DESCRIPTION.rst b/account_sequence_option/readme/DESCRIPTION.rst new file mode 100644 index 000000000..a23cf505f --- /dev/null +++ b/account_sequence_option/readme/DESCRIPTION.rst @@ -0,0 +1,2 @@ +This module extends module ir_sequence_option and allow you to +provide optional sequences for account.move documents, i.e., invoice, bill, journal entry. diff --git a/account_sequence_option/static/description/icon.png b/account_sequence_option/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/account_sequence_option/static/description/icon.png differ diff --git a/account_sequence_option/tests/__init__.py b/account_sequence_option/tests/__init__.py new file mode 100644 index 000000000..7fa68a111 --- /dev/null +++ b/account_sequence_option/tests/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2021 Ecosoft Co., Ltd. (http://ecosoft.co.th) +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from . import test_account_sequence_option diff --git a/account_sequence_option/tests/test_account_sequence_option.py b/account_sequence_option/tests/test_account_sequence_option.py new file mode 100644 index 000000000..1e061b200 --- /dev/null +++ b/account_sequence_option/tests/test_account_sequence_option.py @@ -0,0 +1,74 @@ +# Copyright 2021 Ecosoft Co., Ltd. (http://ecosoft.co.th) +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from odoo import fields +from odoo.tests.common import Form, TransactionCase, tagged + + +@tagged("post_install", "-at_install") +class TestAccountSequenceOption(TransactionCase): + def setUp(self): + super(TestAccountSequenceOption, self).setUp() + self.AccountMove = self.env["account.move"] + self.AccountMoveLine = self.env["account.move.line"] + self.partner_id = self.env.ref("base.res_partner_1") + self.product_id_1 = self.env.ref("product.product_product_6") + self.account_seq_opt1 = self.env.ref("account_sequence_option.account_sequence") + self.pay_in = self.env.ref("account.account_payment_method_manual_in") + self.pay_out = self.env.ref("account.account_payment_method_manual_out") + + def _create_invoice(self, move_type): + move_form = Form( + self.env["account.move"].with_context(default_move_type=move_type) + ) + move_form.partner_id = self.partner_id + move_form.invoice_date = fields.Date.today() + with move_form.invoice_line_ids.new() as line_form: + line_form.product_id = self.product_id_1 + invoice = move_form.save() + return invoice + + def _create_payment(self, payment_type, partner_type): + ctx = { + "default_payment_type": payment_type, + "default_partner_type": partner_type, + "default_move_journal_types": ("bank", "cash"), + } + move_form = Form(self.env["account.payment"].with_context(ctx)) + move_form.payment_type = payment_type + move_form.partner_type = partner_type + move_form.partner_id = self.partner_id + payment = move_form.save() + return payment + + def test_account_sequence_options(self): + """Test different kind of sequences + 1. Customer Invoice 2. Vendor Bill + 3. Customer Refund 4. Vendor Refund + 5. Customer Payment 6. Vendor Payment + """ + self.account_seq_opt1.use_sequence_option = True + # 1. Customer Invoice + self.invoice = self._create_invoice("out_invoice") + self.invoice.action_post() + self.assertIn("CINV", self.invoice.name) + # 2. Vendor Bill + self.invoice = self._create_invoice("in_invoice") + self.invoice.action_post() + self.assertIn("VBIL", self.invoice.name) + # 3. Customer Refund + self.invoice = self._create_invoice("out_refund") + self.invoice.action_post() + self.assertIn("CREF", self.invoice.name) + # 4. Vendor Refund + self.invoice = self._create_invoice("in_refund") + self.invoice.action_post() + self.assertIn("VREF", self.invoice.name) + # 5. Customer Payment + self.payment = self._create_payment("inbound", "customer") + self.payment.action_post() + self.assertIn("CPAY", self.payment.name) + # 6. Vendor Payment + self.payment = self._create_payment("outbound", "supplier") + self.payment.action_post() + self.assertIn("VPAY", self.payment.name) diff --git a/setup/account_sequence_option/odoo/addons/account_sequence_option b/setup/account_sequence_option/odoo/addons/account_sequence_option new file mode 120000 index 000000000..a29bce64b --- /dev/null +++ b/setup/account_sequence_option/odoo/addons/account_sequence_option @@ -0,0 +1 @@ +../../../../account_sequence_option \ No newline at end of file diff --git a/setup/account_sequence_option/setup.py b/setup/account_sequence_option/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/account_sequence_option/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)