Merge pull request #36752 from s-aga-r/FR-35157

feat: `Update Items` for Subcontract Purchase Order
This commit is contained in:
s-aga-r
2023-08-23 11:13:28 +05:30
committed by GitHub
6 changed files with 162 additions and 9 deletions

View File

@@ -185,8 +185,7 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends e
if(!in_list(["Closed", "Delivered"], doc.status)) {
if(this.frm.doc.status !== 'Closed' && flt(this.frm.doc.per_received, 2) < 100 && flt(this.frm.doc.per_billed, 2) < 100) {
// Don't add Update Items button if the PO is following the new subcontracting flow.
if (!(this.frm.doc.is_subcontracted && !this.frm.doc.is_old_subcontracting_flow)) {
if (!this.frm.doc.__onload || this.frm.doc.__onload.can_update_items) {
this.frm.add_custom_button(__('Update Items'), () => {
erpnext.utils.update_child_items({
frm: this.frm,

View File

@@ -52,6 +52,7 @@ class PurchaseOrder(BuyingController):
def onload(self):
supplier_tds = frappe.db.get_value("Supplier", self.supplier, "tax_withholding_category")
self.set_onload("supplier_tds", supplier_tds)
self.set_onload("can_update_items", self.can_update_items())
def validate(self):
super(PurchaseOrder, self).validate()
@@ -450,6 +451,17 @@ class PurchaseOrder(BuyingController):
else:
self.db_set("per_received", 0, update_modified=False)
def can_update_items(self) -> bool:
result = True
if self.is_subcontracted and not self.is_old_subcontracting_flow:
if frappe.db.exists(
"Subcontracting Order", {"purchase_order": self.name, "docstatus": ["!=", 2]}
):
result = False
return result
def item_last_purchase_rate(name, conversion_rate, item_code, conversion_factor=1.0):
"""get last purchase rate for an item"""

View File

@@ -901,6 +901,71 @@ class TestPurchaseOrder(FrappeTestCase):
self.assertRaises(frappe.ValidationError, po.save)
def test_update_items_for_subcontracting_purchase_order(self):
from erpnext.controllers.tests.test_subcontracting_controller import (
get_subcontracting_order,
make_bom_for_subcontracted_items,
make_raw_materials,
make_service_items,
make_subcontracted_items,
)
def update_items(po, qty):
trans_items = [po.items[0].as_dict()]
trans_items[0]["qty"] = qty
trans_items[0]["fg_item_qty"] = qty
trans_items = json.dumps(trans_items, default=str)
return update_child_qty_rate(
po.doctype,
trans_items,
po.name,
)
make_subcontracted_items()
make_raw_materials()
make_service_items()
make_bom_for_subcontracted_items()
service_items = [
{
"warehouse": "_Test Warehouse - _TC",
"item_code": "Subcontracted Service Item 7",
"qty": 10,
"rate": 100,
"fg_item": "Subcontracted Item SA7",
"fg_item_qty": 10,
},
]
po = create_purchase_order(
rm_items=service_items,
is_subcontracted=1,
supplier_warehouse="_Test Warehouse 1 - _TC",
)
update_items(po, qty=20)
po.reload()
# Test - 1: Items should be updated as there is no Subcontracting Order against PO
self.assertEqual(po.items[0].qty, 20)
self.assertEqual(po.items[0].fg_item_qty, 20)
sco = get_subcontracting_order(po_name=po.name, warehouse="_Test Warehouse - _TC")
# Test - 2: ValidationError should be raised as there is Subcontracting Order against PO
self.assertRaises(frappe.ValidationError, update_items, po=po, qty=30)
sco.reload()
sco.cancel()
po.reload()
update_items(po, qty=30)
po.reload()
# Test - 3: Items should be updated as the Subcontracting Order is cancelled
self.assertEqual(po.items[0].qty, 30)
self.assertEqual(po.items[0].fg_item_qty, 30)
def prepare_data_for_internal_transfer():
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier