Odoo v10 display amount in company currency in purchase tree and form view - odoo

I am using Odoo v10 .
As we know in purchase.order, there is a base (Monetary) field amount_total which contains value of total amount of a Purchase Order based on (self) currency_id .
Now, I create a new float field home_currency_amount_total in purchase.order .
home_currency_amount_total = fields.Float(string='Total Amount in company currency', store=True)
How can i have a value in this field based on company currency? i.e. I want to have a corresponding value in company base currency and can be used in my tree & form views.
I am new to Odoo and I wonder if there is a "shortcut" (e.g. a built-in compute method) instead of I have to write up related codes.

There is a built-in method for conversion of currency.
Eg.
#api.model
def _compute(self, from_currency, to_currency, from_amount, round=True):
if (to_currency == from_currency):
amount = to_currency.round(from_amount) if round else from_amount
else:
rate = self._get_conversion_rate(from_currency, to_currency)
amount = to_currency.round(from_amount * rate) if round else from_amount * rate
return amount
So, if you want to calculate the conversion you can use this method.
This method takes 3 arguments, first from currency, second to currency and amount which you want to convert as a third argument.
Eg.
self.env['res.currency']._compute(order.currency_id,order.company_id.currency_id,order.amount_total)
Update :
Create you field like this.
home_currency_amount_total = fields.Float(string='Total Amount in company currency', compute="_compute", store=True)
#api.depends('order_lines.price_subtotal','company_id','currency_id')
def _compute(self);
for order in self:
home_currency_amount_total = self.env['res.currency']._compute(order.currency_id,order.company_id.currency_id,order.amount_total)

You can do it using following method.
class PurchaseOrder(models.Model):
_inherit = "purchase.order"
#api.multi
#api.depends('amount_total')
def get_amount_in_company_currency(self):
for purchase_order in self:
if purchase_order.currency_id.id!=purchase_order.company_id.currency_id.id:
currency_id = purchase_order.currency_id.with_context(date=purchase_order.date_order)
purchase_order.home_currency_amount_total = currency_id.compute(purchase_order.amount_total, purchase_order.company_id.currency_id)
else:
purchase_order.home_currency_amount_total=purchase_order.amount_total
home_currency_amount_total = fields.Float(string='Total Amount in company currency',compute="get_amount_in_company_currency",store=True)
In above code we have create one compute field store True, it means value will be store in the database.
When amount_total will change at that time system will calculate home currency amount.
In method we have checked if company currency & purchase order currency is different then system will compute currency amount.
In odoo base module on method is available for compute currency, in which you can pass date in the context.
purchase_order.currency_id.with_context(date=purchase_order.date_order)
Based on context date system will take currency rate, if you not pass
any date then system will take current date rate.
This will help you.

Related

How to set unit_price automatically as I select product in odoo 15?

I have made one model which is listed below, I want to set the price automatically as I select the product.
class JobCardLine(models.Model):
_name = "job.card.line"
product_id = fields.Many2one('product.template', string="Product", tracking=True)
price = fields.Many2one('product.template.',string="Price", tracking=True)
I think it can be done using depends on onchange but not able to do that.
You can use on_change to automatically set the price to the product list_price
Example:
#api.onchange('product_id')
def _change_price(self):
self.price = self.product_id.list_price
You will need to change the price field type to Float
You can do it using a computed field but you will need to implement the inverse function to allow setting values on the field and the unit price should depend on product price

Reduce product price from php script

I am trying to make a php script that reduces the base price of a product by 20 but it instead changes the base price with the discounted price. I can't figure out what is wrong with the code.
$product_baseprice = round(1.19*($product->base_price));
$product->base_price = $product_baseprice - 20;
$product->update();
There's no "base_price" property in the Product class object.
The base price must be updated with the $product->price property.
Or, like suggested, you can create a new SpecificPrice() where you can apply a percentage-based discount on the product.
Solved it
$pret = $product->base_price;
$pret_redus = $pret - 16.81;
$product->price = $pret_redus;
$product->update();

Method to get product price for a given customer

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], {})

How create my calculate function for my example

I have two models a parent and the son contains two float fields
one of the values this calculates according to the other but when I change the father how can be my calculating function.
Here is my example:
class A(models.model):
trv_ids = fields.One2many(classB,id_A)
class B(models.model):
id_A = fields.Many2one(classA)
qtite = fields.float(default=0)
qtite1 = fields.float(default=0,compute=?????)
qtite1 gets the value of qtite when I change parent
as the example of cumulated amount becomes previous quantity the next month.
Thanks
If i understood right i think what you need is something like this:
#api.depends('id_A')
def _compute_qtie1(self):
for record in self:
record.qtite1 = record.qtite
qtite1 = fields.float(compute=_compute_qtie1, store=True)
The depends is what triggers (any time you change the id_A field in the record) the compute method, if you dont store it in the DB it will re-calculate every time you open a view that contains the record.

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