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
This commit is contained in:
@@ -1032,7 +1032,9 @@ class PurchaseInvoice(BuyingController):
|
|||||||
updated_pr += update_billed_amount_based_on_po(d.po_detail, update_modified)
|
updated_pr += update_billed_amount_based_on_po(d.po_detail, update_modified)
|
||||||
|
|
||||||
for pr in set(updated_pr):
|
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):
|
def on_recurring(self, reference_doc, auto_repeat_doc):
|
||||||
self.due_date = None
|
self.due_date = None
|
||||||
|
|||||||
@@ -497,6 +497,10 @@ class BuyingController(StockController):
|
|||||||
frappe.throw(_("Row {0}: Conversion Factor is mandatory").format(d.idx))
|
frappe.throw(_("Row {0}: Conversion Factor is mandatory").format(d.idx))
|
||||||
d.stock_qty = flt(d.qty) * flt(d.conversion_factor)
|
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):
|
def validate_purchase_return(self):
|
||||||
for d in self.get("items"):
|
for d in self.get("items"):
|
||||||
if self.is_return and flt(d.rejected_qty) != 0:
|
if self.is_return and flt(d.rejected_qty) != 0:
|
||||||
|
|||||||
@@ -203,6 +203,41 @@ def get_already_returned_items(doc):
|
|||||||
|
|
||||||
return items
|
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):
|
def make_return_doc(doctype, source_name, target_doc=None):
|
||||||
from frappe.model.mapper import get_mapped_doc
|
from frappe.model.mapper import get_mapped_doc
|
||||||
company = frappe.db.get_value("Delivery Note", source_name, "company")
|
company = frappe.db.get_value("Delivery Note", source_name, "company")
|
||||||
@@ -263,11 +298,16 @@ def make_return_doc(doctype, source_name, target_doc=None):
|
|||||||
|
|
||||||
def update_item(source_doc, target_doc, source_parent):
|
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":
|
if doctype == "Purchase Receipt":
|
||||||
target_doc.received_qty = -1* source_doc.received_qty
|
returned_qty_map = get_returned_qty_map_for_row(source_doc.name, doctype)
|
||||||
target_doc.rejected_qty = -1* source_doc.rejected_qty
|
target_doc.received_qty = -1 * flt(source_doc.received_qty - (returned_qty_map.get('received_qty') or 0))
|
||||||
target_doc.qty = -1* source_doc.qty
|
target_doc.rejected_qty = -1 * flt(source_doc.rejected_qty - (returned_qty_map.get('rejected_qty') or 0))
|
||||||
target_doc.stock_qty = -1 * source_doc.stock_qty
|
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 = source_doc.purchase_order
|
||||||
target_doc.purchase_order_item = source_doc.purchase_order_item
|
target_doc.purchase_order_item = source_doc.purchase_order_item
|
||||||
target_doc.rejected_warehouse = source_doc.rejected_warehouse
|
target_doc.rejected_warehouse = source_doc.rejected_warehouse
|
||||||
@@ -286,6 +326,10 @@ def make_return_doc(doctype, source_name, target_doc=None):
|
|||||||
target_doc.purchase_invoice_item = source_doc.name
|
target_doc.purchase_invoice_item = source_doc.name
|
||||||
|
|
||||||
elif doctype == "Delivery Note":
|
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_order = source_doc.against_sales_order
|
||||||
target_doc.against_sales_invoice = source_doc.against_sales_invoice
|
target_doc.against_sales_invoice = source_doc.against_sales_invoice
|
||||||
target_doc.so_detail = source_doc.so_detail
|
target_doc.so_detail = source_doc.so_detail
|
||||||
|
|||||||
@@ -338,11 +338,15 @@ class StockController(AccountsController):
|
|||||||
validate_warehouse_company(w, self.company)
|
validate_warehouse_company(w, self.company)
|
||||||
|
|
||||||
def update_billing_percentage(self, update_modified=True):
|
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({
|
self._update_percent_field({
|
||||||
"target_dt": self.doctype + " Item",
|
"target_dt": self.doctype + " Item",
|
||||||
"target_parent_dt": self.doctype,
|
"target_parent_dt": self.doctype,
|
||||||
"target_parent_field": "per_billed",
|
"target_parent_field": "per_billed",
|
||||||
"target_ref_field": "amount",
|
"target_ref_field": target_ref_field,
|
||||||
"target_field": "billed_amt",
|
"target_field": "billed_amt",
|
||||||
"name": self.name,
|
"name": self.name,
|
||||||
}, update_modified)
|
}, update_modified)
|
||||||
|
|||||||
@@ -732,4 +732,4 @@ erpnext.patches.v13_0.set_youtube_video_id
|
|||||||
erpnext.patches.v13_0.print_uom_after_quantity_patch
|
erpnext.patches.v13_0.print_uom_after_quantity_patch
|
||||||
erpnext.patches.v13_0.set_payment_channel_in_payment_gateway_account
|
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.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
|
||||||
@@ -15,6 +15,13 @@ def execute():
|
|||||||
# Update original receipt/delivery document from return
|
# Update original receipt/delivery document from return
|
||||||
return_doc = frappe.get_cached_doc(doctype, return_doc.name)
|
return_doc = frappe.get_cached_doc(doctype, return_doc.name)
|
||||||
return_doc.update_prevdoc_status()
|
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'):
|
for doctype in ('Purchase Receipt', 'Delivery Note'):
|
||||||
update_from_return_docs(doctype)
|
update_from_return_docs(doctype)
|
||||||
@@ -189,6 +189,7 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
|||||||
|
|
||||||
frappe.model.round_floats_in(item, ["qty", "received_qty"]);
|
frappe.model.round_floats_in(item, ["qty", "received_qty"]);
|
||||||
item.rejected_qty = flt(item.received_qty - item.qty, precision("rejected_qty", item));
|
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);
|
this._super(doc, cdt, cdn);
|
||||||
|
|||||||
@@ -77,8 +77,8 @@ class PurchaseReceipt(BuyingController):
|
|||||||
'target_field': 'returned_qty',
|
'target_field': 'returned_qty',
|
||||||
'target_parent_dt': 'Purchase Receipt',
|
'target_parent_dt': 'Purchase Receipt',
|
||||||
'target_parent_field': 'per_returned',
|
'target_parent_field': 'per_returned',
|
||||||
'target_ref_field': 'stock_qty',
|
'target_ref_field': 'received_stock_qty',
|
||||||
'source_field': '-1 * stock_qty',
|
'source_field': '-1 * received_stock_qty',
|
||||||
'percent_join_field_parent': 'return_against'
|
'percent_join_field_parent': 'return_against'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
@@ -503,7 +503,7 @@ class PurchaseReceipt(BuyingController):
|
|||||||
|
|
||||||
for pr in set(updated_pr):
|
for pr in set(updated_pr):
|
||||||
pr_doc = self if (pr == self.name) else frappe.get_doc("Purchase Receipt", 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()
|
self.load_from_db()
|
||||||
|
|
||||||
@@ -543,6 +543,39 @@ def update_billed_amount_based_on_po(po_detail, update_modified=True):
|
|||||||
|
|
||||||
return updated_pr
|
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()
|
@frappe.whitelist()
|
||||||
def make_purchase_invoice(source_name, target_doc=None):
|
def make_purchase_invoice(source_name, target_doc=None):
|
||||||
from frappe.model.mapper import get_mapped_doc
|
from frappe.model.mapper import get_mapped_doc
|
||||||
@@ -562,6 +595,7 @@ def make_purchase_invoice(source_name, target_doc=None):
|
|||||||
|
|
||||||
def update_item(source_doc, target_doc, source_parent):
|
def update_item(source_doc, target_doc, source_parent):
|
||||||
target_doc.qty, returned_qty = get_pending_qty(source_doc)
|
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
|
returned_qty_map[source_doc.name] = returned_qty
|
||||||
|
|
||||||
def get_pending_qty(item_row):
|
def get_pending_qty(item_row):
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
"retain_sample",
|
"retain_sample",
|
||||||
"sample_quantity",
|
"sample_quantity",
|
||||||
"tracking_section",
|
"tracking_section",
|
||||||
|
"received_stock_qty",
|
||||||
"stock_qty",
|
"stock_qty",
|
||||||
"col_break_tracking_section",
|
"col_break_tracking_section",
|
||||||
"returned_qty",
|
"returned_qty",
|
||||||
@@ -854,12 +855,18 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "received_stock_qty",
|
||||||
|
"fieldtype": "Float",
|
||||||
|
"label": "Received Qty in Stock UOM",
|
||||||
|
"print_hide": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-09-09 13:39:46.452817",
|
"modified": "2020-11-02 10:00:38.204294",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Purchase Receipt Item",
|
"name": "Purchase Receipt Item",
|
||||||
|
|||||||
Reference in New Issue
Block a user