Example #1
0
	def test_stock_reco_for_serialized_item(self):
		set_perpetual_inventory()

		to_delete_records = []
		to_delete_serial_nos = []

		# Add new serial nos
		serial_item_code = "Stock-Reco-Serial-Item-1"
		serial_warehouse = "_Test Warehouse for Stock Reco1 - _TC"

		sr = create_stock_reconciliation(item_code=serial_item_code,
			warehouse = serial_warehouse, qty=5, rate=200)

		# print(sr.name)
		serial_nos = get_serial_nos(sr.items[0].serial_no)
		self.assertEqual(len(serial_nos), 5)

		args = {
			"item_code": serial_item_code,
			"warehouse": serial_warehouse,
			"posting_date": nowdate(),
			"posting_time": nowtime(),
			"serial_no": sr.items[0].serial_no
		}

		valuation_rate = get_incoming_rate(args)
		self.assertEqual(valuation_rate, 200)

		to_delete_records.append(sr.name)

		sr = create_stock_reconciliation(item_code=serial_item_code,
			warehouse = serial_warehouse, qty=5, rate=300, serial_no = '\n'.join(serial_nos))

		# print(sr.name)
		serial_nos1 = get_serial_nos(sr.items[0].serial_no)
		self.assertEqual(len(serial_nos1), 5)

		args = {
			"item_code": serial_item_code,
			"warehouse": serial_warehouse,
			"posting_date": nowdate(),
			"posting_time": nowtime(),
			"serial_no": sr.items[0].serial_no
		}

		valuation_rate = get_incoming_rate(args)
		self.assertEqual(valuation_rate, 300)

		to_delete_records.append(sr.name)
		to_delete_records.reverse()

		for d in to_delete_records:
			stock_doc = frappe.get_doc("Stock Reconciliation", d)
			stock_doc.cancel()

		for d in serial_nos + serial_nos1:
			if frappe.db.exists("Serial No", d):
				frappe.delete_doc("Serial No", d)
Example #2
0
    def set_basic_rate(self, force=False, update_finished_item_rate=True):
        """get stock and incoming rate on posting date"""
        raw_material_cost = 0.0
        scrap_material_cost = 0.0
        fg_basic_rate = 0.0

        for d in self.get('items'):
            if d.t_warehouse: fg_basic_rate = flt(d.basic_rate)
            args = self.get_args_for_incoming_rate(d)

            # get basic rate
            if not d.bom_no:
                if (not flt(d.basic_rate) and not d.allow_zero_valuation_rate
                    ) or d.s_warehouse or force:
                    basic_rate = flt(get_incoming_rate(args),
                                     self.precision("basic_rate", d))
                    if basic_rate > 0:
                        d.basic_rate = basic_rate

                d.basic_amount = flt(
                    flt(d.transfer_qty) * flt(d.basic_rate),
                    d.precision("basic_amount"))
                if not d.t_warehouse:
                    raw_material_cost += flt(d.basic_amount)

            # get scrap items basic rate
            if d.bom_no:
                if not flt(d.basic_rate) and not d.allow_zero_valuation_rate and \
                 getattr(self, "pro_doc", frappe._dict()).scrap_warehouse == d.t_warehouse:
                    basic_rate = flt(get_incoming_rate(args),
                                     self.precision("basic_rate", d))
                    if basic_rate > 0:
                        d.basic_rate = basic_rate
                    d.basic_amount = flt(
                        flt(d.transfer_qty) * flt(d.basic_rate),
                        d.precision("basic_amount"))

                if getattr(self, "pro_doc",
                           frappe._dict()).scrap_warehouse == d.t_warehouse:

                    scrap_material_cost += flt(d.basic_amount)

        number_of_fg_items = len(
            [t.t_warehouse for t in self.get("items") if t.t_warehouse])
        if (fg_basic_rate == 0.0
                and number_of_fg_items == 1) or update_finished_item_rate:
            self.set_basic_rate_for_finished_goods(raw_material_cost,
                                                   scrap_material_cost)
Example #3
0
    def set_basic_rate(self, force=False):
        """get stock and incoming rate on posting date"""
        raw_material_cost = 0.0

        for d in self.get("items"):
            args = frappe._dict(
                {
                    "item_code": d.item_code,
                    "warehouse": d.s_warehouse or d.t_warehouse,
                    "posting_date": self.posting_date,
                    "posting_time": self.posting_time,
                    "qty": d.s_warehouse and -1 * flt(d.transfer_qty) or flt(d.transfer_qty),
                    "serial_no": d.serial_no,
                }
            )

            # get basic rate
            if not d.bom_no:
                if not flt(d.basic_rate) or d.s_warehouse or force:
                    basic_rate = flt(get_incoming_rate(args), self.precision("basic_rate", d))
                    if basic_rate > 0:
                        d.basic_rate = basic_rate

                d.basic_amount = flt(flt(d.transfer_qty) * flt(d.basic_rate), d.precision("basic_amount"))
                if not d.t_warehouse:
                    raw_material_cost += flt(d.basic_amount)

        self.set_basic_rate_for_finished_goods(raw_material_cost)
Example #4
0
    def update_raw_materials_supplied(self, item, raw_material_table,
                                      rm_supplied_idx):
        bom_items = self.get_items_from_default_bom(item.item_code)
        raw_materials_cost = 0

        for bom_item in bom_items:
            # check if exists
            exists = 0
            for d in self.get(raw_material_table):
                if d.main_item_code == item.item_code and d.rm_item_code == bom_item.item_code \
                 and d.reference_name == item.name:
                    rm, exists = d, 1
                    break

            if not exists:
                rm = self.append(raw_material_table, {})

            required_qty = flt(bom_item.qty_consumed_per_unit) * flt(
                item.qty) * flt(item.conversion_factor)
            rm.reference_name = item.name
            rm.bom_detail_no = bom_item.name
            rm.main_item_code = item.item_code
            rm.rm_item_code = bom_item.item_code
            rm.stock_uom = bom_item.stock_uom
            rm.required_qty = required_qty

            rm.conversion_factor = item.conversion_factor
            rm.idx = rm_supplied_idx

            if self.doctype == "Purchase Receipt":
                rm.consumed_qty = required_qty
                rm.description = bom_item.description
                if item.batch_no and not rm.batch_no:
                    rm.batch_no = item.batch_no

            rm_supplied_idx += 1

            # get raw materials rate
            if self.doctype == "Purchase Receipt":
                from erpnext.stock.utils import get_incoming_rate
                rm.rate = get_incoming_rate({
                    "item_code": bom_item.item_code,
                    "warehouse": self.supplier_warehouse,
                    "posting_date": self.posting_date,
                    "posting_time": self.posting_time,
                    "qty": -1 * required_qty,
                    "serial_no": rm.serial_no
                })
                if not rm.rate:
                    from erpnext.stock.stock_ledger import get_valuation_rate
                    rm.rate = get_valuation_rate(bom_item.item_code,
                                                 self.supplier_warehouse)
            else:
                rm.rate = bom_item.rate

            rm.amount = required_qty * flt(rm.rate)
            raw_materials_cost += flt(rm.amount)

        if self.doctype == "Purchase Receipt":
            item.rm_supp_cost = raw_materials_cost
