Esempio n. 1
0
    def update_stock_ledger(self):
        self.update_reserved_qty()

        sl_entries = []
        # Loop over items and packed items table
        for d in self.get_item_list():
            if frappe.get_cached_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

                # On cancellation or 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_sle_for_source_warehouse(d))

                if d.target_warehouse:
                    sl_entries.append(self.get_sle_for_target_warehouse(d))

                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_sle_for_source_warehouse(d))

        self.make_sl_entries(sl_entries)
Esempio n. 2
0
def get_price_list_rate_general(args, item_code, variant_template_code=None):
    item_price_args = {
        "item_code": item_code,
        "price_list": args.get('price_list'),
        "uom": "",
        "transaction_date": args.get('transaction_date'),
    }

    if variant_template_code:
        # frappe.errprint("variant set"+ str(variant_template_code))
        general_price_list_rate = get_item_price(item_price_args, item_code)
        if not general_price_list_rate:
            general_price_list_rate = get_item_price(item_price_args,
                                                     variant_template_code)
    else:
        general_price_list_rate = get_item_price(item_price_args, item_code)
    # frappe.errprint("best matches"+str(general_price_list_rate))
    item_price_data = None
    conversion_factor = None

    for price_entry in general_price_list_rate:
        conversion_rate = get_conversion_factor(
            item_code, price_entry[2])["conversion_factor"]
        # frappe.errprint("********"+str(conversion_rate)+"   " + str(price_entry))
        if conversion_rate:
            conversion_factor = conversion_rate
            item_price_data = [price_entry]
            break
        # frappe.errprint("4" + item_code + "  " + str(general_price_list_rate) + str(conversion_factor))

    if item_price_data:
        # found uom -> stock uom -> uom
        return flt(item_price_data[0][1] * (1 / flt(conversion_factor)) *
                   flt(args.get("conversion_factor", 1)))
Esempio n. 3
0
def filter_pricing_rules_for_qty_amount(qty, rate, pricing_rules, args=None):
    rules = []

    for rule in pricing_rules:
        status = False
        conversion_factor = 1

        if rule.get("uom"):
            conversion_factor = get_conversion_factor(
                rule.item_code, rule.uom).get("conversion_factor", 1)

        if (flt(qty) >= (flt(rule.min_qty) * conversion_factor) and
            (flt(qty) <=
             (rule.max_qty * conversion_factor) if rule.max_qty else True)):
            status = True

        # if user has created item price against the transaction UOM
        if args and rule.get("uom") == args.get("uom"):
            conversion_factor = 1.0

        if status and (
                flt(rate) >= (flt(rule.min_amt) * conversion_factor) and
            (flt(rate) <=
             (rule.max_amt * conversion_factor) if rule.max_amt else True)):
            status = True
        else:
            status = False

        if status:
            rules.append(rule)

    return rules
def get_item_details(item_code, uom=None):
	details = frappe.db.get_value('Item', item_code, ['stock_uom', 'name'], as_dict=1)
	details.uom = uom or details.stock_uom
	if uom:
		details.update(get_conversion_factor(item_code, uom))

	return details
Esempio n. 5
0
def get_product_discount_rule(pricing_rule, item_details, args=None, doc=None):
	free_item = pricing_rule.free_item
	if pricing_rule.same_item and pricing_rule.get("apply_on") != 'Transaction':
		free_item = item_details.item_code or args.item_code

	if not free_item:
		frappe.throw(_("Free item not set in the pricing rule {0}")
			.format(get_link_to_form("Pricing Rule", pricing_rule.name)))

	item_details.free_item_data = {
		'item_code': free_item,
		'qty': pricing_rule.free_qty or 1,
		'rate': pricing_rule.free_item_rate or 0,
		'price_list_rate': pricing_rule.free_item_rate or 0,
		'is_free_item': 1
	}

	item_data = frappe.get_cached_value('Item', free_item, ['item_name',
		'description', 'stock_uom'], as_dict=1)

	item_details.free_item_data.update(item_data)
	item_details.free_item_data['uom'] = pricing_rule.free_item_uom or item_data.stock_uom
	item_details.free_item_data['conversion_factor'] = get_conversion_factor(free_item,
		item_details.free_item_data['uom']).get("conversion_factor", 1)

	if item_details.get("parenttype") == 'Purchase Order':
		item_details.free_item_data['schedule_date'] = doc.schedule_date if doc else today()

	if item_details.get("parenttype") == 'Sales Order':
		item_details.free_item_data['delivery_date'] = doc.delivery_date if doc else today()
Esempio n. 6
0
	def update_valuation_rate(self, reset_outgoing_rate=True):
		"""
		item_tax_amount is the total tax amount applied on that item
		stored for valuation

		TODO: rename item_tax_amount to valuation_tax_amount
		"""
		stock_and_asset_items = []
		stock_and_asset_items = self.get_stock_items() + self.get_asset_items()

		stock_and_asset_items_qty, stock_and_asset_items_amount = 0, 0
		last_item_idx = 1
		for d in self.get("items"):
			if d.item_code and d.item_code in stock_and_asset_items:
				stock_and_asset_items_qty += flt(d.qty)
				stock_and_asset_items_amount += flt(d.base_net_amount)
				last_item_idx = d.idx

		total_valuation_amount = sum(
			flt(d.base_tax_amount_after_discount_amount)
			for d in self.get("taxes")
			if d.category in ["Valuation", "Valuation and Total"]
		)

		valuation_amount_adjustment = total_valuation_amount
		for i, item in enumerate(self.get("items")):
			if item.item_code and item.qty and item.item_code in stock_and_asset_items:
				item_proportion = (
					flt(item.base_net_amount) / stock_and_asset_items_amount
					if stock_and_asset_items_amount
					else flt(item.qty) / stock_and_asset_items_qty
				)

				if i == (last_item_idx - 1):
					item.item_tax_amount = flt(
						valuation_amount_adjustment, self.precision("item_tax_amount", item)
					)
				else:
					item.item_tax_amount = flt(
						item_proportion * total_valuation_amount, self.precision("item_tax_amount", item)
					)
					valuation_amount_adjustment -= item.item_tax_amount

				self.round_floats_in(item)
				if flt(item.conversion_factor) == 0.0:
					item.conversion_factor = (
						get_conversion_factor(item.item_code, item.uom).get("conversion_factor") or 1.0
					)

				qty_in_stock_uom = flt(item.qty * item.conversion_factor)
				item.rm_supp_cost = self.get_supplied_items_cost(item.name, reset_outgoing_rate)
				item.valuation_rate = (
					item.base_net_amount
					+ item.item_tax_amount
					+ item.rm_supp_cost
					+ flt(item.landed_cost_voucher_amount)
				) / qty_in_stock_uom
			else:
				item.valuation_rate = 0.0
