Create a sum of specific values in a dict in Python - python

I have this dict with my values for some products which can be added to the cart.
I want to sum the prices of all products in the cart and print them. How Do I select
the specific value (price) from the dict using a function. In this instance ShoeA should be two times in the cart which should result in 144.98 + 144.98 = 289.96
Here is my complete code:
shoeA = {"id": 342453, "name": "Shoe A", "price": 144.98 }
shoeB = {"id": 9800989, "name": "Shoe B", "price": 300}
# A cart of a shop has the following functions. Each functionality should be implemented as a separate function.
# 1.1 add_product(cart, product, times): adds a product "times" times to the cart. The cart is a list and the product a
# dictionary. A product consists of a ID, name and price
cart = []
def add_product(product, times):
for i in range(0, times):
cart.append(product)
print(cart)
add_product(342453, 4)
# 1.2 remove_product(cart, productID): Removes all products with ID = productID from the given cart
# 1.3 print_cart(cart): Prints the whole cart
def remove_product(productID, times):
for i in range(0, times):
cart.remove(productID)
print(cart)
remove_product(342453, 2) #only two reductions.
# 1.4 find_product(cart, productID): Returns a list of integers, which are indexes of the searched product in the cart.
# E.g. find_product(cart, 12) may return [2,5,10] if the cart contains a the product with productID at index 2,5 and 10.
def find_product(productID):
for i, j in enumerate(cart):
if j == productID:
print(i)
find_product(342453)
# 1.5 get_total(cart): Function that sums up the prices of all products in the cart and returns this value
def get_total():
#Please help me here. :)
get_total()

Firstly, you have to store all products in a list or dict.
all_products = {342453: shoeA, 9800989: shoeB}
Then simply iterate over it and add up all the prices.
def get_total():
total = 0
for productId in cart:
shoe = all_products[productId]
total += shoe["price"]
print("Total: ", total)
Here's the Complete code:
shoeA = {"id": 342453, "name": "Shoe A", "price": 144.98 }
shoeB = {"id": 9800989, "name": "Shoe B", "price": 300}
# A cart of a shop has the following functions. Each functionality should be implemented as a separate function.
# 1.1 add_product(cart, product, times): adds a product "times" times to the cart. The cart is a list and the product a
# dictionary. A product consists of a ID, name and price
all_products = {342453: shoeA, 9800989: shoeB}
cart = []
def add_product(product, times):
for i in range(0, times):
cart.append(product)
print(cart)
add_product(342453, 4)
# 1.2 remove_product(cart, productID): Removes all products with ID = productID from the given cart
# 1.3 print_cart(cart): Prints the whole cart
def remove_product(productID, times):
for i in range(0, times):
cart.remove(productID)
print(cart)
remove_product(342453, 2) #only two reductions.
# 1.4 find_product(cart, productID): Returns a list of integers, which are indexes of the searched product in the cart.
# E.g. find_product(cart, 12) may return [2,5,10] if the cart contains a the product with productID at index 2,5 and 10.
def find_product(productID):
for i, j in enumerate(cart):
if j == productID:
print(i)
# find_product(342453)
# 1.5 get_total(cart): Function that sums up the prices of all products in the cart and returns this value
def get_total():
total = 0
for productId in cart:
shoe = all_products[productId]
total += shoe["price"]
print("Total: ", total)
get_total()

First, you'll need somewhere to keep a catalog of the products, like so:
catalog = [shoeA, shoeB]
Then, you can use a simple for-loop to find the sum of the products:
def total_price():
sum = 0
for product in catalog:
sum += product['price'] * cart.count(product['id'])
return sum

Change the declaration of the shoe products into a dictionary of products. I updated the other functions to reflect that change.
products_dict = {342453 : {"name": "Shoe A", "price": 144.98 }, 9800989: {"name": "Shoe B", "price": 300}}
# A cart of a shop has the following functions. Each functionality should be implemented as a separate function.
# 1.1 add_product(cart, product, times): adds a product "times" times to the cart. The cart is a list and the product a
# dictionary. A product consists of a ID, name and price
cart = []
def add_product(product_id, times):
for i in range(0, times):
cart.append(products_dict[product_id])
print(cart)
add_product(342453, 4)
# 1.2 remove_product(cart, productID): Removes all products with ID = productID from the given cart
# 1.3 print_cart(cart): Prints the whole cart
def remove_product(product_id, times):
for i in range(0, times):
cart.remove(products_dict[product_id])
print(cart)
remove_product(342453, 2) #only two reductions.
# 1.4 find_product(cart, productID): Returns a list of integers, which are indexes of the searched product in the cart.
# E.g. find_product(cart, 12) may return [2,5,10] if the cart contains a the product with productID at index 2,5 and 10.
def find_product(product_id):
for index, product in enumerate(cart):
if product == products_dict[product_id]:
print(index)
find_product(342453)
# 1.5 get_total(cart): Function that sums up the prices of all products in the cart and returns this value
def get_total():
#Please help me here. :)
sum = 0
for product in cart:
sum += product["price"]
print(sum)
get_total()

