Initial commit: OCA Workflow Process packages (456 packages)

This commit is contained in:
Ernad Husremovic 2025-08-29 15:43:00 +02:00
commit d366e42934
18799 changed files with 1284507 additions and 0 deletions

View file

@ -0,0 +1,6 @@
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0)
from . import test_purchase_request_allocation
from . import test_purchase_request_procurement
from . import test_purchase_request_to_rfq
from . import test_purchase_request

View file

@ -0,0 +1,311 @@
# Copyright 2018-2019 ForgeFlow, S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0)
from odoo import SUPERUSER_ID, exceptions
from odoo.exceptions import UserError
from odoo.tests.common import Form, TransactionCase
class TestPurchaseRequest(TransactionCase):
def setUp(self):
super(TestPurchaseRequest, self).setUp()
self.purchase_request_obj = self.env["purchase.request"]
self.purchase_request_line_obj = self.env["purchase.request.line"]
self.purchase_order = self.env["purchase.order"]
self.wiz = self.env["purchase.request.line.make.purchase.order"]
self.picking_type_id = self.env.ref("stock.picking_type_in")
vals = {
"group_id": self.env["procurement.group"].create({}).id,
"picking_type_id": self.picking_type_id.id,
"requested_by": SUPERUSER_ID,
}
self.purchase_request = self.purchase_request_obj.create(vals)
vals = {
"request_id": self.purchase_request.id,
"product_id": self.env.ref("product.product_product_13").id,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
"product_qty": 5.0,
}
self.purchase_request_line_obj.create(vals)
def test_purchase_request_line_action(self):
action = self.purchase_request.line_ids.action_show_details()
self.assertEqual(action["res_id"], self.purchase_request.line_ids.id)
def test_purchase_request_status(self):
"""Tests Purchase Request status workflow."""
purchase_request = self.purchase_request
purchase_request.write({"assigned_to": SUPERUSER_ID})
self.assertEqual(purchase_request.is_editable, True, "Should be editable")
self.assertEqual(purchase_request.state, "draft", "Should be in state draft")
purchase_request.button_to_approve()
self.assertEqual(
purchase_request.state, "to_approve", "Should be in state to_approve"
)
with self.assertRaises(exceptions.UserError) as e:
purchase_request.unlink()
msg = "You cannot delete a purchase request which is not draft."
self.assertIn(msg, e.exception.args[0])
self.assertEqual(purchase_request.is_editable, False, "Should not be editable")
purchase_request.button_draft()
self.assertEqual(purchase_request.is_editable, True, "Should be editable")
self.assertEqual(purchase_request.state, "draft", "Should be in state draft")
purchase_request.button_to_approve()
purchase_request.button_in_progress()
self.assertEqual(
purchase_request.state, "in_progress", "Should be in state in_progress"
)
self.assertEqual(purchase_request.is_editable, False, "Should not be editable")
with self.assertRaises(exceptions.UserError) as e:
purchase_request.unlink()
msg = "You cannot delete a purchase request which is not draft."
self.assertIn(msg, e.exception.args[0])
purchase_request.button_draft()
self.assertEqual(purchase_request.is_editable, True, "Should be editable")
self.assertEqual(purchase_request.state, "draft", "Should be in state draft")
purchase_request.button_to_approve()
purchase_request.button_done()
self.assertEqual(purchase_request.is_editable, False, "Should not be editable")
with self.assertRaises(exceptions.UserError) as e:
purchase_request.unlink()
msg = "You cannot delete a purchase request which is not draft."
self.assertIn(msg, e.exception.args[0])
purchase_request.button_rejected()
self.assertEqual(purchase_request.is_editable, False, "Should not be editable")
vals = {
"request_id": purchase_request.id,
"product_id": self.env.ref("product.product_product_6").id,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
"product_qty": 2.0,
}
purchase_request_line = self.purchase_request_line_obj.create(vals)
purchase_request.button_approved()
vals = {"supplier_id": self.env.ref("base.res_partner_1").id}
# It is required to have a picking type
purchase_request.picking_type_id = False
with self.assertRaisesRegex(UserError, "a Picking Type"):
self.wiz.with_context(
active_model="purchase.request",
active_ids=[purchase_request.id],
).create(vals)
purchase_request.picking_type_id = self.picking_type_id
# Picking type across all lines have to be the same
purchase_request2 = purchase_request.copy(
{"picking_type_id": self.picking_type_id.copy().id}
)
purchase_request2.button_approved()
with self.assertRaisesRegex(UserError, "same Picking Type"):
self.wiz.with_context(
active_model="purchase.request.line",
active_ids=(purchase_request_line + purchase_request2.line_ids).ids,
).create(vals)
purchase_request2.picking_type_id = purchase_request.picking_type_id
purchase_request2.group_id = self.env["procurement.group"].create({})
with self.assertRaisesRegex(UserError, "different procurement group"):
self.wiz.with_context(
active_model="purchase.request.line",
active_ids=(purchase_request_line + purchase_request2.line_ids).ids,
).create(vals)
wiz_id = self.wiz.with_context(
active_model="purchase.request.line", active_ids=[purchase_request_line.id]
).create(vals)
wiz_id.make_purchase_order()
# Unlink purchase_lines from state approved
with self.assertRaises(UserError):
purchase_request_line.unlink()
purchase = purchase_request_line.purchase_lines.order_id
purchase.button_done()
self.assertEqual(purchase.state, "done")
with self.assertRaisesRegex(
UserError, "The purchase has already been completed"
):
self.wiz.with_context(
active_model="purchase.request.line",
active_ids=[purchase_request_line.id],
).create(vals)
purchase_request_line._compute_purchase_state()
# Error case purchase_order in state done
with self.assertRaisesRegex(UserError, "has already been completed"):
purchase.button_confirm()
purchase.button_cancel()
self.assertEqual(purchase.state, "cancel")
purchase_request_line._compute_purchase_state()
with self.assertRaisesRegex(
exceptions.UserError,
"You cannot delete a purchase request which is not draft",
):
purchase_request.unlink()
purchase_request.button_draft()
purchase_request.unlink()
def test_auto_reject(self):
"""Tests if a Purchase Request is autorejected when all lines are
cancelled."""
purchase_request = self.purchase_request
# Add a second line to the PR:
vals = {
"request_id": purchase_request.id,
"product_id": self.env.ref("product.product_product_16").id,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
"product_qty": 5.0,
}
self.purchase_request_line_obj.create(vals)
lines = purchase_request.line_ids
# Cancel one line:
lines[0].do_cancel()
self.assertNotEqual(
purchase_request.state,
"rejected",
"Purchase Request should not have been rejected.",
)
# Cancel the second one:
lines[1].do_cancel()
self.assertEqual(
purchase_request.state,
"rejected",
"Purchase Request should have been auto-rejected.",
)
def test_pr_line_to_approve_allowed(self):
request = self.purchase_request
self.assertTrue(request.to_approve_allowed)
pr_lines = self.purchase_request.line_ids
pr_lines.write({"product_qty": 0})
self.assertFalse(request.to_approve_allowed)
pr_lines.write({"product_qty": 5})
self.assertTrue(request.to_approve_allowed)
pr_lines.do_cancel()
self.assertFalse(request.to_approve_allowed)
# Request has been automatically rejected
request.button_draft()
new_line = self.purchase_request_line_obj.create(
{
"product_id": self.env.ref("product.product_product_16").id,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
"product_qty": 0.0,
"request_id": request.id,
}
)
pr_lines.do_cancel()
self.assertFalse(request.to_approve_allowed)
new_line.write({"product_qty": 1})
self.assertTrue(request.to_approve_allowed)
request.line_ids.unlink()
self.assertFalse(request.to_approve_allowed)
def test_empty_purchase_request(self):
pr = self.purchase_request
pr_lines = pr.line_ids
pr_lines.write({"product_qty": 0})
with self.assertRaises(UserError):
self.purchase_request.button_to_approve()
pr_lines.write({"product_qty": 4})
pr.button_to_approve()
self.assertEqual(pr.state, "to_approve")
def test_default_picking_type(self):
with Form(self.purchase_request_obj) as f:
f.name = "Test Purchase"
f.requested_by = self.env.user
f.save()
def test_copy_purchase_request(self):
purchase_request = self.purchase_request
# Add a second line to the PR:
vals = {
"request_id": purchase_request.id,
"product_id": self.env.ref("product.product_product_16").id,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
"product_qty": 5.0,
}
self.purchase_request_line_obj.create(vals)
purchase_request_copy = purchase_request.copy()
self.assertEqual(purchase_request_copy.state, "draft")
def test_raise_error(self):
vals = {
"picking_type_id": self.env.ref("stock.picking_type_in").id,
"requested_by": SUPERUSER_ID,
}
purchase_request = self.purchase_request.create(vals)
vals = {
"request_id": purchase_request.id,
"product_id": self.env.ref("product.product_product_16").id,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
"product_qty": 2.0,
}
purchase_request_line = self.purchase_request_line_obj.create(vals)
self.assertEqual(purchase_request.state, "draft")
# create purchase order from draft state
with self.assertRaises(UserError):
self.wiz.with_context(
active_model="purchase.request.line",
active_ids=[purchase_request_line.id],
).create(vals)
purchase_request.button_done()
# create purchase order from done state
self.assertEqual(purchase_request.state, "done")
purchase_request_line._compute_is_editable()
with self.assertRaisesRegex(UserError, "already been completed"):
self.wiz.with_context(
active_model="purchase.request.line",
active_ids=[purchase_request_line.id],
).create(vals)
# Change product_qty to negative
purchase_request_line.write({"product_qty": -6})
purchase_request.button_approved()
self.assertEqual(purchase_request.state, "approved")
vals = {"supplier_id": self.env.ref("base.res_partner_1").id}
wiz_id = self.wiz.with_context(
active_model="purchase.request.line", active_ids=[purchase_request_line.id]
).create(vals)
with self.assertRaisesRegex(UserError, "Enter a positive quantity"):
wiz_id.make_purchase_order()
def test_purchase_request_unlink(self):
pr = self.purchase_request
pr_lines = pr.line_ids
pr.button_to_approve()
self.assertEqual(pr.state, "to_approve", "Should be in state to_approve")
with self.assertRaises(exceptions.UserError) as e:
pr_lines.unlink()
msg = (
"You can only delete a purchase request line "
"if the purchase request is in draft state."
)
self.assertIn(msg, e.exception.args[0])
pr.button_in_progress()
self.assertEqual(pr.state, "in_progress", "Should be in state in_progress")
with self.assertRaises(exceptions.UserError) as e:
pr_lines.unlink()
msg = (
"You can only delete a purchase request line "
"if the purchase request is in draft state."
)
self.assertIn(msg, e.exception.args[0])
pr.button_done()
self.assertEqual(pr.state, "done", "Should be in state done")
with self.assertRaises(exceptions.UserError) as e:
pr_lines.unlink()
msg = (
"You can only delete a purchase request line "
"if the purchase request is in draft state."
)
self.assertIn(msg, e.exception.args[0])
pr.button_draft()
self.assertEqual(pr.state, "draft", "Should be in state draft")
pr_lines.unlink()

