Skip to content

Commit

Permalink
[MIG] purchase_manual_delivery: Migration to 17.0
Browse files Browse the repository at this point in the history
  • Loading branch information
StefanRijnhart committed Sep 26, 2024
1 parent 1dee0c5 commit 9cae351
Show file tree
Hide file tree
Showing 11 changed files with 157 additions and 97 deletions.
7 changes: 7 additions & 0 deletions purchase_manual_delivery/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ specific lines.
.. contents::
:local:

Configuration
=============

The ``Manual delivery`` checkbox can be edited on any RFQ, on the
``Other Information`` tab. To set the default value for new POs, go to
Settings -> Purchase -> Delivery.

Usage
=====

Expand Down
2 changes: 1 addition & 1 deletion purchase_manual_delivery/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
and adds the ability to manually generate them as the supplier confirms
the different purchase order lines.
""",
"version": "16.0.1.1.5",
"version": "17.0.1.0.0",
"license": "AGPL-3",
"author": "ForgeFlow S.L.," "Odoo Community Association (OCA)",
"website": "https://github.com/OCA/purchase-workflow",
Expand Down
23 changes: 16 additions & 7 deletions purchase_manual_delivery/models/purchase_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,25 @@ class PurchaseOrder(models.Model):

pending_to_receive = fields.Boolean(compute="_compute_pending_to_receive")
manual_delivery = fields.Boolean(
string="Purchase manual delivery?",
default=lambda self: self.env.company.purchase_manual_delivery,
string="Manual delivery",
compute="_compute_manual_delivery",
help=(
"Stock transfers need to be created manually to receive this PO's products"
),
readonly=False,
store=True,
)

@api.depends("company_id")
def _compute_manual_delivery(self):
"""The manual delivery option is derived from the company of the order"""
for po in self:
po.manual_delivery = po.company_id.purchase_manual_delivery

def _compute_pending_to_receive(self):
for order in self:
order.pending_to_receive = True
if all(
val is False for val in order.mapped("order_line.pending_to_receive")
):
if not any(order.mapped("order_line.pending_to_receive")):
order.pending_to_receive = False

def button_confirm_manual(self):
Expand Down Expand Up @@ -74,7 +83,7 @@ def _compute_existing_qty(self):
# This is a return to vendor
if move.to_refund:
total -= move.product_uom._compute_quantity(
move.product_uom_qty, line.product_uom
move.quantity, line.product_uom
)
elif (
move.origin_returned_move_id
Expand All @@ -90,7 +99,7 @@ def _compute_existing_qty(self):
pass

Check warning on line 99 in purchase_manual_delivery/models/purchase_order.py

View check run for this annotation

Codecov / codecov/patch

purchase_manual_delivery/models/purchase_order.py#L99

Added line #L99 was not covered by tests
else:
total += move.product_uom._compute_quantity(
move.product_uom_qty, line.product_uom
move.quantity, line.product_uom
)
line.existing_qty = total
if (
Expand Down
2 changes: 2 additions & 0 deletions purchase_manual_delivery/readme/CONFIGURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
The `Manual delivery` checkbox can be edited on any RFQ, on the `Other Information`
tab. To set the default value for new POs, go to Settings -> Purchase -> Delivery.
4 changes: 2 additions & 2 deletions purchase_manual_delivery/security/ir.model.access.csv
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
create_stock_picking_wizard_all,create_stock_picking_wizard_all,model_create_stock_picking_wizard,,1,1,1,1
create_stock_picking_wizard_line_all,create_stock_picking_wizard_line_all,model_create_stock_picking_wizard_line,,1,1,1,1
create_stock_picking_wizard_all,create_stock_picking_wizard_all,model_create_stock_picking_wizard,stock.group_stock_user,1,1,1,1
create_stock_picking_wizard_line_all,create_stock_picking_wizard_line_all,model_create_stock_picking_wizard_line,stock.group_stock_user,1,1,1,1
31 changes: 19 additions & 12 deletions purchase_manual_delivery/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -381,18 +381,25 @@ <h1 class="title">Purchase Manual Delivery</h1>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#usage" id="toc-entry-1">Usage</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-2">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-3">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-4">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-5">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-6">Maintainers</a></li>
<li><a class="reference internal" href="#configuration" id="toc-entry-1">Configuration</a></li>
<li><a class="reference internal" href="#usage" id="toc-entry-2">Usage</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-3">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-4">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-5">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-6">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-7">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="configuration">
<h1><a class="toc-backref" href="#toc-entry-1">Configuration</a></h1>
<p>The <tt class="docutils literal">Manual delivery</tt> checkbox can be edited on any RFQ, on the
<tt class="docutils literal">Other Information</tt> tab. To set the default value for new POs, go to
Settings -&gt; Purchase -&gt; Delivery.</p>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#toc-entry-1">Usage</a></h1>
<h1><a class="toc-backref" href="#toc-entry-2">Usage</a></h1>
<p>There are two main ways to use this module:</p>
<ul class="simple">
<li>From Purchase Order</li>
Expand All @@ -417,29 +424,29 @@ <h1><a class="toc-backref" href="#toc-entry-1">Usage</a></h1>
incoming shipment.</p>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-2">Bug Tracker</a></h1>
<h1><a class="toc-backref" href="#toc-entry-3">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/purchase-workflow/issues">GitHub Issues</a>.
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
<a class="reference external" href="https://github.com/OCA/purchase-workflow/issues/new?body=module:%20purchase_manual_delivery%0Aversion:%2017.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#toc-entry-3">Credits</a></h1>
<h1><a class="toc-backref" href="#toc-entry-4">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#toc-entry-4">Authors</a></h2>
<h2><a class="toc-backref" href="#toc-entry-5">Authors</a></h2>
<ul class="simple">
<li>ForgeFlow S.L.</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-5">Contributors</a></h2>
<h2><a class="toc-backref" href="#toc-entry-6">Contributors</a></h2>
<ul class="simple">
<li>Adria Gil Sorribes &lt;<a class="reference external" href="mailto:adria.gil&#64;forgeflow.com">adria.gil&#64;forgeflow.com</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-6">Maintainers</a></h2>
<h2><a class="toc-backref" href="#toc-entry-7">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" />
Expand Down
125 changes: 83 additions & 42 deletions purchase_manual_delivery/tests/test_purchase_manual_delivery.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,75 +3,76 @@

from odoo import fields
from odoo.exceptions import UserError
from odoo.tests.common import TransactionCase
from odoo.tests.common import Form, TransactionCase


class TestPurchaseManualDelivery(TransactionCase):
def setUp(self):
super(TestPurchaseManualDelivery, self).setUp()
self.purchase_order_obj = self.env["purchase.order"]
self.purchase_order_line_obj = self.env["purchase.order.line"]
self.stock_picking_obj = self.env["stock.picking"]
self.env.company.purchase_manual_delivery = True
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.purchase_order_obj = cls.env["purchase.order"]
cls.purchase_order_line_obj = cls.env["purchase.order.line"]
cls.stock_picking_obj = cls.env["stock.picking"]
cls.env.company.purchase_manual_delivery = True
# Products
self.product1 = self.env.ref("product.product_product_13")
self.product2 = self.env.ref("product.product_product_25")
cls.product1 = cls.env.ref("product.product_product_13")
cls.product2 = cls.env.ref("product.product_product_25")

# Sublocation
self.shelf2 = self.env.ref("stock.stock_location_14")
cls.shelf2 = cls.env.ref("stock.stock_location_14")

# Purchase Orders
self.po1 = self.purchase_order_obj.create(
cls.po1 = cls.purchase_order_obj.create(
{
"partner_id": self.ref("base.res_partner_3"),
"partner_id": cls.env.ref("base.res_partner_3").id,
}
)
self.po1_line1 = self.purchase_order_line_obj.create(
cls.po1_line1 = cls.purchase_order_line_obj.create(
{
"order_id": self.po1.id,
"product_id": self.product1.id,
"product_uom": self.product1.uom_id.id,
"name": self.product1.name,
"price_unit": self.product1.standard_price,
"order_id": cls.po1.id,
"product_id": cls.product1.id,
"product_uom": cls.product1.uom_id.id,
"name": cls.product1.name,
"price_unit": cls.product1.standard_price,
"date_planned": fields.datetime.now(),
"product_qty": 42.0,
}
)
self.po1_line2 = self.purchase_order_line_obj.create(
cls.po1_line2 = cls.purchase_order_line_obj.create(
{
"order_id": self.po1.id,
"product_id": self.product2.id,
"product_uom": self.product2.uom_id.id,
"name": self.product2.name,
"price_unit": self.product2.standard_price,
"order_id": cls.po1.id,
"product_id": cls.product2.id,
"product_uom": cls.product2.uom_id.id,
"name": cls.product2.name,
"price_unit": cls.product2.standard_price,
"date_planned": fields.datetime.now(),
"product_qty": 12.0,
}
)

self.po2 = self.purchase_order_obj.create(
cls.po2 = cls.purchase_order_obj.create(
{
"partner_id": self.ref("base.res_partner_3"),
"partner_id": cls.env.ref("base.res_partner_3").id,
}
)
self.po2_line1 = self.purchase_order_line_obj.create(
cls.po2_line1 = cls.purchase_order_line_obj.create(
{
"order_id": self.po2.id,
"product_id": self.product1.id,
"product_uom": self.product1.uom_id.id,
"name": self.product1.name,
"price_unit": self.product1.standard_price,
"order_id": cls.po2.id,
"product_id": cls.product1.id,
"product_uom": cls.product1.uom_id.id,
"name": cls.product1.name,
"price_unit": cls.product1.standard_price,
"date_planned": fields.datetime.now(),
"product_qty": 10.0,
}
)
self.po2_line2 = self.purchase_order_line_obj.create(
cls.po2_line2 = cls.purchase_order_line_obj.create(
{
"order_id": self.po2.id,
"product_id": self.product2.id,
"product_uom": self.product2.uom_id.id,
"name": self.product2.name,
"price_unit": self.product2.standard_price,
"order_id": cls.po2.id,
"product_id": cls.product2.id,
"product_uom": cls.product2.uom_id.id,
"name": cls.product2.name,
"price_unit": cls.product2.standard_price,
"date_planned": fields.datetime.now(),
"product_qty": 22.0,
}
Expand Down Expand Up @@ -107,7 +108,7 @@ def test_01_purchase_order_manual_delivery(self):
)
wizard.fill_lines(self.po1.order_line)
wizard.line_ids = wizard.line_ids - wizard.line_ids.filtered(
lambda l: l.product_id == self.product2
lambda li: li.product_id == self.product2
)
wizard.create_stock_picking()
# check picking is created
Expand Down Expand Up @@ -162,6 +163,46 @@ def test_01_purchase_order_manual_delivery(self):
self.assertEqual(self.po1_line1.existing_qty, self.po1_line1.product_qty)
self.assertEqual(self.po1_line2.existing_qty, self.po1_line2.product_qty)

# Process the picking
picking = self.po1.picking_ids
for move in picking.move_ids:
move.quantity = move.product_qty
picking.button_validate()

# Process some returns
stock_return_picking_form = Form(
self.env["stock.return.picking"].with_context(
active_ids=picking.ids,
active_id=picking.id,
active_model=picking._name,
)
)
return_wiz = stock_return_picking_form.save()
return_wiz.product_return_moves.filtered(
lambda prm: prm.move_id.purchase_line_id == self.po1_line1
).write(
{
"quantity": 2,
"to_refund": True,
}
)
return_wiz.product_return_moves.filtered(
lambda prm: prm.move_id.purchase_line_id == self.po1_line2
).write(
{
"quantity": 2,
"to_refund": False,
}
)
return_wiz.create_returns()

# The refund line is open to receive the returned item
self.assertTrue(self.po1_line1.pending_to_receive)
self.assertEqual(self.po1_line1.existing_qty, self.po1_line1.product_qty - 2)
# But the non-refund line is not
self.assertEqual(self.po1_line2.existing_qty, self.po1_line2.product_qty)
self.assertFalse(self.po1_line2.pending_to_receive)

def test_02_purchase_order_line_manual_delivery(self):
"""
Confirm Purchase Order 1 and 2, try to create incoming shipment
Expand Down Expand Up @@ -242,7 +283,7 @@ def test_03_purchase_order_line_location(self):
)
wizard.fill_lines(self.po1.order_line)
wizard.line_ids = wizard.line_ids - wizard.line_ids.filtered(
lambda l: l.product_id == self.product2
lambda li: li.product_id == self.product2
)
wizard.location_dest_id = self.shelf2
wizard.create_stock_picking()
Expand Down Expand Up @@ -290,13 +331,13 @@ def test_04_pending_to_receive(self):
)
wizard.fill_lines(po_existing_bigger.order_line)
wizard.line_ids.filtered(
lambda l: l.purchase_order_line_id.id == pol_existing_bigger.id
lambda li: li.purchase_order_line_id.id == pol_existing_bigger.id
).qty = 1
wizard.create_stock_picking()

