Get the sequence with existing field in odoo 10 - python

I need to get the order number related with its service order. Each service order has many bench orders. E.g.: If the service order number is 223 the bench orders related to that are 223-1, 223-2, 223-3... if SO number is 553, bench order numbers must be 553-1, 553-2, 553-3, etc.
I tried it several ways and I failed to do it. Please help me. I used Odoo sequence to do that, but it did not give the output as I want. Here is my code: (E.g.: 223 means work authorization number).
class MyDepots_so(models.Model):
_name = 'my_depots_so'
so_parts_ids = fields.One2many('tiq_so_parts', 'so_p_id', string='Add Part Details', invisible='1')
so_bo_ids = fields.One2many('my_depots.so_bo',
so_work_authorization = fields.Integer("Work Authorization#")
class SO_Parts(models.Model):
_name = 'tiq_so_parts'
so_p_id = fields.Many2one('my_depots_so',string='Add Service Order Part', invisible='1')
#api.model
def create(self, vals):
sequence = self.env['ir.sequence'].next_by_code('so.benchorder') or '/'
str_sequence = str(sequence)
query = """SELECT so_work_authorization FROM my_depots_so WHERE id=%d """ % (so_p_id)
self.env.cr.execute(query)
result = self.env.cr.fetchall()
result_number = json.dumps(result, ensure_ascii=False)
strip_number = result_number.strip('\' \" [] ')
work_auth_no = str(strip_number)
work_auth_no += "-"
work_auth_no += str_sequence

Ok, I think you are looking for something like this (I added a field to your tiq_so_parts model since you have to store the subsequence somewhere -where were you storing the 223-1, 223-2, 223-3... values?
I created the field part_sequence to store these values-).
class MyDepots_so(models.Model):
_name = 'my_depots_so'
so_parts_ids = fields.One2many('tiq_so_parts', 'so_p_id', string='Add Part Details', invisible='1')
so_bo_ids = fields.One2many('my_depots.so_bo',
so_work_authorization = fields.Integer("Work Authorization#")
class SO_Parts(models.Model):
_name = 'tiq_so_parts'
so_p_id = fields.Many2one('my_depots_so',string='Add Service Order Part', invisible='1')
part_sequence = fields.Char(string='Part Sequence')
#api.model
def create(self, vals):
so_part = super(SO_Parts, self).create(vals)
so_p_id = so_part.so_p_id
main_sequence = so_p_id.so_work_authorization
part_sequence = len(so_p_id.so_parts_ids)
so_part.write({
'part_sequence': str(main_sequence) + '-' + str(part_sequence),
})
return so_part

Related

Add computed field to custom filter as stored field in ODOO

customer_count = fields.Char(string='Customer Count', compute='cust_count')
class ResBuilding(models.Model):
_name = "res.partner.building"
_description = "Customer BUilding"
_order = "id desc"
region_id = fields.Many2one('res.state.city', string='Region', required=True, ondelete='cascade')
city_id = fields.Many2one('city.covered.area', string='Area', required=True, ondelete='cascade')
name = fields.Char(string='Name', required=True, translate=True, copy=False)
image = fields.Binary(string="Building image")
latitude = fields.Char(string='Latitude')
customer_count = fields.Char(string='Customer Count', compute='cust_count', store=True)
longitude = fields.Char(string='Longitude')
active = fields.Boolean(string='Active', default=True, track_visibility='onchange')
partner_ids = fields.One2many('res.partner', 'building_id', string='Customer List', readonly=True)
#api.multi
#api.depends('partner_ids')
def cust_count(self):
for record in self:
count = self.env['res.partner'].search_count([('building_id', '=', record.id)])
record.customer_count = count
#api.multi
def name_get(self):
result = []
for route in self:
name = route.city_id.name + '-' + route.name
result.append((route.id, name))
return result
#api.multi
def write(self, vals):
res = super(ResBuilding, self).write(vals)
print(vals, self.id)
if vals.get('city_id'):
customers = self.env['res.partner'].search([('building_id', '=', self.id)])
for c in customers:
c.living_area = vals.get('city_id')
return res
#api.multi
#api.depends('latitude', 'longitude')
def on_change_location(self):
for li in self:
if li.latitude and li.longitude:
self.env.cr.execute("""update res_partner set location_latitude=""" + str(li.latitude) + """,
location_longitude=""" + str(li.longitude) + """where building_id=""" + str(
li.id))
return True
#api.multi
def write(self, vals):
res = super(ResBuilding, self).write(vals)
self.on_change_region_id()
return res
#api.multi
#api.depends('region_id')
def on_change_region_id(self):
for li in self:
if li.region_id:
self.env.cr.execute(
"""update res_partner set city_id=""" + str(li.region_id.id) + """where building_id=""" + str(
li.id))
return True
I want find the customer count in a specific building based on building id. and want The coustomer_count field to be added to the add custom filter
by this code ,i am getting count correctly . But the field customer_count does not appear in custom filter
when i add store=True, the field is coming in custom filter but the count is coming as 0.
Your code is not correct, even with storing the field.
customer_count = fields.Char(
string='Customer Count', compute='cust_count', store=True)
#api.multi
#api.depends()
def cust_count(self):
for record in self:
count = self.env['res.partner'].search_count([('building_id', '=', record.id)])
record.customer_count = count
Always use for each loops in compute methods, because in case of multi relational fields using your building model or just by presenting this computed field in a list of your building model will lead to a multi recordset behind self.
But that's not all. There should be a possibility to trigger the recomputation of the field and if easy to do using depends. Right now i don't see any easy possibility, because i don't know all your relations and workflows. Without storing the field you probably don't need that, but it would work there too.
So what to do to trigger a recomputation? Just work up from the other site of the relation: res.partner. Override it's write, create and unlink method to trigger the recomputation "manually".
class ResPartner(models.Model):
_inherit = "res.partner"
#api.multi
def write(self, values):
old_buildings = self.mapped('building_id')
res = super(ResPartner, self).write(values)
if 'building_id' in values:
new_buildings = self.mapped('building_id')
trigger_buildings = old_buildins | new_buildings
trigger_buildings.cust_count()
return res
#api.model
def create(self, values):
partner = super(ResPartner, self).create(values)
partner.building_id.cust_count()
return partner
#api.multi
def unlink(self):
buildings = self.mapped('building_id')
res = super(ResPartner, self).unlink()
buildings.cust_count()
return res
Another way is to use a one2many field on your building model in relation to res.partner and fill depends with it, like depends('partner_ids'). But in my experience one2many fields in such and lot of other situations tend to lead to bad performance.

How to speed up writing in a database?

I have a function which search for json files in a directory, parse the file and write data in the database. My problem is writing in database, because it take around 30 minutes. Any idea how can I speed up writting in a database? I have few quite big files to parse, but parsing the file is not a problem it take around 3 minutes. Currently I am using sqlite but in the future I will change it to PostgreSQL.
Here is my function:
def create_database():
with transaction.atomic():
directory = os.fsencode('data/web_files/unzip')
for file in os.listdir(directory):
filename = os.fsdecode(file)
with open('data/web_files/unzip/{}'.format(filename.strip()), encoding="utf8") as f:
data = json.load(f)
cve_items = data['CVE_Items']
for i in range(len(cve_items)):
database_object = DataNist()
try:
impact = cve_items[i]['impact']['baseMetricV2']
database_object.severity = impact['severity']
database_object.exp_score = impact['exploitabilityScore']
database_object.impact_score = impact['impactScore']
database_object.cvss_score = impact['cvssV2']['baseScore']
except KeyError:
database_object.severity = ''
database_object.exp_score = ''
database_object.impact_score = ''
database_object.cvss_score = ''
for vendor_data in cve_items[i]['cve']['affects']['vendor']['vendor_data']:
database_object.vendor_name = vendor_data['vendor_name']
for description_data in cve_items[i]['cve']['description']['description_data']:
database_object.description = description_data['value']
for product_data in vendor_data['product']['product_data']:
database_object.product_name = product_data['product_name']
database_object.save()
for version_data in product_data['version']['version_data']:
if version_data['version_value'] != '-':
database_object.versions_set.create(version=version_data['version_value'])
My models.py:
class DataNist(models.Model):
vendor_name = models.CharField(max_length=100)
product_name = models.CharField(max_length=100)
description = models.TextField()
date = models.DateTimeField(default=timezone.now)
severity = models.CharField(max_length=10)
exp_score = models.IntegerField()
impact_score = models.IntegerField()
cvss_score = models.IntegerField()
def __str__(self):
return self.vendor_name + "-" + self.product_name
class Versions(models.Model):
data = models.ForeignKey(DataNist, on_delete=models.CASCADE)
version = models.CharField(max_length=50)
def __str__(self):
return self.version
I will appreciate if you can give me any advice how can I improve my code.
Okay, given the structure of the data, something like this might work for you.
This is standalone code aside from that .objects.bulk_create() call; as commented in the code, the two classes defined would actually be models within your Django app.
(By the way, you probably want to save the CVE ID as an unique field too.)
Your original code had the misassumption that every "leaf entry" in the affected version data would have the same vendor, which may not be true. That's why the model structure here has a separate product-version model that has vendor, product and version fields. (If you wanted to optimize things a little, you might deduplicate the AffectedProductVersions even across DataNists (which, as an aside, is not a perfect name for a model)).
And of course, as you had already done in your original code, the importing should be run within a transaction (transaction.atomic()).
Hope this helps.
import json
import os
import types
class DataNist(types.SimpleNamespace): # this would actually be a model
severity = ""
exp_score = ""
impact_score = ""
cvss_score = ""
def save(self):
pass
class AffectedProductVersion(types.SimpleNamespace): # this too
# (foreign key to DataNist here)
vendor_name = ""
product_name = ""
version_value = ""
def import_item(item):
database_object = DataNist()
try:
impact = item["impact"]["baseMetricV2"]
except KeyError: # no impact object available
pass
else:
database_object.severity = impact.get("severity", "")
database_object.exp_score = impact.get("exploitabilityScore", "")
database_object.impact_score = impact.get("impactScore", "")
if "cvssV2" in impact:
database_object.cvss_score = impact["cvssV2"]["baseScore"]
for description_data in item["cve"]["description"]["description_data"]:
database_object.description = description_data["value"]
break # only grab the first description
database_object.save() # save the base object
affected_versions = []
for vendor_data in item["cve"]["affects"]["vendor"]["vendor_data"]:
for product_data in vendor_data["product"]["product_data"]:
for version_data in product_data["version"]["version_data"]:
affected_versions.append(
AffectedProductVersion(
data_nist=database_object,
vendor_name=vendor_data["vendor_name"],
product_name=product_data["product_name"],
version_name=version_data["version_value"],
)
)
AffectedProductVersion.objects.bulk_create(
affected_versions
) # save all the version information
return database_object # in case the caller needs it
with open("nvdcve-1.0-2019.json") as infp:
data = json.load(infp)
for item in data["CVE_Items"]:
import_item(item)

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.

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 .

Separating "user-owned" from "other" data in Django template

I have an Openstack-powered, Django-modified application that shows the disk images and snapshots available for a user to launch. The user currently sees both snapshots they created and ones they did not. I would like to separate the current table into two based on whether they are owned by the user or not.
My two table definitions are as follows (note I altered row_actions accordingly):
class UserSnapshotsTable(OldSnapshotsTable):
cloud = tables.Column(get_cloud, verbose_name=_("Cloud"))
class Meta:
name = "usersnapshots"
verbose_name = _("User Snapshots")
table_actions = (DeleteSnapshot,)
row_actions = (LaunchSnapshot, LaunchCluster, EditImage, DeleteSnapshot)
pagination_param = "snapshot_marker"
row_class = UpdateRow
status_columns = ["status"]
class OtherSnapshotsTable(OldSnapshotsTable):
cloud = tables.Column(get_cloud, verbose_name=_("Cloud"))
class Meta:
name = "othersnapshots"
verbose_name = _("Other Snapshots")
table_actions = (DeleteSnapshot,)
row_actions = (LaunchSnapshot, LaunchCluster)
pagination_param = "snapshot_marker"
row_class = UpdateRow
status_columns = ["status"]
I have altered the HTML template to pull the "UserSnapshotsTable" and "OtherSnapshotsTable" tables (I copied the original table and renamed both), but both full tables still generate under the respective headings. There are two functions generating the data:
def get_usersnapshots_data(self):
req = self.request
marker = req.GET.get(UserSnapshotsTable._meta.pagination_param, None)
try:
usersnaps, self._more_snapshots = api.snapshot_list_detailed(req,
marker=marker)
except:
usersnaps = []
exceptions.handle(req, _("Unable to retrieve user-owned snapshots."))
return usersnaps
def get_othersnapshots_data(self):
req = self.request
marker = req.GET.get(OtherSnapshotsTable._meta.pagination_param, None)
try:
othersnaps, self._more_snapshots = api.snapshot_list_detailed(req,
marker=marker)
except:
othersnaps = []
exceptions.handle(req, _("Unable to retrieve non-user-owned snapshots."))
return othersnaps
There are also Edit/Delete options defined for images, and imported for snapshots, that seem to have a key comparison. Here's the "Delete" one (line 7):
class DeleteImage(tables.DeleteAction):
data_type_singular = _("Image")
data_type_plural = _("Images")
def allowed(self, request, image=None):
if image:
return image.owner == request.user.tenant_id
# Return True to allow table-level bulk delete action to appear.
return True
def delete(self, request, obj_id):
api.image_delete(request, obj_id)
How can I separate those tables out? This is my first time asking a question here, so please let me know if I can provide further information. Apologies for the length of it.
As far as I see you are using glanceclient. If that so you can use extra_filters parameter of snapshot_list_detailed() to filter only user images like this:
usersnaps, self._more_snapshots = api.snapshot_list_detailed(
req,
marker = marker,
extra_filters = {"owner": "user_name"}
)
Under cover snapshot_list_detailed uses GET images of Openstack Image Service API.

Categories