Skip to content

Commit

Permalink
Merge PR #733 into 13.0
Browse files Browse the repository at this point in the history
Signed-off-by pedrobaeza
  • Loading branch information
OCA-git-bot committed Dec 17, 2024
2 parents c48386e + bc478bf commit d712123
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 35 deletions.
1 change: 1 addition & 0 deletions purchase_sale_stock_inter_company/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
from . import res_company
from . import res_config
from . import stock_picking
from . import stock_move_line
99 changes: 99 additions & 0 deletions purchase_sale_stock_inter_company/models/stock_move_line.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
from odoo import api, models


class StockMoveLine(models.Model):
_inherit = "stock.move.line"

@api.model_create_multi
def create(self, vals_list):
new_move_lines = super().create(vals_list)
for move_line in new_move_lines.filtered(lambda x: x.state == "done"):
po_moves = move_line._get_stock_moves_to_sync()
for po_move in po_moves:
po_move_line_vals = po_move._prepare_move_line_vals(
quantity=move_line.qty_done
)
if move_line.lot_id:
dest_lot = move_line._get_or_create_lot_intercompany(
po_move.company_id
)
po_move_line_vals["lot_id"] = dest_lot.id
po_move_line_vals["qty_done"] = move_line.qty_done
self.sudo().create(po_move_line_vals)
return new_move_lines

def write(self, vals):
moves_to_sync = {}
fields_to_sync = self._get_fields_to_sync_intercompany()
if fields_to_sync.intersection(set(vals.keys())):
for move_line in self:
purchase_line_origin = (
move_line.move_id.sale_line_id.sudo().auto_purchase_line_id
)
if move_line.state == "done" and purchase_line_origin:
moves_to_sync.setdefault(move_line, move_line.lot_id.name or "")
res = super().write(vals)
for move_line, lot_name in moves_to_sync.items():
move_line._sync_intercompany_move(lot_name, vals)
return res

def _sync_intercompany_move(self, lot_name, vals):
self.ensure_one()
fields_to_sync = self._get_fields_to_sync_intercompany()
po_moves = self._get_stock_moves_to_sync()
for po_move in po_moves:
po_move_line = po_move.move_line_ids.filtered(
lambda x: not self.lot_id or x.lot_id.name == lot_name
)
if not po_move_line:
continue
vals_to_write = {}
for field in fields_to_sync:
if field not in vals:
continue
field_value = self[field]
if field == "lot_id" and field_value:
dest_lot = self._get_or_create_lot_intercompany(
po_move_line.company_id
)
field_value = dest_lot.id
vals_to_write[field] = field_value
if vals_to_write:
po_move_line.write(vals_to_write)

def _get_stock_moves_to_sync(self):
"""
Get the stock moves that need to be synced with the intercompany move.
"""
self.ensure_one()
purchase_line_origin = self.move_id.sale_line_id.sudo().auto_purchase_line_id
po_moves = self.env["stock.move"]
if purchase_line_origin:
po_moves = purchase_line_origin.move_ids.filtered(
lambda m: m.picking_id
== self.move_id.picking_id.intercompany_picking_id
and m.product_id == self.product_id
)
return po_moves

@api.model
def _get_fields_to_sync_intercompany(self):
return {"qty_done", "lot_id"}

def _get_or_create_lot_intercompany(self, dest_company):
# search if the same lot exists in destination company
self.ensure_one()
ProductionLot = self.env["stock.production.lot"].sudo()
lot = self.lot_id
dest_lot = ProductionLot.search(
[
("product_id", "=", lot.product_id.id),
("name", "=", lot.name),
("company_id", "=", dest_company.id),
],
limit=1,
)
if not dest_lot:
# if it doesn't exist, create it by copying from original company
dest_lot = lot.sudo().copy({"company_id": dest_company.id})
return dest_lot
64 changes: 29 additions & 35 deletions purchase_sale_stock_inter_company/models/stock_picking.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@
# Copyright 2023 Tecnativa - Carolina Fernandez
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import _, fields, models
from odoo.exceptions import UserError
from odoo import fields, models


class StockPicking(models.Model):
_inherit = "stock.picking"

intercompany_picking_id = fields.Many2one(comodel_name="stock.picking")
intercompany_picking_id = fields.Many2one(comodel_name="stock.picking", copy=False)