Example #5
0
    def get_average_buying_rate(self, row, item_code):
        if not item_code in self.average_buying_rate:
            if item_code in self.non_stock_items:
                self.average_buying_rate[item_code] = flt(
                    frappe.db.sql(
                        """
					select sum(base_net_amount) / sum(qty * conversion_factor)
					from `tabPurchase Invoice Item`
					where item_code = %s and docstatus=1""", item_code)[0][0])
            else:
                row.voucher_type = row.parenttype
                row.voucher_no = row.parent
                average_buying_rate = get_incoming_rate(row)
                if not average_buying_rate:
                    average_buying_rate = get_valuation_rate(
                        item_code,
                        row.warehouse,
                        row.parenttype,
                        row.parent,
                        allow_zero_rate=row.allow_zero_valuation,
                        currency=self.filters.currency,
                        company=self.filters.company)

                self.average_buying_rate[item_code] = flt(average_buying_rate)

        return self.average_buying_rate[item_code]
Example #6
0
    def set_incoming_rate(self):
        if self.doctype not in ("Delivery Note", "Sales Invoice"):
            return

        items = self.get("items") + (self.get("packed_items") or [])
        for d in items:
            if not cint(self.get("is_return")):
                # Get incoming rate based on original item cost based on valuation method
                d.incoming_rate = get_incoming_rate(
                    {
                        "item_code": d.item_code,
                        "warehouse": d.warehouse,
                        "posting_date": self.posting_date,
                        "posting_time": self.posting_time,
                        "qty": -1 * flt(d.qty),
                        "serial_no": d.serial_no,
                        "company": self.company,
                        "voucher_type": self.doctype,
                        "voucher_no": self.name,
                        "allow_zero_valuation": d.get("allow_zero_valuation")
                    },
                    raise_error_if_no_rate=False)
            elif self.get("return_against"):
                # Get incoming rate of return entry from reference document
                # based on original item cost as per valuation method
                d.incoming_rate = get_rate_for_return(self.doctype,
                                                      self.name,
                                                      d.item_code,
                                                      self.return_against,
                                                      item_row=d)
Example #7
0
    def get_valuation_rate(self, args):
        """ Get average valuation rate of relevant warehouses 
			as per valuation method (MAR/FIFO) 
			as on costing date	
		"""
        from erpnext.stock.utils import get_incoming_rate
        dt = self.doc.costing_date or nowdate()
        time = self.doc.costing_date == nowdate() and now().split(
        )[1] or '23:59'
        warehouse = frappe.db.sql(
            "select warehouse from `tabBin` where item_code = %s",
            args['item_code'])
        rate = []
        for wh in warehouse:
            r = get_incoming_rate({
                "item_code": args.get("item_code"),
                "warehouse": wh[0],
                "posting_date": dt,
                "posting_time": time,
                "qty": args.get("qty") or 0
            })
            if r:
                rate.append(r)

        return rate and flt(sum(rate)) / len(rate) or 0
Example #8
0
    def update_basic_rates(self):
        total_rm_rate = 0
        for rm in self.items:
            rm.basic_rate = flt(
                get_incoming_rate({
                    "item_code":
                    rm.item_code,
                    "warehouse":
                    rm.warehouse,
                    "posting_date":
                    self.posting_date,
                    "posting_time":
                    self.posting_time,
                    "qty":
                    -1 * flt(rm.stock_qty),
                    "serial_no":
                    rm.serial_no,
                    "voucher_type":
                    self.doctype,
                    "voucher_no":
                    rm.name,
                    "company":
                    self.company,
                    "allow_zero_valuation":
                    rm.allow_zero_valuation_rate
                }),  # raise_error_if_no_rate
                self.precision("basic_rate", rm))
            rm.basic_amount = flt(rm.basic_rate * rm.stock_qty,
                                  self.precision("basic_amount", rm))
            total_rm_rate += rm.basic_amount

        # rate = raw_material_csot + (supplier cost if subcontracting)

        self.rate = flt((total_rm_rate + (self.base_total or 0)) / self.qty,
                        self.precision("rate"))
Example #9
0
    def set_basic_rate(self, force=False, update_finished_item_rate=True):
        """get stock and incoming rate on posting date"""
        for d in self.get('items'):
            args = frappe._dict({
                "item_code":
                d.item_code,
                "warehouse":
                d.s_warehouse or d.t_warehouse,
                "posting_date":
                self.posting_date,
                "posting_time":
                self.posting_time,
                "qty":
                d.s_warehouse and -1 * flt(d.transfer_qty)
                or flt(d.transfer_qty),
                "serial_no":
                d.serial_no,
            })

            if not flt(d.basic_rate) or d.s_warehouse or force:
                #			if not flt(d.basic_rate):
                basic_rate = flt(get_incoming_rate(args),
                                 self.precision("basic_rate", d))
                if basic_rate > 0:
                    d.basic_rate = basic_rate

            d.amount = flt(flt(d.transfer_qty) * flt(d.basic_rate))
def _get_qty_rate_for_serial_nos(item_code, warehouse, posting_date,
                                 posting_time, item_dict):
    args = {
        "item_code": item_code,
        "warehouse": warehouse,
        "posting_date": posting_date,
        "posting_time": posting_time,
    }

    serial_nos_list = [
        serial_no.get("name") for serial_no in frappe.db.sql(
            """
                SELECT name FFROM `tabSerial No` WHERE
                    item_code = %(item_code)s AND
                    warehouse = %(warehouse)s AND
                    timestamp(purchase_date, purchase_time) <= timestamp(%(posting_date)s, %(posting_time)s)
            """,
            args,
            as_dict=1,
        )
    ]

    qty = len(serial_nos_list)
    serial_nos = "\n".join(serial_nos_list)
    args.update({"qty": qty, "serial_nos": serial_nos})

    rate = get_incoming_rate(args, raise_error_if_no_rate=False) or 0

    return qty, rate, serial_nos
Example #11
0
    def get_stock_and_rate(self, force=False):
        """get stock and incoming rate on posting date"""

        raw_material_cost = 0.0

        if not self.posting_date or not self.posting_time:
            frappe.throw(_("Posting date and posting time is mandatory"))

        allow_negative_stock = cint(
            frappe.db.get_value("Stock Settings", None,
                                "allow_negative_stock"))

        for d in self.get('items'):
            d.transfer_qty = flt(d.transfer_qty)

            args = frappe._dict({
                "item_code":
                d.item_code,
                "warehouse":
                d.s_warehouse or d.t_warehouse,
                "posting_date":
                self.posting_date,
                "posting_time":
                self.posting_time,
                "qty":
                d.s_warehouse and -1 * d.transfer_qty or d.transfer_qty,
                "serial_no":
                d.serial_no,
            })

            # get actual stock at source warehouse
            d.actual_qty = get_previous_sle(args).get(
                "qty_after_transaction") or 0

            # validate qty during submit
            if d.docstatus == 1 and d.s_warehouse and not allow_negative_stock and d.actual_qty < d.transfer_qty:
                frappe.throw(
                    _("""Row {0}: Qty not avalable in warehouse {1} on {2} {3}.
					Available Qty: {4}, Transfer Qty: {5}""").format(d.idx, d.s_warehouse,
                                                      self.posting_date,
                                                      self.posting_time,
                                                      d.actual_qty,
                                                      d.transfer_qty),
                    NegativeStockError)

            # get incoming rate
            if not d.bom_no:
                if not flt(d.incoming_rate) or d.s_warehouse or force:
                    incoming_rate = flt(get_incoming_rate(args),
                                        self.precision("incoming_rate", d))
                    if incoming_rate > 0:
                        d.incoming_rate = incoming_rate

                d.amount = flt(
                    flt(d.transfer_qty) * flt(d.incoming_rate),
                    d.precision("amount"))
                if not d.t_warehouse:
                    raw_material_cost += flt(d.amount)

        self.add_operation_cost(raw_material_cost, force)