Esempio n. 7
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_valuation_rate(self, parentfield):
        """
			item_tax_amount is the total tax amount applied on that item
			stored for valuation

			TODO: rename item_tax_amount to valuation_tax_amount
		"""
        stock_items = self.get_stock_items()

        stock_items_qty, stock_items_amount = 0, 0
        last_stock_item_idx = 1
        for d in self.get(parentfield):
            if d.item_code and d.item_code in stock_items:
                stock_items_qty += flt(d.qty)
                stock_items_amount += flt(d.base_net_amount)
                last_stock_item_idx = d.idx

        total_valuation_amount = sum([
            flt(d.base_tax_amount_after_discount_amount)
            for d in self.get("taxes")
            if d.category in ["Valuation", "Valuation and Total"]
        ])

        valuation_amount_adjustment = total_valuation_amount
        for i, item in enumerate(self.get(parentfield)):
            if item.item_code and item.qty and item.item_code in stock_items:
                item_proportion = flt(item.base_net_amount) / stock_items_amount if stock_items_amount \
                 else flt(item.qty) / stock_items_qty

                if i == (last_stock_item_idx - 1):
                    item.item_tax_amount = flt(
                        valuation_amount_adjustment,
                        self.precision("item_tax_amount", item))
                else:
                    item.item_tax_amount = flt(
                        item_proportion * total_valuation_amount,
                        self.precision("item_tax_amount", item))
                    valuation_amount_adjustment -= item.item_tax_amount

                self.round_floats_in(item)
                if flt(item.conversion_factor) == 0:
                    item.conversion_factor = get_conversion_factor(
                        item.item_code,
                        item.uom).get("conversion_factor") or 1.0

                qty_in_stock_uom = flt(item.qty * item.conversion_factor)
                rm_supp_cost = flt(
                    item.rm_supp_cost
                ) if self.doctype == "Purchase Receipt" else 0.0

                landed_cost_voucher_amount = flt(item.landed_cost_voucher_amount) \
                 if self.doctype == "Purchase Receipt" else 0.0

                item.valuation_rate = (
                    (item.base_net_amount + item.item_tax_amount +
                     rm_supp_cost + landed_cost_voucher_amount) /
                    qty_in_stock_uom)
            else:
                item.valuation_rate = 0.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)
Esempio n. 10
0
	def update_stock_qty(self):
		for m in self.get('items'):
			if not m.conversion_factor:
				m.conversion_factor = flt(get_conversion_factor(m.item_code, m.uom)['conversion_factor'])
			if m.uom and m.qty:
				m.stock_qty = flt(m.conversion_factor)*flt(m.qty)
			if not m.uom and m.stock_uom:
				m.uom = m.stock_uom
				m.qty = m.stock_qty
Esempio n. 11
0
	def update_stock_qty(self):
		for m in self.get('items'):
			if not m.conversion_factor:
				m.conversion_factor = flt(get_conversion_factor(m.item_code, m.uom)['conversion_factor'])
			if m.uom and m.qty:
				m.stock_qty = flt(m.conversion_factor)*flt(m.qty)
			if not m.uom and m.stock_uom:
				m.uom = m.stock_uom
				m.qty = m.stock_qty
Esempio n. 12
0
	def get_uom_details(self, args):
		conversion_factor = get_conversion_factor(args.get("item_code"), args.get("uom")).get("conversion_factor")

		if not conversion_factor:
			frappe.msgprint(_("UOM coversion factor required for UOM: {0} in Item: {1}")
				.format(args.get("uom"), args.get("item_code")))
			ret = {'uom' : ''}
		else:
			ret = {
				'conversion_factor'		: flt(conversion_factor),
				'transfer_qty'			: flt(args.get("qty")) * flt(conversion_factor)
			}
		return ret
	def get_uom_details(self, args):
		conversion_factor = get_conversion_factor(args.get("item_code"), args.get("uom")).get("conversion_factor")

		if not conversion_factor:
			frappe.msgprint(_("UOM coversion factor required for UOM: {0} in Item: {1}")
				.format(args.get("uom"), args.get("item_code")))
			ret = {'uom' : ''}
		else:
			ret = {
				'conversion_factor'		: flt(conversion_factor),
				'transfer_qty'			: flt(args.get("qty")) * flt(conversion_factor)
			}
		return ret
Esempio n. 14
0
def set_sales_order_defaults(parent_doctype, parent_doctype_name, child_docname, item_code):
	"""
	Returns a Sales Order Item child item containing the default values
	"""
	p_doctype = frappe.get_doc(parent_doctype, parent_doctype_name)
	child_item = frappe.new_doc('Sales Order Item', p_doctype, child_docname)
	item = frappe.get_doc("Item", item_code)
	child_item.item_code = item.item_code
	child_item.item_name = item.item_name
	child_item.description = item.description
	child_item.reqd_by_date = p_doctype.delivery_date
	child_item.uom = item.stock_uom
	child_item.conversion_factor = get_conversion_factor(item_code, item.stock_uom).get("conversion_factor") or 1.0
	return child_item
