blob: efc604bd91fcc6309425443685112b88da440e42 [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
4from __future__ import 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
10from erpnext.accounts.utils import get_fiscal_year
Nabin Haiteea2b342013-10-11 18:31:33 +053011
Nabin Haitb7e46c42015-10-12 16:46:29 +053012def repost(only_actual=False, allow_negative_stock=False, allow_zero_rate=False, only_bin=False):
Nabin Haiteea2b342013-10-11 18:31:33 +053013 """
14 Repost everything!
15 """
Anand Doshie9baaa62014-02-26 12:35:33 +053016 frappe.db.auto_commit_on_many_writes = 1
Nabin Hait62985362014-04-04 12:05:16 +053017
Nabin Haitca471f42013-11-20 13:14:12 +053018 if allow_negative_stock:
Nabin Hait249bbbc2014-11-26 15:35:08 +053019 existing_allow_negative_stock = frappe.db.get_value("Stock Settings", None, "allow_negative_stock")
20 frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
Nabin Hait62985362014-04-04 12:05:16 +053021
22 for d in frappe.db.sql("""select distinct item_code, warehouse from
Nabin Hait4ed7f682013-10-23 11:50:09 +053023 (select item_code, warehouse from tabBin
24 union
Nabin Haitc2caae52013-10-23 12:02:08 +053025 select item_code, warehouse from `tabStock Ledger Entry`) a"""):
Nabin Hait8a28ccf2014-10-14 11:41:44 +053026 try:
Nabin Haitb7e46c42015-10-12 16:46:29 +053027 repost_stock(d[0], d[1], allow_zero_rate, only_actual, only_bin)
Nabin Hait8a28ccf2014-10-14 11:41:44 +053028 frappe.db.commit()
29 except:
30 frappe.db.rollback()
Nabin Hait62985362014-04-04 12:05:16 +053031
Nabin Haitca471f42013-11-20 13:14:12 +053032 if allow_negative_stock:
Nabin Hait249bbbc2014-11-26 15:35:08 +053033 frappe.db.set_value("Stock Settings", None, "allow_negative_stock", existing_allow_negative_stock)
Anand Doshie9baaa62014-02-26 12:35:33 +053034 frappe.db.auto_commit_on_many_writes = 0
Nabin Haiteea2b342013-10-11 18:31:33 +053035
Nabin Haitb7e46c42015-10-12 16:46:29 +053036def repost_stock(item_code, warehouse, allow_zero_rate=False, only_actual=False, only_bin=False):
37 if not only_bin:
Rushabh Mehtac4d4c7f2015-10-14 17:37:28 +053038 repost_actual_qty(item_code, warehouse, allow_zero_rate)
Nabin Hait62985362014-04-04 12:05:16 +053039
Nabin Hait2348a5f2014-10-15 15:31:33 +053040 if item_code and warehouse and not only_actual:
Nabin Haitb7e46c42015-10-12 16:46:29 +053041 qty_dict = {
Nabin Haiteea2b342013-10-11 18:31:33 +053042 "reserved_qty": get_reserved_qty(item_code, warehouse),
43 "indented_qty": get_indented_qty(item_code, warehouse),
44 "ordered_qty": get_ordered_qty(item_code, warehouse),
45 "planned_qty": get_planned_qty(item_code, warehouse)
Nabin Haitb7e46c42015-10-12 16:46:29 +053046 }
47 if only_bin:
48 qty_dict.update({
49 "actual_qty": get_balance_qty_from_sle(item_code, warehouse)
50 })
Rushabh Mehtac4d4c7f2015-10-14 17:37:28 +053051
Nabin Haitb7e46c42015-10-12 16:46:29 +053052 update_bin_qty(item_code, warehouse, qty_dict)
Nabin Haiteea2b342013-10-11 18:31:33 +053053
Nabin Haitf1a07ff2014-10-15 12:23:35 +053054def repost_actual_qty(item_code, warehouse, allow_zero_rate=False):
Nabin Hait5048c982013-10-23 12:14:32 +053055 try:
Nabin Haitf1a07ff2014-10-15 12:23:35 +053056 update_entries_after({ "item_code": item_code, "warehouse": warehouse }, allow_zero_rate)
Nabin Hait5048c982013-10-23 12:14:32 +053057 except:
58 pass
Rushabh Mehtac4d4c7f2015-10-14 17:37:28 +053059
Nabin Haitb7e46c42015-10-12 16:46:29 +053060def get_balance_qty_from_sle(item_code, warehouse):
61 balance_qty = frappe.db.sql("""select qty_after_transaction from `tabStock Ledger Entry`
62 where item_code=%s and warehouse=%s and is_cancelled='No'
63 order by posting_date desc, posting_time desc, name desc
64 limit 1""", (item_code, warehouse))
Rushabh Mehtac4d4c7f2015-10-14 17:37:28 +053065
Nabin Haitb7e46c42015-10-12 16:46:29 +053066 return flt(balance_qty[0][0]) if balance_qty else 0.0
Nabin Hait62985362014-04-04 12:05:16 +053067
Nabin Haiteea2b342013-10-11 18:31:33 +053068def get_reserved_qty(item_code, warehouse):
Anand Doshie9baaa62014-02-26 12:35:33 +053069 reserved_qty = frappe.db.sql("""
Nabin Hait62985362014-04-04 12:05:16 +053070 select
Nabin Haiteea2b342013-10-11 18:31:33 +053071 sum((dnpi_qty / so_item_qty) * (so_item_qty - so_item_delivered_qty))
Nabin Hait62985362014-04-04 12:05:16 +053072 from
Nabin Haiteea2b342013-10-11 18:31:33 +053073 (
74 (select
75 qty as dnpi_qty,
76 (
77 select qty from `tabSales Order Item`
78 where name = dnpi.parent_detail_docname
79 ) as so_item_qty,
80 (
81 select ifnull(delivered_qty, 0) from `tabSales Order Item`
82 where name = dnpi.parent_detail_docname
Nabin Hait62985362014-04-04 12:05:16 +053083 ) as so_item_delivered_qty,
Nabin Haiteea2b342013-10-11 18:31:33 +053084 parent, name
Nabin Hait62985362014-04-04 12:05:16 +053085 from
Nabin Haiteea2b342013-10-11 18:31:33 +053086 (
87 select qty, parent_detail_docname, parent, name
Nabin Haitd1fd1e22013-10-18 12:29:11 +053088 from `tabPacked Item` dnpi_in
Nabin Haiteea2b342013-10-11 18:31:33 +053089 where item_code = %s and warehouse = %s
90 and parenttype="Sales Order"
Nabin Haitfc2dd442014-10-17 13:05:24 +053091 and item_code != parent_item
Nabin Haiteea2b342013-10-11 18:31:33 +053092 and exists (select * from `tabSales Order` so
93 where name = dnpi_in.parent and docstatus = 1 and status != 'Stopped')
94 ) dnpi)
95 union
96 (select qty as dnpi_qty, qty as so_item_qty,
97 ifnull(delivered_qty, 0) as so_item_delivered_qty, parent, name
98 from `tabSales Order Item` so_item
Nabin Hait06927a22014-08-25 14:08:54 +053099 where item_code = %s and warehouse = %s
Nabin Haiteea2b342013-10-11 18:31:33 +0530100 and exists(select * from `tabSales Order` so
Nabin Hait62985362014-04-04 12:05:16 +0530101 where so.name = so_item.parent and so.docstatus = 1
Nabin Haiteea2b342013-10-11 18:31:33 +0530102 and so.status != 'Stopped'))
103 ) tab
Nabin Hait62985362014-04-04 12:05:16 +0530104 where
Nabin Haiteea2b342013-10-11 18:31:33 +0530105 so_item_qty >= so_item_delivered_qty
106 """, (item_code, warehouse, item_code, warehouse))
107
108 return flt(reserved_qty[0][0]) if reserved_qty else 0
Nabin Hait62985362014-04-04 12:05:16 +0530109
Nabin Haiteea2b342013-10-11 18:31:33 +0530110def get_indented_qty(item_code, warehouse):
Nabin Hait4acd4312014-11-04 15:32:31 +0530111 indented_qty = frappe.db.sql("""select sum(mr_item.qty - ifnull(mr_item.ordered_qty, 0))
112 from `tabMaterial Request Item` mr_item, `tabMaterial Request` mr
113 where mr_item.item_code=%s and mr_item.warehouse=%s
114 and mr_item.qty > ifnull(mr_item.ordered_qty, 0) and mr_item.parent=mr.name
115 and mr.status!='Stopped' and mr.docstatus=1""", (item_code, warehouse))
Nabin Hait62985362014-04-04 12:05:16 +0530116
Nabin Haiteea2b342013-10-11 18:31:33 +0530117 return flt(indented_qty[0][0]) if indented_qty else 0
118
119def get_ordered_qty(item_code, warehouse):
Anand Doshie9baaa62014-02-26 12:35:33 +0530120 ordered_qty = frappe.db.sql("""
Nabin Hait1a60fd82013-10-14 14:27:08 +0530121 select sum((po_item.qty - ifnull(po_item.received_qty, 0))*po_item.conversion_factor)
Nabin Haiteea2b342013-10-11 18:31:33 +0530122 from `tabPurchase Order Item` po_item, `tabPurchase Order` po
Nabin Hait62985362014-04-04 12:05:16 +0530123 where po_item.item_code=%s and po_item.warehouse=%s
124 and po_item.qty > ifnull(po_item.received_qty, 0) and po_item.parent=po.name
Nabin Haiteea2b342013-10-11 18:31:33 +0530125 and po.status!='Stopped' and po.docstatus=1""", (item_code, warehouse))
Nabin Hait62985362014-04-04 12:05:16 +0530126
Nabin Haiteea2b342013-10-11 18:31:33 +0530127 return flt(ordered_qty[0][0]) if ordered_qty else 0
Nabin Hait62985362014-04-04 12:05:16 +0530128
Nabin Haiteea2b342013-10-11 18:31:33 +0530129def get_planned_qty(item_code, warehouse):
Anand Doshie9baaa62014-02-26 12:35:33 +0530130 planned_qty = frappe.db.sql("""
Nabin Hait62985362014-04-04 12:05:16 +0530131 select sum(ifnull(qty, 0) - ifnull(produced_qty, 0)) from `tabProduction Order`
Nabin Haiteea2b342013-10-11 18:31:33 +0530132 where production_item = %s and fg_warehouse = %s and status != "Stopped"
Nabin Hait1a60fd82013-10-14 14:27:08 +0530133 and docstatus=1 and ifnull(qty, 0) > ifnull(produced_qty, 0)""", (item_code, warehouse))
Nabin Haiteea2b342013-10-11 18:31:33 +0530134
135 return flt(planned_qty[0][0]) if planned_qty else 0
Nabin Hait62985362014-04-04 12:05:16 +0530136
137
Nabin Hait7f3f2a02014-09-01 18:16:05 +0530138def update_bin_qty(item_code, warehouse, qty_dict=None):
Rushabh Mehta1f847992013-12-12 19:12:19 +0530139 from erpnext.stock.utils import get_bin
Nabin Haiteea2b342013-10-11 18:31:33 +0530140 bin = get_bin(item_code, warehouse)
141 mismatch = False
142 for fld, val in qty_dict.items():
Anand Doshif78d1ae2014-03-28 13:55:00 +0530143 if flt(bin.get(fld)) != flt(val):
144 bin.set(fld, flt(val))
Nabin Haiteea2b342013-10-11 18:31:33 +0530145 mismatch = True
Nabin Hait62985362014-04-04 12:05:16 +0530146
Nabin Haiteea2b342013-10-11 18:31:33 +0530147 if mismatch:
Anand Doshif78d1ae2014-03-28 13:55:00 +0530148 bin.projected_qty = flt(bin.actual_qty) + flt(bin.ordered_qty) + \
149 flt(bin.indented_qty) + flt(bin.planned_qty) - flt(bin.reserved_qty)
Nabin Hait62985362014-04-04 12:05:16 +0530150
151 bin.save()
152
153def set_stock_balance_as_per_serial_no(item_code=None, posting_date=None, posting_time=None,
154 fiscal_year=None):
155 if not posting_date: posting_date = nowdate()
156 if not posting_time: posting_time = nowtime()
157 if not fiscal_year: fiscal_year = get_fiscal_year(posting_date)[0]
158
159 condition = " and item.name='%s'" % item_code.replace("'", "\'") if item_code else ""
160
161 bin = frappe.db.sql("""select bin.item_code, bin.warehouse, bin.actual_qty, item.stock_uom
162 from `tabBin` bin, tabItem item
Rushabh Mehta1e8025b2015-07-24 15:16:25 +0530163 where bin.item_code = item.name and item.has_serial_no = 1 %s""" % condition)
Nabin Hait62985362014-04-04 12:05:16 +0530164
165 for d in bin:
166 serial_nos = frappe.db.sql("""select count(name) from `tabSerial No`
Nabin Hait398c83a2015-10-22 15:11:44 +0530167 where item_code=%s and warehouse=%s and docstatus < 2""", (d[0], d[1]))
Nabin Hait62985362014-04-04 12:05:16 +0530168
169 if serial_nos and flt(serial_nos[0][0]) != flt(d[2]):
170 print d[0], d[1], d[2], serial_nos[0][0]
171
172 sle = frappe.db.sql("""select valuation_rate, company from `tabStock Ledger Entry`
173 where item_code = %s and warehouse = %s and ifnull(is_cancelled, 'No') = 'No'
174 order by posting_date desc limit 1""", (d[0], d[1]))
175
176 sle_dict = {
177 'doctype' : 'Stock Ledger Entry',
178 'item_code' : d[0],
179 'warehouse' : d[1],
180 'transaction_date' : nowdate(),
181 'posting_date' : posting_date,
182 'posting_time' : posting_time,
183 'voucher_type' : 'Stock Reconciliation (Manual)',
184 'voucher_no' : '',
185 'voucher_detail_no' : '',
186 'actual_qty' : flt(serial_nos[0][0]) - flt(d[2]),
187 'stock_uom' : d[3],
188 'incoming_rate' : sle and flt(serial_nos[0][0]) > flt(d[2]) and flt(sle[0][0]) or 0,
189 'company' : sle and cstr(sle[0][1]) or 0,
190 'fiscal_year' : fiscal_year,
191 'is_cancelled' : 'No',
192 'batch_no' : '',
193 'serial_no' : ''
194 }
195
196 sle_doc = frappe.get_doc(sle_dict)
Anand Doshi6dfd4302015-02-10 14:41:27 +0530197 sle_doc.flags.ignore_validate = True
198 sle_doc.flags.ignore_links = True
Nabin Hait62985362014-04-04 12:05:16 +0530199 sle_doc.insert()
200
201 args = sle_dict.copy()
202 args.update({
203 "sle_id": sle_doc.name,
204 "is_amended": 'No'
205 })
206
207 update_bin(args)
208 update_entries_after({
209 "item_code": d[0],
210 "warehouse": d[1],
211 "posting_date": posting_date,
212 "posting_time": posting_time
213 })
nabinhait5c384882014-07-14 11:43:00 +0530214
nabinhait7700c622014-07-14 14:21:21 +0530215def reset_serial_no_status_and_warehouse(serial_nos=None):
nabinhait5c384882014-07-14 11:43:00 +0530216 if not serial_nos:
Nabin Haitc865f222015-09-21 09:18:43 +0530217 serial_nos = frappe.db.sql_list("""select name from `tabSerial No` where docstatus = 0""")
nabinhait5c384882014-07-14 11:43:00 +0530218 for serial_no in serial_nos:
219 try:
220 sr = frappe.get_doc("Serial No", serial_no)
nabinhaitb0a8d002014-07-14 11:56:03 +0530221 last_sle = sr.get_last_sle()
222 if flt(last_sle.actual_qty) > 0:
223 sr.warehouse = last_sle.warehouse
Nabin Hait7f3f2a02014-09-01 18:16:05 +0530224
nabinhait5c384882014-07-14 11:43:00 +0530225 sr.via_stock_ledger = True
226 sr.save()
227 except:
228 pass
Nabin Hait7f3f2a02014-09-01 18:16:05 +0530229
Nabin Hait6c48ef72014-10-08 11:00:38 +0530230def repost_all_stock_vouchers():
Nabin Hait8a28ccf2014-10-14 11:41:44 +0530231 warehouses_with_account = frappe.db.sql_list("""select master_name from tabAccount
232 where ifnull(account_type, '') = 'Warehouse'""")
233
Nabin Hait6c48ef72014-10-08 11:00:38 +0530234 vouchers = frappe.db.sql("""select distinct voucher_type, voucher_no
Nabin Hait8a28ccf2014-10-14 11:41:44 +0530235 from `tabStock Ledger Entry` sle
236 where voucher_type != "Serial No" and sle.warehouse in (%s)
237 order by posting_date, posting_time, name""" %
238 ', '.join(['%s']*len(warehouses_with_account)), tuple(warehouses_with_account))
Nabin Hait6c48ef72014-10-08 11:00:38 +0530239
240 rejected = []
Nabin Hait4d742162014-10-09 19:25:03 +0530241 i = 0
Nabin Hait6c48ef72014-10-08 11:00:38 +0530242 for voucher_type, voucher_no in vouchers:
Nabin Hait4d742162014-10-09 19:25:03 +0530243 i+=1
Nabin Hait7c6f9902014-10-10 18:03:27 +0530244 print i, "/", len(vouchers)
Nabin Hait6c48ef72014-10-08 11:00:38 +0530245 try:
246 for dt in ["Stock Ledger Entry", "GL Entry"]:
247 frappe.db.sql("""delete from `tab%s` where voucher_type=%s and voucher_no=%s"""%
248 (dt, '%s', '%s'), (voucher_type, voucher_no))
249
250 doc = frappe.get_doc(voucher_type, voucher_no)
251 if voucher_type=="Stock Entry" and doc.purpose in ["Manufacture", "Repack"]:
Nabin Hait3c3a3ec2015-08-07 17:17:03 +0530252 doc.calculate_rate_and_amount(force=1)
Nabin Hait7c6f9902014-10-10 18:03:27 +0530253 elif voucher_type=="Purchase Receipt" and doc.is_subcontracted == "Yes":
254 doc.validate()
Nabin Haite96e83d2014-10-08 18:06:14 +0530255
Nabin Hait6c48ef72014-10-08 11:00:38 +0530256 doc.update_stock_ledger()
Nabin Hait4e7cc932015-01-12 10:55:48 +0530257 doc.make_gl_entries(repost_future_gle=False)
Nabin Haite96e83d2014-10-08 18:06:14 +0530258 frappe.db.commit()
259 except Exception, e:
260 print frappe.get_traceback()
Nabin Hait6c48ef72014-10-08 11:00:38 +0530261 rejected.append([voucher_type, voucher_no])
Nabin Haite96e83d2014-10-08 18:06:14 +0530262 frappe.db.rollback()
Nabin Hait6c48ef72014-10-08 11:00:38 +0530263
264 print rejected