Example #12
0
	def set_basic_rate(self, force=False):
		"""get stock and incoming rate on posting date"""
		raw_material_cost = 0.0

		for d in self.get('items'):
			args = frappe._dict({
				"item_code": d.item_code,
				"warehouse": d.s_warehouse or d.t_warehouse,
				"posting_date": self.posting_date,
				"posting_time": self.posting_time,
				"qty": d.s_warehouse and -1*flt(d.transfer_qty) or flt(d.transfer_qty),
				"serial_no": d.serial_no,
			})

			# get basic rate
			if not d.bom_no:
				if not flt(d.basic_rate) or d.s_warehouse or force:
					basic_rate = flt(get_incoming_rate(args), self.precision("basic_rate", d))
					if basic_rate > 0:
						d.basic_rate = basic_rate

				d.basic_amount = flt(flt(d.transfer_qty) * flt(d.basic_rate), d.precision("basic_amount"))
				if not d.t_warehouse:
					raw_material_cost += flt(d.basic_amount)

		self.set_basic_rate_for_finished_goods(raw_material_cost)
	def update_raw_materials_supplied_based_on_stock_entries(self, raw_material_table):
		self.set(raw_material_table, [])
		purchase_orders = [d.purchase_order for d in self.items]
		if purchase_orders:
			items = get_subcontracted_raw_materials_from_se(purchase_orders)
			backflushed_raw_materials = get_backflushed_subcontracted_raw_materials_from_se(purchase_orders, self.name)

			for d in items:
				qty = d.qty - backflushed_raw_materials.get(d.item_code, 0)
				rm = self.append(raw_material_table, {})
				rm.rm_item_code = d.item_code
				rm.item_name = d.item_name
				rm.main_item_code = d.main_item_code
				rm.description = d.description
				rm.stock_uom = d.stock_uom
				rm.required_qty = qty
				rm.consumed_qty = qty
				rm.serial_no = d.serial_no
				rm.batch_no = d.batch_no

				# get raw materials rate
				from erpnext.stock.utils import get_incoming_rate
				rm.rate = get_incoming_rate({
					"item_code": d.item_code,
					"warehouse": self.supplier_warehouse,
					"posting_date": self.posting_date,
					"posting_time": self.posting_time,
					"qty": -1 * qty,
					"serial_no": rm.serial_no
				})
				if not rm.rate:
					rm.rate = get_valuation_rate(d.item_code, self.supplier_warehouse,
						self.doctype, self.name, currency=self.company_currency, company = self.company)

				rm.amount = qty * flt(rm.rate)
Example #14
0
    def get_incoming_rate(self, args):
        incoming_rate = 0
        if self.purpose == "Sales Return" and \
          (self.delivery_note_no or self.sales_invoice_no):
            sle = frappe.db.sql("""select name, posting_date, posting_time,
				actual_qty, stock_value, warehouse from `tabStock Ledger Entry`
				where voucher_type = %s and voucher_no = %s and
				item_code = %s limit 1""", ((self.delivery_note_no and "Delivery Note"
                                 or "Sales Invoice"), self.delivery_note_no
                                or self.sales_invoice_no, args.item_code),
                                as_dict=1)
            if sle:
                args.update({
                    "posting_date": sle[0].posting_date,
                    "posting_time": sle[0].posting_time,
                    "sle": sle[0].name,
                    "warehouse": sle[0].warehouse,
                })
                previous_sle = get_previous_sle(args)
                incoming_rate = (flt(sle[0].stock_value) - flt(previous_sle.get("stock_value"))) / \
                 flt(sle[0].actual_qty)
        else:
            incoming_rate = get_incoming_rate(args)

        return incoming_rate
Example #15
0
	def update_basic_rates(self):
		total_rm_rate = 0
		for rm in self.items:
			rm.basic_rate = flt(
								get_incoming_rate({
									"item_code": rm.item_code,
									"warehouse": rm.warehouse,
									"posting_date": self.posting_date,
									"posting_time": self.posting_time,
									"qty": -1*flt(rm.stock_qty),
									"serial_no": rm.serial_no,
									"voucher_type": self.doctype,
									"voucher_no": rm.name,
									"company": self.company,
									"allow_zero_valuation": rm.allow_zero_valuation_rate
								}), # raise_error_if_no_rate
								self.precision("basic_rate", rm))
			rm.basic_amount = flt(rm.basic_rate * rm.stock_qty, self.precision("basic_amount", rm))
			total_rm_rate += rm.basic_amount
		
		# get additional charges (included for valuation)
		charges_in_valuation = 0
		for tax in self.taxes:
			if tax.category in ['Valuation', 'Valuation and Total']:
				charges_in_valuation += tax.base_tax_amount
				
		
		# rate = raw_material_csot + (supplier cost if subcontracting)
		self.rate = flt((total_rm_rate + (self.base_total or 0) + charges_in_valuation) / self.qty, self.precision("rate"))
	def append_raw_material_to_be_backflushed(self, fg_item_doc, raw_material_data, qty):
		rm = self.append('supplied_items', {})
		rm.update(raw_material_data)

		if not rm.main_item_code:
			rm.main_item_code = fg_item_doc.item_code

		rm.reference_name = fg_item_doc.name
		rm.required_qty = qty
		rm.consumed_qty = qty

		if not raw_material_data.get('non_stock_item'):
			from erpnext.stock.utils import get_incoming_rate
			rm.rate = get_incoming_rate({
				"item_code": raw_material_data.rm_item_code,
				"warehouse": self.supplier_warehouse,
				"posting_date": self.posting_date,
				"posting_time": self.posting_time,
				"qty": -1 * qty,
				"serial_no": rm.serial_no
			})

			if not rm.rate:
				rm.rate = get_valuation_rate(raw_material_data.rm_item_code, self.supplier_warehouse,
					self.doctype, self.name, currency=self.company_currency, company=self.company)

		rm.amount = qty * flt(rm.rate)
		fg_item_doc.rm_supp_cost += rm.amount
	def update_raw_materials_supplied_based_on_stock_entries(self, raw_material_table):
		self.set(raw_material_table, [])
		purchase_orders = [d.purchase_order for d in self.items]
		if purchase_orders:
			items = get_subcontracted_raw_materials_from_se(purchase_orders)
			backflushed_raw_materials = get_backflushed_subcontracted_raw_materials_from_se(purchase_orders, self.name)

			for d in items:
				qty = d.qty - backflushed_raw_materials.get(d.item_code, 0)
				rm = self.append(raw_material_table, {})
				rm.rm_item_code = d.item_code
				rm.item_name = d.item_name
				rm.main_item_code = d.main_item_code
				rm.description = d.description
				rm.stock_uom = d.stock_uom
				rm.required_qty = qty
				rm.consumed_qty = qty
				rm.serial_no = d.serial_no
				rm.batch_no = d.batch_no

				# get raw materials rate
				from erpnext.stock.utils import get_incoming_rate
				rm.rate = get_incoming_rate({
					"item_code": d.item_code,
					"warehouse": self.supplier_warehouse,
					"posting_date": self.posting_date,
					"posting_time": self.posting_time,
					"qty": -1 * qty,
					"serial_no": rm.serial_no
				})
				if not rm.rate:
					rm.rate = get_valuation_rate(d.item_code, self.supplier_warehouse,
						self.doctype, self.name, currency=self.company_currency, company = self.company)

				rm.amount = qty * flt(rm.rate)