Esempio n. 15
0
def set_collect_production_item_defaults(parent_doctype, parent_doctype_name, child_docname, item_code):
	"""
	Returns a Collect Production Item Materials containing the default values
	"""
	p_doctype = frappe.get_doc(parent_doctype, parent_doctype_name)
	child_item = frappe.new_doc('Collect Production Item Materials', p_doctype, child_docname)
	item = frappe.get_doc("Item", item_code)
	child_item.item_code = item.item_code
	child_item.item_name = item.item_name
	child_item.description = item.description
	child_item.uom = item.stock_uom
	child_item.stock_uom = item.stock_uom
	child_item.rate = 0
	child_item.conversion_factor = get_conversion_factor(item_code, item.stock_uom).get("conversion_factor") or 1.0
	return child_item
Esempio n. 16
0
def get_uom_details(item_code, uom):
    """Returns dict `{"conversion_factor": [value], "transfer_qty": qty * [value]}`

	:param args: dict with `item_code`, `uom` and `qty`"""
    conversion_factor = get_conversion_factor(item_code,
                                              uom).get("conversion_factor")

    if not conversion_factor:
        frappe.msgprint(
            _("UOM coversion factor required for UOM: {0} in Item: {1}").
            format(uom, item_code))
        ret = {'transfer_uom': ''}
    else:
        ret = {'conversion_factor': flt(conversion_factor)}
    return ret
Esempio n. 17
0
	def update_valuation_rate(self, parentfield):
		"""
			item_tax_amount is the total tax amount applied on that item
			stored for valuation

			TODO: rename item_tax_amount to valuation_tax_amount
		"""
		stock_items = self.get_stock_items()

		stock_items_qty, stock_items_amount = 0, 0
		last_stock_item_idx = 1
		for d in self.get(parentfield):
			if d.item_code and d.item_code in stock_items:
				stock_items_qty += flt(d.qty)
				stock_items_amount += flt(d.base_net_amount)
				last_stock_item_idx = d.idx

		total_valuation_amount = sum([flt(d.base_tax_amount_after_discount_amount) for d in self.get("taxes")
			if d.category in ["Valuation", "Valuation and Total"]])

		valuation_amount_adjustment = total_valuation_amount
		for i, item in enumerate(self.get(parentfield)):
			if item.item_code and item.qty and item.item_code in stock_items:
				item_proportion = flt(item.base_net_amount) / stock_items_amount if stock_items_amount \
					else flt(item.qty) / stock_items_qty

				if i == (last_stock_item_idx - 1):
					item.item_tax_amount = flt(valuation_amount_adjustment,
						self.precision("item_tax_amount", item))
				else:
					item.item_tax_amount = flt(item_proportion * total_valuation_amount,
						self.precision("item_tax_amount", item))
					valuation_amount_adjustment -= item.item_tax_amount

				self.round_floats_in(item)

				item.conversion_factor = get_conversion_factor(item.item_code, item.uom).get("conversion_factor") or 1.0

				qty_in_stock_uom = flt(item.qty * item.conversion_factor)
				rm_supp_cost = flt(item.rm_supp_cost) if self.doctype=="Purchase Receipt" else 0.0

				landed_cost_voucher_amount = flt(item.landed_cost_voucher_amount) \
					if self.doctype == "Purchase Receipt" else 0.0

				item.valuation_rate = ((item.base_net_amount + item.item_tax_amount + rm_supp_cost
					 + landed_cost_voucher_amount) / qty_in_stock_uom)
			else:
				item.valuation_rate = 0.0
Esempio n. 18
0
	def calculate_total_qty(self):
		
		
		from erpnext.stock.get_item_details import get_conversion_factor
		
		total_qty = 0
		qty_txt = ""
		item_dict = {}
		import copy
		
		if self.get("items"):
			new_list = copy.deepcopy(self.get("items"))
			for item in new_list:
				uom = item.uom
				qty = item.qty
				
				if self.stock_uom == uom:
					if item_dict.has_key(uom):
						item_dict[uom].qty += qty
					else:
						item_dict[uom] = item
				else:
					conversion_factor = get_conversion_factor(self.item_code, uom).get("conversion_factor") or 1
					if conversion_factor == 1:
						if item_dict.has_key(uom):
							item_dict[uom].qty += qty
						else:
							item_dict[uom] = item
					else:
						conversion_factor = flt(1/conversion_factor)
						new_qty = flt(qty) / flt(conversion_factor)
						if item_dict.has_key(self.stock_uom):
							item_dict[self.stock_uom].qty += new_qty
						else:
							item_dict[self.stock_uom] = item
							item_dict[self.stock_uom].qty = new_qty
				
		
			for key in item_dict:
				d = item_dict[key]
				display_uom = str(key)
				display_qty = str(d.qty)
				qty_txt += str(display_qty) + ' ' + str(display_uom) + '<br>'
				total_qty = total_qty + flt(d.qty)
		else:
			qty_txt = "0"

		self.total_qty = qty_txt
Esempio n. 19
0
def get_uom_details(item_code, uom, qty):
	"""Returns dict `{"conversion_factor": [value], "transfer_qty": qty * [value]}`

	:param args: dict with `item_code`, `uom` and `qty`"""
	conversion_factor = get_conversion_factor(item_code, uom).get("conversion_factor")

	if not conversion_factor:
		frappe.msgprint(_("UOM coversion factor required for UOM: {0} in Item: {1}")
			.format(uom, item_code))
		ret = {'uom' : ''}
	else:
		ret = {
			'conversion_factor'		: flt(conversion_factor),
			'transfer_qty'			: flt(qty) * flt(conversion_factor)
		}
	return ret