I would suggest to first try a easier-to-manage structure of your products. Like a nested dictionary
catalog = dict(
shoeA={"id": 342453, "name": "Shoe A", "price": 144.98 },
shoeB={"id": 9800989, "name": "Shoe B", "price": 300}
)
This means that the whole catalog will be callable. The problem with your code is that each product is separated thus not easily callable. In the nested dictionary we can easily call the product variable since it is just considered a string.
Then you edit the add function to accommodate not the internal details of your product (which is the case in your code) but the 'catalog' key(product) instead. Future functions should call this key (e.g. 'shoeA', or 'shoeB')
cart = []
cart_id = []
def add_product(product, times):
for i in range(0, times):
cart.append(product)
cart_id.append(catalog[product]['id'])
print(cart)
print(cart_id)
add_product('shoeA', 4)
['shoeA', 'shoeA', 'shoeA', 'shoeA']
[342453, 342453, 342453, 342453]
In this part we used the callable nested dictionary. Now you have free control of all attributes of the product you want easily. For example, if you want to retain the list of ids you can use the cart_id instead of the cart.
Now this format makes it easy to do a sum.
def get_total():
cart_prices = [catalog[product]['price'] for product in cart ]
total = sum(cart_prices)
print(cart_prices)
print(total)
get_total()
This should work. Feel free to adjust the other functions to accept the new structure.

  To process the extracted products data (documents, api or database) you could store them in this way if they have a fixed and available size:
product_dict = {product["id"]:product for product in products}
Then iterate over cart list like this to return a total sum:
def get_total():
amount = 0
for product_id in set(cart):
amount += product_dict[product_id]["price"] * cart.count(product_id)
return amount
print(get_total())

Related

how to access an element from a list of dictionaries

I'm trying to build a cart view following a tutorial and I need to print out the quantity of an item. I have two functions in utils.py from where I wanna access the quantity element and print it out in a view, currently getting an error 'dict' object has no attribute 'quantity'
def cookieCart(request):
try:
cart = json.loads(request.COOKIES['cart'])
except:
cart = {}
print('Cart:', cart)
items = []
order = {'get_cart_total': 0, 'get_cart_items': 0, 'shipping': False}
cartItems = order['get_cart_items']
for i in cart:
try:
cartItems += cart[i]["quantity"]
product = Product.objects.get(id=i)
total = (product.final_price * cart[i]["quantity"])
order['get_cart_total'] += total
order['get_cart_items'] += cart[i]["quantity"]
item = {
'product':{
'id':product.id,
'name':product.name,
'final_price':product.final_price,
'image_URL':product.image_URL,
},
**#print the quantity on view**
'quantity':cart[i]["quantity"],
'get_total':total,
}
items.append(item)
except:
pass
return {"items": items, "order": order, "cartItems": cartItems}
def cartData(request):
if request.user.is_authenticated:
customer = request.user.customer
order, created = Order.objects.get_or_create(customer=customer, complete=False)
items = order.orderitem_set.all()
cartItems = order.get_cart_items
else:
cookieData = cookieCart(request)
cartItems = cookieData['cartItems']
order = cookieData['order']
items = cookieData['items']
return {'cartItems':cartItems ,'order':order, 'items':items}
Views
from .utils import cookieCart, cartData
def my_view(request):
data = cartData(request)
items = data['items']
qty = items[0].quantity
print(qty)
Data Structure:
if I print out 'items' instead of 'qty' the data looks like this
[{"product": {"id": 9, "name": "p_one", "final_price": 59, "image_URL": "/images/p_one.jpg"}, "quantity": 2, "get_total": 118}, {"product": {"id": 10, "name": "p_two", "final_price": 32, "image_URL": "/images/p_two.jpg"}, "quantity": 3, "get_total": 96}]
Let's decompose your view :
data = cartData(request)
cartData returns a dict where {"items": list of dicts, ... }
items = data['items']
At this point, items's value is a list of dicts.
To access the first item of a list you use integers indices like
myList[0] # first item in "myList"
myList[1] # second item in "myList"
etc
So here, remember this is a list that contains dicts.
So Items[0] = a dict that is defined in your cookieCart function
item = {
'product':{
'id':product.id,
'name':product.name,
'final_price':product.final_price,
'image_URL':product.image_URL,
},
**#print the quantity on view**
'quantity':cart[i]["quantity"],
'get_total':total,
}
this dict has 3 keys : "product", "quantity" and "get_total".
To access a dict key's value, you use this syntax :
myDict["the key"] # As opposed to lists, you use string keys to match values
So to get the quantity in your case, we could decompose like this :
order = cartData(request) # dict
all_items_in_cart_list = order["items"] # list
first_item_in_cart = all_items_in_cart_list[0] # dict again
quantity_of_first_item = first_item_in_cart["quantity"] # your value !
Not sure how does your data look like, but this is where the problem might be:
def my_view(request):
data = cartData(request)
qty = data['items']['quantity']
# qty = data['items',['quantity']]
print(qty)