View file

@ -0,0 +1,434 @@
# Copyright 2018-2019 ForgeFlow, S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0)
from odoo import SUPERUSER_ID
from odoo.tests import common
class TestPurchaseRequestToRfq(common.TransactionCase):
def setUp(self):
super(TestPurchaseRequestToRfq, self).setUp()
self.purchase_request = self.env["purchase.request"]
self.purchase_request_line = self.env["purchase.request.line"]
self.wiz = self.env["purchase.request.line.make.purchase.order"]
self.purchase_order = self.env["purchase.order"]
vendor = self.env["res.partner"].create({"name": "Partner #2"})
self.service_product = self.env["product.product"].create(
{"name": "Product Service Test", "type": "service"}
)
self.product_product = self.env["product.product"].create(
{
"name": "Product Product Test",
"type": "product",
"description_purchase": "Test Description",
}
)
self.env["product.supplierinfo"].create(
{
"partner_id": vendor.id,
"product_tmpl_id": self.service_product.product_tmpl_id.id,
}
)
self.env["product.supplierinfo"].create(
{
"partner_id": vendor.id,
"product_tmpl_id": self.product_product.product_tmpl_id.id,
}
)
def test_purchase_request_allocation(self):
vals = {
"picking_type_id": self.env.ref("stock.picking_type_in").id,
"requested_by": SUPERUSER_ID,
}
purchase_request1 = self.purchase_request.create(vals)
vals = {
"request_id": purchase_request1.id,
"product_id": self.product_product.id,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
"product_qty": 2.0,
}
purchase_request_line1 = self.purchase_request_line.create(vals)
vals = {
"picking_type_id": self.env.ref("stock.picking_type_in").id,
"requested_by": SUPERUSER_ID,
}
purchase_request2 = self.purchase_request.create(vals)
vals = {
"request_id": purchase_request1.id,
"product_id": self.product_product.id,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
"product_qty": 2.0,
}
purchase_request_line2 = self.purchase_request_line.create(vals)
purchase_request1.button_approved()
purchase_request2.button_approved()
purchase_request1.action_view_purchase_request_line()
vals = {"supplier_id": self.env.ref("base.res_partner_1").id}
wiz_id = self.wiz.with_context(
active_model="purchase.request.line",
active_ids=[purchase_request_line1.id, purchase_request_line2.id],
).create(vals)
wiz_id.make_purchase_order()
purchase_request1.action_view_purchase_order()
po_line = purchase_request_line1.purchase_lines[0]
# Add unit price in PO Line
po_line.write({"price_unit": 10})
purchase = po_line.order_id
purchase.order_line.action_open_request_line_tree_view()
purchase.button_confirm()
purchase_request1.action_view_stock_picking()
self.assertEqual(purchase_request_line1.qty_in_progress, 2.0)
self.assertEqual(purchase_request_line2.qty_in_progress, 2.0)
picking = purchase.picking_ids[0]
# Check the move
move = picking.move_ids
self.assertEqual(move.purchase_request_ids, purchase_request1)
# Do a move split/merge roundtrip and check that the allocatable
# quantity remains the same.
self.assertEqual(
sum(move.purchase_request_allocation_ids.mapped("open_product_qty")), 4
)
split_move = self.env["stock.move"].create(move._split(1))
split_move._action_confirm(merge=False)
self.assertEqual(split_move.purchase_request_ids, purchase_request1)
# The quantity of 4 is now split between the two moves
self.assertEqual(
sum(move.purchase_request_allocation_ids.mapped("open_product_qty")), 3
)
self.assertEqual(
sum(split_move.purchase_request_allocation_ids.mapped("open_product_qty")),
1,
)
split_move._merge_moves(merge_into=move)
self.assertFalse(split_move.exists())
self.assertEqual(
sum(move.purchase_request_allocation_ids.mapped("open_product_qty")), 4
)
# Reset reserved quantities messed up by the roundtrip
move._do_unreserve()
move._action_assign()
picking.move_line_ids[0].write({"qty_done": 2.0})
backorder_wiz_id = picking.button_validate()
common.Form(
self.env[backorder_wiz_id["res_model"]].with_context(
**backorder_wiz_id["context"]
)
).save().process()
request_lines = purchase_request_line1 + purchase_request_line2
self.assertEqual(sum(request_lines.mapped("qty_done")), 2.0)
backorder_picking = purchase.picking_ids.filtered(lambda p: p.id != picking.id)
backorder_picking.move_line_ids[0].write({"qty_done": 1.0})
backorder_wiz_id2 = backorder_picking.button_validate()
common.Form(
self.env[backorder_wiz_id2["res_model"]].with_context(
**backorder_wiz_id2["context"]
)
).save().process()
self.assertEqual(sum(request_lines.mapped("qty_done")), 3.0)
for pick in purchase.picking_ids:
if pick.state == "assigned":
pick.action_cancel()
self.assertEqual(sum(request_lines.mapped("qty_cancelled")), 1.0)
self.assertEqual(sum(request_lines.mapped("pending_qty_to_receive")), 1.0)
def test_purchase_request_allocation_services(self):
vals = {
"picking_type_id": self.env.ref("stock.picking_type_in").id,
"requested_by": SUPERUSER_ID,
"assigned_to": SUPERUSER_ID,
}
purchase_request1 = self.purchase_request.create(vals)
vals = {
"request_id": purchase_request1.id,
"product_id": self.service_product.id,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
"product_qty": 2.0,
}
purchase_request_line1 = self.purchase_request_line.create(vals)
vals = {"supplier_id": self.env.ref("base.res_partner_1").id}
purchase_request1.button_approved()
purchase_request1.action_view_purchase_request_line()
wiz_id = self.wiz.with_context(
active_model="purchase.request.line", active_ids=[purchase_request_line1.id]
).create(vals)
wiz_id.make_purchase_order()
purchase_request1.action_view_purchase_order()
po_line = purchase_request_line1.purchase_lines[0]
# Add unit price in PO Line
po_line.write({"price_unit": 10})
purchase = po_line.order_id
purchase.button_confirm()
self.assertEqual(purchase_request_line1.qty_in_progress, 2.0)
# manually set in the PO line
po_line.write({"qty_received": 0.5})
self.assertEqual(purchase_request_line1.qty_done, 0.5)
purchase.button_cancel()
self.assertEqual(purchase_request_line1.qty_cancelled, 1.5)
self.assertEqual(purchase_request_line1.pending_qty_to_receive, 1.5)
# Case revieve 2 product
vals = {
"picking_type_id": self.env.ref("stock.picking_type_in").id,
"requested_by": SUPERUSER_ID,
"assigned_to": SUPERUSER_ID,
}
purchase_request2 = self.purchase_request.create(vals)
vals = {
"request_id": purchase_request2.id,
"product_id": self.service_product.id,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
"product_qty": 2.0,
}
purchase_request_line2 = self.purchase_request_line.create(vals)
vals = {"supplier_id": self.env.ref("base.res_partner_1").id}
purchase_request2.button_approved()
purchase_request2.action_view_purchase_request_line()
wiz_id = self.wiz.with_context(
active_model="purchase.request.line", active_ids=[purchase_request_line2.id]
).create(vals)
wiz_id.make_purchase_order()
(purchase_request1 + purchase_request2).action_view_purchase_order()
po_line = purchase_request_line2.purchase_lines[0]
purchase2 = po_line.order_id
purchase2.button_confirm()
self.assertEqual(purchase_request_line2.qty_in_progress, 2.0)
purchase_request1.action_view_stock_picking()
# manually set in the PO line
po_line.write({"qty_received": 2.0})
self.assertEqual(purchase_request_line2.qty_done, 2.0)
def test_purchase_request_allocation_min_qty(self):
vals = {
"picking_type_id": self.env.ref("stock.picking_type_in").id,
"requested_by": SUPERUSER_ID,
}
purchase_request1 = self.purchase_request.create(vals)
vals = {
"request_id": purchase_request1.id,
"product_id": self.product_product.id,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
"product_qty": 2.0,
}
purchase_request_line1 = self.purchase_request_line.create(vals)
# add a vendor
vendor1 = self.env.ref("base.res_partner_1")
self.env["product.supplierinfo"].create(
{
"partner_id": vendor1.id,
"product_tmpl_id": self.product_product.product_tmpl_id.id,
"min_qty": 8,
}
)
vals = {"supplier_id": self.env.ref("base.res_partner_1").id}
purchase_request1.button_approved()
wiz_id = self.wiz.with_context(
active_model="purchase.request.line", active_ids=[purchase_request_line1.id]
).create(vals)
wiz_id.make_purchase_order()
self.assertEqual(
purchase_request_line1.purchase_request_allocation_ids[0].open_product_qty,
2.0,
)
def test_purchase_request_stock_allocation(self):
product = self.env.ref("product.product_product_6")
product.uom_po_id = self.env.ref("uom.product_uom_dozen")
vals = {
"picking_type_id": self.env.ref("stock.picking_type_in").id,
"requested_by": SUPERUSER_ID,
}
purchase_request = self.purchase_request.create(vals)
vals = {
"request_id": purchase_request.id,
"product_id": product.id,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
"product_qty": 12.0,
}
purchase_request_line1 = self.purchase_request_line.create(vals)
vals = {
"request_id": purchase_request.id,
"product_id": product.id,
"product_uom_id": self.env.ref("uom.product_uom_dozen").id,
"product_qty": 1,
}
purchase_request_line2 = self.purchase_request_line.create(vals)
vals = {"supplier_id": self.env.ref("base.res_partner_1").id}
purchase_request.button_approved()
wiz_id = self.wiz.with_context(
active_model="purchase.request.line",
active_ids=[purchase_request_line1.id, purchase_request_line2.id],
).create(vals)
# Create PO
wiz_id.make_purchase_order()
po_line = purchase_request_line1.purchase_lines[0]
self.assertEqual(po_line.product_qty, 2, "Quantity should be 2")
self.assertEqual(
po_line.product_uom,
self.env.ref("uom.product_uom_dozen"),
"The purchase UoM should be Dozen(s).",
)
self.assertEqual(
purchase_request_line1.purchase_request_allocation_ids[
0
].requested_product_uom_qty,
12.0,
)
self.assertEqual(
purchase_request_line2.purchase_request_allocation_ids[
0
].requested_product_uom_qty,
1.0,
)
purchase = po_line.order_id
# Cancel PO allocation requested quantity is set to 0.
purchase.button_cancel()
self.assertEqual(
purchase_request_line1.purchase_request_allocation_ids[0].open_product_qty,
0,
)
self.assertEqual(
purchase_request_line2.purchase_request_allocation_ids[0].open_product_qty,
0,
)
# Set to draft allocation requested quantity is set
purchase.button_draft()
self.assertEqual(
purchase_request_line1.purchase_request_allocation_ids[0].open_product_qty,
12.0,
)
self.assertEqual(
purchase_request_line2.purchase_request_allocation_ids[0].open_product_qty,
1.0,
)
purchase.button_confirm()
picking = purchase.picking_ids[0]
picking.move_line_ids[0].write({"qty_done": 24.0})
picking.button_validate()
self.assertEqual(
purchase_request_line1.purchase_request_allocation_ids[
0
].allocated_product_qty,
purchase_request_line1.purchase_request_allocation_ids[
0
].requested_product_uom_qty,
)
self.assertEqual(
purchase_request_line2.purchase_request_allocation_ids[
0
].allocated_product_qty,
purchase_request_line2.purchase_request_allocation_ids[
0
].requested_product_uom_qty,
)
def test_purchase_request_stock_allocation_unlink(self):
product = self.env.ref("product.product_product_6")
product.uom_po_id = self.env.ref("uom.product_uom_dozen")
vals = {
"picking_type_id": self.env.ref("stock.picking_type_in").id,
"requested_by": SUPERUSER_ID,
}
purchase_request = self.purchase_request.create(vals)
vals = {
"request_id": purchase_request.id,
"product_id": product.id,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
"product_qty": 12.0,
}
purchase_request_line1 = self.purchase_request_line.create(vals)
vals = {"supplier_id": self.env.ref("base.res_partner_1").id}
purchase_request.button_approved()
wiz_id = self.wiz.with_context(
active_model="purchase.request.line", active_ids=[purchase_request_line1.id]
).create(vals)
# Create PO
wiz_id.make_purchase_order()
po_line = purchase_request_line1.purchase_lines[0]
self.assertEqual(
purchase_request_line1.purchase_request_allocation_ids[
0
].requested_product_uom_qty,
12.0,
)
purchase = po_line.order_id
purchase.button_cancel()
# Delete PO: allocation and Purchase Order Lines are unlinked from PRL
purchase.unlink()
self.assertEqual(len(purchase_request_line1.purchase_lines), 0)
self.assertEqual(len(purchase_request_line1.purchase_request_allocation_ids), 0)
def test_onchange_product_id(self):
vals = {
"picking_type_id": self.env.ref("stock.picking_type_in").id,
"requested_by": SUPERUSER_ID,
}
purchase_request1 = self.purchase_request.create(vals)
vals = {
"request_id": purchase_request1.id,
"product_id": self.product_product.id,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
"product_qty": 2.0,
}
purchase_request_line1 = self.purchase_request_line.create(vals)
purchase_request_line1.onchange_product_id()
def test_empty_records_for_company_constraint(self):
self.assertFalse(self.env["stock.move"]._check_company_purchase_request())
def test_supplier_assignment(self):
"""Suppliers are not assigned across the company boundary"""
product = self.env.ref("product.product_product_6")
product.seller_ids.unlink()
purchase_request = self.purchase_request.create(
{
"picking_type_id": self.env.ref("stock.picking_type_in").id,
"requested_by": SUPERUSER_ID,
"company_id": self.env.ref("base.main_company").id,
}
)
purchase_request_line = self.purchase_request_line.create(
{
"request_id": purchase_request.id,
"product_id": product.id,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
"product_qty": 12.0,
"company_id": self.env.ref("base.main_company").id,
}
)
# A supplier from another company is not assigned
vendor3 = self.env["res.partner"].create({"name": "Partner #3"})
supinfo = self.env["product.supplierinfo"].create(
{
"partner_id": vendor3.id,
"product_tmpl_id": product.product_tmpl_id.id,
"company_id": self.env.ref("stock.res_company_1").id,
}
)
self.assertFalse(purchase_request_line.supplier_id)
# A supplierinfo of a matching company leads to supplier assignment
vendor4 = self.env["res.partner"].create({"name": "Partner #4"})
supinfo = self.env["product.supplierinfo"].create(
{
"partner_id": vendor4.id,
"product_tmpl_id": product.product_tmpl_id.id,
"company_id": self.env.ref("base.main_company").id,
}
)
self.assertEqual(purchase_request_line.supplier_id, vendor4)
supinfo.unlink()
self.assertFalse(purchase_request_line.supplier_id)
# A supplierinfo without company leads to supplier assignment as well
self.env["product.supplierinfo"].create(
{
"partner_id": vendor4.id,
"product_tmpl_id": product.product_tmpl_id.id,
"company_id": False,
}
)
self.assertEqual(purchase_request_line.supplier_id, vendor4)