Esempio n. 20
0
def set_purchase_order_defaults(parent_doctype, parent_doctype_name, child_docname, item_code):
	"""
	Returns a Purchase Order Item child item containing the default values
	"""
	p_doctype = frappe.get_doc(parent_doctype, parent_doctype_name)
	child_item = frappe.new_doc('Purchase Order Item', p_doctype, child_docname)
	item = frappe.get_doc("Item", item_code)
	child_item.item_code = item.item_code
	child_item.item_name = item.item_name
	child_item.description = item.description
	child_item.schedule_date = p_doctype.schedule_date
	child_item.uom = item.stock_uom
	child_item.conversion_factor = get_conversion_factor(item_code, item.stock_uom).get("conversion_factor") or 1.0
	child_item.base_rate = 1 # Initiallize value will update in parent validation
	child_item.base_amount = 1 # Initiallize value will update in parent validation
	return child_item
Esempio n. 21
0
def change_item_code(sales_order, so_detail, new_item_code, old_item_code):
    from erpnext.api2 import customerPriceList
    from erpnext.stock.get_item_details import get_conversion_factor

    doc = frappe.get_doc("Sales Order", sales_order)
    row = filter(lambda d: d.name == so_detail, doc.items)
    if not row:
        frappe.throw(
            _("Could not find Item {0} in {1}").format(old_item_code,
                                                       sales_order))
    else:
        row = row[0]

    rate = flt(
        customerPriceList(row.idx, row.idx, doc.customer, new_item_code,
                          doc.selling_price_list)[0].get('price'))
    item_details = frappe.db.get_value(
        "Item",
        new_item_code, [
            "item_name", "description", "sale_pallets", "gross_weight",
            "sales_uom", "stock_uom", "hst", "weight_per_unit", "weight_uom",
            "cost_center"
        ],
        as_dict=1)

    row.update(item_details)
    row.item_code = new_item_code
    row.rate = rate
    row.uom = item_details.sales_uom or item_details.stock_uom
    row.conversion_factor = get_conversion_factor(new_item_code,
                                                  row.uom)['conversion_factor']
    row.weight_lbs = item_details.weight_per_unit
    row.gross_weight_lbs = item_details.gross_weight
    row.weight_kgs = flt(item_details.weight_per_unit * 0.45359237, 2)
    row.hst = 1 if item_details.hst == "Yes" else 0

    doc.total_boxes = 0
    doc.total_pallets = 0
    doc.total_gross_weight_lbs = 0
    for d in doc.items:
        doc.total_boxes += flt(d.qty)
        doc.total_gross_weight_lbs += flt(d.qty) * flt(d.gross_weight_lbs)
        if flt(d.sale_pallets) > 0:
            doc.total_pallets += flt(d.qty) / flt(d.sale_pallets)

    doc.total_weight_kg = flt(doc.total_gross_weight_lbs * 0.45359237, 2)
    doc.save()
Esempio n. 22
0
def get_product_discount_rule(pricing_rule, item_details, args=None, doc=None):
    free_item = pricing_rule.free_item
    if pricing_rule.same_item and pricing_rule.get(
            "apply_on") != "Transaction":
        free_item = item_details.item_code or args.item_code

    if not free_item:
        frappe.throw(
            _("Free item not set in the pricing rule {0}").format(
                get_link_to_form("Pricing Rule", pricing_rule.name)))

    qty = pricing_rule.free_qty or 1
    if pricing_rule.is_recursive:
        transaction_qty = args.get("qty") if args else doc.total_qty
        if transaction_qty:
            qty = flt(transaction_qty) * qty

    free_item_data_args = {
        "item_code": free_item,
        "qty": qty,
        "pricing_rules": pricing_rule.name,
        "rate": pricing_rule.free_item_rate or 0,
        "price_list_rate": pricing_rule.free_item_rate or 0,
        "is_free_item": 1,
    }

    item_data = frappe.get_cached_value(
        "Item",
        free_item, ["item_name", "description", "stock_uom"],
        as_dict=1)

    free_item_data_args.update(item_data)
    free_item_data_args[
        "uom"] = pricing_rule.free_item_uom or item_data.stock_uom
    free_item_data_args["conversion_factor"] = get_conversion_factor(
        free_item, free_item_data_args["uom"]).get("conversion_factor", 1)

    if item_details.get("parenttype") == "Purchase Order":
        free_item_data_args[
            "schedule_date"] = doc.schedule_date if doc else today()

    if item_details.get("parenttype") == "Sales Order":
        free_item_data_args[
            "delivery_date"] = doc.delivery_date if doc else today()

    item_details.free_item_data.append(free_item_data_args)
Esempio n. 23
0
def set_sales_order_defaults(parent_doctype, parent_doctype_name, child_docname, trans_item):
	"""
	Returns a Sales Order Item child item containing the default values
	"""
	p_doc = frappe.get_doc(parent_doctype, parent_doctype_name)
	child_item = frappe.new_doc('Sales Order Item', p_doc, child_docname)
	item = frappe.get_doc("Item", trans_item.get('item_code'))
	child_item.item_code = item.item_code
	child_item.item_name = item.item_name
	child_item.description = item.description
	child_item.delivery_date = trans_item.get('delivery_date') or p_doc.delivery_date
	child_item.uom = item.stock_uom
	child_item.conversion_factor = get_conversion_factor(item.item_code, item.stock_uom).get("conversion_factor") or 1.0
	child_item.warehouse = get_item_warehouse(item, p_doc, overwrite_warehouse=True)
	if not child_item.warehouse:
		frappe.throw(_("Cannot find {} for item {}. Please set the same in Item Master or Stock Settings.")
			.format(frappe.bold("default warehouse"), frappe.bold(item.item_code)))
	return child_item
