Override Default Route Based on Condition on Incoming Shipment (Receipts) while Confirming the Purchase Order Odoo 13 - odoo

What im trying to achieve is while confirming a purchase order based on a condition in then order, needs to replace the default route with a custom route.
Please share your valuable references or suggetions

You need to inherit the _prepare_stock_moves function of purchase.order.line and check for the condition if true then update the routes with the custom route
class PurchaseOrderLine(models.Model):
_inherit = 'purchase.order.line'
def _prepare_stock_moves(self,picking):
res = super(PurchaseOrderLine,self)._prepare_stock_moves(picking)
if self.order_id.condition:
res['route_ids'] = [(6,0,custom_route.ids)]
return res

Related

How to store relational fields to the database?

I've been searching for this for a week now, and still don't find any satisfying answer. If we make any type of relationship to other model in Odoo (in any framework as well) it won't store the data inside it, it will only store its id. Now when the related model get changed, the change will also true for all the child models that's inheriting it.
I want just like in the Sale module, when I change any product in Products model, it doesn't change the same product that's already stored in the orders. Please, any help, I'm very new here to Odoo I used to develop with Java.
An order correspond to the model named sale.order which is in one2many relationship with the model sale.order.line (SOL). one SOL has it s OWN fields for price, vat... which are computed bases on the current state of product at the time of the customer order. That's why the order and its SOL are not updated when the corresponding product attributes (price...) are changed...
In Odoo : an inherited python class EXTENDS the original class (similar to java extends) : in the sale_coupon module, the model located at src/odoo/addons/sale_coupon/models/sale_order.py is :
class SaleOrder(models.Model):
_inherit = "sale.order"
extends the source class SaleOrder defined in the module sale : src/odoo/addons/sale/models/sale.py:
class SaleOrder(models.Model):
name = "sale.order"
That's mean that the inherited class SaleOrder (_inherit) gets the specific attributes (fields) and methods (def) provided and defined in its source(s) class(es) : saleOrder :
origin = fields.Char(string='Source Document', help="Reference of the document that generated this sales order request.")
def _amount_all(self):
""" Compute the total amounts of the SO."""
for order in self:
amount_untaxed = amount_tax = 0.0
for line in order.order_line:
amount_untaxed += line.price_subtotal
amount_tax += line.price_tax
...
And you can add new fields and new methods in your inherited class SaleOrder scope :
reward_amount = fields.Float(compute='_compute_reward_total')
def action_confirm(self):
self.generated_coupon_ids.write({'state': 'new'})
...
return super(SaleOrder, self).action_confirm()
But, you don t need to instantiate theses Classes in your code (you don t need to create yourself Objects).
Theses classes have the basic CRUD-methods provided from models.Model: def create(), def read(), def write(), def unlink()
The source and the inherited class(es) both are connected to the same database-table : sale_order
So one Class-record (python in Odoo) :
self.env['sale.order'].browse(12)
corresponds to one record in the database-table : sale_order
Theses classes (SaleOrder) have the CRUD-methods from model.Model : def create(), def read(), def write(), def unlink() and they can override them in their own scope, where you can optionally call the "parent"-def : super(SaleOrder, self).unlink() :
def unlink(self):
for order in self:
if order.state not in ('draft', 'cancel'):
raise UserError(_('You can not delete a sent quotation or a confirmed sales order. You must first cancel it.'))
return super(SaleOrder, self).unlink()
Relations betweens models are defined using fields :
A relation between the sale.order model and the res.partner model (contact) is created using fields.Many2one:
class SaleOrder(models.Model):
...
partner_id = fields.Many2one('res.partner')
which is reflected in the corresponding database-table.
First of all, If you change the product details It will these details will change accordingly in the sale order after you refresh, about store the id of relation field its the standard way to use,
but there Is another way I think this is the way you looking for which Is store data as a JSON in column with type JSON as an example for sale order line table if you want to store the product as a JSON column it will be like below:
[{"id": 1, "name": "product 1"},]
of course, there Is a way to read and update and create the data into a JSON column you can read about It.
one more way as an example if you want to store the product to the current record of relation table not just store the Id and query to get the result you can just create new fields for data you want to store like if you want to store the name and price with name and id then you must add fields for this date and when you create in order line rather than add just product Id as a relation just add the product data to the new fields you have added before but this is not a good way.
I hope I understand your question and this answer helps you.

How to disable "You have been assigned" email when a user creates a sales order in Odoo 10

