I am using Odoo 10. I have a custom field call linear_units in Sales Order. I have make to order ticked and it creates an automatic Purchase order. I would like to include the field linear_units from Sales order to the purchase order. With below code I can select the Sales order but I cant figure out how to add a field.
class PurchaseOrder(models.Model):
_inherit = 'purchase.order'
sale_order_id = fields.Many2one(
'sale.order',
"Sale Order",
help="Reference to Sale Order")
The above code works for selecting a sales order in purchase order. I have a float field in Sales order called linear_units. I need this field to copy to purchase order. I tried below but does not work
class PurchaseOrder(models.Model):
_inherit = 'purchase.order'
linear_units2 = fields.Float("Linear Units")
#api.onchange('product_id','linear_units')
def _onchange_product_qty(self):
if self.product_id:
self.linear_units2 = self.sale.order.linear_units
you can add a related field in the purchase order for linear_units like below
class PurchaseOrder(models.Model):
_inherit = 'purchase.order'
sale_order_id = fields.Many2one('sale.order', "Sale Order", help="Reference to Sale Order")
linear_units = fields.Float(related='sale_order_id.linear_units')
It will fetch the related linear_units value from the selected sale_order_id
hope this helps!
What is the purpose of this field. Is it supposed to be on each order line or is it supposed to be on the sale order as a whole. With the setup you have, you two options: First
sale_order_lines = fields.One2many('sale.order.line', 'Sale Order Lines')
Then from there you can reference your order number and your linear units.
sale_order_id = fields.Many2one('sale.order', related='sale_order_lines.order_id', string='Sale Order')
linear_units2 = fields.Float(related='sale_order_lines.linear_units', string='Linear Units')
and Second:
sale_order_id = fields.Many2one('sale.order', string='Sale Order')
linear_units = fields.Float(related='sale_order_id.sale_order_lines.linear_units', string='Linear units')
Though I'm not entirely certain that the second option will work. If this is the same value on all order lines then I would suggest putting linear_units on sale.order, then if you need it on the order lines you can put a related field on the order lines and then your fields will look like below
class SaleOrder(model.Models):
_inherit='sale.order'
linear_units = fields.Float(string='Linear Units')
class SaleOrderLines(model.Models):
_inherit='sale.order.lines'
linear_units = fields.Float(related='order_id.linear_units', string='Linear Units', readonly=True)
class PurchaseOrder(models.Models):
_inherit='purchase.order'
sale_order_id = fields.Many2one('sale.order', string='Sale Order')
linear_units = fields.Float(related='sale_order_id.linear_units', string='Linear Units', readonly=True)
(I suggest putting the read only on your related fields because if they are changed on your inherited view it will change it for that sale order and all of its relations.)
Related
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
Alright,
So I'm using a general listview showing all orders where the payment hasn't been completed yet. Let's call them outstanding orders, orders which still require some sort of payment.
Orders contain one or multiple items and can contain zero or more payments.
So I want to compare the total order value, compare this value with the total payment and if these or not equal to zero, show them in the list.
Is there someway I can build a new queryset for items which do not meet a certain condition?
views.py
class OutstandingOrderListView(ListView):
model = Order
def get_queryset(self):
queryset = Order.objects.all()[:5]
for record in queryset.iterator():
# Retrieve order_total
order_total = record.item_set.aggregate(total=Sum('price'))['total']
# Retrieve payment_total
payment_total = record.payment_set.aggregate(total=Sum('amount'))['total']
# Compare both
delta = order_total - payment_total
if delta != 0:
print("These guys owe you money!")
# Add record to new queryset?
models.py
class Order(models.Model):
no = models.CharField(max_length=9, default=increment_order_number,
editable=False, unique=True)
created_at = models.DateTimeField(auto_now_add=True)
created_by = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.SET_NULL, null=True, related_name='created_by')
class Item(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE)
name = models.CharField(max_length=200, default="", blank=True)
price = models.DecimalField(max_digits=5,
decimal_places=2, default=Decimal('000.00'))
class Payment(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE)
date = models.DateField(default=now)
amount = models.DecimalField(max_digits=5, decimal_places=2,
default=Decimal('000.00'))
Tried to use filtering on annotations like #bdbd mentioned in the comments, in this case we could use exclude():
queryset = Order.objects.annotate(order_total=Sum('item__price')) \
.annotate(payment_total=Sum('payment__amount')) \
.exclude(order_total=F('payment_total'))[:5]
Even though this works, the second annotation shows very unusual results, not sure why but it looks like a multiple from order_total...
I would like to set Sales Team reference in picking directly when sales order confirm and picking is getting created.
But I didn't get enough hint how can I achieve this. Because the method which is called at the time of sales order confirmation is as follow.
def action_button_confirm(self, cr, uid, ids, context=None):
if not context:
context = {}
assert len(ids) == 1, 'This option should only be used for a single id at a time.'
self.signal_workflow(cr, uid, ids, 'order_confirm')
if context.get('send_email'):
self.force_quotation_send(cr, uid, ids, context=context)
return True
Here there is no any hint how can I pass it to picking ?
Purpose:
My aim is to set sales team reference in picking / shipment.
It's not that easy. Odoo uses procurement.orders for creating stock.moves and for them stock.pickings. Problem: Maybe a picking has more than one sales orders as origin. So there could be more than one sales team referenced.
But try to use a computed field:
section_id = fields.Many2one(
comodel_name="crm.case.section", string="Sales Team",
compute="_compute_section_id")
#api.multi
def _compute_section_id(self):
for picking in self:
section_ids = set()
for move in picking.move_lines:
if move.sale_line_id.order_id.section_id
section_ids.add(move.sale_line_id.order_id.section_id.id)
if len(section_ids) == 1:
picking.section_id = section_ids.pop()
You could also use a related field, but that could have really bad side effects. Because Odoo will take the first move.
section_id = fields.Many2one(
comodel_name="crm.case.section", string="Sales Team",
related="move_lines.sale_line_id.order_id.section_id")
I got that method from where it create picking. So I have just inherited it and added my code. action_ship_create will always get called at the time of shipment creation from the sales order.
#api.cr_uid_ids_context
def action_ship_create(self,cr,uid,ids,context={}):
result=super(sale_order,self).action_ship_create(cr,uid,ids,context=context)
for order in self.browse(cr,uid,ids,context=context):
order.picking_ids.write({'section_id':order.section_id.id})
return result
This related field working fine in odoo 9, but not in odoo 10. The field customer_id not updated when I create a new record with nomor_hp_id.
nomor_hp_id = fields.Many2one(
string='Nomor hp',
comodel_name='nomor.hp',
ondelete='cascade',
)
customer_id = fields.Many2one(
string='Customer',
related='nomor_hp_id.customer_id',
ondelete='cascade',
store=True,
readonly=True,
)
Try to start new database but the result still not updated.
You have to give comodel name inside Many2one field either it is normal Many2one or related Many2one. Please have a look at below code. You will get your answer.
nomor_hp_id = fields.Many2one(string='Nomor hp', comodel_name='nomor.hp',ondelete='cascade',)
customer_id = fields.Many2one(string='Customer', comodel_name='res.partner', related='nomor_hp_id.customer_id', ondelete='cascade',readonly=True,)
You have to define the reference of which table. Here customer_id is the reference field of the "res_partner" table or "res.partner" model.
This way works fine for me.
customer_id = fields.Many2one(
string='Customer',
related='nomor_hp_id.customer_id',
store=True,
)
I created a new model 'sale.order.category' in order to group Sale Order Lines in specific subcategories (allowing to display subtotals, etc.)
class SaleOrderCategory(models.Model):
_name = 'sale.order.category'
name = fields.Char('Name', required=True)
line_ids = fields.One2many('sale.order.line', 'category_id', 'Order Lines in this category')
order_id = fields.Many2one('sale.order', 'Order', required=True, readonly=True)
class SaleOrder(models.Model):
_name = 'sale.order'
_inherit = 'sale.order'
order_category_ids = fields.One2many('sale.order.category', 'order_id', 'Categories in this order', readonly=True, copy=True)
Just for info, here is my Order lines tree view modification to add the Category column :
<!-- adds a category column in the order lines list -->
<xpath expr="//field[#name='order_line']/tree/field[#name='name']" position="after">
<field name="category_id"/>
</xpath>
My question is : how can I automatically populate the order_id field with the current Sales Order ID when I create a new Category through the Order Lines Tree (inside a Sales Order) ?
Many thanks,
Max
Preliminary remark: your use case seems related to what the official sale_layout module does, so you might want to have a look at it before going any further. Perhaps you could extend it instead of starting from scratch.
Next, the most basic answer to your question is to pass a default value for the order_id field of your sale.order.category model when you create it from the view. You can do that by setting a context with an appropriate default value on the many2one field from which you will create the value:
<xpath expr="//field[#name='order_line']/tree/field[#name='name']" position="after">
<field name="category_id" context="{'default_order_id': parent.id}"/>
</xpath>
Your category_id field is defined on the sale.order.line tree view, so parent will dynamically refer to the parent record inside the web client interface, here the sale.order.
However this option will not work well:
When you're creating a new sales order, you will have to create your categories before the sales order is even saved, so there is no possible value for order_id yet. For this reason, you cannot make order_id required, and you will have to set its value again later, or you will need to save your orders before starting to add the categories.
You already have an order_lines one2many field in your sale.order.category model. The order_id field is redundant with the line_ids field, because all lines presumably belong to the same order.
A simple alternative would be to entirely omit the order_id field (use lines_id[0].order_id when you need it), or to replace it with a related field that will be automatically computed from the lines (it will take the value from the first order line):
order_id = fields.Many2one('sale.order', related='line_ids.order_id', readonly=True)
What you should do depends on your requirements, it's difficult to say based only on your question.