# Change the done quantity to be bigger than the total needed
picking_id = po_existing_bigger.picking_ids[0]
picking_id.move_ids[0].quantity_done = 6
picking_id.move_ids[0].quantity = 6
picking_id.button_validate()

# The PO Line should not be pending to receive
Expand Down
13 changes: 8 additions & 5 deletions purchase_manual_delivery/views/purchase_order_views.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
string="Create Incoming Shipment"
type="action"
class="btn-primary"
attrs="{'invisible': ['|', '|', ('state', '!=', 'purchase'), ('pending_to_receive', '=', False), ('manual_delivery', '=', False)]}"
invisible="state != 'purchase' or not pending_to_receive or not manual_delivery"
/>
</xpath>
<button id="draft_confirm" position="attributes">
Expand All @@ -23,7 +23,7 @@
<button
name="button_confirm_manual"
type="object"
states="draft"
invisible="state != 'draft'"
string="Confirm Order"
id="draft_confirm_manual"
/>
Expand All @@ -35,7 +35,7 @@
<button
name="button_confirm_manual"
type="object"
states="sent"
invisible="state != 'sent'"
string="Confirm Order"
class="oe_highlight"
id="bid_confirm_manual"
Expand All @@ -46,7 +46,7 @@
<field
name="existing_qty"
optional="hide"
attrs="{'column_invisible': [('parent.state', 'not in', ('purchase', 'done'))]}"
column_invisible="parent.state not in ('purchase', 'done')"
/>
</field>
<xpath expr="//field[@name='order_line']/tree" position="attributes">
Expand All @@ -55,7 +55,10 @@
>state == 'purchase' and pending_to_receive</attribute>
</xpath>
<group name="other_info" position="inside">
<field name="manual_delivery" />
<field
name="manual_delivery"
readonly="state not in ('draft', 'sent')"
/>
</group>
</field>
</record>
Expand Down
Loading

0 comments on commit 9cae351

Please sign in to comment.