def action_done(self):
for pick in self.filtered(
Expand All @@ -19,46 +18,41 @@ def action_done(self):
purchase = pick.sale_id.auto_purchase_order_id
if not purchase:
continue
purchase.picking_ids.write({"intercompany_picking_id": pick.id})
if not pick.intercompany_picking_id and purchase.picking_ids[0]:
pick.write({"intercompany_picking_id": purchase.picking_ids[0]})
po_picking_pending = purchase.picking_ids.filtered(
lambda x: x.state not in ["done", "cancel"]
)
po_picking_pending.intercompany_picking_id = pick.id
if not pick.intercompany_picking_id and po_picking_pending[0]:
pick.intercompany_picking_id = po_picking_pending[0]
for move in pick.move_lines:
move_lines = move.move_line_ids
po_move_lines = move.sale_line_id.auto_purchase_line_id.move_ids.filtered(
move_lines = move.move_line_ids.filtered(lambda x: x.qty_done > 0)
po_move_pending = move.sale_line_id.auto_purchase_line_id.move_ids.filtered(
lambda x, ic_pick=pick.intercompany_picking_id: x.picking_id
== ic_pick
).mapped(
"move_line_ids"
and x.state not in ["done", "cancel"]
)
if not len(move_lines) == len(po_move_lines):
raise UserError(
_(
"Mismatch between move lines with the "
"corresponding PO %s for assigning "
"quantities and lots from %s for product %s"
)
% (purchase.name, pick.name, move.product_id.name)
)
po_move_lines = po_move_pending.mapped("move_line_ids")
move_line_diff = len(move_lines) - len(po_move_lines)
# generate new move lines if needed
# example: In purchase order of C1, we have 2 move lines
# and in reception of C2, we have 3 move lines(with lot or serial number)
# then we need to create 1 more move line in purchase order of C1
if move_line_diff > 0:
new_move_line_vals = []
for _index in range(move_line_diff):
vals = po_move_pending._prepare_move_line_vals()
new_move_line_vals.append(vals)
po_move_lines |= po_move_lines.create(new_move_line_vals)
# check and assign lots here
# if len(move_lines) != (po_move_lines)
# the zip will stop at the shortest list(only with qty_done > 0)
# list(zip([1, 2], [1, 2, 3, 4])) = [(1, 1), (2, 2)]
# list(zip([1, 2, 3, 4], [1, 2])) = [(1, 1), (2, 2)]
for ml, po_ml in zip(move_lines, po_move_lines):
lot_id = ml.lot_id
if not lot_id:
continue
# search if the same lot exists in destination company
dest_lot_id = (
self.env["stock.production.lot"]
.sudo()
.search(
[
("product_id", "=", lot_id.product_id.id),
("name", "=", lot_id.name),
("company_id", "=", po_ml.company_id.id),
],
limit=1,
)
)
if not dest_lot_id:
# if it doesn't exist, create it by copying from original company
dest_lot_id = lot_id.copy({"company_id": po_ml.company_id.id})
po_ml.lot_id = dest_lot_id
dest_lot = ml._get_or_create_lot_intercompany(po_ml.company_id)
po_ml.lot_id = dest_lot
return super().action_done()
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@ def setUpClass(cls):
cls.serial_3 = cls._create_serial_and_quant(
cls.stockable_product_serial, "333", cls.company_b
)
cls.serial_4 = cls._create_serial_and_quant(
cls.stockable_product_serial, "444", cls.company_b
)
cls.serial_5 = cls._create_serial_and_quant(
cls.stockable_product_serial, "555", cls.company_b
)

def test_deliver_to_warehouse_a(self):
self.purchase_company_a.picking_type_id = self.warehouse_a.in_type_id
Expand Down Expand Up @@ -208,3 +214,21 @@ def test_sync_picking_lot(self):
po_lots,
msg="Serial 333 already existed, a new one shouldn't have been created",
)
# create a new lot in the picking done
move_line_vals = so_move._prepare_move_line_vals()
move_line_vals.update({"lot_id": self.serial_4.id, "qty_done": 1})
new_move_line = self.env["stock.move.line"].create(move_line_vals)
self.assertIn(
self.serial_4.name,
po_picking_id.mapped("move_lines.move_line_ids.lot_id.name"),
)
# change the lot in the picking done
new_move_line.lot_id = self.serial_5
self.assertIn(
self.serial_5.name,
po_picking_id.mapped("move_lines.move_line_ids.lot_id.name"),
)
self.assertNotIn(
self.serial_4.name,
po_picking_id.mapped("move_lines.move_line_ids.lot_id.name"),
)

0 comments on commit d712123

Please sign in to comment.