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
})
Related
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 ;)
I wanna now if MongoEngine aggregate() functionality only works on QuerySet?
well, this is the project I'm working on
#imports
class Status(Enum):
ACTIVE = "active"
CLOSED = "closed"
class OrderType(Enum):
BUY = "buy"
SELL = "sell"
class Order(EmbeddedDocument):
type = EnumField(OrderType, required=True)
vol = IntField(required=True)
time = DateTimeField(required=True, default=datetime.now())
class Stock(EmbeddedDocument):
name = StringField(max_length=20, required=True)
orders = EmbeddedDocumentListField(Order, required=True)
status = EnumField(Status, required=True, default=Status.ACTIVE)
amount = IntField(required=True, default=0)
pnl = FloatField()
class Portfolio(Document):
account = IntField(required=True, unique=True)
stocks = EmbeddedDocumentListField(Stock, required=True)
balance = FloatField()
equity = FloatField()
I want to be able to make Stock.amount field be an aggregation of Order.vol which, as can be seen, is an EmbeddedDocumentListField of stock. I already know about mongoengine.signals and seen examples on aggregate(), but all of them use aggregate() on QuerySet returned by .objects(). So what is the tweak for it? Many Thanks.
Currently I come up with this:
def handler(event):
def decorator(fn):
def apply(cls):
event.connect(fn, sender=cls)
return cls
fn.apply = apply
return fn
return decorator
#handler(signals.post_init)
def update_amount(sender, document):
orders = document.orders
amnt = 0
for order in orders:
if order.type == OrderType.Buy:
amnt += order.vol
else:
amnt -= order.vol
document.amount = amnt
and then I added decorator #update_amount.apply to my Stock class. but it would work nicer with aggregate if it's possible
I have created a custom field in the purchase order and another in account.invoice with the same name budget_id, when I create a purchase order and create a bill from this order I would like to copy the value of budget_id in the purchase order to the budget_id in the bill.
I have overridden the smart button method "action_view_invoice" in purchase.order and added my code but nothing happen. Are there other ways to do that?
Thanks in advance!
my code
#api.multi
def action_view_invoice(self):
action = self.env.ref('account.action_invoice_tree2')
result = action.read()[0]
result['context'] = {'type': 'in_invoice', 'default_purchase_id': self.id}
if not self.invoice_ids:
# Choose a default account journal in the same currency in case a new invoice is created
journal_domain = [
('type', '=', 'purchase'),
('company_id', '=', self.company_id.id),
('currency_id', '=', self.currency_id.id),
]
default_journal_id = self.env['account.journal'].search(journal_domain, limit=1)
if default_journal_id:
result['context']['default_journal_id'] = default_journal_id.id
else:
# Use the same account journal than a previous invoice
result['context']['default_journal_id'] = self.invoice_ids[0].journal_id.id
# choose the view_mode accordingly
if len(self.invoice_ids) != 1:
result['domain'] = "[('id', 'in', " + str(self.invoice_ids.ids) + ")]"
elif len(self.invoice_ids) == 1:
res = self.env.ref('account.invoice_supplier_form', False)
result['views'] = [(res and res.id or False, 'form')]
result['res_id'] = self.invoice_ids.id
result['context']['default_origin'] = self.name
result['context']['default_reference'] = self.partner_ref
result['context']['default_budget_id'] = self.budget_id.id # my code here
return result
The account.invoice object has the field purchase_id which is a link with purchase.order.
So in the account.invoice you can get any of the way(like in the vendor bill creation best approch) the purchase order budget_id field value into account.invoice budget_id field.
Code link - Purchase link In Invoice
I am trying to update field price in model custom.sale.line that's related to field product_id.sell_price in model custom.price but without affecting the original value of the latter (in other way i want the cashier to able to change the value on the sales invoice but without changing the value of the product in the database), i'm wondering if there's any change to do so
I tried making another field other_price that takes the value of price, but even with store=True it doesn't save the new value in the database and reverts to the original value
if anyone have a solution for this problem i would be thankful
below is the code
class CustomSaleLine(models.Model):
_name = 'custom.sale.line'
_sql_constraints = [
('product_br_uniq', 'unique(order_id, product_id)',
'Cannot add a product that already exists')]
product_id = fields.Many2one(comodel_name="custom.product", string="Product",
domain="[('branch_line.branch_id.user_lines.user_id','=', user_id)]")
sell_price = fields.Float(string='Main Price', related='product_id.sell_price', required=True, )
other_price = fields.Float(string='Other Price', compute='_compute_price', store=True)
store=True, )
#api.depends('sell_price')
def _compute_price(self):
for rec in self:
rec.other_price = rec.sell_price
Try
sell_price = fields.Float(string='Main Price', inverse='_compute_dummy', compute='_compute_price', required=True, store=True)
#api.depends('product_id.sell_price')
def _compute_price(self):
for rec in self:
rec.sell_price = rec.product_id.sell_price
def _compute_dummy(self):
pass
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