Django raise BadRequestError(msg) razorpay.errors.BadRequestError: The amount must be an integer. while refund

When I try to print it, it appears as an integer, but I get an error saying "The amount must be an integer." when I run the project
if str(Payments).__contains__("pay"):
paymentId = Payments.payment_id
amount = int(Payments.amount_paid)
refund_amount = int(amount) * 100
reamount = int(refund_amount)
print(reamount)
print(type(reamount))
client = razorpay.Client(auth=(settings.RAZOR_KEY_ID, settings.RAZOR_KEY_SECRET))
client.payment.refund(
paymentId,
{
"amount": reamount,
"speed": "optimum",
},
)
# addning stock in product
order_items = OrderProduct.objects.filter(order=order)
for item in order_items:
product = Product.objects.get(id=item.product_id)
product.stock += item.quantity
product.save()
I've just changed the dict type to direct parameter passing
#refund process of stripe
if str(Payments).__contains__("pay"):
paymentId = Payments.payment_id
refund_amount = Payments.amount_paid
amount = int(refund_amount * 100)
client = razorpay.Client(auth=(settings.RAZOR_KEY_ID, settings.RAZOR_KEY_SECRET))
print(paymentId)
client.payment.refund( paymentId,amount,)
#addning stock in product
order_items = OrderProduct.objects.filter(order=order)
for item in order_items:
product = Product.objects.get(id=item.product_id)
product.stock += item.quantity
product.save()
Then its works

Delivery price depending on order value with multiple thresholds

