diff --git a/stock_svl_vendor/README.rst b/stock_svl_vendor/README.rst new file mode 100644 index 00000000..2b8421d4 --- /dev/null +++ b/stock_svl_vendor/README.rst @@ -0,0 +1,64 @@ +============================ +Stock Valuation Layer Vendor +============================ + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:7bb64c277e472c06137f6cf7274c16963ef0a6e00a2a837a9f8cf2dcd5a06433 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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-qrtl%2Fhls--custom-lightgray.png?logo=github + :target: https://github.com/qrtl/hls-custom/tree/18.0/stock_svl_vendor + :alt: qrtl/hls-custom + +|badge1| |badge2| |badge3| + +This module adds a vendor field to stock valuation layers, populated +from the purchase order linked to the related stock move. + +**Table of contents** + +.. contents:: + :local: + +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 +------- + +* Quartile + +Maintainers +----------- + +.. |maintainer-nobuQuartile| image:: https://github.com/nobuQuartile.png?size=40px + :target: https://github.com/nobuQuartile + :alt: nobuQuartile + +Current maintainer: + +|maintainer-nobuQuartile| + +This module is part of the `qrtl/hls-custom `_ project on GitHub. + +You are welcome to contribute. diff --git a/stock_svl_vendor/__init__.py b/stock_svl_vendor/__init__.py new file mode 100644 index 00000000..6d58305f --- /dev/null +++ b/stock_svl_vendor/__init__.py @@ -0,0 +1,2 @@ +from . import models +from .hooks import pre_init_hook diff --git a/stock_svl_vendor/__manifest__.py b/stock_svl_vendor/__manifest__.py new file mode 100644 index 00000000..87fa4b26 --- /dev/null +++ b/stock_svl_vendor/__manifest__.py @@ -0,0 +1,16 @@ +# Copyright 2026 Quartile (https://www.quartile.co) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Stock Valuation Layer Vendor", + "summary": "Store the vendor on stock valuation layers created from purchases.", + "version": "18.0.1.0.0", + "author": "Quartile", + "website": "https://www.quartile.co", + "category": "Inventory", + "license": "AGPL-3", + "depends": ["purchase_stock"], + "data": ["views/stock_valuation_layer_views.xml"], + "pre_init_hook": "pre_init_hook", + "maintainers": ["nobuQuartile"], + "installable": True, +} diff --git a/stock_svl_vendor/hooks.py b/stock_svl_vendor/hooks.py new file mode 100644 index 00000000..8bf95893 --- /dev/null +++ b/stock_svl_vendor/hooks.py @@ -0,0 +1,20 @@ +# Copyright 2026 Quartile (https://www.quartile.co) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo.tools.sql import column_exists, create_column + + +def pre_init_hook(env): + if column_exists(env.cr, "stock_valuation_layer", "vendor_id"): + return + create_column(env.cr, "stock_valuation_layer", "vendor_id", "int4") + env.cr.execute( + """ + UPDATE stock_valuation_layer svl + SET vendor_id = po.partner_id + FROM stock_move sm + JOIN purchase_order_line pol ON pol.id = sm.purchase_line_id + JOIN purchase_order po ON po.id = pol.order_id + WHERE svl.stock_move_id = sm.id + """ + ) diff --git a/stock_svl_vendor/i18n/ja.po b/stock_svl_vendor/i18n/ja.po new file mode 100644 index 00000000..4a358422 --- /dev/null +++ b/stock_svl_vendor/i18n/ja.po @@ -0,0 +1,31 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_svl_vendor +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2026-07-13 04:11+0000\n" +"PO-Revision-Date: 2026-07-13 04:11+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: stock_svl_vendor +#: model:ir.model,name:stock_svl_vendor.model_stock_valuation_layer +msgid "Stock Valuation Layer" +msgstr "在庫評価レイヤ" + +#. module: stock_svl_vendor +#: model:ir.model.fields,field_description:stock_svl_vendor.field_stock_valuation_layer__vendor_id +msgid "Vendor" +msgstr "仕入先" + +#. module: stock_svl_vendor +#: model:ir.model.fields,help:stock_svl_vendor.field_stock_valuation_layer__vendor_id +msgid "Vendor of the purchase order linked to the stock move, if any." +msgstr "在庫移動に紐づく購買オーダの仕入先(存在する場合)。" diff --git a/stock_svl_vendor/models/__init__.py b/stock_svl_vendor/models/__init__.py new file mode 100644 index 00000000..f75b2df3 --- /dev/null +++ b/stock_svl_vendor/models/__init__.py @@ -0,0 +1 @@ +from . import stock_valuation_layer diff --git a/stock_svl_vendor/models/stock_valuation_layer.py b/stock_svl_vendor/models/stock_valuation_layer.py new file mode 100644 index 00000000..b13f9fff --- /dev/null +++ b/stock_svl_vendor/models/stock_valuation_layer.py @@ -0,0 +1,31 @@ +# Copyright 2026 Quartile (https://www.quartile.co) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class StockValuationLayer(models.Model): + _inherit = "stock.valuation.layer" + + vendor_id = fields.Many2one( + "res.partner", + string="Vendor", + readonly=True, + index=True, + help="Vendor of the purchase order linked to the stock move, if any.", + ) + + @api.model_create_multi + def create(self, vals_list): + move_ids = { + vals["stock_move_id"] for vals in vals_list if vals.get("stock_move_id") + } + vendor_by_move = { + move.id: move.purchase_line_id.order_id.partner_id.id + for move in self.env["stock.move"].browse(move_ids) + } + for vals in vals_list: + vendor_id = vendor_by_move.get(vals.get("stock_move_id")) + if vendor_id: + vals["vendor_id"] = vendor_id + return super().create(vals_list) diff --git a/stock_svl_vendor/pyproject.toml b/stock_svl_vendor/pyproject.toml new file mode 100644 index 00000000..4231d0cc --- /dev/null +++ b/stock_svl_vendor/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/stock_svl_vendor/readme/DESCRIPTION.md b/stock_svl_vendor/readme/DESCRIPTION.md new file mode 100644 index 00000000..96cc0724 --- /dev/null +++ b/stock_svl_vendor/readme/DESCRIPTION.md @@ -0,0 +1,2 @@ +This module adds a vendor field to stock valuation layers, populated from the +purchase order linked to the related stock move. diff --git a/stock_svl_vendor/static/description/index.html b/stock_svl_vendor/static/description/index.html new file mode 100644 index 00000000..6a54424c --- /dev/null +++ b/stock_svl_vendor/static/description/index.html @@ -0,0 +1,412 @@ + + + + + +Stock Valuation Layer Vendor + + + +
+