Example #18
0
    def set_incoming_rate(self):
        if self.doctype not in ("Purchase Receipt", "Purchase Invoice",
                                "Purchase Order"):
            return

        ref_doctype_map = {
            "Purchase Order": "Sales Order Item",
            "Purchase Receipt": "Delivery Note Item",
            "Purchase Invoice": "Sales Invoice Item",
        }

        ref_doctype = ref_doctype_map.get(self.doctype)
        items = self.get("items")
        for d in items:
            if not cint(self.get("is_return")):
                # Get outgoing rate based on original item cost based on valuation method

                if not d.get(frappe.scrub(ref_doctype)):
                    outgoing_rate = get_incoming_rate(
                        {
                            "item_code":
                            d.item_code,
                            "warehouse":
                            d.get('from_warehouse'),
                            "posting_date":
                            self.get('posting_date')
                            or self.get('transation_date'),
                            "posting_time":
                            self.get('posting_time'),
                            "qty":
                            -1 * flt(d.get('stock_qty')),
                            "serial_no":
                            d.get('serial_no'),
                            "company":
                            self.company,
                            "voucher_type":
                            self.doctype,
                            "voucher_no":
                            self.name,
                            "allow_zero_valuation":
                            d.get("allow_zero_valuation")
                        },
                        raise_error_if_no_rate=False)

                    rate = flt(outgoing_rate * d.conversion_factor,
                               d.precision('rate'))
                else:
                    rate = frappe.db.get_value(
                        ref_doctype, d.get(frappe.scrub(ref_doctype)), 'rate')

                if self.is_internal_transfer():
                    if rate != d.rate:
                        d.rate = rate
                        d.discount_percentage = 0
                        d.discount_amount = 0
                        frappe.msgprint(_(
                            "Row {0}: Item rate has been updated as per valuation rate since its an internal stock transfer"
                        ).format(d.idx),
                                        alert=1)
Example #19
0
	def update_stock_ledger(self):
		self.update_reserved_qty()

		sl_entries = []
		for d in self.get_item_list():
			if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1 and flt(d.qty):
				if flt(d.conversion_factor)==0.0:
					d.conversion_factor = get_conversion_factor(d.item_code, d.uom).get("conversion_factor") or 1.0
				return_rate = 0
				if cint(self.is_return) and self.return_against and self.docstatus==1:
					return_rate = self.get_incoming_rate_for_sales_return(d.item_code, self.return_against)

				# On cancellation or if return entry submission, make stock ledger entry for
				# target warehouse first, to update serial no values properly

				if d.warehouse and ((not cint(self.is_return) and self.docstatus==1)
					or (cint(self.is_return) and self.docstatus==2)):
						sl_entries.append(self.get_sl_entries(d, {
							"actual_qty": -1*flt(d.qty),
							"incoming_rate": return_rate
						}))

				if d.target_warehouse:
					target_warehouse_sle = self.get_sl_entries(d, {
						"actual_qty": flt(d.qty),
						"warehouse": d.target_warehouse
					})

					if self.docstatus == 1:
						if not cint(self.is_return):
							args = frappe._dict({
								"item_code": d.item_code,
								"warehouse": d.warehouse,
								"posting_date": self.posting_date,
								"posting_time": self.posting_time,
								"qty": -1*flt(d.qty),
								"serial_no": d.serial_no,
								"company": d.company,
								"voucher_type": d.voucher_type,
								"voucher_no": d.name,
								"allow_zero_valuation": d.allow_zero_valuation
							})
							target_warehouse_sle.update({
								"incoming_rate": get_incoming_rate(args)
							})
						else:
							target_warehouse_sle.update({
								"outgoing_rate": return_rate
							})
					sl_entries.append(target_warehouse_sle)

				if d.warehouse and ((not cint(self.is_return) and self.docstatus==2)
					or (cint(self.is_return) and self.docstatus==1)):
						sl_entries.append(self.get_sl_entries(d, {
							"actual_qty": -1*flt(d.qty),
							"incoming_rate": return_rate
						}))

		self.make_sl_entries(sl_entries)
	def update_stock_ledger(self):
		self.update_reserved_qty()

		sl_entries = []
		for d in self.get_item_list():
			if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1 and flt(d.qty):
				if flt(d.conversion_factor)==0.0:
					d.conversion_factor = get_conversion_factor(d.item_code, d.uom).get("conversion_factor") or 1.0
				return_rate = 0
				if cint(self.is_return) and self.return_against and self.docstatus==1:
					return_rate = self.get_incoming_rate_for_sales_return(d.item_code, self.return_against)

				# On cancellation or if return entry submission, make stock ledger entry for
				# target warehouse first, to update serial no values properly

				if d.warehouse and ((not cint(self.is_return) and self.docstatus==1)
					or (cint(self.is_return) and self.docstatus==2)):
						sl_entries.append(self.get_sl_entries(d, {
							"actual_qty": -1*flt(d.qty),
							"incoming_rate": return_rate
						}))

				if d.target_warehouse:
					target_warehouse_sle = self.get_sl_entries(d, {
						"actual_qty": flt(d.qty),
						"warehouse": d.target_warehouse
					})

					if self.docstatus == 1:
						if not cint(self.is_return):
							args = frappe._dict({
								"item_code": d.item_code,
								"warehouse": d.warehouse,
								"posting_date": self.posting_date,
								"posting_time": self.posting_time,
								"qty": -1*flt(d.qty),
								"serial_no": d.serial_no,
								"company": d.company,
								"voucher_type": d.voucher_type,
								"voucher_no": d.name,
								"allow_zero_valuation": d.allow_zero_valuation
							})
							target_warehouse_sle.update({
								"incoming_rate": get_incoming_rate(args)
							})
						else:
							target_warehouse_sle.update({
								"outgoing_rate": return_rate
							})
					sl_entries.append(target_warehouse_sle)

				if d.warehouse and ((not cint(self.is_return) and self.docstatus==2)
					or (cint(self.is_return) and self.docstatus==1)):
						sl_entries.append(self.get_sl_entries(d, {
							"actual_qty": -1*flt(d.qty),
							"incoming_rate": return_rate
						}))

		self.make_sl_entries(sl_entries)