View file

@ -0,0 +1,170 @@
# Copyright 2018-2019 ForgeFlow, S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0)
from odoo import fields
from odoo.tests import common
class TestPurchaseRequestProcurement(common.TransactionCase):
def setUp(self):
super(TestPurchaseRequestProcurement, self).setUp()
# Get required Model
self.pr_model = self.env["purchase.request"]
self.prl_model = self.env["purchase.request.line"]
self.product_uom_model = self.env["uom.uom"]
self.location = self.env.ref("stock.stock_location_stock")
self.customer_location = self.env.ref("stock.stock_location_customers")
# Get required Model data
self.product_1 = self.env.ref("product.product_product_16")
self.product_1.purchase_request = True
self.route_buy = self.env.ref("purchase_stock.route_warehouse0_buy")
self.rule_buy = self.route_buy.rule_ids.filtered(
lambda rule: rule.location_dest_id == self.location
)
# Create Supplier
self.supplier = self.env["res.partner"].create(
{"name": "Supplier", "is_company": True, "company_id": False}
)
# Add supplier to product_1
self.product_1.write(
{
"seller_ids": [
(
0,
0,
{
"partner_id": self.supplier.id,
"price": 100.0,
"company_id": False,
},
)
]
}
)
def _procurement_group_run(self, origin, product, qty):
"""Create an outgoing move and procure it"""
move = self.env["stock.move"].create(
{
"reservation_date": fields.Datetime.now(),
"location_dest_id": self.customer_location.id,
"location_id": self.location.id,
"name": product.name,
"origin": origin,
"procure_method": "make_to_order",
"product_id": product.id,
"product_uom": product.uom_id.id,
"product_uom_qty": qty,
"route_ids": [(4, self.route_buy.id)],
}
)
move._action_confirm()
return move
def test_orderpoint(self):
"""Purchase request quantity is reflected in the orderpoint forecasted qty"""
qty = 5
orderpoint = self.env["stock.warehouse.orderpoint"].create(
{
"name": __name__,
"warehouse_id": self.env.ref("stock.warehouse0").id,
"location_id": self.location.id,
"product_id": self.product_1.id,
"product_min_qty": 1,
"product_max_qty": qty,
}
)
self.env["procurement.group"].run_scheduler()
self.assertEqual(
self.env["purchase.request"]
.search([("product_id", "=", self.product_1.id)])
.line_ids.product_qty,
qty,
)
self.assertEqual(orderpoint.qty_forecast, qty)
def test_procure_purchase_request(self):
"""A request line is created from a procured move"""
move = self._procurement_group_run(
"Test Purchase Request Procurement",
self.product_1,
10,
)
self.assertTrue(move.created_purchase_request_line_id)
pr = move.created_purchase_request_line_id.request_id
self.assertTrue(pr.to_approve_allowed)
self.assertEqual(pr.origin, "Test Purchase Request Procurement")
# Now cancel the move. An activity is created on the request.
# Even if the activity type was deleted
activity = self.env.ref("mail.mail_activity_data_todo")
self.env["mail.activity"].search(
[("activity_type_id", "=", activity.id)]
).unlink()
self.assertFalse(move.created_purchase_request_line_id.request_id.activity_ids)
move._action_cancel()
self.assertTrue(move.created_purchase_request_line_id.request_id.activity_ids)
def test_procure_purchase_request_with_fixed_group(self):
"""Existing requests are reused depending on group settings.
Having a procurement rule with fixed group settings, existing
purchase requests are only matched during procurement
if the groups correspond.
"""
group = self.env["procurement.group"].create({})
self.rule_buy.write(
{
"group_id": group.id,
"group_propagation_option": "fixed",
}
)
move = self._procurement_group_run(
False,
self.product_1,
10,
)
pr = move.created_purchase_request_line_id.request_id
self.assertEqual(pr.group_id, group)
# A second procurement reuses the same request
move2 = self._procurement_group_run(
"Test Origin",
self.product_1,
10,
)
pr2 = move2.created_purchase_request_line_id.request_id
self.assertEqual(pr2, pr)
# Reset the group on the first purchase request
pr.group_id = self.env["procurement.group"].create({})
# Because of the group difference, the request is not reused
move3 = self._procurement_group_run("Test with group", self.product_1, 10)
pr3 = move3.created_purchase_request_line_id.request_id
self.assertEqual(pr3.group_id, group)
self.assertNotEqual(pr3, pr)
def test_origin(self):
"""The purchase request origin reflects the origins of each procurement"""
move = self._procurement_group_run("Test Origin", self.product_1, 10)
pr = move.created_purchase_request_line_id.request_id
self.assertEqual(pr.origin, "Test Origin")
# A new procurement origin is added to the request origin
move2 = self._procurement_group_run("Test, Split", self.product_1, 10)
self.assertEqual(move2.created_purchase_request_line_id.request_id, pr)
self.assertEqual(pr.origin, "Test Origin, Test, Split")
# An empty procurement origin is not added to the request origin
move3 = self._procurement_group_run(False, self.product_1, 10)
self.assertEqual(move3.created_purchase_request_line_id.request_id, pr)
self.assertEqual(pr.origin, "Test Origin, Test, Split")
# An existing procurement origin is not added to the request origin
move4 = self._procurement_group_run("Split", self.product_1, 10)
self.assertEqual(move4.created_purchase_request_line_id.request_id, pr)
self.assertEqual(pr.origin, "Test Origin, Test, Split")

