fix: Billing % Logic and Map Pending Qty only in PR and DN
- Billing % should consider unreturned amount as total
- While mapping to return doc, map unreturned amount
- Added field Received Qty in Stock UOM, to tally against Returned Qty in PR
- PR billing percentage updation custom function
- In patch set received qty in stock uom first, then update returned qty and billing
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 91c4dfb..014f05c 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -1032,7 +1032,9 @@
updated_pr += update_billed_amount_based_on_po(d.po_detail, update_modified)
for pr in set(updated_pr):
- frappe.get_doc("Purchase Receipt", pr).update_billing_percentage(update_modified=update_modified)
+ from erpnext.stock.doctype.purchase_receipt.purchase_receipt import update_billing_percentage
+ pr_doc = frappe.get_doc("Purchase Receipt", pr)
+ update_billing_percentage(pr_doc, update_modified=update_modified)
def on_recurring(self, reference_doc, auto_repeat_doc):
self.due_date = None
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index f376836..af2474d 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -497,6 +497,10 @@
frappe.throw(_("Row {0}: Conversion Factor is mandatory").format(d.idx))
d.stock_qty = flt(d.qty) * flt(d.conversion_factor)
+ if self.doctype=="Purchase Receipt" and d.meta.get_field("received_stock_qty"):
+ # Set Received Qty in Stock UOM
+ d.received_stock_qty = flt(d.received_qty) * flt(d.conversion_factor, d.precision("conversion_factor"))
+
def validate_purchase_return(self):
for d in self.get("items"):
if self.is_return and flt(d.rejected_qty) != 0:
diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py
index b4da5fa..e11289d 100644
--- a/erpnext/controllers/sales_and_purchase_return.py
+++ b/erpnext/controllers/sales_and_purchase_return.py
@@ -203,6 +203,41 @@
return items
+def get_returned_qty_map_for_row(row_name, doctype):
+ child_doctype = doctype + " Item"
+ reference_field = frappe.scrub(child_doctype) if doctype == "Purchase Receipt" else "dn_detail"
+ reference_field = "child." + reference_field
+ columns = ""
+
+ if doctype == "Purchase Receipt":
+ columns += ", sum(abs(child.rejected_qty)) as rejected_qty, \
+ sum(abs(child.received_qty)) as received_qty, \
+ sum(abs(child.received_stock_qty)) as received_stock_qty"
+
+ data = frappe.db.sql("""
+ select
+ sum(abs(child.qty)) as qty,
+ sum(abs(child.stock_qty)) as stock_qty,
+ %(columns)s
+ from
+ `tab{0}` child, `tab{1}` parent
+ where
+ child.parent = parent.name
+ and parent.docstatus = 1
+ and parent.is_return = 1
+ and {2} = %(row_name)s
+ """.format(child_doctype, doctype, reference_field),
+ {
+ "row_name": row_name,
+ "columns": columns,
+ "child_doctype": child_doctype,
+ "doctype": doctype,
+ "reference_field": reference_field
+ },
+ as_dict=1)
+
+ return data[0]
+
def make_return_doc(doctype, source_name, target_doc=None):
from frappe.model.mapper import get_mapped_doc
company = frappe.db.get_value("Delivery Note", source_name, "company")
@@ -262,20 +297,25 @@
doc.run_method("calculate_taxes_and_totals")
def update_item(source_doc, target_doc, source_parent):
- target_doc.qty = -1* source_doc.qty
+ target_doc.qty = -1 * source_doc.qty
+
if doctype == "Purchase Receipt":
- target_doc.received_qty = -1* source_doc.received_qty
- target_doc.rejected_qty = -1* source_doc.rejected_qty
- target_doc.qty = -1* source_doc.qty
- target_doc.stock_qty = -1 * source_doc.stock_qty
+ returned_qty_map = get_returned_qty_map_for_row(source_doc.name, doctype)
+ target_doc.received_qty = -1 * flt(source_doc.received_qty - (returned_qty_map.get('received_qty') or 0))
+ target_doc.rejected_qty = -1 * flt(source_doc.rejected_qty - (returned_qty_map.get('rejected_qty') or 0))
+ target_doc.qty = -1 * flt(source_doc.qty - (returned_qty_map.get('qty') or 0))
+
+ target_doc.stock_qty = -1 * flt(source_doc.stock_qty - (returned_qty_map.get('stock_qty') or 0))
+ target_doc.received_stock_qty = -1 * flt(source_doc.received_stock_qty - (returned_qty_map.get('received_stock_qty') or 0))
+
target_doc.purchase_order = source_doc.purchase_order
target_doc.purchase_order_item = source_doc.purchase_order_item
target_doc.rejected_warehouse = source_doc.rejected_warehouse
target_doc.purchase_receipt_item = source_doc.name
elif doctype == "Purchase Invoice":
- target_doc.received_qty = -1* source_doc.received_qty
- target_doc.rejected_qty = -1* source_doc.rejected_qty
+ target_doc.received_qty = -1 * source_doc.received_qty
+ target_doc.rejected_qty = -1 * source_doc.rejected_qty
target_doc.qty = -1* source_doc.qty
target_doc.stock_qty = -1 * source_doc.stock_qty
target_doc.purchase_order = source_doc.purchase_order
@@ -286,6 +326,10 @@
target_doc.purchase_invoice_item = source_doc.name
elif doctype == "Delivery Note":
+ returned_qty_map = get_returned_qty_map_for_row(source_doc.name, doctype)
+ target_doc.qty = -1 * flt(source_doc.qty - (returned_qty_map.get('qty') or 0))
+ target_doc.stock_qty = -1 * flt(source_doc.stock_qty - (returned_qty_map.get('stock_qty') or 0))
+
target_doc.against_sales_order = source_doc.against_sales_order
target_doc.against_sales_invoice = source_doc.against_sales_invoice
target_doc.so_detail = source_doc.so_detail
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index f743d70..196279f 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -338,11 +338,15 @@
validate_warehouse_company(w, self.company)
def update_billing_percentage(self, update_modified=True):
+ target_ref_field = "amount"
+ if self.doctype == "Delivery Note":
+ target_ref_field = "amount - (returned_qty * rate)"
+
self._update_percent_field({
"target_dt": self.doctype + " Item",
"target_parent_dt": self.doctype,
"target_parent_field": "per_billed",
- "target_ref_field": "amount",
+ "target_ref_field": target_ref_field,
"target_field": "billed_amt",
"name": self.name,
}, update_modified)
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 6dfa085..dc7e99b 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -732,4 +732,4 @@
erpnext.patches.v13_0.print_uom_after_quantity_patch
erpnext.patches.v13_0.set_payment_channel_in_payment_gateway_account
erpnext.patches.v13_0.create_healthcare_custom_fields_in_stock_entry_detail
-erpnext.patches.v13_0.update_returned_qty_in_pr_dn
+erpnext.patches.v13_0.update_returned_qty_in_pr_dn #12am
\ No newline at end of file
diff --git a/erpnext/patches/v13_0/update_returned_qty_in_pr_dn.py b/erpnext/patches/v13_0/update_returned_qty_in_pr_dn.py
index a13640e..7f42cd9 100644
--- a/erpnext/patches/v13_0/update_returned_qty_in_pr_dn.py
+++ b/erpnext/patches/v13_0/update_returned_qty_in_pr_dn.py
@@ -15,6 +15,13 @@
# Update original receipt/delivery document from return
return_doc = frappe.get_cached_doc(doctype, return_doc.name)
return_doc.update_prevdoc_status()
+ return_against = frappe.get_doc(doctype, return_doc.return_against)
+ return_against.update_billing_status()
+
+ # Set received qty in stock uom in PR, as returned qty is checked against it
+ frappe.db.sql(""" update `tabPurchase Receipt Item`
+ set received_stock_qty = received_qty * conversion_factor
+ where docstatus = 1 """)
for doctype in ('Purchase Receipt', 'Delivery Note'):
update_from_return_docs(doctype)
\ No newline at end of file
diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js
index cb76c87..11f70f7 100644
--- a/erpnext/public/js/controllers/buying.js
+++ b/erpnext/public/js/controllers/buying.js
@@ -189,6 +189,7 @@
frappe.model.round_floats_in(item, ["qty", "received_qty"]);
item.rejected_qty = flt(item.received_qty - item.qty, precision("rejected_qty", item));
+ item.received_stock_qty = flt(item.conversion_factor, precision("conversion_factor", item)) * flt(item.received_qty);
}
this._super(doc, cdt, cdn);
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index 551f377..be3ff5e 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -77,8 +77,8 @@
'target_field': 'returned_qty',
'target_parent_dt': 'Purchase Receipt',
'target_parent_field': 'per_returned',
- 'target_ref_field': 'stock_qty',
- 'source_field': '-1 * stock_qty',
+ 'target_ref_field': 'received_stock_qty',
+ 'source_field': '-1 * received_stock_qty',
'percent_join_field_parent': 'return_against'
}
])
@@ -503,7 +503,7 @@
for pr in set(updated_pr):
pr_doc = self if (pr == self.name) else frappe.get_doc("Purchase Receipt", pr)
- pr_doc.update_billing_percentage(update_modified=update_modified)
+ update_billing_percentage(pr_doc, update_modified=update_modified)
self.load_from_db()
@@ -543,6 +543,39 @@
return updated_pr
+def update_billing_percentage(pr_doc, update_modified=True):
+ # Update Billing % based on pending accepted qty
+ total_amount, total_billed_amount = 0, 0
+ for item in pr_doc.items:
+ returned_qty = frappe.db.sql("""
+ select sum(abs(child.qty)) as qty
+ from
+ `tabPurchase Receipt Item` child,
+ `tabPurchase Receipt` parent
+ where
+ child.parent = parent.name
+ and parent.docstatus = 1
+ and parent.is_return = 1
+ and child.purchase_receipt_item = %(row_name)s
+ """, {"row_name": item.name})
+ returned_qty = returned_qty[0][0] if returned_qty else 0
+
+ returned_amount = flt(returned_qty) * flt(item.rate)
+ pending_amount = flt(item.amount) - returned_amount
+ total_billable_amount = pending_amount if item.billed_amt <= pending_amount else item.billed_amt
+
+ total_amount += total_billable_amount
+ total_billed_amount += flt(item.billed_amt)
+
+ print(total_billed_amount, total_amount)
+ percent_billed = round(100 * (total_billed_amount / total_amount), 6)
+ pr_doc.db_set("per_billed", percent_billed)
+ pr_doc.load_from_db()
+
+ if update_modified:
+ pr_doc.set_status(update=True)
+ pr_doc.notify_update()
+
@frappe.whitelist()
def make_purchase_invoice(source_name, target_doc=None):
from frappe.model.mapper import get_mapped_doc
@@ -562,6 +595,7 @@
def update_item(source_doc, target_doc, source_parent):
target_doc.qty, returned_qty = get_pending_qty(source_doc)
+ target_doc.stock_qty = flt(target_doc.qty) * flt(target_doc.conversion_factor, target_doc.precision("conversion_factor"))
returned_qty_map[source_doc.name] = returned_qty
def get_pending_qty(item_row):
diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
index 20ae56f..84c64aa 100644
--- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
+++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
@@ -31,6 +31,7 @@
"retain_sample",
"sample_quantity",
"tracking_section",
+ "received_stock_qty",
"stock_qty",
"col_break_tracking_section",
"returned_qty",
@@ -854,12 +855,18 @@
"no_copy": 1,
"print_hide": 1,
"read_only": 1
+ },
+ {
+ "fieldname": "received_stock_qty",
+ "fieldtype": "Float",
+ "label": "Received Qty in Stock UOM",
+ "print_hide": 1
}
],
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2020-09-09 13:39:46.452817",
+ "modified": "2020-11-02 10:00:38.204294",
"modified_by": "Administrator",
"module": "Stock",
"name": "Purchase Receipt Item",