def create_putaway_rule(**args):
	args = frappe._dict(args)
	putaway = frappe.new_doc("Putaway Rule")

	putaway.disable = args.disable or 0
	putaway.company = args.company or "_Test Company"
	putaway.item_code = args.item or args.item_code or "_Test Item"
	putaway.warehouse = args.warehouse
	putaway.priority = args.priority or 1
	putaway.capacity = args.capacity or 1
	putaway.stock_uom = frappe.db.get_value("Item", putaway.item_code, "stock_uom")
	putaway.uom = args.uom or putaway.stock_uom
	putaway.conversion_factor = get_conversion_factor(putaway.item_code, putaway.uom)['conversion_factor']

	if not args.do_not_save:
		putaway.save()

	return putaway
Esempio n. 25
0
    def get_uom_details(self, args):
        """Returns dict `{"conversion_factor": [value], "transfer_qty": qty * [value]}`

		:param args: dict with `item_code`, `uom` and `qty`"""
        conversion_factor = get_conversion_factor(args.get("item_code"), args.get("uom")).get("conversion_factor")

        if not conversion_factor:
            frappe.msgprint(
                _("UOM coversion factor required for UOM: {0} in Item: {1}").format(
                    args.get("uom"), args.get("item_code")
                )
            )
            ret = {"uom": ""}
        else:
            ret = {
                "conversion_factor": flt(conversion_factor),
                "transfer_qty": flt(args.get("qty")) * flt(conversion_factor),
            }
        return ret
Esempio n. 26
0
def update_item(obj, target, source_parent):
    item = frappe.get_doc("Item", obj.item_code)
    uom = item.purchase_uom if item.purchase_uom else item.stock_uom
    if uom != obj.uom:
        from erpnext.stock.get_item_details import get_conversion_factor
        conversion_factor = flt(
            get_conversion_factor(obj.item_code, uom)['conversion_factor'])
        if conversion_factor == 0:
            frappe.throw(
                """Debe completar el apartado 'Unidades de medida' del producto <a href='#Form/Item/{0}' target='_blank'>{1}</a>, 
				ya que est&aacute; tratando de convertir de {2} a {3} 
				sin especificar el factor de conversi&oacute;n. 
				<br><br>-> <a class='btn btn-warning' href='#Form/Item/{0}' target='_blank'>Abrir {1}</a>
				&nbsp;&nbsp; <a class='btn btn-default' href='https://docs.google.com/document/d/1pHBYzlVx7vL9XSLt3o0cAyqsoycF3ZE5Zr6vUTyR4Dc/edit?usp=sharing' target='_blank'>Manual de ayuda</a>"""
                .format(item.item_code, item.item_code, uom, item.stock_uom))
        target.uom = uom
        target.qty = (flt(obj.qty) / conversion_factor) - (
            flt(obj.ordered_qty) / conversion_factor)
        target.stock_qty = target.qty * conversion_factor
        target.conversion_factor = conversion_factor
    else:
        target.conversion_factor = 1
        target.qty = flt(obj.qty) - flt(obj.ordered_qty)
        target.stock_qty = target.qty
