odoo, custom module margin ZeroDivisionError - python

I'm a odoo 13 user (not developer).
I'm try to create a custom module for to show product margin percent, in purchase order line.
I've copy module code from default Odoo sale_margin addon, and I've adapt it for my custom module.
In Purchase Order, when I add product, edit qty or product price value, I have error:
margin = ((price - line.price_unit) / price) * 100
ZeroDivisionError: float division by zero
Please, can someone help me to solve this issue?
Below code,
Thanks
from odoo import models, fields, api
import odoo.addons.decimal_precision as dp
class PurchaseOrderLine(models.Model):
_inherit = 'purchase.order.line'
margin = fields.Float(string='Margin (%)', compute='_product_margin', digits='Product Price', store=True)
sale_price = fields.Float(string='Price', digits='Product Price')
def _compute_margin(self, order_id, product_id, product_uom_id):
sale_price = product_id.lst_price
if product_uom_id != product_id.uom_id:
sale_price = product_id.uom_id._compute_price(sale_price, product_uom_id)
#api.model
def _get_sale_price(self, product, product_uom):
sale_price = product.lst_price
if product_uom != product.uom_id:
sale_price = product.uom_id._compute_price(sale_price, product_uom)
#api.onchange('product_id', 'product_uom')
def product_id_change_margin(self):
if not self.product_id or not self.product_uom:
return
self.sale_price = self._compute_margin(self.order_id, self.product_id, self.product_uom)
#api.model
def create(self, vals):
vals.update(self._prepare_add_missing_fields(vals))
# Calculation of the margin for programmatic creation of a PO line. It is therefore not
# necessary to call product_id_change_margin manually
if 'sale_price' not in vals and ('display_type' not in vals or not vals['display_type']):
order_id = self.env['sale.order'].browse(vals['order_id'])
product_id = self.env['product.product'].browse(vals['product_id'])
product_uom_id = self.env['uom.uom'].browse(vals['product_uom'])
vals['sale_price'] = self._compute_margin(order_id, product_id, product_uom_id)
return super(SaleOrderLine, self).create(vals)
#api.depends('product_id', 'sale_price', 'product_uom', 'price_unit', 'price_subtotal')
def _product_margin(self):
for line in self:
price = line.sale_price
margin = ((price - line.price_unit) / price) * 100
line.margin = margin

Related

Django and use calculated values in QuerySet

I have a function to convert net to gross price like this.
taxRate is the tax value. e.g. 23, 8, 5, 0
def gross(netValue, taxRate: int, currencyPrecision=2):
if taxRate > 0:
return round(netValue * (100 + taxRate) / 100, currencyPrecision)
else:
return round(netValue, currencyPrecision)
In my model I have a class that is order items with fields: netPrice and taxId.
class OrderPosition(models.Model):
posNumber = models.AutoField(auto_created=True, primary_key=True, editable=False, blank=False)
order = models.ForeignKey(OrderHeader, on_delete=models.PROTECT)
product = models.ForeignKey(Product, on_delete=models.PROTECT)
quantity = models.DecimalField(blank=False, max_digits=3, decimal_places=0)
netPrice = MoneyField(blank=False, max_digits=6, decimal_places=2, default=Money("0", "PLN"))
taxId = models.IntegerField(blank=False, default=0)
The value of the entire order with a given ID can be calculated as follows:
def getNetValue(self):
posList = OrderPosition.objects.filter(order_id=self.orderID)
if posList:
return str(posList.aggregate(netValue=Sum(F('quantity') * F('netPrice'),
output_field=MoneyField()))['netValue'])
else:
return "0"
Question: Can I use my function "gross()" in a query to calculate the gross value of an order in a similar way to calculate the net worth?
I suppose the aggregation function is performed on the database side (mySQL in my case) and we can only use what is understandable at the database and SQL level.
Try this:
net_value = OrderPosition.objects.filter(order_id=self.order_id).aggregate(
net_value=Sum(F('quantity') * F('net_price'), output_field=MoneyField())
)['net_value']
tax_rate = OrderPosition.objects.filter(order_id=self.orderID) \
.values('taxId')[0]['taxId']
gross_value = gross(net_value, tax_rate)
we need to iterate over the order item and calculate the gross for each item like this:
total_gross_value = Money(0, "PLN")
for order_item in OrderPosition.objects.filter(order_id=self.order_id):
net_price = order_item.net_price
tax_rate = order_item.tax_id
gross_price = gross(net_price, tax_rate)
total_gross_value += gross_price
we can use annotate method on queryset like this:
from django.db.models import F, Func
class GrossValue(Func):
function = 'ROUND'
template = '%(function)s(%(expressions)s * (100 + %(tax_rate)s) / 100, 2)'
def __init__(self, expression, tax_rate, **extra):
super().__init__(expression, tax_rate=tax_rate, **extra)
OrderPosition.objects.filter(order_id=self.order_id).annotate(
gross_price=GrossValue(F('net_price'), F('tax_id'))
).aggregate(Sum('gross_price'))
have a nice day ;)

Django and python, how to get a annotate from two different model?

