Merge pull request #39385 from nabinhait/wdv-as-per-income-tax-act
fix: WDV as per IT Act: calculate yearly amount first and then split it based on months
diff --git a/erpnext/accounts/doctype/subscription/subscription.py b/erpnext/accounts/doctype/subscription/subscription.py
index 72e574c..ce56a7b 100644
--- a/erpnext/accounts/doctype/subscription/subscription.py
+++ b/erpnext/accounts/doctype/subscription/subscription.py
@@ -16,6 +16,7 @@
date_diff,
flt,
get_last_day,
+ get_link_to_form,
getdate,
nowdate,
)
@@ -317,6 +318,37 @@
if self.is_new():
self.set_subscription_status()
+ self.validate_party_billing_currency()
+
+ def validate_party_billing_currency(self):
+ """
+ Subscription should be of the same currency as the Party's default billing currency or company default.
+ """
+ if self.party:
+ party_billing_currency = frappe.get_cached_value(
+ self.party_type, self.party, "default_currency"
+ ) or frappe.get_cached_value("Company", self.company, "default_currency")
+
+ plans = [x.plan for x in self.plans]
+ subscription_plan_currencies = frappe.db.get_all(
+ "Subscription Plan", filters={"name": ("in", plans)}, fields=["name", "currency"]
+ )
+ unsupported_plans = []
+ for x in subscription_plan_currencies:
+ if x.currency != party_billing_currency:
+ unsupported_plans.append("{0}".format(get_link_to_form("Subscription Plan", x.name)))
+
+ if unsupported_plans:
+ unsupported_plans = [
+ _(
+ "Below Subscription Plans are of different currency to the party default billing currency/Company currency: {0}"
+ ).format(frappe.bold(party_billing_currency))
+ ] + unsupported_plans
+
+ frappe.throw(
+ unsupported_plans, frappe.ValidationError, "Unsupported Subscription Plans", as_list=True
+ )
+
def validate_trial_period(self) -> None:
"""
Runs sanity checks on trial period dates for the `Subscription`
diff --git a/erpnext/accounts/doctype/subscription/test_subscription.py b/erpnext/accounts/doctype/subscription/test_subscription.py
index 785fd04..a46642a 100644
--- a/erpnext/accounts/doctype/subscription/test_subscription.py
+++ b/erpnext/accounts/doctype/subscription/test_subscription.py
@@ -460,11 +460,13 @@
self.assertEqual(len(subscription.invoices), 1)
def test_multi_currency_subscription(self):
+ party = "_Test Subscription Customer"
+ frappe.db.set_value("Customer", party, "default_currency", "USD")
subscription = create_subscription(
start_date="2018-01-01",
generate_invoice_at="Beginning of the current subscription period",
- plans=[{"plan": "_Test Plan Multicurrency", "qty": 1}],
- party="_Test Subscription Customer",
+ plans=[{"plan": "_Test Plan Multicurrency", "qty": 1, "currency": "USD"}],
+ party=party,
)
subscription.process()
@@ -528,13 +530,21 @@
def make_plans():
- create_plan(plan_name="_Test Plan Name", cost=900)
- create_plan(plan_name="_Test Plan Name 2", cost=1999)
+ create_plan(plan_name="_Test Plan Name", cost=900, currency="INR")
+ create_plan(plan_name="_Test Plan Name 2", cost=1999, currency="INR")
create_plan(
- plan_name="_Test Plan Name 3", cost=1999, billing_interval="Day", billing_interval_count=14
+ plan_name="_Test Plan Name 3",
+ cost=1999,
+ billing_interval="Day",
+ billing_interval_count=14,
+ currency="INR",
)
create_plan(
- plan_name="_Test Plan Name 4", cost=20000, billing_interval="Month", billing_interval_count=3
+ plan_name="_Test Plan Name 4",
+ cost=20000,
+ billing_interval="Month",
+ billing_interval_count=3,
+ currency="INR",
)
create_plan(
plan_name="_Test Plan Multicurrency", cost=50, billing_interval="Month", currency="USD"
diff --git a/erpnext/accounts/doctype/subscription_plan/subscription_plan.json b/erpnext/accounts/doctype/subscription_plan/subscription_plan.json
index 563df79..bc1f579 100644
--- a/erpnext/accounts/doctype/subscription_plan/subscription_plan.json
+++ b/erpnext/accounts/doctype/subscription_plan/subscription_plan.json
@@ -41,7 +41,8 @@
"fieldname": "currency",
"fieldtype": "Link",
"label": "Currency",
- "options": "Currency"
+ "options": "Currency",
+ "reqd": 1
},
{
"fieldname": "column_break_3",
@@ -148,10 +149,11 @@
}
],
"links": [],
- "modified": "2021-12-10 15:24:15.794477",
+ "modified": "2024-01-14 17:59:34.687977",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Subscription Plan",
+ "naming_rule": "By fieldname",
"owner": "Administrator",
"permissions": [
{
@@ -193,5 +195,6 @@
],
"sort_field": "modified",
"sort_order": "DESC",
+ "states": [],
"track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/subscription_plan/subscription_plan.py b/erpnext/accounts/doctype/subscription_plan/subscription_plan.py
index 118d254..cdfa3e5 100644
--- a/erpnext/accounts/doctype/subscription_plan/subscription_plan.py
+++ b/erpnext/accounts/doctype/subscription_plan/subscription_plan.py
@@ -24,7 +24,7 @@
billing_interval_count: DF.Int
cost: DF.Currency
cost_center: DF.Link | None
- currency: DF.Link | None
+ currency: DF.Link
item: DF.Link
payment_gateway: DF.Link | None
plan_name: DF.Data
diff --git a/erpnext/accounts/report/budget_variance_report/budget_variance_report.js b/erpnext/accounts/report/budget_variance_report/budget_variance_report.js
index 9c356bf..d6a4755 100644
--- a/erpnext/accounts/report/budget_variance_report/budget_variance_report.js
+++ b/erpnext/accounts/report/budget_variance_report/budget_variance_report.js
@@ -84,10 +84,6 @@
options: budget_against_options,
default: "Cost Center",
reqd: 1,
- get_data: function() {
- console.log(this.options);
- return ["Emacs", "Rocks"];
- },
on_change: function() {
frappe.query_report.set_filter_value("budget_against_filter", []);
frappe.query_report.refresh();
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py
index 6636b8e..f5b034a 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/general_ledger.py
@@ -449,6 +449,10 @@
for gle in gl_entries:
group_by_value = gle.get(group_by)
gle.voucher_type = _(gle.voucher_type)
+ gle.voucher_subtype = _(gle.voucher_subtype)
+ gle.against_voucher_type = _(gle.against_voucher_type)
+ gle.remarks = _(gle.remarks)
+ gle.party_type = _(gle.party_type)
if gle.posting_date < from_date or (cstr(gle.is_opening) == "Yes" and not show_opening_entries):
if not group_by_voucher_consolidated:
diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.js b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.js
index 39fb3ca..06f426b 100644
--- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.js
+++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.js
@@ -59,7 +59,21 @@
"fieldname": "group_by",
"fieldtype": "Select",
"options": ["Customer Group", "Customer", "Item Group", "Item", "Territory", "Invoice"]
- }
+ },
+ {
+ "fieldname": "income_account",
+ "label": __("Income Account"),
+ "fieldtype": "Link",
+ "options": "Account",
+ get_query: () => {
+ let company = frappe.query_report.get_filter_value('company');
+ return {
+ filters: {
+ 'company': company,
+ }
+ };
+ }
+ },
],
"formatter": function(value, row, column, data, default_formatter) {
value = default_formatter(value, row, column, data);
diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py
index ce22d75..56ae41a 100644
--- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py
+++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py
@@ -83,9 +83,7 @@
"company": d.company,
"sales_order": d.sales_order,
"delivery_note": d.delivery_note,
- "income_account": d.unrealized_profit_loss_account
- if d.is_internal_customer == 1
- else d.income_account,
+ "income_account": get_income_account(d),
"cost_center": d.cost_center,
"stock_qty": d.stock_qty,
"stock_uom": d.stock_uom,
@@ -150,6 +148,15 @@
return columns, data, None, None, None, skip_total_row
+def get_income_account(row):
+ if row.enable_deferred_revenue:
+ return row.deferred_revenue_account
+ elif row.is_internal_customer == 1:
+ return row.unrealized_profit_loss_account
+ else:
+ return row.income_account
+
+
def get_columns(additional_table_columns, filters):
columns = []
@@ -358,6 +365,13 @@
if filters.get("item_group"):
conditions += """and ifnull(`tabSales Invoice Item`.item_group, '') = %(item_group)s"""
+ if filters.get("income_account"):
+ conditions += """
+ and (ifnull(`tabSales Invoice Item`.income_account, '') = %(income_account)s
+ or ifnull(`tabSales Invoice Item`.deferred_revenue_account, '') = %(income_account)s
+ or ifnull(`tabSales Invoice`.unrealized_profit_loss_account, '') = %(income_account)s)
+ """
+
if not filters.get("group_by"):
conditions += (
"ORDER BY `tabSales Invoice`.posting_date desc, `tabSales Invoice Item`.item_group desc"
@@ -399,6 +413,7 @@
`tabItem`.`item_name` as i_item_name, `tabItem`.`item_group` as i_item_group,
`tabSales Invoice Item`.sales_order, `tabSales Invoice Item`.delivery_note,
`tabSales Invoice Item`.income_account, `tabSales Invoice Item`.cost_center,
+ `tabSales Invoice Item`.enable_deferred_revenue, `tabSales Invoice Item`.deferred_revenue_account,
`tabSales Invoice Item`.stock_qty, `tabSales Invoice Item`.stock_uom,
`tabSales Invoice Item`.base_net_rate, `tabSales Invoice Item`.base_net_amount,
`tabSales Invoice`.customer_name, `tabSales Invoice`.customer_group, `tabSales Invoice Item`.so_detail,
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index 8ebdcc5..e234eec 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -6,10 +6,12 @@
from collections import OrderedDict, defaultdict
import frappe
-from frappe import scrub
+from frappe import qb, scrub
from frappe.desk.reportview import get_filters_cond, get_match_cond
-from frappe.query_builder.functions import Concat, Sum
+from frappe.query_builder import Criterion, CustomFunction
+from frappe.query_builder.functions import Concat, Locate, Sum
from frappe.utils import nowdate, today, unique
+from pypika import Order
import erpnext
from erpnext.stock.get_item_details import _get_item_tax_template
@@ -344,37 +346,46 @@
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_project_name(doctype, txt, searchfield, start, page_len, filters):
- doctype = "Project"
- cond = ""
+ proj = qb.DocType("Project")
+ qb_filter_and_conditions = []
+ qb_filter_or_conditions = []
+ ifelse = CustomFunction("IF", ["condition", "then", "else"])
+
if filters and filters.get("customer"):
- cond = """(`tabProject`.customer = %s or
- ifnull(`tabProject`.customer,"")="") and""" % (
- frappe.db.escape(filters.get("customer"))
- )
+ qb_filter_and_conditions.append(proj.customer == filters.get("customer"))
+
+ qb_filter_and_conditions.append(proj.status.notin(["Completed", "Cancelled"]))
+
+ q = qb.from_(proj)
fields = get_fields(doctype, ["name", "project_name"])
- searchfields = frappe.get_meta(doctype).get_search_fields()
- searchfields = " or ".join(["`tabProject`." + field + " like %(txt)s" for field in searchfields])
+ for x in fields:
+ q = q.select(proj[x])
- return frappe.db.sql(
- """select {fields} from `tabProject`
- where
- `tabProject`.status not in ('Completed', 'Cancelled')
- and {cond} {scond} {match_cond}
- order by
- (case when locate(%(_txt)s, `tabProject`.name) > 0 then locate(%(_txt)s, `tabProject`.name) else 99999 end),
- `tabProject`.idx desc,
- `tabProject`.name asc
- limit {page_len} offset {start}""".format(
- fields=", ".join(["`tabProject`.{0}".format(f) for f in fields]),
- cond=cond,
- scond=searchfields,
- match_cond=get_match_cond(doctype),
- start=start,
- page_len=page_len,
- ),
- {"txt": "%{0}%".format(txt), "_txt": txt.replace("%", "")},
- )
+ # don't consider 'customer' and 'status' fields for pattern search, as they must be exactly matched
+ searchfields = [
+ x for x in frappe.get_meta(doctype).get_search_fields() if x not in ["customer", "status"]
+ ]
+
+ # pattern search
+ if txt:
+ for x in searchfields:
+ qb_filter_or_conditions.append(proj[x].like(f"%{txt}%"))
+
+ q = q.where(Criterion.all(qb_filter_and_conditions)).where(Criterion.any(qb_filter_or_conditions))
+
+ # ordering
+ if txt:
+ # project_name containing search string 'txt' will be given higher precedence
+ q = q.orderby(ifelse(Locate(txt, proj.project_name) > 0, Locate(txt, proj.project_name), 99999))
+ q = q.orderby(proj.idx, order=Order.desc).orderby(proj.name)
+
+ if page_len:
+ q = q.limit(page_len)
+
+ if start:
+ q = q.offset(start)
+ return q.run()
@frappe.whitelist()
diff --git a/erpnext/controllers/tests/test_queries.py b/erpnext/controllers/tests/test_queries.py
index 60d1733..3a3bc1c 100644
--- a/erpnext/controllers/tests/test_queries.py
+++ b/erpnext/controllers/tests/test_queries.py
@@ -68,7 +68,7 @@
self.assertGreaterEqual(len(query(txt="_Test Item Home Desktop Manufactured")), 1)
def test_project_query(self):
- query = add_default_params(queries.get_project_name, "BOM")
+ query = add_default_params(queries.get_project_name, "Project")
self.assertGreaterEqual(len(query(txt="_Test Project")), 1)
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index 598167b..de46271 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -21,7 +21,7 @@
},
toggle_naming_series: function() {
- if(cur_frm.fields_dict.naming_series) {
+ if(cur_frm && cur_frm.fields_dict.naming_series) {
cur_frm.toggle_display("naming_series", cur_frm.doc.__islocal?true:false);
}
},
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index b206e3f..56c745c 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -94,6 +94,9 @@
frm.set_value("reserve_stock", 0);
frm.set_df_property("reserve_stock", "read_only", 1);
frm.set_df_property("reserve_stock", "hidden", 1);
+ frm.fields_dict.items.grid.update_docfield_property('reserve_stock', 'hidden', 1);
+ frm.fields_dict.items.grid.update_docfield_property('reserve_stock', 'default', 0);
+ frm.fields_dict.items.grid.update_docfield_property('reserve_stock', 'read_only', 1);
}
})
}
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 9542361..5ef2c50 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -200,6 +200,7 @@
self.validate_for_items()
self.validate_warehouse()
self.validate_drop_ship()
+ self.validate_reserved_stock()
self.validate_serial_no_based_delivery()
validate_against_blanket_order(self)
validate_inter_company_party(
@@ -660,6 +661,17 @@
).format(item.item_code)
)
+ def validate_reserved_stock(self):
+ """Clean reserved stock flag for non-stock Item"""
+
+ enable_stock_reservation = frappe.db.get_single_value(
+ "Stock Settings", "enable_stock_reservation"
+ )
+
+ for item in self.items:
+ if item.reserve_stock and (not enable_stock_reservation or not cint(item.is_stock_item)):
+ item.reserve_stock = 0
+
def has_unreserved_stock(self) -> bool:
"""Returns True if there is any unreserved item in the Sales Order."""
diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json
index d4ccfc4..87aeeac 100644
--- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json
+++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json
@@ -10,6 +10,7 @@
"item_code",
"customer_item_code",
"ensure_delivery_based_on_produced_serial_no",
+ "is_stock_item",
"reserve_stock",
"col_break1",
"delivery_date",
@@ -867,6 +868,7 @@
{
"allow_on_submit": 1,
"default": "1",
+ "depends_on": "eval:doc.is_stock_item",
"fieldname": "reserve_stock",
"fieldtype": "Check",
"label": "Reserve Stock",
@@ -891,6 +893,16 @@
"label": "Production Plan Qty",
"no_copy": 1,
"read_only": 1
+ },
+ {
+ "default": "0",
+ "fetch_from": "item_code.is_stock_item",
+ "fieldname": "is_stock_item",
+ "fieldtype": "Check",
+ "hidden": 1,
+ "label": "Is Stock Item",
+ "print_hide": 1,
+ "report_hide": 1
}
],
"idx": 1,
diff --git a/erpnext/selling/page/sales_funnel/sales_funnel.js b/erpnext/selling/page/sales_funnel/sales_funnel.js
index e3d0a55..a0a1222 100644
--- a/erpnext/selling/page/sales_funnel/sales_funnel.js
+++ b/erpnext/selling/page/sales_funnel/sales_funnel.js
@@ -126,9 +126,9 @@
if (me.options.chart == 'sales_funnel'){
me.render_funnel();
} else if (me.options.chart == 'opp_by_lead_source'){
- me.render_chart("Sales Opportunities by Source");
+ me.render_chart(__("Sales Opportunities by Source"));
} else if (me.options.chart == 'sales_pipeline'){
- me.render_chart("Sales Pipeline by Stage");
+ me.render_chart(__("Sales Pipeline by Stage"));
}
}
diff --git a/erpnext/setup/doctype/vehicle/vehicle.json b/erpnext/setup/doctype/vehicle/vehicle.json
index b19d459..bf1a8c1 100644
--- a/erpnext/setup/doctype/vehicle/vehicle.json
+++ b/erpnext/setup/doctype/vehicle/vehicle.json
@@ -57,7 +57,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Make",
+ "label": "Manufacturer",
"length": 0,
"no_copy": 0,
"permlevel": 0,
diff --git a/erpnext/stock/doctype/bin/bin.json b/erpnext/stock/doctype/bin/bin.json
index 10d9511..39e0917 100644
--- a/erpnext/stock/doctype/bin/bin.json
+++ b/erpnext/stock/doctype/bin/bin.json
@@ -186,7 +186,7 @@
"idx": 1,
"in_create": 1,
"links": [],
- "modified": "2023-11-01 16:51:17.079107",
+ "modified": "2024-01-16 15:11:46.140323",
"modified_by": "Administrator",
"module": "Stock",
"name": "Bin",
@@ -213,6 +213,21 @@
"read": 1,
"report": 1,
"role": "Stock User"
+ },
+ {
+ "read": 1,
+ "report": 1,
+ "role": "Stock Manager"
+ },
+ {
+ "read": 1,
+ "report": 1,
+ "role": "Purchase Manager"
+ },
+ {
+ "read": 1,
+ "report": 1,
+ "role": "Sales Manager"
}
],
"quick_entry": 1,
diff --git a/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary.js b/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary.js
index 61927f5..c175a4a 100644
--- a/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary.js
+++ b/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary.js
@@ -1,7 +1,7 @@
frappe.pages['warehouse-capacity-summary'].on_page_load = function(wrapper) {
var page = frappe.ui.make_app_page({
parent: wrapper,
- title: 'Warehouse Capacity Summary',
+ title: __('Warehouse Capacity Summary'),
single_column: true
});
page.set_secondary_action('Refresh', () => page.capacity_dashboard.refresh(), 'refresh');
diff --git a/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary_header.html b/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary_header.html
index 1183ad4..1883004 100644
--- a/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary_header.html
+++ b/erpnext/stock/page/warehouse_capacity_summary/warehouse_capacity_summary_header.html
@@ -1,19 +1,19 @@
<div class="dashboard-list-item" style="padding: 12px 15px;">
<div class="row">
<div class="col-sm-2 text-muted" style="margin-top: 8px;">
- Warehouse
+ {{ __("Warehouse") }}
</div>
<div class="col-sm-2 text-muted" style="margin-top: 8px;">
- Item
+ {{ __("Item") }}
</div>
<div class="col-sm-1 text-muted" style="margin-top: 8px;">
- Stock Capacity
+ {{ __("Stock Capacity") }}
</div>
<div class="col-sm-2 text-muted" style="margin-top: 8px;">
- Balance Stock Qty
+ {{ __("Balance Stock Qty") }}
</div>
<div class="col-sm-2 text-muted" style="margin-top: 8px;">
- % Occupied
+ {{ __("% Occupied") }}
</div>
</div>
</div>
diff --git a/erpnext/stock/report/stock_ageing/stock_ageing.py b/erpnext/stock/report/stock_ageing/stock_ageing.py
index d0929a0..02ac8c6 100644
--- a/erpnext/stock/report/stock_ageing/stock_ageing.py
+++ b/erpnext/stock/report/stock_ageing/stock_ageing.py
@@ -3,7 +3,7 @@
from operator import itemgetter
-from typing import Dict, List, Tuple, Union
+from typing import Dict, Iterator, List, Tuple, Union
import frappe
from frappe import _
@@ -231,25 +231,32 @@
consumed/updated and maintained via FIFO. **
}
"""
- if self.sle is None:
- self.sle = self.__get_stock_ledger_entries()
- for d in self.sle:
- key, fifo_queue, transferred_item_key = self.__init_key_stores(d)
+ stock_ledger_entries = self.sle
- if d.voucher_type == "Stock Reconciliation":
- # get difference in qty shift as actual qty
- prev_balance_qty = self.item_details[key].get("qty_after_transaction", 0)
- d.actual_qty = flt(d.qty_after_transaction) - flt(prev_balance_qty)
+ with frappe.db.unbuffered_cursor():
+ if stock_ledger_entries is None:
+ stock_ledger_entries = self.__get_stock_ledger_entries()
- serial_nos = get_serial_nos(d.serial_no) if d.serial_no else []
+ for d in stock_ledger_entries:
+ key, fifo_queue, transferred_item_key = self.__init_key_stores(d)
- if d.actual_qty > 0:
- self.__compute_incoming_stock(d, fifo_queue, transferred_item_key, serial_nos)
- else:
- self.__compute_outgoing_stock(d, fifo_queue, transferred_item_key, serial_nos)
+ if d.voucher_type == "Stock Reconciliation":
+ # get difference in qty shift as actual qty
+ prev_balance_qty = self.item_details[key].get("qty_after_transaction", 0)
+ d.actual_qty = flt(d.qty_after_transaction) - flt(prev_balance_qty)
- self.__update_balances(d, key)
+ serial_nos = get_serial_nos(d.serial_no) if d.serial_no else []
+
+ if d.actual_qty > 0:
+ self.__compute_incoming_stock(d, fifo_queue, transferred_item_key, serial_nos)
+ else:
+ self.__compute_outgoing_stock(d, fifo_queue, transferred_item_key, serial_nos)
+
+ self.__update_balances(d, key)
+
+ # Note that stock_ledger_entries is an iterator, you can not reuse it like a list
+ del stock_ledger_entries
if not self.filters.get("show_warehouse_wise_stock"):
# (Item 1, WH 1), (Item 1, WH 2) => (Item 1)
@@ -381,7 +388,7 @@
return item_aggregated_data
- def __get_stock_ledger_entries(self) -> List[Dict]:
+ def __get_stock_ledger_entries(self) -> Iterator[Dict]:
sle = frappe.qb.DocType("Stock Ledger Entry")
item = self.__get_item_query() # used as derived table in sle query
@@ -418,7 +425,7 @@
sle_query = sle_query.orderby(sle.posting_date, sle.posting_time, sle.creation, sle.actual_qty)
- return sle_query.run(as_dict=True)
+ return sle_query.run(as_dict=True, as_iterator=True)
def __get_item_query(self) -> str:
item_table = frappe.qb.DocType("Item")