Suppose we purchase N products from different vendors. We have many suppliers, but not all products are available from every supplier. The price for each product is known to each retailer, unless the product is not available there. There is also a shipping fee for each seller. The shipping fee is payable only once for all orders from a given supplier. It may also be subject to special restrictions, e.g. if the total order value exceeds 179USD, shipping is free, otherwise shipping is 15.99 USD or it is impossible if it does not meet the minimum order value, e.g. 100 USD. The shipping price for each seller may vary. Based on the products selected and the pricing and shipping information from different vendors, how can we optimize the total cost (product price + shipping) for the entire product cart, assuming we always want to buy all products?
Currently, I can solve this problem for fixed delivery costs for each supplier, but I cannot cope with adding conditional constraints taking into account the value of the order with a given supplier, e.g .:
order> = 179 PLN = free delivery
order <179 PLN AND order> = 100 PLN = delivery 15.99 PLN
minimum order = PLN 100 (below this amount, the order is not possible with the given supplier.
As for the structure of data on delivery costs, the 'key' means the minimum amount from which the 'value', i.e. delivery cost, is met for a given supplier. If the cost of a product under 'product_prices' for a given supplier is 99999999, it means that the product is not available from them. Below is the example data:
'delivery_prices': {
'supplier1': {
100: 14.9,
},
'supplier2': {
0: 19.99,
179: 0,
},
'supplier3': {
100: 15,
200: 10,
250: 0,
},
}
Here is my optimization code as for now:
import pyomo.environ as pe
import pyomo.opt as po
solver = po.SolverFactory('glpk')
def optimization_problem(input_data, solver):
model = pe.ConcreteModel("All products filled")
# sets
model.I = pe.Set(initialize=input_data['supplier_names'])
model.J = pe.Set(initialize=input_data['product_names'])
# parameters
model.s = pe.Param(model.I, initialize=input_data['supplier_stock'])
model.d = pe.Param(model.J, initialize=input_data['demand'])
model.f = pe.Param(model.I, initialize=input_data['delivery_prices'])
model.c = pe.Param(model.I, model.J, initialize=input_data['product_prices'])
# variables
model.x = pe.Var(model.I, model.J, domain=pe.NonNegativeReals)
model.y = pe.Var(model.I, domain=pe.Binary) # product quantity for given suppliersupplier
# constraints
# if sum
def con_satisfaction(model, j):
return sum(model.x[i, j] for i in model.I) >= model.d[j]
model.con_satisfaction = pe.Constraint(model.J, rule=con_satisfaction)
def con_transportation(model, i):
return sum(model.x[i, j] for j in model.J) <= model.s[i] * model.y[i]
model.con_transportation = pe.Constraint(model.I, rule=con_transportation)
# objective
def obj_min_cost(model):
return sum(model.f[i] * model.y[i] for i in model.I)\
+ sum(model.c[i, j] * model.x[i, j] for i in model.I for j in model.J)
model.obj_min_cost = pe.Objective(sense=pe.minimize, rule=obj_min_cost)
solver.solve(model)
products_distribution = { key: value for key, value in model.x.extract_values().items() if value > 0}
products_suppliers = list(set([product[0] for product in products_distribution.keys()]))
suppliers_delivery_prices = {supplier:price for supplier, price in input_data['delivery_prices'].items() if supplier in products_suppliers}
return (model.obj_min_cost(), products_suppliers, suppliers_delivery_prices, products_distribution)
# EXECUTE FUNCTION
optimization_problem(example_dataset, solver)
Does anyone have any guidance how to incorporate conditional delivery prices?
Here is a working example with the introduction of a binary variable, indexed by supplier and tier. Also added are 2 constraints to link the tier to the lower and upper bounds on qty from a supplier (linking constraints).
import pyomo.environ as pe
solver = pe.SolverFactory('glpk')
s1, s2 = 'supplier 1', 'supplier 2'
p1, p2 = 'bike', 'cellphone'
# some fake data
input_data = { 'supplier_names' : [s1, s2],
'product_names' : [p1, p2],
'supplier_stock' : {(s1, p1): 1000, (s1, p2): 500, (s2, p1): 700, (s2, p2): 400},
'demand' : {p1: 50, p2: 80},
'product_prices' : {(s1, p1): 100, (s1, p2): 150, (s2, p1): 90, (s2, p2): 160}
}
max_products = 10000 # some reasonable large "big M" upper bound on the total number of products from a supplier
penalty = 10000 # some reasonably large penalty...
# supplier tier (qty, price)
delivery_prices = { s1: {'below min' : (0, penalty), # <100 N/A, use penalty
'1A' : (100, 19.99),
'1B' : (200, 0.00)},
s2: {'regular' : (0, 25.00),
'free' : (150, 0.00)} }
# make a convenience set of all the tier label possiblities accross all suppliers...
all_tiers = set()
for k in delivery_prices:
all_tiers.update(set(delivery_prices[k].keys()))
model = pe.ConcreteModel("All products filled")
# sets
model.suppliers = pe.Set(initialize=input_data['supplier_names'])
model.products = pe.Set(initialize=input_data['product_names'])
model.tiers = pe.Set(initialize=list(all_tiers))
model.supplier_tiers = pe.Set(within=model.suppliers * model.tiers, initialize={(s,t) for s in delivery_prices
for t in delivery_prices[s]})
# parameters
model.s = pe.Param(model.suppliers, model.products, initialize=input_data['supplier_stock'])
model.d = pe.Param(model.products, initialize=input_data['demand'])
model.c = pe.Param(model.suppliers, model.products, initialize=input_data['product_prices'])
# variables
model.x = pe.Var(model.suppliers, model.products, domain=pe.NonNegativeReals) # product quantity for given suppliersupplier
model.y = pe.Var(model.supplier_tiers, domain=pe.Binary) # buy from supplier s at tier t
# constraints
# link quantity to supplier tier LB
def tier(model, supplier, tier):
return sum(model.x[supplier, p] for p in model.products) >= model.y[supplier, tier]*delivery_prices[supplier][tier][0]
model.tier_min = pe.Constraint(model.supplier_tiers, rule=tier)
# link quantity to supplier UB... this forces selection of some tier to get anything from supplier
def upper(model, supplier):
return sum(model.x[supplier, p] for p in model.products) <= sum(model.y[supplier, tier] for tier in model.tiers
if (supplier, tier) in model.supplier_tiers) * max_products
model.upper_bound = pe.Constraint(model.suppliers, rule=upper)
# meet demand
def demand(model, product):
return sum(model.x[supplier, product] for supplier in model.suppliers) >= model.d[product]
model.demand = pe.Constraint(model.products, rule=demand)
# objective
def obj_min_cost(model):
return sum(model.x[s, p] * model.c[s, p] for s in model.suppliers for p in model.products) + \
sum(model.y[s, t] * delivery_prices[s][t][1] for s,t in model.supplier_tiers)
model.obj_min_cost = pe.Objective(sense=pe.minimize, rule=obj_min_cost)
result = solver.solve(model)
print(result)
model.display()
# products_distribution = { key: value for key, value in model.x.extract_values().items() if value > 0}
# products_suppliers = list(set([product[0] for product in products_distribution.keys()]))
# suppliers_delivery_prices = {supplier:price for supplier, price in input_data['delivery_prices'].items() if supplier in products_suppliers}

Split Purchase Order according to Product Category

I wanna split the Purchase Order according to Product Category.
My Code so far:
_inherit ='purchase.order.line'
split = fields.Boolean(string='Split')
_inherit ='purchase.order'
def btn_split_rfq(self):
flag = []
for record in self:
if record.order_line:
for rec in record.order_line:
rec.split = True # oles tis eggrafes true
flag.append(rec.product_id.categ_id.id) # lista me ta categ ids
newlist=[ii for n,ii in enumerate(flag) if ii not in flag[:n]] # ta krata mono mia fora an uparxoun polles
for index in newlist: # gia 2 katigories 8a treksi 2 fores
quotation_id = self.copy()
for index in record.order_line:
if index.split:
self.env['purchase.order.line'].browse(index.id).unlink()
else:
raise ValidationError(_('Please Select Order Line To Split'))
The code so far, is split to multiple POs e.g. if i have 2 type of categories is making 2 POs but and the two POs is taking and the 4 products not only of product category(see image below).
Output:
But i want this kind of Output:
Any solution?
I tried to just ignore your code example, because it is difficult to understand for me. If you want try out my attempt:
def button_split_by_prod_categ(self):
self.ensure_one()
groups = {}
# group lines by product category
for line in self.order_line:
if line.product_id.categ_id not in groups:
groups[line.product_id.categ_id] = line
else:
groups[line.product_id.categ_id] =| line
skip = True
orders = self
for lines in groups.values():
# skip first group
if skip:
skip = False
continue
# or create a new order without lines and connect
# the group's lines with it
else:
default_values = {'order_line': []}
new_order = self.copy(default=default_values)
lines.write({'order_id': new_order.id})
orders |= new_order
# now you could return a list view with all orders
# or just do 'nothing'
return
I found solution to my problem, i dont think is pretty but it does the job. Thanks # CZoellner and #Charif DZ for the effort!!!
def btn_split_rfq(self):
flag =[]
for record in self:
if record.order_line:
for rec in record.order_line: #run for all products on purchase order
flag.append(rec.product_id.categ_id.id) # append product category ids
categ_ids=[ii for n,ii in enumerate(flag) if ii not in flag[:n]] # filter list,keep only one time every product category id
categ_ids.sort() # sorting list
for index in categ_ids: # will run 2 times if there is 2 product categories
quotations_ids = [self.copy()]
for order_line in quotations_ids:
prods = self.env['purchase.order.line'].search([('product_categ_id' ,'!=',index),('order_id','=',int(order_line))])
for ids in prods:
self.env['purchase.order.line'].browse(ids.id).unlink()
else:
raise ValidationError(_('Not Available Purchase Order Lines'))

How to loop the following code in Python?

I am new to Python but I tried to create the following trading strategy but cannot find a way to loop it for different products (trading hours in this case).
def strategy(area_code, product, orders, environment):
order = None
new_orders = []
Quantity = 5
price_delta = 0.1
def process_flex(Plant):
order = None
Tur1 = Plant + "1"
if Tur1Volume > 0:
if Tur1Price:
order = None
if check_if_we_have_order_on_the_market(Plant,Tur1)==0:
order = package.create_sell_order(area_code, Tur1Volume, Quantity, calculate_selling_price(Tur1Price), price_delta, product, environment.current_datetime).with_label((Plant,Tur1))
if order:
new_orders.append(order)
else:
order = None
return
process_flex("bla")
process_flex("blabla")
process_flex("blablabla")
return new_orders
This code is only working for one product (1 hour) and does not loop for all 24 products.
I thought that it could work like this:
for product in products:
Plant = ['bla', 'blabla', 'blablabla']
for i in Plant:
order = process_flex(Plant)
return_orders.append(order)
return return_orders
Unfortunately, it did not work. Do you have any idea on the solution?
Thank a lot in advance!
You want to swap Plant to :
order = process_flex(i)
because i is an element of Plant
for product in products:
Plant = ['bla', 'blabla', 'blablabla']
for i in Plant:
order = process_flex(i)
return_orders.append(order)
return return_orders

Categories