Loop through record lines method - Odoo v8 - python

I have this method:
#api.onchange('qty', 'consumed_qty')
def _remaining_func(self):
for qty in self.isbn:
if self.qty or self.consumed_qty:
self.remaining_qty = self.qty +(-self.consumed_qty)
But I need it to loop through records of my line (One2many field), right now, if I add just one record it works just fine, but if I add two or more, it throws the Expected singleton error.
So, how can I loop with this method?
I have added the for qty in self.isbn but with no success.
This is the class where this method is declared:
class bsi_production_order_lines(models.Model):
_name = 'bsi.production.order.lines'
production_order = fields.Many2one('bsi.production.order', string="Production Orders")
isbn = fields.Many2one('product.product', string="ISBN", domain="[('is_isbn', '=', True)]")
qty = fields.Float(string="Quantity")
consumed_qty = fields.Float(string="Consumed quantity")
remaining_qty = fields.Float(string="Remaining quantity", compute="_remaining_func")
Any ideas?

you could try:
#api.onchange('qty', 'consumed_qty')
def _remaining_func(self):
for s in self:
for qty in s.isbn:
if s.qty or s.consumed_qty:
s.remaining_qty = s.qty +(-s.consumed_qty)
I hope this help you.

Related

Perform CRUD operations on product class?

I'm a newbie to Django-oscar and I'm trying to develop a simple CRUD operation on Product. I've forked the catalogue app and created a views.py file
I fired the query Product.objects.create(title='Hello') and a product does get created with the following error:
AttributeError: 'NoneType' object has no attribute 'attributes'
product_title = 'MyPhone'
upc=987654321
product_class = ProductClass.objects.get_or_create(name='Phone')
def createProduct(request):
line1
product.name = product_title
product.product_class = product_class
product.upc=upc
product.save()
When I put product=Product() in line1 I get the following error:
Cannot assign "(, False)": "Product.product_class" must be a "ProductClass" instance.
When I put product = Product.objects.create(upc=upc) I get the following error :
NoneType' object has no attribute 'attributes'
Anyone guide me on how to write a simple create operation?
ProductClass, Product, Category, ProductCategory = get_classes(
'catalogue.models', ('ProductClass', 'Product', 'Category',
'ProductCategory'))
create_from_breadcrumbs = get_class('catalogue.categories', 'create_from_breadcrumbs')
def _create_item(product_class, category_str, upc, title,
description, stats):
# Ignore any entries that are NULL
if description == 'NULL':
description = ''
# Create item class and item
product_class, __ = ProductClass.objects.get_or_create(name=product_class)
try:
item = Product.objects.get(upc=upc)
stats['updated_items'] += 1
except Product.DoesNotExist:
item = Product()
stats['new_items'] += 1
item.upc = upc
item.title = title
item.description = description
item.product_class = product_class
item.save()
# Category
cat = create_from_breadcrumbs(category_str)
ProductCategory.objects.update_or_create(product=item, category=cat)
return item
This is the actual way to manipulate products with provided information to the function in django oscar. For better design decisions you need to follow this convention. Modify it as you want. Let me know if you want more help. Thank you.

Odoo: How to create many records in Transient.Model?

This code only creates one record. What is wrong?
class PartnerTagCreate(models.TransientModel):
""" Choose tags to be added to partner."""
_name = 'partner.tags.create'
_description = __doc__
market_id = fields.Many2one('partner.tags', string='Market Tag')
application_id = fields.Many2one('partner.tags', string='Application Tag')
partner_id = fields.Integer()
#api.multi
def create_contact_tag(self):
for record in self.env['sale.order.line'].browse(self._context.get('active_ids', [])):
vals = {}
vals['partner_id'] = record.order_partner_id
self.write(vals)
return True
I need this function to create one record for each order_partner_id I selected before opening the wizard...
How to achieve that?
Here my new code (function) ...
def create_contact_tag(self):
sale_order_line_ids = self.env['sale.order.line'].browse(self._context.get('active_ids', []))
for partner in sale_order_line_ids:
values = {}
values['partner_id'] = partner.order_partner_id
self.create(values)
return {}
This creates one record for marketing_id and/or application_id and dedicated records for each partner_id in the record.
You use the 'create' method to create new records; this is the same for TransientModel as for the persistent Model.
So, replace
self.write(vals)
by
self.create(vals)
and you should be fine.

Show one2many field in a tree view of different model [Odoo]

