Good day,
We want to only allow one product order in Odoo Cart, although we are selling all products on our website.
We want a customer to only order one product at a time, so my question is How can I clear the cart in Odoo 15 when it is not empty every time a customer click Add to Cart.
We have thought of changing the add to cart function but we have failed please help.
#http.route(['shop/cart/update'], type='http', auth="public", methods=['POST'], website=True)
def cart_update(self, product_id, add_qty=1, set_qty=0, **kw):
"""This route is called when adding a product to cart (no options)."""
sale_order = request.website.sale_get_order(force_create=True)
if sale_order.state != 'draft':
request.session['sale_order_id'] = None
sale_order = request.website.sale_get_order(force_create=True)
product_custom_attribute_values = None
if kw.get('product_custom_attribute_values'):
product_custom_attribute_values = json_scriptsafe.loads(kw.get('product_custom_attribute_values'))
no_variant_attribute_values = None
if kw.get('no_variant_attribute_values'):
no_variant_attribute_values = json_scriptsafe.loads(kw.get('no_variant_attribute_values'))
sale_order._cart_update(
product_id=int(product_id),
add_qty=add_qty,
set_qty=set_qty,
product_custom_attribute_values=product_custom_attribute_values,
no_variant_attribute_values=no_variant_attribute_values
)
if kw.get('express'):
return request.redirect("/checkout?express=1")
return request.redirect("/cart")
You could simple always delete the order_line records from the order in the add_to_cart function.
Would be something like this :
#http.route(['shop/cart/update'], type='http', auth="public", methods=['POST'], website=True)
def cart_update(self, product_id, add_qty=1, set_qty=0, **kw):
"""This route is called when adding a product to cart (no options)."""
sale_order = request.website.sale_get_order(force_create=True)
if sale_order.state != 'draft':
request.session['sale_order_id'] = None
sale_order = request.website.sale_get_order(force_create=True)
# Delete the lines if there are some:
if sale_order.order_line:
sale_order.order_line.unlink()
# ...
In case you have an error for unauthorized operation, you'll have to sudo() your sale_order so sale_order.sudo().order_line.unlink()
Related
I have two models, Product and Price. I have used the ForeignKey association of the Django models to define the association between product and price. the scenario is, one product can have multiple prices according to size. On the home page, I have to fetch all the products with their prices and need to show their price(probably base price).
Following is the code that I tried.
class Product(BaseModel):
name = models.CharField(max_length=50)
category = models.ForeignKey(Category, null=True, on_delete=models.SET_NULL, help_text='Please add new category if not given.')
image = models.ImageField(upload_to='images/')
tag = models.ManyToManyField(Tag, help_text='You can add multiple tags')
slug = models.SlugField(unique=True, null=True)
time = models.TimeField(verbose_name='Time Required')
class Price(BaseModel):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
size = models.FloatField(validators=[MinValueValidator(0)])
amount = models.FloatField(validators=[MinValueValidator(0)])
Then in the view.py file
class ProductListView(ListView):
model = Product
context_object_name = 'products'
paginate_by = 32
def get_context_data(self,*args, **kwargs):
object = super(ProductListView, self).get_context_data(*args, **kwargs)
object['categories'] = Category.objects.order_by('name')
return object
def get_queryset(self):
return Product.objects.order_by('name')
In the template, I am able to get and loop through the categories and products but I am not able to access the related prices of each product.
If I tried something in the get_context_data, will it cause N+1 queries to fetch prices for every product?
In the template I tried to use something like {{ product.price_set }} but it returns order.Price.None.
use {{ product.price_set.all }}.
To avoid N+1 queries in your filter, use prefetch_related so it looks something like.
Product.objects.all().prefetch_related('price_set')
See prefetch_related in the Django documentation.
See also select related vs prefetch related
I am trying to find a way to update the latest field in a model if there are changes in the earlier field.
for example: say I have a Cash Balance model
If I change the sale inv 134 debits to 50. how do I make this change reflect on the other cash balance coming after it automatically?
Edit 1 :
class AccountsModel(models.Model):
Date = models.DateField(auto_now=True)
INV_No = models.IntegerField(null=True,blank=True)
Discription = models.CharField(max_length=500,blank=True)
Debit = models.DecimalField(max_digits=8,decimal_places=2,default=0.0)
Credit = models.DecimalField(max_digits=8,decimal_places=2,default=0.0)
CashBalance = models.DecimalField(max_digits=8,decimal_places=2,default=0.0)
created_at = models.DateTimeField(auto_now_add=True)
update_at = models.DateTimeField(auto_now=True)
#property
def GetLastCB(self):
return AccountsModel.objects.last().CashBalance
def get_bookno(self):
if not self.INV_No:
return ''
return self.INV_No
This is a simple model that I made. I made API views to GET, POST AND DELETE
What you probably want to use is a signal
https://docs.djangoproject.com/en/4.0/topics/signals/
from django.dispatch import receiver
#receiver(post_save, sender=CashBalance)
def update_cash_balance(sender, instance, **kwargs):
if instance.balance != instance.calculate_balance()
instance.set_balance()
Be wary of using .save() within the signal because you can start a recursive loop, put an if-statement check to prevent this from happening
I Have a Invoice system where employee or staff can create invoice and can add multiple product and quantity for the specific customer . as i am using mysql i cant take json data or an array data .so i was taking the quantity and price( after discount and other modificaion) as a string and then when showing or printing the invoice i used regex to find the quantity and price .i added product ids in a manytomay field from where i am getting the product name and selling price. while showing the data on printing page in when i use zip the products are showing as the id of the product so i want to retrive the data the way it is being saved . or could you tell me any way to do it more easier way?
Here is my models.py
class Invoice(models.Model):
customers = models.ForeignKey(Customer, on_delete=models.CASCADE)
products = models.ManyToManyField(Product)
total = models.FloatField()
date = models.DateField(auto_now_add=True)
amounts = models.CharField(max_length=500, default="00")
quantity = models.CharField(max_length=500, blank=True)
def save(self, *args, **kwargs):
if not Invoice.objects.count():
self.id = 20210001
else:
self.id = Invoice.objects.last().id + 1
super(Invoice, self).save(*args, **kwargs)
Here is my views.py of printing page function
def final_billing(request, id=None):
pk = id
obj = Invoice.objects.get(id=pk)
products = obj.products.all()
customer = Customer.objects.get(id=obj.customers.id)
amn = obj.amounts
qt = obj.quantity
list_of_comma = re.findall("[\d+.+\d]+", amn)
amnts = [float(n) for n in list_of_comma]
list_of_quantity = re.findall('[0-9]+', qt)
qty = [int(n) for n in list_of_quantity if n.isdigit()]
products = list(products)
both = zip(products,amnts,qty)
return render(request, 'finalbill.html',{'bills': obj, "due": customer, "both": both})
I want it to be retrieved the product objects in the sequence of it was saved
The query can only be sorted with a specific field, Django cannot guess otherwise, so in your case the best case is to sort your products by the date they were created, for example :
obj.products.all().order_by("created")
This suppose that you have a "created" field that is added each time a product is save in your database.
Another way of doing it is to specify the through option, from the documentation :
you can use the through option to specify the Django model that represents the intermediate table that you want to use.
The most common use for this option is when you want to associate extra data with a many-to-many relationship.
The through table contains an the primary key of the relation, you can use that to retrieve the sequence in which your objects were added.
for example :
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=50)
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(
Person,
through='Membership',
through_fields=('group', 'person'),
)
class Membership(models.Model):
group = models.ForeignKey(Group, on_delete=models.CASCADE)
person = models.ForeignKey(Person, on_delete=models.CASCADE)
inviter = models.ForeignKey(
Person,
on_delete=models.CASCADE,
related_name="membership_invites",
)
invite_reason = models.CharField(max_length=64)
Through Field
I'm currently using PeeWee together with Python and I have managed to create a cool application
CREATE TABLE stores (
id SERIAL PRIMARY KEY,
store_name TEXT
);
CREATE TABLE products (
id SERIAL,
store_id INTEGER NOT NULL,
title TEXT,
image TEXT,
url TEXT UNIQUE,
added_date timestamp without time zone NOT NULL DEFAULT NOW(),
PRIMARY KEY(id, store_id)
);
ALTER TABLE products
ADD CONSTRAINT "FK_products_stores" FOREIGN KEY ("store_id")
REFERENCES stores (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE RESTRICT;
which has been converted to peewee by following code:
# ------------------------------------------------------------------------------- #
class Stores(Model):
id = IntegerField(column_name='id')
store_name = TextField(column_name='store_name')
class Meta:
database = postgres_pool
db_table = "stores"
#classmethod
def get_all(cls):
try:
return cls.select(cls.id, cls.store_name).order_by(cls.store)
except Stores.IntegrityError:
return None
# ------------------------------------------------------------------------------- #
class Products(Model):
id = IntegerField(column_name='id')
title = TextField(column_name='title')
url = TextField(column_name='url')
image = TextField(column_name='image')
store = ForeignKeyField(Stores, backref='products')
class Meta:
database = postgres_pool
db_table = "products"
#classmethod
def add_product(cls, pageData, store_name):
"""
INSERT
INTO
public.products(store_id, title, image, url)
VALUES((SELECT id FROM stores WHERE store_name = 'footish'), 'Teva Flatform Universal Pride',
'https://www.footish.se/sneakers/teva-flatform-universal-pride-t1116376',
'https://www.footish.se/pub_images/large/teva-flatform-universal-pride-t1116376-p77148.jpg?timestamp=1623417840')
"""
try:
return cls.insert(
store_id=cls.select(cls.store.id).join(Stores).where(cls.store.store_name == store_name).get().store.id,
title=pageData.title,
url=pageData.url,
image=pageData.image,
).execute()
except Products.DoesNotExist:
return None
However I have realized that working with id's is quite faster than working with text and I have an issue where I am trying to figure out what would be the best way to insert the ID. I did get a comment regarding my code as for today:
your insert isn't' referencing "stores" at all so not sure what your hoping to get from that since you have a sub query there
I am a bit confused what that means however my question is that I would like to know which approach is the correct way to insert
Is it better on start of application, to store the id as a variable and pass the variable into a insert function (argument)
Or to call store_id=cls.select(cls.store.id).join(Stores).where(cls.store.store_name == store_name).get().store.id where I instead pass the store_name and then it would return the correct id?
My first thought is that by doing the number 2, that is like doing 2 queries instead of one? but I might be wrong. Looking forward to know!
This is quite incorrect:
# Wrong
store_id=cls.select(cls.store.id).join(Stores).where(cls.store.store_name == store_name).get().store.id,
Correct:
try:
store = Stores.select().where(Stores.name == store_name).get()
except Stores.DoesNotExist:
# the store name does not exist. do whatever?
return
Products.insert(store=store, ...rest-of-fields...).execute()
I am working a CRUD flask project that works with a 1-to-many relationship. The end result looks like this, Flask Webform. However when I submit the form for the Update route, it returns to the home page and displays this. Webform After Update.
Here is my DB model
def update(id):
frank = Frankendama.query.get(id)
form = FrankForm()
if form.validate_on_submit():
frank.title=form.title.data
frank.description=form.description.data
frank.tama=form.tama.data
frank.sarado=form.sarado.data
frank.sword=form.sword.data
frank.string=form.string.data
frank.bearing=form.bearing.data
db.session.add(frank)
db.session.commit()
comps = form.companies.data
comps_used = comps.split(",")
all_comps = Company.query.all().filter_by(Company.frankendama_id == id) #Error here
for entry in all_comps:
if entry.frankendama_id == id:
db.session.delete(entry)
for i in range(0, len(comps_used)):
new_entry = comps_used[i]
new_comp = Company(name=new_entry, frankendama_id=id)
db.session.add(new_comp)
db.session.commit()
return redirect(url_for("home"))
else:
return render_template("create.html", form=form)
I am trying to find a query for the Companies table that sorts for all rows with the foreign key 'frankendama_id' that is same to the main tables id. That way i can delete them and then re add them.
When i try using filter() or filter_by() i get the error AttributeError: 'list' object has no attribute 'filter_by'
I am really stumped, any suggestions are welcome! Thanks
move filter_by in front of .all()
all_comps = Company.query.filter_by(frankendama_id = id).all()
edit 1:
Also you can remove 'Company.' when using filter_by and you only need a single equals sign