Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[IMP] purchase_lot : lot_id is computed from stock moves so that it c… #2247

Open
wants to merge 7 commits into
base: 16.0
Choose a base branch
from
26 changes: 24 additions & 2 deletions purchase_lot/models/purchase_order_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,27 @@ class PurchaseOrderLine(models.Model):
_inherit = "purchase.order.line"

lot_id = fields.Many2one(
"stock.lot", string="Serial Number", readonly=True, copy=False
"stock.lot",
string="Serial Number",
readonly=True,
copy=False,
compute="_compute_lot_id",
store=True,
)

@api.depends(
"move_dest_ids.restrict_lot_id",
"move_ids.restrict_lot_id",
"sale_line_id.lot_id",
)
def _compute_lot_id(self):
for line in self:
line.lot_id = (
line.move_dest_ids.restrict_lot_id
| line.move_ids.restrict_lot_id
| line.sale_line_id.lot_id
)

@api.model
def _prepare_purchase_order_line_from_procurement(
self, product_id, product_qty, product_uom, company_id, values, po
Expand Down Expand Up @@ -46,7 +64,11 @@ def _find_candidate(
values,
):
lot_id = values.get("restrict_lot_id", False)
self = self.filtered(lambda l: l.lot_id.id == lot_id)
moves_dest = values.get("move_dest_ids", False)
if lot_id:
self = self.filtered(lambda l: l.lot_id.id == lot_id)
elif self.product_id.tracking != "none" and moves_dest:
self = self.filtered(lambda l: moves_dest in l.move_dest_ids)
return super()._find_candidate(
product_id,
product_qty,
Expand Down
2 changes: 1 addition & 1 deletion purchase_lot/models/stock_rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ class StockRule(models.Model):
@api.model
def _get_procurements_to_merge_groupby(self, procurement):
return (
procurement.values.get("restrict_lot_id"),
procurement.values.get("move_dest_ids"),
super()._get_procurements_to_merge_groupby(procurement),
)
12 changes: 7 additions & 5 deletions purchase_lot/static/description/index.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
Expand All @@ -9,10 +8,11 @@

/*
:Author: David Goodger ([email protected])
:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
:Copyright: This stylesheet has been placed in the public domain.

Default cascading style sheet for the HTML output of Docutils.
Despite the name, some widely supported CSS2 features are used.

See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet.
Expand Down Expand Up @@ -275,7 +275,7 @@
margin-left: 2em ;
margin-right: 2em }

pre.code .ln { color: grey; } /* line numbers */
pre.code .ln { color: gray; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
Expand All @@ -301,7 +301,7 @@
span.pre {
white-space: pre }

span.problematic {
span.problematic, pre.problematic {
color: red }

span.section-subtitle {
Expand Down Expand Up @@ -410,7 +410,9 @@ <h2><a class="toc-backref" href="#toc-entry-4">Contributors</a></h2>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-5">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
</a>
<p>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.</p>
Expand Down
65 changes: 65 additions & 0 deletions purchase_lot/tests/test_purchase_lot.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# Copyright (C) 2022 Akretion (<http://www.akretion.com>).
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo.tests import Form
from odoo.tests.common import TransactionCase
from odoo.tools import mute_logger


class TestPurchaseLot(TransactionCase):
Expand Down Expand Up @@ -31,6 +33,24 @@ def setUpClass(cls):
}
)
cls.out_picking_type = cls.env.ref("stock.picking_type_out")
cls.supplier = cls.env["res.partner"].create({"name": "Vendor"})
cls.customer = cls.env["res.partner"].create({"name": "Customer"})
cls.external_serial_product = cls.env["product.product"].create(
{
"name": "Pen drive",
"type": "product",
"categ_id": cls.env.ref("product.product_category_1").id,
"lst_price": 100.0,
"standard_price": 0.0,
"uom_id": cls.env.ref("uom.product_uom_unit").id,
"uom_po_id": cls.env.ref("uom.product_uom_unit").id,
"seller_ids": [
(0, 0, {"delay": 1, "partner_id": cls.supplier.id, "min_qty": 2.0})
],
"route_ids": [(4, buy_route.id, 0), (4, mto_route.id, 0)],
}
)
cls.external_serial_product.product_tmpl_id.tracking = "serial"

def test_purchase_lot(self):
lot1 = self.env["stock.lot"].create(
Expand Down Expand Up @@ -88,3 +108,48 @@ def test_purchase_lot(self):
self.assertEqual(pol1.lot_id.id, lot1.id)
pol1.order_id.button_confirm()
self.assertEqual(pol1.move_ids.restrict_lot_id.id, lot1.id)

def test_lot_propagation(self):
# Required for `route_id` to be visible in the view
self.env.user.groups_id += self.env.ref("stock.group_adv_location")

# Create a sales order with a line of 200 PCE incoming shipment,
# with route_id buy
so_form = Form(self.env["sale.order"])
so_form.partner_id = self.customer
so_form.payment_term_id = self.env.ref(
"account.account_payment_term_end_following_month"
)
with mute_logger("odoo.tests.common.onchange"):
# otherwise complains that there's not enough inventory and
# apparently that's normal according to @jco and @sle
with so_form.order_line.new() as line:
line.product_id = self.external_serial_product
line.product_uom_qty = 200
line.price_unit = 1.00
line.route_id = self.env.ref("purchase_stock.route_warehouse0_buy")

sale_order = so_form.save()
sale_order.order_line.lot_id = self.env["stock.lot"].create(
{
"name": "Seq test DS pdt",
"product_id": self.external_serial_product.id,
}
)
initial_lot = sale_order.order_line.lot_id
# Confirm sales order
sale_order.action_confirm()

# Check a quotation was created to a certain vendor
# and confirm so it becomes a confirmed purchase order
purchase = self.env["purchase.order"].search(
[("partner_id", "=", self.supplier.id)]
)
self.assertEqual(purchase.state, "draft")
self.assertTrue(purchase.order_line.lot_id)
self.assertEqual(purchase.order_line.lot_id, initial_lot)
purchase.button_confirm()
purchase.button_approve()
self.assertTrue(purchase.picking_ids.move_ids.restrict_lot_id)
self.assertTrue(purchase.order_line.lot_id)
self.assertEqual(purchase.order_line.lot_id, initial_lot)
Loading