fix: added progress bar in repost item valuation (#26680)
diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js
index b3e4286..4cd40bf 100644
--- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js
+++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js
@@ -29,13 +29,50 @@
};
});
}
+
+ frm.trigger('setup_realtime_progress');
},
+
+ setup_realtime_progress: function(frm) {
+ frappe.realtime.on('item_reposting_progress', data => {
+ if (frm.doc.name !== data.name) {
+ return;
+ }
+
+ if (frm.doc.status == 'In Progress') {
+ frm.doc.current_index = data.current_index;
+ frm.doc.items_to_be_repost = data.items_to_be_repost;
+
+ frm.dashboard.reset();
+ frm.trigger('show_reposting_progress');
+ }
+ });
+ },
+
refresh: function(frm) {
if (frm.doc.status == "Failed" && frm.doc.docstatus==1) {
frm.add_custom_button(__('Restart'), function () {
frm.trigger("restart_reposting");
}).addClass("btn-primary");
}
+
+ frm.trigger('show_reposting_progress');
+ },
+
+ show_reposting_progress: function(frm) {
+ var bars = [];
+
+ let total_count = frm.doc.items_to_be_repost ? JSON.parse(frm.doc.items_to_be_repost).length : 0;
+ let progress = flt(cint(frm.doc.current_index) / total_count * 100, 2) || 0.5;
+ var title = __('Reposting Completed {0}%', [progress]);
+
+ bars.push({
+ 'title': title,
+ 'width': progress + '%',
+ 'progress_class': 'progress-bar-success'
+ });
+
+ frm.dashboard.add_progress(__('Reposting Progress'), bars);
},
restart_reposting: function(frm) {
diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.json b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.json
index 071fc86..a800bf8 100644
--- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.json
+++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.json
@@ -21,7 +21,10 @@
"allow_zero_rate",
"amended_from",
"error_section",
- "error_log"
+ "error_log",
+ "items_to_be_repost",
+ "distinct_item_and_warehouse",
+ "current_index"
],
"fields": [
{
@@ -142,12 +145,39 @@
"fieldname": "allow_zero_rate",
"fieldtype": "Check",
"label": "Allow Zero Rate"
+ },
+ {
+ "fieldname": "items_to_be_repost",
+ "fieldtype": "Code",
+ "hidden": 1,
+ "label": "Items to Be Repost",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "distinct_item_and_warehouse",
+ "fieldtype": "Code",
+ "hidden": 1,
+ "label": "Distinct Item and Warehouse",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "current_index",
+ "fieldtype": "Int",
+ "hidden": 1,
+ "label": "Current Index",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2020-12-10 07:52:12.476589",
+ "modified": "2021-07-22 18:59:43.057878",
"modified_by": "Administrator",
"module": "Stock",
"name": "Repost Item Valuation",
diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
index 5f31d9c..b22759d 100644
--- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
+++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
@@ -81,7 +81,7 @@
def repost_sl_entries(doc):
if doc.based_on == 'Transaction':
repost_future_sle(voucher_type=doc.voucher_type, voucher_no=doc.voucher_no,
- allow_negative_stock=doc.allow_negative_stock, via_landed_cost_voucher=doc.via_landed_cost_voucher)
+ allow_negative_stock=doc.allow_negative_stock, via_landed_cost_voucher=doc.via_landed_cost_voucher, doc=doc)
else:
repost_future_sle(args=[frappe._dict({
"item_code": doc.item_code,
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index c15d1ed..f990ce0 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -127,30 +127,26 @@
sle.submit()
return sle
-def repost_future_sle(args=None, voucher_type=None, voucher_no=None, allow_negative_stock=None, via_landed_cost_voucher=False):
+def repost_future_sle(args=None, voucher_type=None, voucher_no=None, allow_negative_stock=None, via_landed_cost_voucher=False, doc=None):
if not args and voucher_type and voucher_no:
- args = get_args_for_voucher(voucher_type, voucher_no)
+ args = get_items_to_be_repost(voucher_type, voucher_no, doc)
- distinct_item_warehouses = {}
- for i, d in enumerate(args):
- distinct_item_warehouses.setdefault((d.item_code, d.warehouse), frappe._dict({
- "reposting_status": False,
- "sle": d,
- "args_idx": i
- }))
+ distinct_item_warehouses = get_distinct_item_warehouse(args, doc)
- i = 0
+ i = get_current_index(doc) or 0
while i < len(args):
+ validate_item_warehouse(args[i])
+
obj = update_entries_after({
- "item_code": args[i].item_code,
- "warehouse": args[i].warehouse,
- "posting_date": args[i].posting_date,
- "posting_time": args[i].posting_time,
- "creation": args[i].get("creation"),
- "distinct_item_warehouses": distinct_item_warehouses
+ 'item_code': args[i].get('item_code'),
+ 'warehouse': args[i].get('warehouse'),
+ 'posting_date': args[i].get('posting_date'),
+ 'posting_time': args[i].get('posting_time'),
+ 'creation': args[i].get('creation'),
+ 'distinct_item_warehouses': distinct_item_warehouses
}, allow_negative_stock=allow_negative_stock, via_landed_cost_voucher=via_landed_cost_voucher)
- distinct_item_warehouses[(args[i].item_code, args[i].warehouse)].reposting_status = True
+ distinct_item_warehouses[(args[i].get('item_code'), args[i].get('warehouse'))].reposting_status = True
if obj.new_items_found:
for item_wh, data in iteritems(distinct_item_warehouses):
@@ -159,11 +155,41 @@
args.append(data.sle)
elif data.sle_changed and not data.reposting_status:
args[data.args_idx] = data.sle
-
+
data.sle_changed = False
i += 1
-def get_args_for_voucher(voucher_type, voucher_no):
+ if doc and i % 2 == 0:
+ update_args_in_repost_item_valuation(doc, i, args, distinct_item_warehouses)
+
+ if doc and args:
+ update_args_in_repost_item_valuation(doc, i, args, distinct_item_warehouses)
+
+def validate_item_warehouse(args):
+ for field in ['item_code', 'warehouse', 'posting_date', 'posting_time']:
+ if not args.get(field):
+ validation_msg = f'The field {frappe.unscrub(args.get(field))} is required for the reposting'
+ frappe.throw(_(validation_msg))
+
+def update_args_in_repost_item_valuation(doc, index, args, distinct_item_warehouses):
+ frappe.db.set_value(doc.doctype, doc.name, {
+ 'items_to_be_repost': json.dumps(args, default=str),
+ 'distinct_item_and_warehouse': json.dumps({str(k): v for k,v in distinct_item_warehouses.items()}, default=str),
+ 'current_index': index
+ })
+
+ frappe.db.commit()
+
+ frappe.publish_realtime('item_reposting_progress', {
+ 'name': doc.name,
+ 'items_to_be_repost': json.dumps(args, default=str),
+ 'current_index': index
+ })
+
+def get_items_to_be_repost(voucher_type, voucher_no, doc=None):
+ if doc and doc.items_to_be_repost:
+ return json.loads(doc.items_to_be_repost) or []
+
return frappe.db.get_all("Stock Ledger Entry",
filters={"voucher_type": voucher_type, "voucher_no": voucher_no},
fields=["item_code", "warehouse", "posting_date", "posting_time", "creation"],
@@ -171,6 +197,25 @@
group_by="item_code, warehouse"
)
+def get_distinct_item_warehouse(args=None, doc=None):
+ distinct_item_warehouses = {}
+ if doc and doc.distinct_item_and_warehouse:
+ distinct_item_warehouses = json.loads(doc.distinct_item_and_warehouse)
+ distinct_item_warehouses = {frappe.safe_eval(k): frappe._dict(v) for k, v in distinct_item_warehouses.items()}
+ else:
+ for i, d in enumerate(args):
+ distinct_item_warehouses.setdefault((d.item_code, d.warehouse), frappe._dict({
+ "reposting_status": False,
+ "sle": d,
+ "args_idx": i
+ }))
+
+ return distinct_item_warehouses
+
+def get_current_index(doc=None):
+ if doc and doc.current_index:
+ return doc.current_index
+
class update_entries_after(object):
"""
update valution rate and qty after transaction