From f47de6b7eb48103cec5a77d0fad2c03da10f8612 Mon Sep 17 00:00:00 2001 From: Hardik Suthar Date: Tue, 28 Oct 2025 18:16:52 +0530 Subject: [PATCH] [18.0][ADD] Lims Sale --- lims_sale/README.rst | 168 +++++++ lims_sale/__init__.py | 1 + lims_sale/__manifest__.py | 20 + lims_sale/models/__init__.py | 4 + lims_sale/models/lims_order.py | 24 + lims_sale/models/lims_template.py | 56 +++ lims_sale/models/product_template.py | 23 + lims_sale/models/sale_order.py | 72 +++ lims_sale/pyproject.toml | 3 + lims_sale/readme/CONFIGURE.md | 20 + lims_sale/readme/CONTRIBUTORS.md | 4 + lims_sale/readme/DESCRIPTION.md | 20 + lims_sale/readme/USAGE.md | 11 + lims_sale/static/description/index.html | 492 +++++++++++++++++++++ lims_sale/tests/__init__.py | 5 + lims_sale/tests/common.py | 37 ++ lims_sale/tests/test_sale_order.py | 99 +++++ lims_sale/views/lms_order_view.xml | 18 + lims_sale/views/product_template_views.xml | 13 + lims_sale/views/sale_order_views.xml | 24 + test-requirements.txt | 1 + 21 files changed, 1115 insertions(+) create mode 100644 lims_sale/README.rst create mode 100644 lims_sale/__init__.py create mode 100644 lims_sale/__manifest__.py create mode 100644 lims_sale/models/__init__.py create mode 100644 lims_sale/models/lims_order.py create mode 100644 lims_sale/models/lims_template.py create mode 100644 lims_sale/models/product_template.py create mode 100644 lims_sale/models/sale_order.py create mode 100644 lims_sale/pyproject.toml create mode 100644 lims_sale/readme/CONFIGURE.md create mode 100644 lims_sale/readme/CONTRIBUTORS.md create mode 100644 lims_sale/readme/DESCRIPTION.md create mode 100644 lims_sale/readme/USAGE.md create mode 100644 lims_sale/static/description/index.html create mode 100644 lims_sale/tests/__init__.py create mode 100644 lims_sale/tests/common.py create mode 100644 lims_sale/tests/test_sale_order.py create mode 100644 lims_sale/views/lms_order_view.xml create mode 100644 lims_sale/views/product_template_views.xml create mode 100644 lims_sale/views/sale_order_views.xml create mode 100644 test-requirements.txt diff --git a/lims_sale/README.rst b/lims_sale/README.rst new file mode 100644 index 0000000..2ed2ce6 --- /dev/null +++ b/lims_sale/README.rst @@ -0,0 +1,168 @@ +===================================================== +Laboratory Information Management System (LIMS) Sales +===================================================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:d274e09eca8e2b00568dd1e5af7ad4f65974a93060575219b51e9ff6a5451476 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fconnector--lims-lightgray.png?logo=github + :target: https://github.com/OCA/connector-lims/tree/18.0/lims_sale + :alt: OCA/connector-lims +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/connector-lims-18-0/connector-lims-18-0-lims_sale + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/connector-lims&target_branch=18.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +========================== LIMS Sale Integration +================================================ + +| This module integrates **Odoo LIMS** with **Sales Orders**, allowing + laboratories to sell LIMS services directly as products. +| When a sale order is confirmed, corresponding LIMS Orders are + automatically created based on the configuration defined on each + product. + +The module supports multiple creation strategies for LIMS Orders via the +field ``lims_tracking`` on the product template. + +- **No** – No LIMS order is created. +- **Per Sales Order** – One LIMS order is created for the whole sale + order. +- **Per Sales Order Line** – One LIMS order is created for each sale + order line. +- **Per Quantity** – One LIMS order is created per quantity unit in the + sale line. + +Each LIMS Order is generated using the selected **LIMS Template**, +carrying details such as categories, operator, and test configurations +defined within the template. + +This module extends the ``lims`` and ``sale`` modules. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +========================== LIMS Sale Integration +================================================ + +| This module integrates **Odoo LIMS** with **Sales Orders**, allowing + laboratories to sell LIMS services directly as products. +| When a sale order is confirmed, corresponding LIMS Orders are + automatically created based on the configuration defined on each + product. + +The module supports multiple creation strategies for LIMS Orders via the +field ``lims_tracking`` on the product template. + +- **No** – No LIMS order is created. +- **Per Sales Order** – One LIMS order is created for the whole sale + order. +- **Per Sales Order Line** – One LIMS order is created for each sale + order line. +- **Per Quantity** – One LIMS order is created per quantity unit in the + sale line. + +Each LIMS Order is generated using the selected **LIMS Template**, +carrying details such as categories, operator, and test configurations +defined within the template. + +This module extends the ``lims`` and ``sale`` modules. + +Usage +===== + +Usage +===== + +1. Go to *Sales › Products* and open or create a product. +2. Under the *LIMS Configuration* section: + + - Select a **LIMS Template**. + - Choose the **LIMS Tracking** mode (No / Order / Line / Quantity). + +3. Create a **Sale Order** and add products with a configured LIMS + Template. +4. Confirm the sale order: + + - LIMS Orders will be automatically generated. + - A smart button **“LIMS Orders”** appears on the sale order form. + +5. Click the button to view all generated LIMS Orders linked to the + sale. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Open Source Integrators + +Contributors +------------ + +- Rodrigo Madrid rmadrid@opensourceintegrators.com +- Adriana Alpizar aalpizar@opensourceintegrators.com +- Maxime Chambreuil mchambreuil@opensourceintegrators.com +- Hardik Suthar hsuthar@opensourceintegrators.com + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +.. |maintainer-max3903| image:: https://github.com/max3903.png?size=40px + :target: https://github.com/max3903 + :alt: max3903 +.. |maintainer-jasiel-osi| image:: https://github.com/jasiel-osi.png?size=40px + :target: https://github.com/jasiel-osi + :alt: jasiel-osi +.. |maintainer-Hardik-OSI| image:: https://github.com/Hardik-OSI.png?size=40px + :target: https://github.com/Hardik-OSI + :alt: Hardik-OSI + +Current `maintainers `__: + +|maintainer-max3903| |maintainer-jasiel-osi| |maintainer-Hardik-OSI| + +This module is part of the `OCA/connector-lims `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/lims_sale/__init__.py b/lims_sale/__init__.py new file mode 100644 index 0000000..0650744 --- /dev/null +++ b/lims_sale/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/lims_sale/__manifest__.py b/lims_sale/__manifest__.py new file mode 100644 index 0000000..4d395d2 --- /dev/null +++ b/lims_sale/__manifest__.py @@ -0,0 +1,20 @@ +# Copyright (C) 2025 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +{ + "name": "Laboratory Information Management System (LIMS) Sales", + "summary": "Manage LIMS Instruments, Analysis and Tests Sales Integration", + "version": "18.0.1.0.0", + "license": "AGPL-3", + "category": "LIMS", + "author": "Open Source Integrators, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/connector-lims", + "depends": ["lims", "sale"], + "data": [ + "views/product_template_views.xml", + "views/sale_order_views.xml", + "views/lms_order_view.xml", + ], + "application": False, + "development_status": "Beta", + "maintainers": ["max3903", "jasiel-osi", "Hardik-OSI"], +} diff --git a/lims_sale/models/__init__.py b/lims_sale/models/__init__.py new file mode 100644 index 0000000..1e71c77 --- /dev/null +++ b/lims_sale/models/__init__.py @@ -0,0 +1,4 @@ +from . import sale_order +from . import product_template +from . import lims_order +from . import lims_template diff --git a/lims_sale/models/lims_order.py b/lims_sale/models/lims_order.py new file mode 100644 index 0000000..39ceadd --- /dev/null +++ b/lims_sale/models/lims_order.py @@ -0,0 +1,24 @@ +from odoo import fields, models + + +class LimsOrder(models.Model): + _inherit = "lims.order" + + sale_order_id = fields.Many2one("sale.order", string="Sale Order", index=True) + sale_order_line_id = fields.Many2one( + "sale.order.line", string="Sale Order Line", index=True + ) + sale_origin = fields.Char(help="Original sale reference") + + def action_open_sale_order(self): + self.ensure_one() + if not self.sale_order_id: + return + return { + "type": "ir.actions.act_window", + "name": "Sale Order", + "res_model": "sale.order", + "view_mode": "form", + "res_id": self.sale_order_id.id, + "target": "current", + } diff --git a/lims_sale/models/lims_template.py b/lims_sale/models/lims_template.py new file mode 100644 index 0000000..3886b34 --- /dev/null +++ b/lims_sale/models/lims_template.py @@ -0,0 +1,56 @@ +from odoo import fields, models + + +class LimsTemplate(models.Model): + _inherit = "lims.template" + + def create_lims_order_from_template(self, sale_order=None, sale_line=None): + """Generate a lims.order record based on this + template and optionally link it to Sale Order.""" + self.ensure_one() + + test_commands = [] + for test in self.test_ids: + if hasattr(test, "_prepare_order_test_values"): + values = test._prepare_order_test_values() + else: + values = { + "name": test.name, + "instrument_id": getattr(test, "instrument_id", False) + and test.instrument_id.id + or False, + "company_id": test.company_id.id + if test.company_id + else self.company_id.id, + } + + if self.operator_id: + values["operator_id"] = self.operator_id.id + + test_commands.append(fields.Command.create(values)) + + vals = { + "name": f"{self.name} - {fields.Date.today()}", + "template_id": self.id, + "operator_id": self.operator_id.id if self.operator_id else False, + "company_id": self.company_id.id or self.env.company.id, + "category_ids": [(6, 0, self.category_ids.ids)], + "test_ids": test_commands, + } + + if sale_order: + vals.update( + { + "sale_order_id": sale_order.id, + "partner_id": sale_order.partner_id.id, + } + ) + if sale_line: + vals.update( + { + "sale_line_id": sale_line.id, + "partner_id": sale_order.partner_id.id, + } + ) + + return self.env["lims.order"].create(vals) diff --git a/lims_sale/models/product_template.py b/lims_sale/models/product_template.py new file mode 100644 index 0000000..bc70dfc --- /dev/null +++ b/lims_sale/models/product_template.py @@ -0,0 +1,23 @@ +from odoo import fields, models + + +class ProductTemplate(models.Model): + _inherit = "product.template" + + lims_tracking = fields.Selection( + [ + ("no", "No LIMS Order"), + ("order", "Per Sales Order"), + ("line", "Per Sales Order Line"), + ("quantity", "Per Quantity"), + ], + string="LIMS Tracking", + default="no", + help="Defines how LIMS orders are generated when a sale order is confirmed.", + ) + + lims_template_id = fields.Many2one( + "lims.template", + string="LIMS Template", + help="Template used to create the LIMS Order when a Sale Order is confirmed.", + ) diff --git a/lims_sale/models/sale_order.py b/lims_sale/models/sale_order.py new file mode 100644 index 0000000..0b61e0b --- /dev/null +++ b/lims_sale/models/sale_order.py @@ -0,0 +1,72 @@ +from odoo import fields, models + + +class SaleOrder(models.Model): + _inherit = "sale.order" + + lims_order_count = fields.Integer( + string="LIMS Orders", compute="_compute_lims_order_count", store=False + ) + + def _compute_lims_order_count(self): + lims_order_data = self.env["lims.order"].read_group( + [("sale_order_id", "in", self.ids)], ["sale_order_id"], ["sale_order_id"] + ) + mapped_data = { + data["sale_order_id"][0]: data["sale_order_id_count"] + for data in lims_order_data + } + for order in self: + order.lims_order_count = mapped_data.get(order.id, 0) + + def action_view_lims_orders(self): + self.ensure_one() + return { + "name": "LIMS Orders", + "type": "ir.actions.act_window", + "res_model": "lims.order", + "view_mode": "list,form", + "domain": [("sale_order_id", "=", self.id)], + "context": {"default_sale_order_id": self.id}, + } + + def action_confirm(self): + res = super().action_confirm() + for order in self: + for line in order.order_line: + product = line.product_id + if product.lims_tracking and product.lims_tracking != "no": + template = product.lims_template_id + if not template: + continue + + if product.lims_tracking == "order": + lims_order = template.create_lims_order_from_template() + lims_order.write( + { + "sale_order_id": order.id, + "sale_origin": order.name, + } + ) + + elif product.lims_tracking == "line": + lims_order = template.create_lims_order_from_template() + lims_order.write( + { + "sale_order_id": order.id, + "sale_order_line_id": line.id, + "sale_origin": order.name, + } + ) + + elif product.lims_tracking == "quantity": + for i in range(int(line.product_uom_qty)): + lims_order = template.create_lims_order_from_template() + lims_order.write( + { + "sale_order_id": order.id, + "sale_order_line_id": line.id, + "sale_origin": f"{order.name}-{i+1}", + } + ) + return res diff --git a/lims_sale/pyproject.toml b/lims_sale/pyproject.toml new file mode 100644 index 0000000..4231d0c --- /dev/null +++ b/lims_sale/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/lims_sale/readme/CONFIGURE.md b/lims_sale/readme/CONFIGURE.md new file mode 100644 index 0000000..6b75c98 --- /dev/null +++ b/lims_sale/readme/CONFIGURE.md @@ -0,0 +1,20 @@ +========================== +LIMS Sale Integration +========================== +This module integrates **Odoo LIMS** with **Sales Orders**, allowing laboratories +to sell LIMS services directly as products. +When a sale order is confirmed, corresponding LIMS Orders are automatically created +based on the configuration defined on each product. + +The module supports multiple creation strategies for LIMS Orders via the field +``lims_tracking`` on the product template. + +* **No** – No LIMS order is created. +* **Per Sales Order** – One LIMS order is created for the whole sale order. +* **Per Sales Order Line** – One LIMS order is created for each sale order line. +* **Per Quantity** – One LIMS order is created per quantity unit in the sale line. + +Each LIMS Order is generated using the selected **LIMS Template**, carrying details +such as categories, operator, and test configurations defined within the template. + +This module extends the `lims` and `sale` modules. diff --git a/lims_sale/readme/CONTRIBUTORS.md b/lims_sale/readme/CONTRIBUTORS.md new file mode 100644 index 0000000..c82e339 --- /dev/null +++ b/lims_sale/readme/CONTRIBUTORS.md @@ -0,0 +1,4 @@ + * Rodrigo Madrid + * Adriana Alpizar + * Maxime Chambreuil + * Hardik Suthar \ No newline at end of file diff --git a/lims_sale/readme/DESCRIPTION.md b/lims_sale/readme/DESCRIPTION.md new file mode 100644 index 0000000..b0d66cd --- /dev/null +++ b/lims_sale/readme/DESCRIPTION.md @@ -0,0 +1,20 @@ +========================== +LIMS Sale Integration +========================== +This module integrates **Odoo LIMS** with **Sales Orders**, allowing laboratories +to sell LIMS services directly as products. +When a sale order is confirmed, corresponding LIMS Orders are automatically created +based on the configuration defined on each product. + +The module supports multiple creation strategies for LIMS Orders via the field +``lims_tracking`` on the product template. + +* **No** – No LIMS order is created. +* **Per Sales Order** – One LIMS order is created for the whole sale order. +* **Per Sales Order Line** – One LIMS order is created for each sale order line. +* **Per Quantity** – One LIMS order is created per quantity unit in the sale line. + +Each LIMS Order is generated using the selected **LIMS Template**, carrying details +such as categories, operator, and test configurations defined within the template. + +This module extends the `lims` and `sale` modules. \ No newline at end of file diff --git a/lims_sale/readme/USAGE.md b/lims_sale/readme/USAGE.md new file mode 100644 index 0000000..50dd719 --- /dev/null +++ b/lims_sale/readme/USAGE.md @@ -0,0 +1,11 @@ +Usage +===== +1. Go to *Sales › Products* and open or create a product. +2. Under the *LIMS Configuration* section: + - Select a **LIMS Template**. + - Choose the **LIMS Tracking** mode (No / Order / Line / Quantity). +3. Create a **Sale Order** and add products with a configured LIMS Template. +4. Confirm the sale order: + - LIMS Orders will be automatically generated. + - A smart button **“LIMS Orders”** appears on the sale order form. +5. Click the button to view all generated LIMS Orders linked to the sale. diff --git a/lims_sale/static/description/index.html b/lims_sale/static/description/index.html new file mode 100644 index 0000000..2301734 --- /dev/null +++ b/lims_sale/static/description/index.html @@ -0,0 +1,492 @@ + + + + + +Laboratory Information Management System (LIMS) Sales + + + +
+

