def __init__(self, args, allow_zero_rate=False, allow_negative_stock=None, via_landed_cost_voucher=False, verbose=1): from frappe.model.meta import get_field_precision self.exceptions = [] self.verbose = verbose self.allow_zero_rate = allow_zero_rate self.allow_negative_stock = allow_negative_stock self.via_landed_cost_voucher = via_landed_cost_voucher if not self.allow_negative_stock: self.allow_negative_stock = cint(frappe.db.get_single_value("Stock Settings", "allow_negative_stock")) self.args = args for key, value in args.iteritems(): setattr(self, key, value) self.previous_sle = self.get_sle_before_datetime() self.previous_sle = self.previous_sle[0] if self.previous_sle else frappe._dict() for key in ("qty_after_transaction", "valuation_rate", "stock_value"): setattr(self, key, flt(self.previous_sle.get(key))) self.company = frappe.db.get_value("Warehouse", self.warehouse, "company") self.precision = get_field_precision(frappe.get_meta("Stock Ledger Entry").get_field("stock_value"), currency=frappe.db.get_value("Company", self.company, "default_currency", cache=True)) self.prev_stock_value = self.previous_sle.stock_value or 0.0 self.stock_queue = json.loads(self.previous_sle.stock_queue or "[]") self.valuation_method = get_valuation_method(self.item_code) self.stock_value_difference = 0.0 self.build()
def __init__(self, args, allow_zero_rate=False, allow_negative_stock=None, via_landed_cost_voucher=False, verbose=1): self.exceptions = {} self.verbose = verbose self.allow_zero_rate = allow_zero_rate self.via_landed_cost_voucher = via_landed_cost_voucher self.allow_negative_stock = allow_negative_stock \ or cint(frappe.db.get_single_value("Stock Settings", "allow_negative_stock")) self.args = frappe._dict(args) self.item_code = args.get("item_code") if self.args.sle_id: self.args['name'] = self.args.sle_id self.company = frappe.get_cached_value("Warehouse", self.args.warehouse, "company") self.get_precision() self.valuation_method = get_valuation_method(self.item_code) self.new_items = {} self.data = frappe._dict() self.initialize_previous_data(self.args) self.build()
def __init__(self, args, allow_zero_rate=False, allow_negative_stock=None, via_landed_cost_voucher=False, verbose=1): from frappe.model.meta import get_field_precision self.exceptions = [] self.verbose = verbose self.allow_zero_rate = allow_zero_rate self.allow_negative_stock = allow_negative_stock self.via_landed_cost_voucher = via_landed_cost_voucher if not self.allow_negative_stock: self.allow_negative_stock = cint(frappe.db.get_single_value("Stock Settings", "allow_negative_stock")) self.args = args for key, value in iteritems(args): setattr(self, key, value) self.previous_sle = self.get_sle_before_datetime() self.previous_sle = self.previous_sle[0] if self.previous_sle else frappe._dict() for key in ("qty_after_transaction", "valuation_rate", "stock_value"): setattr(self, key, flt(self.previous_sle.get(key))) self.company = frappe.db.get_value("Warehouse", self.warehouse, "company") self.precision = get_field_precision(frappe.get_meta("Stock Ledger Entry").get_field("stock_value"), currency=frappe.db.get_value("Company", self.company, "default_currency", cache=True)) self.prev_stock_value = self.previous_sle.stock_value or 0.0 self.stock_queue = json.loads(self.previous_sle.stock_queue or "[]") self.valuation_method = get_valuation_method(self.item_code) self.stock_value_difference = 0.0 self.build()
def __init__( self, args, allow_zero_rate=False, allow_negative_stock=None, via_landed_cost_voucher=False, verbose=1, ): self.exceptions = {} self.verbose = verbose self.allow_zero_rate = allow_zero_rate self.via_landed_cost_voucher = via_landed_cost_voucher self.item_code = args.get("item_code") self.allow_negative_stock = allow_negative_stock or is_negative_stock_allowed( item_code=self.item_code ) self.args = frappe._dict(args) if self.args.sle_id: self.args["name"] = self.args.sle_id self.company = frappe.get_cached_value("Warehouse", self.args.warehouse, "company") self.get_precision() self.valuation_method = get_valuation_method(self.item_code) self.new_items_found = False self.distinct_item_warehouses = args.get("distinct_item_warehouses", frappe._dict()) self.affected_transactions: Set[Tuple[str, str]] = set() self.data = frappe._dict() self.initialize_previous_data(self.args) self.build()
def get_incoming_rate(args, raise_error_if_no_rate=True): """Get Incoming Rate based on valuation method""" from erpnext.stock.stock_ledger import get_previous_sle, get_valuation_rate from erpnext.stock.utils import get_fifo_rate, get_avg_purchase_rate, get_valuation_method from erpnext.stock.stock_ledger import get_previous_sle from six import string_types if isinstance(args, string_types): args = json.loads(args) in_rate = 0 #finbyz changes batch_wise_cost = cint( frappe.db.get_single_value( "Stock Settings", 'exact_cost_valuation_for_batch_wise_items')) # finbyz changes #finbyz changes if args.get("batch_no") and batch_wise_cost: in_rate = get_batch_rate(args) #frappe.msgprint(f"inside:{in_rate}") elif (args.get("serial_no") or "").strip(): in_rate = get_avg_purchase_rate(args.get("serial_no")) else: valuation_method = get_valuation_method(args.get("item_code")) previous_sle = get_previous_sle(args) if valuation_method == 'FIFO': if previous_sle: previous_stock_queue = json.loads( previous_sle.get('stock_queue', '[]') or '[]') in_rate = get_fifo_rate(previous_stock_queue, args.get("qty") or 0) if previous_stock_queue else 0 elif valuation_method == 'Moving Average': in_rate = previous_sle.get('valuation_rate') or 0 if not in_rate: voucher_no = args.get('voucher_no') or args.get('name') in_rate = get_valuation_rate( args.get('item_code'), args.get('warehouse'), args.get('voucher_type'), voucher_no, args.get('allow_zero_valuation'), currency=erpnext.get_company_currency(args.get('company')), company=args.get('company'), raise_error_if_no_rate=raise_error_if_no_rate) #frappe.msgprint(str(in_rate)) return in_rate
def set_valuation_method(item_code, valuation_method): existing_valuation_method = get_valuation_method(item_code) if valuation_method == existing_valuation_method: return frappe.db.set_value("Item", item_code, "valuation_method", valuation_method) for warehouse in frappe.get_all("Warehouse", filters={"company": "_Test Company"}, fields=["name", "is_group"]): if not warehouse.is_group: update_entries_after({ "item_code": item_code, "warehouse": warehouse.name }, allow_negative_stock=1)
def insert_stock_ledger_entries(self): """ find difference between current and expected entries and create stock ledger entries based on the difference""" from erpnext.stock.utils import get_valuation_method from erpnext.stock.stock_ledger import get_previous_sle row_template = ["item_code", "warehouse", "qty", "valuation_rate"] if not self.doc.reconciliation_json: msgprint(_("""Stock Reconciliation file not uploaded"""), raise_exception=1) data = json.loads(self.doc.reconciliation_json) for row_num, row in enumerate(data[data.index(self.head_row)+1:]): row = frappe._dict(zip(row_template, row)) row["row_num"] = row_num previous_sle = get_previous_sle({ "item_code": row.item_code, "warehouse": row.warehouse, "posting_date": self.doc.posting_date, "posting_time": self.doc.posting_time }) # check valuation rate mandatory if row.qty != "" and not row.valuation_rate and \ flt(previous_sle.get("qty_after_transaction")) <= 0: frappe.throw(_("As existing qty for item: ") + row.item_code + _(" at warehouse: ") + row.warehouse + _(" is less than equals to zero in the system, valuation rate is mandatory for this item")) change_in_qty = row.qty != "" and \ (flt(row.qty) - flt(previous_sle.get("qty_after_transaction"))) change_in_rate = row.valuation_rate != "" and \ (flt(row.valuation_rate) - flt(previous_sle.get("valuation_rate"))) if get_valuation_method(row.item_code) == "Moving Average": self.sle_for_moving_avg(row, previous_sle, change_in_qty, change_in_rate) else: self.sle_for_fifo(row, previous_sle, change_in_qty, change_in_rate)
def get_incoming_rate(args): """Get Incoming Rate based on valuation method""" if isinstance(args, basestring): args = json.loads(args) in_rate = 0 batch_wise_rate = cint( frappe.db.get_single_value( "Stock Settings", 'exact_cost_valuation_for_batch_wise_items')) if args.get("batch_no") and batch_wise_rate: in_rate = get_batch_rate(args.get("batch_no")) elif (args.get("serial_no") or "").strip(): in_rate = get_avg_purchase_rate(args.get("serial_no")) else: valuation_method = get_valuation_method(args.get("item_code")) previous_sle = get_previous_sle(args) if valuation_method == 'FIFO': if previous_sle: previous_stock_queue = json.loads( previous_sle.get('stock_queue', '[]') or '[]') in_rate = get_fifo_rate(previous_stock_queue, args.get("qty") or 0) if previous_stock_queue else 0 elif valuation_method == 'Moving Average': in_rate = previous_sle.get('valuation_rate') or 0 if not in_rate: voucher_no = args.get('voucher_no') or args.get('name') in_rate = get_valuation_rate(args.get('item_code'), args.get('warehouse'), args.get('voucher_type'), voucher_no, args.get('allow_zero_valuation'), currency=erpnext.get_company_currency( args.get('company')), company=args.get('company')) return in_rate
def insert_stock_ledger_entries(self): """ find difference between current and expected entries and create stock ledger entries based on the difference""" from erpnext.stock.utils import get_valuation_method from erpnext.stock.stock_ledger import get_previous_sle row_template = ["item_code", "warehouse", "qty", "valuation_rate"] if not self.reconciliation_json: msgprint(_("""Stock Reconciliation file not uploaded"""), raise_exception=1) data = json.loads(self.reconciliation_json) for row_num, row in enumerate(data[data.index(self.head_row)+1:]): row = frappe._dict(zip(row_template, row)) row["row_num"] = row_num previous_sle = get_previous_sle({ "item_code": row.item_code, "warehouse": row.warehouse, "posting_date": self.posting_date, "posting_time": self.posting_time }) # check valuation rate mandatory if row.qty != "" and not row.valuation_rate and \ flt(previous_sle.get("qty_after_transaction")) <= 0: frappe.throw(_("Valuation Rate required for Item {0}").format(row.item_code)) change_in_qty = row.qty != "" and \ (flt(row.qty) - flt(previous_sle.get("qty_after_transaction"))) change_in_rate = row.valuation_rate != "" and \ (flt(row.valuation_rate) - flt(previous_sle.get("valuation_rate"))) if get_valuation_method(row.item_code) == "Moving Average": self.sle_for_moving_avg(row, previous_sle, change_in_qty, change_in_rate) else: self.sle_for_fifo(row, previous_sle, change_in_qty, change_in_rate)
def update_entries_after(args, allow_zero_rate=False, verbose=1): """ update valution rate and qty after transaction from the current time-bucket onwards args = { "item_code": "ABC", "warehouse": "XYZ", "posting_date": "2012-12-12", "posting_time": "12:00" } """ if not _exceptions: frappe.local.stockledger_exceptions = [] previous_sle = get_sle_before_datetime(args) qty_after_transaction = flt(previous_sle.get("qty_after_transaction")) valuation_rate = flt(previous_sle.get("valuation_rate")) stock_queue = json.loads(previous_sle.get("stock_queue") or "[]") stock_value = flt(previous_sle.get("stock_value")) prev_stock_value = flt(previous_sle.get("stock_value")) entries_to_fix = get_sle_after_datetime(previous_sle or \ {"item_code": args["item_code"], "warehouse": args["warehouse"]}, for_update=True) valuation_method = get_valuation_method(args["item_code"]) stock_value_difference = 0.0 for sle in entries_to_fix: if sle.serial_no or not cint( frappe.db.get_value("Stock Settings", None, "allow_negative_stock")): # validate negative stock for serialized items, fifo valuation # or when negative stock is not allowed for moving average if not validate_negative_stock(qty_after_transaction, sle): qty_after_transaction += flt(sle.actual_qty) continue if sle.serial_no: valuation_rate = get_serialized_values(qty_after_transaction, sle, valuation_rate) qty_after_transaction += flt(sle.actual_qty) else: if sle.voucher_type == "Stock Reconciliation": valuation_rate = sle.valuation_rate qty_after_transaction = sle.qty_after_transaction stock_queue = [[qty_after_transaction, valuation_rate]] else: if valuation_method == "Moving Average": valuation_rate = get_moving_average_values( qty_after_transaction, sle, valuation_rate, allow_zero_rate) else: valuation_rate = get_fifo_values(qty_after_transaction, sle, stock_queue, allow_zero_rate) qty_after_transaction += flt(sle.actual_qty) # get stock value if sle.serial_no: stock_value = qty_after_transaction * valuation_rate elif valuation_method == "Moving Average": stock_value = qty_after_transaction * valuation_rate else: stock_value = sum( (flt(batch[0]) * flt(batch[1]) for batch in stock_queue)) # rounding as per precision from frappe.model.meta import get_field_precision meta = frappe.get_meta("Stock Ledger Entry") stock_value = flt( stock_value, get_field_precision(meta.get_field("stock_value"), frappe._dict({"fields": sle}))) stock_value_difference = stock_value - prev_stock_value prev_stock_value = stock_value # update current sle frappe.db.sql( """update `tabStock Ledger Entry` set qty_after_transaction=%s, valuation_rate=%s, stock_queue=%s, stock_value=%s, stock_value_difference=%s where name=%s""", (qty_after_transaction, valuation_rate, json.dumps(stock_queue), stock_value, stock_value_difference, sle.name)) if _exceptions: _raise_exceptions(args, verbose) # update bin if not frappe.db.exists({ "doctype": "Bin", "item_code": args["item_code"], "warehouse": args["warehouse"] }): bin_wrapper = frappe.get_doc({ "doctype": "Bin", "item_code": args["item_code"], "warehouse": args["warehouse"], }) bin_wrapper.ignore_permissions = 1 bin_wrapper.insert() frappe.db.sql( """update `tabBin` set valuation_rate=%s, actual_qty=%s, stock_value=%s, projected_qty = (actual_qty + indented_qty + ordered_qty + planned_qty - reserved_qty) where item_code=%s and warehouse=%s""", (valuation_rate, qty_after_transaction, stock_value, args["item_code"], args["warehouse"]))
def update_entries_after(args, allow_zero_rate=False, allow_negative_stock=False, verbose=1): """ update valution rate and qty after transaction from the current time-bucket onwards args = { "item_code": "ABC", "warehouse": "XYZ", "posting_date": "2012-12-12", "posting_time": "12:00" } """ if not _exceptions: frappe.local.stockledger_exceptions = [] if not allow_negative_stock: allow_negative_stock = cint(frappe.db.get_default("allow_negative_stock")) previous_sle = get_sle_before_datetime(args) qty_after_transaction = flt(previous_sle.get("qty_after_transaction")) valuation_rate = flt(previous_sle.get("valuation_rate")) stock_queue = json.loads(previous_sle.get("stock_queue") or "[]") stock_value = flt(previous_sle.get("stock_value")) prev_stock_value = flt(previous_sle.get("stock_value")) entries_to_fix = get_sle_after_datetime( previous_sle or {"item_code": args["item_code"], "warehouse": args["warehouse"]}, for_update=True ) valuation_method = get_valuation_method(args["item_code"]) stock_value_difference = 0.0 for sle in entries_to_fix: if sle.serial_no or not allow_negative_stock: # validate negative stock for serialized items, fifo valuation # or when negative stock is not allowed for moving average if not validate_negative_stock(qty_after_transaction, sle): qty_after_transaction += flt(sle.actual_qty) continue if sle.serial_no: valuation_rate = get_serialized_values(qty_after_transaction, sle, valuation_rate) qty_after_transaction += flt(sle.actual_qty) else: if sle.voucher_type == "Stock Reconciliation": valuation_rate = sle.valuation_rate qty_after_transaction = sle.qty_after_transaction stock_queue = [[qty_after_transaction, valuation_rate]] else: if valuation_method == "Moving Average": valuation_rate = get_moving_average_values( qty_after_transaction, sle, valuation_rate, allow_zero_rate ) else: valuation_rate = get_fifo_values(qty_after_transaction, sle, stock_queue, allow_zero_rate) qty_after_transaction += flt(sle.actual_qty) # get stock value if sle.serial_no: stock_value = qty_after_transaction * valuation_rate elif valuation_method == "Moving Average": stock_value = qty_after_transaction * valuation_rate else: stock_value = sum((flt(batch[0]) * flt(batch[1]) for batch in stock_queue)) # rounding as per precision from frappe.model.meta import get_field_precision meta = frappe.get_meta("Stock Ledger Entry") stock_value = flt( stock_value, get_field_precision(meta.get_field("stock_value"), frappe._dict({"fields": sle})) ) stock_value_difference = stock_value - prev_stock_value prev_stock_value = stock_value # update current sle frappe.db.sql( """update `tabStock Ledger Entry` set qty_after_transaction=%s, valuation_rate=%s, stock_queue=%s, stock_value=%s, stock_value_difference=%s where name=%s""", ( qty_after_transaction, valuation_rate, json.dumps(stock_queue), stock_value, stock_value_difference, sle.name, ), ) if _exceptions: _raise_exceptions(args, verbose) # update bin if not frappe.db.exists({"doctype": "Bin", "item_code": args["item_code"], "warehouse": args["warehouse"]}): bin_wrapper = frappe.get_doc({"doctype": "Bin", "item_code": args["item_code"], "warehouse": args["warehouse"]}) bin_wrapper.ignore_permissions = 1 bin_wrapper.insert() frappe.db.sql( """update `tabBin` set valuation_rate=%s, actual_qty=%s, stock_value=%s, projected_qty = (actual_qty + indented_qty + ordered_qty + planned_qty - reserved_qty) where item_code=%s and warehouse=%s""", (valuation_rate, qty_after_transaction, stock_value, args["item_code"], args["warehouse"]), )