Esempio n. 27
0
def update_child_qty_rate(parent_doctype,
                          trans_items,
                          parent_doctype_name,
                          child_docname="items"):
    def check_doc_permissions(doc, perm_type="create"):
        try:
            doc.check_permission(perm_type)
        except frappe.PermissionError:
            actions = {"create": "add", "write": "update"}

            frappe.throw(
                _("You do not have permissions to {} items in a {}.").format(
                    actions[perm_type], parent_doctype),
                title=_("Insufficient Permissions"),
            )

    def validate_workflow_conditions(doc):
        workflow = get_workflow_name(doc.doctype)
        if not workflow:
            return

        workflow_doc = frappe.get_doc("Workflow", workflow)
        current_state = doc.get(workflow_doc.workflow_state_field)
        roles = frappe.get_roles()

        transitions = []
        for transition in workflow_doc.transitions:
            if transition.next_state == current_state and transition.allowed in roles:
                if not is_transition_condition_satisfied(transition, doc):
                    continue
                transitions.append(transition.as_dict())

        if not transitions:
            frappe.throw(
                _("You are not allowed to update as per the conditions set in {} Workflow."
                  ).format(get_link_to_form("Workflow", workflow)),
                title=_("Insufficient Permissions"),
            )

    def get_new_child_item(item_row):
        child_doctype = "Sales Order Item" if parent_doctype == "Sales Order" else "Purchase Order Item"
        return set_order_defaults(parent_doctype, parent_doctype_name,
                                  child_doctype, child_docname, item_row)

    def validate_quantity(child_item, d):
        if parent_doctype == "Sales Order" and flt(d.get("qty")) < flt(
                child_item.delivered_qty):
            frappe.throw(_("Cannot set quantity less than delivered quantity"))

        if parent_doctype == "Purchase Order" and flt(d.get("qty")) < flt(
                child_item.received_qty):
            frappe.throw(_("Cannot set quantity less than received quantity"))

    data = json.loads(trans_items)

    sales_doctypes = [
        "Sales Order", "Sales Invoice", "Delivery Note", "Quotation"
    ]
    parent = frappe.get_doc(parent_doctype, parent_doctype_name)

    check_doc_permissions(parent, "write")
    validate_and_delete_children(parent, data)

    for d in data:
        new_child_flag = False

        if not d.get("item_code"):
            # ignore empty rows
            continue

        if not d.get("docname"):
            new_child_flag = True
            check_doc_permissions(parent, "create")
            child_item = get_new_child_item(d)
        else:
            check_doc_permissions(parent, "write")
            child_item = frappe.get_doc(parent_doctype + " Item",
                                        d.get("docname"))

            prev_rate, new_rate = flt(child_item.get("rate")), flt(
                d.get("rate"))
            prev_qty, new_qty = flt(child_item.get("qty")), flt(d.get("qty"))
            prev_con_fac, new_con_fac = flt(
                child_item.get("conversion_factor")), flt(
                    d.get("conversion_factor"))
            prev_uom, new_uom = child_item.get("uom"), d.get("uom")

            if parent_doctype == "Sales Order":
                prev_date, new_date = child_item.get("delivery_date"), d.get(
                    "delivery_date")
            elif parent_doctype == "Purchase Order":
                prev_date, new_date = child_item.get("schedule_date"), d.get(
                    "schedule_date")

            rate_unchanged = prev_rate == new_rate
            qty_unchanged = prev_qty == new_qty
            uom_unchanged = prev_uom == new_uom
            conversion_factor_unchanged = prev_con_fac == new_con_fac
            date_unchanged = (prev_date == getdate(new_date)
                              if prev_date and new_date else False
                              )  # in case of delivery note etc
            if (rate_unchanged and qty_unchanged
                    and conversion_factor_unchanged and uom_unchanged
                    and date_unchanged):
                continue

        validate_quantity(child_item, d)

        child_item.qty = flt(d.get("qty"))
        rate_precision = child_item.precision("rate") or 2
        conv_fac_precision = child_item.precision("conversion_factor") or 2
        qty_precision = child_item.precision("qty") or 2

        if flt(child_item.billed_amt, rate_precision) > flt(
                flt(d.get("rate"), rate_precision) *
                flt(d.get("qty"), qty_precision), rate_precision):
            frappe.throw(
                _("Row #{0}: Cannot set Rate if amount is greater than billed amount for Item {1}."
                  ).format(child_item.idx, child_item.item_code))
        else:
            child_item.rate = flt(d.get("rate"), rate_precision)

        if d.get("conversion_factor"):
            if child_item.stock_uom == child_item.uom:
                child_item.conversion_factor = 1
            else:
                child_item.conversion_factor = flt(d.get("conversion_factor"),
                                                   conv_fac_precision)

        if d.get("uom"):
            child_item.uom = d.get("uom")
            conversion_factor = flt(
                get_conversion_factor(child_item.item_code,
                                      child_item.uom).get("conversion_factor"))
            child_item.conversion_factor = (flt(d.get("conversion_factor"),
                                                conv_fac_precision)
                                            or conversion_factor)

        if d.get("delivery_date") and parent_doctype == "Sales Order":
            child_item.delivery_date = d.get("delivery_date")

        if d.get("schedule_date") and parent_doctype == "Purchase Order":
            child_item.schedule_date = d.get("schedule_date")

        if flt(child_item.price_list_rate):
            if flt(child_item.rate) > flt(child_item.price_list_rate):
                #  if rate is greater than price_list_rate, set margin
                #  or set discount
                child_item.discount_percentage = 0

                if parent_doctype in sales_doctypes:
                    child_item.margin_type = "Amount"
                    child_item.margin_rate_or_amount = flt(
                        child_item.rate - child_item.price_list_rate,
                        child_item.precision("margin_rate_or_amount"))
                    child_item.rate_with_margin = child_item.rate
            else:
                child_item.discount_percentage = flt(
                    (1 -
                     flt(child_item.rate) / flt(child_item.price_list_rate)) *
                    100.0,
                    child_item.precision("discount_percentage"),
                )
                child_item.discount_amount = flt(
                    child_item.price_list_rate) - flt(child_item.rate)

                if parent_doctype in sales_doctypes:
                    child_item.margin_type = ""
                    child_item.margin_rate_or_amount = 0
                    child_item.rate_with_margin = 0

        child_item.flags.ignore_validate_update_after_submit = True
        if new_child_flag:
            parent.load_from_db()
            child_item.idx = len(parent.items) + 1
            child_item.insert()
        else:
            child_item.save()

    parent.reload()
    parent.flags.ignore_validate_update_after_submit = True
    parent.set_qty_as_per_stock_uom()
    parent.calculate_taxes_and_totals()
    parent.set_total_in_words()
    if parent_doctype == "Sales Order":
        make_packing_list(parent)
        parent.set_gross_profit()
    frappe.get_doc("Authorization Control").validate_approving_authority(
        parent.doctype, parent.company, parent.base_grand_total)

    parent.set_payment_schedule()
    if parent_doctype == "Purchase Order":
        parent.validate_minimum_order_qty()
        parent.validate_budget()
        if parent.is_against_so():
            parent.update_status_updater()
    else:
        parent.check_credit_limit()

    # reset index of child table
    for idx, row in enumerate(parent.get(child_docname), start=1):
        row.idx = idx

    parent.save()

    if parent_doctype == "Purchase Order":
        update_last_purchase_rate(parent, is_submit=1)
        parent.update_prevdoc_status()
        parent.update_requested_qty()
        parent.update_ordered_qty()
        parent.update_ordered_and_reserved_qty()
        parent.update_receiving_percentage()
        if parent.is_subcontracted == "Yes":
            parent.update_reserved_qty_for_subcontract()
            parent.create_raw_materials_supplied("supplied_items")
            parent.save()
    else:
        parent.update_reserved_qty()
        parent.update_project()
        parent.update_prevdoc_status("submit")
        parent.update_delivery_status()

    parent.reload()
    validate_workflow_conditions(parent)

    parent.update_blanket_order()
    parent.update_billing_percentage()
    parent.set_status()
Esempio n. 28
0
def convert_to_liters(item, quantity):
        uom = get_conversion_factor(item.item_code, "Litre")
        return quantity * uom['conversion_factor']
