コード例 #1
0
ファイル: stock_ledger.py プロジェクト: Cattmy/erpnext
	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()
コード例 #2
0
    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()
コード例 #3
0
	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()
コード例 #4
0
	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()
コード例 #5
0
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
コード例 #6
0
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)
コード例 #7
0
	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)
コード例 #8
0
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
コード例 #9
0
	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)
コード例 #10
0
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"]))
コード例 #11
0
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"]),
    )