mirror of
https://github.com/bringout/oca-purchase.git
synced 2026-04-20 07:02:09 +02:00
🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
311 lines
13 KiB
Python
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()
|