I'm trying to import new customer data into Odoo using CSV import. There is one field customer_id_no which is auto generated when the record is created(using the "ir.sequence").
Now each customer record in the CSV has a unique customer_id_no but when I try to import it, the existing customer_id_no is overridden by the standard sequence.
How can I insert the data from CSV as it is in the Odoo?
Also I was unable to find an answer to import many2one fields. Any help on that would be greatful.
#CZoellner is right. You have to change your method. It would be something like this :
#api.model
def create(self, vals):
vals['customer_id_no'] = mechanics_to_generate_sequence()
return super(ClassName, self).create(vals)
It needs to address the case where customer_id_no is provided. Like this
#api.model
def create(self, vals):
if not vals.get('customer_id_no'):
vals['customer_id_no'] = mechanics_to_generate_sequence()
return super(ClassName, self).create(vals)
Note that afterward you would need to make the sequence next iteration to the value next to the highest in customer_id_no.
Related
I am new around here, and I need some help
so, I am trying to make a report in odoo with Base report CSV, in the table, I have 2 relational field, and I don't know how to combine those table, I tried combining the function from the module Base report CSV like below, but it give an error, a blank error which only make me confused, anyone got any idea how I could do this?
from odoo import models
import csv
class csvreport(models.AbstractModel):
_name = 'report.hr_timesheet.report'
_inherit = 'report.report_csv.abstract'
def generate_csv_report(self, writer, data, partners):
writer.writeheader()
for obj in partners:
employee = self.env.cr.execute("""select hr_employee.name where hr_employee.id = %s;""", (obj.employee_id))
task = self.env.cr.execute("""select project_task.name where project_task.id = %s;""", (obj.project_id))
writer.writerow({
'name': obj.name,
'date': obj.date,
'unit_amount': obj.unit_amount,
'responsible': employee.fetchall(),
'task': task.fetchall(),
})
def csv_report_options(self):
res = super().csv_report_options()
res['fieldnames'].append('name')
res['fieldnames'].append('date')
res['fieldnames'].append('unit_amount')
res['fieldnames'].append('responsible')
res['fieldnames'].append('task')
res['delimiter'] = ';'
res['quoting'] = csv.QUOTE_ALL
return res
The Error :
Since i can't post picture, i'll just post a gdrive link
You should see the following error message in the error log:
ValueError: SQL query parameters should be a tuple, list or dict; ...
To fix that error pass query arguments in a tuple:
employee = self.env.cr.execute(query_str, (obj.employee_id.id, ))
You can't pass obj.employee_id (a record), because psycopg2 can't adapt type hr.employee.
To get the employee name just use dot notation:
employee_name = obj.employee_id.name
The from clause is missing for both queries and you can't call fetchall on employee or task because self.env.cr.execute will return None, to fetch the result, use the cursor fetch*() methods.
self.env.cr.fetchall()
I have a model that saves reports in binary fields for archiving. To do that I use the pdf_get().
document = self.env['report'].sudo().get_pdf(ids, report_name)
The problem is when I want to create a report that doesn't use the models fields but has to compute values from related models with the model that is pass with ids.
My report model
class ReportHistory(models.AbstractModel):
_name = 'report.hr.report_history'
def _get_report(self, ids[0]):
record = self.env['hr.history'].search([('id', '=', ids[0])])
return record
def _get_company(self, ids):
rec = self._get_report(ids)
if len(rec) > 0:
return rec[0].company_name
My biggest problem is that I can't debug so I can't what data is passed. The print or logger or raise ValidationError won't work. Probably due to running odoo on windows pc.
Every answer that I found it was said to pass values to report like this but it doesn't work.
#api.model
def render_html(self, docids, data=None):
docargs =
'doc_ids': self.ids,
'doc_model': self.model,
'data': data,
'company': self._get_company,
}
return self.env['report'].render()
So how to correctly pass values from methods to report? Or did I only do a dumb mistake?
Try this:
return self.env['report'].render(report_name, docargs)
In SqlAlchemy I use:
price = Column(Numeric(18, 5))
in various placed throught my app. When I get a number formatted in swedish, with a comma instead of a dot (0,34 instead of 0.34) and try to change the price column the number gets set to 0.00000.
To solve this I have this code:
obj.price = price.replace(',','.')
But having this all over the code makes it pretty ugly and the risk is that I forget one place. Would it be possible to have some kind of generic converter function which gets called before a value is converted from a string to a Numeric? And that I have that in one place only.
Check the validates decorator of SQLAlchemy: http://docs.sqlalchemy.org/en/rel_1_0/orm/mapped_attributes.html
A quick way to add a “validation” routine to an attribute is to use
the validates() decorator. An attribute validator can raise an
exception, halting the process of mutating the attribute’s value, or
can change the given value into something different.
In your case the code could look similar to:
from sqlalchemy.orm import validates
class Obj(Base):
__tablename__ = 'obj'
id = Column(Integer, primary_key=True)
price = Column(Numeric(18, 5))
#validates('price')
def validate_price(self, key, price):
if ',' in price:
return float(price.replace(',','.'))
else:
return float(price)
How do I update an HSTORE field with Flask-Admin?
The regular ModelView doesn't show the HSTORE field in Edit view. It shows nothing. No control at all. In list view, it shows a column with data in JSON notation. That's fine with me.
Using a custom ModelView, I can change the HSTORE field into a TextAreaField. This will show me the HSTORE field in JSON notation when in edit view. But I cannot edit/update it. In list view, it still shows me the object in JSON notation. Looks fine to me.
class MyView(ModelView):
form_overrides = dict(attributes=fields.TextAreaField)
When I attempt to save/edit the JSON, I receive this error:
sqlalchemy.exc.InternalError
InternalError: (InternalError) Unexpected end of string
LINE 1: UPDATE mytable SET attributes='{}' WHERE mytable.id = ...
^
'UPDATE mytable SET attributes=%(attributes)s WHERE mytable.id = %(mytable_id)s' {'attributes': u'{}', 'mytable_id': 14L}
Now -- using code, I can get something to save into the HSTORE field:
class MyView(ModelView):
form_overrides = dict(attributes=fields.TextAreaField)
def on_model_change(self, form, model, is_created):
model.attributes = {"a": "1"}
return
This basically overrides the model and put this object into it. I can then see the object in the List view and the Edit view. Still not good enough -- I want to save/edit the object that the user typed in.
I tried to parse and save the content from the form into JSON and back out. This doesn't work:
class MyView(ModelView):
form_overrides = dict(attributes=fields.TextAreaField)
def on_model_change(self, form, model, is_created):
x = form.data['attributes']
y = json.loads(x)
model.attributes = y
return
json.loads(x) says this:
ValueError ValueError: Expecting property name: line 1 column 1 (char
1)
and here are some sample inputs that fail:
{u's': u'ff'}
{'s':'ff'}
However, this input works:
{}
Blank also works
This is my SQL Table:
CREATE TABLE mytable (
id BIGSERIAL UNIQUE PRIMARY KEY,
attributes hstore
);
This is my SQA Model:
class MyTable(Base):
__tablename__ = u'mytable'
id = Column(BigInteger, primary_key=True)
attributes = Column(HSTORE)
Here is how I added the view's to the admin object
admin.add_view(ModelView(models.MyTable, db.session))
Add the view using a custom Model View
admin.add_view(MyView(models.MyTable, db.session))
But I don't do those views at the same time -- I get a Blueprint name collision error -- separate issue)
I also attempted to use a form field converter. I couldn't get it to actually hit the code.
class MyModelConverter(AdminModelConverter):
def post_process(self, form_class, info):
raise Exception('here I am') #but it never hits this
return form_class
class MyView(ModelView):
form_overrides = dict(attributes=fields.TextAreaField)
The answer gives you a bit more then asked
Fist of all it "extends" hstore to be able to store actually JSON, not just key-value
So this structure is also OK:
{"key":{"inner_object_key":{"Another_key":"Done!","list":["no","problem"]}}}
So, first of all your ModelView should use custom converter
class ExtendedModelView(ModelView):
model_form_converter=CustomAdminConverter
Converter itself should know how to use hstore dialect:
class CustomAdminConverter(AdminModelConverter):
#converts('sqlalchemy.dialects.postgresql.hstore.HSTORE')
def conv_HSTORE(self, field_args, **extra):
return DictToHstoreField(**field_args)
This one as you can see uses custom WTForms field which converts data in both directions:
class DictToHstoreField(TextAreaField):
def process_data(self, value):
if value is None:
value = {}
else:
for key,obj in value.iteritems():
if (obj.startswith("{") and obj.endswith("}")) or (obj.startswith("[") and obj.endswith("]")):
try:
value[key]=json.loads(obj)
except:
pass #
self.data=json.dumps(value)
def process_formdata(self, valuelist):
if valuelist:
self.data = json.loads(valuelist[0])
for key,obj in self.data.iteritems():
if isinstance(obj,dict) or isinstance(obj,list):
self.data[key]=json.dumps(obj)
if isinstance(obj,int):
self.data[key]=str(obj)
The final step will be to actual use this data in application
I did not make it in common nice way for SQLalchemy, since was used with flask-restful, so I have only adoption for flask-restful in one direction, but I think it's easy to get the idea from here and do the rest.
And if your case is simple key-value storage so nothing additionaly should be done, just use it as is.
But if you want to unwrap JSON somewhere in code, it's simple like this whenever you use it, just wrap in function
if (value.startswith("{") and value.endswith("}")) or (value.startswith("[") and value.endswith("]")):
value=json.loads(value)
Creating dynamical field for actual nice non-JSON way for editing of data also possible by extending FormField and adding some javascript for adding/removing fields, but this is whole different story, in my case I needed actual json storage, with blackjack and lists :)
Was working on postgres JSON datatype. The above solution worked great with a minor modifications.
Tried
'sqlalchemy.dialects.postgresql.json.JSON',
'sqlalchemy.dialects.postgresql.JSON',
'dialects.postgresql.json.JSON',
'dialects.postgresql.JSON'
The above versions did not work.
Finally the following change worked
#converts('JSON')
And changed class DictToHstoreField to the following:
class DictToJSONField(fields.TextAreaField):
def process_data(self, value):
if value is None:
value = {}
self.data = json.dumps(value)
def process_formdata(self, valuelist):
if valuelist:
self.data = json.loads(valuelist[0])
else:
self.data = '{}'
Although, this is might not be the answer to your question, but by default SQLAlchemy's ORM doesn't detect in-place changes to HSTORE field values. But fortunately there's a solution: SQLAlchemy's MutableDict type:
from sqlalchemy.ext.mutable import MutableDict
class MyClass(Base):
__tablename__ = 'mytable'
id = Column(Integer, primary_key=True)
attributes = Column(MutableDict.as_mutable(HSTORE))
Now when you change something in-place:
my_object.attributes.['some_key'] = 'some value'
The hstore field will be updated after session.commit().
I've been trying very hard to get this working but so far haven't found the correct route.
I am using pyqt, and I am querying a MySql DataBase, collecting from it a model with all the columns. Until here it's all good..
I've created a combobox that is displaying the correct text using model.setcolumn(1)
What I need now is for this combobox to send on "activated" the relative unique ID of this record, so I am able to create a category relatioship.
What exactly is the best way to do this? I feel I've arrived to a dead end, any help would be appreciated.
Best,
Cris
Best way would be sub-classing QComboBox. You can't override the activated signal but you can create a custom signal that will also be emitted with ID whenever activated is emitted. And you can connect to this signal and do your stuff. It will be something like this:
class MyComboBox(QtGui.QComboBox):
activatedId = QtCore.pyqtSignal(int) #correct this if your ID is not an int
def __init__(self, parent=None):
super(MyComboBox, self).__init__(parent)
self.activated.connect(self.sendId)
#QtCore.pyqtSlot(int)
def sendId(self, index):
model = self.model()
uniqueIdColumn = 0 # if ID is elsewhere adjust
uniqueId = model.data(model.createIndex(index,uniqueIdColumn,0),QtCore.Qt.DisplayRole)
self.activatedId.emit(uniqueId)
Edit
Here is a similar version without Signals. This will return uniqueId whenever you call sendId with an index of the combobox.
class MyComboBox(QtGui.QComboBox):
def __init__(self, parent=None):
super(MyComboBox, self).__init__(parent)
def sendId(self, index):
model = self.model()
uniqueIdColumn = 0 # if ID is elsewhere adjust
uniqueId = model.data(model.createIndex(index,uniqueIdColumn,0),QtCore.Qt.DisplayRole)
return uniqueId