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