blob: 4c145487d8fca6cfead047a8821f1a7fb9a4bd60 [file] [log] [blame]
Rushabh Mehtaad45e312013-11-20 12:59:58 +05301# Copyright (c) 2013, Web Notes 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 Haitca471f42013-11-20 13:14:12 +053012def repost(allow_negative_stock=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:
Anand Doshie9baaa62014-02-26 12:35:33 +053019 frappe.db.set_default("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 Hait7f3f2a02014-09-01 18:16:05 +053025 repost_stock(d[0], d[1])
Nabin Hait62985362014-04-04 12:05:16 +053026
Nabin Haitca471f42013-11-20 13:14:12 +053027 if allow_negative_stock:
Nabin Hait62985362014-04-04 12:05:16 +053028 frappe.db.set_default("allow_negative_stock",
Anand Doshie9baaa62014-02-26 12:35:33 +053029 frappe.db.get_value("Stock Settings", None, "allow_negative_stock"))
30 frappe.db.auto_commit_on_many_writes = 0
Nabin Haiteea2b342013-10-11 18:31:33 +053031
32def repost_stock(item_code, warehouse):
33 repost_actual_qty(item_code, warehouse)
Nabin Hait62985362014-04-04 12:05:16 +053034
Nabin Haiteea2b342013-10-11 18:31:33 +053035 if item_code and warehouse:
Nabin Hait7f3f2a02014-09-01 18:16:05 +053036 update_bin_qty(item_code, warehouse, {
Nabin Haiteea2b342013-10-11 18:31:33 +053037 "reserved_qty": get_reserved_qty(item_code, warehouse),
38 "indented_qty": get_indented_qty(item_code, warehouse),
39 "ordered_qty": get_ordered_qty(item_code, warehouse),
40 "planned_qty": get_planned_qty(item_code, warehouse)
41 })
42
43def repost_actual_qty(item_code, warehouse):
Nabin Hait5048c982013-10-23 12:14:32 +053044 try:
45 update_entries_after({ "item_code": item_code, "warehouse": warehouse })
46 except:
47 pass
Nabin Hait62985362014-04-04 12:05:16 +053048
Nabin Haiteea2b342013-10-11 18:31:33 +053049def get_reserved_qty(item_code, warehouse):
Anand Doshie9baaa62014-02-26 12:35:33 +053050 reserved_qty = frappe.db.sql("""
Nabin Hait62985362014-04-04 12:05:16 +053051 select
Nabin Haiteea2b342013-10-11 18:31:33 +053052 sum((dnpi_qty / so_item_qty) * (so_item_qty - so_item_delivered_qty))
Nabin Hait62985362014-04-04 12:05:16 +053053 from
Nabin Haiteea2b342013-10-11 18:31:33 +053054 (
55 (select
56 qty as dnpi_qty,
57 (
58 select qty from `tabSales Order Item`
59 where name = dnpi.parent_detail_docname
60 ) as so_item_qty,
61 (
62 select ifnull(delivered_qty, 0) from `tabSales Order Item`
63 where name = dnpi.parent_detail_docname
Nabin Hait62985362014-04-04 12:05:16 +053064 ) as so_item_delivered_qty,
Nabin Haiteea2b342013-10-11 18:31:33 +053065 parent, name
Nabin Hait62985362014-04-04 12:05:16 +053066 from
Nabin Haiteea2b342013-10-11 18:31:33 +053067 (
68 select qty, parent_detail_docname, parent, name
Nabin Haitd1fd1e22013-10-18 12:29:11 +053069 from `tabPacked Item` dnpi_in
Nabin Haiteea2b342013-10-11 18:31:33 +053070 where item_code = %s and warehouse = %s
71 and parenttype="Sales Order"
72 and item_code != parent_item
73 and exists (select * from `tabSales Order` so
74 where name = dnpi_in.parent and docstatus = 1 and status != 'Stopped')
75 ) dnpi)
76 union
77 (select qty as dnpi_qty, qty as so_item_qty,
78 ifnull(delivered_qty, 0) as so_item_delivered_qty, parent, name
79 from `tabSales Order Item` so_item
Nabin Hait06927a22014-08-25 14:08:54 +053080 where item_code = %s and warehouse = %s
Nabin Haiteea2b342013-10-11 18:31:33 +053081 and exists(select * from `tabSales Order` so
Nabin Hait62985362014-04-04 12:05:16 +053082 where so.name = so_item.parent and so.docstatus = 1
Nabin Haiteea2b342013-10-11 18:31:33 +053083 and so.status != 'Stopped'))
84 ) tab
Nabin Hait62985362014-04-04 12:05:16 +053085 where
Nabin Haiteea2b342013-10-11 18:31:33 +053086 so_item_qty >= so_item_delivered_qty
87 """, (item_code, warehouse, item_code, warehouse))
88
89 return flt(reserved_qty[0][0]) if reserved_qty else 0
Nabin Hait62985362014-04-04 12:05:16 +053090
Nabin Haiteea2b342013-10-11 18:31:33 +053091def get_indented_qty(item_code, warehouse):
Anand Doshie9baaa62014-02-26 12:35:33 +053092 indented_qty = frappe.db.sql("""select sum(pr_item.qty - ifnull(pr_item.ordered_qty, 0))
Nabin Haiteea2b342013-10-11 18:31:33 +053093 from `tabMaterial Request Item` pr_item, `tabMaterial Request` pr
Nabin Hait62985362014-04-04 12:05:16 +053094 where pr_item.item_code=%s and pr_item.warehouse=%s
95 and pr_item.qty > ifnull(pr_item.ordered_qty, 0) and pr_item.parent=pr.name
Nabin Haiteea2b342013-10-11 18:31:33 +053096 and pr.status!='Stopped' and pr.docstatus=1""", (item_code, warehouse))
Nabin Hait62985362014-04-04 12:05:16 +053097
Nabin Haiteea2b342013-10-11 18:31:33 +053098 return flt(indented_qty[0][0]) if indented_qty else 0
99
100def get_ordered_qty(item_code, warehouse):
Anand Doshie9baaa62014-02-26 12:35:33 +0530101 ordered_qty = frappe.db.sql("""
Nabin Hait1a60fd82013-10-14 14:27:08 +0530102 select sum((po_item.qty - ifnull(po_item.received_qty, 0))*po_item.conversion_factor)
Nabin Haiteea2b342013-10-11 18:31:33 +0530103 from `tabPurchase Order Item` po_item, `tabPurchase Order` po
Nabin Hait62985362014-04-04 12:05:16 +0530104 where po_item.item_code=%s and po_item.warehouse=%s
105 and po_item.qty > ifnull(po_item.received_qty, 0) and po_item.parent=po.name
Nabin Haiteea2b342013-10-11 18:31:33 +0530106 and po.status!='Stopped' and po.docstatus=1""", (item_code, warehouse))
Nabin Hait62985362014-04-04 12:05:16 +0530107
Nabin Haiteea2b342013-10-11 18:31:33 +0530108 return flt(ordered_qty[0][0]) if ordered_qty else 0
Nabin Hait62985362014-04-04 12:05:16 +0530109
Nabin Haiteea2b342013-10-11 18:31:33 +0530110def get_planned_qty(item_code, warehouse):
Anand Doshie9baaa62014-02-26 12:35:33 +0530111 planned_qty = frappe.db.sql("""
Nabin Hait62985362014-04-04 12:05:16 +0530112 select sum(ifnull(qty, 0) - ifnull(produced_qty, 0)) from `tabProduction Order`
Nabin Haiteea2b342013-10-11 18:31:33 +0530113 where production_item = %s and fg_warehouse = %s and status != "Stopped"
Nabin Hait1a60fd82013-10-14 14:27:08 +0530114 and docstatus=1 and ifnull(qty, 0) > ifnull(produced_qty, 0)""", (item_code, warehouse))
Nabin Haiteea2b342013-10-11 18:31:33 +0530115
116 return flt(planned_qty[0][0]) if planned_qty else 0
Nabin Hait62985362014-04-04 12:05:16 +0530117
118
Nabin Hait7f3f2a02014-09-01 18:16:05 +0530119def update_bin_qty(item_code, warehouse, qty_dict=None):
Rushabh Mehta1f847992013-12-12 19:12:19 +0530120 from erpnext.stock.utils import get_bin
Nabin Haiteea2b342013-10-11 18:31:33 +0530121 bin = get_bin(item_code, warehouse)
122 mismatch = False
123 for fld, val in qty_dict.items():
Anand Doshif78d1ae2014-03-28 13:55:00 +0530124 if flt(bin.get(fld)) != flt(val):
125 bin.set(fld, flt(val))
Nabin Haiteea2b342013-10-11 18:31:33 +0530126 mismatch = True
Nabin Hait62985362014-04-04 12:05:16 +0530127
Nabin Haiteea2b342013-10-11 18:31:33 +0530128 if mismatch:
Anand Doshif78d1ae2014-03-28 13:55:00 +0530129 bin.projected_qty = flt(bin.actual_qty) + flt(bin.ordered_qty) + \
130 flt(bin.indented_qty) + flt(bin.planned_qty) - flt(bin.reserved_qty)
Nabin Hait62985362014-04-04 12:05:16 +0530131
132 bin.save()
133
134def set_stock_balance_as_per_serial_no(item_code=None, posting_date=None, posting_time=None,
135 fiscal_year=None):
136 if not posting_date: posting_date = nowdate()
137 if not posting_time: posting_time = nowtime()
138 if not fiscal_year: fiscal_year = get_fiscal_year(posting_date)[0]
139
140 condition = " and item.name='%s'" % item_code.replace("'", "\'") if item_code else ""
141
142 bin = frappe.db.sql("""select bin.item_code, bin.warehouse, bin.actual_qty, item.stock_uom
143 from `tabBin` bin, tabItem item
144 where bin.item_code = item.name and item.has_serial_no = 'Yes' %s""" % condition)
145
146 for d in bin:
147 serial_nos = frappe.db.sql("""select count(name) from `tabSerial No`
148 where item_code=%s and warehouse=%s and status = 'Available' and docstatus < 2""", (d[0], d[1]))
149
150 if serial_nos and flt(serial_nos[0][0]) != flt(d[2]):
151 print d[0], d[1], d[2], serial_nos[0][0]
152
153 sle = frappe.db.sql("""select valuation_rate, company from `tabStock Ledger Entry`
154 where item_code = %s and warehouse = %s and ifnull(is_cancelled, 'No') = 'No'
155 order by posting_date desc limit 1""", (d[0], d[1]))
156
157 sle_dict = {
158 'doctype' : 'Stock Ledger Entry',
159 'item_code' : d[0],
160 'warehouse' : d[1],
161 'transaction_date' : nowdate(),
162 'posting_date' : posting_date,
163 'posting_time' : posting_time,
164 'voucher_type' : 'Stock Reconciliation (Manual)',
165 'voucher_no' : '',
166 'voucher_detail_no' : '',
167 'actual_qty' : flt(serial_nos[0][0]) - flt(d[2]),
168 'stock_uom' : d[3],
169 'incoming_rate' : sle and flt(serial_nos[0][0]) > flt(d[2]) and flt(sle[0][0]) or 0,
170 'company' : sle and cstr(sle[0][1]) or 0,
171 'fiscal_year' : fiscal_year,
172 'is_cancelled' : 'No',
173 'batch_no' : '',
174 'serial_no' : ''
175 }
176
177 sle_doc = frappe.get_doc(sle_dict)
178 sle_doc.insert()
179
180 args = sle_dict.copy()
181 args.update({
182 "sle_id": sle_doc.name,
183 "is_amended": 'No'
184 })
185
186 update_bin(args)
187 update_entries_after({
188 "item_code": d[0],
189 "warehouse": d[1],
190 "posting_date": posting_date,
191 "posting_time": posting_time
192 })
nabinhait5c384882014-07-14 11:43:00 +0530193
nabinhait7700c622014-07-14 14:21:21 +0530194def reset_serial_no_status_and_warehouse(serial_nos=None):
nabinhait5c384882014-07-14 11:43:00 +0530195 if not serial_nos:
196 serial_nos = frappe.db.sql_list("""select name from `tabSerial No` where status != 'Not in Use'
197 and docstatus = 0""")
198 for serial_no in serial_nos:
199 try:
200 sr = frappe.get_doc("Serial No", serial_no)
nabinhaitb0a8d002014-07-14 11:56:03 +0530201 last_sle = sr.get_last_sle()
202 if flt(last_sle.actual_qty) > 0:
203 sr.warehouse = last_sle.warehouse
Nabin Hait7f3f2a02014-09-01 18:16:05 +0530204
nabinhait5c384882014-07-14 11:43:00 +0530205 sr.via_stock_ledger = True
206 sr.save()
207 except:
208 pass
Nabin Hait7f3f2a02014-09-01 18:16:05 +0530209
nabinhait5c384882014-07-14 11:43:00 +0530210 frappe.db.sql("""update `tabSerial No` set warehouse='' where status in ('Delivered', 'Purchase Returned')""")
Nabin Hait7f3f2a02014-09-01 18:16:05 +0530211