blob: e5dc6b12df73c05006d4f06697df9a60165d9041 [file] [log] [blame]
Anand Doshi885e0742015-03-03 14:55:30 +05301# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
Nabin Haiteea2b342013-10-11 18:31:33 +05302# License: GNU General Public License v3. See license.txt
3
Aditya Hase6ccb6562017-08-28 18:17:36 +05304from __future__ import print_function, unicode_literals
Rushabh Mehta793ba6b2014-02-14 15:47:51 +05305import frappe
Nabin Hait62985362014-04-04 12:05:16 +05306from frappe.utils import flt, cstr, nowdate, nowtime
7from erpnext.stock.utils import update_bin
8from erpnext.stock.stock_ledger import update_entries_after
Nabin Hait001edb42019-09-26 16:44:35 +05309from erpnext.controllers.stock_controller import update_gl_entries_after
Nabin Haiteea2b342013-10-11 18:31:33 +053010
Nabin Haitb7e46c42015-10-12 16:46:29 +053011def repost(only_actual=False, allow_negative_stock=False, allow_zero_rate=False, only_bin=False):
Nabin Haiteea2b342013-10-11 18:31:33 +053012 """
13 Repost everything!
14 """
Anand Doshie9baaa62014-02-26 12:35:33 +053015 frappe.db.auto_commit_on_many_writes = 1
Nabin Hait62985362014-04-04 12:05:16 +053016
Nabin Haitca471f42013-11-20 13:14:12 +053017 if allow_negative_stock:
Nabin Hait249bbbc2014-11-26 15:35:08 +053018 existing_allow_negative_stock = frappe.db.get_value("Stock Settings", None, "allow_negative_stock")
19 frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
Nabin Hait62985362014-04-04 12:05:16 +053020
Nabin Hait001edb42019-09-26 16:44:35 +053021 item_warehouses = frappe.db.sql("""
22 select distinct item_code, warehouse
23 from
24 (select item_code, warehouse from tabBin
25 union
26 select item_code, warehouse from `tabStock Ledger Entry`) a
27 """)
28 for d in item_warehouses:
29 try:
30 repost_stock(d[0], d[1], allow_zero_rate, only_actual, only_bin, allow_negative_stock)
31 frappe.db.commit()
32 except:
33 frappe.db.rollback()
Nabin Hait62985362014-04-04 12:05:16 +053034
Nabin Haitca471f42013-11-20 13:14:12 +053035 if allow_negative_stock:
Nabin Hait249bbbc2014-11-26 15:35:08 +053036 frappe.db.set_value("Stock Settings", None, "allow_negative_stock", existing_allow_negative_stock)
Anand Doshie9baaa62014-02-26 12:35:33 +053037 frappe.db.auto_commit_on_many_writes = 0
Nabin Haiteea2b342013-10-11 18:31:33 +053038
Nabin Hait001edb42019-09-26 16:44:35 +053039def repost_stock(item_code, warehouse, allow_zero_rate=False,
40 only_actual=False, only_bin=False, allow_negative_stock=False):
41
Nabin Haitb7e46c42015-10-12 16:46:29 +053042 if not only_bin:
Nabin Hait001edb42019-09-26 16:44:35 +053043 repost_actual_qty(item_code, warehouse, allow_zero_rate, allow_negative_stock)
Nabin Hait62985362014-04-04 12:05:16 +053044
Nabin Hait2348a5f2014-10-15 15:31:33 +053045 if item_code and warehouse and not only_actual:
Nabin Haitb7e46c42015-10-12 16:46:29 +053046 qty_dict = {
Nabin Haiteea2b342013-10-11 18:31:33 +053047 "reserved_qty": get_reserved_qty(item_code, warehouse),
48 "indented_qty": get_indented_qty(item_code, warehouse),
49 "ordered_qty": get_ordered_qty(item_code, warehouse),
50 "planned_qty": get_planned_qty(item_code, warehouse)
Nabin Haitb7e46c42015-10-12 16:46:29 +053051 }
52 if only_bin:
53 qty_dict.update({
54 "actual_qty": get_balance_qty_from_sle(item_code, warehouse)
55 })
Rushabh Mehtac4d4c7f2015-10-14 17:37:28 +053056
Nabin Haitb7e46c42015-10-12 16:46:29 +053057 update_bin_qty(item_code, warehouse, qty_dict)
Nabin Haiteea2b342013-10-11 18:31:33 +053058
Nabin Hait001edb42019-09-26 16:44:35 +053059def repost_actual_qty(item_code, warehouse, allow_zero_rate=False, allow_negative_stock=False): update_entries_after({ "item_code": item_code, "warehouse": warehouse },
60 allow_zero_rate=allow_zero_rate, allow_negative_stock=allow_negative_stock)
Rushabh Mehtac4d4c7f2015-10-14 17:37:28 +053061
Nabin Haitb7e46c42015-10-12 16:46:29 +053062def get_balance_qty_from_sle(item_code, warehouse):
63 balance_qty = frappe.db.sql("""select qty_after_transaction from `tabStock Ledger Entry`
64 where item_code=%s and warehouse=%s and is_cancelled='No'
Aditya Hase0c164242019-01-07 22:07:13 +053065 order by posting_date desc, posting_time desc, creation desc
Nabin Haitb7e46c42015-10-12 16:46:29 +053066 limit 1""", (item_code, warehouse))
Rushabh Mehtac4d4c7f2015-10-14 17:37:28 +053067
Nabin Haitb7e46c42015-10-12 16:46:29 +053068 return flt(balance_qty[0][0]) if balance_qty else 0.0
Nabin Hait62985362014-04-04 12:05:16 +053069
Nabin Haiteea2b342013-10-11 18:31:33 +053070def get_reserved_qty(item_code, warehouse):
Anand Doshie9baaa62014-02-26 12:35:33 +053071 reserved_qty = frappe.db.sql("""
Nabin Hait62985362014-04-04 12:05:16 +053072 select
rohitwaghchaureafa93c62017-03-29 17:29:20 +053073 sum(dnpi_qty * ((so_item_qty - so_item_delivered_qty) / so_item_qty))
Nabin Hait62985362014-04-04 12:05:16 +053074 from
Nabin Haiteea2b342013-10-11 18:31:33 +053075 (
76 (select
77 qty as dnpi_qty,
78 (
rohitwaghchaureafa93c62017-03-29 17:29:20 +053079 select qty from `tabSales Order Item`
Nabin Haiteea2b342013-10-11 18:31:33 +053080 where name = dnpi.parent_detail_docname
Saurabh2e292062015-11-18 17:03:33 +053081 and (delivered_by_supplier is null or delivered_by_supplier = 0)
Nabin Haiteea2b342013-10-11 18:31:33 +053082 ) as so_item_qty,
83 (
Anand Doshi602e8252015-11-16 19:05:46 +053084 select delivered_qty from `tabSales Order Item`
85 where name = dnpi.parent_detail_docname
86 and delivered_by_supplier = 0
Nabin Hait62985362014-04-04 12:05:16 +053087 ) as so_item_delivered_qty,
Nabin Haiteea2b342013-10-11 18:31:33 +053088 parent, name
Nabin Hait62985362014-04-04 12:05:16 +053089 from
Nabin Haiteea2b342013-10-11 18:31:33 +053090 (
91 select qty, parent_detail_docname, parent, name
Nabin Haitd1fd1e22013-10-18 12:29:11 +053092 from `tabPacked Item` dnpi_in
Nabin Haiteea2b342013-10-11 18:31:33 +053093 where item_code = %s and warehouse = %s
94 and parenttype="Sales Order"
Nabin Haitfc2dd442014-10-17 13:05:24 +053095 and item_code != parent_item
Nabin Haiteea2b342013-10-11 18:31:33 +053096 and exists (select * from `tabSales Order` so
patilsangrama812d672016-02-23 19:04:29 +053097 where name = dnpi_in.parent and docstatus = 1 and status != 'Closed')
Nabin Haiteea2b342013-10-11 18:31:33 +053098 ) dnpi)
99 union
rohitwaghchaureafa93c62017-03-29 17:29:20 +0530100 (select stock_qty as dnpi_qty, qty as so_item_qty,
Anand Doshi602e8252015-11-16 19:05:46 +0530101 delivered_qty as so_item_delivered_qty, parent, name
Nabin Haiteea2b342013-10-11 18:31:33 +0530102 from `tabSales Order Item` so_item
Anand Doshi602e8252015-11-16 19:05:46 +0530103 where item_code = %s and warehouse = %s
Saurabh2e292062015-11-18 17:03:33 +0530104 and (so_item.delivered_by_supplier is null or so_item.delivered_by_supplier = 0)
Nabin Haiteea2b342013-10-11 18:31:33 +0530105 and exists(select * from `tabSales Order` so
Nabin Hait62985362014-04-04 12:05:16 +0530106 where so.name = so_item.parent and so.docstatus = 1
patilsangrama812d672016-02-23 19:04:29 +0530107 and so.status != 'Closed'))
Nabin Haiteea2b342013-10-11 18:31:33 +0530108 ) tab
Nabin Hait62985362014-04-04 12:05:16 +0530109 where
Nabin Haiteea2b342013-10-11 18:31:33 +0530110 so_item_qty >= so_item_delivered_qty
111 """, (item_code, warehouse, item_code, warehouse))
112
113 return flt(reserved_qty[0][0]) if reserved_qty else 0
Nabin Hait62985362014-04-04 12:05:16 +0530114
Nabin Haiteea2b342013-10-11 18:31:33 +0530115def get_indented_qty(item_code, warehouse):
Mangesh-Khairnar1ac9a8e2019-07-15 14:08:47 +0530116 indented_qty = frappe.db.sql("""select sum((mr_item.qty - mr_item.ordered_qty) * mr_item.conversion_factor)
Nabin Hait4acd4312014-11-04 15:32:31 +0530117 from `tabMaterial Request Item` mr_item, `tabMaterial Request` mr
118 where mr_item.item_code=%s and mr_item.warehouse=%s
Anand Doshi602e8252015-11-16 19:05:46 +0530119 and mr_item.qty > mr_item.ordered_qty and mr_item.parent=mr.name
Nabin Hait4acd4312014-11-04 15:32:31 +0530120 and mr.status!='Stopped' and mr.docstatus=1""", (item_code, warehouse))
Nabin Hait62985362014-04-04 12:05:16 +0530121
Nabin Haiteea2b342013-10-11 18:31:33 +0530122 return flt(indented_qty[0][0]) if indented_qty else 0
123
124def get_ordered_qty(item_code, warehouse):
Anand Doshie9baaa62014-02-26 12:35:33 +0530125 ordered_qty = frappe.db.sql("""
Anand Doshi602e8252015-11-16 19:05:46 +0530126 select sum((po_item.qty - po_item.received_qty)*po_item.conversion_factor)
Nabin Haiteea2b342013-10-11 18:31:33 +0530127 from `tabPurchase Order Item` po_item, `tabPurchase Order` po
Nabin Hait62985362014-04-04 12:05:16 +0530128 where po_item.item_code=%s and po_item.warehouse=%s
Anand Doshi602e8252015-11-16 19:05:46 +0530129 and po_item.qty > po_item.received_qty and po_item.parent=po.name
patilsangrambf2b5112016-02-22 16:24:23 +0530130 and po.status not in ('Closed', 'Delivered') and po.docstatus=1
Anand Doshi602e8252015-11-16 19:05:46 +0530131 and po_item.delivered_by_supplier = 0""", (item_code, warehouse))
Nabin Hait62985362014-04-04 12:05:16 +0530132
Nabin Haiteea2b342013-10-11 18:31:33 +0530133 return flt(ordered_qty[0][0]) if ordered_qty else 0
Nabin Hait62985362014-04-04 12:05:16 +0530134
Nabin Haiteea2b342013-10-11 18:31:33 +0530135def get_planned_qty(item_code, warehouse):
Anand Doshie9baaa62014-02-26 12:35:33 +0530136 planned_qty = frappe.db.sql("""
Zarrar13ddc7e2018-03-20 12:38:43 +0530137 select sum(qty - produced_qty) from `tabWork Order`
Nabin Hait949a9202017-07-05 13:55:41 +0530138 where production_item = %s and fg_warehouse = %s and status not in ("Stopped", "Completed")
Anand Doshi602e8252015-11-16 19:05:46 +0530139 and docstatus=1 and qty > produced_qty""", (item_code, warehouse))
Nabin Haiteea2b342013-10-11 18:31:33 +0530140
141 return flt(planned_qty[0][0]) if planned_qty else 0
Nabin Hait62985362014-04-04 12:05:16 +0530142
143
Nabin Hait7f3f2a02014-09-01 18:16:05 +0530144def update_bin_qty(item_code, warehouse, qty_dict=None):
Rushabh Mehta1f847992013-12-12 19:12:19 +0530145 from erpnext.stock.utils import get_bin
Nabin Haiteea2b342013-10-11 18:31:33 +0530146 bin = get_bin(item_code, warehouse)
147 mismatch = False
148 for fld, val in qty_dict.items():
Anand Doshif78d1ae2014-03-28 13:55:00 +0530149 if flt(bin.get(fld)) != flt(val):
150 bin.set(fld, flt(val))
Nabin Haiteea2b342013-10-11 18:31:33 +0530151 mismatch = True
Nabin Hait62985362014-04-04 12:05:16 +0530152
Nabin Haiteea2b342013-10-11 18:31:33 +0530153 if mismatch:
Himanshu Mishraf56aac62018-08-08 18:32:03 +0530154 bin.set_projected_qty()
155 bin.db_update()
156 bin.clear_cache()
Nabin Hait62985362014-04-04 12:05:16 +0530157
158def set_stock_balance_as_per_serial_no(item_code=None, posting_date=None, posting_time=None,
159 fiscal_year=None):
160 if not posting_date: posting_date = nowdate()
161 if not posting_time: posting_time = nowtime()
Nabin Hait62985362014-04-04 12:05:16 +0530162
163 condition = " and item.name='%s'" % item_code.replace("'", "\'") if item_code else ""
164
165 bin = frappe.db.sql("""select bin.item_code, bin.warehouse, bin.actual_qty, item.stock_uom
166 from `tabBin` bin, tabItem item
Rushabh Mehta1e8025b2015-07-24 15:16:25 +0530167 where bin.item_code = item.name and item.has_serial_no = 1 %s""" % condition)
Nabin Hait62985362014-04-04 12:05:16 +0530168
169 for d in bin:
170 serial_nos = frappe.db.sql("""select count(name) from `tabSerial No`
Nabin Hait398c83a2015-10-22 15:11:44 +0530171 where item_code=%s and warehouse=%s and docstatus < 2""", (d[0], d[1]))
Nabin Hait62985362014-04-04 12:05:16 +0530172
173 if serial_nos and flt(serial_nos[0][0]) != flt(d[2]):
Aditya Hase6ccb6562017-08-28 18:17:36 +0530174 print(d[0], d[1], d[2], serial_nos[0][0])
Nabin Hait62985362014-04-04 12:05:16 +0530175
176 sle = frappe.db.sql("""select valuation_rate, company from `tabStock Ledger Entry`
177 where item_code = %s and warehouse = %s and ifnull(is_cancelled, 'No') = 'No'
178 order by posting_date desc limit 1""", (d[0], d[1]))
179
180 sle_dict = {
181 'doctype' : 'Stock Ledger Entry',
182 'item_code' : d[0],
183 'warehouse' : d[1],
184 'transaction_date' : nowdate(),
185 'posting_date' : posting_date,
186 'posting_time' : posting_time,
187 'voucher_type' : 'Stock Reconciliation (Manual)',
188 'voucher_no' : '',
189 'voucher_detail_no' : '',
190 'actual_qty' : flt(serial_nos[0][0]) - flt(d[2]),
191 'stock_uom' : d[3],
192 'incoming_rate' : sle and flt(serial_nos[0][0]) > flt(d[2]) and flt(sle[0][0]) or 0,
193 'company' : sle and cstr(sle[0][1]) or 0,
Nabin Hait62985362014-04-04 12:05:16 +0530194 'is_cancelled' : 'No',
195 'batch_no' : '',
196 'serial_no' : ''
197 }
198
199 sle_doc = frappe.get_doc(sle_dict)
Anand Doshi6dfd4302015-02-10 14:41:27 +0530200 sle_doc.flags.ignore_validate = True
201 sle_doc.flags.ignore_links = True
Nabin Hait62985362014-04-04 12:05:16 +0530202 sle_doc.insert()
203
204 args = sle_dict.copy()
205 args.update({
206 "sle_id": sle_doc.name,
207 "is_amended": 'No'
208 })
209
210 update_bin(args)
211 update_entries_after({
212 "item_code": d[0],
213 "warehouse": d[1],
214 "posting_date": posting_date,
215 "posting_time": posting_time
216 })
nabinhait5c384882014-07-14 11:43:00 +0530217
nabinhait7700c622014-07-14 14:21:21 +0530218def reset_serial_no_status_and_warehouse(serial_nos=None):
nabinhait5c384882014-07-14 11:43:00 +0530219 if not serial_nos:
Nabin Haitc865f222015-09-21 09:18:43 +0530220 serial_nos = frappe.db.sql_list("""select name from `tabSerial No` where docstatus = 0""")
nabinhait5c384882014-07-14 11:43:00 +0530221 for serial_no in serial_nos:
222 try:
223 sr = frappe.get_doc("Serial No", serial_no)
nabinhaitb0a8d002014-07-14 11:56:03 +0530224 last_sle = sr.get_last_sle()
225 if flt(last_sle.actual_qty) > 0:
226 sr.warehouse = last_sle.warehouse
Nabin Hait7f3f2a02014-09-01 18:16:05 +0530227
nabinhait5c384882014-07-14 11:43:00 +0530228 sr.via_stock_ledger = True
229 sr.save()
230 except:
231 pass
Nabin Hait7f3f2a02014-09-01 18:16:05 +0530232
Nabin Hait001edb42019-09-26 16:44:35 +0530233def repost_gle_for_stock_transactions(posting_date=None, posting_time=None, for_warehouses=None):
234 frappe.db.auto_commit_on_many_writes = 1
Nabin Hait8a28ccf2014-10-14 11:41:44 +0530235
Nabin Hait001edb42019-09-26 16:44:35 +0530236 if not posting_date:
237 posting_date = "1900-01-01"
238 if not posting_time:
239 posting_time = "00:00"
Nabin Hait6c48ef72014-10-08 11:00:38 +0530240
Nabin Hait001edb42019-09-26 16:44:35 +0530241 update_gl_entries_after(posting_date, posting_time, for_warehouses=for_warehouses)
Nabin Hait6c48ef72014-10-08 11:00:38 +0530242
Nabin Hait001edb42019-09-26 16:44:35 +0530243 frappe.db.auto_commit_on_many_writes = 0