<!-- Set Extended View for Administrator --> <record model="res.users" id="base.user_root"> <field name="view">extended</field> </record>
'reference': fields.char('Reference', size=128, required=1, states={'done': [('readonly', True)]}),
_columns = { 'create_date': fields.datetime('Creation Date' , readonly=True), 'write_date': fields.datetime('Write Date' , readonly=True), }
Unbedingt alle Python Dateien mit UTF-8 explizit kodieren, um ASCII-Konvertierungsfehler zu vermeiden.
# -*- coding: utf-8 -*-
Legt man eine Bool-Spalte namens “active” an, wird dieses standardmäßig in Domains abgefragt.
from tools.translate import _ raise osv.except_osv( _('Could not cancel purchase order !'), _('You must first cancel all picking attached to this purchase order.'))
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"
from tools.translate import _ result = _('text zu übersetzen')
<field name="residual" sum="Residual Amount"/>
print pool.get("ir.model.data").get_object(cr, uid, "cp_crm", "salutation_1").title
_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.
<field name="company_id" widget="selection" width="150" on_change="on_change_company_id(company_id)"/> <field name="account_payable" width="150"/> <field name="account_receivable" width="150"/>
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}
<field name="product_id" colspan="4" context="partner_id=parent.partner_id,quantity=product_qty,pricelist=parent.pricelist_id,uom=product_uom,warehouse=parent.warehouse_id"/>
<field name="levels"/> <!-- one2many Verknüpfung --> <field name="units" nolabel="1" mode="tree,form" context="{'levels': map(lambda x: x[1], levels)}"> <!-- neue context variable levels = liste aus ids aus levels --> <tree string="Units"> <field name="name" /> <field name="level_id" /> </tree> <form string="Unit"> <field name="name"/> <field name="level_id" domain="[('id', 'in', context['levels'])]"/> <!-- many2one nur auf levels die im übergeordneten levels stehen --> </form> </field>
#zur Verfügung stehen search_view_ref, form_view_ref und tree_view_ref
<field name="test" context="{'search_view_ref':'modul.xml_id'}"/>
#filter im such view <filter string="Das ist ein Test Filter" name="test_filter" domain="[('id','>',0)]/>" #filter setzen im field das auf andere Entität geht <field name="test_field" context="{'search_default_test_filter':1}" # 1 = filter an, 0 = filter aus
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.
<record id="server_action_assign_task" model="ir.actions.server"> <field name="name">Assign task to me</field> <field name="type">ir.actions.server</field> <field name="model_id" search="[('model', '=', 'project.task')]" /> <field name="state">code</field> <field name="code">obj.assign_task_to_me()</field> </record> <record id="ir_value_assign_task" model="ir.values"> <field name="name">Assign task to me</field> <field name="key">action</field> <field name="key2">client_action_multi</field> <field name="model">project.task</field> <field name="value" eval="'ir.actions.server,%d'%server_action_assign_task"/> <field name="object" eval="True"/> </record>
<field name="domain" eval="[('user_id','=',ref('base.user_root'))]"/>
_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, }
Hiermit wird der default Wert des Feldes date überschrieben.
<field name="works" colspan="4" nolabel="1" mode="tree,form" context="{'default_date': date_current + time.strftime(' %%H:%%M:%%S')}">
Um nur ein spezifisches Modul beim start neu zu laden:
openerp_server.py -d <dbname> --update=<modulname> -----------------
Wenn das Feld related auf ein one2many Feld zeigt, dann wird dort das erste Element verwendet unter Beachtund der Sortierung (_order).
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:
<note important>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.</note>
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'))
'company_id': fields.many2one('res.company', 'Company', required=True, readonly=True, states={'draft':[('readonly',False)]}),
ähnlich im XML:
<group attrs="{'readonly': [('field_name', '=', 'value')]}">
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
#wizard erstellen class open_ref_wizard(osv.osv_memory): def open_ref(self, cr, uid, data, context): return { 'name': 'test', 'context': context, 'view_type': 'form', 'view_mode': 'form,tree,calendar', 'res_model': model, 'res_id': id, 'view_id': False, 'type': 'ir.actions.act_window', 'target': 'new', #weitere parameter: 'nodestroy': True #keine Ahnung was der macht 'views': [(view_id_cal, 'calendar'), (view_id_form, 'form'), (view_id_tree, 'tree')], } } open_ref_wizard()
<note tip>res_id ist die Instanz-ID von res_model und muss ein int sein (kein List, Tuple, Array) </note>
<note warning>Das hat nicht funktioniert: wenn man in view_id eine Liste oder Int setzt, dann kommt zwar der web-client damit klar, aber nicht der GUI Client. Mit dem Parameter views gehts.</note>
<!-- wizard definieren --> <wizard string="Open Ref" model="cp_cash.liquidity.source" name="cp_cash.open_ref" id="open_ref" /> <!-- button in tree oder form einbinden --> <button string="Open Ref" name="%(open_ref)d" type="action" icon="gtk-open" />
raise osv.osv.except_osv("Message", Values_For_Message, exc_Type)
Felder in Views haben ein “onchange” event Attribut: http://doc.openerp.com/v6.0/developer/2_6_views_events/events/events.html#on-change Format:
MethodenName(Parameter)
Die Methode muss folgende Signatur haben:
MethodenName(self, cursor, userid, selectierteElementeIds, parameter)
Um den View über die Änderungen zu informieren, wird eine collection Zurückgegeben:
{'values':{'KlassenAttribut':Wert}}
xml_id = "message_new_allocation" try: _, id = self.pool.get('ir.model.data').get_object_reference(cr, uid, module_name, xml_id) except: id = None
@Miki: wo ist die get_object Methode???
<openerp> <data> <record model="ir.actions.act_window" id="ACTION_ID"> <field name="name">Label of the window</field> <field name="res_model">cp_base.the_cool_entity</field> <field name="view_mode">tree,form,graph</field> </record> <record model="ir.actions.server" id="ACTION_ID"> <field name="name">Label</field> <field name="model_id" search="[('name', '=', 'cp_base.irgendwas')]" /> <field name="type">ir.actions.server</field> <field name="state">code</field> <field name="code"> #method must have params(self, cr, uid, *args) obj.a_cool_method() </field> </record> <menuitem name="Label" icon="terp-project" parent="base.menu_administration" id="menu1"/> <menuitem name="SubmenuLabel" parent="menu1" id="menu2" action="ACTION_ID" type="server"/> </data> </openerp>
<openerp> <data> <record id="view_payment_tree" model="ir.ui.view"> <field name="name">cp_cash.payment.tree</field> <field name="model">cp_cash.payment</field> <field name="type">tree</field> <field name="arch" type="xml"> <tree string="Payment"> <field name="pay_date" /> <field name="income" /> <field name="amount" /> <field name="name" /> <field name="invoice_date" /> <field name="due_date" /> <field name="recurring_monthly" /> <field name="recurring_until" /> <field name="partner_id" /> <field name="company_id" /> </tree> </field> </record> <record id="view_payment_search" model="ir.ui.view"> <field name="name">cp_cash.payment.search</field> <field name="model">cp_cash.payment</field> <field name="type">search</field> <field name="arch" type="xml"> <search string="Search"> <filter string="Recurring Monthly" domain="[('recurring_monthly', '=', True)]" help="Recurring Monthly True" icon="terp-project"/> </search> </field> </record> <record id="view_payment_form" model="ir.ui.view"> <field name="name">cp_cash.payment.form</field> <field name="model">cp_cash.payment</field> <field name="type">form</field> <field name="arch" type="xml"> <form string="Payment"> <field name="name"/> <field name="partner_id"/> <field name="recurring_monthly"/> <field name="recurring_until"/> <group colspan="4" col="6"> <separator string="Amounts and Dates" colspan="6"/> <group colspan="6" col="4"> <field name="income"/> <field name="amount"/> <field name="pay_date"/> </group> <separator string="Invoice Details" colspan="6"/> <group colspan="4" col="6"> <field name="invoice_date"/> <field name="due_date"/> </group> </group> <separator string="Notes" colspan="4"/> <field name="notes" colspan="4" nolabel="1"/> </form> </field> </record> <record model="ir.ui.view" id="view_payments_line_graph"> <field name="name">payments.line.graph</field> <field name="model">cp_cash.payment</field> <field name="type">graph</field> <field name="arch" type="xml"> <graph string="Payments"> <field name="pay_date" group="1" /> <field name="amount" operator="+" /> </graph> </field> </record> </data> </openerp>
Methode in Model:
def assign_task_to_me(self, cr, uid, ids, *args): ======= ... return True #or raise Exception
View XML:
<button name="assign_task_to_me" string="Assign task to me" type="object" icon="gtk-execute" />
<field name="works" colspan="4" nolabel="1" mode="tree,form" context="{'default_date': date_current + time.strftime(' %%H:%%M:%%S')}">
_sql_constraints = [ ('type_value', "CHECK( (holiday_type='employee' AND employee_id IS NOT NULL) or (holiday_type='category' AND category_id IS NOT NULL))", "You have to select an employee or ('date_check', "CHECK ( number_of_days_temp > 0 )", "The number of days must be greater than 0 !"), ('date_check2', "CHECK ( (type='add') OR (date_from < date_to))", "The start date must be before the end date !") ]
<tree colors="red:state in ('refuse');blue:state in ('draft');black:state in ('confirm','validate','validate1')" string="Leaves" >