I want to display all the taxes that are applied in a particular invoice and their amounts[in the tree view of a model account.invoice]
This is the output:
The column Tax Lines shows the ids of the taxes that are present in table account.invoice.tax (whereas I want to show their names and corresponding amount)
The model account.invoice has a field called tax_line_ids[Tax Lines] that contains the record of all the taxes on a invoice which is stored in a separate table account.invoice.tax, which in its own tree view looks like this:
I want to extract the tax name and its corresponding amount for it to reflect in account.invoice's tree view
Here's my python code which does'nt seem to work:
#api.one
def taxz(self):
tax_pool = self.pool.get("account.tax")
found_taxes = tax_pool.read(cr, uid, [tax_id,], ["tax_line_ids"], context)
found_tax = found_taxes[0] if found_taxes else None
tax_line_ids = found_tax["tax_line_ids"]
_logger.critical("context type: " + type(context))
_logger.critical("context content: " + str(context))
_logger.critical(tax_line_ids)
xml code for the view:
<field name="tax_line_ids" widget="many2many_tags" />
Try this:
class Invoice(models.Model):
_inherit = 'account.invoice'
tax_line_ids = fields.Many2many('account.invoice.tax',
'invoice_taxes',
'invoice_id',
'taxt_id',
'List of taxes',
compute='get_tax_list', store=True)
#api.depends('tax_line', 'tax_line.amount')
def get_tax_list(self):
for rec in self:
if rec.taxe_line:
rec.tax_line_ids = [(6,0,rec.tax_line.ids)]
else:
rec.tax_line_ids = [(5,0,0)]
But doing this will just show the list of taxes without amount in your tree view
if you want to show the amount you need to override the name_get method in account.invoice.tax
but this will affect all the x2many fields.
class AcountInvoiceTax(models.Model):
_inherit = 'account.invoice.tax'
#api.multi
def name_get(self):
res = []
for rec in self:
res.append((rec.id, rec.name +': '+ str(rec.amount)))
return res
If you don't want this then you need to change the type to Char and recompute the field
or create another model to save taxes and define name_get for that model.
As you can see this worked for me now if you still getting the keyErro you must be doing some thing wrong check your code for indentation inherit value... :
You can do add a char field just to use it in display in treeview :
class Invoice(models.Model):
_inherit = 'account.invoice'
tax_line_tree_view = fields.Char(compute='get_tax_list')
#api.multi
def get_tax_list(self):
tax_disp = ""
for rec in self:
if rec.taxe_line:
for tax in taxe_line:
tax_disp = tax_disp + "["+tax.name+"], "
rec.tax_line_tree_view = tax_disp[:-2] # [:-2] just to remove the last ', ' characters.
else:
rec.tax_line_tree_view = tax_disp
In your XML file where tree_view is located, add this field:
<field name="tax_line_tree_view " />
instead of tax_line_ids.
I hope that answer your question.

Read product qty on lines and on warehouses