Example #21
0
	def get_incoming_rate(self, args):
		incoming_rate = 0
		if self.purpose == "Sales Return":
			incoming_rate = self.get_incoming_rate_for_sales_return(args)
		else:
			incoming_rate = get_incoming_rate(args)

		return incoming_rate
	def get_incoming_rate(self, args):
		incoming_rate = 0
		if self.purpose == "Sales Return":
			incoming_rate = self.get_incoming_rate_for_sales_return(args)
		else:
			incoming_rate = get_incoming_rate(args)

		return incoming_rate
	def update_raw_materials_supplied(self, item, raw_material_table, rm_supplied_idx):
		bom_items = self.get_items_from_default_bom(item.item_code)
		raw_materials_cost = 0

		for bom_item in bom_items:
			# check if exists
			exists = 0
			for d in self.get(raw_material_table):
				if d.main_item_code == item.item_code and d.rm_item_code == bom_item.item_code \
					and d.reference_name == item.name:
						rm, exists = d, 1
						break

			if not exists:
				rm = self.append(raw_material_table, {})

			required_qty = flt(bom_item.qty_consumed_per_unit) * flt(item.qty) * flt(item.conversion_factor)
			rm.reference_name = item.name
			rm.bom_detail_no = bom_item.name
			rm.main_item_code = item.item_code
			rm.rm_item_code = bom_item.item_code
			rm.stock_uom = bom_item.stock_uom
			rm.required_qty = required_qty

			rm.conversion_factor = item.conversion_factor
			rm.idx = rm_supplied_idx

			if self.doctype == "Purchase Receipt":
				rm.consumed_qty = required_qty
				rm.description = bom_item.description
				if item.batch_no and not rm.batch_no:
					rm.batch_no = item.batch_no

			rm_supplied_idx += 1

			# get raw materials rate
			if self.doctype == "Purchase Receipt":
				from erpnext.stock.utils import get_incoming_rate
				item_rate = get_incoming_rate({
					"item_code": bom_item.item_code,
					"warehouse": self.supplier_warehouse,
					"posting_date": self.posting_date,
					"posting_time": self.posting_time,
					"qty": -1 * required_qty,
					"serial_no": rm.serial_no
				})
				if not item_rate:
					from erpnext.controllers.stock_controller import get_valuation_rate
					item_rate = get_valuation_rate(bom_item.item_code, self.supplier_warehouse)
				rm.rate = item_rate or bom_item.rate
			else:
				rm.rate = bom_item.rate

			rm.amount = required_qty * flt(rm.rate)
			raw_materials_cost += flt(rm.amount)

		if self.doctype == "Purchase Receipt":
			item.rm_supp_cost = raw_materials_cost
Example #24
0
def set_basic_rate(self, force=False, update_finished_item_rate=True):
	if print_debug: frappe.logger().debug("---radplusplus.manufacturing_controllers.set_basic_rate---")
	"""get stock and incoming rate on posting date"""
	raw_material_cost = 0.0
	scrap_material_cost = 0.0
	fg_basic_rate = 0.0

	for d in self.get('items'):
		if d.t_warehouse: fg_basic_rate = flt(d.basic_rate)
		args = frappe._dict({
			"item_code": d.item_code,
			"warehouse": d.s_warehouse or d.t_warehouse,
			"posting_date": self.posting_date,
			"posting_time": self.posting_time,
			"qty": d.s_warehouse and -1*flt(d.transfer_qty) or flt(d.transfer_qty),
			"serial_no": d.serial_no,
		})

		# get basic rate
		if not d.bom_no:
			if not flt(d.basic_rate) or d.s_warehouse or force:
				basic_rate = flt(get_incoming_rate(args), self.precision("basic_rate", d))
				if basic_rate > 0:
					d.basic_rate = basic_rate

			d.basic_amount = flt(flt(d.transfer_qty) * flt(d.basic_rate), d.precision("basic_amount"))
			if not d.t_warehouse:
				raw_material_cost += flt(d.basic_amount)

		# get scrap items basic rate
		if d.bom_no:
			if not flt(d.basic_rate) and getattr(self, "pro_doc", frappe._dict()).scrap_warehouse == d.t_warehouse:
				basic_rate = flt(get_incoming_rate(args), self.precision("basic_rate", d))
				if basic_rate > 0:
					d.basic_rate = basic_rate
				d.basic_amount = flt(flt(d.transfer_qty) * flt(d.basic_rate), d.precision("basic_amount"))

			if getattr(self, "pro_doc", frappe._dict()).scrap_warehouse == d.t_warehouse:

				scrap_material_cost += flt(d.basic_amount)

	number_of_fg_items = len([t.t_warehouse for t in self.get("items") if t.t_warehouse])
	if (fg_basic_rate == 0.0 and number_of_fg_items == 1) or update_finished_item_rate:
		set_basic_rate_for_finished_goods(self, raw_material_cost, scrap_material_cost)
Example #25
0
    def set_incoming_rate(self):
        if self.doctype not in ("Delivery Note", "Sales Invoice",
                                "Sales Order"):
            return

        items = self.get("items") + (self.get("packed_items") or [])
        for d in items:
            if not cint(self.get("is_return")):
                # Get incoming rate based on original item cost based on valuation method
                d.incoming_rate = get_incoming_rate(
                    {
                        "item_code":
                        d.item_code,
                        "warehouse":
                        d.warehouse,
                        "posting_date":
                        self.get('posting_date')
                        or self.get('transaction_date'),
                        "posting_time":
                        self.get('posting_time') or nowtime(),
                        "qty":
                        -1 * flt(d.get('stock_qty') or d.get('actual_qty')),
                        "serial_no":
                        d.get('serial_no'),
                        "company":
                        self.company,
                        "voucher_type":
                        self.doctype,
                        "voucher_no":
                        self.name,
                        "allow_zero_valuation":
                        d.get("allow_zero_valuation")
                    },
                    raise_error_if_no_rate=False)

                # For internal transfers use incoming rate as the valuation rate
                if self.is_internal_transfer():
                    rate = flt(d.incoming_rate * d.conversion_factor,
                               d.precision('rate'))
                    if d.rate != rate:
                        d.rate = rate
                        d.discount_percentage = 0
                        d.discount_amount = 0
                        frappe.msgprint(_(
                            "Row {0}: Item rate has been updated as per valuation rate since its an internal stock transfer"
                        ).format(d.idx),
                                        alert=1)

            elif self.get("return_against"):
                # Get incoming rate of return entry from reference document
                # based on original item cost as per valuation method
                d.incoming_rate = get_rate_for_return(self.doctype,
                                                      self.name,
                                                      d.item_code,
                                                      self.return_against,
                                                      item_row=d)
Example #26
0
    def test_stock_reco_for_batch_item(self):
        set_perpetual_inventory()

        to_delete_records = []
        to_delete_serial_nos = []

        # Add new serial nos
        item_code = "Stock-Reco-batch-Item-1"
        warehouse = "_Test Warehouse for Stock Reco2 - _TC"

        sr = create_stock_reconciliation(item_code=item_code,
                                         warehouse=warehouse,
                                         qty=5,
                                         rate=200,
                                         do_not_submit=1)
        sr.save(ignore_permissions=True)
        sr.submit()

        self.assertTrue(sr.items[0].batch_no)
        to_delete_records.append(sr.name)

        sr1 = create_stock_reconciliation(item_code=item_code,
                                          warehouse=warehouse,
                                          qty=6,
                                          rate=300,
                                          batch_no=sr.items[0].batch_no)

        args = {
            "item_code": item_code,
            "warehouse": warehouse,
            "posting_date": nowdate(),
            "posting_time": nowtime(),
        }

        valuation_rate = get_incoming_rate(args)
        self.assertEqual(valuation_rate, 300)
        to_delete_records.append(sr1.name)

        sr2 = create_stock_reconciliation(item_code=item_code,
                                          warehouse=warehouse,
                                          qty=0,
                                          rate=0,
                                          batch_no=sr.items[0].batch_no)

        stock_value = get_stock_value_on(warehouse, nowdate(), item_code)
        self.assertEqual(stock_value, 0)
        to_delete_records.append(sr2.name)

        to_delete_records.reverse()
        for d in to_delete_records:
            stock_doc = frappe.get_doc("Stock Reconciliation", d)
            stock_doc.cancel()

        frappe.delete_doc("Batch", sr.items[0].batch_no)
        for d in to_delete_records:
            frappe.delete_doc("Stock Reconciliation", d)