Laboratory Information Management System (LIMS) Sales

+ + +

Beta License: AGPL-3 OCA/connector-lims Translate me on Weblate Try me on Runboat

+
+

========================== LIMS Sale Integration

+
+
This module integrates Odoo LIMS with Sales Orders, allowing +laboratories to sell LIMS services directly as products.
+
When a sale order is confirmed, corresponding LIMS Orders are +automatically created based on the configuration defined on each +product.
+
+

The module supports multiple creation strategies for LIMS Orders via the +field lims_tracking on the product template.

+
    +
  • No – No LIMS order is created.
  • +
  • Per Sales Order – One LIMS order is created for the whole sale +order.
  • +
  • Per Sales Order Line – One LIMS order is created for each sale +order line.
  • +
  • Per Quantity – One LIMS order is created per quantity unit in the +sale line.
  • +
+

Each LIMS Order is generated using the selected LIMS Template, +carrying details such as categories, operator, and test configurations +defined within the template.

+

This module extends the lims and sale modules.

+

Table of contents

+
+
+

Configuration

+
+
+

========================== LIMS Sale Integration

+
+
This module integrates Odoo LIMS with Sales Orders, allowing +laboratories to sell LIMS services directly as products.
+
When a sale order is confirmed, corresponding LIMS Orders are +automatically created based on the configuration defined on each +product.
+
+

