blob: 52b94aee798b8a6b5b78467a517e903e261cdbca [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 Hait2348a5f2014-10-15 15:31:33 +053012def repost(only_actual=False, allow_negative_stock=False, allow_zero_rate=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 Hait2348a5f2014-10-15 15:31:33 +053027 repost_stock(d[0], d[1], allow_zero_rate, only_actual)
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 Hait2348a5f2014-10-15 15:31:33 +053036def repost_stock(item_code, warehouse, allow_zero_rate=False, only_actual=False):
Nabin Haitf1a07ff2014-10-15 12:23:35 +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 Hait7f3f2a02014-09-01 18:16:05 +053040 update_bin_qty(item_code, warehouse, {
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)
45 })
46
Nabin Haitf1a07ff2014-10-15 12:23:35 +053047def repost_actual_qty(item_code, warehouse, allow_zero_rate=False):
Nabin Hait5048c982013-10-23 12:14:32 +053048 try:
Nabin Haitf1a07ff2014-10-15 12:23:35 +053049 update_entries_after({ "item_code": item_code, "warehouse": warehouse }, allow_zero_rate)
Nabin Hait5048c982013-10-23 12:14:32 +053050 except:
51 pass
Nabin Hait62985362014-04-04 12:05:16 +053052
Nabin Haiteea2b342013-10-11 18:31:33 +053053def get_reserved_qty(item_code, warehouse):
Anand Doshie9baaa62014-02-26 12:35:33 +053054 reserved_qty = frappe.db.sql("""
Nabin Hait62985362014-04-04 12:05:16 +053055 select
Nabin Haiteea2b342013-10-11 18:31:33 +053056 sum((dnpi_qty / so_item_qty) * (so_item_qty - so_item_delivered_qty))
Nabin Hait62985362014-04-04 12:05:16 +053057 from
Nabin Haiteea2b342013-10-11 18:31:33 +053058 (
59 (select
60 qty as dnpi_qty,
61 (
62 select qty from `tabSales Order Item`
63 where name = dnpi.parent_detail_docname
64 ) as so_item_qty,
65 (
66 select ifnull(delivered_qty, 0) from `tabSales Order Item`
67 where name = dnpi.parent_detail_docname
Nabin Hait62985362014-04-04 12:05:16 +053068 ) as so_item_delivered_qty,
Nabin Haiteea2b342013-10-11 18:31:33 +053069 parent, name
Nabin Hait62985362014-04-04 12:05:16 +053070 from
Nabin Haiteea2b342013-10-11 18:31:33 +053071 (
72 select qty, parent_detail_docname, parent, name
Nabin Haitd1fd1e22013-10-18 12:29:11 +053073 from `tabPacked Item` dnpi_in
Nabin Haiteea2b342013-10-11 18:31:33 +053074 where item_code = %s and warehouse = %s
75 and parenttype="Sales Order"
Nabin Haitfc2dd442014-10-17 13:05:24 +053076 and item_code != parent_item
Nabin Haiteea2b342013-10-11 18:31:33 +053077 and exists (select * from `tabSales Order` so
78 where name = dnpi_in.parent and docstatus = 1 and status != 'Stopped')
79 ) dnpi)
80 union
81 (select qty as dnpi_qty, qty as so_item_qty,
82 ifnull(delivered_qty, 0) as so_item_delivered_qty, parent, name
83 from `tabSales Order Item` so_item
Nabin Hait06927a22014-08-25 14:08:54 +053084 where item_code = %s and warehouse = %s
Nabin Haiteea2b342013-10-11 18:31:33 +053085 and exists(select * from `tabSales Order` so
Nabin Hait62985362014-04-04 12:05:16 +053086 where so.name = so_item.parent and so.docstatus = 1
Nabin Haiteea2b342013-10-11 18:31:33 +053087 and so.status != 'Stopped'))
88 ) tab
Nabin Hait62985362014-04-04 12:05:16 +053089 where
Nabin Haiteea2b342013-10-11 18:31:33 +053090 so_item_qty >= so_item_delivered_qty
91 """, (item_code, warehouse, item_code, warehouse))
92
93 return flt(reserved_qty[0][0]) if reserved_qty else 0
Nabin Hait62985362014-04-04 12:05:16 +053094
Nabin Haiteea2b342013-10-11 18:31:33 +053095def get_indented_qty(item_code, warehouse):
Nabin Hait4acd4312014-11-04 15:32:31 +053096 indented_qty = frappe.db.sql("""select sum(mr_item.qty - ifnull(mr_item.ordered_qty, 0))
97 from `tabMaterial Request Item` mr_item, `tabMaterial Request` mr
98 where mr_item.item_code=%s and mr_item.warehouse=%s
99 and mr_item.qty > ifnull(mr_item.ordered_qty, 0) and mr_item.parent=mr.name
100 and mr.status!='Stopped' and mr.docstatus=1""", (item_code, warehouse))
Nabin Hait62985362014-04-04 12:05:16 +0530101
Nabin Haiteea2b342013-10-11 18:31:33 +0530102 return flt(indented_qty[0][0]) if indented_qty else 0
103
104def get_ordered_qty(item_code, warehouse):
Anand Doshie9baaa62014-02-26 12:35:33 +0530105 ordered_qty = frappe.db.sql("""
Nabin Hait1a60fd82013-10-14 14:27:08 +0530106 select sum((po_item.qty - ifnull(po_item.received_qty, 0))*po_item.conversion_factor)
Nabin Haiteea2b342013-10-11 18:31:33 +0530107 from `tabPurchase Order Item` po_item, `tabPurchase Order` po
Nabin Hait62985362014-04-04 12:05:16 +0530108 where po_item.item_code=%s and po_item.warehouse=%s
109 and po_item.qty > ifnull(po_item.received_qty, 0) and po_item.parent=po.name
Nabin Haiteea2b342013-10-11 18:31:33 +0530110 and po.status!='Stopped' and po.docstatus=1""", (item_code, warehouse))
Nabin Hait62985362014-04-04 12:05:16 +0530111
Nabin Haiteea2b342013-10-11 18:31:33 +0530112 return flt(ordered_qty[0][0]) if ordered_qty else 0
Nabin Hait62985362014-04-04 12:05:16 +0530113
Nabin Haiteea2b342013-10-11 18:31:33 +0530114def get_planned_qty(item_code, warehouse):
Anand Doshie9baaa62014-02-26 12:35:33 +0530115 planned_qty = frappe.db.sql("""
Nabin Hait62985362014-04-04 12:05:16 +0530116 select sum(ifnull(qty, 0) - ifnull(produced_qty, 0)) from `tabProduction Order`
Nabin Haiteea2b342013-10-11 18:31:33 +0530117 where production_item = %s and fg_warehouse = %s and status != "Stopped"
Nabin Hait1a60fd82013-10-14 14:27:08 +0530118 and docstatus=1 and ifnull(qty, 0) > ifnull(produced_qty, 0)""", (item_code, warehouse))
Nabin Haiteea2b342013-10-11 18:31:33 +0530119
120 return flt(planned_qty[0][0]) if planned_qty else 0
Nabin Hait62985362014-04-04 12:05:16 +0530121
122
Nabin Hait7f3f2a02014-09-01 18:16:05 +0530123def update_bin_qty(item_code, warehouse, qty_dict=None):
Rushabh Mehta1f847992013-12-12 19:12:19 +0530124 from erpnext.stock.utils import get_bin
Nabin Haiteea2b342013-10-11 18:31:33 +0530125 bin = get_bin(item_code, warehouse)
126 mismatch = False
127 for fld, val in qty_dict.items():
Anand Doshif78d1ae2014-03-28 13:55:00 +0530128 if flt(bin.get(fld)) != flt(val):
129 bin.set(fld, flt(val))
Nabin Haiteea2b342013-10-11 18:31:33 +0530130 mismatch = True
Nabin Hait62985362014-04-04 12:05:16 +0530131
Nabin Haiteea2b342013-10-11 18:31:33 +0530132 if mismatch:
Anand Doshif78d1ae2014-03-28 13:55:00 +0530133 bin.projected_qty = flt(bin.actual_qty) + flt(bin.ordered_qty) + \
134 flt(bin.indented_qty) + flt(bin.planned_qty) - flt(bin.reserved_qty)
Nabin Hait62985362014-04-04 12:05:16 +0530135
136 bin.save()
137
138def set_stock_balance_as_per_serial_no(item_code=None, posting_date=None, posting_time=None,
139 fiscal_year=None):
140 if not posting_date: posting_date = nowdate()
141 if not posting_time: posting_time = nowtime()
142 if not fiscal_year: fiscal_year = get_fiscal_year(posting_date)[0]
143
144 condition = " and item.name='%s'" % item_code.replace("'", "\'") if item_code else ""
145
146 bin = frappe.db.sql("""select bin.item_code, bin.warehouse, bin.actual_qty, item.stock_uom
147 from `tabBin` bin, tabItem item
Rushabh Mehta1e8025b2015-07-24 15:16:25 +0530148 where bin.item_code = item.name and item.has_serial_no = 1 %s""" % condition)
Nabin Hait62985362014-04-04 12:05:16 +0530149
150 for d in bin:
151 serial_nos = frappe.db.sql("""select count(name) from `tabSerial No`
152 where item_code=%s and warehouse=%s and status = 'Available' and docstatus < 2""", (d[0], d[1]))
153
154 if serial_nos and flt(serial_nos[0][0]) != flt(d[2]):
155 print d[0], d[1], d[2], serial_nos[0][0]
156
157 sle = frappe.db.sql("""select valuation_rate, company from `tabStock Ledger Entry`
158 where item_code = %s and warehouse = %s and ifnull(is_cancelled, 'No') = 'No'
159 order by posting_date desc limit 1""", (d[0], d[1]))
160
161 sle_dict = {
162 'doctype' : 'Stock Ledger Entry',
163 'item_code' : d[0],
164 'warehouse' : d[1],
165 'transaction_date' : nowdate(),
166 'posting_date' : posting_date,
167 'posting_time' : posting_time,
168 'voucher_type' : 'Stock Reconciliation (Manual)',
169 'voucher_no' : '',
170 'voucher_detail_no' : '',
171 'actual_qty' : flt(serial_nos[0][0]) - flt(d[2]),
172 'stock_uom' : d[3],
173 'incoming_rate' : sle and flt(serial_nos[0][0]) > flt(d[2]) and flt(sle[0][0]) or 0,
174 'company' : sle and cstr(sle[0][1]) or 0,
175 'fiscal_year' : fiscal_year,
176 'is_cancelled' : 'No',
177 'batch_no' : '',
178 'serial_no' : ''
179 }
180
181 sle_doc = frappe.get_doc(sle_dict)
Anand Doshi6dfd4302015-02-10 14:41:27 +0530182 sle_doc.flags.ignore_validate = True
183 sle_doc.flags.ignore_links = True
Nabin Hait62985362014-04-04 12:05:16 +0530184 sle_doc.insert()
185
186 args = sle_dict.copy()
187 args.update({
188 "sle_id": sle_doc.name,
189 "is_amended": 'No'
190 })
191
192 update_bin(args)
193 update_entries_after({
194 "item_code": d[0],
195 "warehouse": d[1],
196 "posting_date": posting_date,
197 "posting_time": posting_time
198 })
nabinhait5c384882014-07-14 11:43:00 +0530199
nabinhait7700c622014-07-14 14:21:21 +0530200def reset_serial_no_status_and_warehouse(serial_nos=None):
nabinhait5c384882014-07-14 11:43:00 +0530201 if not serial_nos:
202 serial_nos = frappe.db.sql_list("""select name from `tabSerial No` where status != 'Not in Use'
203 and docstatus = 0""")
204 for serial_no in serial_nos:
205 try:
206 sr = frappe.get_doc("Serial No", serial_no)
nabinhaitb0a8d002014-07-14 11:56:03 +0530207 last_sle = sr.get_last_sle()
208 if flt(last_sle.actual_qty) > 0:
209 sr.warehouse = last_sle.warehouse
Nabin Hait7f3f2a02014-09-01 18:16:05 +0530210
nabinhait5c384882014-07-14 11:43:00 +0530211 sr.via_stock_ledger = True
212 sr.save()
213 except:
214 pass
Nabin Hait7f3f2a02014-09-01 18:16:05 +0530215
nabinhait5c384882014-07-14 11:43:00 +0530216 frappe.db.sql("""update `tabSerial No` set warehouse='' where status in ('Delivered', 'Purchase Returned')""")
Nabin Hait7f3f2a02014-09-01 18:16:05 +0530217
Nabin Hait6c48ef72014-10-08 11:00:38 +0530218def repost_all_stock_vouchers():
Nabin Hait8a28ccf2014-10-14 11:41:44 +0530219 warehouses_with_account = frappe.db.sql_list("""select master_name from tabAccount
220 where ifnull(account_type, '') = 'Warehouse'""")
221
Nabin Hait6c48ef72014-10-08 11:00:38 +0530222 vouchers = frappe.db.sql("""select distinct voucher_type, voucher_no
Nabin Hait8a28ccf2014-10-14 11:41:44 +0530223 from `tabStock Ledger Entry` sle
224 where voucher_type != "Serial No" and sle.warehouse in (%s)
225 order by posting_date, posting_time, name""" %
226 ', '.join(['%s']*len(warehouses_with_account)), tuple(warehouses_with_account))
Nabin Hait6c48ef72014-10-08 11:00:38 +0530227
228 rejected = []
Nabin Hait4d742162014-10-09 19:25:03 +0530229 i = 0
Nabin Hait6c48ef72014-10-08 11:00:38 +0530230 for voucher_type, voucher_no in vouchers:
Nabin Hait4d742162014-10-09 19:25:03 +0530231 i+=1
Nabin Hait7c6f9902014-10-10 18:03:27 +0530232 print i, "/", len(vouchers)
Nabin Hait6c48ef72014-10-08 11:00:38 +0530233 try:
234 for dt in ["Stock Ledger Entry", "GL Entry"]:
235 frappe.db.sql("""delete from `tab%s` where voucher_type=%s and voucher_no=%s"""%
236 (dt, '%s', '%s'), (voucher_type, voucher_no))
237
238 doc = frappe.get_doc(voucher_type, voucher_no)
239 if voucher_type=="Stock Entry" and doc.purpose in ["Manufacture", "Repack"]:
240 doc.get_stock_and_rate(force=1)
Nabin Hait7c6f9902014-10-10 18:03:27 +0530241 elif voucher_type=="Purchase Receipt" and doc.is_subcontracted == "Yes":
242 doc.validate()
Nabin Haite96e83d2014-10-08 18:06:14 +0530243
Nabin Hait6c48ef72014-10-08 11:00:38 +0530244 doc.update_stock_ledger()
Nabin Hait4e7cc932015-01-12 10:55:48 +0530245 doc.make_gl_entries(repost_future_gle=False)
Nabin Haite96e83d2014-10-08 18:06:14 +0530246 frappe.db.commit()
247 except Exception, e:
248 print frappe.get_traceback()
Nabin Hait6c48ef72014-10-08 11:00:38 +0530249 rejected.append([voucher_type, voucher_no])
Nabin Haite96e83d2014-10-08 18:06:14 +0530250 frappe.db.rollback()
Nabin Hait6c48ef72014-10-08 11:00:38 +0530251
252 print rejected