Odoo- How load products with multiple parents - orm

I am working on Odoo 10e . I have situation which i am unable to solve in here.
I have a relation like following
Customer 1-------* Shipments 1-------* Shipment Detail 1-----* Products
Now i have a separate form in which i want to show products which are associated against a specific Customer in dropdown . How can i do this in Odoo

Do you mean you want to sort all products that have related to the Customer who selected in form view?
You can do this way:
#api.depends('customer')
def get_related_product(self):
res = []
#compute to get your product id here
return res
customer = fields.Many2one(....)
related_product = fields.Many2many(......., compute='get_related_product')

Related

Django complex filter and order

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')

WooCommerce products shortcode order by sku list

Is there a way to modify the WooCommerce Products shortcode to order by a list of product sku's?
A search engine send a Post to the page with a list of sku's. The page should display the Products in the same order the http post is.
Example php and mysql select (the code like this worked in my old shop system where I can use SQL syntax):
$_POST['skus'] = "51,57,34,12,111";
$skus = $_POST['skus'];
select * from products where sku in ('$skus') order by FIELD(sku,'$skus);
How can I do an "orderby" like the example with products shortcode from woocommerce or is there a better way to do that with woocommerce?
Thanks for every answer.
With the help from Gavin and the code from https://wordpress.stackexchange.com/a/67830/43362
I found this solution:
function wpse67823_orderby_post_in($orderby, $query){
//Remove it so it doesn't effect future queries
remove_filter(current_filter(), __FUNCTION__);
$post__in = $_POST['skus'];
$post__in = str_replace(',','\',\'',$post__in);
return "FIELD(CAST(mt2.meta_value AS CHAR), '$post__in' )";
}
//Add filter and perform query
add_filter('posts_orderby','wpse67823_orderby_post_in',10,2);
echo do_shortcode('[products skus="'.$skus.'" orderby="sku"]');
remove_filter('posts_orderby','wpse67823_orderby_post_in',10,2);

Display Product Combinations in Prestashop Customer View

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.

Magento SQL Query to show product manufacturer

I am trying to query the Product Manufacturer in Magento 1.7.0.2 . I browse again and again all the table to where I can get the manufacturer table and connect it with product SKU.
I try this query to hope that I can get the manufacturers of the product:
SELECT
eav_attribute_option_value.value FROM
eav_attribute,
eav_attribute_option,
eav_attribute_option_value
WHERE
eav_attribute.attribute_code = 'manufacturer' AND
eav_attribute_option.attribute_id = eav_attribute.attribute_id AND
eav_attribute_option_value.option_id = eav_attribute_option.option_id
but it is not equal to the product manufacturer when I compare the result to my magento admin product manufacturer.
My question is that what should I do to query so that I can get the list of manufacturers of the product so that I can sql join in with catalog_product_enity's SKU.
Does anyone has an idea about my case? I am new with magento so please be gentle with me.
Any help will be appreciated, Thanks in advance
I hope I understood correctly.
If you want to get the manufacturer for a product, you don't need any query.
This should work. Let's assume that you already have the product in var $_product;
$_product->getAttributeText('manufacturer');//this gets you the label
$_product->getManufacturer(); //gets the manufacturer id
[EDIT]
To get this for all the products do this:
$collection = Mage::getModel('catalog/product')->getCollection()
->addAttributeToSelect('manufacturer');
$collection->addAttributeToFilter('status', 1);//optional for only enabled products
$collection->addAttributeToFilter('visibility', 4);//optional for products only visible in catalog and search
foreach ($collection as $product) {
$sku = $product->getSku();
$manufacturerId = $product->getManufacturer();
$manufacturerLabel = $product->getAttributeText('manufacturer');
//do something with the values above - like write them in a csv or excel
}
Little late, but this is what I came up with. Works like a charm.
SELECT cpe.sku, cpev.value, cpf1.manufacturer_value
FROM catalog_product_entity cpe
JOIN catalog_product_entity_varchar cpev ON cpev.entity_id = cpe.entity_id
JOIN catalog_product_flat_1 cpf1 ON cpf1.entity_id = cpe.entity_id
WHERE cpev.attribute_id = 191

Magento: Get Collection of Order Items for a product collection filtered by an attribute

I'm working on developing a category roll-up report for a Magento (1.6) store.
To that end, I want to get an Order Item collection for a subset of products - those product whose unique category id (that's a Magento product attribute that I created) match a particular value.
I can get the relevant result set by basing the collection on catalog/product.
$collection = Mage::getModel('catalog/product')
->getCollection()
->addAttributeToFilter('unique_category_id', '75')
->joinTable('sales/order_item', 'product_id=entity_id', array('price'=>'price','qty_ordered' => 'qty_ordered'));
Magento doesn't like it, since there are duplicate entries for the same product id.
How do I craft the code to get this result set based on Order Items? Joining in the product collection filtered by an attribute is eluding me. This code isn't doing the trick, since it assumes that attribute is on the Order Item, and not the Product.
$collection = Mage::getModel('sales/order_item')
->getCollection()
->join('catalog/product', 'entity_id=product_id')
->addAttributeToFilter('unique_category_id', '75');
Any help is appreciated.
The only way to make cross entity selects work cleanly and efficiently is by building the SQL with the collections select object.
$attributeCode = 'unique_category_id';
$alias = $attributeCode.'_table';
$attribute = Mage::getSingleton('eav/config')
->getAttribute(Mage_Catalog_Model_Product::ENTITY, $attributeCode);
$collection = Mage::getResourceModel('sales/order_item_collection');
$select = $collection->getSelect()->join(
array($alias => $attribute->getBackendTable()),
"main_table.product_id = $alias.entity_id AND $alias.attribute_id={$attribute->getId()}",
array($attributeCode => 'value')
)
->where("$alias.value=?", 75);
This works quite well for me. I tend to skip going the full way of joining the eav_entity_type table, then eav_attribute, then the value table etc for performance reasons. Since the attribute_id is entity specific, that is all that is needed.
Depending on the scope of your attribute you might need to add in the store id, too.