Merge with lp:~openerp-dev/openobject-addons/trunk-dev-addons3

bzr revid: sbh@tinyerp.com-20100624101452-uklaltn5iwgi4t0n
This commit is contained in:
sbh (Open ERP)
2010-06-24 15:44:52 +05:30
53 changed files with 884 additions and 574 deletions
+3 -3
View File
@@ -72,8 +72,8 @@
<field name="priority">2</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
<notebook>
<page string="Accounting" position="inside">
<page string="Notes" position="before">
<page string="Accounting">
<group col="2" colspan="2">
<separator string="Customer Accounting Properties" colspan="2"/>
<field name="property_account_receivable" groups="account.group_account_user" />
@@ -121,7 +121,7 @@
</tree>
</field>
</page>
</notebook>
</page>
</field>
</record>
+335 -230
View File
@@ -25,6 +25,7 @@ from tools.translate import _
import ir
import pooler
import time
import tools
class audittrail_rule(osv.osv):
"""
@@ -33,25 +34,28 @@ class audittrail_rule(osv.osv):
_name = 'audittrail.rule'
_description = "Audittrail Rule"
_columns = {
"name": fields.char("Rule Name", size=32, required=True),
"object_id": fields.many2one('ir.model', 'Object', required=True),
"user_id": fields.many2many('res.users', 'audittail_rules_users',
'user_id', 'rule_id', 'Users'),
"log_read": fields.boolean("Log reads"),
"log_write": fields.boolean("Log writes"),
"log_unlink": fields.boolean("Log deletes"),
"log_create": fields.boolean("Log creates"),
"state": fields.selection((("draft", "Draft"),
("subscribed", "Subscribed")),
"State", required=True),
"action_id": fields.many2one('ir.actions.act_window', "Action ID"),
"name": fields.char("Rule Name", size=32, required=True),
"object_id": fields.many2one('ir.model', 'Object', required=True),
"user_id": fields.many2many('res.users', 'audittail_rules_users',
'user_id', 'rule_id', 'Users', help="if User is not added then it will applicable for all users"),
"log_read": fields.boolean("Log Reads"),
"log_write": fields.boolean("Log Writes"),
"log_unlink": fields.boolean("Log Deletes"),
"log_create": fields.boolean("Log Creates"),
"log_action": fields.boolean("Log Action"),
"log_workflow": fields.boolean("Log Workflow"),
"state": fields.selection((("draft", "Draft"),
("subscribed", "Subscribed")),
"State", required=True),
"action_id": fields.many2one('ir.actions.act_window', "Action ID"),
}
_defaults = {
'state': lambda *a: 'draft',
'log_create': lambda *a: 1,
'log_unlink': lambda *a: 1,
'log_write': lambda *a: 1,
'state': lambda *a: 'draft',
'log_create': lambda *a: 1,
'log_unlink': lambda *a: 1,
'log_write': lambda *a: 1,
}
_sql_constraints = [
@@ -65,7 +69,7 @@ class audittrail_rule(osv.osv):
@param cr: the current row, from the database cursor,
@param uid: the current user’s ID for security checks,
@param ids: List of Auddittrail Rule’s IDs.
@return: True
@return: True
"""
obj_action = self.pool.get('ir.actions.act_window')
obj_model = self.pool.get('ir.model.data')
@@ -74,20 +78,20 @@ class audittrail_rule(osv.osv):
obj = self.pool.get(thisrule.object_id.model)
if not obj:
raise osv.except_osv(
_('WARNING: audittrail is not part of the pool'),
_('WARNING: audittrail is not part of the pool'),
_('Change audittrail depends -- Setting rule as DRAFT'))
self.write(cr, uid, [thisrule.id], {"state": "draft"})
val = {
"name": 'View Log',
"res_model": 'audittrail.log',
"src_model": thisrule.object_id.model,
"name": 'View Log',
"res_model": 'audittrail.log',
"src_model": thisrule.object_id.model,
"domain": "[('object_id','=', " + str(thisrule.object_id.id) + "), ('res_id', '=', active_id)]"
}
id = obj_action.create(cr, uid, val)
self.write(cr, uid, [thisrule.id], {"state": "subscribed", "action_id": id})
action_id = obj_action.create(cr, uid, val)
self.write(cr, uid, [thisrule.id], {"state": "subscribed", "action_id": action_id})
keyword = 'client_action_relate'
value = 'ir.actions.act_window,' + str(id)
value = 'ir.actions.act_window,' + str(action_id)
res = obj_model.ir_set(cr, uid, 'action', keyword, 'View_log_' + thisrule.object_id.model, [thisrule.object_id.model], value, replace=True, isobject=True, xml_id=False)
#End Loop
return True
@@ -98,7 +102,7 @@ class audittrail_rule(osv.osv):
@param cr: the current row, from the database cursor,
@param uid: the current user’s ID for security checks,
@param ids: List of Auddittrail Rule’s IDs.
@return: True
@return: True
"""
obj_action = self.pool.get('ir.actions.act_window')
val_obj = self.pool.get('ir.values')
@@ -127,17 +131,28 @@ class audittrail_log(osv.osv):
_name = 'audittrail.log'
_description = "Audittrail Log"
def _name_get_resname(self, cr, uid, ids, *args):
data = {}
for resname in self.browse(cr, uid, ids,[]):
model_object = resname.object_id
res_id = resname.res_id
if model_object and res_id:
model_pool = self.pool.get(model_object.model)
res = model_pool.read(cr, uid, res_id, ['name'])
data[resname.id] = res['name']
else:
data[resname.id] = False
return data
_columns = {
"name": fields.char("Name", size=32),
"object_id": fields.many2one('ir.model', 'Object'),
"user_id": fields.many2one('res.users', 'User'),
"method": fields.selection((('read', 'Read'),
('write', 'Write'),
('unlink', 'Delete'),
('create', 'Create')), "Method"),
"timestamp": fields.datetime("Date"),
"res_id": fields.integer('Resource Id'),
"line_ids": fields.one2many('audittrail.log.line', 'log_id', 'Log lines'),
"name": fields.char("Resource Name",size=64),
# "name": fields.function(_name_get_resname, type='char', string='Resource Name', method=True),
"object_id": fields.many2one('ir.model', 'Object'),
"user_id": fields.many2one('res.users', 'User'),
"method": fields.char("Method", size=64),
"timestamp": fields.datetime("Date"),
"res_id": fields.integer('Resource Id'),
"line_ids": fields.one2many('audittrail.log.line', 'log_id', 'Log lines'),
}
_defaults = {
@@ -155,14 +170,14 @@ class audittrail_log_line(osv.osv):
_name = 'audittrail.log.line'
_description = "Log Line"
_columns = {
'field_id': fields.many2one('ir.model.fields', 'Fields', required=True),
'log_id': fields.many2one('audittrail.log', 'Log'),
'log': fields.integer("Log ID"),
'old_value': fields.text("Old Value"),
'new_value': fields.text("New Value"),
'old_value_text': fields.text('Old value Text'),
'new_value_text': fields.text('New value Text'),
'field_description': fields.char('Field Description', size=64),
'field_id': fields.many2one('ir.model.fields', 'Fields', required=True),
'log_id': fields.many2one('audittrail.log', 'Log'),
'log': fields.integer("Log ID"),
'old_value': fields.text("Old Value"),
'new_value': fields.text("New Value"),
'old_value_text': fields.text('Old value Text'),
'new_value_text': fields.text('New value Text'),
'field_description': fields.char('Field Description', size=64),
}
audittrail_log_line()
@@ -170,276 +185,366 @@ audittrail_log_line()
class audittrail_objects_proxy(osv_pool):
""" Uses Object proxy for auditing changes on object of subscribed Rules"""
def get_value_text(self, cr, uid, field_name, values, object, context=None):
def get_value_text(self, cr, uid, field_name, values, model, context=None):
"""
Gets textual values for the fields
e.g.: For field of type many2one it gives its name value instead of id
@param cr: the current row, from the database cursor,
@param uid: the current user’s ID for security checks,
@param field_name: List of fields for text values
@param values: Values for field to be converted into textual values
@return: values: List of textual values for given fields
@param field_name: List of fields for text values
@param values: Values for field to be converted into textual values
@return: values: List of textual values for given fields
"""
if not context:
context = {}
pool = pooler.get_pool(cr.dbname)
f_id = pool.get('ir.model.fields').search(cr, uid, [('name', '=', field_name), ('model_id', '=', object.id)])
if f_id:
field = pool.get('ir.model.fields').read(cr, uid, f_id)[0]
model = field['relation']
field_pool = pool.get('ir.model.fields')
model_pool = pool.get('ir.model')
obj_pool = pool.get(model.model)
if obj_pool._inherits:
inherits_ids = model_pool.search(cr, uid, [('model', '=', obj_pool._inherits.keys()[0])])
field_ids = field_pool.search(cr, uid, [('name', '=', field_name), ('model_id', 'in', (model.id, inherits_ids[0]))])
else:
field_ids = field_pool.search(cr, uid, [('name', '=', field_name), ('model_id', '=', model.id)])
field_id = field_ids and field_ids[0] or False
assert field_id, _("'%s' field is not exits in '%s' model" %(field_name, model.model))
if field['ttype'] == 'many2one':
if values:
if type(values) == tuple:
values = values[0]
val = pool.get(model).read(cr, uid, [values], [pool.get(model)._rec_name])
if val:
return val[0][pool.get(model)._rec_name]
elif field['ttype'] == 'many2many':
value = []
if values:
for id in values:
val = pool.get(model).read(cr, uid, [id], [pool.get(model)._rec_name])
if val:
value.append(val[0][pool.get(model)._rec_name])
return value
field = field_pool.read(cr, uid, field_id)
relation_model = field['relation']
relation_model_pool = relation_model and pool.get(relation_model) or False
elif field['ttype'] == 'one2many':
if values:
value = []
for id in values:
val = pool.get(model).read(cr, uid, [id], [pool.get(model)._rec_name])
if field['ttype'] == 'many2one':
res = False
relation_id = False
if values and type(values) == tuple:
relation_id = values[0]
if relation_id and relation_model_pool:
relation_model_object = relation_model_pool.read(cr, uid, relation_id, [relation_model_pool._rec_name])
res = relation_model_object[relation_model_pool._rec_name]
return res
if val:
value.append(val[0][pool.get(model)._rec_name])
return value
return values
elif field['ttype'] in ('many2many','one2many'):
res = []
for relation_model_object in relation_model_pool.read(cr, uid, values, [relation_model_pool._rec_name]):
res.append(relation_model_object[relation_model_pool._rec_name])
return res
def create_log_line(self, cr, uid, id, object, lines=[]):
return values
def create_log_line(self, cr, uid, log_id, model, lines=[]):
"""
Creates lines for changed fields with its old and new values
@param cr: the current row, from the database cursor,
@param uid: the current user’s ID for security checks,
@param object: Object who's values are being changed
@param model: Object who's values are being changed
@param lines: List of values for line is to be created
"""
pool = pooler.get_pool(cr.dbname)
obj = pool.get(object.model)
obj_pool = pool.get(model.model)
model_pool = pool.get('ir.model')
field_pool = pool.get('ir.model.fields')
log_line_pool = pool.get('audittrail.log.line')
#start Loop
for line in lines:
if obj._inherits:
inherits_ids = pool.get('ir.model').search(cr, uid, [('model', '=', obj._inherits.keys()[0])])
f_id = pool.get('ir.model.fields').search(cr, uid, [('name', '=', line['name']), ('model_id', 'in', (object.id, inherits_ids[0]))])
if obj_pool._inherits:
inherits_ids = model_pool.search(cr, uid, [('model', '=', obj_pool._inherits.keys()[0])])
field_ids = field_pool.search(cr, uid, [('name', '=', line['name']), ('model_id', 'in', (model.id, inherits_ids[0]))])
else:
f_id = pool.get('ir.model.fields').search(cr, uid, [('name', '=', line['name']), ('model_id', '=', object.id)])
if f_id:
fields = pool.get('ir.model.fields').read(cr, uid, f_id)
old_value = 'old_value' in line and line['old_value'] or ''
new_value = 'new_value' in line and line['new_value'] or ''
old_value_text = 'old_value_text' in line and line['old_value_text'] or ''
new_value_text = 'new_value_text' in line and line['new_value_text'] or ''
if old_value_text == new_value_text:
continue
if fields[0]['ttype'] == 'many2one':
if type(old_value) == tuple:
old_value = old_value[0]
if type(new_value) == tuple:
new_value = new_value[0]
vals = {
"log_id": id,
"field_id": f_id[0],
"old_value": old_value,
"new_value": new_value,
"old_value_text": old_value_text,
"new_value_text": new_value_text,
"field_description": fields[0]['field_description']
}
line_id = pool.get('audittrail.log.line').create(cr, uid, vals)
cr.commit()
#End Loop
field_ids = field_pool.search(cr, uid, [('name', '=', line['name']), ('model_id', '=', model.id)])
field_id = field_ids and field_ids[0] or False
assert field_id, _("'%s' field is not exits in '%s' model" %(line['name'], model.model))
field = field_pool.read(cr, uid, field_id)
old_value = 'old_value' in line and line['old_value'] or ''
new_value = 'new_value' in line and line['new_value'] or ''
old_value_text = 'old_value_text' in line and line['old_value_text'] or ''
new_value_text = 'new_value_text' in line and line['new_value_text'] or ''
if old_value_text == new_value_text:
continue
if field['ttype'] == 'many2one':
if type(old_value) == tuple:
old_value = old_value[0]
if type(new_value) == tuple:
new_value = new_value[0]
vals = {
"log_id": log_id,
"field_id": field_id,
"old_value": old_value,
"new_value": new_value,
"old_value_text": old_value_text,
"new_value_text": new_value_text,
"field_description": field['field_description']
}
line_id = log_line_pool.create(cr, uid, vals)
#End Loop
return True
def log_fct(self, db, uid, object, method, fct_src, *args):
def log_fct(self, db, uid, model, method, fct_src, *args):
"""
Logging function: This function is performs logging oprations according to method
@param db: the current database
@param uid: the current user’s ID for security checks,
@param object: Object who's values are being changed
@param method: method to log: create, read, write, unlink
@param method: method to log: create, read, write, unlink
@param fct_src: execute method of Object proxy
@return: Returns result as per method of Object proxy
@return: Returns result as per method of Object proxy
"""
logged_uids = []
res2 = args
pool = pooler.get_pool(db)
cr = pooler.get_db(db).cursor()
obj_ids = pool.get('ir.model').search(cr, uid, [('model', '=', object)])
model_object = pool.get('ir.model').browse(cr, uid, obj_ids)[0]
resource_pool = pool.get(model)
log_pool = pool.get('audittrail.log')
model_pool = pool.get('ir.model')
model_ids = model_pool.search(cr, uid, [('model', '=', model)])
model_id = model_ids and model_ids[0] or False
assert model_id, _("'%s' Model is not exits..." %(model))
model = model_pool.browse(cr, uid, model_id)
if method in ('create'):
res_id = fct_src(db, uid, object, method, *args)
res_id = fct_src(db, uid, model.model, method, *args)
cr.commit()
new_value = pool.get(model_object.model).read(cr, uid, [res_id], args[0].keys())[0]
if 'id' in new_value:
del new_value['id']
if not logged_uids or uid in logged_uids:
resource_name = pool.get(model_object.model).name_get(cr, uid, [res_id])
resource_name = resource_name and resource_name[0][1] or ''
vals = {
"method": method,
"object_id": model_object.id,
"user_id": uid, "res_id": res_id,
"name": resource_name
}
id = pool.get('audittrail.log').create(cr, uid, vals)
lines = []
for field in new_value:
if new_value[field]:
line = {
'name': field,
'new_value': new_value[field],
'new_value_text': self.get_value_text(cr, uid, field, new_value[field], model_object)
}
lines.append(line)
self.create_log_line(cr, uid, id, model_object, lines)
resource = resource_pool.read(cr, uid, res_id, args[0].keys())
vals = {
"method": method,
"object_id": model.id,
"user_id": uid,
"res_id": resource['id'],
}
if 'id' in resource:
del resource['id']
log_id = log_pool.create(cr, uid, vals)
lines = []
for field in resource:
line = {
'name': field,
'new_value': resource[field],
'new_value_text': self.get_value_text(cr, uid, field, resource[field], model)
}
lines.append(line)
self.create_log_line(cr, uid, log_id, model, lines)
cr.commit()
cr.close()
return res_id
if method in ('write'):
res_ids = args[0]
for res_id in res_ids:
old_values = pool.get(model_object.model).read(cr, uid, res_id, args[1].keys())
old_values_text = {}
for field in args[1].keys():
old_values_text[field] = self.get_value_text(cr, uid, field, old_values[field], model_object)
res = fct_src(db, uid, object, method, *args)
cr.commit()
if res:
new_values = pool.get(model_object.model).read(cr, uid, res_ids, args[1].keys())[0]
if not logged_uids or uid in logged_uids:
resource_name = pool.get(model_object.model).name_get(cr, uid, [res_id])
resource_name = resource_name and resource_name[0][1] or ''
id = pool.get('audittrail.log').create(cr, uid, {"method": method, "object_id": model_object.id, "user_id": uid, "res_id": res_id, "name": resource_name})
lines = []
for field in args[1].keys():
if args[1].keys():
line = {
'name': field,
'new_value': field in new_values and new_values[field] or '',
'old_value': field in old_values and old_values[field] or '',
'new_value_text': self.get_value_text(cr, uid, field, new_values[field], model_object),
'old_value_text': old_values_text[field]
}
lines.append(line)
cr.commit()
self.create_log_line(cr, uid, id, model_object, lines)
cr.close()
return res
if method in ('read'):
elif method in ('read'):
res_ids = args[0]
old_values = {}
res = fct_src(db, uid, object, method, *args)
res = fct_src(db, uid, model.model, method, *args)
if type(res) == list:
for v in res:
old_values[v['id']] = v
else:
old_values[res['id']] = res
for res_id in old_values:
if not logged_uids or uid in logged_uids:
resource_name = pool.get(model_object.model).name_get(cr, uid, [res_id])
resource_name = resource_name and resource_name[0][1] or ''
id = pool.get('audittrail.log').create(cr, uid, {"method": method, "object_id": model_object.id, "user_id": uid, "res_id": res_id, "name": resource_name})
lines = []
for field in old_values[res_id]:
if old_values[res_id][field]:
line = {
'name': field,
'old_value': old_values[res_id][field],
'old_value_text': self.get_value_text(cr, uid, field, old_values[res_id][field], model_object)
}
lines.append(line)
cr.commit()
self.create_log_line(cr, uid, id, model_object, lines)
vals = {
"method": method,
"object_id": model.id,
"user_id": uid,
"res_id": res_id,
}
log_id = log_pool.create(cr, uid, vals)
lines = []
for field in old_values[res_id]:
line = {
'name': field,
'old_value': old_values[res_id][field],
'old_value_text': self.get_value_text(cr, uid, field, old_values[res_id][field], model)
}
lines.append(line)
self.create_log_line(cr, uid, log_id, model, lines)
cr.close()
return res
if method in ('unlink'):
elif method in ('unlink'):
res_ids = args[0]
old_values = {}
for res_id in res_ids:
old_values[res_id] = pool.get(model_object.model).read(cr, uid, res_id, [])
old_values[res_id] = resource_pool.read(cr, uid, res_id)
for res_id in res_ids:
if not logged_uids or uid in logged_uids:
resource_name = pool.get(model_object.model).name_get(cr, uid, [res_id])
resource_name = resource_name and resource_name[0][1] or ''
id = pool.get('audittrail.log').create(cr, uid, {"method": method, "object_id": model_object.id, "user_id": uid, "res_id": res_id, "name": resource_name})
lines = []
for field in old_values[res_id]:
if old_values[res_id][field]:
line = {
'name': field,
'old_value': old_values[res_id][field],
'old_value_text': self.get_value_text(cr, uid, field, old_values[res_id][field], model_object)
}
lines.append(line)
cr.commit()
self.create_log_line(cr, uid, id, model_object, lines)
res = fct_src(db, uid, object, method, *args)
vals = {
"method": method,
"object_id": model.id,
"user_id": uid,
"res_id": res_id,
}
log_id = log_pool.create(cr, uid, vals)
lines = []
for field in old_values[res_id]:
if field in ('id'):
continue
line = {
'name': field,
'old_value': old_values[res_id][field],
'old_value_text': self.get_value_text(cr, uid, field, old_values[res_id][field], model)
}
lines.append(line)
self.create_log_line(cr, uid, log_id, model, lines)
res = fct_src(db, uid, model.model, method, *args)
cr.commit()
cr.close()
return res
cr.close()
else:
res_ids = args[0]
old_values = {}
fields = []
if len(args)>1 and type(args[1]) == dict:
fields = args[1].keys()
if type(res_ids) in (long, int):
res_ids = [res_ids]
if res_ids:
for resource in resource_pool.read(cr, uid, res_ids):
resource_id = resource['id']
if 'id' in resource:
del resource['id']
old_values_text = {}
old_value = {}
for field in resource.keys():
old_value[field] = resource[field]
old_values_text[field] = self.get_value_text(cr, uid, field, resource[field], model)
old_values[resource_id] = {'text':old_values_text, 'value': old_value}
def execute(self, db, uid, object, method, *args, **kw):
res = fct_src(db, uid, model.model, method, *args)
cr.commit()
if res_ids:
for resource in resource_pool.read(cr, uid, res_ids):
resource_id = resource['id']
if 'id' in resource:
del resource['id']
vals = {
"method": method,
"object_id": model.id,
"user_id": uid,
"res_id": resource_id,
}
log_id = log_pool.create(cr, uid, vals)
lines = []
for field in resource.keys():
line = {
'name': field,
'new_value': resource[field],
'old_value': old_values[resource_id]['value'][field],
'new_value_text': self.get_value_text(cr, uid, field, resource[field], model),
'old_value_text': old_values[resource_id]['text'][field]
}
lines.append(line)
self.create_log_line(cr, uid, log_id, model, lines)
cr.commit()
cr.close()
return res
return True
def execute(self, db, uid, model, method, *args, **kw):
"""
Overrides Object Proxy execute method
@param db: the current database
@param uid: the current user’s ID for security checks,
@param object: Object who's values are being changed
@param method: method to log: create, read, write, unlink
@return: Returns result as per method of Object proxy
@param method: get any method and create log
@return: Returns result as per method of Object proxy
"""
pool = pooler.get_pool(db)
model_pool = pool.get('ir.model')
rule_pool = pool.get('audittrail.rule')
cr = pooler.get_db(db).cursor()
cr.autocommit(True)
logged_uids = []
fct_src = super(audittrail_objects_proxy, self).execute
def my_fct(db, uid, object, method, *args):
field = method
def my_fct(db, uid, model, method, *args):
rule = False
obj_ids = pool.get('ir.model').search(cr, uid, [('model', '=', object)])
for obj_name in pool.obj_list():
if obj_name == 'audittrail.rule':
model_ids = model_pool.search(cr, uid, [('model', '=', model)])
model_id = model_ids and model_ids[0] or False
for model_name in pool.obj_list():
if model_name == 'audittrail.rule':
rule = True
if not rule:
return fct_src(db, uid, object, method, *args)
if not obj_ids:
return fct_src(db, uid, object, method, *args)
rule_ids = pool.get('audittrail.rule').search(cr, uid, [('object_id', '=', obj_ids[0]), ('state', '=', 'subscribed')])
if not rule_ids:
return fct_src(db, uid, object, method, *args)
return fct_src(db, uid, model, method, *args)
if not model_id:
return fct_src(db, uid, model, method, *args)
for thisrule in pool.get('audittrail.rule').browse(cr, uid, rule_ids):
rule_ids = rule_pool.search(cr, uid, [('object_id', '=', model_id), ('state', '=', 'subscribed')])
if not rule_ids:
return fct_src(db, uid, model, method, *args)
for thisrule in rule_pool.browse(cr, uid, rule_ids):
for user in thisrule.user_id:
logged_uids.append(user.id)
if not logged_uids or uid in logged_uids:
if field in ('read', 'write', 'create', 'unlink'):
if getattr(thisrule, 'log_' + field):
return self.log_fct(db, uid, object, method, fct_src, *args)
return fct_src(db, uid, object, method, *args)
res = my_fct(db, uid, object, method, *args)
if method in ('read', 'write', 'create', 'unlink'):
if getattr(thisrule, 'log_' + method):
return self.log_fct(db, uid, model, method, fct_src, *args)
elif method not in ('default_get','read','fields_view_get','fields_get','search','search_count','name_search','name_get','get','request_get', 'get_sc', 'unlink', 'write', 'create'):
if thisrule.log_action:
return self.log_fct(db, uid, model, method, fct_src, *args)
return fct_src(db, uid, model, method, *args)
res = my_fct(db, uid, model, method, *args)
cr.close()
return res
def exec_workflow(self, db, uid, model, method, *args, **argv):
pool = pooler.get_pool(db)
cr = pooler.get_db(db).cursor()
cr.autocommit(True)
logged_uids = []
fct_src = super(audittrail_objects_proxy, self).exec_workflow
field = method
rule = False
model_pool = pool.get('ir.model')
rule_pool = pool.get('audittrail.rule')
model_ids = model_pool.search(cr, uid, [('model', '=', model)])
for obj_name in pool.obj_list():
if obj_name == 'audittrail.rule':
rule = True
if not rule:
cr.close()
return super(audittrail_objects_proxy, self).exec_workflow(db, uid, model, method, *args, **argv)
if not model_ids:
cr.close()
return super(audittrail_objects_proxy, self).exec_workflow(db, uid, model, method, *args, **argv)
rule_ids = rule_pool.search(cr, uid, [('object_id', 'in', model_ids), ('state', '=', 'subscribed')])
if not rule_ids:
cr.close()
return super(audittrail_objects_proxy, self).exec_workflow(db, uid, model, method, *args, **argv)
for thisrule in rule_pool.browse(cr, uid, rule_ids):
for user in thisrule.user_id:
logged_uids.append(user.id)
if not logged_uids or uid in logged_uids:
if thisrule.log_workflow:
cr.close()
return self.log_fct(db, uid, model, method, fct_src, *args)
cr.close()
return super(audittrail_objects_proxy, self).exec_workflow(db, uid, model, method, *args, **argv)
cr.close()
return True
audittrail_objects_proxy()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+18 -16
View File
@@ -12,12 +12,15 @@
<form string="AuditTrail Rule">
<field name="name" select="1" required="1"/>
<field name="object_id" select="1"/>
<field name="log_read" />
<field name="log_write" />
<field name="log_unlink" />
<field name="log_create" />
<field name="action_id" colspan="4" readonly="1"/>
<field name="user_id" select="1" colspan="4"/>
<field name="log_read"/>
<field name="log_write"/>
<field name="log_unlink"/>
<field name="log_create"/>
<field name="log_action"/>
<field name="log_workflow"/>
<separator string="Users (if User is not added then it will applicable for all users)" colspan="4" />
<field name="user_id" select="1" colspan="4" nolabel="1" />
<field name="action_id" colspan="4" readonly="1" groups="base.group_extended"/>
<field name="state" select="1" readonly="1" />
<group colspan="2" col="2">
<button string="Subscribe" name="subscribe"
@@ -42,6 +45,8 @@
<field name="log_write" />
<field name="log_unlink" />
<field name="log_create" />
<field name="log_action"/>
<field name="log_workflow"/>
<field name="state" />
</tree>
</field>
@@ -58,9 +63,10 @@
<!--<field name="view_id" ref="view_audittrail_rule_form" />-->
</record>
<menuitem name="Audittrails" id="menu_action_audittrail"
<menuitem name="Audittrail" id="menu_action_audittrail"
groups="base.group_extended"
parent="base.menu_administration" />
<menuitem name="Rules" id="menu_action_audittrail_rule_tree"
action="action_audittrail_rule_tree" parent="menu_action_audittrail" />
@@ -83,13 +89,13 @@
<field name="arch" type="xml">
<form string="AuditTrail Logs">
<field name="timestamp" select="1" required="1" readonly="1"/>
<field name="object_id" select="1" readonly="1"/>
<field name="method" select="1" readonly="1"/>
<field name="user_id" select="1" readonly="1"/>
<field name="res_id" readonly="1"/>
<field name="method" select="1" readonly="1"/>
<field name="name" readonly="1" select="1"/>
<field name="res_id" readonly="1"/>
<field name="object_id" select="1" readonly="1"/>
<field name="line_ids" colspan="4" mode="tree,form"
widget="one2many_list" readonly="1">
widget="one2many_list" readonly="1" nolabel="1">
<form string="Log Lines">
<field name="field_id" colspan="4"
readonly="1" />
@@ -151,11 +157,7 @@
<field name="view_type">form</field>
</record>
<menuitem name="Logs" id="menu_action_audittrail_log_tree"
action="action_audittrail_log_tree" parent="menu_action_audittrail" />
<!-- <wizard string="View log" menu="False" model="audittrail.log" name="audittrail.view.log" id="wizard_audittrail_log"/>-->
<menuitem name="View Logs" id="menu_action_log_tree2"
action="action_audittrail_view_log" parent="menu_action_audittrail" />
action="action_audittrail_log_tree" parent="menu_action_audittrail" />
</data>
</openerp>
+3 -1
View File
@@ -27,7 +27,9 @@
'author': 'Tiny',
'website': 'http://www.openerp.com',
'depends': ['base'],
'init_xml': [],
'init_xml': [
'base_action_rule_data.xml'
],
'update_xml': [
'base_action_rule_view.xml',
'security/ir.model.access.csv',
+99 -9
View File
@@ -19,14 +19,16 @@
#
##############################################################################
import time
import mx.DateTime
import re
import tools
from datetime import datetime
from osv import fields, osv, orm
from osv.orm import except_orm
from osv.osv import osv_pool
from tools.translate import _
import mx.DateTime
import pooler
import re
import time
import tools
class base_action_rule(osv.osv):
""" Base Action Rules """
@@ -132,6 +134,71 @@ the rule to mark CC(mail to any other person defined in actions)."),
_order = 'sequence'
def pre_action(self, cr, uid, ids, model, context=None):
# Searching for action rules
cr.execute("SELECT model.model, rule.id FROM base_action_rule rule LEFT JOIN ir_model model on (model.id = rule.name)")
res = cr.fetchall()
# Check if any rule matching with current object
for obj_name, rule_id in res:
if not (model == obj_name):
continue
else:
obj = self.pool.get(obj_name)
self._action(cr, uid, [rule_id], obj.browse(cr, uid, ids, context=context))
return True
def _create(self, old_create, model, context=None):
if not context:
context = {}
def make_call_old(cr, uid, vals, context=context):
new_id = old_create(cr, uid, vals, context=context)
if not context.get('action'):
self.pre_action(cr, uid, [new_id], model, context=context)
return new_id
return make_call_old
def _write(self, old_write, model, context=None):
if not context:
context = {}
def make_call_old(cr, uid, ids, vals, context=context):
if isinstance(ids, (str, int, long)):
ids = [ids]
if not context.get('action'):
self.pre_action(cr, uid, ids, model, context=context)
return old_write(cr, uid, ids, vals, context=context)
return make_call_old
def _register_hook(self, cr, uid, ids, context=None):
if not context:
context = {}
model_pool = self.pool.get('ir.model')
for action_rule in self.browse(cr, uid, ids, context=context):
model = action_rule.name.model
obj_pool = self.pool.get(model)
obj_pool.__setattr__('create', self._create(obj_pool.create, model, context=context))
obj_pool.__setattr__('write', self._write(obj_pool.write, model, context=context))
return True
def create(self, cr, uid, vals, context=None):
res_id = super(base_action_rule, self).create(cr, uid, vals, context)
self._register_hook(cr, uid, [res_id], context=context)
return res_id
def write(self, cr, uid, ids, vals, context=None):
res = super(base_action_rule, self).write(cr, uid, ids, vals, context)
self._register_hook(cr, uid, ids, context=context)
return res
def _check(self, cr, uid, automatic=False, use_new_cursor=False, \
context=None):
"""
This Function is call by scheduler.
"""
rule_pool= self.pool.get('base.action.rule')
rule_ids = rule_pool.search(cr, uid, [], context=context)
return self._register_hook(cr, uid, rule_ids, context=context)
def format_body(self, body):
""" Foramat Action rule's body
@param self: The object pointer """
@@ -235,6 +302,7 @@ the rule to mark CC(mail to any other person defined in actions)."),
context.update({'active_id':obj.id, 'active_ids':[obj.id]})
self.pool.get('ir.actions.server').run(cr, uid, [action.server_action_id.id], context)
write = {}
if hasattr(obj, 'user_id') and action.act_user_id:
obj.user_id = action.act_user_id
write['user_id'] = action.act_user_id.id
@@ -279,12 +347,10 @@ the rule to mark CC(mail to any other person defined in actions)."),
@param ids: List of Basic Action Rule’s IDs,
@param objects: pass objects
@param context: A standard dictionary for contextual values """
context.update({'action': True})
if not scrit:
scrit = []
cr.execute("select id from base_action_rule order by sequence")
rule_ids = map(lambda x: x[0], cr.fetchall())
for action in self.browse(cr, uid, rule_ids):
for action in self.browse(cr, uid, ids):
level = action.max_level
if not level:
break
@@ -333,6 +399,7 @@ the rule to mark CC(mail to any other person defined in actions)."),
self.do_action(cr, uid, action, model_obj, obj, context)
break
level -= 1
context.update({'action': False})
return True
def _check_mail(self, cr, uid, ids, context=None):
@@ -359,4 +426,27 @@ the rule to mark CC(mail to any other person defined in actions)."),
base_action_rule()
class ir_cron(osv.osv):
_inherit = 'ir.cron'
def _poolJobs(self, db_name, check=False):
try:
db, pool = pooler.get_db_and_pool(db_name)
except:
return False
cr = db.cursor()
try:
next = datetime.now().strftime('%Y-%m-%d %H:00:00')
# Putting nextcall always less than current time in order to call it every time
cr.execute('UPDATE ir_cron set nextcall = \'%s\' where numbercall<>0 and active and model=\'base.action.rule\' ' % (next))
cr.commit()
res = super(ir_cron, self)._poolJobs(db_name, check=check)
finally:
cr.commit()
cr.close()
ir_cron()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="1">
<record id="ir_cron_crm_action" model="ir.cron">
<field name="name">Check Action Rules</field>
<field name="interval_number">4</field>
<field name="interval_type">hours</field>
<field name="numbercall">-1</field>
<field eval="False" name="doall"/>
<field eval="'base.action.rule'" name="model"/>
<field eval="'_check'" name="function"/>
<field eval="'()'" name="args"/>
</record>
</data>
</openerp>
+2
View File
@@ -20,5 +20,7 @@
##############################################################################
import base_contact
import base_contact_installer
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+1
View File
@@ -45,6 +45,7 @@
'update_xml': [
'security/ir.model.access.csv',
'base_contact_view.xml',
'base_contact_installer_view.xml',
'process/base_contact_process.xml'
],
'demo_xml': ['base_contact_demo.xml'],
@@ -0,0 +1,66 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from lxml import etree
from osv import fields, osv
class base_contact_installer(osv.osv_memory):
_name = 'base.contact.installer'
_inherit = 'res.config.installer'
_columns = {
'name': fields.char('Name', size=64),
'migrate': fields.boolean('Migrate', help="If you select this, all addresses will be migrated."),
}
def execute(self, cr, uid, ids, context=None):
"""
This function is used to create contact and address from existing partner address
"""
cr.execute("""DROP TRIGGER IF EXISTS contactjob on res_partner_contact;
DROP LANGUAGE IF EXISTS plpgsql CASCADE;
CREATE LANGUAGE plpgsql ;
CREATE OR REPLACE FUNCTION add_to_job() RETURNS TRIGGER AS $contactjob$
DECLARE
new_name varchar;
new_phonenum varchar;
BEGIN
IF(TG_OP='INSERT') THEN
INSERT INTO res_partner_job(contact_id, address_id, function, state) VALUES(NEW.id, NEW.website::integer,NEW.first_name, 'current');
UPDATE res_partner_contact set first_name=Null, website=Null, active=True where id=NEW.id;
END IF;
RETURN NEW;
END;
$contactjob$ LANGUAGE plpgsql;
CREATE TRIGGER contactjob AFTER INSERT ON res_partner_contact FOR EACH ROW EXECUTE PROCEDURE add_to_job();""")
cr.commit()
cr.execute("INSERT into res_partner_contact (name, title, email, first_name, website) (SELECT coalesce(name, 'Noname'), title, email, function , to_char(id, '99999999') from res_partner_address)")
cr.commit()
cr.execute("DROP TRIGGER IF EXISTS contactjob on res_partner_contact")
cr.execute("DROP LANGUAGE IF EXISTS plpgsql CASCADE;")
cr.execute("DROP FUNCTION IF EXISTS add_to_job()")
cr.commit()
base_contact_installer()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
@@ -0,0 +1,56 @@
<openerp>
<data>
<record id="view_base_contact_installer" model="ir.ui.view">
<field name="name">base.contact.installer.view</field>
<field name="model">base.contact.installer</field>
<field name="type">form</field>
<field name="inherit_id" ref="base.res_config_installer"/>
<field name="arch" type="xml">
<data>
<form position="attributes">
<attribute name="string">Address's Migration to Contacts</attribute>
</form>
<separator string="title" position="attributes">
<attribute name="string">Select the Option for Addresses Migration</attribute>
</separator>
<xpath expr="//label[@string='description']"
position="attributes">
<attribute name="string">You can migrate Partner's current addresses to the contact.</attribute>
</xpath>
<xpath expr='//separator[@string="vsep"]' position='attributes'>
<attribute name='rowspan'>13</attribute>
<attribute name='string'></attribute>
</xpath>
<xpath expr="//button[@string='Install Modules']" position="attributes">
<attribute name="string">Migrate</attribute>
</xpath>
<group colspan="8">
<group colspan="2" col="2">
<label string="Due to changes in Address and Partner's relation, some of the details from address are needed to migrated into contact information." colspan="4"/>
<label string="Otherwise these details will not be visible from address/contact." colspan="4"/>
<label string="Do you want to migrate your Address data in Contact Data?" colspan="4" />
<field name="migrate" string="Yes/No" />
</group>
</group>
</data>
</field>
</record>
<record id="action_base_contact_installer" model="ir.actions.act_window">
<field name="name">Address Migration</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">base.contact.installer</field>
<field name="view_id" ref="view_base_contact_installer"/>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<record id="base_contact_installer_todo" model="ir.actions.todo">
<field name="action_id" ref="action_base_contact_installer"/>
<field name="sequence">3</field>
</record>
</data>
</openerp>
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
#
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
@@ -15,7 +15,7 @@
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
@@ -48,7 +48,7 @@ PEP-8 Test , copyright of py files check, method can not call from loops
list_files.append(os.path.join(i, j))
py_list = []
for file_py in list_files:
if file_py.split('.')[-1] == 'py' and not file_py.endswith('__init__.py') and not file_py.endswith('__terp__.py'):
if file_py.split('.')[-1] == 'py' and not file_py.endswith('__init__.py') and not file_py.endswith('__openerp__.py'):
file_path = os.path.join(module_path, file_py)
py_list.append(file_path)
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
#
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
@@ -15,7 +15,7 @@
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
@@ -50,7 +50,7 @@ class quality_test(base_module_quality.abstract_quality_check):
flag = False
self.result_details += '''<html><body><head>%s</head>'''%(self.get_style())
for file_py in list_files:
if file_py.split('.')[-1] == 'py' and not file_py.endswith('__init__.py') and not file_py.endswith('__terp__.py'):
if file_py.split('.')[-1] == 'py' and not file_py.endswith('__init__.py') and not file_py.endswith('__openerp__.py'):
if not flag:
flag = True
file_path = os.path.join(module_path, file_py)
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
#
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
@@ -15,7 +15,7 @@
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
@@ -82,7 +82,7 @@ This test checks if the module satisfy tiny structure
# module files calculation (module.py,module_view.xml,etc..)
com_list = ['_unit_test.xml', '.py', '_view.xml', '_workflow.xml' , '_wizard.xml', '_report.xml', '_data.xml', '_demo.xml', '_security.xml', '_sequence.xml', '_graph.xml']
com_list = map(lambda x: module_name + x, com_list)
main_file = ['__init__.py', '__terp__.py']
main_file = ['__init__.py', '__openerp__.py']
com_list.extend(main_file)
module_dict['module'] = filter(lambda x: len(x.split(".")) > 1, module_dict['module'])
score = self.get_score(module_dict['module'], com_list)
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
#
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
@@ -15,7 +15,7 @@
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
@@ -49,13 +49,13 @@ class quality_test(base_module_quality.abstract_quality_check):
score = 1.0
feel_good_factor = 0
feel_bad_factor = 0
if '__terp__.py' not in list_files:
if '__openerp__.py' not in list_files:
self.no_terp = True
self.result += _("The module does not contain the __terp__.py file")
self.result += _("The module does not contain the __openerp__.py file")
return None
result_dict = {}
result_dict1 = {}
terp_file = os.path.join(module_path,'__terp__.py')
terp_file = os.path.join(module_path,'__openerp__.py')
res = eval(tools.file_open(terp_file).read())
terp_keys = ['category', 'name', 'description', 'author', 'website', 'update_xml', 'init_xml', 'depends', 'version', 'active', 'installable', 'demo_xml']
for key in terp_keys:
@@ -117,7 +117,7 @@ class quality_test(base_module_quality.abstract_quality_check):
self.result_details += self.get_result_details(result_dict)
self.result_details += self.get_result_details(result_dict1)
return [_('__terp__.py file'), score]
return [_('__openerp__.py file'), score]
def run_test(self, cr, uid, module_path):
terp_score = self.run_test_terp(cr, uid, module_path)
@@ -125,7 +125,7 @@ class quality_test(base_module_quality.abstract_quality_check):
if self.score*100 < self.min_score:
self.message = 'Score is below than minimal score(%s%%)' % self.min_score
if terp_score:
self.result = self.get_result({'__terp__.py': terp_score})
self.result = self.get_result({'__openerp__.py': terp_score})
return None
def get_result(self, dict_terp):
@@ -144,4 +144,4 @@ class quality_test(base_module_quality.abstract_quality_check):
return res
return ""
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+3 -10
View File
@@ -32,16 +32,6 @@ class calendar_event_export(osv.osv_memory):
"""
Export Calendar Event.
"""
def process_export_ics(self, cr, uid, ids, context):
"""
Get Default value for file_path field.
"""
model = context.get('model', 'basic.calendar')
model_obj = self.pool.get(model)
calendar = model_obj.export_cal(cr, uid, context['active_ids'], context)
self.write(cr, uid, ids, {'file_path': base64.encodestring(calendar)})
return False
def default_get(self, cr, uid, fields, context):
"""
@@ -54,6 +44,9 @@ class calendar_event_export(osv.osv_memory):
name = 'OpenERP %s.ics' % (model_obj._description)
if 'name' in fields:
res.update({'name': name})
if 'file_path' in fields:
calendar = model_obj.export_cal(cr, uid, context['active_ids'], context)
res.update({'file_path': base64.encodestring(calendar)})
return res
_name = "calendar.event.export"
@@ -13,8 +13,8 @@
</group>
<separator string="" colspan="4" />
<group colspan="4" col="6">
<button name="process_export_ics" icon="gtk-execute" string="Genetate ics" type="object"/>
<button icon="gtk-cancel" special="cancel" string="_Cancel"/>
<label string=""/>
<button icon="gtk-close" special="cancel" string="_Close"/>
</group>
</form>
</field>
-1
View File
@@ -69,7 +69,6 @@ Create dashboard for CRM that includes:
'crm_opportunity_data.xml',
'crm_phonecall_data.xml',
],
'update_xml': [
'wizard/crm_lead_to_partner_view.xml',
'wizard/crm_lead_to_opportunity_view.xml',
-13
View File
@@ -5,18 +5,5 @@
<field name="name">Sales Department</field>
<field name="code">Sales</field>
</record>
<record id="ir_cron_crm_action" model="ir.cron">
<field name="name">Check cases rules</field>
<field name="interval_number">4</field>
<field name="interval_type">hours</field>
<field name="numbercall">-1</field>
<field eval="False" name="doall"/>
<field eval="'crm.case'" name="model"/>
<field eval="'_check'" name="function"/>
<field eval="'()'" name="args"/>
</record>
</data>
</openerp>
+3 -4
View File
@@ -30,12 +30,10 @@ from crm import crm_case
class crm_lead(osv.osv, crm_case):
""" CRM Lead Case """
_name = "crm.lead"
_description = "Lead"
_order = "priority, id desc"
_inherit = ['res.partner.address']
_inherits = {'mailgate.thread': 'thread_id'}
_inherit = ['mailgate.thread','res.partner.address']
def _compute_day(self, cr, uid, ids, fields, args, context={}):
"""
@@ -112,7 +110,6 @@ and users by email"),
'write_date': fields.datetime('Update Date' , readonly=True),
# Lead fields
'thread_id': fields.many2one('mailgate.thread', 'Thread', required=False),
'categ_id': fields.many2one('crm.case.categ', 'Lead Source', \
domain="[('section_id','=',section_id),\
('object_id.model', '=', 'crm.lead')]"),
@@ -142,6 +139,8 @@ and users by email"),
\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=[('history', '=', True),('res_model','=',_name)]),
'log_ids': fields.one2many('mailgate.message', 'res_id', 'Logs', domain=[('history', '=', False),('res_model','=',_name)]),
}
_defaults = {
+1 -2
View File
@@ -38,9 +38,8 @@ from tools import command_re
class mailgate_thread(osv.osv):
""" mailgate_thread """
_name = "mailgate.thread"
_inherit = "mailgate.thread"
_inherit = "mailgate.thread"
def message_new(self, cr, uid, msg, context):
"""
+3 -4
View File
@@ -43,9 +43,7 @@ class crm_meeting(osv.osv, crm_case):
_name = 'crm.meeting'
_description = "Meeting"
_order = "id desc"
_inherit = ["calendar.event"]
_inherits = {'mailgate.thread': 'thread_id'}
_inherit = ['mailgate.thread',"calendar.event"]
_columns = {
# From crm.case
'name': fields.char('Summary', size=124, required=True),
@@ -59,7 +57,6 @@ class crm_meeting(osv.osv, crm_case):
'id': fields.integer('ID'),
# Meeting fields
'thread_id': fields.many2one('mailgate.thread', 'Thread', required=False),
'categ_id': fields.many2one('crm.case.categ', 'Meeting Type', \
domain="[('object_id.model', '=', 'crm.meeting')]", \
),
@@ -69,6 +66,8 @@ class crm_meeting(osv.osv, crm_case):
'event_id', 'attendee_id', 'Attendees'),
'date_closed': fields.datetime('Closed', readonly=True),
'date_deadline': fields.datetime('Deadline'),
'message_ids': fields.one2many('mailgate.message', 'res_id', 'Messages', domain=[('history', '=', True),('res_model','=',_name)]),
'log_ids': fields.one2many('mailgate.message', 'res_id', 'Logs', domain=[('history', '=', False),('res_model','=',_name)]),
'state': fields.selection([('open', 'Confirmed'),
('draft', 'Unconfirmed'),
('cancel', 'Cancelled'),
+3 -3
View File
@@ -31,13 +31,11 @@ class crm_phonecall(osv.osv, crm_case):
_name = "crm.phonecall"
_description = "Phonecall"
_order = "id desc"
_inherits = {'mailgate.thread': 'thread_id'}
_inherit = ['mailgate.thread']
_columns = {
# From crm.case
'name': fields.char('Name', size=64),
'active': fields.boolean('Active', required=False),
'thread_id': fields.many2one('mailgate.thread', 'Thread', required=False),
'date_action_last': fields.datetime('Last Action', readonly=1),
'date_action_next': fields.datetime('Next Action', readonly=1),
'create_date': fields.datetime('Creation Date' , readonly=True),
@@ -84,6 +82,8 @@ class crm_phonecall(osv.osv, crm_case):
'date_closed': fields.datetime('Closed', readonly=True),
'date': fields.datetime('Date'),
'opportunity_id': fields.many2one ('crm.lead', 'Opportunity'),
'message_ids': fields.one2many('mailgate.message', 'res_id', 'Messages', domain=[('history', '=', True),('res_model','=',_name)]),
'log_ids': fields.one2many('mailgate.message', 'res_id', 'Logs', domain=[('history', '=', False),('res_model','=',_name)]),
}
_defaults = {
@@ -1,91 +1,87 @@
<?xml version="1.0" ?>
<openerp>
<data>
<data>
<!--
Process
-->
<!--
Process
-->
<record id="process_process_contractprocess0" model="process.process">
<field eval="1" name="active"/>
<field name="model_id" ref="mail_gateway.model_mailgate_thread"/>
<field eval="&quot;&quot;&quot;Contract&quot;&quot;&quot;" name="name"/>
</record>
<field eval="1" name="active"/>
<field eval="&quot;&quot;&quot;Contract&quot;&quot;&quot;" name="name"/>
</record>
<!--
Process Node
-->
<!--
Process Node
-->
<record id="process_node_leads0" model="process.node">
<field name="model_id" ref="mail_gateway.model_mailgate_thread"/>
<field eval="&quot;&quot;&quot;state&quot;&quot;&quot;" name="kind"/>
<field eval="&quot;&quot;&quot;Leads&quot;&quot;&quot;" name="name"/>
<field eval="&quot;&quot;&quot;Very first contact with new prospect&quot;&quot;&quot;" name="note"/>
<field name="process_id" ref="process_process_contractprocess0"/>
<field eval="&quot;&quot;&quot;object.state in ('draft', 'open', 'pending', 'done', 'cancel')&quot;&quot;&quot;" name="model_states"/>
<field eval="1" name="flow_start"/>
</record>
<record id="process_node_leads0" model="process.node">
<field eval="&quot;&quot;&quot;state&quot;&quot;&quot;" name="kind"/>
<field eval="&quot;&quot;&quot;Leads&quot;&quot;&quot;" name="name"/>
<field eval="&quot;&quot;&quot;Very first contact with new prospect&quot;&quot;&quot;" name="note"/>
<field name="process_id" ref="process_process_contractprocess0"/>
<field eval="&quot;&quot;&quot;object.state in ('draft', 'open', 'pending', 'done', 'cancel')&quot;&quot;&quot;" name="model_states"/>
<field eval="1" name="flow_start"/>
</record>
<record id="process_node_partner0" model="process.node">
<field name="menu_id" ref="base.menu_partner_form"/>
<field name="model_id" ref="base.model_res_partner"/>
<field eval="&quot;&quot;&quot;state&quot;&quot;&quot;" name="kind"/>
<field eval="&quot;&quot;&quot;Partner&quot;&quot;&quot;" name="name"/>
<field eval="&quot;&quot;&quot;Convert to prospect to business partner&quot;&quot;&quot;" name="note"/>
<field name="process_id" ref="process_process_contractprocess0"/>
<field eval="0" name="flow_start"/>
</record>
<record id="process_node_partner0" model="process.node">
<field name="menu_id" ref="base.menu_partner_form"/>
<field name="model_id" ref="base.model_res_partner"/>
<field eval="&quot;&quot;&quot;state&quot;&quot;&quot;" name="kind"/>
<field eval="&quot;&quot;&quot;Partner&quot;&quot;&quot;" name="name"/>
<field eval="&quot;&quot;&quot;Convert to prospect to business partner&quot;&quot;&quot;" name="note"/>
<field name="process_id" ref="process_process_contractprocess0"/>
<field eval="0" name="flow_start"/>
</record>
<record id="process_node_opportunities0" model="process.node">
<field name="model_id" ref="mail_gateway.model_mailgate_thread"/>
<field eval="&quot;&quot;&quot;state&quot;&quot;&quot;" name="kind"/>
<field eval="&quot;&quot;&quot;Opportunities&quot;&quot;&quot;" name="name"/>
<field eval="&quot;&quot;&quot;When a real project/opportunity is detected&quot;&quot;&quot;" name="note"/>
<field name="process_id" ref="process_process_contractprocess0"/>
<field eval="&quot;&quot;&quot;object.state in ('draft', 'open', 'pending', 'done', 'cancel')&quot;&quot;&quot;" name="model_states"/>
<field eval="0" name="flow_start"/>
</record>
<record id="process_node_opportunities0" model="process.node">
<field eval="&quot;&quot;&quot;state&quot;&quot;&quot;" name="kind"/>
<field eval="&quot;&quot;&quot;Opportunities&quot;&quot;&quot;" name="name"/>
<field eval="&quot;&quot;&quot;When a real project/opportunity is detected&quot;&quot;&quot;" name="note"/>
<field name="process_id" ref="process_process_contractprocess0"/>
<field eval="&quot;&quot;&quot;object.state in ('draft', 'open', 'pending', 'done', 'cancel')&quot;&quot;&quot;" name="model_states"/>
<field eval="0" name="flow_start"/>
</record>
<record id="process_node_meeting0" model="process.node">
<field name="model_id" ref="mail_gateway.model_mailgate_thread"/>
<field eval="&quot;&quot;&quot;state&quot;&quot;&quot;" name="kind"/>
<field eval="&quot;&quot;&quot;Meeting&quot;&quot;&quot;" name="name"/>
<field eval="&quot;&quot;&quot;Schedule a normal or phone meeting&quot;&quot;&quot;" name="note"/>
<field name="process_id" ref="process_process_contractprocess0"/>
<field eval="&quot;&quot;&quot;object.state in ('draft', 'open', 'pending', 'done', 'cancel')&quot;&quot;&quot;" name="model_states"/>
<field eval="0" name="flow_start"/>
</record>
<record id="process_node_meeting0" model="process.node">
<field eval="&quot;&quot;&quot;state&quot;&quot;&quot;" name="kind"/>
<field eval="&quot;&quot;&quot;Meeting&quot;&quot;&quot;" name="name"/>
<field eval="&quot;&quot;&quot;Schedule a normal or phone meeting&quot;&quot;&quot;" name="note"/>
<field name="process_id" ref="process_process_contractprocess0"/>
<field eval="&quot;&quot;&quot;object.state in ('draft', 'open', 'pending', 'done', 'cancel')&quot;&quot;&quot;" name="model_states"/>
<field eval="0" name="flow_start"/>
</record>
<!--
Process Transition
-->
<!--
Process Transition
-->
<record id="process_transition_leadopportunity0" model="process.transition">
<field eval="[(6,0,[])]" name="role_ids"/>
<field eval="[(6,0,[])]" name="transition_ids"/>
<field eval="&quot;&quot;&quot;Prospect Opportunity&quot;&quot;&quot;" name="name"/>
<field eval="&quot;&quot;&quot;Creating business opportunities from Leads&quot;&quot;&quot;" name="note"/>
<field model="process.node" name="target_node_id" ref="process_node_opportunities0"/>
<field model="process.node" name="source_node_id" ref="process_node_leads0"/>
</record>
<record id="process_transition_leadopportunity0" model="process.transition">
<field eval="[(6,0,[])]" name="role_ids"/>
<field eval="[(6,0,[])]" name="transition_ids"/>
<field eval="&quot;&quot;&quot;Prospect Opportunity&quot;&quot;&quot;" name="name"/>
<field eval="&quot;&quot;&quot;Creating business opportunities from Leads&quot;&quot;&quot;" name="note"/>
<field model="process.node" name="target_node_id" ref="process_node_opportunities0"/>
<field model="process.node" name="source_node_id" ref="process_node_leads0"/>
</record>
<record id="process_transition_leadpartner0" model="process.transition">
<field eval="[(6,0,[])]" name="role_ids"/>
<field eval="[(6,0,[])]" name="transition_ids"/>
<field eval="&quot;&quot;&quot;Prospect Partner&quot;&quot;&quot;" name="name"/>
<field eval="&quot;&quot;&quot;Prospect is converting to business partner&quot;&quot;&quot;" name="note"/>
<field model="process.node" name="target_node_id" ref="process_node_partner0"/>
<field model="process.node" name="source_node_id" ref="process_node_leads0"/>
</record>
<record id="process_transition_leadpartner0" model="process.transition">
<field eval="[(6,0,[])]" name="role_ids"/>
<field eval="[(6,0,[])]" name="transition_ids"/>
<field eval="&quot;&quot;&quot;Prospect Partner&quot;&quot;&quot;" name="name"/>
<field eval="&quot;&quot;&quot;Prospect is converting to business partner&quot;&quot;&quot;" name="note"/>
<field model="process.node" name="target_node_id" ref="process_node_partner0"/>
<field model="process.node" name="source_node_id" ref="process_node_leads0"/>
</record>
<record id="process_transition_opportunitymeeting0" model="process.transition">
<field eval="[(6,0,[])]" name="role_ids"/>
<field eval="[(6,0,[])]" name="transition_ids"/>
<field eval="&quot;&quot;&quot;Opportunity Meeting&quot;&quot;&quot;" name="name"/>
<field eval="&quot;&quot;&quot;Normal or phone meeting for opportunity&quot;&quot;&quot;" name="note"/>
<field model="process.node" name="target_node_id" ref="process_node_meeting0"/>
<field model="process.node" name="source_node_id" ref="process_node_opportunities0"/>
</record>
<record id="process_transition_opportunitymeeting0" model="process.transition">
<field eval="[(6,0,[])]" name="role_ids"/>
<field eval="[(6,0,[])]" name="transition_ids"/>
<field eval="&quot;&quot;&quot;Opportunity Meeting&quot;&quot;&quot;" name="name"/>
<field eval="&quot;&quot;&quot;Normal or phone meeting for opportunity&quot;&quot;&quot;" name="note"/>
<field model="process.node" name="target_node_id" ref="process_node_meeting0"/>
<field model="process.node" name="source_node_id" ref="process_node_opportunities0"/>
</record>
</data>
</openerp>
</data>
</openerp>
+1 -2
View File
@@ -109,7 +109,6 @@ class crm_lead_report(osv.osv):
'date_closed': fields.date('Close Date', readonly=True),
'company_id': fields.many2one('res.company', 'Company', readonly=True),
'priority': fields.selection(crm.AVAILABLE_PRIORITIES, 'Priority'),
'type':fields.selection([
('lead','Lead'),
('opportunity','Opportunity'),
@@ -148,7 +147,7 @@ class crm_lead_report(osv.osv):
0 as avg_answers,
0.0 as perc_done,
0.0 as perc_cancel,
(select count(id) from mailgate_message where thread_id=c.id) as email,
(select count(id) from mailgate_message where res_id=c.id and res_model='crm.lead') as email,
date_trunc('day',c.create_date) as create_date,
avg(extract('epoch' from (c.date_closed-c.create_date)))/(3600*24) as delay_close,
avg(extract('epoch' from (c.date_deadline - c.date_closed)))/(3600*24) as delay_expected,
+6 -17
View File
@@ -185,23 +185,12 @@ class crm_lead_forward_to_partner(osv.osv_memory):
email_from = this.email_from or False
case_pool._history(cr, uid, [case], _('Forward'), history=True, email=this.email_to, details=body, email_from=email_from)
flag = False
if case.section_id and case.section_id.server_id:
flag = smtp_pool.send_email(
cr=cr,
uid=uid,
server_id=case.section_id.server_id.id,
emailto=emails,
subject=this.subject,
body="<pre>%s</pre>" % body,
)
else:
flag = tools.email_send(
email_from,
emails,
this.subject,
body,
)
flag = tools.email_send(
email_from,
emails,
this.subject,
body,
)
if this.add_cc:
case_pool.write(cr, uid, case.id, {'email_cc' : case.email_cc and case.email_cc + ', ' + this.email_to or this.email_to})
return {}
+7 -10
View File
@@ -96,11 +96,10 @@ class crm_send_new_email(osv.osv_memory):
else:
hist = hist_obj.browse(cr, uid, res_id)
message_id = hist.message_id
model = hist.model_id.model
model = hist.res_model
model_pool = self.pool.get(model)
res_ids = model_pool.search(cr, uid, [('thread_id','=', hist.thread_id.id)])
res_id = res_ids and res_ids[0] or False
case = model_pool.browse(cr, uid, res_id)
case = model_pool.browse(cr, uid, hist.res_id)
res_id = hist.res_id
emails = [obj.email_to] + (obj.email_cc or '').split(',')
emails = filter(None, emails)
body = obj.text
@@ -120,15 +119,14 @@ class crm_send_new_email(osv.osv_memory):
if message_id:
x_headers['References'] = "%s" % (message_id)
flag = False
print case.section_id
flag = tools.email_send(
email_from,
emails,
obj.subject,
body,
attach=attach,
reply_to=case.section_id.reply_to,
reply_to=case.section_id and case.section_id.reply_to or email_from,
openobject_id=str(case.id),
x_headers=x_headers
)
@@ -196,15 +194,14 @@ class crm_send_new_email(osv.osv_memory):
include_original = context and context.get('include_original', False) or False
res = {}
for hist in hist_obj.browse(cr, uid, res_ids, context=context):
model = hist.model_id.model
model = hist.res_model
# In the case where the crm.case does not exist in the database
if not model:
return {}
model_pool = self.pool.get(model)
res_ids = model_pool.search(cr, uid, [('thread_id','=', hist.thread_id.id)])
res_id = res_ids and res_ids[0] or False
res_id = hist.res_id or False
case = model_pool.browse(cr, uid, res_id)
if 'email_to' in fields:
res.update({'email_to': case.email_from or hist.email_from or False})
+8 -6
View File
@@ -9,13 +9,15 @@
<field name="model">crm.send.mail</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Send New Mail" col="2">
<separator string="Send New Mail" colspan="2"/>
<form string="Send New Mail" col="4">
<separator string="Send New Mail" colspan="4"/>
<group colspan="4" col="6">
<field name="email_from" />
<field name="email_to" />
<field name="email_cc" />
<field name="subject" />
<notebook colspan="2">
<field name="subject" colspan="6"/>
</group>
<notebook colspan="6">
<page string="Message">
<field name="text" nolabel="1" colspan="4"/>
</page>
@@ -31,8 +33,8 @@
</field>
</page>
</notebook>
<separator string="" colspan="2"/>
<group colspan="2" col="4" >
<separator string="" colspan="6"/>
<group colspan="6" col="4" >
<field name="state" />
<button name="action_cancel" string="_Cancel" icon="gtk-cancel" special="cancel" />
<button name="action_send" type="object" string="_Send" icon="gtk-go-forward" />
+3 -3
View File
@@ -29,10 +29,8 @@ class crm_claim(osv.osv, crm.crm_case):
_name = "crm.claim"
_description = "Claim Cases"
_order = "id desc"
_inherits = {'mailgate.thread': 'thread_id'}
_inherit = ['mailgate.thread']
_columns = {
'thread_id': fields.many2one('mailgate.thread', 'Thread', required=False),
'id': fields.integer('ID', readonly=True),
'name': fields.char('Name', size=128, required=True),
'active': fields.boolean('Active', required=False),
@@ -90,6 +88,8 @@ class crm_claim(osv.osv, crm.crm_case):
\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=[('history', '=', True),('res_model','=',_name)]),
'log_ids': fields.one2many('mailgate.message', 'res_id', 'Logs', domain=[('history', '=', False),('res_model','=',_name)]),
}
_defaults = {
+3 -3
View File
@@ -28,10 +28,8 @@ class crm_fundraising(osv.osv, crm.crm_case):
_name = "crm.fundraising"
_description = "Fund Raising Cases"
_order = "id desc"
_inherits = {'mailgate.thread': 'thread_id'}
_inherit = ['mailgate.thread']
_columns = {
'thread_id': fields.many2one('mailgate.thread', 'Thread', required=False),
'id': fields.integer('ID'),
'name': fields.char('Name', size=128, required=True),
'active': fields.boolean('Active', required=False),
@@ -87,6 +85,8 @@ class crm_fundraising(osv.osv, crm.crm_case):
\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=[('history', '=', True),('res_model','=',_name)]),
'log_ids': fields.one2many('mailgate.message', 'res_id', 'Logs', domain=[('history', '=', False),('res_model','=',_name)]),
}
_defaults = {
+1 -3
View File
@@ -28,10 +28,8 @@ class crm_helpdesk(osv.osv, crm.crm_case):
_name = "crm.helpdesk"
_description = "Helpdesk Cases"
_order = "id desc"
_inherits = {'mailgate.thread': 'thread_id'}
_inherit = ['mailgate.thread']
_columns = {
'thread_id': fields.many2one('mailgate.thread', 'Thread', required=False),
'id': fields.integer('ID', readonly=True),
'name': fields.char('Name', size=128, required=True),
'active': fields.boolean('Active', required=False),
+1 -1
View File
@@ -149,7 +149,7 @@ class delivery_grid_line(osv.osv):
'name': fields.char('Name', size=32, required=True),
'grid_id': fields.many2one('delivery.grid', 'Grid',required=True),
'type': fields.selection([('weight','Weight'),('volume','Volume'),('wv','Weight * Volume'), ('price','Price')], 'Variable', required=True),
'operator': fields.selection([('=','='),('<=','<='),('>=','>=')], 'Operator', required=True),
'operator': fields.selection([('==','='),('<=','<='),('>=','>=')], 'Operator', required=True),
'max_value': fields.float('Maximum Value', required=True),
'price_type': fields.selection([('fixed','Fixed'),('variable','Variable')], 'Price Type', required=True),
'variable_factor': fields.selection([('weight','Weight'),('volume','Volume'),('wv','Weight * Volume'), ('price','Price')], 'Variable Factor', required=True),
+3 -3
View File
@@ -57,11 +57,11 @@ class hr_applicant(osv.osv, crm.crm_case):
_name = "hr.applicant"
_description = "Applicant"
_order = "id desc"
_inherits = {'mailgate.thread': 'thread_id'}
_inherit = ['mailgate.thread']
_columns = {
'thread_id': fields.many2one('mailgate.thread', 'Thread', required=False),
'name': fields.char('Name', size=128, required=True),
'message_ids': fields.one2many('mailgate.message', 'res_id', 'Messages', domain=[('history', '=', True),('res_model','=',_name)]),
'log_ids': fields.one2many('mailgate.message', 'res_id', 'Logs', domain=[('history', '=', False),('res_model','=',_name)]),
'active': fields.boolean('Active', help="If the active field is set to false, it will allow you to hide the case without removing it."),
'description': fields.text('Description'),
'section_id': fields.many2one('crm.case.section', 'Sales Team', \
+8 -23
View File
@@ -30,14 +30,10 @@ class mailgate_thread(osv.osv):
'''
_name = 'mailgate.thread'
_description = 'Mailgateway Thread'
_rec_name = 'thread'
_columns = {
'thread': fields.char('Thread', size=32, required=False),
'message_ids': fields.one2many('mailgate.message', 'thread_id', 'Messages', domain=[('history', '=', True)], required=False),
'log_ids': fields.one2many('mailgate.message', 'thread_id', 'Logs', domain=[('history', '=', False)], required=False),
'message_ids': fields.one2many('mailgate.message', 'res_id', 'Messages', domain=[('history', '=', True)]),
'log_ids': fields.one2many('mailgate.message', 'res_id', 'Logs', domain=[('history', '=', False)]),
}
def _history(self, cr, uid, cases, keyword, history=False, subject=None, email=False, details=None, email_from=False, message_id=False, attach=None, context=None):
"""
@param self: The object pointer
@@ -60,18 +56,16 @@ class mailgate_thread(osv.osv):
if all(isinstance(case_id, (int, long)) for case_id in cases):
cases = self.browse(cr, uid, cases, context=context)
model_obj = self.pool.get('ir.model')
att_obj = self.pool.get('ir.attachment')
obj = self.pool.get('mailgate.message')
for case in cases:
model_ids = model_obj.search(cr, uid, [('model', '=', case._name)])
data = {
'name': keyword,
'user_id': uid,
'model_id' : model_ids and model_ids[0] or False,
'res_model' : case._name,
'res_id': case.id,
'date': time.strftime('%Y-%m-%d %H:%M:%S'),
'thread_id': case.thread_id.id,
'message_id': message_id,
}
attachments = []
@@ -83,7 +77,7 @@ class mailgate_thread(osv.osv):
'name': subject or 'History',
'history': True,
'user_id': uid,
'model_id' : model_ids and model_ids[0] or False,
'res_model' : case._name,
'res_id': case.id,
'date': time.strftime('%Y-%m-%d %H:%M:%S'),
'description': details or (hasattr(case, 'description') and case.description or False),
@@ -94,16 +88,11 @@ class mailgate_thread(osv.osv):
(hasattr(case, 'user_id') and case.user_id and case.user_id.address_id and \
case.user_id.address_id.email) or tools.config.get('email_from', False),
'partner_id': hasattr(case, 'partner_id') and (case.partner_id and case.partner_id.id or False) or False,
'thread_id': case.thread_id.id,
'message_id': message_id,
'attachment_ids': [(6, 0, attachments)]
}
res = obj.create(cr, uid, data, context)
return True
__history = history = _history
mailgate_thread()
class mailgate_message(osv.osv):
@@ -112,15 +101,13 @@ class mailgate_message(osv.osv):
'''
_name = 'mailgate.message'
_description = 'Mailgateway Message'
_order = 'date desc'
_order = 'id desc'
_columns = {
'name':fields.char('Message', size=64),
'model_id': fields.many2one('ir.model', 'Model'),
'res_model': fields.char('Object Name', size=128),
'res_id': fields.integer('Resource ID'),
'thread_id':fields.many2one('mailgate.thread', 'Thread'),
'date': fields.datetime('Date'),
'history': fields.boolean('Is History?', required=False),
'history': fields.boolean('Is History?'),
'user_id': fields.many2one('res.users', 'User Responsible', readonly=True),
'message': fields.text('Description'),
'email_from': fields.char('Email From', size=84),
@@ -135,5 +122,3 @@ class mailgate_message(osv.osv):
mailgate_message()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
@@ -127,13 +127,11 @@ class rpc_proxy(object):
return self.rpc.execute(self.dbname, self.user_id, self.passwd, *request, **kwargs)
class email_parser(object):
def __init__(self, uid, password, model, email, email_default, dbname, host, port):
def __init__(self, uid, password, model, email, email_default, dbname, host, port):
self.rpc = rpc_proxy(uid, password, host=host, port=port, dbname=dbname)
try:
self.model_id = int(model)
self.model = str(model)
except:
self.model_id = self.rpc('ir.model', 'search', [('model', '=', model)])[0]
self.model = str(model)
self.email = email
self.email_default = email_default
@@ -188,7 +186,7 @@ class email_parser(object):
values = {
'message_ids' : [
(0, 0, {
'model_id' : self.rpc('ir.model', 'search', [('name', '=', self.model)])[0],
'res_model' : self.model,
'date' : time.strftime('%Y-%m-%d %H:%M:%S'),
'description' : message['body'],
'email_from' : msg_from,
@@ -200,8 +198,6 @@ class email_parser(object):
)
]
}
thread_id = self.rpc('mailgate.thread', 'create', values)
data['thread_id'] = thread_id
oid = self.rpc(self.model, 'create', data)
attachments = message['attachment']
@@ -216,7 +212,7 @@ class email_parser(object):
}
self.rpc('ir.attachment', 'create', data_attach)
return (oid, thread_id,)
return (oid, )
def msg_body_get(self, msg):
message = {
@@ -320,8 +316,7 @@ class email_parser(object):
> create_message(id, msg['From'], msg['To'], 'Send', message['body'])
"""
values = {
'thread_id' : self.rpc(self.model, 'read', [oid], ['thread_id'])[0]['thread_id'][0],
'model_id' : self.rpc('ir.model', 'search', [('name', '=', self.model)])[0],
'res_model' : self.model,
'res_id' : oid,
'date' : time.strftime('%Y-%m-%d %H:%M:%S'),
'description' : body,
@@ -390,13 +385,7 @@ class email_parser(object):
logging.info("email: %s -> %s -- %s", msg['From'], self.email, msg['Subject'])
(case_id, emails) = self.msg_test(msg, case_str)
thread_id = None
if case_id:
values = self.rpc(self.model, 'read', [case_id], ['thread_id'])
if values:
thread_id = values[0]['thread_id'][0]
emails = emails[str(thread_id)]
user_email = filter(None, emails['user_email'])[0]
if user_email and self.email_get(user_email) == self.email_get(self._decode_header(msg['From'])):
@@ -404,13 +393,12 @@ class email_parser(object):
else:
self.msg_partner(msg, case_id)
else:
case_id, thread_id = self.msg_new(msg)
case_id = self.msg_new(msg)
subject = self._decode_header(msg['Subject'])
msg['Subject'] = "[%s] %s" % (case_id, subject,)
msg['Message-Id'] = "<%s-openerpcrm-%s@%s>" % (time.time(), case_id, socket.gethostname(),)
logging.info(" case: %r", case_id)
logging.info(" thread: %r", thread_id)
values = self.rpc(self.model, 'emails_get', [case_id])
@@ -431,7 +419,7 @@ class email_parser(object):
a = self._decode_header(msg['Subject'])
msg['Subject'] = '[OpenERP-CaseError] ' + a
self.msg_send(msg, self.email_default.split(','))
return case_id, thread_id, emails
return case_id, emails
if __name__ == '__main__':
parser = optparse.OptionParser(usage='usage: %prog [options]', version='%prog v1.0')
+5 -5
View File
@@ -28,11 +28,11 @@ class company(osv.osv):
help="This is the time frame analysed by the scheduler when "\
"computing procurements. All procurements that are not between "\
"today and today+range are skipped for futur computation."),
}
}
_defaults = {
'schedule_range': lambda *a: 80.0,
}
'schedule_range': 80.0,
}
company()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+9 -9
View File
@@ -464,7 +464,7 @@ class stock_warehouse_orderpoint(osv.osv):
"""
_name = "stock.warehouse.orderpoint"
_description = "Minimum Inventory Rule"
_columns = {
'name': fields.char('Name', size=32, required=True),
'active': fields.boolean('Active', help="If the active field is set to true, it will allow you to hide the orderpoint without removing it."),
@@ -485,17 +485,17 @@ class stock_warehouse_orderpoint(osv.osv):
'company_id': fields.many2one('res.company','Company',required=True),
}
_defaults = {
'active': lambda *a: 1,
'logic': lambda *a: 'max',
'qty_multiple': lambda *a: 1,
'active': 1,
'logic': 'max',
'qty_multiple': 1,
'name': lambda x,y,z,c: x.pool.get('ir.sequence').get(y,z,'stock.orderpoint') or '',
'product_uom': lambda sel, cr, uid, context: context.get('product_uom', False),
'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'stock.warehouse.orderpoint', context=c)
}
_sql_constraints = [
('qty_multiple_check', 'CHECK( qty_multiple > 0 )', _('Qty Multiple must be greater than zero.')),
]
]
def onchange_warehouse_id(self, cr, uid, ids, warehouse_id, context={}):
""" Finds location id for changed warehouse.
@param warehouse_id: Changed id of warehouse.
@@ -506,7 +506,7 @@ class stock_warehouse_orderpoint(osv.osv):
v = {'location_id': w.lot_stock_id.id}
return {'value': v}
return {}
def onchange_product_id(self, cr, uid, ids, product_id, context={}):
""" Finds UoM for changed product.
@param product_id: Changed id of product.
@@ -517,7 +517,7 @@ class stock_warehouse_orderpoint(osv.osv):
v = {'product_uom': prod.uom_id.id}
return {'value': v}
return {}
def copy(self, cr, uid, id, default=None,context={}):
if not default:
default = {}
@@ -525,6 +525,6 @@ class stock_warehouse_orderpoint(osv.osv):
'name': self.pool.get('ir.sequence').get(cr, uid, 'stock.orderpoint') or '',
})
return super(stock_warehouse_orderpoint, self).copy(cr, uid, id, default, context)
stock_warehouse_orderpoint()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+7 -6
View File
@@ -19,12 +19,12 @@
#
##############################################################################
import time
from mx import DateTime
from osv import osv
import netsvc
import pooler
from mx import DateTime
import time
class procurement_order(osv.osv):
_inherit = 'procurement.order'
@@ -37,7 +37,7 @@ class procurement_order(osv.osv):
context = {}
if use_new_cursor:
cr = pooler.get_db(use_new_cursor).cursor()
cr = pooler.get_db(use_new_cursor).cursor()
wf_service = netsvc.LocalService("workflow")
procurement_obj = self.pool.get('procurement.order')
@@ -172,7 +172,7 @@ class procurement_order(osv.osv):
if not context:
context = {}
if use_new_cursor:
cr = pooler.get_db(use_new_cursor).cursor()
cr = pooler.get_db(use_new_cursor).cursor()
orderpoint_obj = self.pool.get('stock.warehouse.orderpoint')
location_obj = self.pool.get('stock.location')
procurement_obj = self.pool.get('procurement.order')
@@ -196,7 +196,7 @@ class procurement_order(osv.osv):
qty = max(op.product_min_qty, op.product_max_qty)-prods
reste = qty % op.qty_multiple
if reste > 0:
qty += op.qty_multiple - reste
qty += op.qty_multiple - reste
newdate = DateTime.now() + DateTime.RelativeDateTime(
days = int(op.product_id.seller_delay))
if op.product_id.supply_method == 'buy':
@@ -238,6 +238,7 @@ class procurement_order(osv.osv):
cr.commit()
cr.close()
return {}
procurement_order()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
@@ -30,36 +30,36 @@ from osv import fields,osv
class procurement_compute(osv.osv_memory):
_name = 'procurement.orderpoint.compute'
_description = 'Automatic Order Point'
_columns = {
'automatic': fields.boolean('Automatic Orderpoint', help='If the stock of a product is under 0, it will act like an orderpoint'),
'automatic': fields.boolean('Automatic Orderpoint', help='If the stock of a product is under 0, it will act like an orderpoint'),
}
_defaults = {
'automatic' : lambda *a: False,
'automatic': False,
}
def _procure_calculation_orderpoint(self, cr, uid, ids, context):
"""
"""
@param self: The object pointer.
@param cr: A database cursor
@param uid: ID of the user currently logged in
@param ids: List of IDs selected
@param context: A standard dictionary
"""
@param ids: List of IDs selected
@param context: A standard dictionary
"""
proc_obj = self.pool.get('procurement.order')
for proc in self.browse(cr, uid, ids):
proc_obj._procure_orderpoint_confirm(cr, uid, automatic=proc.automatic, use_new_cursor=cr.dbname, context=context)
return {}
def procure_calculation(self, cr, uid, ids, context):
"""
"""
@param self: The object pointer.
@param cr: A database cursor
@param uid: ID of the user currently logged in
@param ids: List of IDs selected
@param context: A standard dictionary
@param ids: List of IDs selected
@param context: A standard dictionary
"""
threaded_calculation = threading.Thread(target=self._procure_calculation_orderpoint, args=(cr, uid, ids, context))
threaded_calculation.start()
+12 -14
View File
@@ -26,43 +26,41 @@ from osv import osv, fields
class procurement_compute_all(osv.osv_memory):
_name = 'procurement.order.compute.all'
_description = 'Compute all schedulers'
_columns = {
'automatic': fields.boolean('Automatic orderpoint',help='Triggers an automatic procurement for all products that have a virtual stock under 0. You should probably not use this option, we suggest using a MTO configuration on products.'),
}
_defaults ={
'automatic': lambda *a: False,
}
def _procure_calculation_all(self, cr, uid, ids, context):
"""
"""
@param self: The object pointer.
@param cr: A database cursor
@param uid: ID of the user currently logged in
@param ids: List of IDs selected
@param context: A standard dictionary
@param ids: List of IDs selected
@param context: A standard dictionary
"""
proc_obj = self.pool.get('procurement.order')
for proc in self.browse(cr, uid, ids):
proc_obj.run_scheduler(cr, uid, automatic=proc.automatic, use_new_cursor=cr.dbname,\
context=context)
context=context)
return {}
def procure_calculation(self, cr, uid, ids, context):
"""
"""
@param self: The object pointer.
@param cr: A database cursor
@param uid: ID of the user currently logged in
@param ids: List of IDs selected
@param context: A standard dictionary
@param ids: List of IDs selected
@param context: A standard dictionary
"""
threaded_calculation = threading.Thread(target=self._procure_calculation_all, args=(cr, uid, ids, context))
threaded_calculation.start()
return {}
procurement_compute_all()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+3 -2
View File
@@ -36,7 +36,7 @@ class project_issue(osv.osv, crm.crm_case):
_name = "project.issue"
_description = "Project Issue"
_order = "priority, id desc"
_inherits = {'mailgate.thread': 'thread_id'}
_inherit = ['mailgate.thread']
def case_open(self, cr, uid, ids, *args):
"""
@@ -121,7 +121,6 @@ class project_issue(osv.osv, crm.crm_case):
return res
_columns = {
'thread_id': fields.many2one('mailgate.thread', 'Thread', required=False),
'id': fields.integer('ID'),
'name': fields.char('Name', size=128, required=True),
'active': fields.boolean('Active', required=False),
@@ -179,6 +178,8 @@ class project_issue(osv.osv, crm.crm_case):
method=True, multi='working_days_open', type="float", store=True),
'working_hours_close': fields.function(_compute_day, string='Working Hours to Close the Issue', \
method=True, multi='working_days_close', type="float", store=True),
'message_ids': fields.one2many('mailgate.message', 'res_id', 'Messages', domain=[('history', '=', True),('res_model','=',_name)]),
'log_ids': fields.one2many('mailgate.message', 'res_id', 'Logs', domain=[('history', '=', False),('res_model','=',_name)]),
}
def _get_project(self, cr, uid, context):
+6 -4
View File
@@ -205,7 +205,8 @@ class sale_order(osv.osv):
return result.keys()
_columns = {
'name': fields.char('Order Reference', size=64, required=True, select=True, help="unique number of the sale order,computed automatically when the sale order is created"),
'name': fields.char('Order Reference', size=64, required=True,
readonly=True, states={'draft': [('readonly', False)]}, select=True),
'shop_id': fields.many2one('sale.shop', 'Shop', required=True, readonly=True, states={'draft': [('readonly', False)]}),
'origin': fields.char('Source document', size=64, help="Reference of the document that generated this sale order request."),
'client_order_ref': fields.char('Customer Reference', size=64),
@@ -429,7 +430,6 @@ class sale_order(osv.osv):
for preline in preinv.invoice_line:
inv_line_id = self.pool.get('account.invoice.line').copy(cr, uid, preline.id, {'invoice_id': False, 'price_unit': -preline.price_unit})
lines.append(inv_line_id)
inv = {
'name': order.client_order_ref or order.name,
'origin': order.name,
@@ -462,7 +462,7 @@ class sale_order(osv.osv):
invoices = {}
invoice_ids = []
picking_obj = self.pool.get('stock.picking')
invoice = self.pool.get('account.invoice')
if context is None:
context = {}
# If date was specified, use it as date invoiced, usefull when invoices are generated this month and put the
@@ -477,7 +477,6 @@ class sale_order(osv.osv):
created_lines = self.pool.get('sale.order.line').invoice_line_create(cr, uid, lines)
if created_lines:
invoices.setdefault(o.partner_id.id, []).append((o, created_lines))
if not invoices:
for o in self.browse(cr, uid, ids):
for i in o.invoice_ids:
@@ -486,11 +485,14 @@ class sale_order(osv.osv):
for val in invoices.values():
if grouped:
res = self._make_invoice(cr, uid, val[0][0], reduce(lambda x,y: x + y, [l for o,l in val], []), context=context)
invoice_ref = ''
for o, l in val:
invoice_ref += o.name + '|'
self.write(cr, uid, [o.id], {'state': 'progress'})
if o.order_policy == 'picking':
picking_obj.write(cr, uid, map(lambda x: x.id, o.picking_ids), {'invoice_state': 'invoiced'})
cr.execute('insert into sale_order_invoice_rel (order_id,invoice_id) values (%s,%s)', (o.id, res))
invoice.write(cr, uid, [res], {'origin': invoice_ref, 'name': invoice_ref})
else:
for order, il in val:
res = self._make_invoice(cr, uid, order, il, context=context)
-3
View File
@@ -65,7 +65,6 @@
-
!record {model: account.account, id: account_account_receivable0}:
code: AR
company_id: base.main_company
currency_mode: current
name: Receivable
parent_id: account_account_minimalchart0
@@ -79,7 +78,6 @@
-
!record {model: account.account, id: account_account_cash0}:
code: C
company_id: base.main_company
currency_mode: current
name: Cash
parent_id: account_account_minimalchart0
@@ -142,7 +140,6 @@
-
!record {model: account.journal, id: account_journal_bankjournal0}:
code: BNK
company_id: base.main_company
default_credit_account_id: account_account_cash0
default_debit_account_id: account_account_cash0
name: Bank Journal
-1
View File
@@ -78,7 +78,6 @@
-
!record {model: account.account, id: account_account_cash0}:
code: C
company_id: base.main_company
currency_mode: current
name: Cash
parent_id: account_account_minimalchart0
-3
View File
@@ -65,7 +65,6 @@
-
!record {model: account.account, id: account_account_receivable0}:
code: AR
company_id: base.main_company
currency_mode: current
name: Receivable
parent_id: account_account_minimalchart0
@@ -79,7 +78,6 @@
-
!record {model: account.account, id: account_account_cash0}:
code: C
company_id: base.main_company
currency_mode: current
name: Cash
parent_id: account_account_minimalchart0
@@ -142,7 +140,6 @@
-
!record {model: account.journal, id: account_journal_bankjournal0}:
code: BNK
company_id: base.main_company
default_credit_account_id: account_account_cash0
default_debit_account_id: account_account_cash0
name: Bank Journal
@@ -65,7 +65,6 @@
-
!record {model: account.account, id: account_account_receivable0}:
code: AR
company_id: base.main_company
currency_mode: current
name: Receivable
parent_id: account_account_minimalchart0
@@ -79,7 +78,6 @@
-
!record {model: account.account, id: account_account_cash0}:
code: C
company_id: base.main_company
currency_mode: current
name: Cash
parent_id: account_account_minimalchart0
@@ -142,7 +140,6 @@
-
!record {model: account.journal, id: account_journal_bankjournal0}:
code: BNK
company_id: base.main_company
default_credit_account_id: account_account_cash0
default_debit_account_id: account_account_cash0
name: Bank Journal
+4 -4
View File
@@ -26,7 +26,7 @@ class sale_make_invoice(osv.osv_memory):
_name = "sale.make.invoice"
_description = "Sale Make Invoice"
_columns = {
'grouped': fields.boolean('Group the invoices'),
'grouped': fields.boolean('Group the invoices', help='Check the box to group the invoices for the same customers'),
'invoice_date':fields.date('Invoice Date'),
}
_default = {
@@ -50,11 +50,11 @@ class sale_make_invoice(osv.osv_memory):
for o in order_obj.browse(cr, uid, context.get(('active_ids'),[]), context):
for i in o.invoice_ids:
newinv.append(i.id)
mod_obj =self.pool.get('ir.model.data')
result = mod_obj._get_id(cr, uid, 'account', 'view_account_invoice_filter')
id = mod_obj.read(cr, uid, result, ['res_id'])
id = mod_obj.read(cr, uid, result, ['res_id'])
return {
'domain': "[('id','in', ["+','.join(map(str,newinv))+"])]",
'name': 'Invoices',
@@ -64,7 +64,7 @@ class sale_make_invoice(osv.osv_memory):
'view_id': False,
'context': "{'type':'out_refund'}",
'type': 'ir.actions.act_window',
'search_view_id': id['id']
'search_view_id': id['res_id']
}
sale_make_invoice()
+6 -5
View File
@@ -6,14 +6,15 @@
<field name="model">sale.make.invoice</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Create invoices">
<separator colspan="4" string="Do you really want to create the invoices ?" />
<field name="grouped" />
<form string="Create invoices">
<separator colspan="4" string="Do you really want to create the invoices ?" />
<field name="grouped"/>
<newline/>
<field name="invoice_date"/>
<separator string="" colspan="6" />
<separator string="" colspan="6"/>
<button special="cancel" string="Cancel" icon="gtk-cancel"/>
<button name="make_invoices" string="Create Invoices" type="object" icon="gtk-ok"/>
</form>
</form>
</field>
</record>
+3 -3
View File
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
#
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
@@ -15,7 +15,7 @@
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
@@ -29,7 +29,7 @@
'depends': ['sale', 'delivery'],
'init_xml': [],
'update_xml': [
'delivery_report.xml'
'sale_delivery_report.xml'
],
'demo_xml': [],
'installable': True,
+4 -2
View File
@@ -127,6 +127,7 @@ class picking_journal(osv.osv):
'state': fields.selection([
('draft','Draft'),
('open','Open'),
('cancel','Cancel'),
('done','Done'),
], 'Creation date', required=True, readonly=True),
'note': fields.text('Note'),
@@ -138,6 +139,7 @@ class picking_journal(osv.osv):
'state': lambda self,cr,uid,context: 'draft',
}
def button_picking_cancel(self, cr, uid, ids, context={}):
self.write(cr, uid, ids, {'state':'cancel'})
for id in ids:
pick_ids = self.pool.get('stock.picking').search(cr, uid, [('journal_id','=',id)])
for pickid in pick_ids:
@@ -177,7 +179,7 @@ res_partner()
class picking(osv.osv):
_inherit="stock.picking"
_columns = {
'journal_id': fields.many2one('sale_journal.picking.journal', 'Journal'),
'journal_id': fields.many2one('sale_journal.picking.journal', 'Journal', domain=[('state','!=', 'done')]),
'sale_journal_id': fields.many2one('sale_journal.sale.journal', 'Sale Journal'),
'invoice_type_id': fields.many2one('sale_journal.invoice.type', 'Invoice Type', readonly=True)
}
@@ -186,7 +188,7 @@ picking()
class sale(osv.osv):
_inherit="sale.order"
_columns = {
'journal_id': fields.many2one('sale_journal.sale.journal', 'Journal'),
'journal_id': fields.many2one('sale_journal.sale.journal', 'Journal', domain=[('state','!=', 'done')]),
'invoice_type_id': fields.many2one('sale_journal.invoice.type', 'Invoice Type')
}
def action_ship_create(self, cr, uid, ids, *args):
+21 -14
View File
@@ -113,13 +113,16 @@
<field name="arch" type="xml">
<search string="Sales by Journal">
<group col="8" colspan="4">
<filter icon="terp-personal" string="My Sale Journals" domain="[('user_id','=',uid)]" help="My Sale Journals"/>
<filter icon="terp-camera_test" string="Open" domain="[('state','=','open')]" help="Open Sale Journals"/>
<separator orientation="vertical"/>
<field name="name" select="1"/>
<field name="code" select="1"/>
<field name="user_id" select="1"/>
<field name="date" select="1"/>
<filter icon="terp-document-new" string="Draft" domain="[('state','=','draft')]" help="Sale Journals which are in draft state"/>
<filter icon="gtk-open" string="Open" domain="[('state','=','open')]" help="Open Sale Journals"/>
<filter icon="gtk-cancel" string="Cancel" domain="[('state','=','cancel')]" help="Sale Journals which are cancelled"/>
<filter icon="terp-check" string="Confirm" domain="[('state','=','confirm')]" help="Confirmed Sale Journals"/>
<filter icon="terp-camera_test" string="Close" domain="[('state','=','done')]" help="Sale Journals which are closed"/>
<separator orientation="vertical"/>
<field name="name"/>
<field name="code"/>
<field name="user_id"/>
<field name="date"/>
</group>
</search>
</field>
@@ -131,6 +134,7 @@
<field name="res_model">sale_journal.sale.journal</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="context">{'search_default_user_id':uid}</field>
<field name="search_view_id" ref="view_sale_journal_search"/>
</record>
@@ -386,7 +390,7 @@
<group col="6" colspan="2">
<button name="button_open" string="Open Journal" states="draft" type="object" icon="gtk-open"/>
<button name="button_close" string="Close Journal" states="open" type="object" icon="gtk-close"/>
<button name="button_draft" string="Set to Draft" states="close,open" type="object" icon="gtk-convert"/>
<button name="button_draft" string="Set to Draft" states="close,open,cancel" type="object" icon="gtk-convert"/>
<button string="Cancel Picking" name="button_picking_cancel" states="draft,open" type="object" icon="gtk-cancel"/>
</group>
</form>
@@ -417,13 +421,15 @@
<field name="arch" type="xml">
<search string="Picking Journals">
<group col="8" colspan="4">
<filter icon="terp-personal" string="My Picking Journals" domain="[('user_id','=',uid)]" help="My Picking Journals"/>
<filter icon="terp-camera_test" string="Open" domain="[('state','=','open')]" help="Open Picking Journals"/>
<filter icon="terp-document-new" string="Draft" domain="[('state','=','draft')]" help="Picking Journals which are in draft state"/>
<filter icon="gtk-open" string="Open" domain="[('state','=','open')]" help="Open Picking Journals"/>
<filter icon="gtk-cancel" string="Cancel" domain="[('state','=','cancel')]" help="Picking Journals which are cancelled"/>
<filter icon="terp-camera_test" string="Close" domain="[('state','=','done')]" help="Picking Journals which are closed"/>
<separator orientation="vertical"/>
<field name="name" select="1"/>
<field name="code" select="1"/>
<field name="user_id" select="1"/>
<field name="date" select="1"/>
<field name="name"/>
<field name="code"/>
<field name="user_id"/>
<field name="date"/>
</group>
</search>
</field>
@@ -436,6 +442,7 @@
<field name="res_model">sale_journal.picking.journal</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="context">{'search_default_user_id':uid}</field>
<field name="search_view_id" ref="view_picking_journal_search"/>
</record>
+11 -1
View File
@@ -26,6 +26,16 @@ class sale_order_line(osv.osv):
_name = "sale.order.line"
_inherit = "sale.order.line"
def product_id_change(self, cr, uid, ids, pricelist, product, qty=0,
uom=False, qty_uos=0, uos=False, name='', partner_id=False,
lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False):
res = super(sale_order_line, self).product_id_change(cr, uid, ids, pricelist, product, qty=qty,
uom=uom, qty_uos=qty_uos, uos=uos, name=name, partner_id=partner_id,
lang=lang, update_tax=update_tax, date_order=date_order, packaging=packaging, fiscal_position=fiscal_position, flag=flag)
purchase_price = self.pool.get('product.product').browse(cr, uid, product).standard_price
res['value'].update({'purchase_price':purchase_price})
return res
def _product_margin(self, cr, uid, ids, field_name, arg, context=None):
res = {}
for line in self.browse(cr, uid, ids):
@@ -38,7 +48,7 @@ class sale_order_line(osv.osv):
return res
_columns = {
'margin': fields.function(_product_margin, method=True, string='Margin', store=True),
'margin': fields.function(_product_margin, method=True, string='Margin', store={}),
'purchase_price': fields.float('Cost Price', digits=(16,2))
}
+27 -2
View File
@@ -13,6 +13,31 @@
</field>
</field>
</record>
<record model="ir.ui.view" id="sale_margin_sale_order_line">
<field name="name">sale.order.line.margin.view.form</field>
<field name="type">form</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form" />
<field name="arch" type="xml">
<xpath expr="/form/notebook/page/field[@name='order_line']/form/notebook/page/field[@name='price_unit']" position="after">
<field name="purchase_price"/>
</xpath>
</field>
</record>
<record model="ir.ui.view" id="sale_margin_sale_order_line_form">
<field name="name">sale.order.line.tree.margin.view.form</field>
<field name="type">form</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form" />
<field name="arch" type="xml">
<xpath expr="/form/notebook/page/field[@name='order_line']/tree/field[@name='price_unit']" position="after">
<field name="purchase_price"/>
</xpath>
</field>
</record>
<record model="ir.ui.view" id="sale_margin_sale_order_tree">
<field name="name">sale.order.margin.view.tree</field>
<field name="type">tree</field>
@@ -24,7 +49,7 @@
</field>
</field>
</record>
<record model="ir.ui.view" id="sale_margin_sale_order_line_tree">
<field name="name">sale.order.margin.line.view.tree</field>
<field name="type">tree</field>
@@ -42,7 +67,7 @@
<field name="name">picking.margin.view.form</field>
<field name="type">form</field>
<field name="model">stock.picking</field>
<field name="inherit_id" ref="stock.view_picking_out_form" />
<field name="inherit_id" ref="stock.view_picking_in_form" />
<field name="arch" type="xml">
<notebook colspan="4">
<page string="Supplier Invoices">