diff --git a/accounts/report/gross_profit/gross_profit.py b/accounts/report/gross_profit/gross_profit.py index dcef5b815a..3aba234c19 100644 --- a/accounts/report/gross_profit/gross_profit.py +++ b/accounts/report/gross_profit/gross_profit.py @@ -10,9 +10,7 @@ def execute(filters=None): if not filters: filters = {} stock_ledger_entries = get_stock_ledger_entries(filters) - source = get_source_data(filters) - item_sales_bom = get_item_sales_bom() columns = ["Delivery Note/Sales Invoice::120", "Link::30", "Posting Date:Date", "Posting Time", @@ -20,12 +18,12 @@ def execute(filters=None): "Qty:Float", "Selling Rate:Currency", "Avg. Buying Rate:Currency", "Selling Amount:Currency", "Buying Amount:Currency", "Gross Profit:Currency", "Gross Profit %:Percent", "Project:Link/Project"] - data = [] for row in source: selling_amount = flt(row.amount) - buying_amount = get_buying_amount(row.item_code, row.warehouse, -1*row.qty, - row.parenttype, row.name, row.item_row, stock_ledger_entries, + + buying_amount = get_buying_amount(row.item_code, row.parenttype, row.name, row.item_row, + stock_ledger_entries.get((row.item_code, row.warehouse), []), item_sales_bom.get(row.parenttype, {}).get(row.name, webnotes._dict())) buying_amount = buying_amount > 0 and buying_amount or 0 @@ -56,8 +54,17 @@ def get_stock_ledger_entries(filters): query += """ and company=%(company)s""" query += " order by item_code desc, warehouse desc, posting_date desc, posting_time desc, name desc" + + res = webnotes.conn.sql(query, filters, as_dict=True) + + out = {} + for r in res: + if (r.item_code, r.warehouse) not in out: + out[(r.item_code, r.warehouse)] = [] + + out[(r.item_code, r.warehouse)].append(r) - return webnotes.conn.sql(query, filters, as_dict=True) + return out def get_item_sales_bom(): item_sales_bom = {} diff --git a/controllers/selling_controller.py b/controllers/selling_controller.py index eb2e9ef604..033ac83db8 100644 --- a/controllers/selling_controller.py +++ b/controllers/selling_controller.py @@ -103,8 +103,8 @@ class SellingController(StockController): for item in self.doclist.get({"parentfield": self.fname}): if item.item_code in self.stock_items or \ (item_sales_bom and item_sales_bom.get(item.item_code)): - buying_amount = get_buying_amount(item.item_code, item.warehouse, -1*item.qty, - self.doc.doctype, self.doc.name, item.name, stock_ledger_entries, + buying_amount = get_buying_amount(item.item_code, self.doc.doctype, self.doc.name, item.name, + stock_ledger_entries.get((item.item_code, item.warehouse), []), item_sales_bom) item.buying_amount = buying_amount >= 0.01 and buying_amount or 0 diff --git a/controllers/stock_controller.py b/controllers/stock_controller.py index 8384973d48..1aeca1bc73 100644 --- a/controllers/stock_controller.py +++ b/controllers/stock_controller.py @@ -38,11 +38,13 @@ class StockController(AccountsController): return gl_entries def get_stock_ledger_entries(self, item_list=None, warehouse_list=None): + out = {} + if not (item_list and warehouse_list): item_list, warehouse_list = self.get_distinct_item_warehouse() if item_list and warehouse_list: - return webnotes.conn.sql("""select item_code, voucher_type, voucher_no, + res = webnotes.conn.sql("""select item_code, voucher_type, voucher_no, voucher_detail_no, posting_date, posting_time, stock_value, warehouse, actual_qty as qty from `tabStock Ledger Entry` where ifnull(`is_cancelled`, "No") = "No" and company = %s @@ -51,6 +53,14 @@ class StockController(AccountsController): posting_time desc, name desc""" % ('%s', ', '.join(['%s']*len(item_list)), ', '.join(['%s']*len(warehouse_list))), tuple([self.doc.company] + item_list + warehouse_list), as_dict=1) + + for r in res: + if (r.item_code, r.warehouse) not in out: + out[(r.item_code, r.warehouse)] = [] + + out[(r.item_code, r.warehouse)].append(r) + + return out def get_distinct_item_warehouse(self): item_list = [] diff --git a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py index 4a78421d6c..3fda3ba3dc 100644 --- a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -112,5 +112,4 @@ def on_doctype_update(): where Key_name="posting_sort_index" """): webnotes.conn.commit() webnotes.conn.sql("""alter table `tabStock Ledger Entry` - add index posting_sort_index(posting_date, posting_time, name)""") - webnotes.conn.begin() \ No newline at end of file + add index posting_sort_index(posting_date, posting_time, name)""") \ No newline at end of file diff --git a/stock/doctype/stock_reconciliation/stock_reconciliation.py b/stock/doctype/stock_reconciliation/stock_reconciliation.py index 36f872eb4f..dbe2d2a4c5 100644 --- a/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -290,9 +290,8 @@ class DocType(StockController): self.doc.stock_value_difference = 0.0 for d in self.entries: - self.doc.stock_value_difference -= get_buying_amount(d.item_code, d.warehouse, - d.actual_qty, self.doc.doctype, self.doc.name, d.voucher_detail_no, - stock_ledger_entries) + self.doc.stock_value_difference -= get_buying_amount(d.item_code, self.doc.doctype, self.doc.name, + d.voucher_detail_no, stock_ledger_entries.get((d.item_code, d.warehouse), [])) webnotes.conn.set(self.doc, "stock_value_difference", self.doc.stock_value_difference) def make_gl_entries(self): diff --git a/stock/utils.py b/stock/utils.py index d53d271e1c..96eeef644e 100644 --- a/stock/utils.py +++ b/stock/utils.py @@ -152,32 +152,28 @@ def get_warehouse_list(doctype, txt, searchfield, start, page_len, filters): wlist.append([w]) return wlist -def get_buying_amount(item_code, warehouse, qty, voucher_type, voucher_no, voucher_detail_no, +def get_buying_amount(item_code, voucher_type, voucher_no, voucher_detail_no, stock_ledger_entries, item_sales_bom=None): if item_sales_bom and item_sales_bom.get(item_code): # sales bom item buying_amount = 0.0 for bom_item in item_sales_bom[item_code]: if bom_item.get("parent_detail_docname")==voucher_detail_no: - buying_amount += _get_buying_amount(voucher_type, voucher_no, voucher_detail_no, - bom_item.item_code, bom_item.warehouse or warehouse, - bom_item.total_qty or (bom_item.qty * qty), stock_ledger_entries) + buying_amount += _get_buying_amount(voucher_type, voucher_no, voucher_detail_no, stock_ledger_entries) return buying_amount else: # doesn't have sales bom - return _get_buying_amount(voucher_type, voucher_no, voucher_detail_no, - item_code, warehouse, qty, stock_ledger_entries) + return _get_buying_amount(voucher_type, voucher_no, voucher_detail_no, stock_ledger_entries) -def _get_buying_amount(voucher_type, voucher_no, item_row, item_code, warehouse, qty, - stock_ledger_entries): - relevant_stock_ledger_entries = [sle for sle in stock_ledger_entries - if sle.item_code == item_code and sle.warehouse == warehouse] - - for i, sle in enumerate(relevant_stock_ledger_entries): +def _get_buying_amount(voucher_type, voucher_no, item_row, stock_ledger_entries): + # IMP NOTE + # stock_ledger_entries should already be filtered by item_code and warehouse and + # sorted by posting_date desc, posting_time desc + for i, sle in enumerate(stock_ledger_entries): if sle.voucher_type == voucher_type and sle.voucher_no == voucher_no and \ sle.voucher_detail_no == item_row: - previous_stock_value = len(relevant_stock_ledger_entries) > i+1 and \ - flt(relevant_stock_ledger_entries[i+1].stock_value) or 0.0 + previous_stock_value = len(stock_ledger_entries) > i+1 and \ + flt(stock_ledger_entries[i+1].stock_value) or 0.0 buying_amount = previous_stock_value - flt(sle.stock_value)