Stock Valuation Layer Vendor

+ + +

Beta License: AGPL-3 qrtl/hls-custom

+

This module adds a vendor field to stock valuation layers, populated +from the purchase order linked to the related stock move.

+

Table of contents

+ +
+

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

+
    +
  • Quartile
  • +
+
+
+

Maintainers

+

Current maintainer:

+

nobuQuartile

+

This module is part of the qrtl/hls-custom project on GitHub.

+

You are welcome to contribute.

+
+
+
+ + diff --git a/stock_svl_vendor/tests/__init__.py b/stock_svl_vendor/tests/__init__.py new file mode 100644 index 00000000..65d94fc9 --- /dev/null +++ b/stock_svl_vendor/tests/__init__.py @@ -0,0 +1 @@ +from . import test_stock_svl_vendor diff --git a/stock_svl_vendor/tests/test_stock_svl_vendor.py b/stock_svl_vendor/tests/test_stock_svl_vendor.py new file mode 100644 index 00000000..cec67609 --- /dev/null +++ b/stock_svl_vendor/tests/test_stock_svl_vendor.py @@ -0,0 +1,104 @@ +# Copyright 2026 Quartile (https://www.quartile.co) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import Command + +from odoo.addons.base.tests.common import BaseCommon + + +class TestStockSvlVendor(BaseCommon): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.vendor = cls.env["res.partner"].create({"name": "Test Vendor"}) + cls.product = cls.env["product.product"].create( + {"name": "Test Product", "is_storable": True, "standard_price": 100.0} + ) + cls.supplier_location = cls.env.ref("stock.stock_location_suppliers") + cls.stock_location = cls.env.ref("stock.stock_location_stock") + purchase_order = cls.env["purchase.order"].create( + { + "partner_id": cls.vendor.id, + "order_line": [ + Command.create( + { + "product_id": cls.product.id, + "name": cls.product.name, + "product_qty": 10.0, + "product_uom": cls.product.uom_id.id, + "price_unit": 100.0, + } + ) + ], + } + ) + cls.purchase_line = purchase_order.order_line + + def _create_move(self, purchase_line=False): + return self.env["stock.move"].create( + { + "name": "Test move", + "product_id": self.product.id, + "product_uom_qty": 10.0, + "product_uom": self.product.uom_id.id, + "location_id": self.supplier_location.id, + "location_dest_id": self.stock_location.id, + "purchase_line_id": purchase_line.id if purchase_line else False, + } + ) + + def _create_svl(self, stock_move=False): + vals = { + "product_id": self.product.id, + "company_id": self.env.company.id, + "quantity": 10.0, + "value": 1000.0, + "unit_cost": 100.0, + } + if stock_move: + vals["stock_move_id"] = stock_move.id + return self.env["stock.valuation.layer"].create(vals) + + def test_vendor_id_set_from_purchase_move(self): + move = self._create_move(purchase_line=self.purchase_line) + svl = self._create_svl(stock_move=move) + self.assertEqual(svl.vendor_id, self.vendor) + + def test_vendor_id_empty_without_purchase(self): + move = self._create_move() + svl = self._create_svl(stock_move=move) + self.assertFalse(svl.vendor_id) + + def test_vendor_id_empty_without_move(self): + svl = self._create_svl() + self.assertFalse(svl.vendor_id) + + def test_vendor_id_set_from_purchase_move_batch(self): + vendor_2 = self.env["res.partner"].create({"name": "Test Vendor 2"}) + purchase_line_2 = self.purchase_line.order_id.copy( + {"partner_id": vendor_2.id} + ).order_line + move_1 = self._create_move(purchase_line=self.purchase_line) + move_2 = self._create_move(purchase_line=purchase_line_2) + svl_1, svl_2 = self.env["stock.valuation.layer"].create( + [ + { + "product_id": self.product.id, + "company_id": self.env.company.id, + "quantity": 10.0, + "value": 1000.0, + "unit_cost": 100.0, + "stock_move_id": move_1.id, + }, + { + "product_id": self.product.id, + "company_id": self.env.company.id, + "quantity": 5.0, + "value": 500.0, + "unit_cost": 100.0, + "stock_move_id": move_2.id, + }, + ] + ) + self.assertEqual(svl_1.vendor_id, self.vendor) + self.assertEqual(svl_2.vendor_id, vendor_2) diff --git a/stock_svl_vendor/views/stock_valuation_layer_views.xml b/stock_svl_vendor/views/stock_valuation_layer_views.xml new file mode 100644 index 00000000..044300b3 --- /dev/null +++ b/stock_svl_vendor/views/stock_valuation_layer_views.xml @@ -0,0 +1,23 @@ + + + + stock.valuation.layer.form + stock.valuation.layer + + + + + + + + + stock.valuation.layer.list + stock.valuation.layer + + + + + + + +