2015-03-03 09:25:30 +00:00
|
|
|
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
2013-10-11 13:01:33 +00:00
|
|
|
# License: GNU General Public License v3. See license.txt
|
|
|
|
|
2017-08-28 12:47:36 +00:00
|
|
|
from __future__ import print_function, unicode_literals
|
2014-02-14 10:17:51 +00:00
|
|
|
import frappe
|
2013-10-11 13:01:33 +00:00
|
|
|
|
2014-04-04 06:35:16 +00:00
|
|
|
from frappe.utils import flt, cstr, nowdate, nowtime
|
|
|
|
from erpnext.stock.utils import update_bin
|
|
|
|
from erpnext.stock.stock_ledger import update_entries_after
|
2013-10-11 13:01:33 +00:00
|
|
|
|
2015-10-12 11:16:29 +00:00
|
|
|
def repost(only_actual=False, allow_negative_stock=False, allow_zero_rate=False, only_bin=False):
|
2013-10-11 13:01:33 +00:00
|
|
|
"""
|
|
|
|
Repost everything!
|
|
|
|
"""
|
2014-02-26 07:05:33 +00:00
|
|
|
frappe.db.auto_commit_on_many_writes = 1
|
2014-04-04 06:35:16 +00:00
|
|
|
|
2013-11-20 07:44:12 +00:00
|
|
|
if allow_negative_stock:
|
2014-11-26 10:05:08 +00:00
|
|
|
existing_allow_negative_stock = frappe.db.get_value("Stock Settings", None, "allow_negative_stock")
|
|
|
|
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
|
2014-04-04 06:35:16 +00:00
|
|
|
|
|
|
|
for d in frappe.db.sql("""select distinct item_code, warehouse from
|
2013-10-23 06:20:09 +00:00
|
|
|
(select item_code, warehouse from tabBin
|
|
|
|
union
|
2013-10-23 06:32:08 +00:00
|
|
|
select item_code, warehouse from `tabStock Ledger Entry`) a"""):
|
2014-10-14 06:11:44 +00:00
|
|
|
try:
|
2015-10-12 11:16:29 +00:00
|
|
|
repost_stock(d[0], d[1], allow_zero_rate, only_actual, only_bin)
|
2014-10-14 06:11:44 +00:00
|
|
|
frappe.db.commit()
|
|
|
|
except:
|
|
|
|
frappe.db.rollback()
|
2014-04-04 06:35:16 +00:00
|
|
|
|
2013-11-20 07:44:12 +00:00
|
|
|
if allow_negative_stock:
|
2014-11-26 10:05:08 +00:00
|
|
|
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", existing_allow_negative_stock)
|
2014-02-26 07:05:33 +00:00
|
|
|
frappe.db.auto_commit_on_many_writes = 0
|
2013-10-11 13:01:33 +00:00
|
|
|
|
2015-10-12 11:16:29 +00:00
|
|
|
def repost_stock(item_code, warehouse, allow_zero_rate=False, only_actual=False, only_bin=False):
|
|
|
|
if not only_bin:
|
2015-10-14 12:07:28 +00:00
|
|
|
repost_actual_qty(item_code, warehouse, allow_zero_rate)
|
2014-04-04 06:35:16 +00:00
|
|
|
|
2014-10-15 10:01:33 +00:00
|
|
|
if item_code and warehouse and not only_actual:
|
2015-10-12 11:16:29 +00:00
|
|
|
qty_dict = {
|
2013-10-11 13:01:33 +00:00
|
|
|
"reserved_qty": get_reserved_qty(item_code, warehouse),
|
|
|
|
"indented_qty": get_indented_qty(item_code, warehouse),
|
|
|
|
"ordered_qty": get_ordered_qty(item_code, warehouse),
|
|
|
|
"planned_qty": get_planned_qty(item_code, warehouse)
|
2015-10-12 11:16:29 +00:00
|
|
|
}
|
|
|
|
if only_bin:
|
|
|
|
qty_dict.update({
|
|
|
|
"actual_qty": get_balance_qty_from_sle(item_code, warehouse)
|
|
|
|
})
|
2015-10-14 12:07:28 +00:00
|
|
|
|
2015-10-12 11:16:29 +00:00
|
|
|
update_bin_qty(item_code, warehouse, qty_dict)
|
2013-10-11 13:01:33 +00:00
|
|
|
|
2014-10-15 06:53:35 +00:00
|
|
|
def repost_actual_qty(item_code, warehouse, allow_zero_rate=False):
|
2013-10-23 06:44:32 +00:00
|
|
|
try:
|
2014-10-15 06:53:35 +00:00
|
|
|
update_entries_after({ "item_code": item_code, "warehouse": warehouse }, allow_zero_rate)
|
2013-10-23 06:44:32 +00:00
|
|
|
except:
|
|
|
|
pass
|
2015-10-14 12:07:28 +00:00
|
|
|
|
2015-10-12 11:16:29 +00:00
|
|
|
def get_balance_qty_from_sle(item_code, warehouse):
|
|
|
|
balance_qty = frappe.db.sql("""select qty_after_transaction from `tabStock Ledger Entry`
|
|
|
|
where item_code=%s and warehouse=%s and is_cancelled='No'
|
|
|
|
order by posting_date desc, posting_time desc, name desc
|
|
|
|
limit 1""", (item_code, warehouse))
|
2015-10-14 12:07:28 +00:00
|
|
|
|
2015-10-12 11:16:29 +00:00
|
|
|
return flt(balance_qty[0][0]) if balance_qty else 0.0
|
2014-04-04 06:35:16 +00:00
|
|
|
|
2013-10-11 13:01:33 +00:00
|
|
|
def get_reserved_qty(item_code, warehouse):
|
2014-02-26 07:05:33 +00:00
|
|
|
reserved_qty = frappe.db.sql("""
|
2014-04-04 06:35:16 +00:00
|
|
|
select
|
2017-03-29 11:59:20 +00:00
|
|
|
sum(dnpi_qty * ((so_item_qty - so_item_delivered_qty) / so_item_qty))
|
2014-04-04 06:35:16 +00:00
|
|
|
from
|
2013-10-11 13:01:33 +00:00
|
|
|
(
|
|
|
|
(select
|
|
|
|
qty as dnpi_qty,
|
|
|
|
(
|
2017-03-29 11:59:20 +00:00
|
|
|
select qty from `tabSales Order Item`
|
2013-10-11 13:01:33 +00:00
|
|
|
where name = dnpi.parent_detail_docname
|
2015-11-18 11:33:33 +00:00
|
|
|
and (delivered_by_supplier is null or delivered_by_supplier = 0)
|
2013-10-11 13:01:33 +00:00
|
|
|
) as so_item_qty,
|
|
|
|
(
|
2015-11-16 13:35:46 +00:00
|
|
|
select delivered_qty from `tabSales Order Item`
|
|
|
|
where name = dnpi.parent_detail_docname
|
|
|
|
and delivered_by_supplier = 0
|
2014-04-04 06:35:16 +00:00
|
|
|
) as so_item_delivered_qty,
|
2013-10-11 13:01:33 +00:00
|
|
|
parent, name
|
2014-04-04 06:35:16 +00:00
|
|
|
from
|
2013-10-11 13:01:33 +00:00
|
|
|
(
|
|
|
|
select qty, parent_detail_docname, parent, name
|
2013-10-18 06:59:11 +00:00
|
|
|
from `tabPacked Item` dnpi_in
|
2013-10-11 13:01:33 +00:00
|
|
|
where item_code = %s and warehouse = %s
|
|
|
|
and parenttype="Sales Order"
|
2014-10-17 07:35:24 +00:00
|
|
|
and item_code != parent_item
|
2013-10-11 13:01:33 +00:00
|
|
|
and exists (select * from `tabSales Order` so
|
2016-02-23 13:34:29 +00:00
|
|
|
where name = dnpi_in.parent and docstatus = 1 and status != 'Closed')
|
2013-10-11 13:01:33 +00:00
|
|
|
) dnpi)
|
|
|
|
union
|
2017-03-29 11:59:20 +00:00
|
|
|
(select stock_qty as dnpi_qty, qty as so_item_qty,
|
2015-11-16 13:35:46 +00:00
|
|
|
delivered_qty as so_item_delivered_qty, parent, name
|
2013-10-11 13:01:33 +00:00
|
|
|
from `tabSales Order Item` so_item
|
2015-11-16 13:35:46 +00:00
|
|
|
where item_code = %s and warehouse = %s
|
2015-11-18 11:33:33 +00:00
|
|
|
and (so_item.delivered_by_supplier is null or so_item.delivered_by_supplier = 0)
|
2013-10-11 13:01:33 +00:00
|
|
|
and exists(select * from `tabSales Order` so
|
2014-04-04 06:35:16 +00:00
|
|
|
where so.name = so_item.parent and so.docstatus = 1
|
2016-02-23 13:34:29 +00:00
|
|
|
and so.status != 'Closed'))
|
2013-10-11 13:01:33 +00:00
|
|
|
) tab
|
2014-04-04 06:35:16 +00:00
|
|
|
where
|
2013-10-11 13:01:33 +00:00
|
|
|
so_item_qty >= so_item_delivered_qty
|
|
|
|
""", (item_code, warehouse, item_code, warehouse))
|
|
|
|
|
|
|
|
return flt(reserved_qty[0][0]) if reserved_qty else 0
|
2014-04-04 06:35:16 +00:00
|
|
|
|
2013-10-11 13:01:33 +00:00
|
|
|
def get_indented_qty(item_code, warehouse):
|
2015-11-16 13:35:46 +00:00
|
|
|
indented_qty = frappe.db.sql("""select sum(mr_item.qty - mr_item.ordered_qty)
|
2014-11-04 10:02:31 +00:00
|
|
|
from `tabMaterial Request Item` mr_item, `tabMaterial Request` mr
|
|
|
|
where mr_item.item_code=%s and mr_item.warehouse=%s
|
2015-11-16 13:35:46 +00:00
|
|
|
and mr_item.qty > mr_item.ordered_qty and mr_item.parent=mr.name
|
2014-11-04 10:02:31 +00:00
|
|
|
and mr.status!='Stopped' and mr.docstatus=1""", (item_code, warehouse))
|
2014-04-04 06:35:16 +00:00
|
|
|
|
2013-10-11 13:01:33 +00:00
|
|
|
return flt(indented_qty[0][0]) if indented_qty else 0
|
|
|
|
|
|
|
|
def get_ordered_qty(item_code, warehouse):
|
2014-02-26 07:05:33 +00:00
|
|
|
ordered_qty = frappe.db.sql("""
|
2015-11-16 13:35:46 +00:00
|
|
|
select sum((po_item.qty - po_item.received_qty)*po_item.conversion_factor)
|
2013-10-11 13:01:33 +00:00
|
|
|
from `tabPurchase Order Item` po_item, `tabPurchase Order` po
|
2014-04-04 06:35:16 +00:00
|
|
|
where po_item.item_code=%s and po_item.warehouse=%s
|
2015-11-16 13:35:46 +00:00
|
|
|
and po_item.qty > po_item.received_qty and po_item.parent=po.name
|
2016-02-22 10:54:23 +00:00
|
|
|
and po.status not in ('Closed', 'Delivered') and po.docstatus=1
|
2015-11-16 13:35:46 +00:00
|
|
|
and po_item.delivered_by_supplier = 0""", (item_code, warehouse))
|
2014-04-04 06:35:16 +00:00
|
|
|
|
2013-10-11 13:01:33 +00:00
|
|
|
return flt(ordered_qty[0][0]) if ordered_qty else 0
|
2014-04-04 06:35:16 +00:00
|
|
|
|
2013-10-11 13:01:33 +00:00
|
|
|
def get_planned_qty(item_code, warehouse):
|
2014-02-26 07:05:33 +00:00
|
|
|
planned_qty = frappe.db.sql("""
|
2015-11-16 13:35:46 +00:00
|
|
|
select sum(qty - produced_qty) from `tabProduction Order`
|
2017-07-05 08:25:41 +00:00
|
|
|
where production_item = %s and fg_warehouse = %s and status not in ("Stopped", "Completed")
|
2015-11-16 13:35:46 +00:00
|
|
|
and docstatus=1 and qty > produced_qty""", (item_code, warehouse))
|
2013-10-11 13:01:33 +00:00
|
|
|
|
|
|
|
return flt(planned_qty[0][0]) if planned_qty else 0
|
2014-04-04 06:35:16 +00:00
|
|
|
|
|
|
|
|
2014-09-01 12:46:05 +00:00
|
|
|
def update_bin_qty(item_code, warehouse, qty_dict=None):
|
2013-12-12 13:42:19 +00:00
|
|
|
from erpnext.stock.utils import get_bin
|
2013-10-11 13:01:33 +00:00
|
|
|
bin = get_bin(item_code, warehouse)
|
|
|
|
mismatch = False
|
|
|
|
for fld, val in qty_dict.items():
|
2014-03-28 08:25:00 +00:00
|
|
|
if flt(bin.get(fld)) != flt(val):
|
|
|
|
bin.set(fld, flt(val))
|
2013-10-11 13:01:33 +00:00
|
|
|
mismatch = True
|
2014-04-04 06:35:16 +00:00
|
|
|
|
2013-10-11 13:01:33 +00:00
|
|
|
if mismatch:
|
2016-04-18 13:57:36 +00:00
|
|
|
bin.projected_qty = (flt(bin.actual_qty) + flt(bin.ordered_qty) +
|
2014-03-28 08:25:00 +00:00
|
|
|
flt(bin.indented_qty) + flt(bin.planned_qty) - flt(bin.reserved_qty)
|
2018-03-12 08:42:12 +00:00
|
|
|
- flt(bin.reserved_qty_for_production)) - flt(bin.reserved_qty_for_sub_contract)
|
2014-04-04 06:35:16 +00:00
|
|
|
|
|
|
|
bin.save()
|
|
|
|
|
|
|
|
def set_stock_balance_as_per_serial_no(item_code=None, posting_date=None, posting_time=None,
|
|
|
|
fiscal_year=None):
|
|
|
|
if not posting_date: posting_date = nowdate()
|
|
|
|
if not posting_time: posting_time = nowtime()
|
|
|
|
|
|
|
|
condition = " and item.name='%s'" % item_code.replace("'", "\'") if item_code else ""
|
|
|
|
|
|
|
|
bin = frappe.db.sql("""select bin.item_code, bin.warehouse, bin.actual_qty, item.stock_uom
|
|
|
|
from `tabBin` bin, tabItem item
|
2015-07-24 09:46:25 +00:00
|
|
|
where bin.item_code = item.name and item.has_serial_no = 1 %s""" % condition)
|
2014-04-04 06:35:16 +00:00
|
|
|
|
|
|
|
for d in bin:
|
|
|
|
serial_nos = frappe.db.sql("""select count(name) from `tabSerial No`
|
2015-10-22 09:41:44 +00:00
|
|
|
where item_code=%s and warehouse=%s and docstatus < 2""", (d[0], d[1]))
|
2014-04-04 06:35:16 +00:00
|
|
|
|
|
|
|
if serial_nos and flt(serial_nos[0][0]) != flt(d[2]):
|
2017-08-28 12:47:36 +00:00
|
|
|
print(d[0], d[1], d[2], serial_nos[0][0])
|
2014-04-04 06:35:16 +00:00
|
|
|
|
|
|
|
sle = frappe.db.sql("""select valuation_rate, company from `tabStock Ledger Entry`
|
|
|
|
where item_code = %s and warehouse = %s and ifnull(is_cancelled, 'No') = 'No'
|
|
|
|
order by posting_date desc limit 1""", (d[0], d[1]))
|
|
|
|
|
|
|
|
sle_dict = {
|
|
|
|
'doctype' : 'Stock Ledger Entry',
|
|
|
|
'item_code' : d[0],
|
|
|
|
'warehouse' : d[1],
|
|
|
|
'transaction_date' : nowdate(),
|
|
|
|
'posting_date' : posting_date,
|
|
|
|
'posting_time' : posting_time,
|
|
|
|
'voucher_type' : 'Stock Reconciliation (Manual)',
|
|
|
|
'voucher_no' : '',
|
|
|
|
'voucher_detail_no' : '',
|
|
|
|
'actual_qty' : flt(serial_nos[0][0]) - flt(d[2]),
|
|
|
|
'stock_uom' : d[3],
|
|
|
|
'incoming_rate' : sle and flt(serial_nos[0][0]) > flt(d[2]) and flt(sle[0][0]) or 0,
|
|
|
|
'company' : sle and cstr(sle[0][1]) or 0,
|
|
|
|
'is_cancelled' : 'No',
|
|
|
|
'batch_no' : '',
|
|
|
|
'serial_no' : ''
|
|
|
|
}
|
|
|
|
|
|
|
|
sle_doc = frappe.get_doc(sle_dict)
|
2015-02-10 09:11:27 +00:00
|
|
|
sle_doc.flags.ignore_validate = True
|
|
|
|
sle_doc.flags.ignore_links = True
|
2014-04-04 06:35:16 +00:00
|
|
|
sle_doc.insert()
|
|
|
|
|
|
|
|
args = sle_dict.copy()
|
|
|
|
args.update({
|
|
|
|
"sle_id": sle_doc.name,
|
|
|
|
"is_amended": 'No'
|
|
|
|
})
|
|
|
|
|
|
|
|
update_bin(args)
|
|
|
|
update_entries_after({
|
|
|
|
"item_code": d[0],
|
|
|
|
"warehouse": d[1],
|
|
|
|
"posting_date": posting_date,
|
|
|
|
"posting_time": posting_time
|
|
|
|
})
|
2014-07-14 06:13:00 +00:00
|
|
|
|
2014-07-14 08:51:21 +00:00
|
|
|
def reset_serial_no_status_and_warehouse(serial_nos=None):
|
2014-07-14 06:13:00 +00:00
|
|
|
if not serial_nos:
|
2015-09-21 03:48:43 +00:00
|
|
|
serial_nos = frappe.db.sql_list("""select name from `tabSerial No` where docstatus = 0""")
|
2014-07-14 06:13:00 +00:00
|
|
|
for serial_no in serial_nos:
|
|
|
|
try:
|
|
|
|
sr = frappe.get_doc("Serial No", serial_no)
|
2014-07-14 06:26:03 +00:00
|
|
|
last_sle = sr.get_last_sle()
|
|
|
|
if flt(last_sle.actual_qty) > 0:
|
|
|
|
sr.warehouse = last_sle.warehouse
|
2014-09-01 12:46:05 +00:00
|
|
|
|
2014-07-14 06:13:00 +00:00
|
|
|
sr.via_stock_ledger = True
|
|
|
|
sr.save()
|
|
|
|
except:
|
|
|
|
pass
|
2014-09-01 12:46:05 +00:00
|
|
|
|
2014-10-08 05:30:38 +00:00
|
|
|
def repost_all_stock_vouchers():
|
2016-09-28 12:47:52 +00:00
|
|
|
warehouses_with_account = frappe.db.sql_list("""select warehouse from tabAccount
|
2016-06-25 08:48:28 +00:00
|
|
|
where ifnull(account_type, '') = 'Stock' and (warehouse is not null and warehouse != '')
|
|
|
|
and is_group=0""")
|
2014-10-14 06:11:44 +00:00
|
|
|
|
2014-10-08 05:30:38 +00:00
|
|
|
vouchers = frappe.db.sql("""select distinct voucher_type, voucher_no
|
2014-10-14 06:11:44 +00:00
|
|
|
from `tabStock Ledger Entry` sle
|
|
|
|
where voucher_type != "Serial No" and sle.warehouse in (%s)
|
|
|
|
order by posting_date, posting_time, name""" %
|
|
|
|
', '.join(['%s']*len(warehouses_with_account)), tuple(warehouses_with_account))
|
2014-10-08 05:30:38 +00:00
|
|
|
|
|
|
|
rejected = []
|
2014-10-09 13:55:03 +00:00
|
|
|
i = 0
|
2014-10-08 05:30:38 +00:00
|
|
|
for voucher_type, voucher_no in vouchers:
|
2014-10-09 13:55:03 +00:00
|
|
|
i+=1
|
2017-08-28 12:47:36 +00:00
|
|
|
print(i, "/", len(vouchers), voucher_type, voucher_no)
|
2014-10-08 05:30:38 +00:00
|
|
|
try:
|
|
|
|
for dt in ["Stock Ledger Entry", "GL Entry"]:
|
|
|
|
frappe.db.sql("""delete from `tab%s` where voucher_type=%s and voucher_no=%s"""%
|
|
|
|
(dt, '%s', '%s'), (voucher_type, voucher_no))
|
|
|
|
|
|
|
|
doc = frappe.get_doc(voucher_type, voucher_no)
|
|
|
|
if voucher_type=="Stock Entry" and doc.purpose in ["Manufacture", "Repack"]:
|
2015-08-07 11:47:03 +00:00
|
|
|
doc.calculate_rate_and_amount(force=1)
|
2014-10-10 12:33:27 +00:00
|
|
|
elif voucher_type=="Purchase Receipt" and doc.is_subcontracted == "Yes":
|
|
|
|
doc.validate()
|
2014-10-08 12:36:14 +00:00
|
|
|
|
2014-10-08 05:30:38 +00:00
|
|
|
doc.update_stock_ledger()
|
2015-01-12 05:25:48 +00:00
|
|
|
doc.make_gl_entries(repost_future_gle=False)
|
2014-10-08 12:36:14 +00:00
|
|
|
frappe.db.commit()
|
2017-08-28 12:47:36 +00:00
|
|
|
except Exception as e:
|
|
|
|
print(frappe.get_traceback())
|
2014-10-08 05:30:38 +00:00
|
|
|
rejected.append([voucher_type, voucher_no])
|
2014-10-08 12:36:14 +00:00
|
|
|
frappe.db.rollback()
|
2014-10-08 05:30:38 +00:00
|
|
|
|
2017-08-28 12:47:36 +00:00
|
|
|
print(rejected)
|