View file

@ -0,0 +1,424 @@
# Copyright 2018-2019 ForgeFlow, S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0)
from odoo import SUPERUSER_ID
from odoo.tests import common
class TestPurchaseRequestToRfq(common.TransactionCase):
def setUp(self):
super(TestPurchaseRequestToRfq, self).setUp()
self.purchase_request_obj = self.env["purchase.request"]
self.purchase_request_line_obj = self.env["purchase.request.line"]
self.wiz = self.env["purchase.request.line.make.purchase.order"]
self.purchase_order = self.env["purchase.order"]
vendor = self.env["res.partner"].create({"name": "Partner #2"})
self.service_product = self.env["product.product"].create(
{"name": "Product Service Test", "type": "service"}
)
self.env["product.supplierinfo"].create(
{
"partner_id": vendor.id,
"product_tmpl_id": self.service_product.product_tmpl_id.id,
}
)
self.product_product = self.env["product.product"].create(
{
"name": "Product Product Test",
"type": "product",
"description_purchase": "Test Description",
}
)
def test_wizard_default_get(self):
# Check that correct create items by purchase.request
vals = {
"picking_type_id": self.env.ref("stock.picking_type_in").id,
"requested_by": SUPERUSER_ID,
"line_ids": [
[
0,
0,
{
"product_id": self.env.ref("product.product_product_13").id,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
"product_qty": 2.0,
},
]
],
}
purchase_request1 = self.purchase_request_obj.create(vals)
purchase_request1.button_approved()
vals = {
"picking_type_id": self.env.ref("stock.picking_type_in").id,
"requested_by": SUPERUSER_ID,
"line_ids": [
[
0,
0,
{
"product_id": self.env.ref("product.product_product_13").id,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
"product_qty": 2.0,
},
]
],
}
purchase_request2 = self.purchase_request_obj.create(vals)
purchase_request2.button_approved()
vals = {"supplier_id": self.env.ref("base.res_partner_1").id}
wiz_id = self.wiz.with_context(
active_model="purchase.request.line",
active_ids=[
purchase_request1.mapped("line_ids").id,
purchase_request2.mapped("line_ids").id,
],
).create(vals)
self.assertEqual(
(purchase_request1 | purchase_request2).mapped("line_ids"),
wiz_id.item_ids.mapped("line_id"),
"Should have same purchase request lines",
)
def test_purchase_request_to_purchase_rfq(self):
vals = {
"picking_type_id": self.env.ref("stock.picking_type_in").id,
"requested_by": SUPERUSER_ID,
}
purchase_request = self.purchase_request_obj.create(vals)
vals = {
"request_id": purchase_request.id,
"product_id": self.env.ref("product.product_product_13").id,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
"product_qty": 5.0,
"estimated_cost": 50.0,
}
purchase_request_line = self.purchase_request_line_obj.create(vals)
purchase_request.button_to_approve()
purchase_request.button_approved()
vals = {"supplier_id": self.env.ref("base.res_partner_12").id}
wiz_id = self.wiz.with_context(
active_model="purchase.request.line",
active_ids=[purchase_request_line.id],
active_id=purchase_request_line.id,
).create(vals)
for item in wiz_id.item_ids:
if item.line_id.id == purchase_request_line.id:
item.keep_estimated_cost = True
wiz_id.make_purchase_order()
purchase_order = purchase_request_line.purchase_lines.order_id
self.assertTrue(
len(purchase_request_line.purchase_lines), "Should have a purchase line"
)
self.assertEqual(
purchase_request_line.purchase_lines.product_id.id,
purchase_request_line.product_id.id,
"Should have same product",
)
self.assertEqual(
purchase_request_line.purchase_lines.state,
purchase_request_line.purchase_state,
"Should have same state",
)
self.assertEqual(
purchase_order.order_line.price_total,
purchase_request_line.estimated_cost,
"Should have same price",
)
def test_bug_is_editable_multiple_lines(self):
# Check that reading multiple lines is still possible
# https://github.com/OCA/purchase-workflow/pull/291
vals = {
"picking_type_id": self.env.ref("stock.picking_type_in").id,
"requested_by": SUPERUSER_ID,
}
purchase_request = self.purchase_request_obj.create(vals)
vals = {
"request_id": purchase_request.id,
"product_id": self.env.ref("product.product_product_13").id,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
"product_qty": 5.0,
}
purchase_request_line = self.purchase_request_line_obj.create(vals)
request_lines = purchase_request_line + purchase_request_line.copy()
request_lines.mapped("is_editable")
# Test also for onchanges on non created lines
self.purchase_request_line_obj.new({}).is_editable
def test_purchase_request_to_purchase_rfq_minimum_order_qty(self):
vals = {
"picking_type_id": self.env.ref("stock.picking_type_in").id,
"requested_by": SUPERUSER_ID,
}
purchase_request = self.purchase_request_obj.create(vals)
vals = {
"request_id": purchase_request.id,
"product_id": self.env.ref("product.product_product_8").id,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
"product_qty": 1.0,
}
purchase_request_line = self.purchase_request_line_obj.create(vals)
vals = {"supplier_id": self.env.ref("base.res_partner_1").id}
purchase_request.button_approved()
wiz_id = self.wiz.with_context(
active_model="purchase.request.line",
active_ids=[purchase_request_line.id],
active_id=purchase_request_line.id,
).create(vals)
wiz_id.make_purchase_order()
self.assertTrue(
len(purchase_request_line.purchase_lines), "Should have a purchase line"
)
self.assertEqual(
purchase_request_line.purchase_lines.product_id.id,
purchase_request_line.product_id.id,
"Should have same product",
)
self.assertEqual(
purchase_request_line.purchase_lines.state,
purchase_request_line.purchase_state,
"Should have same state",
)
self.assertEqual(
purchase_request_line.purchase_lines.product_qty,
5,
"The PO line should have the minimum order quantity.",
)
self.assertEqual(
purchase_request_line,
purchase_request_line.purchase_lines.purchase_request_lines,
"The PO should cross-reference to the purchase request.",
)
def test_purchase_request_to_purchase_rfq_multiple_po(self):
vals = {
"picking_type_id": self.env.ref("stock.picking_type_in").id,
"requested_by": SUPERUSER_ID,
}
purchase_request1 = self.purchase_request_obj.create(vals)
vals = {
"picking_type_id": self.env.ref("stock.picking_type_in").id,
"requested_by": SUPERUSER_ID,
}
purchase_request2 = self.purchase_request_obj.create(vals)
vals = {
"request_id": purchase_request1.id,
"product_id": self.env.ref("product.product_product_6").id,
"product_uom_id": self.env.ref("uom.product_uom_dozen").id,
"product_qty": 1.0,
}
purchase_request_line1 = self.purchase_request_line_obj.create(vals)
vals = {
"request_id": purchase_request2.id,
"product_id": self.env.ref("product.product_product_6").id,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
"product_qty": 1.0,
}
purchase_request_line2 = self.purchase_request_line_obj.create(vals)
vals = {
"request_id": purchase_request2.id,
"product_id": self.product_product.id,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
"product_qty": 1.0,
}
purchase_request_line3 = self.purchase_request_line_obj.create(vals)
vals = {"supplier_id": self.env.ref("base.res_partner_1").id}
purchase_request1.button_approved()
purchase_request2.button_approved()
wiz_id = self.wiz.with_context(
active_model="purchase.request.line",
active_ids=[
purchase_request_line1.id,
purchase_request_line2.id,
purchase_request_line3.id,
],
).create(vals)
for item in wiz_id.item_ids:
if item.line_id.id == purchase_request_line2.id:
item.keep_description = True
if item.line_id.id == purchase_request_line3.id:
item.onchange_product_id()
wiz_id.make_purchase_order()
self.assertEqual(
purchase_request_line1.purchased_qty, 1.0, "Should be a quantity of 1"
)
self.assertEqual(
purchase_request_line2.purchased_qty, 1.0, "Should be a quantity of 1"
)
def test_purchase_request_to_purchase_rfq_multiple_PO_purchaseUoM(self):
product = self.env.ref("product.product_product_6")
product.uom_po_id = self.env.ref("uom.product_uom_dozen")
vals = {
"picking_type_id": self.env.ref("stock.picking_type_in").id,
"requested_by": SUPERUSER_ID,
}
purchase_request1 = self.purchase_request_obj.create(vals)
vals = {
"picking_type_id": self.env.ref("stock.picking_type_in").id,
"requested_by": SUPERUSER_ID,
}
purchase_request2 = self.purchase_request_obj.create(vals)
vals = {
"request_id": purchase_request1.id,
"product_id": product.id,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
"product_qty": 12.0,
}
purchase_request_line1 = self.purchase_request_line_obj.create(vals)
vals = {
"request_id": purchase_request2.id,
"product_id": product.id,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
"product_qty": 12.0,
}
purchase_request_line2 = self.purchase_request_line_obj.create(vals)
vals = {
"request_id": purchase_request2.id,
"product_id": product.id,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
"product_qty": 1.0,
}
purchase_request_line3 = self.purchase_request_line_obj.create(vals)
vals = {"supplier_id": self.env.ref("base.res_partner_1").id}
purchase_request1.button_approved()
purchase_request2.button_approved()
wiz_id = self.wiz.with_context(
active_model="purchase.request.line",
active_ids=[
purchase_request_line1.id,
purchase_request_line2.id,
purchase_request_line3.id,
],
).create(vals)
for item in wiz_id.item_ids:
if item.line_id.id == purchase_request_line2.id:
# PRL will be splitted into another POL to keep description
item.keep_description = True
wiz_id.make_purchase_order()
po_line = purchase_request_line1.purchase_lines[0]
self.assertEqual(po_line.product_qty, 1.09, "Quantity should be 1.09")
self.assertEqual(
po_line.product_uom,
self.env.ref("uom.product_uom_dozen"),
"The purchase UoM should be Dozen(s).",
)
def test_purchase_request_to_rfq_minimum_order_qty_existing_po(self):
# Define Supplier
supplier = self.env.ref("base.res_partner_1")
# Create Product Widget min_qty = 5
product = self.env["product.product"].create(
{
"name": "Widget",
"type": "product",
"seller_ids": [
(0, 0, {"partner_id": supplier.id, "delay": 10, "min_qty": 5})
],
}
)
# Create Purchase Order with qty = 3 through Purchase Request
vals = {
"picking_type_id": self.env.ref("stock.picking_type_in").id,
"requested_by": SUPERUSER_ID,
}
purchase_request1 = self.purchase_request_obj.create(vals)
vals = {
"request_id": purchase_request1.id,
"product_id": product.id,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
"product_qty": 3.0,
}
purchase_request_line1 = self.purchase_request_line_obj.create(vals)
purchase_request1.button_approved()
vals = {"supplier_id": supplier.id}
wiz_id = self.wiz.with_context(
active_model="purchase.request.line", active_ids=[purchase_request_line1.id]
).create(vals)
wiz_id.make_purchase_order()
# The planned date is taken from the request, not from the supplier
self.assertEqual(
purchase_request_line1.date_required.day,
purchase_request_line1.purchase_lines.date_planned.day,
)
po = purchase_request_line1.purchase_lines[0].order_id
# Create Purchase Request
vals = {
"picking_type_id": self.env.ref("stock.picking_type_in").id,
"requested_by": SUPERUSER_ID,
}
purchase_request2 = self.purchase_request_obj.create(vals)
# Create Purchase Request Line qty = 3
vals = {
"request_id": purchase_request2.id,
"product_id": product.id,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
"product_qty": 3.0,
}
purchase_request_line2 = self.purchase_request_line_obj.create(vals)
# Validate
purchase_request2.button_approved()
# Create RFQ to Previous PO
vals = {"supplier_id": supplier.id, "purchase_order_id": po.id}
wiz_id = self.wiz.with_context(
active_model="purchase.request.line", active_ids=[purchase_request_line2.id]
).create(vals)
wiz_id.make_purchase_order()
# Check Purchase qty should be 6
po_line = purchase_request_line2.purchase_lines[0]
# Add unit price in PO Line
po_line.write({"price_unit": 10})
self.assertEqual(po_line.product_qty, 6.0, "Quantity should be 6")
# auto change state to done
po_line.order_id.button_confirm()
picking = po_line.order_id.picking_ids[0]
picking.move_line_ids[0].write({"qty_done": 6.0})
picking.button_validate()
def _setup_analytic_distribution(self):
analytic_plan = self.env["account.analytic.plan"].create(
{"name": "Plan Test", "company_id": False}
)
analytic_account = self.env["account.analytic.account"].create(
{"name": "default", "plan_id": analytic_plan.id}
)
return {str(analytic_account.id): 100}
def test_purchase_request_to_purchase_order_analytic_data_propagation(self):
analytic_distribution = self._setup_analytic_distribution()
vals = {
"picking_type_id": self.env.ref("stock.picking_type_in").id,
"requested_by": SUPERUSER_ID,
"line_ids": [
(
0,
0,
{
"product_id": self.env.ref("product.product_product_10").id,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
"product_qty": 5.0,
"analytic_distribution": analytic_distribution,
},
)
],
}
purchase_request = self.purchase_request_obj.create(vals)
purchase_request.button_to_approve()
purchase_request.button_approved()
supplier = self.env.ref("base.res_partner_12")
vals = {
"supplier_id": supplier.id,
}
wiz_id = self.wiz.with_context(
active_model="purchase.request.line",
active_ids=[purchase_request["line_ids"][0].id],
active_id=purchase_request["line_ids"][0].id,
).create(vals)
wiz_id.make_purchase_order()
po_line = purchase_request["line_ids"][0].purchase_lines[0]
self.assertEqual(po_line.analytic_distribution, analytic_distribution)