The module supports multiple creation strategies for LIMS Orders via the +field lims_tracking on the product template.

+
    +
  • No – No LIMS order is created.
  • +
  • Per Sales Order – One LIMS order is created for the whole sale +order.
  • +
  • Per Sales Order Line – One LIMS order is created for each sale +order line.
  • +
  • Per Quantity – One LIMS order is created per quantity unit in the +sale line.
  • +
+

Each LIMS Order is generated using the selected LIMS Template, +carrying details such as categories, operator, and test configurations +defined within the template.

+

This module extends the lims and sale modules.

+
+
+

Usage

+
+
+

Usage

+
    +
  1. Go to Sales › Products and open or create a product.
  2. +
  3. Under the LIMS Configuration section:
      +
    • Select a LIMS Template.
    • +
    • Choose the LIMS Tracking mode (No / Order / Line / Quantity).
    • +
    +
  4. +
  5. Create a Sale Order and add products with a configured LIMS +Template.
  6. +
  7. Confirm the sale order:
      +
    • LIMS Orders will be automatically generated.
    • +
    • A smart button “LIMS Orders” appears on the sale order form.
    • +
    +
  8. +
  9. Click the button to view all generated LIMS Orders linked to the +sale.
  10. +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Open Source Integrators
  • +
+
+ +
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

