I have this function it filters in all selected MO's raw material lines, and then creates a report that is displayed in tree view.
But I have one problem, there can be allot lines with the same product. So my goal is to group all these lines and display them then just in one line with summed quantity.
Can someone help me with this?
class RawMaterialReport(models.Model):
_name = 'raw.material.report'
_description = 'Raw Material Report'
product_id = fields.Many2one('product.product', string='Product', required=False)
code = fields.Char(string='Code', required=True, readonly=True)
total_qty = fields.Float(string='Total Qty', digits=(6, 2), readonly=True)
virtual_qty = fields.Float(string='Forcasted Qty', digits=(6, 2), readonly=True)
origin = fields.Char(string='Origin', required=True, readonly=True)
production_id = fields.Many2one('mrp.production')
#api.multi
def open_raw_materials(self):
self.search([]).unlink()
mrp_productions = self._context.get('active_ids')
mrp_production = self.env['mrp.production'].browse(mrp_productions)
products_without_default_code = mrp_production.mapped('move_raw_ids').filtered(
lambda x: not x.product_id.default_code
)
raws = mrp_production.mapped('move_raw_ids').sorted(
key=lambda r: r.product_id.default_code
)
for r in raws:
vals = {
'product_id': r.product_id.id,
'code': r.product_id.default_code,
'total_qty': r.product_id.qty_available,
'virtual_qty': r.product_id.virtual_available,
'origin': r.reference,
'production_id': r.raw_material_production_id.id,
}
self.create(vals)
Instead of creating the record directly, keep them in dictionary grouped by product ID and when ever you find that the product all ready have a record just sum its
quantity.
#api.multi
def open_raw_materials(self):
self.search([]).unlink()
mrp_productions = self._context.get('active_ids')
mrp_production = self.env['mrp.production'].browse(mrp_productions)
products_without_default_code = mrp_production.mapped('move_raw_ids').filtered(
lambda x: not x.product_id.default_code
)
raws = mrp_production.mapped('move_raw_ids').sorted(
key=lambda r: r.product_id.default_code
)
# to group by product
recs = {}
for r in raws:
product_id = self.product_id.id
if product_id in recs:
# here just update the quantities or any other fields you want to sum
recs[product_id]['product_uom_qty'] += self.product_id.product_uom_qty
else:
# keep the record in recs
recs[product_id] = {
'product_id': r.product_id.id,
'code': r.product_id.default_code,
'total_qty': r.product_id.product_uom_qty,
'virtual_qty': r.product_id.virtual_available,
'origin': r.reference,
'production_id': r.raw_material_production_id.id,
}
for vals in recs.values():
# create records this will create a record by product
self.create(vals)
Related
I have an Inventory module. I want to check db before creating data. Check for reference code. If ref_code already exist then cancel the creation.
This is my .py file:
ref_code = fields.Char(string="Referans Numarası: ", required=True, tracking=True, related="products_id.ref_no")
#product_name = fields.Char(string="Ürün Adı: ", required=True, tracking=True)
product_description = fields.Char(string="Ürün Tanımı: ", tracking=True,)
teslim_alan = fields.Char(string="Teslim Alan: ", required=True, tracking=True,)
teslim_eden = fields.Char(string="Teslim Eden: ", required=True, tracking=True,)
quantity = fields.Float(string="Miktar: ", required=True, tracking=True)
price = fields.Float(string="Fiyat(€): ", required=True, tracking=True, related="products_id.unit_price")
unit_price = fields.Float(string="Birim Fiyat(€): ", compute="_unitPriceCalcuteFunc")
scrap_quantity = fields.Float(string="Hurdaya Taşınacak Miktar: ")
warehouse_id = fields.Many2one('ware.houses', string='Depo Adı: ')
products_id = fields.Many2one('products', string='Ürün: ')
state = fields.Selection([
('unapproved', 'Çıkış İçin Onay Verilmedi.'),
('approved', 'Çıkış İçin Onay verildi.')], string="Status", default="unapproved", tracking=True)
cikis_line_ids = fields.One2many('inventory.out.report.lines', 'inventory_id', string='Çıkış Listesi')
#api.model
def create(self, values):
global count
count = 0
value = self.env['inventory.menu'].search([])
for record in values:
for v in value:
print(v.ref_code, record.ref_code)
if(v.ref_code == record.ref_code):
count += 1
return print("Zaten Var!")
if(count == 0):
return super(InventoryMenu, self).create(values)
I can find the all data in db. It is ok. But the current data is not exist, i can't use it. I need the compare current data with db data.
How can i do it? Many thanks..
#api.model
def create(self, values):
global count
count = 0
value = self.env['inventory.menu'].search([])
for v in value:
if(v.ref_code == values['ref_code']):
count += 1
return print("Zaten Var!")
if(count == 0):
return super(InventoryMenu, self).create(values)
enter code here
You can search for the specific ref_code. Just didn't do something like search([]) cause it's contrproductive.
#api.model
def create(self, values):
ref_codes_count = self.env['inventory.menu'].search(
[("ref_code", "=", values.get("ref_code"))],
count=True,
)
if not ref_codes_count:
return super(InventoryMenu, self).create(values)
or you can try to use something like this
#api.model
def create(self, values):
self.env.cr.execute(
"SELECT COUNT(*) FROM module_name.model_name WHERE ref_code='%s'" %
values.get("ref_code")
)
ref_codes_count = self.env.cr.fetchall()[0]
if not ref_codes_count:
return super(InventoryMenu, self).create(values)
I have inherited account.move model and added job_card_id field(many2one) in it, as shown as below :
Image
Below given is Image of Selected Job Card :
Image
Below given is code of my model and I also tried creating function below fields :
class JobCard(models.Model):
_name = "job.card"
_inherit = ['mail.thread', 'mail.activity.mixin']
_description = "Job Card Master"
_rec_name = 'job_card_number'
job_card_number = fields.Char(string='Job Card No.', readonly=True)
customer_id = fields.Many2one('res.partner', string="Customer Name", tracking=True)
vehicle_id = fields.Many2one('res.partner.line', string="Vehicle", tracking=True,
domain="[('x_customer_id','=',customer_id)]")
date_time_of_invoice = fields.Datetime(string='Date & Time of Invoice', tracking=True, default=fields.Datetime.now)
start_date_time = fields.Datetime(string='Start Date & Time', tracking=True)
end_date_time = fields.Datetime(string='End Date & Time', tracking=True)
priority = fields.Selection([
('0', 'Normal'),
('1', 'Low'),
('2', 'High'),
('3', 'Very High')], string="Priority") # priority widget
state = fields.Selection([
('draft', 'Draft'),
('in_progress', 'In Progress'),
('done', 'Done'),
('cancel', 'Cancelled')], string="Status", default='draft', required=True) # status bar
active = fields.Boolean(string="Active", default=True, tracking=True)
x_product_ids = fields.Many2many('job.card.line', 'product_id', string="Job Card Details")
x_quantity_ids = fields.One2many('job.card.line', 'quantity', string="Job Card Details")
x_price_ids = fields.One2many('job.card.line', 'price', string="Job Card Details")
x_total_ids = fields.One2many('job.card.line', 'total', string="Job Card Details")
x_employee_ids = fields.One2many('job.card.line', 'employee_id', string="Job Card Details")
x_job_card_ids = fields.One2many('job.card.line', 'job_card_id', string="Job Card Details")
job_card_count = fields.Integer(compute='compute_job_card_count', string='Job Card Count')
def get_invoice_line_vals(self):
vals_list = []
for job_card_line in self.x_product_ids:
vals_list.append({
' price_unit': job_card_line.price_unit,
'quantity': job_card_line.quantity
})
return vals_list
Below given is code of inherited model and also added onchange function :
class CustomInvoice(models.Model):
_inherit = "account.move"
job_card_id = fields.Many2one('job.card', string="Job Card", domain="[('customer_id','=',partner_id)]",
tracking=True)
#api.onchange('job_card_id')
def _onchange_job_card_id(self):
# creates your invoice lines vals according to your values
invoice_lines_vals = self.job_card_id.get_invoice_line_vals()
self.update({'invoice_line_ids': [(5, 0)] + [(0, 0, vals) for vals in invoice_lines_vals]})
Below given is code of my job card line :
class JobCardLine(models.Model):
_name = "job.card.line"
job_card_id = fields.Many2one('job.card', string="Job Card Id", tracking=True)
product_id = fields.Many2one('product.template', string="Product", tracking=True)
quantity = fields.Integer(string="Quantity", tracking=True)
# price = fields.Char(string="Price")
price = fields.Float(string="Price")
total = fields.Integer(string='Total', compute='_compute_total', tracking=True,
help="This field will be calculated from quantity and price !")
employee_id = fields.Many2one('hr.employee', string="Employee", tracking=True)
x_job_card_id = fields.Many2one('res.partner', string="Vehicle Details")
#api.onchange('product_id')
def _on_change_product_id(self):
self.price = self.product_id.list_price
#api.depends('quantity', 'price')
def _compute_total(self):
print("self........", self)
for rec in self:
rec.total = rec.quantity * rec.price
Actually I wanted to add product line of selected job card into Invoice product line automatically when I select the job card.
But I am getting error as shown below :
Error
You got that error because you have no field named line_ids in job.card model. Maybe you need to change it to x_product_ids.
The TyprError (int object is not iterable) is caused by the first tuple passed to the write method :
(6, 0, 0)
Odoo expects the third parameter to be iterable. If you need to clear the list, use (5,0)
Avoid calling the write method inside an onchange function. You can read the following danger notice in the official onchange documentation:
DangerSince #onchange returns a recordset of pseudo-records, calling any one of the CRUD methods (create(), read(), write(), unlink()) on the aforementioned recordset is undefined behaviour, as they potentially do not exist in the database yet.Instead, simply set the record’s field like shown in the example above or call the update() method.
Edit:
You have two errors in get_invoice_line_vals function
1/ ValueError:
Invalid field ' price_unit' on model 'account.move.line'
You need to remove the space at the beginning.
2/ AttributeError:
'job.card.line' object has no attribute 'price_unit'.
Use the price field instead.
In res.partner model I have a field
property_product_pricelist = fields.Many2many('product.pricelist')
and in sale.order
alternative_pricelist_ids = fields.Many2many(
'product.pricelist')
Partner can have more than one price list so my goal is to add the first pricelist to the pricelist_id field and other pricelists to alternative_pricelist_ids. The things are that how I wrote code is not really good, as you can see I will get an error if there are more than 4 pricelists. So how can I avoid it and write it another way?
#api.multi
#api.onchange('partner_id')
def onchange_partner_id(self):
super(SaleOrder,self).onchange_partner_id()
values = { 'pricelist_id': self.partner_id.property_product_pricelist[0] and self.partner_id.property_product_pricelist.id[0] or False,
'alternative_pricelist_ids': self.partner_id.property_product_pricelist[1] and self.partner_id.property_product_pricelist[2] and self.partner_id.property_product_pricelist[3] or False,
}
self.update(values)
Try this :
#api.multi
#api.onchange('partner_id')
def onchange_partner_id(self):
super(SaleOrder, self).onchange_partner_()
for record in self:
pricelist_id = False
alternative_ids = []
for pricelist in record.partner_id.property_product_pricelist:
if not pricelist_id:
pricelist_id = pricelist.id
else:
alternative_ids.append(pricelist.id)
record.pricelist_id = pricelist_id
record.alternative_pricelist_ids = [(6, 0, alternative_ids)]
I am trying to create a sample order in sales order.In the sample order form, products are sold to customers as complimentary copy(books in my case) without charging any money so I have created a separate sub-menu in sales menu.Here I take only product and quantity as input. Sample order number will be the next number from the sales order(like SO360).So I am fetching sales order number as parent_id in my inherited module.I am not able to create sale order line(data in order lines tab)
class SaleOrder(models.Model):
_inherit = 'sale.order'
# Fields
is_sample = fields.Boolean(string="Sample Order", default=False)
parent_id = fields.Many2one('sale.order', string="Parent Sales Order")
sample_ids = fields.One2many('sale.order', 'parent_id',
string="Sample Orders")
# Methods
#api.model
#api.returns('sale.order')
def create(self, vals):
if vals.get('is_sample', False) and vals.get('name', '/') == '/':
IrSeq = self.env['ir.sequence']
ref = IrSeq.next_by_code('sale.order.sample.ref') or '/'
parent = self.search([('id', '=', vals.get('parent_id'))])
vals['name'] = parent.name + ref
vals['user_id'] = parent.user_id.id
return super(SaleOrder, self).create(vals)
class SampleOrderWizard(models.TransientModel):
_name = 'sale.order.sample.wizard'
_description = 'Sample Sale Order Wizard'
# Field default values
#
def _get_parent(self):
res = False
if self.env.context \
and 'active_id' in list(self.env.context.iterkeys()):
res = self.env.context['active_id']
return res
def _get_new_sale_line(self, orig_sale, orig_sale_line, wizard_line):
"""Internal function to get the fields of the sale order line. Modules
enhancing this one should add their own fields to the return value."""
res = {
'order_id': orig_sale.id,
'product_id': orig_sale_line.product_id.id,
'name': orig_sale_line.name,
'sequence': orig_sale_line.sequence,
'price_unit': orig_sale_line.price_unit,
'product_uom': orig_sale_line.product_uom.id,
'product_uom_qty': wizard_line and wizard_line.qty or 0,
'product_uos_qty': wizard_line and wizard_line.qty or 0,
}
# Simple check for installation of sale_line_code module
if hasattr(orig_sale_line, 'order_line_ref'):
res.update({'order_line_ref': orig_sale_line.order_line_ref})
return res
def _get_order_lines(self, sale):
res = []
for line in sale.order_line:
wizard_line = False
for wzline in self.wizard_lines:
if wzline.product == line.product_id:
wizard_line = wzline
break
if wizard_line:
res.append(
(0, 0, self._get_new_sale_line(sale, line, wizard_line))
)
return res
def _get_wizard_lines(self):
res = []
if self._get_parent():
SaleOrder = self.env['sale.order']
parent = SaleOrder.search([('id', '=', self._get_parent())])
for line in parent.order_line:
res.append((0, 0,
{
'product': line.product_id,
'qty': 1,
}))
return res
# Fields
#
order = fields.Many2one('sale.order', default=_get_parent, readonly=True)
wizard_lines = fields.One2many('sale.order.sample.wizard.line', 'wizard',
default=_get_wizard_lines)
order_date = fields.Datetime(default=fields.Datetime.now())
# Methods
#
#api.one
def create_order(self):
sale_vals = {
'user_id': self.order.user_id.id,
'partner_id': self.order.partner_id.id,
'parent_id': self.order.id,
'date_order': self.order_date,
'client_order_ref': self.order.client_order_ref,
'company_id': self.order.company_id.id,
'is_sample': True,
'order_line': self._get_order_lines(self.order)
}
self.env['sale.order'].create(sale_vals)
return {'type': 'ir.actions.act_window_close'}
class SampleOrderWizardLine(models.TransientModel):
_name = 'sale.order.sample.wizard.line'
_description = 'Sample Order Wizard Line'
wizard = fields.Many2one('sale.order.sample.wizard')
product = fields.Many2one('product.product',
domain=[('sale_ok', '=', True)])
qty = fields.Float(string="Quantity", default=1.0,
digits_compute=dp.get_precision('Product UoS'))
I am trying to convert openerp 7 code to odoo8. In V7 browse() method had several parameters like self,cr,uid,ids,context but in V8 I think none of these is needed.In my custom module I am trying to create a purchase order based on the information obtained from mrp.I have done a custom calculation for how many Kgs of paper needed for 10000 quantities of books to be manufactured.After calculation this info should go to purchase invoice.Products will be obtained from bill of materials,quantity from no of kgs of paper needed and unit price from product cost attribute.I am unable to solve this error "method takes exactly 1 argument (5 given)"
mrp.py,
from openerp import models
class mrp_production(models.Model):
_inherit = 'mrp.production'
def generate_purchase_order(self,supplier_id,warehouse_id):
purchase_obj = self.env['purchase.order']
purchase_line_obj = self.env['purchase.order.line']
warehouse_obj = self.env['stock.warehouse']
warehouse = warehouse_obj.browse(warehouse_id)
if not warehouse:
return False
if isinstance(warehouse, list):
warehouse = warehouse[0]
for order in self:
vals = {}
vals = purchase_obj.onchange_partner_id()
vals['origin'] = order.name
vals['partner_id'] = supplier_id
vals['warehouse_id'] = warehouse_id
vals['location_id'] = warehouse.lot_stock_id.id
vals['date_order'] = order.date_planned
purchase_id = purchase_obj.create(vals)
for line in self.bom_id.bom_line_ids:
if not line.product_id:
continue
line_vals = purchase_line_obj.onchange_product_id(line.product_id.id,
line.product_uom_qty, line.product_uom.id, supplier_id,
date_planned=line.date_planned)['value']
line_vals['name'] = line.name
line_vals['product_id'] = line.product_id.id
if not line_vals.get('price_unit', False):
line_vals['price_unit'] = line.product_id.list_price
line_vals['product_uom'] = line.product_uom.id
line_vals['product_uom_qty'] = 181.13
line_vals['order_id'] = purchase_id
purchase_line_obj.create(line_vals)
return True
generate_purchase_order.py,
from openerp import models,fields,api
class generate_purchase_order(models.Model):
_name = 'mrp_to_purchase_order.generate_purchase_order'
_description = 'Generate Purchase Order'
partner_id = fields.Many2one('res.partner', 'Supplier', required=True, domain="[('supplier','=',True)]")
warehouse_id = fields.Many2one('stock.warehouse', 'Warehouse', required=True)
#api.multi
def onchange_partner_id(self,partner_id):
return {}
def generate_purchase_order(self):
for wizard in self:
#mrp_order_ids = [context['active_id']]
mrp_obj = self.env['mrp.production']
mrp_obj.generate_purchase_order(wizard.partner_id.id, wizard.warehouse_id.id)
return { 'type': 'ir.actions.act_window_close'}
If you are calling the generate_purchase_order method from some other method in your model, then use the decorator #api.multi for that method.
Also in your generate_purchase_order method, replace
for order in self.browse():
by
for order in self:
EDIT
#api.multi
def generate_purchase_order(self):
for wizard in self:
#mrp_order_ids = [context['active_id']]
mrp_obj = self.env['mrp.production']
# Get the mrp record
mrp_rec = code to get mrp record
mrp_rec.generate_purchase_order(wizard.partner_id.id, wizard.warehouse_id.id)
return { 'type': 'ir.actions.act_window_close'}