diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index 7f6e2b99c89..2890ba929d1 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -3,8 +3,14 @@ import frappe +<<<<<<< HEAD from frappe import _, scrub from frappe.utils import cint, flt +======= +from frappe import _, qb, scrub +from frappe.query_builder import Order +from frappe.utils import cint, flt, formatdate +>>>>>>> e4d16c31da (fix: GP incorrect buying amount if no upd on SI and Delivery Note) from erpnext.controllers.queries import get_match_cond from erpnext.stock.utils import get_incoming_rate @@ -367,6 +373,7 @@ class GrossProfitGenerator(object): self.average_buying_rate = {} self.filters = frappe._dict(filters) self.load_invoice_items() + self.get_delivery_notes() if filters.group_by == "Invoice": self.group_items_by_invoice() @@ -535,6 +542,21 @@ class GrossProfitGenerator(object): return flt(buying_amount, self.currency_precision) + def calculate_buying_amount_from_sle(self, row, my_sle, parenttype, parent, item_row, item_code): + for i, sle in enumerate(my_sle): + # find the stock valution rate from stock ledger entry + if ( + sle.voucher_type == parenttype + and parent == sle.voucher_no + and sle.voucher_detail_no == item_row + ): + previous_stock_value = len(my_sle) > i + 1 and flt(my_sle[i + 1].stock_value) or 0.0 + + if previous_stock_value: + return abs(previous_stock_value - flt(sle.stock_value)) * flt(row.qty) / abs(flt(sle.qty)) + else: + return flt(row.qty) * self.get_average_buying_rate(row, item_code) + def get_buying_amount(self, row, item_code): # IMP NOTE # stock_ledger_entries should already be filtered by item_code and warehouse and @@ -551,19 +573,22 @@ class GrossProfitGenerator(object): if row.dn_detail: parenttype, parent = "Delivery Note", row.delivery_note - for i, sle in enumerate(my_sle): - # find the stock valution rate from stock ledger entry - if ( - sle.voucher_type == parenttype - and parent == sle.voucher_no - and sle.voucher_detail_no == row.item_row - ): - previous_stock_value = len(my_sle) > i + 1 and flt(my_sle[i + 1].stock_value) or 0.0 - - if previous_stock_value: - return abs(previous_stock_value - flt(sle.stock_value)) * flt(row.qty) / abs(flt(sle.qty)) - else: - return flt(row.qty) * self.get_average_buying_rate(row, item_code) + return self.calculate_buying_amount_from_sle( + row, my_sle, parenttype, parent, row.item_row, item_code + ) + elif self.delivery_notes.get((row.parent, row.item_code), None): + # check if Invoice has delivery notes + dn = self.delivery_notes.get((row.parent, row.item_code)) + parenttype, parent, item_row, warehouse = ( + "Delivery Note", + dn["delivery_note"], + dn["item_row"], + dn["warehouse"], + ) + my_sle = self.sle.get((item_code, warehouse)) + return self.calculate_buying_amount_from_sle( + row, my_sle, parenttype, parent, item_row, item_code + ) else: return flt(row.qty) * self.get_average_buying_rate(row, item_code) @@ -667,6 +692,29 @@ class GrossProfitGenerator(object): as_dict=1, ) + def get_delivery_notes(self): + self.delivery_notes = frappe._dict({}) + if self.si_list: + invoices = [x.parent for x in self.si_list] + dni = qb.DocType("Delivery Note Item") + delivery_notes = ( + qb.from_(dni) + .select( + dni.against_sales_invoice.as_("sales_invoice"), + dni.item_code, + dni.warehouse, + dni.parent.as_("delivery_note"), + dni.name.as_("item_row"), + ) + .where((dni.docstatus == 1) & (dni.against_sales_invoice.isin(invoices))) + .groupby(dni.against_sales_invoice, dni.item_code) + .orderby(dni.creation, order=Order.desc) + .run(as_dict=True) + ) + + for entry in delivery_notes: + self.delivery_notes[(entry.sales_invoice, entry.item_code)] = entry + def group_items_by_invoice(self): """ Turns list of Sales Invoice Items to a tree of Sales Invoices with their Items as children.