class res_request(osv.osv): _name = 'res.request' def request_send(self, cr, uid, ids, *args): for id in ids: cr.execute('update res_request set state=%s,date_sent=%s where id=%s', ('waiting', time.strftime('%Y-%m-%d %H:%M:%S'), id)) cr.execute('select act_from,act_to,body,date_sent from res_request where id=%s', (id,)) values = cr.dictfetchone() if values['body'] and (len(values['body']) > 128): values['name'] = values['body'][:125] + '...' else: values['name'] = values['body'] or '/' values['req_id'] = id self.pool.get('res.request.history').create(cr, uid, values) return True def request_reply(self, cr, uid, ids, *args): for id in ids: cr.execute("update res_request set state='active', act_from=%s, act_to=act_from, trigger_date=NULL, body='' where id=%s", (uid,id)) return True def request_close(self, cr, uid, ids, *args): self.write(cr, uid, ids, {'state':'closed'}) return True def request_get(self, cr, uid): cr.execute('select id from res_request where act_to=%s and (trigger_date<=%s or trigger_date is null) and active=True and state != %s', (uid,time.strftime('%Y-%m-%d'), 'closed')) ids = map(lambda x:x[0], cr.fetchall()) cr.execute('select id from res_request where act_from=%s and (act_to<>%s) and (trigger_date<=%s or trigger_date is null) and active=True and state != %s', (uid,uid,time.strftime('%Y-%m-%d'), 'closed')) ids2 = map(lambda x:x[0], cr.fetchall()) return (ids, ids2) _columns = { 'create_date': fields.datetime('Created Date', readonly=True), 'name': fields.char('Subject', states={'waiting':[('readonly',True)],'active':[('readonly',True)],'closed':[('readonly',True)]}, required=True, size=128), 'active': fields.boolean('Active'), 'priority': fields.selection([('0','Low'),('1','Normal'),('2','High')], 'Priority', states={'waiting':[('readonly',True)],'closed':[('readonly',True)]}, required=True), 'act_from': fields.many2one('res.users', 'From', required=True, readonly=True, states={'closed':[('readonly',True)]}, select=1), 'act_to': fields.many2one('res.users', 'To', required=True, states={'waiting':[('readonly',True)],'closed':[('readonly',True)]}, select=1), 'body': fields.text('Request', states={'waiting':[('readonly',True)],'closed':[('readonly',True)]}), 'date_sent': fields.datetime('Date', readonly=True), 'trigger_date': fields.datetime('Trigger Date', states={'waiting':[('readonly',True)],'closed':[('readonly',True)]}, select=1), 'ref_partner_id':fields.many2one('res.partner', 'Partner Ref.', states={'closed':[('readonly',True)]}), 'ref_doc1':fields.reference('Document Ref 1', selection=_links_get, size=128, states={'closed':[('readonly',True)]}), 'ref_doc2':fields.reference('Document Ref 2', selection=_links_get, size=128, states={'closed':[('readonly',True)]}), 'state': fields.selection([('draft','draft'),('waiting','waiting'),('active','active'),('closed','closed')], 'State', required=True, readonly=True), 'history': fields.one2many('res.request.history','req_id', 'History') } _defaults = { 'act_from': lambda obj,cr,uid,context=None: uid, 'state': 'draft', 'active': True, 'priority': '1', } _order = 'priority desc, trigger_date, create_date desc' _table = 'res_request'
class project_reference(osv.osv): _inherit = "project.task" _columns = { 'ref_partner_id': fields.many2one('res.partner', 'Partner Ref.'), 'ref_doc1': fields.reference('Document Ref 1', selection=_links_get, size=128), 'ref_doc2': fields.reference('Document Ref 2', selection=_links_get, size=128), }
class ir_attachment(osv.osv): _inherit = "ir.attachment" # def _ref (self, cr, uid, ids, field_name, arg, context) : # res = {} # for obj in self.browse (cr, uid, ids) : # if obj.res_model and obj.res_id : # res[obj.id] = obj.res_model + ",%s" % obj.res_id # else : # res[obj.id] = False # return res # # end def _ref # _columns = \ # { 'ref' : fields.function # ( _ref # , type = 'char', size=128 # , method = True # , string = 'Migration aid' # , store = True # , readonly = True # ) # } def _links_get(self, cr, uid, context={}): obj = self.pool.get("res.request.link") ids = obj.search(cr, uid, []) res = obj.read(cr, uid, ids, ["object", "name"], context) return [(r["object"], r["name"]) for r in res] # ende def _links_get _columns = \ { 'ref' : fields.reference('Migration aid', selection=_links_get, size=128, readonly=True)}
class crm_opportunity(osv.osv): """ Opportunity Cases """ _order = "priority,date_action,id desc" _inherit = 'crm.lead' _columns = { # From crm.case 'partner_address_id': fields.many2one('res.partner.address', 'Partner Contact', \ domain="[('partner_id','=',partner_id)]"), # Opportunity fields 'probability': fields.float('Probability (%)',group_operator="avg"), 'planned_revenue': fields.float('Expected Revenue'), 'ref': fields.reference('Reference', selection=crm._links_get, size=128), 'ref2': fields.reference('Reference 2', selection=crm._links_get, size=128), 'phone': fields.char("Phone", size=64), 'date_deadline': fields.date('Expected Closing'), 'date_action': fields.date('Next Action Date'), 'title_action': fields.char('Next Action', size=64), 'stage_id': fields.many2one('crm.case.stage', 'Stage', domain="[('type','=','opportunity')]"), } def _case_close_generic(self, cr, uid, ids, find_stage, *args): res = super(crm_opportunity, self).case_close(cr, uid, ids, *args) for case in self.browse(cr, uid, ids): #if the case is not an opportunity close won't change the stage if not case.type == 'opportunity': return res value = {} stage_id = find_stage(cr, uid, 'opportunity', case.section_id.id or False) if stage_id: stage_obj = self.pool.get('crm.case.stage').browse( cr, uid, stage_id) value.update({'stage_id': stage_id}) if stage_obj.on_change: value.update({'probability': stage_obj.probability}) #Done un crm.case #value.update({'date_closed': time.strftime('%Y-%m-%d %H:%M:%S')}) self.write(cr, uid, ids, value) return res
class qc_test_template(osv.osv): """ A template is a group of proofs to with the values that make them valid. """ _name = 'qc.test.template' _description='Test Template' def _links_get(self, cr, uid, context=None): #TODO: Select models obj = self.pool.get('res.request.link') ids = obj.search(cr, uid, [], context=context) res = obj.read(cr, uid, ids, ['object', 'name'], context) return [(r['object'], r['name']) for r in res] def _default_name(self, cr, uid, context=None): if context and context.get('reference_model', False): id = context.get('reference_id') if not id: id = context.get('active_id') if id: source=self.pool.get(context['reference_model']).browse(cr, uid, id, context) if hasattr(source, 'name'): return source.name def _default_object_id(self, cr, uid, context=None): if context and context.get('reference_model', False): return '%s,%d' % (context['reference_model'], context['reference_id']) else: return False def _default_type(self, cr, uid, context=None): if context and context.get('reference_model'): return 'related' else: return False _columns = { 'active':fields.boolean('Active', select="1"), 'name': fields.char('Name', size=200, required=True,translate=True,select="1"), 'test_template_line_ids':fields.one2many('qc.test.template.line','test_template_id', 'Lines' ), 'object_id':fields.reference('Reference Object', selection=_links_get, size=128 ) , 'fill_correct_values':fields.boolean('Fill With Correct Values' ), 'type':fields.selection([('generic','Generic'),('related','Related')], 'Type' , select="1"), 'category_id': fields.many2one('qc.test.template.category','Category'), 'trig_on' : fields.many2one('qc.test.template.trigger', 'Trigger'), } _defaults = { 'name': _default_name, 'active': lambda *a: True, 'object_id': _default_object_id, 'type': _default_type, }
class account_account_records(osv.osv): _name = 'account.account.records' _auto = False _description = 'Records by Accounts' _rec_name = 'record_id' _columns = { 'record_id': fields.reference('Record', selection=_links_get, size=128, readonly=True), 'model_id': fields.many2one('ir.model', 'Model', readonly=True), 'value_id': fields.integer('Value', readonly=True), 'field_id': fields.many2one('ir.model.fields', 'Field', readonly=True), } def _get_records(self, cr, uid=1, id=None, context=None): if context is None: context = {} res = [] imf_obj = self.pool.get('ir.model.fields') #~ imf_ids = imf_obj.search(cr,uid,[('ttype','=','many2one'),('relation','=','account.account'),('model','!=','account.account'),('view_load','=',False)]) imf_ids = imf_obj.search(cr, uid, [('ttype', '=', 'many2one'), ('relation', '=', 'account.account'), ('model', '!=', 'account.account')]) if imf_ids: for each in imf_obj.browse(cr, uid, imf_ids, context=context): if not each.model_id.osv_memory: cr.execute( """SELECT attname FROM pg_attribute WHERE attrelid = (SELECT oid FROM pg_class WHERE relname = '%s') AND attname = '%s'""" % (each.model.replace('.', '_'), each.name)) value = cr.fetchall() if not value: continue res.append( """SELECT COALESCE(%s,NULL) as value_id, CASE WHEN id > 0 THEN (%s || id) END AS record_id, CASE WHEN id > 0 THEN %s END AS field_id, CASE WHEN id > 0 THEN %s END AS model_id, CASE WHEN id > 0 THEN (%s * %s + id) END AS id FROM %s""" % (each.name, "'%s,'" % each.model, each.id, each.model_id.id, each.id, each.model_id.id, each.model.replace('.', '_'))) res = ' UNION '.join(res) return res def init(self, cr): tools.drop_view_if_exists(cr, 'account_account_records') cr.execute(""" CREATE OR REPLACE view account_account_records AS (%s) """ % (self._get_records(cr, 1), ))
class stock_move(osv.osv): _inherit = "stock.move" def _get_selection_list(self, cr, uid, context=None): #@return a list of tuples. tuples containing model name and name of the record model_obj = self.pool.get('ir.model') ids = model_obj.search(cr, uid, [('name', 'not ilike', '.')]) res = model_obj.read(cr, uid, ids, ['model', 'name']) return [(r['model'], r['name']) for r in res] + [('', '')] _columns = { 'origin_document': fields.reference("Origin Document", selection=_get_selection_list, size=None) }
class account_cashflow_provision_line(osv.osv): _inherit = 'account.cashflow.provision.line' def _get_reference_model(self, cr, uid, context=None): res = super(account_cashflow_provision_line, self)._get_reference_model(cr, uid, context=context) res += [('account.cash.operation','Cash Management Operation')] return res _columns = { 'origin': fields.reference('Originating Transaction', size=128, readonly=True, selection=_get_reference_model, help='This field contains a reference to the transaction that originated the creation of this provision.'), }
class reconcile_item(osv.osv_memory): _name = "fg_account.reconcile.item" _columns = { 'ref_doc': fields.reference('单据', selection=[('fg_sale.order', '销售订单'), ('fg_account.bill', '收款单')], size=128, readonly=True), 'o_date': fields.date('单据日期', readonly=True), 'name': fields.char('单号', size=24), 'o_partner': fields.many2one('res.partner', '客户', readonly=True), 't': fields.char('项目', size=12, readonly=True), 'reconciled': fields.boolean('已对账', readonly=True), 'cleared': fields.boolean('已清账', readonly=True), 'amount': fields.float('金额', digits=(16, 4), readonly=True), 'balance': fields.float('余额', digits=(16, 4), readonly=True), 'note': fields.text('附注'), } _order = 'o_date asc' def button_view(self, cr, uid, ids, context=None): record = self.browse(cr, uid, ids)[0] r = { 'type': 'ir.actions.act_window', 'name': '查看单据', 'view_mode': 'form', 'view_type': 'form', 'res_model': record.ref_doc._table_name, 'res_id': record.ref_doc.id, 'target': 'new', 'context': context, } #if record.ref_doc._table_name == 'fg_account.bill': # r['res_id'] = record.id - 1000000000 # #print r return r
class ineco_jasper_report_params(osv.osv): _name = 'ineco.jasper.report.params' _description = 'Ineco Jasper Report Parameter' _columns = { 'param_name': fields.char('Name', size=250, required=True), 'param_uristring': fields.char('uriString', size=250, required=True), 'param_label': fields.char('Label', size=250, required=True), 'reference_id':fields.reference('Document', selection=_links_get, size=128), 'report_id': fields.many2one('ineco.jasper.report', 'Report', ondelete="cascade"), } _sql_constraints = [ ('name_uniq', 'unique(param_name,report_id)', 'Report and Parameters must be unique!'), ]
class detail_ledger(osv.osv_memory): ''' 根据输入的科目和期间、辅助核算项目输出《明细账》 现金日记账,现金外币账,数量金额明细账,三栏帐,外币往来帐 ''' def _get_co(self, cr, uid, context=None): return [('res.partner', '往来')] _name = 'detail.ledger' _descript = u'明细账' _columns = { 'acc_id': fields.many2one('fi.acc', u'会计科目', required=True), 'period_from': fields.many2one('fi.period', u'开始期间', required=True), 'period_to': fields.many2one('fi.period', u'截至期间', required=True), 'co_obj': fields.reference(u'辅助核算项目', selection=_get_co, size=128), } def default_get(self, cr, uid, fields, context=None): return { 'acc_id': context.get('active_id', None), 'period_to': self.pool.get('fi.period').find(cr, uid, context=context), 'period_from': self.pool.get('fi.period').find(cr, uid, context=context), } def print_report(self, cr, uid, ids, context=None): datas = {} res = self.read(cr, uid, ids[0], ['acc_id', 'period_from', 'period_to', 'co_obj'], context=context) acc = self.pool.get('fi.acc').browse(cr, uid, res['acc_id'][0], context=context) datas['ids'] = [ res['acc_id'][0], ] datas['period_to'] = res['period_to'][0] datas['period_from'] = res['period_from'][0] datas['cost_obj'] = res['co_obj'] return { 'type': 'ir.actions.report.xml', 'report_name': acc.format, 'datas': datas }
class xml_template_ref(osv.osv): _name = "xml.template.ref" _description = "XML Template Reference" _order = "name" def _links_get(self, cr, uid, context={}): obj = self.pool.get("res.request.link") ids = obj.search(cr, uid, []) res = obj.read(cr, uid, ids, ["object", "name"], context) return [(r["object"], r["name"]) for r in res] # ende def _links_get _columns = \ { "xml_template_id" : fields.many2one("xml.template", "XML Template", required=True, ondelete="cascade") , "name" : fields.reference('Reference', selection=_links_get, size=128, required=True) }
class subscription_subscription_history(osv.osv): _name = "subscription.subscription.history" _description = "Subscription history" _rec_name = 'date' _columns = { 'date': fields.datetime('Date'), 'subscription_id': fields.many2one('subscription.subscription', 'Subscription', ondelete='cascade'), 'document_id': fields.reference('Source Document', required=True, selection=_get_document_types, size=128), }
class subscription_subscription_history(osv.osv): _name = "subscription.subscription.history" _description = "Subscription history" _rec_name = 'date' _columns = { 'date': fields.datetime('Date'), 'subscription_id': fields.many2one('subscription.subscription', 'Subscription', ondelete='cascade'), 'document_id': fields.reference('Source Document', required=True, selection=[('account.invoice', 'Invoice'), ('sale.order', 'Sale Order')], size=128), }
class letter_ref(osv.osv): _name = 'letter.ref' def _name_get_intref(self, cr, uid, ids, prop, unknow_none, context=None): if not len(ids): return [] reads = self.read(cr, uid, ids, ['id', 'int_ref'], context=context) res = [] for record in reads: try: (model_name, obj_id) = record['int_ref'].split(',') if model_name and obj_id: obj_id = int(obj_id) model = self.pool.get(model_name) obj_name = model.name_get(cr, uid, [obj_id])[0] if obj_name and len(obj_name) > 1: print(record['id'], obj_name[1]) res.append((record['id'], obj_name[1])) except: print repr(traceback.extract_tb(sys.exc_traceback)) return dict(res) _columns = { 'name': fields.char('Name', size=128, help="Subject of letter"), 'int_ref': fields.reference('Reference', selection=_links_get, size=128), 'ref_name': fields.function(_name_get_intref, method=True, type="char", string="Letter Reference"), 'letter_id': fields.many2one('res.letter', "Letter"), } _defaults = { 'name': lambda self, cr, uid, context: self.pool.get('ir.sequence').get( cr, uid, 'letter.ref'), }
class res_partner_event(osv.osv): _name = "res.partner.event" _columns = { 'name': fields.char('Events', size=64, required=True), 'som': fields.many2one('res.partner.som', 'State of Mind'), 'description': fields.text('Description'), 'planned_cost': fields.float('Planned Cost'), 'planned_revenue': fields.float('Planned Revenue'), 'probability': fields.float('Probability (0.50)'), 'document': fields.reference('Document', selection=_links_get, size=128), 'partner_id': fields.many2one('res.partner', 'Partner', select=True), 'date': fields.datetime('Date', size=16), 'user_id': fields.many2one('res.users', 'User'), 'canal_id': fields.many2one('res.partner.canal', 'Channel'), 'partner_type': fields.selection([('customer', 'Customer'), ('retailer', 'Retailer'), ('prospect', 'Commercial Prospect')], 'Partner Relation'), 'type': fields.selection([('sale', 'Sale Opportunity'), ('purchase', 'Purchase Offer'), ('prospect', 'Prospect Contact')], 'Type of Event'), 'event_ical_id': fields.char('iCal id', size=64), } _order = 'date desc' _defaults = { 'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'), }
class etl_mapping_line(osv.Model): def _get_map_ref(self, cr, uid, context=None): return [('res.partner', 'Partner')] _name = 'etl.mapping.line' _description = 'ETL Mapping Line' _columns = { 'mapping_id': fields.many2one('etl.mapping', string='Mapping', required=True), 'name': fields.char('Original Char', 256, required=True), 'map_char': fields.char('Map Char', 256), 'map_id': fields.integer('Map Id'), 'map_xml_id': fields.char('Map XML Id', 128), 'map_ref': fields.reference( 'Map Reference', _get_map_ref, 64, help= "Use this field only in case the destinity server is equal to your local OpenERP server" ), 'is_default': fields.boolean( 'Default', help= "This row is selected when the value is not equal to another lines" ) } _defaults = { 'is_default': False, } _sql_constraints = [ ('mapping_name_uniq', 'unique(mapping_id,name)', 'The mapping and source char must be unique!'), ]
class ir_attachment_ref(osv.osv): _name = "ir.attachment.ref" _description = "Attachment Reference" def _links_get(self, cr, uid, context={}): obj = self.pool.get("res.request.link") ids = obj.search(cr, uid, []) res = obj.read(cr, uid, ids, ["object", "name"], context) return [(r["object"], r["name"]) for r in res] # ende def _links_get _columns = \ { "ir_attachment_id" : fields.many2one("ir.attachment", "Attachment", required=True, ondelete="cascade") , "name" : fields.reference('Reference', selection=_links_get, size=128, required=True) } _sql_constraints = \ [( "ir_attachment_ref_name_index" , "unique (name)" , "The Reference has to be unique!" ) ]
class admin_property(osv.osv): _name = 'admin.property' _description = 'Tables to handle properties specific to each admin project' _columns = { 'name': fields.char('Property Name', required=True, size=128), 'value': fields.char('Property Value', required=True, size=600), 'ref_record': fields.reference('Record Ref', selection=_links_get, size=128), } _sql_constraints = [ ('name_ref_uniq', 'unique (name)', 'The property name must be unique !'), ] def _get_project_property_by_name(self, cr, uid, name): result = None property_ids = self.search(cr, uid, [('name', '=', name)]) if property_ids: property_obj = self.browse(cr, uid, property_ids[0]) if property_obj.ref_record: # update the value if needed if property_obj.ref_record.name != property_obj.value: self.write(cr, uid, [property_obj.id], {'value': property_obj.ref_record.name}) result = property_obj return result def write(self, cr, uid, ids, vals, context=None): if vals.get('name'): del vals['name'] return super(admin_property, self).write(cr, uid, ids, vals, context)
class qc_test(osv.osv): """ This model contains an instance of a test template. """ _name = 'qc.test' def _success(self, cr, uid, ids, field_name, arg, context=None): result = {} for test in self.browse(cr, uid, ids, context): success = True proof={} for line in test.test_line_ids: proof[ line.proof_id.id ] = proof.get(line.proof_id.id,False) or line.success for p in proof: if not proof[p]: success = False break result[test.id] = success return result def _links_get(self, cr, uid, context=None): # TODO: Select models obj = self.pool.get('res.request.link') ids = obj.search(cr, uid, [], context=context) res = obj.read(cr, uid, ids, ['object', 'name'], context) return [(r['object'], r['name']) for r in res] def _default_object_id(self, cr, uid, context=None): if context and context.get('reference_model', False): return '%s,%d' % (context['reference_model'], context['reference_id']) else: return False _columns = { 'name': fields.datetime('Date',required=True, readonly=True, states={'draft':[('readonly',False)]}, select="1"), 'object_id':fields.reference('Reference', selection=_links_get, size=128, readonly=True, states={'draft':[('readonly',False)]}, select="1"), 'test_template_id': fields.many2one('qc.test.template','Test', states={'success':[('readonly',True)], 'failed':[('readonly',True)]}, select="1"), 'test_line_ids': fields.one2many( 'qc.test.line', 'test_id', 'Test Lines', states={'success':[('readonly',True)], 'failed':[('readonly',True)]}), 'test_internal_note': fields.text('Internal Note', states={'success':[('readonly',True)], 'failed':[('readonly',True)]}), 'test_external_note': fields.text('External Note', states={'success':[('readonly',True)], 'failed':[('readonly',True)]}), 'state': fields.selection([ ('draft','Draft'), ('waiting','Waiting Supervisor Approval'), ('success','Quality Success'), ('failed','Quality Failed'), ], 'State', readonly=True, select="1"), 'success': fields.function(_success, method=True, type='boolean', string='Success', help='This field will be active if all tests have succeeded.',select="1"), 'enabled': fields.boolean('Enabled', readonly=True, help='If a quality control test is not enabled it means it can not be moved from "Quality Success" or "Quality Failed" state.',select="1"), } _defaults = { 'name' : lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'), 'state': lambda *a: 'draft', 'object_id': _default_object_id, 'enabled': lambda *a: True, } def copy(self, cr, uid, id, default=None,context=None): if context == None: context = {} if default == None: default = {} default['name'] = time.strftime('%Y-%m-%d %H:%M:%S') return super( qc_test, self).copy( cr, uid, id, default, context) def create(self, cr, uid, datas, context=None): if context and context.get('reference_model', False): datas['object_id'] = context['reference_model'] + "," + str(context['reference_id']) return super(osv.osv, self).create(cr, uid, datas, context=context) def qc_test_success(self, cr, uid, ids, context): self.write(cr, uid, ids, { 'state' : 'success' }, context) return True def qc_test_failed(self, cr, uid, ids, context): self.write(cr, uid, ids, { 'state' : 'failed' }, context) return True def test_state(self, cr, uid, ids, mode, *args): quality_check=False if mode == 'failed': return not quality_check if mode == 'success': return quality_check return False def set_test_template(self, cr, uid, ids, template_id, force_fill=False, context=None): if context == None: context={} for id in ids: self.pool.get('qc.test').write( cr, uid, id, { 'test_template_id' : template_id }, context) test = self.pool.get('qc.test').browse( cr, uid, id, context ) if len(test.test_line_ids) > 0: self.pool.get( 'qc.test.line' ).unlink(cr, uid, [x.id for x in test.test_line_ids], context ) fill=False if test.test_template_id.fill_correct_values: fill=True for line in test.test_template_id.test_template_line_ids: data = { 'test_id': id, 'method_id': line.method_id.id, 'proof_id': line.proof_id.id, 'test_template_line_id': line.id, 'notes': line.notes, 'min_value': line.min_value, 'max_value': line.max_value, 'uom_id': line.uom_id.id, 'test_uom_id': line.uom_id.id, 'proof_type': line.type, } if fill or force_fill : if line.type == 'qualitative': # Fill wiht the first correct value finded. data['actual_value_ql'] = len(line.valid_value_ids) and line.valid_value_ids[0] and line.valid_value_ids[0].id or False else: # Fill with value inside rang. data['actual_value_qt'] =line.min_value data['test_uom_id'] = line.uom_id.id test_line_id = self.pool.get('qc.test.line').create( cr,uid,data , context) self.pool.get('qc.test.line').write(cr, uid, [test_line_id], { 'valid_value_ids': [(6, 0,[x.id for x in line.valid_value_ids ])] })
class actions_server(osv.osv): def _select_signals(self, cr, uid, context=None): cr.execute("""SELECT distinct w.osv, t.signal FROM wkf w, wkf_activity a, wkf_transition t WHERE w.id = a.wkf_id AND (t.act_from = a.id OR t.act_to = a.id) AND t.signal IS NOT NULL""") result = cr.fetchall() or [] res = [] for rs in result: if rs[0] is not None and rs[1] is not None: line = rs[1], "%s - (%s)" % (rs[1], rs[0]) res.append(line) return res def _select_objects(self, cr, uid, context=None): model_pool = self.pool.get('ir.model') ids = model_pool.search(cr, uid, [('name','not ilike','.')]) res = model_pool.read(cr, uid, ids, ['model', 'name']) return [(r['model'], r['name']) for r in res] + [('','')] def change_object(self, cr, uid, ids, copy_object, state, context=None): if state == 'object_copy' and copy_object: if context is None: context = {} model_pool = self.pool.get('ir.model') model = copy_object.split(',')[0] mid = model_pool.search(cr, uid, [('model','=',model)]) return { 'value': {'srcmodel_id': mid[0]}, 'context': context } else: return {} _name = 'ir.actions.server' _table = 'ir_act_server' _sequence = 'ir_actions_id_seq' _order = 'sequence,name' _columns = { 'name': fields.char('Action Name', required=True, size=64, translate=True), 'condition' : fields.char('Condition', size=256, required=True, help="Condition that is tested before the action is executed, " "and prevent execution if it is not verified.\n" "Example: object.list_price > 5000\n" "It is a Python expression that can use the following values:\n" " - self: ORM model of the record on which the action is triggered\n" " - object or obj: browse_record of the record on which the action is triggered\n" " - pool: ORM model pool (i.e. self.pool)\n" " - time: Python time module\n" " - cr: database cursor\n" " - uid: current user id\n" " - context: current context"), 'state': fields.selection([ ('client_action','Client Action'), ('dummy','Dummy'), ('loop','Iteration'), ('code','Python Code'), ('trigger','Trigger'), ('email','Email'), ('sms','SMS'), ('object_create','Create Object'), ('object_copy','Copy Object'), ('object_write','Write Object'), ('other','Multi Actions'), ], 'Action Type', required=True, size=32, help="Type of the Action that is to be executed"), 'code':fields.text('Python Code', help="Python code to be executed if condition is met.\n" "It is a Python block that can use the same values as for the condition field"), 'sequence': fields.integer('Sequence', help="Important when you deal with multiple actions, the execution order will be decided based on this, low number is higher priority."), 'model_id': fields.many2one('ir.model', 'Object', required=True, help="Select the object on which the action will work (read, write, create)."), 'action_id': fields.many2one('ir.actions.actions', 'Client Action', help="Select the Action Window, Report, Wizard to be executed."), 'trigger_name': fields.selection(_select_signals, string='Trigger Signal', size=128, help="The workflow signal to trigger"), 'wkf_model_id': fields.many2one('ir.model', 'Target Object', help="The object that should receive the workflow signal (must have an associated workflow)"), 'trigger_obj_id': fields.many2one('ir.model.fields','Relation Field', help="The field on the current object that links to the target object record (must be a many2one, or an integer field with the record ID)"), 'email': fields.char('Email Address', size=512, help="Expression that returns the email address to send to. Can be based on the same values as for the condition field.\n" "Example: object.invoice_address_id.email, or '*****@*****.**'"), 'subject': fields.char('Subject', size=1024, translate=True, help="Email subject, may contain expressions enclosed in double brackets based on the same values as those " "available in the condition field, e.g. `Hello [[ object.partner_id.name ]]`"), 'message': fields.text('Message', translate=True, help="Email contents, may contain expressions enclosed in double brackets based on the same values as those " "available in the condition field, e.g. `Dear [[ object.partner_id.name ]]`"), 'mobile': fields.char('Mobile No', size=512, help="Provides fields that be used to fetch the mobile number, e.g. you select the invoice, then `object.invoice_address_id.mobile` is the field which gives the correct mobile number"), 'sms': fields.char('SMS', size=160, translate=True), 'child_ids': fields.many2many('ir.actions.server', 'rel_server_actions', 'server_id', 'action_id', 'Other Actions'), 'usage': fields.char('Action Usage', size=32), 'type': fields.char('Action Type', size=32, required=True), 'srcmodel_id': fields.many2one('ir.model', 'Model', help="Object in which you want to create / write the object. If it is empty then refer to the Object field."), 'fields_lines': fields.one2many('ir.server.object.lines', 'server_id', 'Field Mappings.'), 'record_id':fields.many2one('ir.model.fields', 'Create Id', help="Provide the field name where the record id is stored after the create operations. If it is empty, you can not track the new record."), 'write_id':fields.char('Write Id', size=256, help="Provide the field name that the record id refers to for the write operation. If it is empty it will refer to the active id of the object."), 'loop_action':fields.many2one('ir.actions.server', 'Loop Action', help="Select the action that will be executed. Loop action will not be avaliable inside loop."), 'expression':fields.char('Loop Expression', size=512, help="Enter the field/expression that will return the list. E.g. select the sale order in Object, and you can have loop on the sales order line. Expression = `object.order_line`."), 'copy_object': fields.reference('Copy Of', selection=_select_objects, size=256), } _defaults = { 'state': lambda *a: 'dummy', 'condition': lambda *a: 'True', 'type': lambda *a: 'ir.actions.server', 'sequence': lambda *a: 5, 'code': lambda *a: """# You can use the following variables: # - self: ORM model of the record on which the action is triggered # - object: browse_record of the record on which the action is triggered if there is one, otherwise None # - pool: ORM model pool (i.e. self.pool) # - time: Python time module # - cr: database cursor # - uid: current user id # - context: current context # If you plan to return an action, assign: action = {...} """, } def get_email(self, cr, uid, action, context): obj_pool = self.pool.get(action.model_id.model) id = context.get('active_id') obj = obj_pool.browse(cr, uid, id) fields = None if '/' in action.email.complete_name: fields = action.email.complete_name.split('/') elif '.' in action.email.complete_name: fields = action.email.complete_name.split('.') for field in fields: try: obj = getattr(obj, field) except Exception: _logger.exception('Failed to parse: %s', field) return obj def get_mobile(self, cr, uid, action, context): obj_pool = self.pool.get(action.model_id.model) id = context.get('active_id') obj = obj_pool.browse(cr, uid, id) fields = None if '/' in action.mobile.complete_name: fields = action.mobile.complete_name.split('/') elif '.' in action.mobile.complete_name: fields = action.mobile.complete_name.split('.') for field in fields: try: obj = getattr(obj, field) except Exception: _logger.exception('Failed to parse: %s', field) return obj def merge_message(self, cr, uid, keystr, action, context=None): if context is None: context = {} def merge(match): obj_pool = self.pool.get(action.model_id.model) id = context.get('active_id') obj = obj_pool.browse(cr, uid, id) exp = str(match.group()[2:-2]).strip() result = eval(exp, { 'object': obj, 'context': dict(context), # copy context to prevent side-effects of eval 'time': time, }) if result in (None, False): return str("--------") return tools.ustr(result) com = re.compile('(\[\[.+?\]\])') message = com.sub(merge, keystr) return message # Context should contains: # ids : original ids # id : current id of the object # OUT: # False : Finnished correctly # ACTION_ID : Action to launch # FIXME: refactor all the eval() calls in run()! def run(self, cr, uid, ids, context=None): if context is None: context = {} user = self.pool.get('res.users').browse(cr, uid, uid) for action in self.browse(cr, uid, ids, context): obj = None obj_pool = self.pool.get(action.model_id.model) if context.get('active_model') == action.model_id.model and context.get('active_id'): obj = obj_pool.browse(cr, uid, context['active_id'], context=context) cxt = { 'self': obj_pool, 'object': obj, 'obj': obj, 'pool': self.pool, 'time': time, 'cr': cr, 'context': dict(context), # copy context to prevent side-effects of eval 'uid': uid, 'user': user } expr = eval(str(action.condition), cxt) if not expr: continue if action.state=='client_action': if not action.action_id: raise osv.except_osv(_('Error'), _("Please specify an action to launch !")) return self.pool.get(action.action_id.type)\ .read(cr, uid, action.action_id.id, context=context) if action.state=='code': eval(action.code, cxt, mode="exec", nocopy=True) # nocopy allows to return 'action' if 'action' in cxt: return cxt['action'] if action.state == 'email': email_from = config['email_from'] address = str(action.email) try: address = eval(str(action.email), cxt) except: pass if not address: _logger.info('No partner email address specified, not sending any email.') continue if not email_from: _logger.debug('--email-from command line option is not specified, using a fallback value instead.') if user.user_email: email_from = user.user_email else: email_from = "%s@%s" % (user.login, gethostname()) subject = self.merge_message(cr, uid, action.subject, action, context) body = self.merge_message(cr, uid, action.message, action, context) ir_mail_server = self.pool.get('ir.mail_server') msg = ir_mail_server.build_email(email_from, [address], subject, body) res_email = ir_mail_server.send_email(cr, uid, msg) if res_email: _logger.info('Email successfully sent to: %s', address) else: _logger.warning('Failed to send email to: %s', address) if action.state == 'trigger': wf_service = netsvc.LocalService("workflow") model = action.wkf_model_id.model m2o_field_name = action.trigger_obj_id.name target_id = obj_pool.read(cr, uid, context.get('active_id'), [m2o_field_name])[m2o_field_name] target_id = target_id[0] if isinstance(target_id,tuple) else target_id wf_service.trg_validate(uid, model, int(target_id), action.trigger_name, cr) if action.state == 'sms': #TODO: set the user and password from the system # for the sms gateway user / password # USE smsclient module from extra-addons _logger.warning('SMS Facility has not been implemented yet. Use smsclient module!') if action.state == 'other': res = [] for act in action.child_ids: context['active_id'] = context['active_ids'][0] result = self.run(cr, uid, [act.id], context) if result: res.append(result) return res if action.state == 'loop': expr = eval(str(action.expression), cxt) context['object'] = obj for i in expr: context['active_id'] = i.id result = self.run(cr, uid, [action.loop_action.id], context) if action.state == 'object_write': res = {} for exp in action.fields_lines: euq = exp.value if exp.type == 'equation': expr = eval(euq, cxt) else: expr = exp.value res[exp.col1.name] = expr if not action.write_id: if not action.srcmodel_id: obj_pool = self.pool.get(action.model_id.model) obj_pool.write(cr, uid, [context.get('active_id')], res) else: write_id = context.get('active_id') obj_pool = self.pool.get(action.srcmodel_id.model) obj_pool.write(cr, uid, [write_id], res) elif action.write_id: obj_pool = self.pool.get(action.srcmodel_id.model) rec = self.pool.get(action.model_id.model).browse(cr, uid, context.get('active_id')) id = eval(action.write_id, {'object': rec}) try: id = int(id) except: raise osv.except_osv(_('Error'), _("Problem in configuration `Record Id` in Server Action!")) if type(id) != type(1): raise osv.except_osv(_('Error'), _("Problem in configuration `Record Id` in Server Action!")) write_id = id obj_pool.write(cr, uid, [write_id], res) if action.state == 'object_create': res = {} for exp in action.fields_lines: euq = exp.value if exp.type == 'equation': expr = eval(euq, cxt) else: expr = exp.value res[exp.col1.name] = expr obj_pool = None res_id = False obj_pool = self.pool.get(action.srcmodel_id.model) res_id = obj_pool.create(cr, uid, res) if action.record_id: self.pool.get(action.model_id.model).write(cr, uid, [context.get('active_id')], {action.record_id.name:res_id}) if action.state == 'object_copy': res = {} for exp in action.fields_lines: euq = exp.value if exp.type == 'equation': expr = eval(euq, cxt) else: expr = exp.value res[exp.col1.name] = expr model = action.copy_object.split(',')[0] cid = action.copy_object.split(',')[1] obj_pool = self.pool.get(model) res_id = obj_pool.copy(cr, uid, int(cid), res) return False
class crm_lead(crm_case, osv.osv): """ CRM Lead Case """ _name = "crm.lead" _description = "Lead/Opportunity" _order = "priority,date_action,id desc" _inherit = ['mail.thread', 'res.partner.address'] def _read_group_stage_ids(self, cr, uid, ids, domain, read_group_order=None, access_rights_uid=None, context=None): access_rights_uid = access_rights_uid or uid stage_obj = self.pool.get('crm.case.stage') order = stage_obj._order if read_group_order == 'stage_id desc': # lame hack to allow reverting search, should just work in the trivial case order = "%s desc" % order stage_ids = stage_obj._search( cr, uid, ['|', ('id', 'in', ids), ('case_default', '=', 1)], order=order, access_rights_uid=access_rights_uid, context=context) result = stage_obj.name_get(cr, access_rights_uid, stage_ids, context=context) # restore order of the search result.sort( lambda x, y: cmp(stage_ids.index(x[0]), stage_ids.index(y[0]))) return result _group_by_full = {'stage_id': _read_group_stage_ids} # overridden because res.partner.address has an inconvenient name_get, # especially if base_contact is installed. def name_get(self, cr, user, ids, context=None): if isinstance(ids, (int, long)): ids = [ids] return [(r['id'], tools.ustr(r[self._rec_name])) for r in self.read(cr, user, ids, [self._rec_name], context)] # overridden because if 'base_contact' is installed - their default_get() will remove # 'default_type' from context making it impossible to record an 'opportunity' def default_get(self, cr, uid, fields_list, context=None): return super(osv.osv, self).default_get(cr, uid, fields_list, context=context) def _compute_day(self, cr, uid, ids, fields, args, context=None): """ @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @param ids: List of Openday’s IDs @return: difference between current date and log date @param context: A standard dictionary for contextual values """ cal_obj = self.pool.get('resource.calendar') res_obj = self.pool.get('resource.resource') res = {} for lead in self.browse(cr, uid, ids, context=context): for field in fields: res[lead.id] = {} duration = 0 ans = False if field == 'day_open': if lead.date_open: date_create = datetime.strptime( lead.create_date, "%Y-%m-%d %H:%M:%S") date_open = datetime.strptime(lead.date_open, "%Y-%m-%d %H:%M:%S") ans = date_open - date_create date_until = lead.date_open elif field == 'day_close': if lead.date_closed: date_create = datetime.strptime( lead.create_date, "%Y-%m-%d %H:%M:%S") date_close = datetime.strptime(lead.date_closed, "%Y-%m-%d %H:%M:%S") date_until = lead.date_closed ans = date_close - date_create if ans: resource_id = False if lead.user_id: resource_ids = res_obj.search( cr, uid, [('user_id', '=', lead.user_id.id)]) if len(resource_ids): resource_id = resource_ids[0] duration = float(ans.days) if lead.section_id and lead.section_id.resource_calendar_id: duration = float(ans.days) * 24 new_dates = cal_obj.interval_get( cr, uid, lead.section_id.resource_calendar_id and lead.section_id.resource_calendar_id.id or False, datetime.strptime(lead.create_date, '%Y-%m-%d %H:%M:%S'), duration, resource=resource_id) no_days = [] date_until = datetime.strptime(date_until, '%Y-%m-%d %H:%M:%S') for in_time, out_time in new_dates: if in_time.date not in no_days: no_days.append(in_time.date) if out_time > date_until: break duration = len(no_days) res[lead.id][field] = abs(int(duration)) return res def _history_search(self, cr, uid, obj, name, args, context=None): res = [] msg_obj = self.pool.get('mail.message') message_ids = msg_obj.search(cr, uid, [('email_from', '!=', False), ('subject', args[0][1], args[0][2])], context=context) lead_ids = self.search(cr, uid, [('message_ids', 'in', message_ids)], context=context) if lead_ids: return [('id', 'in', lead_ids)] else: return [('id', '=', '0')] def _get_email_subject(self, cr, uid, ids, fields, args, context=None): res = {} for obj in self.browse(cr, uid, ids, context=context): res[obj.id] = '' for msg in obj.message_ids: if msg.email_from: res[obj.id] = msg.subject break return res _columns = { # Overridden from res.partner.address: 'partner_id': fields.many2one('res.partner', 'Partner', ondelete='set null', select=True, help="Optional linked partner, usually after conversion of the lead"), 'id': fields.integer('ID', readonly=True), 'name': fields.char('Name', size=64, select=1), 'active': fields.boolean('Active', required=False), 'date_action_last': fields.datetime('Last Action', readonly=1), 'date_action_next': fields.datetime('Next Action', readonly=1), 'email_from': fields.char('Email', size=128, help="E-mail address of the contact", select=1), 'section_id': fields.many2one('crm.case.section', 'Sales Team', \ select=True, help='When sending mails, the default email address is taken from the sales team.'), 'create_date': fields.datetime('Creation Date' , readonly=True), 'email_cc': fields.text('Global CC', size=252 , help="These email addresses will be added to the CC field of all inbound and outbound emails for this record before being sent. Separate multiple email addresses with a comma"), 'description': fields.text('Notes'), 'write_date': fields.datetime('Update Date' , readonly=True), 'categ_id': fields.many2one('crm.case.categ', 'Category', \ domain="['|',('section_id','=',section_id),('section_id','=',False), ('object_id.model', '=', 'crm.lead')]"), 'type_id': fields.many2one('crm.case.resource.type', 'Campaign', \ domain="['|',('section_id','=',section_id),('section_id','=',False)]", help="From which campaign (seminar, marketing campaign, mass mailing, ...) did this contact come from?"), 'channel_id': fields.many2one('crm.case.channel', 'Channel', help="Communication channel (mail, direct, phone, ...)"), 'contact_name': fields.char('Contact Name', size=64), 'partner_name': fields.char("Customer Name", size=64,help='The name of the future partner that will be created while converting the lead into opportunity', select=1), 'optin': fields.boolean('Opt-In', help="If opt-in is checked, this contact has accepted to receive emails."), 'optout': fields.boolean('Opt-Out', help="If opt-out is checked, this contact has refused to receive emails or unsubscribed to a campaign."), 'type':fields.selection([ ('lead','Lead'), ('opportunity','Opportunity'), ],'Type', help="Type is used to separate Leads and Opportunities"), 'priority': fields.selection(crm.AVAILABLE_PRIORITIES, 'Priority', select=True), 'date_closed': fields.datetime('Closed', readonly=True), 'stage_id': fields.many2one('crm.case.stage', 'Stage', domain="[('section_ids', '=', section_id)]"), 'user_id': fields.many2one('res.users', 'Salesman', select=1), 'referred': fields.char('Referred By', size=64), 'date_open': fields.datetime('Opened', readonly=True), 'day_open': fields.function(_compute_day, string='Days to Open', \ multi='day_open', type="float", store=True), 'day_close': fields.function(_compute_day, string='Days to Close', \ multi='day_close', type="float", store=True), 'state': fields.selection(crm.AVAILABLE_STATES, 'State', size=16, readonly=True, help='The state is set to \'Draft\', when a case is created.\ \nIf the case is in progress the state is set to \'Open\'.\ \nWhen the case is over, the state is set to \'Done\'.\ \nIf the case needs to be reviewed then the state is set to \'Pending\'.' ), 'message_ids': fields.one2many('mail.message', 'res_id', 'Messages', domain=[('model','=',_name)]), 'subjects': fields.function(_get_email_subject, fnct_search=_history_search, string='Subject of Email', type='char', size=64), # Only used for type opportunity 'partner_address_id': fields.many2one('res.partner.address', 'Partner Contact', domain="[('partner_id','=',partner_id)]"), 'probability': fields.float('Probability (%)',group_operator="avg"), 'planned_revenue': fields.float('Expected Revenue'), 'ref': fields.reference('Reference', selection=crm._links_get, size=128), 'ref2': fields.reference('Reference 2', selection=crm._links_get, size=128), 'phone': fields.char("Phone", size=64), 'date_deadline': fields.date('Expected Closing'), 'date_action': fields.date('Next Action Date', select=True), 'title_action': fields.char('Next Action', size=64), 'stage_id': fields.many2one('crm.case.stage', 'Stage', domain="[('section_ids', '=', section_id)]"), 'color': fields.integer('Color Index'), 'partner_address_name': fields.related('partner_address_id', 'name', type='char', string='Partner Contact Name', readonly=True), 'partner_address_email': fields.related('partner_address_id', 'email', type='char', string='Partner Contact Email', readonly=True), 'company_currency': fields.related('company_id', 'currency_id', 'symbol', type='char', string='Company Currency', readonly=True), 'user_email': fields.related('user_id', 'user_email', type='char', string='User Email', readonly=True), 'user_login': fields.related('user_id', 'login', type='char', string='User Login', readonly=True), } _defaults = { 'active': lambda *a: 1, 'user_id': crm_case._get_default_user, 'email_from': crm_case._get_default_email, 'state': lambda *a: 'draft', 'type': lambda *a: 'lead', 'section_id': crm_case._get_section, 'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get( cr, uid, 'crm.lead', context=c), 'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0], 'color': 0, } def onchange_partner_address_id(self, cr, uid, ids, add, email=False): """This function returns value of partner email based on Partner Address """ if not add: return {'value': {'email_from': False, 'country_id': False}} address = self.pool.get('res.partner.address').browse(cr, uid, add) return { 'value': { 'email_from': address.email, 'phone': address.phone, 'country_id': address.country_id.id } } def on_change_optin(self, cr, uid, ids, optin): return {'value': {'optin': optin, 'optout': False}} def on_change_optout(self, cr, uid, ids, optout): return {'value': {'optout': optout, 'optin': False}} def onchange_stage_id(self, cr, uid, ids, stage_id, context={}): if not stage_id: return {'value': {}} stage = self.pool.get('crm.case.stage').browse(cr, uid, stage_id, context) if not stage.on_change: return {'value': {}} return {'value': {'probability': stage.probability}} def stage_find_percent(self, cr, uid, percent, section_id): """ Return the first stage with a probability == percent """ stage_pool = self.pool.get('crm.case.stage') if section_id: ids = stage_pool.search(cr, uid, [("probability", '=', percent), ("section_ids", 'in', [section_id])]) else: ids = stage_pool.search(cr, uid, [("probability", '=', percent)]) if ids: return ids[0] return False def stage_find_lost(self, cr, uid, section_id): return self.stage_find_percent(cr, uid, 0.0, section_id) def stage_find_won(self, cr, uid, section_id): return self.stage_find_percent(cr, uid, 100.0, section_id) def case_open(self, cr, uid, ids, *args): for l in self.browse(cr, uid, ids): # When coming from draft override date and stage otherwise just set state if l.state == 'draft': if l.type == 'lead': message = _("The lead '%s' has been opened.") % l.name elif l.type == 'opportunity': message = _( "The opportunity '%s' has been opened.") % l.name else: message = _("The case '%s' has been opened.") % l.name self.log(cr, uid, l.id, message) value = {'date_open': time.strftime('%Y-%m-%d %H:%M:%S')} self.write(cr, uid, [l.id], value) if l.type == 'opportunity' and not l.stage_id: stage_id = self.stage_find(cr, uid, l.section_id.id or False, [('sequence', '>', 0)]) if stage_id: self.stage_set(cr, uid, [l.id], stage_id) res = super(crm_lead, self).case_open(cr, uid, ids, *args) return res def case_close(self, cr, uid, ids, *args): res = super(crm_lead, self).case_close(cr, uid, ids, *args) self.write(cr, uid, ids, {'date_closed': time.strftime('%Y-%m-%d %H:%M:%S')}) for case in self.browse(cr, uid, ids): if case.type == 'lead': message = _("The lead '%s' has been closed.") % case.name else: message = _("The case '%s' has been closed.") % case.name self.log(cr, uid, case.id, message) return res
class subscription_subscription(osv.osv): _name = "subscription.subscription" _description = "Subscription" _columns = { 'name': fields.char('Name', size=60, required=True), 'active': fields.boolean( 'Active', help= "If the active field is set to False, it will allow you to hide the subscription without removing it." ), 'partner_id': fields.many2one('res.partner', 'Partner'), 'notes': fields.text('Notes'), 'user_id': fields.many2one('res.users', 'User', required=True), 'interval_number': fields.integer('Interval Qty'), 'interval_type': fields.selection([('days', 'Days'), ('weeks', 'Weeks'), ('months', 'Months')], 'Interval Unit'), 'exec_init': fields.integer('Number of documents'), 'date_init': fields.datetime('First Date'), 'state': fields.selection([('draft', 'Draft'), ('running', 'Running'), ('done', 'Done')], 'State'), 'doc_source': fields.reference( 'Source Document', required=True, selection=_get_document_types, size=128, help= "User can choose the source document on which he wants to create documents" ), 'doc_lines': fields.one2many('subscription.subscription.history', 'subscription_id', 'Documents created', readonly=True), 'cron_id': fields.many2one('ir.cron', 'Cron Job', help="Scheduler which runs on subscription"), 'note': fields.text('Notes', help="Description or Summary of Subscription"), } _defaults = { 'date_init': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'), 'user_id': lambda obj, cr, uid, context: uid, 'active': lambda *a: True, 'interval_number': lambda *a: 1, 'interval_type': lambda *a: 'months', 'doc_source': lambda *a: False, 'state': lambda *a: 'draft' } def set_process(self, cr, uid, ids, context=None): for row in self.read(cr, uid, ids, context=context): mapping = { 'name': 'name', 'interval_number': 'interval_number', 'interval_type': 'interval_type', 'exec_init': 'numbercall', 'date_init': 'nextcall' } res = { 'model': 'subscription.subscription', 'args': repr([[row['id']]]), 'function': 'model_copy', 'priority': 6, 'user_id': row['user_id'] and row['user_id'][0] } for key, value in mapping.items(): res[value] = row[key] id = self.pool.get('ir.cron').create(cr, uid, res) self.write(cr, uid, [row['id']], { 'cron_id': id, 'state': 'running' }) return True def model_copy(self, cr, uid, ids, context=None): for row in self.read(cr, uid, ids, context=context): if not row.get('cron_id', False): continue cron_ids = [row['cron_id'][0]] remaining = self.pool.get('ir.cron').read( cr, uid, cron_ids, ['numbercall'])[0]['numbercall'] try: (model_name, id) = row['doc_source'].split(',') id = int(id) model = self.pool.get(model_name) except: raise osv.except_osv( _('Wrong Source Document !'), _('Please provide another source document.\nThis one does not exist !' )) default = {'state': 'draft'} doc_obj = self.pool.get('subscription.document') document_ids = doc_obj.search(cr, uid, [('model.model', '=', model_name)]) doc = doc_obj.browse(cr, uid, document_ids)[0] for f in doc.field_ids: if f.value == 'date': value = time.strftime('%Y-%m-%d') else: value = False default[f.field.name] = value state = 'running' # if there was only one remaining document to generate # the subscription is over and we mark it as being done if remaining == 1: state = 'done' id = self.pool.get(model_name).copy(cr, uid, id, default, context) self.pool.get('subscription.subscription.history').create( cr, uid, { 'subscription_id': row['id'], 'date': time.strftime('%Y-%m-%d %H:%M:%S'), 'document_id': model_name + ',' + str(id) }) self.write(cr, uid, [row['id']], {'state': state}) return True def set_done(self, cr, uid, ids, context=None): res = self.read(cr, uid, ids, ['cron_id']) ids2 = [x['cron_id'][0] for x in res if x['id']] self.pool.get('ir.cron').write(cr, uid, ids2, {'active': False}) self.write(cr, uid, ids, {'state': 'done'}) return True def set_draft(self, cr, uid, ids, context=None): self.write(cr, uid, ids, {'state': 'draft'}) return True
class crm_helpdesk(crm.crm_case, osv.osv): """ Helpdesk Cases """ _name = "crm.helpdesk" _description = "Helpdesk" _order = "id desc" _inherit = ['mailgate.thread'] _columns = { 'id': fields.integer('ID', readonly=True), 'name': fields.char('Name', size=128, required=True), 'active': fields.boolean('Active', required=False), 'date_action_last': fields.datetime('Last Action', readonly=1), 'date_action_next': fields.datetime('Next Action', readonly=1), 'description': fields.text('Description'), 'create_date': fields.datetime('Creation Date' , readonly=True), 'write_date': fields.datetime('Update Date' , readonly=True), 'date_deadline': fields.date('Deadline'), 'user_id': fields.many2one('res.users', 'Responsible'), 'section_id': fields.many2one('crm.case.section', 'Sales Team', \ select=True, help='Sales team to which Case belongs to.\ Define Responsible user and Email account for mail gateway.' ), 'company_id': fields.many2one('res.company', 'Company'), 'date_closed': fields.datetime('Closed', readonly=True), 'partner_id': fields.many2one('res.partner', 'Partner'), 'partner_address_id': fields.many2one('res.partner.address', 'Partner Contact', \ domain="[('partner_id','=',partner_id)]"), 'email_cc': fields.text('Watchers Emails', size=252 , help="These email addresses will be added to the CC field of all inbound and outbound emails for this record before being sent. Separate multiple email addresses with a comma"), 'email_from': fields.char('Email', size=128, help="These people will receive email."), 'date': fields.datetime('Date'), 'ref' : fields.reference('Reference', selection=crm._links_get, size=128), 'ref2' : fields.reference('Reference 2', selection=crm._links_get, size=128), 'canal_id': fields.many2one('res.partner.canal', 'Channel', \ help="The channels represent the different communication \ modes available with the customer." ), 'planned_revenue': fields.float('Planned Revenue'), 'planned_cost': fields.float('Planned Costs'), 'priority': fields.selection(crm.AVAILABLE_PRIORITIES, 'Priority'), 'probability': fields.float('Probability (%)'), 'categ_id': fields.many2one('crm.case.categ', 'Category', \ domain="[('section_id','=',section_id),\ ('object_id.model', '=', 'crm.helpdesk')]" ), 'duration': fields.float('Duration', states={'done': [('readonly', True)]}), 'state': fields.selection(crm.AVAILABLE_STATES, 'State', size=16, readonly=True, help='The state is set to \'Draft\', when a case is created.\ \nIf the case is in progress the state is set to \'Open\'.\ \nWhen the case is over, the state is set to \'Done\'.\ \nIf the case needs to be reviewed then the state is set to \'Pending\'.' ), 'message_ids': fields.one2many('mailgate.message', 'res_id', 'Messages', domain=[('model','=',_name)]), } _defaults = { 'active': lambda *a: 1, 'user_id': crm.crm_case._get_default_user, 'partner_id': crm.crm_case._get_default_partner, 'partner_address_id': crm.crm_case._get_default_partner_address, 'email_from': crm.crm_case._get_default_email, 'state': lambda *a: 'draft', 'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'), 'section_id': crm.crm_case._get_section, 'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get( cr, uid, 'crm.helpdesk', context=c), 'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0], } def message_new(self, cr, uid, msg, context=None): """ Automatically calls when new email message arrives @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks """ mailgate_pool = self.pool.get('email.server.tools') subject = msg.get('subject') or _("No Subject") body = msg.get('body') msg_from = msg.get('from') priority = msg.get('priority') vals = { 'name': subject, 'email_from': msg_from, 'email_cc': msg.get('cc'), 'description': body, 'user_id': False, } if msg.get('priority', False): vals['priority'] = priority res = mailgate_pool.get_partner(cr, uid, msg.get('from') or msg.get_unixfrom()) if res: vals.update(res) res = self.create(cr, uid, vals, context) attachents = msg.get('attachments', []) att_ids = [] for attactment in attachents or []: data_attach = { 'name': attactment, 'datas': binascii.b2a_base64(str(attachents.get(attactment))), 'datas_fname': attactment, 'description': 'Mail attachment', 'res_model': self._name, 'res_id': res, } att_ids.append( self.pool.get('ir.attachment').create(cr, uid, data_attach)) return res, att_ids def message_update(self, cr, uid, ids, vals={}, msg="", default_act='pending', context=None): """ @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @param ids: List of update mail’s IDs """ if isinstance(ids, (str, int, long)): ids = [ids] if msg.get('priority') in dict(crm.AVAILABLE_PRIORITIES): vals['priority'] = msg.get('priority') maps = { 'cost': 'planned_cost', 'revenue': 'planned_revenue', 'probability': 'probability' } vls = {} for line in msg['body'].split('\n'): line = line.strip() res = tools.misc.command_re.match(line) if res and maps.get(res.group(1).lower()): key = maps.get(res.group(1).lower()) vls[key] = res.group(2).lower() vals.update(vls) # Unfortunately the API is based on lists # but we want to update the state based on the # previous state, so we have to loop: for case in self.browse(cr, uid, ids, context=context): values = dict(vals) if case.state in CRM_HELPDESK_STATES: values.update(state=crm.AVAILABLE_STATES[1][0]) #re-open res = self.write(cr, uid, [case.id], values, context=context) return res
class ir_property(osv.osv): _name = 'ir.property' def _models_field_get(self, cr, uid, field_key, field_value, context=None): get = attrgetter(field_key, field_value) obj = self.pool.get('ir.model.fields') ids = obj.search(cr, uid, [('view_load', '=', 1)], context=context) res = set() for o in obj.browse(cr, uid, ids, context=context): res.add(get(o)) return list(res) def _models_get(self, cr, uid, context=None): return self._models_field_get(cr, uid, 'model', 'model_id.name', context) def _models_get2(self, cr, uid, context=None): return self._models_field_get(cr, uid, 'relation', 'relation', context) _columns = { 'name': fields.char('Name', size=128, select=1), 'res_id': fields.reference( 'Resource', selection=_models_get, size=128, help="If not set, acts as a default value for new resources", select=1), 'company_id': fields.many2one('res.company', 'Company', select=1), 'fields_id': fields.many2one('ir.model.fields', 'Field', ondelete='cascade', required=True, select=1), 'value_float': fields.float('Value'), 'value_integer': fields.integer('Value'), 'value_text': fields.text('Value'), # will contain (char, text) 'value_binary': fields.binary('Value'), 'value_reference': fields.reference('Value', selection=_models_get2, size=128), 'value_datetime': fields.datetime('Value'), 'type': fields.selection([ ('char', 'Char'), ('float', 'Float'), ('boolean', 'Boolean'), ('integer', 'Integer'), ('text', 'Text'), ('binary', 'Binary'), ('many2one', 'Many2One'), ('date', 'Date'), ('datetime', 'DateTime'), ], 'Type', required=True, select=1), } _defaults = { 'type': 'many2one', } def _update_values(self, cr, uid, ids, values): value = values.pop('value', None) if not value: return values prop = None type_ = values.get('type') if not type_: if ids: prop = self.browse(cr, uid, ids[0]) type_ = prop.type else: type_ = self._defaults['type'] type2field = { 'char': 'value_text', 'float': 'value_float', 'boolean': 'value_integer', 'integer': 'value_integer', 'text': 'value_text', 'binary': 'value_binary', 'many2one': 'value_reference', 'date': 'value_datetime', 'datetime': 'value_datetime', } field = type2field.get(type_) if not field: raise osv.except_osv('Error', 'Invalid type') if field == 'value_reference': if isinstance(value, osv.orm.browse_record): value = '%s,%d' % (value._name, value.id) elif isinstance(value, (int, long)): field_id = values.get('fields_id') if not field_id: if not prop: raise ValueError() field_id = prop.fields_id else: field_id = self.pool.get('ir.model.fields').browse( cr, uid, field_id) value = '%s,%d' % (field_id.relation, value) values[field] = value return values def write(self, cr, uid, ids, values, context=None): return super(ir_property, self).write(cr, uid, ids, self._update_values(cr, uid, ids, values), context=context) def create(self, cr, uid, values, context=None): return super(ir_property, self).create(cr, uid, self._update_values(cr, uid, None, values), context=context) def get_by_record(self, cr, uid, record, context=None): if record.type in ('char', 'text'): return record.value_text elif record.type == 'float': return record.value_float elif record.type == 'boolean': return bool(record.value_integer) elif record.type == 'integer': return record.value_integer elif record.type == 'binary': return record.value_binary elif record.type == 'many2one': return record.value_reference elif record.type == 'datetime': return record.value_datetime elif record.type == 'date': if not record.value_datetime: return False return time.strftime( '%Y-%m-%d', time.strptime(record.value_datetime, '%Y-%m-%d %H:%M:%S')) return False def get(self, cr, uid, name, model, res_id=False, context=None): domain = self._get_domain(cr, uid, name, model, context=context) if domain is not None: domain = [('res_id', '=', res_id)] + domain nid = self.search(cr, uid, domain, context=context) if not nid: return False record = self.browse(cr, uid, nid[0], context=context) return self.get_by_record(cr, uid, record, context=context) return False def _get_domain_default(self, cr, uid, prop_name, model, context=None): domain = self._get_domain(cr, uid, prop_name, model, context=context) if domain is None: return None return ['&', ('res_id', '=', False)] + domain def _get_domain(self, cr, uid, prop_name, model, context=None): context = context or {} cr.execute('select id from ir_model_fields where name=%s and model=%s', (prop_name, model)) res = cr.fetchone() if not res: return None if 'force_company' in context and context['force_company']: cid = context['force_company'] else: company = self.pool.get('res.company') cid = company._company_default_get(cr, uid, model, res[0], context=context) domain = [ '&', ('fields_id', '=', res[0]), '|', ('company_id', '=', cid), ('company_id', '=', False) ] return domain
class qc_test_template(osv.osv): """ A template is a group of proofs to with the values that make them valid. """ _name = 'qc.test.template' _description = 'Test Template' # qc.test.template def _default_name(self, cr, uid, context=None): if context and context.get('reference_model', False): ref_id = context.get('reference_id') if not ref_id: ref_id = context.get('active_id') if ref_id: source = self.pool.get(context['reference_model']).browse(cr, uid, ref_id, context) if hasattr(source, 'name'): return source.name # qc.test.template def _default_object_id(self, cr, uid, context=None): if context and context.get('reference_model', False): return '%s,%d' % (context['reference_model'], context['reference_id']) else: return False # qc.test.template def _default_type(self, cr, uid, context=None): if context and context.get('reference_model'): return 'related' else: return False _columns = { 'active': fields.boolean('Active', select=True), 'name': fields.char('Name', size=200, required=True, translate=True, select=True), 'test_template_line_ids': fields.one2many('qc.test.template.line', 'test_template_id', 'Lines'), 'object_id': fields.reference('Reference Object', selection=_links_get, size=128), 'fill_correct_values': fields.boolean('Fill With Correct Values'), 'type': fields.selection([ ('generic', 'Generic'), ('related', 'Related'), ], 'Type', select=True), 'category_id': fields.many2one('qc.test.template.category', 'Category'), 'formula': fields.text('Formula'), 'company_id': fields.many2one('res.company', 'Company'), 'uom_id': fields.many2one('product.uom', 'UoM'), } _defaults = { 'name': _default_name, 'active': lambda *a: True, 'object_id': _default_object_id, 'type': _default_type, 'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'qc.test.template', context=c), }
class actions_server(osv.osv): def _select_signals(self, cr, uid, context={}): cr.execute( "SELECT distinct w.osv, t.signal FROM wkf w, wkf_activity a, wkf_transition t \ WHERE w.id = a.wkf_id AND t.act_from = a.id OR t.act_to = a.id AND t.signal!='' \ AND t.signal NOT IN (null, NULL)") result = cr.fetchall() or [] res = [] for rs in result: if rs[0] is not None and rs[1] is not None: line = rs[0], "%s - (%s)" % (rs[1], rs[0]) res.append(line) return res def _select_objects(self, cr, uid, context={}): model_pool = self.pool.get('ir.model') ids = model_pool.search(cr, uid, [('name', 'not ilike', '.')]) res = model_pool.read(cr, uid, ids, ['model', 'name']) return [(r['model'], r['name']) for r in res] + [('', '')] def change_object(self, cr, uid, ids, copy_object, state, context={}): if state == 'object_copy': model_pool = self.pool.get('ir.model') model = copy_object.split(',')[0] mid = model_pool.search(cr, uid, [('model', '=', model)]) return {'value': {'srcmodel_id': mid[0]}, 'context': context} else: return {} _name = 'ir.actions.server' _table = 'ir_act_server' _sequence = 'ir_actions_id_seq' _order = 'sequence' _columns = { 'name': fields.char( 'Action Name', required=True, size=64, help= "Easy to Refer action by name e.g. One Sales Order -> Many Invoices", translate=True), 'condition': fields.char( 'Condition', size=256, required=True, help= "Condition that is to be tested before action is executed, e.g. object.list_price > object.cost_price" ), 'state': fields.selection([ ('client_action', 'Client Action'), ('dummy', 'Dummy'), ('loop', 'Iteration'), ('code', 'Python Code'), ('trigger', 'Trigger'), ('email', 'Email'), ('sms', 'SMS'), ('object_create', 'Create Object'), ('object_copy', 'Copy Object'), ('object_write', 'Write Object'), ('other', 'Multi Actions'), ], 'Action Type', required=True, size=32, help="Type of the Action that is to be executed"), 'code': fields.text('Python Code', help="Python code to be executed"), 'sequence': fields.integer( 'Sequence', help= "Important when you deal with multiple actions, the execution order will be decided based on this, low number is higher priority." ), 'model_id': fields.many2one( 'ir.model', 'Object', required=True, help= "Select the object on which the action will work (read, write, create)." ), 'action_id': fields.many2one( 'ir.actions.actions', 'Client Action', help="Select the Action Window, Report, Wizard to be executed."), 'trigger_name': fields.selection( _select_signals, string='Trigger Name', size=128, help="Select the Signal name that is to be used as the trigger."), 'wkf_model_id': fields.many2one('ir.model', 'Workflow On', help="Workflow to be executed on this model."), 'trigger_obj_id': fields.many2one( 'ir.model.fields', 'Trigger On', help= "Select the object from the model on which the workflow will executed." ), 'email': fields.char( 'Email Address', size=512, help= "Provides the fields that will be used to fetch the email address, e.g. when you select the invoice, then `object.invoice_address_id.email` is the field which gives the correct address" ), 'subject': fields.char( 'Subject', size=1024, translate=True, help= "Specify the subject. You can use fields from the object, e.g. `Hello [[ object.partner_id.name ]]`" ), 'message': fields.text( 'Message', translate=True, help= "Specify the message. You can use the fields from the object. e.g. `Dear [[ object.partner_id.name ]]`" ), 'mobile': fields.char( 'Mobile No', size=512, help= "Provides fields that be used to fetch the mobile number, e.g. you select the invoice, then `object.invoice_address_id.mobile` is the field which gives the correct mobile number" ), 'sms': fields.char('SMS', size=160, translate=True), 'child_ids': fields.many2many('ir.actions.server', 'rel_server_actions', 'server_id', 'action_id', 'Other Actions'), 'usage': fields.char('Action Usage', size=32), 'type': fields.char('Action Type', size=32, required=True), 'srcmodel_id': fields.many2one( 'ir.model', 'Model', help= "Object in which you want to create / write the object. If it is empty then refer to the Object field." ), 'fields_lines': fields.one2many('ir.server.object.lines', 'server_id', 'Field Mappings.'), 'record_id': fields.many2one( 'ir.model.fields', 'Create Id', help= "Provide the field name where the record id is stored after the create operations. If it is empty, you can not track the new record." ), 'write_id': fields.char( 'Write Id', size=256, help= "Provide the field name that the record id refers to for the write operation. If it is empty it will refer to the active id of the object." ), 'loop_action': fields.many2one( 'ir.actions.server', 'Loop Action', help= "Select the action that will be executed. Loop action will not be avaliable inside loop." ), 'expression': fields.char( 'Loop Expression', size=512, help= "Enter the field/expression that will return the list. E.g. select the sale order in Object, and you can have loop on the sales order line. Expression = `object.order_line`." ), 'copy_object': fields.reference('Copy Of', selection=_select_objects, size=256), } _defaults = { 'state': lambda *a: 'dummy', 'condition': lambda *a: 'True', 'type': lambda *a: 'ir.actions.server', 'sequence': lambda *a: 5, 'code': lambda *a: """# You can use the following variables # - object or obj # - time # - cr # - uid # - ids # If you plan to return an action, assign: action = {...} """, } def get_email(self, cr, uid, action, context): logger = netsvc.Logger() obj_pool = self.pool.get(action.model_id.model) id = context.get('active_id') obj = obj_pool.browse(cr, uid, id) fields = None if '/' in action.email.complete_name: fields = action.email.complete_name.split('/') elif '.' in action.email.complete_name: fields = action.email.complete_name.split('.') for field in fields: try: obj = getattr(obj, field) except Exception, e: logger.notifyChannel('Workflow', netsvc.LOG_ERROR, 'Failed to parse : %s' % (field)) return obj
class qc_test(osv.osv): """ This model contains an instance of a test template. """ _name = 'qc.test' # qc.test def _success(self, cr, uid, ids, field_name, arg, context=None): result = {} for test in self.browse(cr, uid, ids, context): success = True proof = {} for line in test.test_line_ids: # Check the partner (test method). Check that at least the test # is a test method with some success. proof[line.proof_id.id] = (proof.get(line.proof_id.id, False) or line.success) for p in proof: if not proof[p]: success = False break result[test.id] = success return result # qc.test def _default_object_id(self, cr, uid, context=None): if context and context.get('reference_model', False): return '%s,%d' % ( context['reference_model'], context['reference_id']) else: return False # qc.test def _action_calc_formula(self, cr, uid, ids, field_names, args, context): result = {}.fromkeys(ids, 0) for test in self.browse(cr, uid, ids, context): vals = {} for line in test.test_line_ids: if line.name and line.proof_type == 'quantitative': vals[line.name] = line.actual_value_qt if not test.formula: result[test.id] = 0 continue try: value = safe_eval(test.formula, vals) result[test.id] = value except NameError: pass #raise osv.except_osv( _('Error:'), msg ) return result _columns = { 'name': fields.char('Number', size=64, required=True, select=True), 'date': fields.datetime('Date', required=True, readonly=True, select=True, states={ 'draft': [('readonly', False)], }), 'object_id': fields.reference('Reference', selection=_links_get, size=128, readonly=True, select=True, states={ 'draft': [('readonly', False)], }), 'test_template_id': fields.many2one('qc.test.template', 'Test template', select=True, states={ 'success': [('readonly', True)], 'failed': [('readonly', True)], }), 'test_line_ids': fields.one2many('qc.test.line', 'test_id', 'Test Lines', states={ 'success': [('readonly', True)], 'failed': [('readonly', True)], }), 'test_internal_note': fields.text('Internal Note', states={ 'success': [('readonly', True)], 'failed': [('readonly', True)], }), 'test_external_note': fields.text('External Note', states={ 'success': [('readonly', True)], 'failed': [('readonly', True)], }), 'state': fields.selection( [('draft', 'Draft'), ('waiting', 'Waiting Approval'), ('success', 'Quality Success'), ('failed', 'Quality Failed'), ], 'Status', readonly=True, select=True), 'success': fields.function(_success, method=True, type='boolean', string='Success', select=True, store=True, help='This field will be active if all tests have succeeded.'), 'formula': fields.text('Formula', readonly=1), 'formula_result': fields.function(_action_calc_formula, method=True, string='Formula Value', type='float', digits_compute=dp.get_precision( 'Quality Control')), 'uom_id': fields.many2one('product.uom', 'UoM'), 'company_id': fields.many2one('res.company', 'Company'), } _defaults = { 'name': lambda obj, cr, uid, context: \ obj.pool.get('ir.sequence').get(cr, uid, 'qc.test'), 'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'), 'state': 'draft', 'success': False, 'object_id': _default_object_id, 'company_id': lambda s, cr, uid, c: s.pool.get('res.company') \ ._company_default_get(cr, uid, 'qc.test', context=c), } # qc.test def _calc_line_vals_from_template(self, cr, uid, test_id, template_line, fill_correct_values, context): data = { 'name': template_line.name, 'test_id': test_id, 'method_id': template_line.method_id.id, 'proof_id': template_line.proof_id.id, 'test_template_line_id': template_line.id, 'notes': template_line.notes, 'min_value': template_line.min_value, 'max_value': template_line.max_value, 'uom_id': template_line.uom_id.id, 'test_uom_id': template_line.uom_id.id, 'proof_type': template_line.proof_id.type, } if fill_correct_values: if template_line.type == 'qualitative': # Fill with the first correct value found. data['actual_value_ql'] = (len(template_line.valid_value_ids) and template_line.valid_value_ids[0] and template_line.valid_value_ids[ 0].id or False) else: # Fill with value in the range. data['actual_value_qt'] = template_line.min_value data['test_uom_id'] = template_line.uom_id.id return data # qc.test def set_test_template(self, cr, uid, ids, template_id, force_fill=False, context=None): test_line_proxy = self.pool.get('qc.test.line') if context is None: context = {} template = self.pool.get('qc.test.template').browse(cr, uid, template_id, context=context) for test_id in ids: self.write(cr, uid, test_id, { 'test_template_id': template_id, 'formula': template.formula, 'uom_id': template.uom_id and template.uom_id.id }, context) test = self.browse(cr, uid, test_id, context) if len(test.test_line_ids) > 0: test_line_proxy.unlink(cr, uid, [x.id for x in test.test_line_ids], context) fill = test.test_template_id.fill_correct_values or False for line in test.test_template_id.test_template_line_ids: data = self._calc_line_vals_from_template(cr, uid, test_id, line, fill or force_fill, context) test_line_id = test_line_proxy.create(cr, uid, data, context) test_line_proxy.write(cr, uid, [test_line_id], { 'valid_value_ids': [ (6, 0, [x.id for x in line.valid_value_ids]), ], }, context) # It writes again the test to force to recalculate 'success' field self.write(cr, uid, test_id, { 'formula': template.formula, 'uom_id': template.uom_id and template.uom_id.id }, context) return True # qc.test def test_state(self, cr, uid, ids, mode, context): ''' Currently not used. Probably it will be completed (this code is a fake) when the nan_stock_production_lot_quality_control module will be implemented ''' quality_check = False if mode == 'failed': return not quality_check if mode == 'success': return quality_check return False # qc.test def action_workflow_draft(self, cr, uid, ids, context=None): self.write(cr, uid, ids, { 'state': 'draft' }, context) return True # qc.test def action_workflow_waiting(self, cr, uid, ids, context=None): self.write(cr, uid, ids, { 'state': 'waiting' }, context) return True # qc.test def action_workflow_success(self, cr, uid, ids, context=None): self.write(cr, uid, ids, { 'state': 'success' }, context) return True # qc.test def action_workflow_failed(self, cr, uid, ids, context=None): self.write(cr, uid, ids, { 'state': 'failed' }, context) return True # qc.test def test_workflow_draft(self, cr, uid, ids, context=None): # if qc_test.state=='success': return True # qc.test def copy(self, cr, uid, test_id, default=None, context=None): if context is None: context = {} if default is None: default = {} if not 'name' in default: default['name'] = self.pool.get('ir.sequence').get(cr, uid, 'qc.test') if not 'date' in default: default['date'] = time.strftime('%Y-%m-%d %H:%M:%S') return super(qc_test, self).copy(cr, uid, test_id, default, context) # qc.test def create(self, cr, uid, datas, context=None): if context and context.get('reference_model'): datas['object_id'] = context['reference_model'] + "," + \ str(context['reference_id']) return super(qc_test, self).create(cr, uid, datas, context=context)
class nan_document(osv.osv): _name = 'nan.document' _columns = { 'name': fields.char('Name', 64), 'datas': fields.binary('Data'), 'properties': fields.one2many('nan.document.property', 'document', 'Properties'), 'template': fields.many2one('nan.template', 'Template'), 'document': fields.reference('Document', selection=attachableDocuments, size=128), 'task': fields.text('Task', readonly=True), 'state': fields.selection([('pending', 'Pending'), ('scanning', 'Scanning'), ('scanned', 'Scanned'), ('verified', 'Verified'), ('processing', 'Processing'), ('processed', 'Processed')], 'State', required=True, readonly=True) } _defaults = {'state': lambda *a: 'pending'} def write(self, cr, uid, ids, values, context=None): # Scan after writting as it will modify the objects and thus a "modified in # the meanwhile" would be thrown, so by now check which of the records # we'll want to scan later toScan = [] if 'template' in values: for x in self.read(cr, uid, ids, ['state', 'template'], context): # We only scan the document if template has changed and the document # is in 'scanned' state. if x['state'] == 'scanned' and x['template'] != values[ 'template']: toScan.append({ 'id': x['id'], 'template': values['template'] }) ret = super(nan_document, self).write(cr, uid, ids, values, context) for x in toScan: self.scanDocumentWithTemplate(cr, uid, x['id'], x['template']) return ret def scan_document_background(self, cr, uid, imageIds): print "Scan document background" self.pool.get('ir.cron').create( cr, uid, { 'name': 'Scan document', 'user_id': uid, 'model': 'nan.document', 'function': 'scan_document', 'args': repr([imageIds, True]) }) cr.commit() def scan_documents_batch(self, cr, uid, imageIds): self.scan_document(cr, uid, imageIds) self.pool.get('res.request').create( cr, uid, { 'act_from': uid, 'act_to': uid, 'name': 'Finished scanning documents', 'body': 'The auto_attach system has finished scanning the documents you requested. You can now go to the Scanned Documents queue to verify and process them.', }) # If notify=True sends a request/notification to uid def scan_document(self, cr, uid, imageIds, notify=False): print "Scan_documentcalled" # Load templates into 'templates' list templates = self.pool.get('nan.template').getAllTemplates(cr, uid) # Initialize Ocr System (Gamera) initOcrSystem() recognizer = Recognizer() # Iterate over all images and try to find the most similar template for document in self.browse(cr, uid, imageIds): if document.state not in ('pending', 'scanning'): continue fp, image = tempfile.mkstemp() fp = os.fdopen(fp, 'wb+') fp.write(base64.decodestring(document.datas)) fp.close() recognizer.recognize(QImage(image)) result = recognizer.findMatchingTemplateByOffset(templates) template = result['template'] doc = result['document'] if not template: print "No template found for document %s." % document.name else: print "The best template found for document %s is %s." % ( document.name, template.name) if template: template_id = template.id else: template_id = False self.write(cr, uid, [document.id], { 'template': template_id, 'state': 'scanned' }) if doc: obj = self.pool.get('nan.document.property') for box in doc.boxes: obj.create( cr, uid, { 'name': box.templateBox.name, 'value': box.text, 'document': document.id, 'template_box': box.templateBox.id }) if notify: self.pool.get('res.request').create( cr, uid, { 'act_from': uid, 'act_to': uid, 'name': 'Finished scanning document', 'body': 'The auto_attach system has finished scanning the document you requested. A reference to the document can be found in field Document Ref 1.', 'ref_doc1': 'nan.document,%d' % document.id, }) self.executeAttachs(cr, uid, imageIds) self.executeActions(cr, uid, imageIds, True) cr.commit() def scanDocumentWithTemplate(self, cr, uid, documentId, templateId): # Whether templateId is valid or not # Remove previous properties obj = self.pool.get('nan.document.property') ids = obj.search(cr, uid, [('document', '=', documentId)]) obj.unlink(cr, uid, ids) if templateId: # Initialize Ocr System (Gamera) initOcrSystem() template = self.pool.get('nan.template').getTemplateFromId( cr, uid, templateId) documents = self.read(cr, uid, [documentId]) if not documents: return document = documents[0] fp, image = tempfile.mkstemp() fp = os.fdopen(fp, 'wb+') fp.write(base64.decodestring(document['datas'])) fp.close() recognizer = Recognizer() recognizer.recognize(QImage(image)) doc = recognizer.extractWithTemplate(image, template) for box in doc.boxes: obj.create( cr, uid, { 'name': box.templateBox.name, 'value': box.text, 'document': document['id'], 'template_box': box.templateBox.id }) self.executeAttachs(cr, uid, [documentId]) self.executeActions(cr, uid, [documentId], True) cr.commit() def process_document(self, cr, uid, ids): self.executeActions(cr, uid, ids, False) cr.commit() def _parseFunction(self, function, properties): expression = re.match('(.*)\((.*)\)', function) name = expression.group(1) parameters = expression.group(2) if name not in dir(self): print "Function '%s' not found" % (name) return False parameters = parameters.split(',') newParameters = [] for p in parameters: value = p.strip() if value.startswith('#'): if value[1:] not in properties: print "Property '%s' not found" % value newParameters.append("''") continue value = properties[value[1:]] value = "'" + value.replace("'", "\\'") + "'" if type(value) != unicode: value = unicode(value, errors='ignore') newParameters.append(value) return (name, newParameters) def executeActions(self, cr, uid, ids, explain): for document in self.browse(cr, uid, ids): print "Executing action on document with state ", document.state if not explain and document.state not in ('verified', 'processing'): continue print "Yes" task = None if document.template: function = document.template.action_function if function: properties = dict([(x.name, unicode(x.value)) for x in document.properties]) (name, parameters) = self._parseFunction(function, properties) obj = self.pool.get('nan.document') task = eval('obj.%s(cr, uid, explain, %s)' % (name, ','.join(parameters))) if explain: self.write(cr, uid, [document.id], {'task': task}) elif document.document: # Attach document to the appropiate reference ref = document.document.split(',') model = ref[0] id = ref[1] self.pool.get('ir.attachment').create( cr, uid, { 'res_id': id, 'res_model': model, 'name': document.name, 'datas': document.datas, 'datas_fname': document.name, 'description': 'Document attached automatically' }) self.write(cr, uid, [document.id], {'state': 'processed'}) def executeAttachs(self, cr, uid, ids): for document in self.browse(cr, uid, ids): reference = None if document.template: function = document.template.attach_function if function: properties = dict([(x.name, unicode(x.value, 'latin-1')) for x in document.properties]) (name, parameters) = self._parseFunction(function, properties) obj = self.pool.get('nan.document') #print 'CALLING: obj.%s(cr, uid, %s)' % ( name, u','.join( parameters ) ), reference = eval('obj.%s(cr, uid, %s)' % (name, u','.join(parameters))) if reference: self.write( cr, uid, [document.id], {'document': '%s,%s' % (reference[0], reference[1])}) else: self.write(cr, uid, [document.id], {'document': False}) def actionAddPartner(self, cr, uid, explain, name): if explain: return "A new partner with name '%s' will be created (if it doesn't exist already)." % name else: if not self.pool.get('res.partner').search(cr, uid, [('name', '=', name)]): self.pool.get('res.partner').create(cr, uid, {'name': name}) return True def attachModelByField(self, cr, uid, model, field, name): table = self.pool.get(model)._table # TODO: Security issues cr.execute('SELECT id FROM "' + table + '" ORDER BY similarity("' + field + '",\'%s\') DESC LIMIT 1' % name) record = cr.fetchone() if not record: return False return (model, record[0])
class event_registration(osv.osv): """Event Registration""" _name = 'event.registration' _description = __doc__ _inherit = 'mail.thread' def _amount_line(self, cr, uid, ids, field_name, arg, context=None): cur_obj = self.pool.get('res.currency') res = {} for line in self.browse(cr, uid, ids, context=context): price = line.unit_price * line.nb_register pricelist = line.event_id.pricelist_id or line.partner_invoice_id.property_product_pricelist cur = pricelist and pricelist.currency_id or False res[line.id] = cur and cur_obj.round(cr, uid, cur, price) or price return res _columns = { 'id': fields.integer('ID'), 'name': fields.char('Summary', size=124, readonly=True, states={'draft': [('readonly', False)]}), 'email_cc': fields.text('CC', size=252, readonly=False, states={'done': [('readonly', True)]}, help="These email addresses will be added to the CC field of all inbound and outbound emails for this record before being sent. Separate multiple email addresses with a comma"), 'nb_register': fields.integer('Quantity', required=True, readonly=True, states={'draft': [('readonly', False)]}, help="Number of Registrations or Tickets"), 'event_id': fields.many2one('event.event', 'Event', required=True, readonly=True, states={'draft': [('readonly', False)]}), 'partner_id': fields.many2one('res.partner', 'Partner', states={'done': [('readonly', True)]}), "partner_invoice_id": fields.many2one('res.partner', 'Partner Invoiced', readonly=True, states={'draft': [('readonly', False)]}), "contact_id": fields.many2one('res.partner.address', 'Partner Contact', readonly=False, states={'done': [('readonly', True)]}), #TODO: filter only the contacts that have a function into the selected partner_id "unit_price": fields.float('Unit Price', required=True, digits_compute=dp.get_precision('Sale Price'), readonly=True, states={'draft': [('readonly', False)]}), 'price_subtotal': fields.function(_amount_line, string='Subtotal', digits_compute=dp.get_precision('Sale Price'), store=True), "badge_ids": fields.one2many('event.registration.badge', 'registration_id', 'Badges', readonly=False, states={'done': [('readonly', True)]}), "event_product": fields.char("Invoice Name", size=128, readonly=True, states={'draft': [('readonly', False)]}), "tobe_invoiced": fields.boolean("To be Invoiced", readonly=True, states={'draft': [('readonly', False)]}), "invoice_id": fields.many2one("account.invoice", "Invoice", readonly=True), 'date_closed': fields.datetime('Closed', readonly=True), 'ref': fields.reference('Reference', selection=crm._links_get, size=128), 'ref2': fields.reference('Reference 2', selection=crm._links_get, size=128), 'email_from': fields.char('Email', size=128, states={'done': [('readonly', True)]}, help="These people will receive email."), 'create_date': fields.datetime('Creation Date', readonly=True), 'write_date': fields.datetime('Write Date', readonly=True), 'description': fields.text('Description', states={'done': [('readonly', True)]}), 'message_ids': fields.one2many('mail.message', 'res_id', 'Messages', domain=[('model','=',_name)]), 'log_ids': fields.one2many('mail.message', 'res_id', 'Logs', domain=[('email_from', '=', False),('model','=',_name)]), 'date_deadline': fields.related('event_id','date_end', type='datetime', string="End Date", readonly=True), 'date': fields.related('event_id', 'date_begin', type='datetime', string="Start Date", readonly=True), 'user_id': fields.many2one('res.users', 'Responsible', states={'done': [('readonly', True)]}), 'active': fields.boolean('Active'), 'section_id': fields.related('event_id', 'section_id', type='many2one', relation='crm.case.section', string='Sale Team', store=True, readonly=True), 'company_id': fields.related('event_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True, states={'draft':[('readonly',False)]}), 'state': fields.selection([('open', 'Confirmed'), ('draft', 'Unconfirmed'), ('cancel', 'Cancelled'), ('done', 'Done')], 'State', \ size=16, readonly=True) } _defaults = { 'nb_register': 1, 'tobe_invoiced': True, 'state': 'draft', 'active': 1, 'user_id': lambda self, cr, uid, ctx: uid, } def _make_invoice(self, cr, uid, reg, lines, context=None): """ Create Invoice from Invoice lines @param reg: Model of Event Registration @param lines: Ids of Invoice lines """ if context is None: context = {} inv_pool = self.pool.get('account.invoice') val_invoice = inv_pool.onchange_partner_id(cr, uid, [], 'out_invoice', reg.partner_invoice_id.id, False, False) val_invoice['value'].update({'partner_id': reg.partner_invoice_id.id}) val_invoice['value'].update({ 'origin': reg.event_product, 'reference': False, 'invoice_line': [(6, 0, lines)], 'comment': "", 'date_invoice': context.get('date_inv', False) }) inv_id = inv_pool.create(cr, uid, val_invoice['value'], context=context) inv_pool.button_compute(cr, uid, [inv_id]) self.message_append(cr, uid, [reg], _('Invoiced')) return inv_id def copy(self, cr, uid, id, default=None, context=None): """ Copy record of Given id @param id: Id of Registration record. @param context: A standard dictionary for contextual values """ if not default: default = {} default.update({ 'invoice_id': False, }) return super(event_registration, self).copy(cr, uid, id, default=default, context=context) def action_invoice_create(self, cr, uid, ids, grouped=False, date_inv=False, context=None): """ Action of Create Invoice """ res = False invoices = {} tax_ids = [] new_invoice_ids = [] inv_lines_pool = self.pool.get('account.invoice.line') inv_pool = self.pool.get('account.invoice') product_pool = self.pool.get('product.product') contact_pool = self.pool.get('res.partner.address') if context is None: context = {} # If date was specified, use it as date invoiced, usefull when invoices are generated this month and put the # last day of the last month as invoice date if date_inv: context['date_inv'] = date_inv for reg in self.browse(cr, uid, ids, context=context): val_invoice = inv_pool.onchange_partner_id( cr, uid, [], 'out_invoice', reg.partner_invoice_id.id, False, False) val_invoice['value'].update( {'partner_id': reg.partner_invoice_id.id}) partner_address_id = val_invoice['value']['address_invoice_id'] if not partner_address_id: raise osv.except_osv( _('Error !'), _("Registered partner doesn't have an address to make the invoice." )) value = inv_lines_pool.product_id_change( cr, uid, [], reg.event_id.product_id.id, uom=False, partner_id=reg.partner_invoice_id.id, fposition_id=reg.partner_invoice_id.property_account_position. id) product = product_pool.browse(cr, uid, reg.event_id.product_id.id, context=context) for tax in product.taxes_id: tax_ids.append(tax.id) vals = value['value'] c_name = reg.contact_id and ('-' + contact_pool.name_get( cr, uid, [reg.contact_id.id])[0][1]) or '' vals.update({ 'name': reg.event_product + '-' + c_name, 'price_unit': reg.unit_price, 'quantity': reg.nb_register, 'product_id': reg.event_id.product_id.id, 'invoice_line_tax_id': [(6, 0, tax_ids)], }) inv_line_ids = self._create_invoice_lines(cr, uid, [reg.id], vals) invoices.setdefault(reg.partner_id.id, []).append( (reg, inv_line_ids)) for val in invoices.values(): res = False if grouped: res = self._make_invoice(cr, uid, val[0][0], [v for k, v in val], context=context) for k, v in val: self.do_close(cr, uid, [k.id], context={'invoice_id': res}) else: for k, v in val: res = self._make_invoice(cr, uid, k, [v], context=context) self.do_close(cr, uid, [k.id], context={'invoice_id': res}) if res: new_invoice_ids.append(res) return new_invoice_ids def do_open(self, cr, uid, ids, context=None): """ Open Registration """ res = self.write(cr, uid, ids, {'state': 'open'}, context=context) self.mail_user(cr, uid, ids) self.message_append(cr, uid, ids, _('Open')) return res def do_close(self, cr, uid, ids, context=None): """ Close Registration """ if context is None: context = {} invoice_id = context.get('invoice_id', False) values = { 'state': 'done', 'date_closed': time.strftime('%Y-%m-%d %H:%M:%S') } msg = _('Done') if invoice_id: values['invoice_id'] = invoice_id res = self.write(cr, uid, ids, values) self.message_append(cr, uid, ids, msg) return res # event uses add_note wizard from crm, which expects case_* methods def case_open(self, cr, uid, ids, context=None): self.do_open(cr, uid, ids, context) # event uses add_note wizard from crm, which expects case_* methods def case_close(self, cr, uid, ids, context=None): self.do_close(cr, uid, ids, context) # event uses add_note wizard from crm, which expects case_* methods def case_cancel(self, cr, uid, ids, context=None): """ Cancel Registration """ self.message_append(cr, uid, ids, _('Cancel')) return self.write(cr, uid, ids, {'state': 'cancel'}) # event uses add_note wizard from crm, which expects case_* methods def case_reset(self, cr, uid, ids, context=None): pass # event uses add_note wizard from crm, which expects case_* methods def case_pending(self, cr, uid, ids, context=None): pass def check_confirm(self, cr, uid, ids, context=None): """This Function Open Event Registration and send email to user. @param ids: List of Event registration's IDs @param context: A standard dictionary for contextual values @return: True """ if type(ids) in ( int, long, ): ids = [ids] data_pool = self.pool.get('ir.model.data') unconfirmed_ids = [] if context is None: context = {} for registration in self.browse(cr, uid, ids, context=context): total_confirmed = registration.event_id.register_current + registration.nb_register if total_confirmed <= registration.event_id.register_max or registration.event_id.register_max == 0: self.do_open(cr, uid, [registration.id], context=context) else: unconfirmed_ids.append(registration.id) if unconfirmed_ids: view_id = data_pool.get_object_reference( cr, uid, 'event', 'view_event_confirm_registration') view_id = view_id and view_id[1] or False context['registration_ids'] = unconfirmed_ids return { 'name': _('Confirm Registration'), 'context': context, 'view_type': 'form', 'view_mode': 'tree,form', 'res_model': 'event.confirm.registration', 'views': [(view_id, 'form')], 'type': 'ir.actions.act_window', 'target': 'new', 'context': context, 'nodestroy': True } return True def button_reg_close(self, cr, uid, ids, context=None): """This Function Close Event Registration. """ data_pool = self.pool.get('ir.model.data') unclosed_ids = [] for registration in self.browse(cr, uid, ids, context=context): if registration.tobe_invoiced and not registration.invoice_id: unclosed_ids.append(registration.id) else: self.do_close(cr, uid, [registration.id], context=context) if unclosed_ids: view_id = data_pool.get_object_reference( cr, uid, 'event', 'view_event_make_invoice') view_id = view_id and view_id[1] or False context['active_ids'] = unclosed_ids return { 'name': _('Close Registration'), 'context': context, 'view_type': 'form', 'view_mode': 'tree,form', 'res_model': 'event.make.invoice', 'views': [(view_id, 'form')], 'type': 'ir.actions.act_window', 'target': 'new', 'context': context, 'nodestroy': True } return True def button_reg_cancel(self, cr, uid, ids, context=None, *args): return self.case_cancel(cr, uid, ids) def mail_user(self, cr, uid, ids, confirm=False, context=None): """ Send email to user """ mail_message = self.pool.get('mail.message') for registration in self.browse(cr, uid, ids, context=context): src = registration.event_id.reply_to or False email_to = [] email_cc = [] if registration.email_from: email_to = [registration.email_from] if registration.email_cc: email_cc += [registration.email_cc] if not (email_to or email_cc): continue subject = "" body = "" if confirm: subject = _('Auto Confirmation: [%s] %s') % (registration.id, registration.name) body = registration.event_id.mail_confirm elif registration.event_id.mail_auto_confirm or registration.event_id.mail_auto_registr: if registration.event_id.state in [ 'draft', 'fixed', 'open', 'confirm', 'running' ] and registration.event_id.mail_auto_registr: subject = _('Auto Registration: [%s] %s') % ( registration.id, registration.name) body = registration.event_id.mail_registr if (registration.event_id.state in [ 'confirm', 'running' ]) and registration.event_id.mail_auto_confirm: subject = _('Auto Confirmation: [%s] %s') % ( registration.id, registration.name) body = registration.event_id.mail_confirm if subject or body: mail_message.schedule_with_attach(cr, uid, src, email_to, subject, body, model='event.registration', email_cc=email_cc, res_id=registration.id) return True def mail_user_confirm(self, cr, uid, ids, context=None): """ Send email to user """ return self.mail_user(cr, uid, ids, confirm=True, context=context) def _create_invoice_lines(self, cr, uid, ids, vals): """ Create account Invoice line for Registration Id. """ return self.pool.get('account.invoice.line').create(cr, uid, vals) def onchange_contact_id(self, cr, uid, ids, contact, partner): """This function returns value of Badge Name, Badge Title based on Partner contact. @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @param ids: List of Registration IDs @param contact: Patner Contact IDS @param partner: Partner IDS """ data = {} if not contact: return data addr_obj = self.pool.get('res.partner.address') data['email_from'] = addr_obj.browse(cr, uid, contact).email return {'value': data} def onchange_event(self, cr, uid, ids, event_id, partner_invoice_id): """This function returns value of Product Name, Unit Price based on Event. @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @param ids: List of Registration IDs @param event_id: Event ID @param partner_invoice_id: Partner Invoice ID """ context = {} if not event_id: return {'value': {'unit_price': False, 'event_product': False}} event_obj = self.pool.get('event.event') prod_obj = self.pool.get('product.product') res_obj = self.pool.get('res.partner') data_event = event_obj.browse(cr, uid, event_id) res = { 'value': { 'unit_price': False, 'event_product': False, 'user_id': False, 'date': data_event.date_begin, 'date_deadline': data_event.date_end, 'description': data_event.note, 'name': data_event.name, 'section_id': data_event.section_id and data_event.section_id.id or False, } } if data_event.user_id.id: res['value'].update({'user_id': data_event.user_id.id}) if data_event.product_id: pricelist_id = data_event.pricelist_id and data_event.pricelist_id.id or False if partner_invoice_id: partner = res_obj.browse(cr, uid, partner_invoice_id, context=context) pricelist_id = pricelist_id or partner.property_product_pricelist.id unit_price = prod_obj._product_price( cr, uid, [data_event.product_id.id], False, False, {'pricelist': pricelist_id})[data_event.product_id.id] if not unit_price: unit_price = data_event.unit_price res['value'].update({ 'unit_price': unit_price, 'event_product': data_event.product_id.name }) return res def onchange_partner_id(self, cr, uid, ids, part, event_id, email=False): """This function returns value of Patner Invoice id, Unit Price, badget title based on partner and Event. @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @param ids: List of Registration IDs @param event_id: Event ID @param partner_invoice_id: Partner Invoice ID """ res_obj = self.pool.get('res.partner') data = {} data['contact_id'], data['partner_invoice_id'], data['email_from'] = ( False, False, False) if not part: return {'value': data} data['partner_invoice_id'] = part # this calls onchange_partner_invoice_id d = self.onchange_partner_invoice_id(cr, uid, ids, event_id, part) # this updates the dictionary data.update(d['value']) addr = res_obj.address_get(cr, uid, [part]).get('default', False) if addr: d = self.onchange_contact_id(cr, uid, ids, addr, part) data.update(d['value']) return {'value': data} def onchange_partner_invoice_id(self, cr, uid, ids, event_id, partner_invoice_id): """This function returns value of Product unit Price based on Invoiced partner. @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @param ids: List of Registration IDs @param event_id: Event ID @param partner_invoice_id: Partner Invoice ID """ data = {} context = {} event_obj = self.pool.get('event.event') prod_obj = self.pool.get('product.product') res_obj = self.pool.get('res.partner') data['unit_price'] = False if not event_id: return {'value': data} data_event = event_obj.browse(cr, uid, event_id, context=context) if data_event.product_id: data['event_product'] = data_event.product_id.name pricelist_id = data_event.pricelist_id and data_event.pricelist_id.id or False if partner_invoice_id: partner = res_obj.browse(cr, uid, partner_invoice_id, context=context) pricelist_id = pricelist_id or partner.property_product_pricelist.id unit_price = prod_obj._product_price( cr, uid, [data_event.product_id.id], False, False, {'pricelist': pricelist_id})[data_event.product_id.id] if not unit_price: unit_price = data_event.unit_price data['unit_price'] = unit_price return {'value': data}