In Odoo 10, when user "A" creates a new sales order and assigns it to a different salesperson (user "B"), no matter what configuration you have applied to email templates/subtypes/send notifications, an email is automatically sent to the customer and the salesperson (I am still amazed on which business logic was follow to send internal notification emails to customers by default).
The email is the well known one with this format:
"You have been assigned to SOxxxx."
To make things worse the email is set to "Auto-delete", so you do not even know what your system is sending to customers (no comments).
Which module or function or setting in Odoo 10 CE shall be overwritten to avoid such default behaviour?
Overwrite _message_auto_subscribe_notify method for sale.order class and add to context mail_auto_subscribe_no_notify.
from odoo import models, api
class SaleOrder(models.Model):
_inherit = 'sale.order'
#api.multi
def _message_auto_subscribe_notify(self, partner_ids):
""" Notify newly subscribed followers of the last posted message.
:param partner_ids : the list of partner to add as needaction partner of the last message
(This excludes the current partner)
"""
return super(SaleOrder, self.with_context(mail_auto_subscribe_no_notify=True))\
._message_auto_subscribe_notify(partner_ids)
The original method will not send the message if that key is passed in the context
#api.multi
def _message_auto_subscribe_notify(self, partner_ids):
""" Notify newly subscribed followers of the last posted message.
:param partner_ids : the list of partner to add as needaction partner of the last message
(This excludes the current partner)
"""
if not partner_ids:
return
if self.env.context.get('mail_auto_subscribe_no_notify'): # Here
return
# send the email only to the current record and not all the ids matching active_domain !
# by default, send_mail for mass_mail use the active_domain instead of active_ids.
if 'active_domain' in self.env.context:
ctx = dict(self.env.context)
ctx.pop('active_domain')
self = self.with_context(ctx)
for record in self:
record.message_post_with_view(
'mail.message_user_assigned',
composition_mode='mass_mail',
partner_ids=[(4, pid) for pid in partner_ids],
auto_delete=True,
auto_delete_message=True,
parent_id=False, # override accidental context defaults
subtype_id=self.env.ref('mail.mt_note').id)
If this should only be disabled for SaleOrder which are generated through custom code (e.g. an developed API endpoint), you could use the with_context() method on each model:
sale_order = {
'partner_id': partner['id'],
'state': 'sent',
'user_id': 6,
'source_id': 3,
'currency_id': currency['id'],
'payment_term_id': payment_term['id'],
}
created_sale_order = request.env['sale.order'].with_context(mail_auto_subscribe_no_notify=True).create(sale_order)
In my example, the user with the ID 6 does not get the notification about the assignment of this sale order.

Odoo: Set default team of a module from settings page

Having created a view on the res.config page, I implemented a many2one field which lists the set of existing teams on the Helpdesk Module. What I would like to do is set the default helpdesk team upon the creation of a ticket automatically (By default this is "Customer Care"). So basically, the team the user chooses in my custom field on the res.config view would be the default helpdesk team. What would be the best way to implement this?
this could be easily achieved using the context in the action:
<field name="context">{'default_team_id': active_id}</field>
or you could do it programmatically (not advisable) using lambda default function as following:
team_id = fields.Many2one(comodel_name='helpdesk.team', default=_default_team_id)
def _default_team_id(self):
team_id = self.env.ref('my_module.best_team_ever').read()[0]
return team_id
# update using configuration would be:
def _default_team_id(self):
get_param = self.env['ir.config_parameter'].sudo().get_param
default_team = get_param('helpdesk.my_custom_default_team')
return default_team

How to send multiple values in many2many field in odoo?

I am trying to generate purchase order from manufacturing order.I have created many2many field for getting multiple products.I want to send multiple product ids to my custom function.I am able to send 1 value but sending more than one gives error as Expected singleton: product.template(4, 3).
from openerp import models,fields,api
class generate_purchase_order(models.Model):
_name = 'mrp_to_purchase_order'
product_id = fields.Many2many('product.template',string='Products',required=True)
#api.multi
def generate_purchase_order2(self):
for wizard in self:
mrp_obj = self.env['mrp.production']
mrp_obj.generate_purchase_order(wizard.product_id.id) #function call
return { 'type': 'ir.actions.act_window_close'}
mrp_custom.py,
from openerp import models,api
class mrp_production(models.Model):
_inherit = 'mrp.production'
#api.multi
def generate_purchase_order(self,product_id):
purchase_line_obj = self.env['purchase.order.line']
context = self._context
for order in self.browse(context['active_ids']):
for line in order.bom_id.bom_line_ids:
if line.product_id.id != product_id:#problem line
continue
#rest of code
singleton: product.template(4, 3)
This error means that code is expecting single record not recordset, so you must change code to allow recordset using or make ensureone with try-catch and avoid errors. Thats general information.
Now if you want to get multiple records from many2many its not problem at all, you must pass this many2many object only and then work with it.
After getting many2many object to work with every record from this recordset you must use for record in recordset:
Also wizard.product_id.id this is error!!! product_id is many2many so you must pass product_id or if you want to browse by yourself you must pass product_id.ids

How to pass an external id to a domain filter

I have a Many2One field accepting a product in my model, but I want to limit this field to a specific product template, using the said template external id (The XML id).
I've try this without success:
#This piece of code doesn't work
the_product = fields.Many2one('product.product',
domain = [('product_tmpl_id','=', "ref('the_package.the_external_id')")])
How can I do this?
The solution to this problem is to use a function that returns the filters parameters. That way, we have access to the self variable in the body of the function, and therefore, we can use it to search specific external ids.
#api.model
def _get_domain(self):
# We have access to self.env in this context.
ids = self.env.ref('the_package.the_external_id').ids
return [('product_tmpl_id','=', ids)]
the_field = fields.Many2one('product.product',
required=False,
domain = _get_picking_product_domain)
The above solution does does not work.
Error :
ProgrammingError: can't adapt type 'model_name'
But try this:
You don't have to insert domain in your field :
#api.onchange('field_a')
def fiel_change(self):
dom['field_a'] = [(*)] #* type your domain
return {'domain':dom}