Current maintainers:

+

max3903 jasiel-osi Hardik-OSI

+

This module is part of the OCA/connector-lims project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/lims_sale/tests/__init__.py b/lims_sale/tests/__init__.py new file mode 100644 index 0000000..c5bd5a3 --- /dev/null +++ b/lims_sale/tests/__init__.py @@ -0,0 +1,5 @@ +# Copyright (C) 2025 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import common +from . import test_sale_order diff --git a/lims_sale/tests/common.py b/lims_sale/tests/common.py new file mode 100644 index 0000000..8bc9648 --- /dev/null +++ b/lims_sale/tests/common.py @@ -0,0 +1,37 @@ +# Copyright (C) 2025 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.addons.lims.tests.common import LIMSCommon + + +class LIMSCommon(LIMSCommon): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.cbc_product, cls.wbc_product, cls.rbc_product = cls.env[ + "product.template" + ].create( + [ + { + "name": "Complete Blood Count (CBC)", + "type": "service", + "lims_tracking": "order", + "list_price": 100, + "lims_template_id": cls.lims_template.id, + }, + { + "name": "White blood cells (WBC)", + "type": "service", + "lims_tracking": "line", + "list_price": 50, + "lims_template_id": cls.lims_template.id, + }, + { + "name": "Red blood cells (RBC)", + "type": "service", + "lims_tracking": "quantity", + "list_price": 50, + "lims_template_id": cls.lims_template.id, + }, + ] + ) diff --git a/lims_sale/tests/test_sale_order.py b/lims_sale/tests/test_sale_order.py new file mode 100644 index 0000000..3e6c415 --- /dev/null +++ b/lims_sale/tests/test_sale_order.py @@ -0,0 +1,99 @@ +# Copyright (C) 2025 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.fields import Command + +from odoo.addons.lims_sale.tests.common import LIMSCommon + + +class TestLIMSSaleOrder(LIMSCommon): + def setUp(self): + super().setUp() + # Sample partner for test orders + self.partner_id = self.env.ref("base.res_partner_12", raise_if_not_found=False) + + # Create a test Sale Order with multiple products + self.sale_order = self.env["sale.order"].create( + { + "partner_id": self.partner_id.id, + "order_line": [ + Command.create( + {"product_id": self.cbc_product.product_variant_ids.id} + ), + Command.create( + {"product_id": self.wbc_product.product_variant_ids.id} + ), + Command.create( + {"product_id": self.rbc_product.product_variant_ids.id} + ), + ], + } + ) + + def test_01_sale_order_confirmation_creates_lims_orders(self): + """Verify that confirming a Sale Order + automatically creates related LIMS Orders.""" + sale_order = self.sale_order + + # Initially no linked LIMS orders + self.assertFalse( + sale_order.lims_order_count, + "Sale Order should not have linked LIMS Orders before confirmation.", + ) + + # Confirm sale order → should trigger LIMS Order creation + sale_order.action_confirm() + sale_order._compute_lims_order_count() + + self.assertTrue( + sale_order.lims_order_count, + "Sale Order confirmation should create related LIMS Orders.", + ) + + # Test the action returning the LIMS Orders view + sale_order.action_view_lims_orders() + + # Validate LIMS Orders linkage + lims_orders = self.env["lims.order"].search( + [("sale_order_id", "=", sale_order.id)] + ) + self.assertTrue( + lims_orders, "LIMS Orders should exist and be linked to the Sale Order." + ) + + # Check reverse linkage from LIMS Order to Sale Order + lims_orders[0].action_open_sale_order() + + def test_02_sale_order_with_multiple_quantities_creates_multiple_lims_orders(self): + product_uom_qty = 5 + + sale_order_multi_qty = self.env["sale.order"].create( + { + "partner_id": self.partner_id.id, + "order_line": [ + Command.create( + { + "product_id": self.rbc_product.product_variant_ids.id, + "product_uom_qty": product_uom_qty, + } + ), + ], + } + ) + + # Before confirmation — lims_order_count should not match qty + self.assertNotEqual( + sale_order_multi_qty.lims_order_count, + product_uom_qty, + "Before confirmation, LIMS order count should not match ordered quantity.", + ) + + # After confirmation — should create LIMS Orders equal to ordered quantity + sale_order_multi_qty.action_confirm() + sale_order_multi_qty._compute_lims_order_count() + + self.assertEqual( + sale_order_multi_qty.lims_order_count, + product_uom_qty, + "After confirmation, LIMS Orders count should match ordered quantity.", + ) diff --git a/lims_sale/views/lms_order_view.xml b/lims_sale/views/lms_order_view.xml new file mode 100644 index 0000000..5fd0513 --- /dev/null +++ b/lims_sale/views/lms_order_view.xml @@ -0,0 +1,18 @@ + + + lims.order.form.inherit.sale.button + lims.order + + + + + + + + diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 0000000..fef89ce --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1 @@ +odoo-addon-lims @ git+https://github.com/OCA/connector-lims.git@refs/pull/20/head#subdirectory=lims