Fixed logic and tests
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index a43c30d..5af3078 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -292,6 +292,13 @@
if d.rm_item_code:
stock_bin = get_bin(d.rm_item_code, d.reserve_warehouse)
stock_bin.update_reserved_qty_for_sub_contracting()
+
+ def update_receiving_percentage(self):
+ total_qty, received_qty = 0.0, 0.0
+ for item in self.items:
+ received_qty += item.received_qty
+ total_qty += item.qty
+ self.db_set("per_received", flt(received_qty/total_qty) * 100, update_modified=False)
def item_last_purchase_rate(name, conversion_rate, item_code, conversion_factor= 1.0):
"""get last purchase rate for an item"""
diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
index 32f8ee8..c67d4e5 100644
--- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
@@ -9,6 +9,8 @@
from frappe.utils import flt, add_days, nowdate
from erpnext.stock.doctype.item.test_item import make_item
from erpnext.buying.doctype.purchase_order.purchase_order import (make_purchase_receipt, make_purchase_invoice, make_rm_stock_entry as make_subcontract_transfer_entry)
+from erpnext.stock.doctype.material_request.test_material_request import make_material_request
+from erpnext.stock.doctype.material_request.material_request import make_purchase_order
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
from erpnext.controllers.accounts_controller import update_child_qty_rate
import json
@@ -78,18 +80,34 @@
self.assertEqual(po.get("items")[0].received_qty, 0)
def test_update_child_qty_rate(self):
- po = create_purchase_order(item_code= "_Test Item", qty=4)
+ mr = make_material_request(qty=10)
+ po = make_purchase_order(mr.name)
+ po.supplier = "_Test Supplier"
+ po.items[0].qty = 4
+ po.save()
+ po.submit()
create_pr_against_po(po.name)
make_purchase_invoice(po.name)
- trans_item = {'item_code' : '_Test Item', 'rate' : 200, 'qty' : 7}
+ existing_ordered_qty = get_ordered_qty()
+ existing_requested_qty = get_requested_qty()
+
+ trans_item = json.dumps([{'item_code' : '_Test Item', 'rate' : 200, 'qty' : 7, 'docname': po.items[0].name}])
update_child_qty_rate('Purchase Order', trans_item, po.name)
+ mr.reload()
+ self.assertEqual(mr.items[0].ordered_qty, 7)
+ self.assertEqual(mr.per_ordered, 70)
+ self.assertEqual(get_requested_qty(), existing_requested_qty - 3)
+
+ po.reload()
self.assertEqual(po.get("items")[0].rate, 200)
self.assertEqual(po.get("items")[0].qty, 7)
self.assertEqual(po.get("items")[0].amount, 1400)
+ self.assertEqual(get_ordered_qty(), existing_ordered_qty + 3)
+
def test_make_purchase_invoice(self):
po = create_purchase_order(do_not_submit=True)
@@ -536,6 +554,10 @@
return flt(frappe.db.get_value("Bin", {"item_code": item_code, "warehouse": warehouse},
"ordered_qty"))
+def get_requested_qty(item_code="_Test Item", warehouse="_Test Warehouse - _TC"):
+ return flt(frappe.db.get_value("Bin", {"item_code": item_code, "warehouse": warehouse},
+ "indented_qty"))
+
test_dependencies = ["BOM", "Item Price"]
test_records = frappe.get_test_records('Purchase Order')
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 9751e83..fe8e34e 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -783,7 +783,6 @@
else:
return frappe.db.get_single_value("Global Defaults", "disable_rounded_total")
-
@frappe.whitelist()
def get_tax_rate(account_head):
return frappe.db.get_value("Account", account_head, ["tax_rate", "account_name"], as_dict=True)
@@ -1045,13 +1044,13 @@
data = json.loads(trans_items)
for d in data:
child_item = frappe.get_doc(parent_doctype + ' Item', d.get("docname"))
- child_item.qty = float(d.get("qty"))
+ child_item.qty = flt(d.get("qty"))
- if child_item.billed_amt > (float(d.get("rate")) * float(d.get("qty"))):
+ if child_item.billed_amt > (flt(d.get("rate")) * flt(d.get("qty"))):
frappe.throw(_("Row #{0}: Cannot set Rate if amount is greater than billed amount for Item {1}.")
.format(child_item.idx, child_item.item_code))
else:
- child_item.rate = float(d.get("rate"))
+ child_item.rate = flt(d.get("rate"))
child_item.flags.ignore_validate_update_after_submit = True
child_item.save()
@@ -1059,28 +1058,36 @@
p_doctype.flags.ignore_validate_update_after_submit = True
p_doctype.set_qty_as_per_stock_uom()
- if parent_doctype == 'Purchase Order':
- p_doctype.validate_minimum_order_qty()
- update_last_purchase_rate(p_doctype, is_submit = 1)
- if p_doctype.is_against_so():
- p_doctype.update_status_updater()
- p_doctype.update_prevdoc_status()
- p_doctype.update_requested_qty()
- p_doctype.update_ordered_qty()
- p_doctype.validate_budget()
- p_doctype.update_ordered_and_reserved_qty()
- if p_doctype.is_subcontracted == "Yes":
- p_doctype.update_reserved_qty_for_subcontract()
- else:
- p_doctype.check_credit_limit()
- p_doctype.update_reserved_qty()
- p_doctype.update_project()
- p_doctype.update_prevdoc_status('submit')
- p_doctype.update_blanket_order()
- p_doctype.set_status()
+ p_doctype.calculate_taxes_and_totals()
frappe.get_doc('Authorization Control').validate_approving_authority(p_doctype.doctype,
p_doctype.company, p_doctype.base_grand_total)
- p_doctype.calculate_taxes_and_totals()
p_doctype.set_payment_schedule()
+ if parent_doctype == 'Purchase Order':
+ p_doctype.validate_minimum_order_qty()
+ p_doctype.validate_budget()
+ if p_doctype.is_against_so():
+ p_doctype.update_status_updater()
+ else:
+ p_doctype.check_credit_limit()
+
p_doctype.save()
+
+ if parent_doctype == 'Purchase Order':
+ update_last_purchase_rate(p_doctype, is_submit = 1)
+ p_doctype.update_prevdoc_status()
+ p_doctype.update_requested_qty()
+ p_doctype.update_ordered_qty()
+ p_doctype.update_ordered_and_reserved_qty()
+ p_doctype.update_receiving_percentage()
+ if p_doctype.is_subcontracted == "Yes":
+ p_doctype.update_reserved_qty_for_subcontract()
+ else:
+ p_doctype.update_reserved_qty()
+ p_doctype.update_project()
+ p_doctype.update_prevdoc_status('submit')
+ p_doctype.update_delivery_status()
+
+ p_doctype.update_blanket_order()
+ p_doctype.update_billing_percentage()
+ p_doctype.set_status()
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index 410510b..a3993b8 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -256,17 +256,21 @@
def test_update_child_qty_rate(self):
so = make_sales_order(item_code= "_Test Item", qty=4)
-
- make_delivery_note(so.name)
-
+ create_dn_against_so(so.name, 4)
make_sales_invoice(so.name)
- trans_item = {'item_code' : '_Test Item', 'rate' : 200, 'qty' : 7}
+ existing_reserved_qty = get_reserved_qty()
+
+ trans_item = json.dumps([{'item_code' : '_Test Item', 'rate' : 200, 'qty' : 7, 'docname': so.items[0].name}])
update_child_qty_rate('Sales Order', trans_item, so.name)
-
+
+ so.reload()
self.assertEqual(so.get("items")[0].rate, 200)
self.assertEqual(so.get("items")[0].qty, 7)
self.assertEqual(so.get("items")[0].amount, 1400)
+ self.assertEqual(so.status, 'To Deliver and Bill')
+
+ self.assertEqual(get_reserved_qty(), existing_reserved_qty + 3)
def test_warehouse_user(self):
frappe.permissions.add_user_permission("Warehouse", "_Test Warehouse 1 - _TC", "test@example.com")
diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py
index 6b0b7bb..c9bb169 100644
--- a/erpnext/stock/doctype/material_request/test_material_request.py
+++ b/erpnext/stock/doctype/material_request/test_material_request.py
@@ -601,5 +601,21 @@
mr = frappe.get_doc("Material Request", mr.name)
self.assertEqual(mr.per_ordered, 100)
+def make_material_request(**args):
+ args = frappe._dict(args)
+ mr = frappe.new_doc("Material Request")
+ mr.material_request_type = args.material_request_type or "Purchase"
+ mr.company = args.company or "_Test Company"
+ mr.append("items", {
+ "item_code": args.item_code or "_Test Item",
+ "qty": args.qty or 10,
+ "schedule_date": args.schedule_date or today(),
+ "warehouse": args.warehouse or "_Test Warehouse - _TC"
+ })
+ mr.insert()
+ if not args.do_not_submit:
+ mr.submit()
+ return mr
+
test_dependencies = ["Currency Exchange", "BOM"]
test_records = frappe.get_test_records('Material Request')