Example #27
0
	def set_basic_rate(self, force=False, update_finished_item_rate=True):
		"""get stock and incoming rate on posting date"""
		raw_material_cost = 0.0
		scrap_material_cost = 0.0
		fg_basic_rate = 0.0

		for d in self.get('items'):
			if d.t_warehouse: fg_basic_rate = flt(d.basic_rate)
			args = frappe._dict({
				"item_code": d.item_code,
				"warehouse": d.s_warehouse or d.t_warehouse,
				"posting_date": self.posting_date,
				"posting_time": self.posting_time,
				"qty": d.s_warehouse and -1*flt(d.transfer_qty) or flt(d.transfer_qty),
				"serial_no": d.serial_no,
			})

			# get basic rate
			if not d.bom_no:
				if not flt(d.basic_rate) or d.s_warehouse or force:
					basic_rate = flt(get_incoming_rate(args), self.precision("basic_rate", d))
					if basic_rate > 0:
						d.basic_rate = basic_rate

				d.basic_amount = flt(flt(d.transfer_qty) * flt(d.basic_rate), d.precision("basic_amount"))
				if not d.t_warehouse:
					raw_material_cost += flt(d.basic_amount)

			# get scrap items basic rate
			if d.bom_no:
				if not flt(d.basic_rate) and getattr(self, "pro_doc", frappe._dict()).scrap_warehouse == d.t_warehouse:
					basic_rate = flt(get_incoming_rate(args), self.precision("basic_rate", d))
					if basic_rate > 0:
						d.basic_rate = basic_rate
					d.basic_amount = flt(flt(d.transfer_qty) * flt(d.basic_rate), d.precision("basic_amount"))

				if getattr(self, "pro_doc", frappe._dict()).scrap_warehouse == d.t_warehouse:

					scrap_material_cost += flt(d.basic_amount)

		number_of_fg_items = len([t.t_warehouse for t in self.get("items") if t.t_warehouse])
		if (fg_basic_rate == 0.0 and number_of_fg_items == 1) or update_finished_item_rate:
			self.set_basic_rate_for_finished_goods(raw_material_cost, scrap_material_cost)
def get_rate_for_return(
    voucher_type,
    voucher_no,
    item_code,
    return_against=None,
    item_row=None,
    voucher_detail_no=None,
    sle=None,
):
    if not return_against:
        return_against = frappe.get_cached_value(voucher_type, voucher_no,
                                                 "return_against")

    return_against_item_field = get_return_against_item_fields(voucher_type)

    filters = get_filters(
        voucher_type,
        voucher_no,
        voucher_detail_no,
        return_against,
        item_code,
        return_against_item_field,
        item_row,
    )

    if voucher_type in ("Purchase Receipt", "Purchase Invoice"):
        select_field = "incoming_rate"
    else:
        select_field = "abs(stock_value_difference / actual_qty)"

    rate = flt(frappe.db.get_value("Stock Ledger Entry", filters,
                                   select_field))
    if not (rate and return_against) and voucher_type in [
            "Sales Invoice", "Delivery Note"
    ]:
        rate = frappe.db.get_value(f"{voucher_type} Item", voucher_detail_no,
                                   "incoming_rate")

        if not rate and sle:
            rate = get_incoming_rate(
                {
                    "item_code": sle.item_code,
                    "warehouse": sle.warehouse,
                    "posting_date": sle.get("posting_date"),
                    "posting_time": sle.get("posting_time"),
                    "qty": sle.actual_qty,
                    "serial_no": sle.get("serial_no"),
                    "company": sle.company,
                    "voucher_type": sle.voucher_type,
                    "voucher_no": sle.voucher_no,
                },
                raise_error_if_no_rate=False,
            )

    return rate
Example #29
0
def get_warehouse_details(args):
    if isinstance(args, basestring):
        args = json.loads(args)

    args = frappe._dict(args)

    ret = {}
    if args.warehouse and args.item_code:
        args.update({
            "posting_date": args.posting_date,
            "posting_time": args.posting_time,
        })
        ret = {
            "actual_qty": get_previous_sle(args).get("qty_after_transaction")
            or 0,
            "basic_rate": get_incoming_rate(args),
            "valuation_rate": get_incoming_rate(args)
        }

    return ret
Example #30
0
	def set_incoming_rate(self):
		for d in self.items:
			if d.s_warehouse:
				args = self.get_args_for_incoming_rate(d)
				d.basic_rate = get_incoming_rate(args)
			elif d.allow_zero_valuation_rate and not d.s_warehouse:
				d.basic_rate = 0.0
			elif d.t_warehouse and not d.basic_rate:
				d.basic_rate = get_valuation_rate(d.item_code, d.t_warehouse,
					self.doctype, d.name, d.allow_zero_valuation_rate,
					currency=erpnext.get_company_currency(self.company))
Example #31
0
	def set_incoming_rate(self):
		for d in self.items:
			if d.s_warehouse:
				args = self.get_args_for_incoming_rate(d)
				d.basic_rate = get_incoming_rate(args)
			elif d.allow_zero_valuation_rate and not d.s_warehouse:
				d.basic_rate = 0.0
			elif d.t_warehouse and not d.basic_rate:
				d.basic_rate = get_valuation_rate(d.item_code, d.t_warehouse,
					self.doctype, d.name, d.allow_zero_valuation_rate,
					currency=erpnext.get_company_currency(self.company))
Example #32
0
    def get_warehouse_details(self, args):
        ret = {}
        if args.get("warehouse") and args.get("item_code"):
            args.update({"posting_date": self.posting_date, "posting_time": self.posting_time})
            args = frappe._dict(args)

            ret = {
                "actual_qty": get_previous_sle(args).get("qty_after_transaction") or 0,
                "basic_rate": get_incoming_rate(args),
            }
        return ret
Example #33
0
    def get_average_buying_rate(self, row, item_code):
        if not item_code in self.average_buying_rate:
            if item_code in self.non_stock_items:
                self.average_buying_rate[item_code] = flt(
                    frappe.db.sql(
                        """select sum(base_net_amount) / sum(qty * conversion_factor)
					from `tabPurchase Invoice Item`
					where item_code = %s and docstatus=1""", item_code)[0][0])
            else:
                self.average_buying_rate[item_code] = get_incoming_rate(row)

        return self.average_buying_rate[item_code]