Esempio n. 29
0
	def make_stock_entries(self):
	
		from erpnext.stock.stock_ledger import NegativeStockError
		from erpnext.stock.doctype.stock_entry.stock_entry import IncorrectValuationRateError, \
			DuplicateEntryForProductionOrderError, OperationsNotCompleteError, get_best_warehouse
		
		
		stock_entry_list = []	
		items = self.get("items")
		if not items:
			return False
		
		for fg_item in items:
		
			prev_stock_entry = frappe.db.sql("""select name,docstatus from `tabStock Entry` where custom_production_order=%s and manufactured_item=%s and docstatus < 2""", (self.name,fg_item.item_code), as_dict = 1)
			if prev_stock_entry:
				break
			
			if not fg_item.depth or not fg_item.width or not fg_item.height:
				frappe.throw(_("Item {0} needs all dimensions").format(fg_item.item_code))
				
			if not fg_item.bom:
					frappe.throw(_("Item {0} has missing bom").format(fg_item.item_code))
			elif fg_item.bom:
				bom = frappe.get_doc("BOM", fg_item.bom)
				
			from erpnext.stock.utils import get_default_warehouse
			default_warehouses = get_default_warehouse(company = self.company)
		
			try:	
				stock_entry = frappe.new_doc("Stock Entry")
				stock_entry.purpose = "Manufacture"
				# stock_entry.sales_order = sales_order_no
				
				if self.reference_doctype == "Delivery Note":
					stock_entry.delivery_note_no = self.reference_name
				
				stock_entry.project = self.project
				stock_entry.company = self.company
				stock_entry.custom_production_order = self.name
				stock_entry.from_bom = 0
				stock_entry.use_multi_level_bom = 0
				stock_entry.manufactured_item = fg_item.item_code
				stock_entry.remarks = self.remarks
				
				stock_entry.posting_date = nowdate()
				stock_entry.posting_time = nowtime()
				
				conversion_factor = get_conversion_factor(fg_item.item_code,fg_item.uom).get("conversion_factor")
				if not conversion_factor:
					conversion_factor = 1
				
				stock_entry.fg_completed_qty = flt(fg_item.qty) * flt(conversion_factor)
				
				stock_entry.from_warehouse = default_warehouses.get("source_warehouse")
				stock_entry.to_warehouse = default_warehouses.get("fg_warehouse")
				stock_entry.title = 'Manufacture {0}'.format(fg_item.item_code)
					
				if fg_item.uom == bom.uom:
					qty = fg_item.qty
				else:
					conversion_factor = get_conversion_factor_between_two_units(fg_item.item_code,fg_item.uom, bom.uom).get("conversion_factor")
			
					if not conversion_factor:
						conversion_factor = 1
						frappe.msgprint(_("Item {0} has no conversion factor for {1}").format(fg_item.item_code, bom.uom))
			
			
					qty = flt(fg_item.qty) * flt(conversion_factor)
				
				depthOriginal = convert_units(fg_item.depthunit,fg_item.depth)
				widthOriginal = convert_units(fg_item.widthunit,fg_item.width)
				heightOriginal = convert_units(fg_item.heightunit,fg_item.height)
					
					
				if bom.get("bomitems"):
					updated_builder_items = calculate_builder_items_dimensions(bom.get("bomitems"),fg_item.depth,fg_item.depthunit,fg_item.width,fg_item.widthunit,fg_item.height,fg_item.heightunit)
					merged,summary,unmerged = build_bom_ext(updated_builder_items,qty,depthOriginal,widthOriginal,heightOriginal)

				elif bom.get("items"):
					
					qtyOriginal = bom.quantity
					merged,summary,unmerged = get_material_list(bom.get("items"),qty,qtyOriginal)
				else:
					raise Exception('Represents a hidden bug, do not catch this')
					
				exploded_items,raw_material_cost = self.update_bom_builder(merged)		
				
				for item in exploded_items:
					
					# item = frappe._dict(item)
					best_warehouse,enough_stock = get_best_warehouse(item.item_code,item.stock_qty,stock_entry.from_warehouse,company = stock_entry.company)
					stock_entry.add_to_stock_entry_detail({
						item.item_code: {
							"to_warehouse": "",
							"from_warehouse": best_warehouse,
							"qty": item.stock_qty,
							"item_name": item.item_name,
							"description": item.description,
							"stock_uom": item.stock_uom,
							"expense_account": None,
							"cost_center": None
						}
					})
	
				item_dict = get_item_det(fg_item.item_code)
				
				stock_entry.add_to_stock_entry_detail({
					fg_item.item_code: {
						"to_warehouse": stock_entry.to_warehouse,
						"from_warehouse": "",
						"qty": qty,
						"item_name": item_dict['item_name'],
						"description": item_dict['description'],
						"stock_uom": item_dict['stock_uom'],
						"expense_account": None,
						"cost_center": None,
						"basic_rate" : raw_material_cost
					}
				})
				

				# additional_costs = []
				# if purpose=="Manufacture" and add_operating_costs:
					
					# additional_costs.append({
						# "description": "Operating Cost as per Production Order / BOM",
						# "amount": self.operating_cost * flt(qty)
					# })
					
					# stock_entry.set("additional_costs", additional_costs)	
			

				stock_entry.get_stock_and_rate()
				# stock_entry.get_items()
				stock_entry.insert()
				frappe.db.commit()
			
				# if submit:
					# stock_entry.submit()
				link = ['<a href="#Form/Stock Entry/{0}">{0}</a>'.format(stock_entry.name)]
				stock_entry_list.append(link)
			
		
			except (NegativeStockError, IncorrectValuationRateError, DuplicateEntryForProductionOrderError,
				OperationsNotCompleteError,OperationsNotCompleteError):
				frappe.db.rollback()
			except Exception as error:
				frappe.db.rollback()
				
		if len(stock_entry_list) > 0:
			return True
		else:
			return False
