oca-purchase/odoo-bringout-oca-purchase-workflow-purchase_request/purchase_request/tests/test_purchase_request.py
Ernad Husremovic 7378b233e9 Add oca-purchase submodule with 96 purchase modules moved from oca-workflow-process
🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-30 18:00:40 +02:00

311 lines
13 KiB
Python

# 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()