====== OpenERP ====== ====== OpenERP Entwicklung ====== ===== Standardmäßig extended view für admin setzen ===== extended ===== Felder anhand von Status sperren ===== 'reference': fields.char('Reference', size=128, required=1, states={'done': [('readonly', True)]}), ===== Spalten Create_Date und Write_Date einblenden: ===== _columns = { 'create_date': fields.datetime('Creation Date' , readonly=True), 'write_date': fields.datetime('Write Date' , readonly=True), } ===== Encoding ===== Unbedingt alle Python Dateien mit UTF-8 explizit kodieren, um ASCII-Konvertierungsfehler zu vermeiden. # -*- coding: utf-8 -*- ===== Domain Filter auf one2many Spalte ===== [[http://www.openerp.com/forum/topic23503.html]] ===== Active Spalte ===== Legt man eine Bool-Spalte namens "active" an, wird dieses standardmäßig in Domains abgefragt. ===== Message an ui ===== from tools.translate import _ raise osv.except_osv( _('Could not cancel purchase order !'), _('You must first cancel all picking attached to this purchase order.')) === Übersetzung der message === In der .po Datei #. module: purchase #: code:addons/purchase/purchase.py:721 #, python-format msgid "" "You have to select a product UOM in the same category than the purchase UOM " "of the product" msgstr "" "Sie müssen eine Mengeneinheit auswählen, die sich in derselben Kategorie wie " "die Produktmengeneinheit (ME) des Einkaufs befindet" ===== einen String übersetzen ===== from tools.translate import _ result = _('text zu übersetzen') ===== summmen von float fields im tree ==== ===== ein browse-objekt per xml-id holen ===== print pool.get("ir.model.data").get_object(cr, uid, "cp_crm", "salutation_1").title ===== kontextsensitive Suchformulare ===== _columns={ 'partner_id': fields.many2one('res.partner', string='Partner'), 'company_id': fields.many2one('res.company', string='Company'), 'account_receivable': fields.many2one('account.account', domain="[('type', '=', 'receivable'), ('company_id', '=', company_id)]", string="Account Receivable"), 'account_payable': fields.many2one('account.account', domain="[('type', '=', 'payable'), ('company_id', '=', company_id)]", string="Account Payable"), 'company_name': fields.related('company_id', 'name', type='char', string='Company name'), 'partner_name': fields.related('partner_id', 'name', type='char', string='Partner name'), Durch **('company_id', '=', company_id)** nimmt die Domäne aus dem aktuellen Kontext den Wert company_id. Weiterhin kann auf ein Ändern eines Feldes aus dem Kontext reagiert werden, um die Domäne abzudaten. def on_change_company_id(self, cr, uid, ids, company_id): d={} if company_id!=False: d['account_receivable']=[('company_id', '=', company_id)] return{'domain':d} ==== Context => auf übergeordnete Felder zugreifen ===
===== Spezifischen View in Field durch context verwenden ===== #zur Verfügung stehen search_view_ref, form_view_ref und tree_view_ref ===== Filter durch Context setzen ===== #filter im such view ===== SQL Constraints ===== Im Modul res.groups habe folgende Anweisung entdeckt: _sqlconstraints = [ ('name_uniq', 'unique (name)', 'The name of the group must be unique!') ] Man kann also super leicht contraints definieren...z.B. praktisch für NLV: maximal ein gültiger Standort zu einem Zeitpunkt und nicht zwei. ===== xml_id in id umwandeln ===== Assign task to me ir.actions.server code obj.assign_task_to_me() Assign task to me action client_action_multi project.task ===== domain in action window mit xml_id ===== ===== lambda Ausdrücke in defaults columns ===== _defaults = { 'name':lambda self, cursor, user, context:self.pool.get( 'res.users' ).read( cursor, user, user, ['name'], context )['name'], 'state':lambda * a:'draft', 'smtpport':lambda *a:25, 'smtpserver':lambda *a:'localhost', 'company':lambda *a:'yes', 'user':lambda self, cursor, user, context:user, 'send_pref':lambda *a: 'html', 'smtptls':lambda *a:True, } ===== defaults überschreiben ===== Hiermit wird der default Wert des Feldes date überschrieben. ==== Praktische Parameter der openerp_server.py ==== Um nur ein spezifisches Modul beim start neu zu laden: openerp_server.py -d --update= ----------------- ===== Felder: one2many - was wird angezeigt ===== Wenn das Feld related auf ein one2many Feld zeigt, dann wird dort das erste Element verwendet unter Beachtund der Sortierung (_order). ===== Erweitern von Standard Selection Fields ===== Beispielsweise gibt es bei res.partner ein Auswahlfeld für den Adresstyp. Um diesen zu erweitern, muss im __init__.py der eigenen Klasse per Programmcode die neuen Selections hinzugefügt werden. Geht so: Miki hat herausgefunden, dass die alten Selection-Werte erhalten bleiben. Damit ist folgendes Vorgehen eigentlich nicht mehr so notwendig und vereinfacht sich so, dass nur ein weiteres selection-Feld hinzugefügt werden muss. Dieses ergänzt dann die Auswahlwerte. def __init__(self, pool, cr): #TIP extend selection super(osv.osv, self).__init__(pool, cr) pool = pooler.get_pool(cr.dbname) partner_object = pool.get("res.partner.address") partner_object._columns['type'].selection.append(('house', 'House Address')) ===== Feldattribute in Abhängigkeit vom Status setzen, z.B. readonly nur bei Draft ===== 'company_id': fields.many2one('res.company', 'Company', required=True, readonly=True, states={'draft':[('readonly',False)]}), ähnlich im XML: ==== Many2Many Felder Füllen ==== Note: The type of field values to pass in vals for relationship fields is specific: * For a many2many field, a list of tuples is expected. Here is the list of tuple that are accepted, with the corresponding semantics (0, 0, { values }) link to a new record that needs to be created with the given values dictionary (1, ID, { values }) update the linked record with id = ID (write *values* on it) (2, ID) remove and delete the linked record with id = ID (calls unlink on ID, that will delete the object completely, and the link to it as well) (3, ID) cut the link to the linked record with id = ID (delete the relationship between the two objects but does not delete the target object itself) (4, ID) link to existing record with id = ID (adds a relationship) (5) unlink all (like using (3,ID) for all linked records) (6, 0, [IDs]) replace the list of linked IDs (like using (5) then (4,ID) for each ID in the list of IDs) Example: [(6, 0, [8, 5, 6, 4])] sets the many2many to ids [8, 5, 6, 4] * For a one2many field, a lits of tuples is expected. Here is the list of tuple that are accepted, with the corresponding semantics (0, 0, { values }) link to a new record that needs to be created with the given values dictionary (1, ID, { values }) update the linked record with id = ID (write *values* on it) (2, ID) remove and delete the linked record with id = ID (calls unlink on ID, that will delete the object completely, and the link to it as well) Example: [(0, 0, {'field_name':field_value_record1, ...}), (0, 0, {'field_name':field_value_record2, ...})] * For a many2one field, simply use the ID of target record, which must already exist, or False to remove the link. * For a reference field, use a string with the model name, a comma, and the target object id (example: 'product.product, 5') Mittels eineer Funktion lässt sich dies folgendermassen erledigen: # Felddeklaration: 'move_lines':fields.function(_get_lines, method=True, type='many2many', relation='account.move.line', string='Entry Lin # Funktionsdefinition # Give Journal Items related to the payment reconciled to this invoice # Return ids of partial and total payments related to the selected invoices def _get_lines(self, cr, uid, ids, name, arg, context=None): res = {} for invoice in self.browse(cr, uid, ids, context=context): id = invoice.id res[id] = [] if not invoice.move_id: continue data_lines = [x for x in invoice.move_id.line_id if x.account_id.id == invoice.account_id.id] partial_ids = [] for line in data_lines: ids_line = [] if line.reconcile_id: ids_line = line.reconcile_id.line_id elif line.reconcile_partial_id: ids_line = line.reconcile_partial_id.line_partial_ids l = map(lambda x: x.id, ids_line) partial_ids.append(line.id) res[id] =[x for x in l if x <> line.id and x not in partial_ids] return res ===== Aus einem Tree oder From View einen anderen View per Python-Code öffnen ===== #wizard erstellen class open_ref_wizard(osv.osv_memory): def open_ref(self, cr, uid, data, context): return { 'name': 'test', 'view_type': 'form', 'view_mode': 'form,tree', 'res_model': model, 'res_id': int(id), 'view_id': False, 'type': 'ir.actions.act_window', 'target': 'new', } } open_ref_wizard() ===== Old-Style Wizards =====