blob: 04ee0b3b1ebcffefc46d82884aa405c69f0ed06d [file] [log] [blame]
marination60261852021-04-13 00:39:26 +05301# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
Faris Ansarifd345f82017-10-05 11:17:30 +05302# License: GNU General Public License v3. See license.txt
3
Faris Ansarifd345f82017-10-05 11:17:30 +05304import frappe
Chillar Anand915b3432021-09-02 16:44:59 +05305from frappe.utils import cint, flt, fmt_money, getdate, nowdate
6
Faris Ansarifd345f82017-10-05 11:17:30 +05307from erpnext.accounts.doctype.pricing_rule.pricing_rule import get_pricing_rule_for_item
tundebabzyc14f1f12018-01-27 06:28:29 +01008from erpnext.stock.doctype.batch.batch import get_batch_qty
Faris Ansarifd345f82017-10-05 11:17:30 +05309
marination9fb61ef2022-02-01 00:39:14 +053010
marination60261852021-04-13 00:39:26 +053011def get_web_item_qty_in_stock(item_code, item_warehouse_field, warehouse=None):
Ankush Menat494bd9e2022-03-28 18:52:46 +053012 in_stock, stock_qty = 0, ""
13 template_item_code, is_stock_item = frappe.db.get_value(
14 "Item", item_code, ["variant_of", "is_stock_item"]
15 )
Faris Ansarifd345f82017-10-05 11:17:30 +053016
tundebabzyc14f1f12018-01-27 06:28:29 +010017 if not warehouse:
marination60261852021-04-13 00:39:26 +053018 warehouse = frappe.db.get_value("Website Item", {"item_code": item_code}, item_warehouse_field)
tundebabzyc14f1f12018-01-27 06:28:29 +010019
Faris Ansarifd345f82017-10-05 11:17:30 +053020 if not warehouse and template_item_code and template_item_code != item_code:
Ankush Menat494bd9e2022-03-28 18:52:46 +053021 warehouse = frappe.db.get_value(
22 "Website Item", {"item_code": template_item_code}, item_warehouse_field
23 )
Faris Ansarifd345f82017-10-05 11:17:30 +053024
25 if warehouse:
Ankush Menat494bd9e2022-03-28 18:52:46 +053026 stock_qty = frappe.db.sql(
27 """
Rushabh Mehta708e47a2018-08-08 16:37:31 +053028 select GREATEST(S.actual_qty - S.reserved_qty - S.reserved_qty_for_production - S.reserved_qty_for_sub_contract, 0) / IFNULL(C.conversion_factor, 1)
Britloge3a9b9f2018-03-20 09:58:44 +010029 from tabBin S
30 inner join `tabItem` I on S.item_code = I.Item_code
Rushabh Mehta708e47a2018-08-08 16:37:31 +053031 left join `tabUOM Conversion Detail` C on I.sales_uom = C.uom and C.parent = I.Item_code
Ankush Menat494bd9e2022-03-28 18:52:46 +053032 where S.item_code=%s and S.warehouse=%s""",
33 (item_code, warehouse),
34 )
Faris Ansarifd345f82017-10-05 11:17:30 +053035
Britloge3a9b9f2018-03-20 09:58:44 +010036 if stock_qty:
37 stock_qty = adjust_qty_for_expired_items(item_code, stock_qty, warehouse)
38 in_stock = stock_qty[0][0] > 0 and 1 or 0
tundebabzyc14f1f12018-01-27 06:28:29 +010039
Ankush Menat494bd9e2022-03-28 18:52:46 +053040 return frappe._dict(
41 {"in_stock": in_stock, "stock_qty": stock_qty, "is_stock_item": is_stock_item}
42 )
Faris Ansarifd345f82017-10-05 11:17:30 +053043
tundebabzyc14f1f12018-01-27 06:28:29 +010044
tundebabzy29c81422018-01-31 10:36:31 +010045def adjust_qty_for_expired_items(item_code, stock_qty, warehouse):
Ankush Menat494bd9e2022-03-28 18:52:46 +053046 batches = frappe.get_all("Batch", filters=[{"item": item_code}], fields=["expiry_date", "name"])
tundebabzyc14f1f12018-01-27 06:28:29 +010047 expired_batches = get_expired_batches(batches)
48 stock_qty = [list(item) for item in stock_qty]
Rushabh Mehta708e47a2018-08-08 16:37:31 +053049
tundebabzy29c81422018-01-31 10:36:31 +010050 for batch in expired_batches:
51 if warehouse:
52 stock_qty[0][0] = max(0, stock_qty[0][0] - get_batch_qty(batch, warehouse))
53 else:
54 stock_qty[0][0] = max(0, stock_qty[0][0] - qty_from_all_warehouses(get_batch_qty(batch)))
tundebabzyc14f1f12018-01-27 06:28:29 +010055
tundebabzy29c81422018-01-31 10:36:31 +010056 if not stock_qty[0][0]:
57 break
58
tundebabzyc14f1f12018-01-27 06:28:29 +010059 return stock_qty
60
61
62def get_expired_batches(batches):
63 """
64 :param batches: A list of dict in the form [{'expiry_date': datetime.date(20XX, 1, 1), 'name': 'batch_id'}, ...]
65 """
66 return [b.name for b in batches if b.expiry_date and b.expiry_date <= getdate(nowdate())]
67
68
69def qty_from_all_warehouses(batch_info):
70 """
71 :param batch_info: A list of dict in the form [{u'warehouse': u'Stores - I', u'qty': 0.8}, ...]
72 """
73 qty = 0
74 for batch in batch_info:
75 qty = qty + batch.qty
76
77 return qty
78
Ankush Menat494bd9e2022-03-28 18:52:46 +053079
Faris Ansarifd345f82017-10-05 11:17:30 +053080def get_price(item_code, price_list, customer_group, company, qty=1):
Devin Slauenwhite282fbf42021-12-18 16:03:16 -050081 from erpnext.e_commerce.shopping_cart.cart import get_party
82
Faris Ansarifd345f82017-10-05 11:17:30 +053083 template_item_code = frappe.db.get_value("Item", item_code, "variant_of")
84
85 if price_list:
Ankush Menat494bd9e2022-03-28 18:52:46 +053086 price = frappe.get_all(
87 "Item Price",
88 fields=["price_list_rate", "currency"],
89 filters={"price_list": price_list, "item_code": item_code},
90 )
Faris Ansarifd345f82017-10-05 11:17:30 +053091
92 if template_item_code and not price:
Ankush Menat494bd9e2022-03-28 18:52:46 +053093 price = frappe.get_all(
94 "Item Price",
95 fields=["price_list_rate", "currency"],
96 filters={"price_list": price_list, "item_code": template_item_code},
97 )
Faris Ansarifd345f82017-10-05 11:17:30 +053098
99 if price:
Devin Slauenwhite282fbf42021-12-18 16:03:16 -0500100 party = get_party()
Ankush Menat494bd9e2022-03-28 18:52:46 +0530101 pricing_rule_dict = frappe._dict(
102 {
103 "item_code": item_code,
104 "qty": qty,
105 "stock_qty": qty,
106 "transaction_type": "selling",
107 "price_list": price_list,
108 "customer_group": customer_group,
109 "company": company,
110 "conversion_rate": 1,
111 "for_shopping_cart": True,
112 "currency": frappe.db.get_value("Price List", price_list, "currency"),
113 }
114 )
Devin Slauenwhite282fbf42021-12-18 16:03:16 -0500115
116 if party and party.doctype == "Customer":
117 pricing_rule_dict.update({"customer": party.name})
118
119 pricing_rule = get_pricing_rule_for_item(pricing_rule_dict)
marination60261852021-04-13 00:39:26 +0530120 price_obj = price[0]
Faris Ansarifd345f82017-10-05 11:17:30 +0530121
122 if pricing_rule:
marination60261852021-04-13 00:39:26 +0530123 # price without any rules applied
124 mrp = price_obj.price_list_rate or 0
125
Faris Ansarifd345f82017-10-05 11:17:30 +0530126 if pricing_rule.pricing_rule_for == "Discount Percentage":
marination1d949142021-04-20 21:54:52 +0530127 price_obj.discount_percent = pricing_rule.discount_percentage
marination60261852021-04-13 00:39:26 +0530128 price_obj.formatted_discount_percent = str(flt(pricing_rule.discount_percentage, 0)) + "%"
Ankush Menat494bd9e2022-03-28 18:52:46 +0530129 price_obj.price_list_rate = flt(
130 price_obj.price_list_rate * (1.0 - (flt(pricing_rule.discount_percentage) / 100.0))
131 )
Faris Ansarifd345f82017-10-05 11:17:30 +0530132
Charles-Henri Decultot614959d2018-08-06 11:12:04 +0200133 if pricing_rule.pricing_rule_for == "Rate":
marination60261852021-04-13 00:39:26 +0530134 rate_discount = flt(mrp) - flt(pricing_rule.price_list_rate)
135 if rate_discount > 0:
136 price_obj.formatted_discount_rate = fmt_money(rate_discount, currency=price_obj["currency"])
137 price_obj.price_list_rate = pricing_rule.price_list_rate or 0
Faris Ansarifd345f82017-10-05 11:17:30 +0530138
Faris Ansarifd345f82017-10-05 11:17:30 +0530139 if price_obj:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530140 price_obj["formatted_price"] = fmt_money(
141 price_obj["price_list_rate"], currency=price_obj["currency"]
142 )
marination60261852021-04-13 00:39:26 +0530143 if mrp != price_obj["price_list_rate"]:
144 price_obj["formatted_mrp"] = fmt_money(mrp, currency=price_obj["currency"])
Faris Ansarifd345f82017-10-05 11:17:30 +0530145
Ankush Menat494bd9e2022-03-28 18:52:46 +0530146 price_obj["currency_symbol"] = (
147 not cint(frappe.db.get_default("hide_currency_symbol"))
148 and (
149 frappe.db.get_value("Currency", price_obj.currency, "symbol", cache=True)
150 or price_obj.currency
151 )
Faris Ansarifd345f82017-10-05 11:17:30 +0530152 or ""
Ankush Menat494bd9e2022-03-28 18:52:46 +0530153 )
Faris Ansarifd345f82017-10-05 11:17:30 +0530154
Ankush Menat494bd9e2022-03-28 18:52:46 +0530155 uom_conversion_factor = frappe.db.sql(
156 """select C.conversion_factor
Britloge3a9b9f2018-03-20 09:58:44 +0100157 from `tabUOM Conversion Detail` C
Britlog7d9689c2018-11-13 07:06:41 +0100158 inner join `tabItem` I on C.parent = I.name and C.uom = I.sales_uom
Ankush Menat494bd9e2022-03-28 18:52:46 +0530159 where I.name = %s""",
160 item_code,
161 )
Britloge3a9b9f2018-03-20 09:58:44 +0100162
163 uom_conversion_factor = uom_conversion_factor[0][0] if uom_conversion_factor else 1
Ankush Menat494bd9e2022-03-28 18:52:46 +0530164 price_obj["formatted_price_sales_uom"] = fmt_money(
165 price_obj["price_list_rate"] * uom_conversion_factor, currency=price_obj["currency"]
166 )
Britloge3a9b9f2018-03-20 09:58:44 +0100167
Faris Ansarifd345f82017-10-05 11:17:30 +0530168 if not price_obj["price_list_rate"]:
169 price_obj["price_list_rate"] = 0
170
171 if not price_obj["currency"]:
172 price_obj["currency"] = ""
173
174 if not price_obj["formatted_price"]:
marination60261852021-04-13 00:39:26 +0530175 price_obj["formatted_price"], price_obj["formatted_mrp"] = "", ""
Faris Ansarifd345f82017-10-05 11:17:30 +0530176
177 return price_obj
Marica40dffab2020-01-24 15:52:27 +0530178
Ankush Menat494bd9e2022-03-28 18:52:46 +0530179
Marica40dffab2020-01-24 15:52:27 +0530180def get_non_stock_item_status(item_code, item_warehouse_field):
marination60261852021-04-13 00:39:26 +0530181 # if item is a product bundle, check if its bundle items are in stock
Marica40dffab2020-01-24 15:52:27 +0530182 if frappe.db.exists("Product Bundle", item_code):
183 items = frappe.get_doc("Product Bundle", item_code).get_all_children()
Ankush Menat494bd9e2022-03-28 18:52:46 +0530184 bundle_warehouse = frappe.db.get_value(
185 "Website Item", {"item_code": item_code}, item_warehouse_field
186 )
187 return all(
188 get_web_item_qty_in_stock(d.item_code, item_warehouse_field, bundle_warehouse).in_stock
189 for d in items
190 )
Marica40dffab2020-01-24 15:52:27 +0530191 else:
192 return 1