blob: 90c82c43c3eca00a6743d066b39cf0ab21f176e8 [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 Haiteea2b342013-10-11 18:31:33 +05306
Nabin Hait62985362014-04-04 12:05:16 +05307from frappe.utils import flt, cstr, nowdate, nowtime
8from erpnext.stock.utils import update_bin
9from erpnext.stock.stock_ledger import update_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
21 for d in frappe.db.sql("""select distinct item_code, warehouse from
Nabin Hait4ed7f682013-10-23 11:50:09 +053022 (select item_code, warehouse from tabBin
23 union
Nabin Haitc2caae52013-10-23 12:02:08 +053024 select item_code, warehouse from `tabStock Ledger Entry`) a"""):
Nabin Hait8a28ccf2014-10-14 11:41:44 +053025 try:
Nabin Haitb7e46c42015-10-12 16:46:29 +053026 repost_stock(d[0], d[1], allow_zero_rate, only_actual, only_bin)
Nabin Hait8a28ccf2014-10-14 11:41:44 +053027 frappe.db.commit()
28 except:
29 frappe.db.rollback()
Nabin Hait62985362014-04-04 12:05:16 +053030
Nabin Haitca471f42013-11-20 13:14:12 +053031 if allow_negative_stock:
Nabin Hait249bbbc2014-11-26 15:35:08 +053032 frappe.db.set_value("Stock Settings", None, "allow_negative_stock", existing_allow_negative_stock)
Anand Doshie9baaa62014-02-26 12:35:33 +053033 frappe.db.auto_commit_on_many_writes = 0
Nabin Haiteea2b342013-10-11 18:31:33 +053034
Nabin Haitb7e46c42015-10-12 16:46:29 +053035def repost_stock(item_code, warehouse, allow_zero_rate=False, only_actual=False, only_bin=False):
36 if not only_bin:
Rushabh Mehtac4d4c7f2015-10-14 17:37:28 +053037 repost_actual_qty(item_code, warehouse, allow_zero_rate)
Nabin Hait62985362014-04-04 12:05:16 +053038
Nabin Hait2348a5f2014-10-15 15:31:33 +053039 if item_code and warehouse and not only_actual:
Nabin Haitb7e46c42015-10-12 16:46:29 +053040 qty_dict = {
Nabin Haiteea2b342013-10-11 18:31:33 +053041 "reserved_qty": get_reserved_qty(item_code, warehouse),
42 "indented_qty": get_indented_qty(item_code, warehouse),
43 "ordered_qty": get_ordered_qty(item_code, warehouse),
44 "planned_qty": get_planned_qty(item_code, warehouse)
Nabin Haitb7e46c42015-10-12 16:46:29 +053045 }
46 if only_bin:
47 qty_dict.update({
48 "actual_qty": get_balance_qty_from_sle(item_code, warehouse)
49 })
Rushabh Mehtac4d4c7f2015-10-14 17:37:28 +053050
Nabin Haitb7e46c42015-10-12 16:46:29 +053051 update_bin_qty(item_code, warehouse, qty_dict)
Nabin Haiteea2b342013-10-11 18:31:33 +053052
Nabin Haitf1a07ff2014-10-15 12:23:35 +053053def repost_actual_qty(item_code, warehouse, allow_zero_rate=False):
Nabin Hait5048c982013-10-23 12:14:32 +053054 try:
Nabin Haitf1a07ff2014-10-15 12:23:35 +053055 update_entries_after({ "item_code": item_code, "warehouse": warehouse }, allow_zero_rate)
Nabin Hait5048c982013-10-23 12:14:32 +053056 except:
57 pass
Rushabh Mehtac4d4c7f2015-10-14 17:37:28 +053058
Nabin Haitb7e46c42015-10-12 16:46:29 +053059def get_balance_qty_from_sle(item_code, warehouse):
60 balance_qty = frappe.db.sql("""select qty_after_transaction from `tabStock Ledger Entry`
61 where item_code=%s and warehouse=%s and is_cancelled='No'
62 order by posting_date desc, posting_time desc, name desc
63 limit 1""", (item_code, warehouse))
Rushabh Mehtac4d4c7f2015-10-14 17:37:28 +053064
Nabin Haitb7e46c42015-10-12 16:46:29 +053065 return flt(balance_qty[0][0]) if balance_qty else 0.0
Nabin Hait62985362014-04-04 12:05:16 +053066
Nabin Haiteea2b342013-10-11 18:31:33 +053067def get_reserved_qty(item_code, warehouse):
Anand Doshie9baaa62014-02-26 12:35:33 +053068 reserved_qty = frappe.db.sql("""
Nabin Hait62985362014-04-04 12:05:16 +053069 select
rohitwaghchaureafa93c62017-03-29 17:29:20 +053070 sum(dnpi_qty * ((so_item_qty - so_item_delivered_qty) / so_item_qty))
Nabin Hait62985362014-04-04 12:05:16 +053071 from
Nabin Haiteea2b342013-10-11 18:31:33 +053072 (
73 (select
74 qty as dnpi_qty,
75 (
rohitwaghchaureafa93c62017-03-29 17:29:20 +053076 select qty from `tabSales Order Item`
Nabin Haiteea2b342013-10-11 18:31:33 +053077 where name = dnpi.parent_detail_docname
Saurabh2e292062015-11-18 17:03:33 +053078 and (delivered_by_supplier is null or delivered_by_supplier = 0)
Nabin Haiteea2b342013-10-11 18:31:33 +053079 ) as so_item_qty,
80 (
Anand Doshi602e8252015-11-16 19:05:46 +053081 select delivered_qty from `tabSales Order Item`
82 where name = dnpi.parent_detail_docname
83 and delivered_by_supplier = 0
Nabin Hait62985362014-04-04 12:05:16 +053084 ) as so_item_delivered_qty,
Nabin Haiteea2b342013-10-11 18:31:33 +053085 parent, name
Nabin Hait62985362014-04-04 12:05:16 +053086 from
Nabin Haiteea2b342013-10-11 18:31:33 +053087 (
88 select qty, parent_detail_docname, parent, name
Nabin Haitd1fd1e22013-10-18 12:29:11 +053089 from `tabPacked Item` dnpi_in
Nabin Haiteea2b342013-10-11 18:31:33 +053090 where item_code = %s and warehouse = %s
91 and parenttype="Sales Order"
Nabin Haitfc2dd442014-10-17 13:05:24 +053092 and item_code != parent_item
Nabin Haiteea2b342013-10-11 18:31:33 +053093 and exists (select * from `tabSales Order` so
patilsangrama812d672016-02-23 19:04:29 +053094 where name = dnpi_in.parent and docstatus = 1 and status != 'Closed')
Nabin Haiteea2b342013-10-11 18:31:33 +053095 ) dnpi)
96 union
rohitwaghchaureafa93c62017-03-29 17:29:20 +053097 (select stock_qty as dnpi_qty, qty as so_item_qty,
Anand Doshi602e8252015-11-16 19:05:46 +053098 delivered_qty as so_item_delivered_qty, parent, name
Nabin Haiteea2b342013-10-11 18:31:33 +053099 from `tabSales Order Item` so_item
Anand Doshi602e8252015-11-16 19:05:46 +0530100 where item_code = %s and warehouse = %s
Saurabh2e292062015-11-18 17:03:33 +0530101 and (so_item.delivered_by_supplier is null or so_item.delivered_by_supplier = 0)
Nabin Haiteea2b342013-10-11 18:31:33 +0530102 and exists(select * from `tabSales Order` so
Nabin Hait62985362014-04-04 12:05:16 +0530103 where so.name = so_item.parent and so.docstatus = 1
patilsangrama812d672016-02-23 19:04:29 +0530104 and so.status != 'Closed'))
Nabin Haiteea2b342013-10-11 18:31:33 +0530105 ) tab
Nabin Hait62985362014-04-04 12:05:16 +0530106 where
Nabin Haiteea2b342013-10-11 18:31:33 +0530107 so_item_qty >= so_item_delivered_qty
108 """, (item_code, warehouse, item_code, warehouse))
109
110 return flt(reserved_qty[0][0]) if reserved_qty else 0
Nabin Hait62985362014-04-04 12:05:16 +0530111
Nabin Haiteea2b342013-10-11 18:31:33 +0530112def get_indented_qty(item_code, warehouse):
Anand Doshi602e8252015-11-16 19:05:46 +0530113 indented_qty = frappe.db.sql("""select sum(mr_item.qty - mr_item.ordered_qty)
Nabin Hait4acd4312014-11-04 15:32:31 +0530114 from `tabMaterial Request Item` mr_item, `tabMaterial Request` mr
115 where mr_item.item_code=%s and mr_item.warehouse=%s
Anand Doshi602e8252015-11-16 19:05:46 +0530116 and mr_item.qty > mr_item.ordered_qty and mr_item.parent=mr.name
Nabin Hait4acd4312014-11-04 15:32:31 +0530117 and mr.status!='Stopped' and mr.docstatus=1""", (item_code, warehouse))
Nabin Hait62985362014-04-04 12:05:16 +0530118
Nabin Haiteea2b342013-10-11 18:31:33 +0530119 return flt(indented_qty[0][0]) if indented_qty else 0
120
121def get_ordered_qty(item_code, warehouse):
Anand Doshie9baaa62014-02-26 12:35:33 +0530122 ordered_qty = frappe.db.sql("""
Anand Doshi602e8252015-11-16 19:05:46 +0530123 select sum((po_item.qty - po_item.received_qty)*po_item.conversion_factor)
Nabin Haiteea2b342013-10-11 18:31:33 +0530124 from `tabPurchase Order Item` po_item, `tabPurchase Order` po
Nabin Hait62985362014-04-04 12:05:16 +0530125 where po_item.item_code=%s and po_item.warehouse=%s
Anand Doshi602e8252015-11-16 19:05:46 +0530126 and po_item.qty > po_item.received_qty and po_item.parent=po.name
patilsangrambf2b5112016-02-22 16:24:23 +0530127 and po.status not in ('Closed', 'Delivered') and po.docstatus=1
Anand Doshi602e8252015-11-16 19:05:46 +0530128 and po_item.delivered_by_supplier = 0""", (item_code, warehouse))
Nabin Hait62985362014-04-04 12:05:16 +0530129
Nabin Haiteea2b342013-10-11 18:31:33 +0530130 return flt(ordered_qty[0][0]) if ordered_qty else 0
Nabin Hait62985362014-04-04 12:05:16 +0530131
Nabin Haiteea2b342013-10-11 18:31:33 +0530132def get_planned_qty(item_code, warehouse):
Anand Doshie9baaa62014-02-26 12:35:33 +0530133 planned_qty = frappe.db.sql("""
Zarrar13ddc7e2018-03-20 12:38:43 +0530134 select sum(qty - produced_qty) from `tabWork Order`
Nabin Hait949a9202017-07-05 13:55:41 +0530135 where production_item = %s and fg_warehouse = %s and status not in ("Stopped", "Completed")
Anand Doshi602e8252015-11-16 19:05:46 +0530136 and docstatus=1 and qty > produced_qty""", (item_code, warehouse))
Nabin Haiteea2b342013-10-11 18:31:33 +0530137
138 return flt(planned_qty[0][0]) if planned_qty else 0
Nabin Hait62985362014-04-04 12:05:16 +0530139
140
Nabin Hait7f3f2a02014-09-01 18:16:05 +0530141def update_bin_qty(item_code, warehouse, qty_dict=None):
Rushabh Mehta1f847992013-12-12 19:12:19 +0530142 from erpnext.stock.utils import get_bin
Nabin Haiteea2b342013-10-11 18:31:33 +0530143 bin = get_bin(item_code, warehouse)
144 mismatch = False
145 for fld, val in qty_dict.items():
Anand Doshif78d1ae2014-03-28 13:55:00 +0530146 if flt(bin.get(fld)) != flt(val):
147 bin.set(fld, flt(val))
Nabin Haiteea2b342013-10-11 18:31:33 +0530148 mismatch = True
Nabin Hait62985362014-04-04 12:05:16 +0530149
Nabin Haiteea2b342013-10-11 18:31:33 +0530150 if mismatch:
Rushabh Mehta05253872016-04-18 19:27:36 +0530151 bin.projected_qty = (flt(bin.actual_qty) + flt(bin.ordered_qty) +
Anand Doshif78d1ae2014-03-28 13:55:00 +0530152 flt(bin.indented_qty) + flt(bin.planned_qty) - flt(bin.reserved_qty)
pawanf5279a02017-11-24 11:21:47 +0530153 - flt(bin.reserved_qty_for_production)) - flt(bin.reserved_qty_for_sub_contract)
Nabin Hait62985362014-04-04 12:05:16 +0530154
155 bin.save()
156
157def set_stock_balance_as_per_serial_no(item_code=None, posting_date=None, posting_time=None,
158 fiscal_year=None):
159 if not posting_date: posting_date = nowdate()
160 if not posting_time: posting_time = nowtime()
Nabin Hait62985362014-04-04 12:05:16 +0530161
162 condition = " and item.name='%s'" % item_code.replace("'", "\'") if item_code else ""
163
164 bin = frappe.db.sql("""select bin.item_code, bin.warehouse, bin.actual_qty, item.stock_uom
165 from `tabBin` bin, tabItem item
Rushabh Mehta1e8025b2015-07-24 15:16:25 +0530166 where bin.item_code = item.name and item.has_serial_no = 1 %s""" % condition)
Nabin Hait62985362014-04-04 12:05:16 +0530167
168 for d in bin:
169 serial_nos = frappe.db.sql("""select count(name) from `tabSerial No`
Nabin Hait398c83a2015-10-22 15:11:44 +0530170 where item_code=%s and warehouse=%s and docstatus < 2""", (d[0], d[1]))
Nabin Hait62985362014-04-04 12:05:16 +0530171
172 if serial_nos and flt(serial_nos[0][0]) != flt(d[2]):
Aditya Hase6ccb6562017-08-28 18:17:36 +0530173 print(d[0], d[1], d[2], serial_nos[0][0])
Nabin Hait62985362014-04-04 12:05:16 +0530174
175 sle = frappe.db.sql("""select valuation_rate, company from `tabStock Ledger Entry`
176 where item_code = %s and warehouse = %s and ifnull(is_cancelled, 'No') = 'No'
177 order by posting_date desc limit 1""", (d[0], d[1]))
178
179 sle_dict = {
180 'doctype' : 'Stock Ledger Entry',
181 'item_code' : d[0],
182 'warehouse' : d[1],
183 'transaction_date' : nowdate(),
184 'posting_date' : posting_date,
185 'posting_time' : posting_time,
186 'voucher_type' : 'Stock Reconciliation (Manual)',
187 'voucher_no' : '',
188 'voucher_detail_no' : '',
189 'actual_qty' : flt(serial_nos[0][0]) - flt(d[2]),
190 'stock_uom' : d[3],
191 'incoming_rate' : sle and flt(serial_nos[0][0]) > flt(d[2]) and flt(sle[0][0]) or 0,
192 'company' : sle and cstr(sle[0][1]) or 0,
Nabin Hait62985362014-04-04 12:05:16 +0530193 'is_cancelled' : 'No',
194 'batch_no' : '',
195 'serial_no' : ''
196 }
197
198 sle_doc = frappe.get_doc(sle_dict)
Anand Doshi6dfd4302015-02-10 14:41:27 +0530199 sle_doc.flags.ignore_validate = True
200 sle_doc.flags.ignore_links = True
Nabin Hait62985362014-04-04 12:05:16 +0530201 sle_doc.insert()
202
203 args = sle_dict.copy()
204 args.update({
205 "sle_id": sle_doc.name,
206 "is_amended": 'No'
207 })
208
209 update_bin(args)
210 update_entries_after({
211 "item_code": d[0],
212 "warehouse": d[1],
213 "posting_date": posting_date,
214 "posting_time": posting_time
215 })
nabinhait5c384882014-07-14 11:43:00 +0530216
nabinhait7700c622014-07-14 14:21:21 +0530217def reset_serial_no_status_and_warehouse(serial_nos=None):
nabinhait5c384882014-07-14 11:43:00 +0530218 if not serial_nos:
Nabin Haitc865f222015-09-21 09:18:43 +0530219 serial_nos = frappe.db.sql_list("""select name from `tabSerial No` where docstatus = 0""")
nabinhait5c384882014-07-14 11:43:00 +0530220 for serial_no in serial_nos:
221 try:
222 sr = frappe.get_doc("Serial No", serial_no)
nabinhaitb0a8d002014-07-14 11:56:03 +0530223 last_sle = sr.get_last_sle()
224 if flt(last_sle.actual_qty) > 0:
225 sr.warehouse = last_sle.warehouse
Nabin Hait7f3f2a02014-09-01 18:16:05 +0530226
nabinhait5c384882014-07-14 11:43:00 +0530227 sr.via_stock_ledger = True
228 sr.save()
229 except:
230 pass
Nabin Hait7f3f2a02014-09-01 18:16:05 +0530231
Nabin Hait6c48ef72014-10-08 11:00:38 +0530232def repost_all_stock_vouchers():
Nabin Haitb3bc4112016-09-28 18:17:52 +0530233 warehouses_with_account = frappe.db.sql_list("""select warehouse from tabAccount
Saurabh78333c72016-06-25 14:18:28 +0530234 where ifnull(account_type, '') = 'Stock' and (warehouse is not null and warehouse != '')
235 and is_group=0""")
Nabin Hait8a28ccf2014-10-14 11:41:44 +0530236
Nabin Hait6c48ef72014-10-08 11:00:38 +0530237 vouchers = frappe.db.sql("""select distinct voucher_type, voucher_no
Nabin Hait8a28ccf2014-10-14 11:41:44 +0530238 from `tabStock Ledger Entry` sle
239 where voucher_type != "Serial No" and sle.warehouse in (%s)
240 order by posting_date, posting_time, name""" %
241 ', '.join(['%s']*len(warehouses_with_account)), tuple(warehouses_with_account))
Nabin Hait6c48ef72014-10-08 11:00:38 +0530242
243 rejected = []
Nabin Hait4d742162014-10-09 19:25:03 +0530244 i = 0
Nabin Hait6c48ef72014-10-08 11:00:38 +0530245 for voucher_type, voucher_no in vouchers:
Nabin Hait4d742162014-10-09 19:25:03 +0530246 i+=1
Aditya Hase6ccb6562017-08-28 18:17:36 +0530247 print(i, "/", len(vouchers), voucher_type, voucher_no)
Nabin Hait6c48ef72014-10-08 11:00:38 +0530248 try:
249 for dt in ["Stock Ledger Entry", "GL Entry"]:
250 frappe.db.sql("""delete from `tab%s` where voucher_type=%s and voucher_no=%s"""%
251 (dt, '%s', '%s'), (voucher_type, voucher_no))
252
253 doc = frappe.get_doc(voucher_type, voucher_no)
254 if voucher_type=="Stock Entry" and doc.purpose in ["Manufacture", "Repack"]:
Nabin Hait3c3a3ec2015-08-07 17:17:03 +0530255 doc.calculate_rate_and_amount(force=1)
Nabin Hait7c6f9902014-10-10 18:03:27 +0530256 elif voucher_type=="Purchase Receipt" and doc.is_subcontracted == "Yes":
257 doc.validate()
Nabin Haite96e83d2014-10-08 18:06:14 +0530258
Nabin Hait6c48ef72014-10-08 11:00:38 +0530259 doc.update_stock_ledger()
Nabin Hait4e7cc932015-01-12 10:55:48 +0530260 doc.make_gl_entries(repost_future_gle=False)
Nabin Haite96e83d2014-10-08 18:06:14 +0530261 frappe.db.commit()
Aditya Hase6ccb6562017-08-28 18:17:36 +0530262 except Exception as e:
263 print(frappe.get_traceback())
Nabin Hait6c48ef72014-10-08 11:00:38 +0530264 rejected.append([voucher_type, voucher_no])
Nabin Haite96e83d2014-10-08 18:06:14 +0530265 frappe.db.rollback()
Nabin Hait6c48ef72014-10-08 11:00:38 +0530266
Aditya Hase6ccb6562017-08-28 18:17:36 +0530267 print(rejected)