Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions mrp_subcontracting_serial_mass_produce/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
=====================================
MRP Subcontracting Serial Mass Record
=====================================

This module automatically records subcontracted components after using
``Mass Produce`` on a subcontracting manufacturing order with serial-tracked
finished products.
4 changes: 4 additions & 0 deletions mrp_subcontracting_serial_mass_produce/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright 2026 Quartile Limited
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from . import wizard
13 changes: 13 additions & 0 deletions mrp_subcontracting_serial_mass_produce/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright 2026 Quartile
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

{
"name": "MRP Subcontracting Serial Mass Produce",
"version": "16.0.1.0.0",
"author": "Quartile, Odoo Community Association (OCA)",
"category": "Manufacturing",
"website": "https://github.com/OCA/manufacture",
"depends": ["mrp_subcontracting"],
"license": "AGPL-3",
"installable": True,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
* `Quartile <https://www.quartile.co>`_:

* Toshikimi Shigenobu
3 changes: 3 additions & 0 deletions mrp_subcontracting_serial_mass_produce/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
This module automatically records subcontracted components after using
``Mass Produce`` on a subcontracting manufacturing order with serial-tracked
finished products.
4 changes: 4 additions & 0 deletions mrp_subcontracting_serial_mass_produce/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright 2026 Quartile Limited
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from . import test_mrp_subcontracting_serial_mass_produce
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Copyright 2026 Quartile Limited
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo.tests import Form

from odoo.addons.mrp_subcontracting.tests.common import TestMrpSubcontractingCommon


class TestMrpSubcontractingSerialMassProduce(TestMrpSubcontractingCommon):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.finished.tracking = "serial"
cls.subcontract_location = (
cls.subcontractor_partner1.property_stock_subcontractor
)
picking_form = Form(cls.env["stock.picking"])
picking_form.picking_type_id = cls.env.ref("stock.picking_type_in")
picking_form.partner_id = cls.subcontractor_partner1
with picking_form.move_ids_without_package.new() as move:
move.product_id = cls.finished
move.product_uom_qty = 2
cls.receipt = picking_form.save()
cls.receipt.action_confirm()
cls.env["stock.quant"]._update_available_quantity(
cls.comp1, cls.subcontract_location, 2
)
cls.env["stock.quant"]._update_available_quantity(
cls.comp2, cls.subcontract_location, 2
)

def test_mrp_subcontracting_serial_mass_produce_01(self):
production = self.receipt.move_ids.move_orig_ids.production_id
production.action_assign()
action = production.action_serial_mass_produce_wizard()
wizard = Form(self.env["stock.assign.serial"].with_context(**action["context"]))
wizard.next_serial_number = "SN0001"
wizard.next_serial_count = 2
action = wizard.save().generate_serial_numbers_production()
wizard = Form(self.env["stock.assign.serial"].browse(action["res_id"]))
wizard.save().apply()
productions = self.receipt.move_ids.move_orig_ids.production_id.sorted("id")
self.assertEqual(len(productions), 2)
self.assertEqual(
productions.mapped("subcontracting_has_been_recorded"), [True, True]
)
self.assertEqual(
productions.mapped("lot_producing_id.name"), ["SN0001", "SN0002"]
)
self.assertEqual(
sorted(self.receipt.move_line_ids.mapped("lot_id.name")),
["SN0001", "SN0002"],
)
1 change: 1 addition & 0 deletions mrp_subcontracting_serial_mass_produce/wizard/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import stock_assign_serial_numbers
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Copyright 2026 Quartile
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import models


class StockAssignSerialNumbers(models.TransientModel):
_inherit = "stock.assign.serial"

def _assign_serial_numbers(self, cancel_remaining_quantity=False):
serial_numbers = set(self._get_serial_numbers())
res = super()._assign_serial_numbers(cancel_remaining_quantity)
if not serial_numbers:
return res
productions = (
self.production_id.procurement_group_id.mrp_production_ids.filtered(
lambda mo: mo.state not in ("done", "cancel")
and not mo.subcontracting_has_been_recorded
and mo._get_subcontract_move()
and mo.lot_producing_id
and mo.lot_producing_id.name in serial_numbers
)
)
for production in productions:
production.subcontracting_record_component()
return res
6 changes: 6 additions & 0 deletions setup/mrp_subcontracting_serial_mass_produce/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import setuptools

setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)
Loading