Esempio n. 30
0
def _get_basic_details(args, item):
    """
    :param args: {
                    "item_code": "",
                    "warehouse": None,
                    "customer": "",
                    "conversion_rate": 1.0,
                    "selling_price_list": None,
                    "price_list_currency": None,
                    "price_list_uom_dependant": None,
                    "plc_conversion_rate": 1.0,
                    "doctype": "",
                    "name": "",
                    "supplier": None,
                    "transaction_date": None,
                    "conversion_rate": 1.0,
                    "buying_price_list": None,
                    "is_subcontracted": "Yes" / "No",
                    "ignore_pricing_rule": 0/1
                    "project": "",
                    barcode: "",
                    serial_no: "",
                    currency: "",
                    update_stock: "",
                    price_list: "",
                    company: "",
                    order_type: "",
                    is_pos: "",
                    project: "",
                    qty: "",
                    stock_qty: "",
                    conversion_factor: ""
            }
    :param item: `item_code` of Item object
    :return: frappe._dict
    """

    if not item:
        item = frappe.get_doc("Item", args.get("item_code"))

    if item.variant_of:
        item.update_template_tables()

    from frappe.defaults import get_user_default_as_list

    user_default_warehouse_list = get_user_default_as_list("Warehouse")
    user_default_warehouse = (user_default_warehouse_list[0]
                              if len(user_default_warehouse_list) == 1 else "")

    item_defaults = get_item_defaults(item.name, args.company)
    item_group_defaults = get_item_group_defaults(item.name, args.company)

    warehouse = (args.get("set_warehouse") or user_default_warehouse
                 or item_defaults.get("default_warehouse")
                 or item_group_defaults.get("default_warehouse")
                 or args.warehouse)

    if not args.get("material_request_type"):
        args["material_request_type"] = frappe.db.get_value(
            "Material Request",
            args.get("name"),
            "material_request_type",
            cache=True)

    # Set the UOM to the Default Sales UOM or Default Purchase UOM if configured in the Item Master
    if not args.uom:
        args.uom = item.purchase_uom if item.purchase_uom else item.stock_uom

    out = frappe._dict({
        "item_code":
        item.name,
        "item_name":
        item.item_name,
        "description":
        cstr(item.description).strip(),
        "image":
        cstr(item.image).strip(),
        "warehouse":
        warehouse,
        "income_account":
        get_default_income_account(args, item_defaults, item_group_defaults),
        "expense_account":
        get_default_expense_account(args, item_defaults, item_group_defaults),
        "cost_center":
        get_default_cost_center(args, item_defaults, item_group_defaults),
        "has_serial_no":
        item.has_serial_no,
        "has_batch_no":
        item.has_batch_no,
        "batch_no":
        None,
        "item_tax_rate":
        json.dumps(dict(
            ([d.tax_type, d.tax_rate] for d in item.get("taxes")))),
        "uom":
        args.uom,
        "min_order_qty":
        flt(item.min_order_qty),
        "qty":
        args.qty or 1.0,
        "stock_qty":
        args.qty or 1.0,
        "price_list_rate":
        0.0,
        "base_price_list_rate":
        0.0,
        "rate":
        0.0,
        "base_rate":
        0.0,
        "amount":
        0.0,
        "base_amount":
        0.0,
        "net_rate":
        0.0,
        "net_amount":
        0.0,
        "discount_percentage":
        0.0,
        "supplier":
        get_default_supplier(args, item_defaults, item_group_defaults),
        "update_stock":
        args.get("update_stock")
        if args.get("doctype") in ["Sales Invoice", "Purchase Invoice"] else 0,
        "delivered_by_supplier":
        item.delivered_by_supplier
        if args.get("doctype") in ["Sales Order", "Sales Invoice"] else 0,
        "is_fixed_asset":
        item.is_fixed_asset,
        "weight_per_unit":
        item.weight_per_unit,
        "weight_uom":
        item.weight_uom,
        "last_purchase_rate":
        item.last_purchase_rate
        if args.get("doctype") in ["Purchase Order"] else 0,
        "transaction_date":
        args.get("transaction_date"),
    })

    if item.get("enable_deferred_revenue") or item.get(
            "enable_deferred_expense"):
        out.update(calculate_service_end_date(args, item))

    # calculate conversion factor
    if item.stock_uom == args.uom:
        out.conversion_factor = 1.0
    else:
        out.conversion_factor = args.conversion_factor or get_conversion_factor(
            item.name, args.uom).get("conversion_factor")

    args.conversion_factor = out.conversion_factor
    out.stock_qty = out.qty * out.conversion_factor

    # calculate last purchase rate
    from erpnext.buying.doctype.purchase_order.purchase_order import (
        item_last_purchase_rate, )

    out.last_purchase_rate = item_last_purchase_rate(args.name,
                                                     args.conversion_rate,
                                                     item.name,
                                                     out.conversion_factor)

    # if default specified in item is for another company, fetch from company
    for d in [
        ["Account", "income_account", "default_income_account"],
        ["Account", "expense_account", "default_expense_account"],
        ["Cost Center", "cost_center", "cost_center"],
        ["Warehouse", "warehouse", ""],
    ]:
        if not out[d[1]]:
            out[d[1]] = (frappe.get_cached_value("Company", args.company, d[2])
                         if d[2] else None)

    for fieldname in ("item_name", "item_group", "barcodes", "brand",
                      "stock_uom"):
        out[fieldname] = item.get(fieldname)

    meta = frappe.get_meta(args.child_doctype)
    if meta.get_field("barcode"):
        update_barcode_value(out)

    return out