I need to check in my lines, the products I have, their respective quantities, and know what is the availability of such products in warehouses, the stock.move and stock.picking do something like that, but it's old api, I need a custom method.
This is my method:
class bsi_production_order(models.Model):
_name = 'bsi.production.order'
name = fields.Char('Reference', required=True, index=True, copy=False, readonly='True', default='New')
date = fields.Date(string="Production Date")
production_type = fields.Selection([
('budgeted','Budgeted'),
('nonbudgeted','Non Budgeted'),
('direct','Direct Order'),
], string='Type of Order', index=True,
track_visibility='onchange', copy=False,
help=" ")
notes = fields.Text(string="Notes")
order_lines = fields.One2many('bsi.production.order.lines', 'production_order', states={'finished': [('readonly', True)], 'cancel': [('readonly', True)]}, string="Order lines", copy=True)
print_orders = fields.One2many('bsi.print.order', 'production_orders', string="Print Orders")
warehouse_quantity = fields.Char(compute='quantity', string='Quantity per warehouse')
class bsi_production_order_lines(models.Model):
_name = 'bsi.production.order.lines'
production_order = fields.Many2one('bsi.production.order', string="Production Orders")
isbn = fields.Many2one('product.product', string="ISBN", domain="[('is_isbn', '=', True)]")
qty = fields.Integer(string="Quantity")
consumed_qty = fields.Float(string="Consumed quantity")
remaining_qty = fields.Float(string="Remaining quantity")
I need to check from bsi.production.order on the order_lines One2many field, the isbn which is a product, how much of it is available on all the locations of the system, also, compare it to the qty field, so, from there I can go to another state on the object.
Think about the stock.picking or stock.move objects. It's basically the same logic.
So far, I've tried this method, to check if there is any line on the One2many object.
#api.multi
#api.depends('order_lines', 'order_lines.isbn')
def checkit(self):
#actual_stock = self.env['product.product'].browse(qty_available)
for record in self:
if self.order_lines:
for line in self.order_lines:
if line.isbn:
return line.isbn
else:
raise Warning(('Enter​ ​at least​ ​1​ ​ISBN to produce'))
This works so far, to check whether there is a isbn on the line, or not, I'll need to also check if there is enough on warehouse to make the calculation, and if there is, then proceed to the next stage, I'm only tuck on the stock.location part.
I've checked some other modules on stock management OCA repo, although there are similar routines, I couldn't find something really suitable to this.
There is this method, which seems quite likely what I need:
#api.multi
#api.depends('order_lines', 'order_lines.isbn')
def quantity(self):
for record in self:
warehouse_quantity_text = ''
isbn = self.env['product.product'].sudo().search([('product_tmpl_id', '=', record.id)])
if isbn:
quant_ids = self.env['stock.quant'].sudo().search([('isbn','=',isbn[0].id),('location_id.usage','=','internal')])
t_warehouses = {}
for quant in quant_ids:
if quant.location_id:
if quant.location_id not in t_warehouses:
t_warehouses.update({quant.location_id:0})
t_warehouses[quant.location_id] += quant.qty
tt_warehouses = {}
for location in t_warehouses:
warehouse = False
location1 = location
while (not warehouse and location1):
warehouse_id = self.env['stock.warehouse'].sudo().search([('lot_stock_id','=',location1.id)])
if len(warehouse_id) > 0:
warehouse = True
else:
warehouse = False
location1 = location1.location_id
if warehouse_id:
if warehouse_id.name not in tt_warehouses:
tt_warehouses.update({warehouse_id.name:0})
tt_warehouses[warehouse_id.name] += t_warehouses[location]
for item in tt_warehouses:
if tt_warehouses[item] != 0:
warehouse_quantity_text = warehouse_quantity_text + ' ** ' + item + ': ' + str(tt_warehouses[item])
record.warehouse_quantity = warehouse_quantity_text
But it doesn't works since it needs a field, also, I think it's far complex, there must be an easier way to do this checking.
In a nutshell: I need to check the quantities on the system, compare it to every isbn (product) on the line, which it'll be the qty field, if not enough, do nothing, if there is, then pass to the next state.
First if you want to check if the data is correct use #api.constrains not #api.depends, #api.depends if for computing.
From what is see isbn is many2one to product.product so just make that field required and check if order_lines is empty or not.
#api.constrains('order_lines', 'order_lines.isbn')
def checkit(self):
#actual_stock = self.env['product.product'].browse(qty_available)
for record in self:
# inside the loop use record not self
if self.order_lines:continue # if the order_lines contains one record go back and check the second record
# no need for other instruction because if the field is empty this will full
# another thing if you return the program will exit the function but you only
# checked one record what if someone user write with mutliple record
else: # here order_line is empty
raise Warning(('Enter? ?at least? ?1? ?ISBN to produce'))
but if some how you need to keep it unrequired i think will be much faster.
#api.constrains('order_lines', 'order_lines.isbn')
def checkit(self):
for record in self:
# inside the loop use record not self
if self.order_lines:
found_isbn = False
for line in self.order_lines:
if line.isbn:
found_isbn = True
break # no need to check other lines.
if not found_isbn: # after the looping the lines check if the isbn is found
raise Warning(('Enter at least one ISBN to produce'))
else: # here order_line is empty
raise Warning(('Enter? ?at least? ?1? ?ISBN to produce'))
and about the the quantity i didn't understand exactly what you need but i think this answer will help you a lot.
how to get available quantity of Lot number
and what you need to do is something like this.
if you want just to show a warning to user and don't stop him from working use onchange
#api.onchange('order_lines.qty')
def check_quantity(self):
if self.order_lines:
for line in rec.order_lines:
if line.qty > line.isbn.qty_available:
# return warning or validation error if it's restricted .
return {'warning': {
'title': _('Warning'),
'message': _('Quantity is invalid.')
}
but if this operation is restricted and should not be saved in database use constrains:
#api.constrains('order_lines.qty')
def check_quantity(self):
for rec in self:
if rec.order_lines:
for line in rec.order_lines:
if line.qty > line.isbn.qty_available:
# raise validation error to user .

Python populating a database with one-to-many relationship

I'm a beginner, so please go easy on me. I am working on a script so that I don't have to keep entering in data when I decide to drop the database. My entire script works well, except when I'm dealing with a one-to-many relationship. It will not save to the database. Can anyone tell me what I am doing wrong or point me in the right direction?
SCRIPT:
try:
pmod.Instrument.objects.get(title='kjkjsdfsadfs')
except pmod.Instrument.DoesNotExist:
u = pmod.Instrument()
u.title = 'Bach 42 Trombone'
u.price = 550.00
u.soundDescription = 'Good'
u.functionalityDescription = 'Good'
u.damageDescription = 'Good'
u.accessoryDescription = 'Good'
u.customerName = 'Jake'
u.customerEmail = 'ks#gmail.com'
u.instrumentCategory = 1
print('Good2')
u.save()
print('Instrument1 saved')
MODEL:
class Category(models.Model):
instrumentCategory=models.CharField(max_length=50,blank=True,null=True)
def __str__(self):
return self.instrumentCategory
class Instrument(models.Model):
title = models.CharField(help_text='title',max_length=50,blank=True,null=True)
price = models.DecimalField(max_digits=8, decimal_places=2)
soundDescription=models.CharField(max_length=1000,blank=True,null=True)
functionalityDescription=models.CharField(max_length=1000,blank=True,null=True)
damageDescription=models.CharField(max_length=1000,blank=True,null=True)
accessoryDescription=models.CharField(max_length=1000,blank=True,null=True)
customerName=models.CharField(max_length=50,blank=True,null=True)
customerEmail=models.EmailField(max_length=254,help_text='Enter valid email address')
instrumentCategory=models.ForeignKey(Category)
u.instrumentCategory = 1
That's not how a models.ForeignKey field works in Django. You need to get an instance of the Category object and assign that to u.instrumentCategory.
u.instrumentCategory = pmod.Category.objects.get(id=1)
You may try :
u.instrumentCategory_id = 1

Categories