Example #34
0
	def get_average_buying_rate(self, row, item_code):
		if not item_code in self.average_buying_rate:
			if item_code in self.non_stock_items:
				self.average_buying_rate[item_code] = flt(frappe.db.sql("""select sum(base_net_amount) / sum(qty * conversion_factor)
					from `tabPurchase Invoice Item`
					where item_code = %s and docstatus=1""", item_code)[0][0])
			else:
				average_buying_rate = get_incoming_rate(row)
				if not average_buying_rate:
					average_buying_rate = get_valuation_rate(item_code, row.warehouse, allow_zero_rate=True)
				self.average_buying_rate[item_code] =  average_buying_rate

		return self.average_buying_rate[item_code]
Example #35
0
    def get_average_buying_rate(self, row, item_code):
        args = row
        if not item_code in self.average_buying_rate:
            args.update({
                'voucher_type': row.parenttype,
                'voucher_no': row.parent,
                'allow_zero_valuation': True,
                'company': self.filters.company
            })

            average_buying_rate = get_incoming_rate(args)
            self.average_buying_rate[item_code] = flt(average_buying_rate)

        return self.average_buying_rate[item_code]
Example #36
0
	def get_warehouse_details(self, args):
		ret = {}
		if args.get('warehouse') and args.get('item_code'):
			args.update({
				"posting_date": self.posting_date,
				"posting_time": self.posting_time,
			})
			args = frappe._dict(args)

			ret = {
				"actual_qty" : get_previous_sle(args).get("qty_after_transaction") or 0,
				"basic_rate" : get_incoming_rate(args)
			}
		return ret
Example #37
0
    def get_average_buying_rate(self, row, item_code):
        args = row
        if not item_code in self.average_buying_rate:
            args.update({
                "voucher_type": row.parenttype,
                "voucher_no": row.parent,
                "allow_zero_valuation": True,
                "company": self.filters.company,
            })

            average_buying_rate = get_incoming_rate(args)
            self.average_buying_rate[item_code] = flt(average_buying_rate)

        return self.average_buying_rate[item_code]
Example #38
0
	def set_incoming_rate(self):
		precision = cint(frappe.db.get_default("float_precision")) 
		for d in self.items:
			if d.source_warehouse:
				args = self.get_args_for_incoming_rate(d)
				d.basic_rate = flt(get_incoming_rate(args), precision)
			elif not d.source_warehouse:
				d.basic_rate = 0.0
			elif self.warehouse and not d.basic_rate:
				d.basic_rate = flt(get_valuation_rate(d.item_code, self.warehouse,
					self.doctype, d.name, 1,
					currency=erpnext.get_company_currency(self.company)), precision)

			d.basic_amount = d.basic_rate * d.qty
Example #39
0
def get_warehouse_details(args):
    if isinstance(args, basestring):
        args = json.loads(args)

    args = frappe._dict(args)

    ret = {}
    if args.warehouse and args.item_code:
        args.update({"posting_date": args.posting_date, "posting_time": args.posting_time})
        ret = {
            "actual_qty": get_previous_sle(args).get("qty_after_transaction") or 0,
            "basic_rate": get_incoming_rate(args),
        }

    return ret
    def set_incoming_rate(self):
        for d in self.items:
            if d.source_warehouse:
                args = self.get_args_for_incoming_rate(d)
                d.basic_rate = get_incoming_rate(args)
            elif not d.source_warehouse:
                d.basic_rate = 0.0
            elif self.warehouse and not d.basic_rate:
                d.basic_rate = get_valuation_rate(
                    d.item_code,
                    self.warehouse,
                    self.doctype,
                    d.name,
                    1,
                    currency=erpnext.get_company_currency(self.company))

            d.basic_amount = d.basic_rate * d.quantity
Example #41
0
	def get_stock_and_rate(self, force=False):
		"""get stock and incoming rate on posting date"""

		raw_material_cost = 0.0

		if not self.posting_date or not self.posting_time:
			frappe.throw(_("Posting date and posting time is mandatory"))

		allow_negative_stock = cint(frappe.db.get_value("Stock Settings", None, "allow_negative_stock"))

		for d in self.get('items'):
			d.transfer_qty = flt(d.transfer_qty)

			args = frappe._dict({
				"item_code": d.item_code,
				"warehouse": d.s_warehouse or d.t_warehouse,
				"posting_date": self.posting_date,
				"posting_time": self.posting_time,
				"qty": d.s_warehouse and -1*d.transfer_qty or d.transfer_qty,
				"serial_no": d.serial_no,
			})

			# get actual stock at source warehouse
			d.actual_qty = get_previous_sle(args).get("qty_after_transaction") or 0

			# validate qty during submit
			if d.docstatus==1 and d.s_warehouse and not allow_negative_stock and d.actual_qty < d.transfer_qty:
				frappe.throw(_("""Row {0}: Qty not avalable in warehouse {1} on {2} {3}.
					Available Qty: {4}, Transfer Qty: {5}""").format(d.idx, d.s_warehouse,
					self.posting_date, self.posting_time, d.actual_qty, d.transfer_qty), NegativeStockError)

			# get incoming rate
			if not d.bom_no:
				if not flt(d.incoming_rate) or d.s_warehouse or force:
					incoming_rate = flt(get_incoming_rate(args), self.precision("incoming_rate", d))
					if incoming_rate > 0:
						d.incoming_rate = incoming_rate

				d.amount = flt(flt(d.transfer_qty) * flt(d.incoming_rate), d.precision("amount"))
				if not d.t_warehouse:
					raw_material_cost += flt(d.amount)


		self.add_operation_cost(raw_material_cost, force)
Example #42
0
	def get_average_buying_rate(self, row, item_code):
		args = row
		if not item_code in self.average_buying_rate:
			if item_code in self.non_stock_items:
				self.average_buying_rate[item_code] = flt(frappe.db.sql("""
					select sum(base_net_amount) / sum(qty * conversion_factor)
					from `tabPurchase Invoice Item`
					where item_code = %s and docstatus=1""", item_code)[0][0])
			else:
				args.update({
					'voucher_type': row.parenttype,
					'voucher_no': row.parent,
					'allow_zero_valuation': True,
					'company': self.filters.company
				})

				average_buying_rate = get_incoming_rate(args)
				self.average_buying_rate[item_code] =  flt(average_buying_rate)

		return self.average_buying_rate[item_code]
Example #43
0
	def get_valuation_rate(self, args):
		""" Get average valuation rate of relevant warehouses
			as per valuation method (MAR/FIFO)
			as on costing date
		"""
		from erpnext.stock.utils import get_incoming_rate
		posting_date, posting_time = nowdate(), now().split()[1]
		warehouse = frappe.db.sql("select warehouse from `tabBin` where item_code = %s", args['item_code'])
		rate = []
		for wh in warehouse:
			r = get_incoming_rate({
				"item_code": args.get("item_code"),
				"warehouse": wh[0],
				"posting_date": posting_date,
				"posting_time": posting_time,
				"qty": args.get("qty") or 0
			})
			if r:
				rate.append(r)

		return rate and flt(sum(rate))/len(rate) or 0