I have the following model framework:
class Subcategory(models.Model):
nome=models.CharField()
class Order(models.Model):
order=models.CharField()
class Quantity(models.Model):
order=models.ForeignKey(Order)
subcategory=models.ForeignKey(Subcategory)
quantity=models.DecimalField()
class Price(models.Model):
order=models.ForeignKey(Order)
subcategory=models.ForeignKey(Subcategory)
price=models.DecimalField()
Now I want to obtain a new value that give me the possibility to filter for subcategory and order both price and quantity queryset and give me the moltiplication of them.
this is the code that I have set, but I don't know how obtain the price*quantity operation.
cod='1234'
price=dict()
defaults=list(0 for m in range(1))
filter_quantity = list(Quantity.objects.values_list('subcategory__id', flat=True).distinct()).filter(order__order=cod)
for subcategory__id, totals in(Price.objects.filter(
subcategoty__in=filter_quantity ).values_list('subcategory__id').annotate(totals=ExpressionWrapper(Sum(F('price')),
output_field=FloatField())).values_list('subcategory__id', 'totals'):
if subcategory__id not in price.keys():
price[subcategory__id ]=list(defaults)
index=0
price[subcategory__id][index]=totals
total_costs={'Costs': [sum(t) for t in zip(*price.values())]}
You can also make changes to this method according to your need.
def get_order_details(order_code):
order_details = []
quantities = Quantity.objects.filter(order__order=order_code)
prices_queryset = Price.objects.filter(order__order=order_code)
for quantity in quantities:
price = prices_queryset.filter(order__order=order_code, subcategory=quantity.subcategory).first()
if price:
order_details.append({
'subcategory_name': quantity.subcategory.nome,
'quantity': quantity.quantity,
'unit_price': price.price,
'total_price': quantity.quantity * price.price
})
return {
'order_code': order_code,
'details': order_details
}

Get the values from one app to another in Django

I am working on creating shopping cart. I am still in learning phase. I need to know how I can pass/use values from shop's models.py to cart's cart.py.
shop/models.py
class Product(models.Model):
delivery_price = models.DecimalField(max_digits=10, decimal_places=0,default=0)
support_price = models.DecimalField(max_digits=10, decimal_places=0,default=0)
cart/cart.py : I think this is the file where I need to get delivery_price and support_price. I dont know how I can get these two values. I want to add these prices and multiply it by quantity (something like Product.delivery_price + Product.support_price * item.quantity -> not sure about the way this is being done) How is this flow working? If anyone help me understand, it would be great.
class Cart(object):
def __init__(self, request):
def add(self, product, quantity=1,update_quantity=False, support_req=False):
"""
Add a product to the cart or update its quantity.
"""
product_id = str(product.id)
if product_id not in self.cart:
self.cart[product_id] = {'quantity': 0,
'price': str(product.price)}
if update_quantity:
self.cart[product_id]['quantity'] = quantity
else:
self.cart[product_id]['quantity'] += quantity
self.save()
def __iter__(self):
"""
Iterate over the items in the cart and get the products
from the database.
"""
product_ids = self.cart.keys()
# get the product objects and add them to the cart
products = Product.objects.filter(id__in=product_ids)
for product in products:
self.cart[str(product.id)]['product'] = product
for item in self.cart.values():
item['price'] = Decimal(item['price'])
item['total_price'] = item['price'] * item['quantity']
yield item
def __len__(self):
"""
Count all items in the cart.
"""
return sum(item['quantity'] for item in self.cart.values())
def get_total_price(self):
return sum(Decimal(item['price']) * item['quantity'] for item in self.cart.values())
I used code from https://github.com/twtrubiks/django-shop-tutorial
First you need to create an instance of your Product model. This is done by instantiate it like any other Python class (see documentation)
product = Product(100,10) #this is an example
Then you can add a product to a cart by using the built-in add method:
cart.add(product)
Note
You'll also need to instantiate a cart the same way as you did for your product.Then, you'll have access to other methods decalred in the Cart which handles calculating the total price.
And just for your understanding, you were asking how to Get the values from one app to another in Django. Well, in this case, since your passing a product object to cart via product parameter, you have acess to its attributes.

How to store values using onchange in odoo?

If I save the amount_total value changes to prior position because it is readonly. i want that field to be readonly.
discount = fields.Selection([('fixed', 'fixed Price'), ('percentage', 'Percentage')], string="Discount")
amount = fields.Float("Amount")
total = fields.Float("Discounted Amount", store=True, compute='discount_amount')
amount_total = fields.Monetary(string='Total', store=True,readonly=True, compute='_amount_all')
#api.onchange('total')
def totalamount(self):
if self.total:
self.amount_total -= self.total
How to deal with this
Instead of writing on change function you can do like the following
#api.depends('total')
def _amount_all(self):
if self.total:
total_amount = self.amount_total - self.total
self.update({
'amount_total': total_amount
})

Django, Model with "Def Self" value, SUM aggregate not working

I have the following model:
class PurchaseOrderLine(models.Model):
productcode = models.ForeignKey(OurProduct, on_delete=models.PROTECT)
price = models.DecimalField (max_digits=6, decimal_places=2)
qty = models.IntegerField()
def linetotal(self):
from decimal import *
total = (self.price * self.qty)
return total
In my VIEWS.PY I am trying to total the linetotal's:
tot=PurchaseOrderLine.objects.aggregate(total=Sum('linetotal'))['total']
return HttpResponse(tot)
But it returns FIELDERROR "Cannot resolve keyword 'linetotal' into field"???
In the query I can replace Sum('linetotal') for Sum('price') and it work fine, but not with the def linetotal(self).
The linetotal property doesn't exist at the database level, so how would the ORM handle it? You need to implement the query using extra:
for purchase_order_line in PurchaseOrderLine.objects.extra(select={'total': 'price * qty'}):
print purchase_order.total

Categories

Resources