In 'products.template' table I created three fields width,length and gsm. Now I want to retrieve it in 'mrp' table.First I will get the ids from mrp bill of materials and assign it to a variable called prod. 'mrp.bom.line' table contains product id.So through iterator I want to pass id of product stored in mrp bill of materials table to retrieve the value of width,length and gsm stored in product.template table.I am getting error as programming error can't adapt type 'product.product'.
#api.multi
def _compute_rim_weight(self):
bill_of_materials_id=[1,2,3]
prod = self.env['mrp.bom.line'].browse(bill_of_materials_id)
for i in prod:
j = self.env['product.template'].browse(i.product_id)
self.rim_weight = (j.width * j.length * j.gsm)/20000
return self.rim_weight
In ODOO browse take id not object
so just replace browse(i.product_id) with browse(i.product_id.id) as below:
j = self.env['product.template'].browse(i.product_id.id)
One more thing if in case product.template have** many2one relation** with model :mrp.bom.line from my understanding you even don't need the call browse .
Directly call line.product_id.width ,line.product_id.length,line.product_id.gsm as below :
#api.multi
def _compute_rim_weight(self):
bill_of_materials_ids=[1,2,3]
bom_lines = self.env['mrp.bom.line'].browse(bill_of_materials_ids)
for line in bom_lines:
self.rim_weight = (line.product_id.width * line.product_id.length * line.product_id.gsm)/20000
return self.rim_weight
#api.one
def _compute_rim_weight(self):
rim_weight =0
for line in self.bom_id.bom_line_ids:
rim_weight+ = (line.product_id.width * line.product_id.length * line.product_id.gsm)/20000
self.rim_weight =rim_weight
Related
I'm trying to create a query set that filters all the cars hired by a user.
the car hire model has a foreignkey which stores the user's ID when a car is hired
My current solution is like this, where I get current users ID and then try filtering the Cars database against the user's ID.
view.py:
def view_hire(request):
current_users_id = request.user.id
car_hired = Cars_hired.objects.filter(user_id__in=current_users_id)
args =
{
'car_hired': car_hired,
}
Models
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
def __str__(self):
return str(self.user.id)
class car_hired(models.Model):
car = models.ForeignKey('Car', on_delete=models.CASCADE)
customer = models.ForeignKey('UserProfile', on_delete=models.CASCADE)
start_date = models.DateField(help_text='Date of booking')
end_time = models.DateField(help_text='Date of booking')
def __str__(self):
return str(self.id)
However, I can't seem to get this to work and I am getting the error "'int' object is not iterable"
I would like to create a query set that returns the row of data that matches the query
for example, if the current user's id is 10 I would like to get all the cars hired by the user. All the data stored in the rows where car_hirer_is == 10
This part is causing the error:
...(user_id__in=current_users_id)
When you add the __in part it makes django think that current_users_id is an iterable but current_users_id = request.user.id is a single id. To make it work change it to:
def view_hire(request):
current_users_id = request.user.id
car_hired = Cars_hired.objects.filter(customer__user_id=current_users_id)
I would also reconsider the names of the variables (current_user_id instead of current_users_id and cars_hired instead of car_hired).
I need to retrieve product price via XMLRPC.
I am using Product Price Lists so each customer can be assigned a given price list which gives specific discounts based on categories, etc.
I am struggling to find which method can be used to retrieve the price for a given product_template id at a given quantity, if that is actually possible.
So far I have not been able to try any specific method as I can not identify how can this be achieved without actually creating a sales order.
The module 'product' holds the pricelist mechanics. The model product.pricelist has a really nice method get_product_price(), which could be easily used server-side but not for the external/web API.
But if you have the possibility to write a little custom module, do that and override the model product.pricelist. Add the possibility to use this method, like:
Origin Method which can't be used because parameters are RecordSets:
def get_product_price(self, product, quantity, partner, date=False, uom_id=False):
""" For a given pricelist, return price for a given product """
self.ensure_one()
return self._compute_price_rule([(product, quantity, partner)], date=date, uom_id=uom_id)[product.id][0]
"Wrapper" for external/web API:
def web_api_get_product_price(
self, product_id, quantity, partner_id, date=False, uom_id=False):
""" For a given pricelist, return price for a given product
callable from web api"""
self.ensure_one()
# get records
product = self.env['product.product'].browse(product_id)
partner = self.env['res.partner'].browse(partner_id)
# call origin method
return self.get_product_price(
product, quantity, partner, date=date, uom_id=uom_id)
Now you can call this method, an example:
import xmlrpclib
db = 'db_name'
password = 'admin'
common = xmlrpclib.ServerProxy('http://localhost:8069/xmlrpc/2/common')
uid = common.authenticate(db, 'admin', password, {})
models = xmlrpclib.ServerProxy('http://localhost:8069/xmlrpc/2/object')
pricelist_id = 1
product_id = 5
partner_id = 7
quantity = 20
price = models.execute_kw(
db, uid, password, 'product.pricelist',
'web_api_get_product_price',
[[pricelist_id], product_id, quantity, partner_id], {})
I have 4 model like this
class Site(models.Model):
name = models.CharField(max_length=200)
def get_lowest_price(self, mm_date):
'''This method returns lowest product price on a site at a particular date'''
class Category(models.Model):
name = models.CharField(max_length=200)
site = models.ForeignKey(Site)
class Product(models.Model):
name = models.CharField(max_length=200)
category = models.ForeignKey(Category)
class Price(models.Model):
date = models.DateField()
price = models.IntegerField()
product = models.ForeignKey(Product)
Here every have many category, every category have many product. Now product price can change every day so price model will hold the product price and date.
My problem is I want list of site filter by price range. This price range will depends on the get_lowest_price method and can be sort Min to Max and Max to Min. Already I've used lambda expression to do that but I think it's not appropriate
sorted(Site.objects.all(), key=lambda x: x.get_lowest_price(the_date))
Also I can get all site within a price range by running a loop but this is also not a good idea. Please help my someone to do the query in right manner.
If you still need more clear view of the question please see the first comment from "Ishtiaque Khan", his assumption is 100% right.
*In these models writing frequency is low and reading frequency is high.
1. Using query
If you just wanna query using a specific date. Here is how:
q = Site.objects.filter(category__product__price__date=mm_date) \
.annotate(min_price=Min('category__product__price__price')) \
.filter(min_price__gte=min_price, min_price__lte=max_price)
It will return a list of Site with lowest price on mm_date fall within range of min_price - max_price. You can also query for multiple date using query like so:
q = Site.objects.values('name', 'category__product__price__date') \
.annotate(min_price=Min('category__product__price__price')) \
.filter(min_price__gte=min_price, min_price__lte=max_price)
2. Eager/pre-calculation, you can use post_save signal. Since the write frequency is low this will not be expensive
Create another Table to hold lowest prices per date. Like this:
class LowestPrice(models.Model):
date = models.DateField()
site = models.ForeignKey(Site)
lowest_price = models.IntegerField(default=0)
Use post_save signal to calculate and update this every time there. Sample code (not tested)
from django.db.models.signals import post_save
from django.dispatch import receiver
#receiver(post_save, sender=Price)
def update_price(sender, instance, **kwargs):
cur_price = LowestPrice.objects.filter(site=instance.product.category.site, date=instance.date).first()
if not cur_price:
new_price = LowestPrice()
new_price.site = instance.product.category.site
new_price.date = instance.date
else:
new_price = cur_price
# update price only if needed
if instance.price<new_price.lowest_price:
new_price.lowest_price = instance.price
new_price.save()
Then just query directly from this table when needed:
LowestPrice.objects.filter(date=mm_date, lowest_price__gte=min_price, lowest_price__lte=max_price)
Solution:
from django.db.models import Min
Site.objects.annotate(
price_min=Min('categories__products__prices__price')
).filter(
categories__products__prices__date=the_date,
).distinct().order_by('price_min') # prefix '-' for descending order
For this to work, you need to modify the models by adding a related_name attribute to the ForeignKey fields.
Like this -
class Category(models.Model):
# rest of the fields
site = models.ForeignKey(Site, related_name='categories')
Similary, for Product and Price models, add related_name as products and prices in the ForeignKey fields.
Explanation:
Starting with related_name, it describes the reverse relation from one model to another.
After the reverse relationship is setup, you can use them to inner join the tables.
You can use the reverse relationships to get the price of a product of a category on a site and annotate the min price, filtered by the_date. I have used the annotated value to order by min price of the product, in ascending order. You can use '-' as a prefix character to do in descending order.
Do it with django queryset operations
Price.objects.all().order_by('price') #add [0] for only the first object
or
Price.objects.all().order_by('-price') #add [0] for only the first object
or
Price.objects.filter(date= ... ).order_by('price') #add [0] for only the first object
or
Price.objects.filter(date= ... ).order_by('-price') #add [0] for only the first object
or
Price.objects.filter(date= ... , price__gte=lower_limit, price__lte=upper_limit ).order_by('price') #add [0] for only the first object
or
Price.objects.filter(date= ... , price__gte=lower_limit, price__lte=upper_limit ).order_by('-price') #add [0] for only the first object
I think this ORM query could do the job ...
from django.db.models import Min
sites = Site.objects.annotate(price_min= Min('category__product__price'))
.filter(category__product__price=mm_date).unique().order_by('price_min')
or /and for reversing the order :
sites = Site.objects.annotate(price_min= Min('category__product__price'))
.filter(category__product__price=mm_date).unique().order_by('-price_min')
I am trying to get the product combinations displayed in Prestashop admin Customer detail view in addition to the products that are displayed for the customer.
This seems to be the relevant call from AdminCustomersController.php in public form renderForm():
$products = $customer->getBoughtProducts();
Then in the Customer class I found the method:
public function getBoughtProducts()
{
return Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
SELECT * FROM `'._DB_PREFIX_.'orders` o
LEFT JOIN `'._DB_PREFIX_.'order_detail` od ON o.id_order = od.id_order
WHERE o.valid = 1 AND o.`id_customer` = '.(int)$this->id);
}
How can I modify this method to show the product combination alongside the product name?
I am using Prestashop version 1.6.0.9.
you can get it using 2 ways:
order_detail table already have field 'product_name' that contains value like 'Product Name - Combination', so you can use $products['product_name'] in that case.
or
if for some reason it is not good for you, same table contains also product_attribute_id field, it is combination id, so:
$combination = new Combination($product['product_attribute_id']);
$attributes = $combination->getAttributesName($id_lang);
var_dump($attributes);
will give you array of attributes that current combination contains.
I want to know how to show a one2many computed field in a tree view, I tried the following code but without results:
#api.one
def _compute_o2m_field(self):
related_recordset = self.env["product.product"].search([])
self.productos = related_recordset
products = fields.One2many(string="products", compute='_compute_o2m_field')
any idea?,
thanks
#api.one
def _compute_o2m_field(self):
related_recordset = self.env["product.product"].search([])
self.products = related_recordset.ids
products = fields.One2many('product.product','many2onefieldonproduct',string="products", compute='_compute_o2m_field')
Computed Fields
There is no more direct creation of fields.function.
Instead you add a compute kwarg. The value is the name of the function as a string or a function. This allows to
have fields definition atop of class
Your compute function should be like this,
#api.multi
def _compute_o2m_field(self):
related_recordset = self.env["product.product"].search([])
for obj in self:
obj.products = related_recordset
One2many
Store a relation against many rows of co-model.
Specific options:
• comodel_name: name of the opposite model
• comodel_name: relational column of the opposite model
So, your field definition should be like this,
products = fields.One2many(comodel_name,comodel_name,string="products", compute='_compute_o2m_field')