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:
marination 2020-11-02 15:07:48 +05:30
parent 7496ac0fe2
commit d6596a169c
9 changed files with 117 additions and 14 deletions

View File

@ -1032,7 +1032,9 @@ class PurchaseInvoice(BuyingController):
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

View File

@ -497,6 +497,10 @@ class BuyingController(StockController):
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:

View File

@ -203,6 +203,41 @@ def get_already_returned_items(doc):
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 @@ def make_return_doc(doctype, source_name, target_doc=None):
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 @@ def make_return_doc(doctype, source_name, target_doc=None):
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

View File

@ -338,11 +338,15 @@ class StockController(AccountsController):
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)

View File

@ -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.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

View File

@ -15,6 +15,13 @@ def execute():
# 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)

View File

@ -189,6 +189,7 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
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);

View File

@ -77,8 +77,8 @@ class PurchaseReceipt(BuyingController):
'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 @@ class PurchaseReceipt(BuyingController):
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 @@ def update_billed_amount_based_on_po(po_detail, update_modified=True):
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 make_purchase_invoice(source_name, target_doc=None):
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):

View File

@ -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",