Example #44
0
	def get_incoming_rate(self, args):
		incoming_rate = 0
		if self.purpose == "Sales Return" and \
				(self.delivery_note_no or self.sales_invoice_no):
			sle = frappe.db.sql("""select name, posting_date, posting_time,
				actual_qty, stock_value, warehouse from `tabStock Ledger Entry`
				where voucher_type = %s and voucher_no = %s and
				item_code = %s limit 1""",
				((self.delivery_note_no and "Delivery Note" or "Sales Invoice"),
				self.delivery_note_no or self.sales_invoice_no, args.item_code), as_dict=1)
			if sle:
				args.update({
					"posting_date": sle[0].posting_date,
					"posting_time": sle[0].posting_time,
					"sle": sle[0].name,
					"warehouse": sle[0].warehouse,
				})
				previous_sle = get_previous_sle(args)
				incoming_rate = (flt(sle[0].stock_value) - flt(previous_sle.get("stock_value"))) / \
					flt(sle[0].actual_qty)
		else:
			incoming_rate = get_incoming_rate(args)

		return incoming_rate
	def update_raw_materials_supplied_based_on_bom(self, item, raw_material_table):
		exploded_item = 1
		if hasattr(item, 'include_exploded_items'):
			exploded_item = item.get('include_exploded_items')

		bom_items = get_items_from_bom(item.item_code, item.bom, exploded_item)

		used_alternative_items = []
		if self.doctype == 'Purchase Receipt' and item.purchase_order:
			used_alternative_items = get_used_alternative_items(purchase_order = item.purchase_order)

		raw_materials_cost = 0
		items = list(set([d.item_code for d in bom_items]))
		item_wh = frappe._dict(frappe.db.sql("""select i.item_code, id.default_warehouse
			from `tabItem` i, `tabItem Default` id
			where id.parent=i.name and id.company=%s and i.name in ({0})"""
			.format(", ".join(["%s"] * len(items))), [self.company] + items))

		for bom_item in bom_items:
			if self.doctype == "Purchase Order":
				reserve_warehouse = bom_item.source_warehouse or item_wh.get(bom_item.item_code)
				if frappe.db.get_value("Warehouse", reserve_warehouse, "company") != self.company:
					reserve_warehouse = None

			conversion_factor = item.conversion_factor
			if (self.doctype == 'Purchase Receipt' and item.purchase_order and
				bom_item.item_code in used_alternative_items):
				alternative_item_data = used_alternative_items.get(bom_item.item_code)
				bom_item.item_code = alternative_item_data.item_code
				bom_item.item_name = alternative_item_data.item_name
				bom_item.stock_uom = alternative_item_data.stock_uom
				conversion_factor = alternative_item_data.conversion_factor
				bom_item.description = alternative_item_data.description

			# check if exists
			exists = 0
			for d in self.get(raw_material_table):
				if d.main_item_code == item.item_code and d.rm_item_code == bom_item.item_code \
					and d.reference_name == item.name:
						rm, exists = d, 1
						break

			if not exists:
				rm = self.append(raw_material_table, {})

			required_qty = flt(flt(bom_item.qty_consumed_per_unit) * (flt(item.qty) + getattr(item, 'rejected_qty', 0)) *
				flt(conversion_factor), rm.precision("required_qty"))
			rm.reference_name = item.name
			rm.bom_detail_no = bom_item.name
			rm.main_item_code = item.item_code
			rm.rm_item_code = bom_item.item_code
			rm.stock_uom = bom_item.stock_uom
			rm.required_qty = required_qty
			if self.doctype == "Purchase Order" and not rm.reserve_warehouse:
				rm.reserve_warehouse = reserve_warehouse

			rm.conversion_factor = conversion_factor

			if self.doctype in ["Purchase Receipt", "Purchase Invoice"]:
				rm.consumed_qty = required_qty
				rm.description = bom_item.description
				if item.batch_no and not rm.batch_no:
					rm.batch_no = item.batch_no

			# get raw materials rate
			if self.doctype == "Purchase Receipt":
				from erpnext.stock.utils import get_incoming_rate
				rm.rate = get_incoming_rate({
					"item_code": bom_item.item_code,
					"warehouse": self.supplier_warehouse,
					"posting_date": self.posting_date,
					"posting_time": self.posting_time,
					"qty": -1 * required_qty,
					"serial_no": rm.serial_no
				})
				if not rm.rate:
					rm.rate = get_valuation_rate(bom_item.item_code, self.supplier_warehouse,
						self.doctype, self.name, currency=self.company_currency, company = self.company)
			else:
				rm.rate = bom_item.rate

			rm.amount = required_qty * flt(rm.rate)
			raw_materials_cost += flt(rm.amount)

		if self.doctype in ("Purchase Receipt", "Purchase Invoice"):
			item.rm_supp_cost = raw_materials_cost
	def update_raw_materials_supplied(self, item, raw_material_table):
		bom_items = self.get_items_from_bom(item.item_code, item.bom)
		raw_materials_cost = 0
		items = list(set([d.item_code for d in bom_items]))
		item_wh = frappe._dict(frappe.db.sql("""select item_code, default_warehouse
			from `tabItem` where name in ({0})""".format(", ".join(["%s"] * len(items))), items))

		for bom_item in bom_items:
			if self.doctype == "Purchase Order":
				reserve_warehouse = bom_item.source_warehouse or item_wh.get(bom_item.item_code)
				if frappe.db.get_value("Warehouse", reserve_warehouse, "company") != self.company:
					reserve_warehouse = None

			# check if exists
			exists = 0
			for d in self.get(raw_material_table):
				if d.main_item_code == item.item_code and d.rm_item_code == bom_item.item_code \
					and d.reference_name == item.name:
						rm, exists = d, 1
						break

			if not exists:
				rm = self.append(raw_material_table, {})

			required_qty = flt(flt(bom_item.qty_consumed_per_unit) * flt(item.qty) *
				flt(item.conversion_factor), rm.precision("required_qty"))
			rm.reference_name = item.name
			rm.bom_detail_no = bom_item.name
			rm.main_item_code = item.item_code
			rm.rm_item_code = bom_item.item_code
			rm.stock_uom = bom_item.stock_uom
			rm.required_qty = required_qty
			if self.doctype == "Purchase Order" and not rm.reserve_warehouse:
				rm.reserve_warehouse = reserve_warehouse

			rm.conversion_factor = item.conversion_factor

			if self.doctype in ["Purchase Receipt", "Purchase Invoice"]:
				rm.consumed_qty = required_qty
				rm.description = bom_item.description
				if item.batch_no and not rm.batch_no:
					rm.batch_no = item.batch_no

			# get raw materials rate
			if self.doctype == "Purchase Receipt":
				from erpnext.stock.utils import get_incoming_rate
				rm.rate = get_incoming_rate({
					"item_code": bom_item.item_code,
					"warehouse": self.supplier_warehouse,
					"posting_date": self.posting_date,
					"posting_time": self.posting_time,
					"qty": -1 * required_qty,
					"serial_no": rm.serial_no
				})
				if not rm.rate:
					rm.rate = get_valuation_rate(bom_item.item_code, self.supplier_warehouse,
						self.doctype, self.name, currency=self.company_currency, company = self.company)
			else:
				rm.rate = bom_item.rate

			rm.amount = required_qty * flt(rm.rate)
			raw_materials_cost += flt(rm.amount)

		if self.doctype in ("Purchase Receipt", "Purchase Invoice"):
			item.rm_supp_cost = raw_materials_cost