Purchase form
This commit is contained in:
53
ir/model.py
53
ir/model.py
@@ -1606,8 +1606,53 @@ class Log(ResourceAccessMixin, ModelSQL, ModelView):
|
|||||||
return json.dumps(value, sort_keys=True, ensure_ascii=False)
|
return json.dumps(value, sort_keys=True, ensure_ascii=False)
|
||||||
if value in (None, ''):
|
if value in (None, ''):
|
||||||
return ''
|
return ''
|
||||||
|
if isinstance(value, str) and re.match(r'^-?\d+(\.\d+)?$', value):
|
||||||
|
value = value.rstrip('0').rstrip('.')
|
||||||
|
return value or '0'
|
||||||
return str(value)
|
return str(value)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _singular_label(label):
|
||||||
|
if label.endswith('ies'):
|
||||||
|
return label[:-3] + 'y'
|
||||||
|
if label.endswith('s'):
|
||||||
|
return label[:-1]
|
||||||
|
return label
|
||||||
|
|
||||||
|
def _format_nested_change_summary(
|
||||||
|
self, field_label, target_model, old_value, new_value):
|
||||||
|
pool = Pool()
|
||||||
|
Field = pool.get('ir.model.field')
|
||||||
|
lines = []
|
||||||
|
if not isinstance(old_value, dict) or not isinstance(new_value, dict):
|
||||||
|
return lines
|
||||||
|
record_label = self._singular_label(field_label)
|
||||||
|
def record_sort_key(value):
|
||||||
|
try:
|
||||||
|
return int(value)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
return value
|
||||||
|
for record_id in sorted(
|
||||||
|
set(old_value) | set(new_value), key=record_sort_key):
|
||||||
|
record_old = old_value.get(record_id, {})
|
||||||
|
record_new = new_value.get(record_id, {})
|
||||||
|
if not isinstance(record_old, dict) or not isinstance(
|
||||||
|
record_new, dict):
|
||||||
|
continue
|
||||||
|
for child_field in sorted(set(record_old) | set(record_new)):
|
||||||
|
child_old = record_old.get(child_field)
|
||||||
|
child_new = record_new.get(child_field)
|
||||||
|
if child_old == child_new:
|
||||||
|
continue
|
||||||
|
child_label = Field.get_name(target_model, child_field)
|
||||||
|
lines.append('%s %s %s %s => %s' % (
|
||||||
|
record_label,
|
||||||
|
record_id,
|
||||||
|
child_label,
|
||||||
|
self._format_change_value(child_old),
|
||||||
|
self._format_change_value(child_new)))
|
||||||
|
return lines
|
||||||
|
|
||||||
def get_change_summary(self, name):
|
def get_change_summary(self, name):
|
||||||
if self.event != 'write':
|
if self.event != 'write':
|
||||||
return ''
|
return ''
|
||||||
@@ -1628,6 +1673,14 @@ class Log(ResourceAccessMixin, ModelSQL, ModelView):
|
|||||||
field_label = Field.get_name(model, field_name)
|
field_label = Field.get_name(model, field_name)
|
||||||
else:
|
else:
|
||||||
field_label = field_name
|
field_label = field_name
|
||||||
|
field = getattr(self.resource.__class__, field_name, None)
|
||||||
|
if field and hasattr(field, 'get_target'):
|
||||||
|
target_model = field.get_target().__name__
|
||||||
|
nested_lines = self._format_nested_change_summary(
|
||||||
|
field_label, target_model, old_value, new_value)
|
||||||
|
if nested_lines:
|
||||||
|
lines.extend(nested_lines)
|
||||||
|
continue
|
||||||
lines.append('%s: %s -> %s' % (
|
lines.append('%s: %s -> %s' % (
|
||||||
field_label,
|
field_label,
|
||||||
self._format_change_value(old_value),
|
self._format_change_value(old_value),
|
||||||
|
|||||||
@@ -221,6 +221,72 @@ class ModelStorage(Model):
|
|||||||
}
|
}
|
||||||
return json.dumps(values, sort_keys=True, ensure_ascii=False)
|
return json.dumps(values, sort_keys=True, ensure_ascii=False)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _iter_log_commands(value):
|
||||||
|
if not isinstance(value, (list, tuple)):
|
||||||
|
return
|
||||||
|
for item in value:
|
||||||
|
if (isinstance(item, (list, tuple))
|
||||||
|
and item and isinstance(item[0], str)):
|
||||||
|
command = item[0]
|
||||||
|
if len(item) >= 3:
|
||||||
|
yield command, item[1], item[2]
|
||||||
|
elif len(item) >= 2:
|
||||||
|
yield command, item[1], None
|
||||||
|
if value and all(isinstance(item, (list, tuple)) for item in value):
|
||||||
|
return
|
||||||
|
index = 0
|
||||||
|
while index < len(value):
|
||||||
|
command = value[index]
|
||||||
|
if not isinstance(command, str):
|
||||||
|
index += 1
|
||||||
|
continue
|
||||||
|
if command == 'write':
|
||||||
|
if index + 2 >= len(value):
|
||||||
|
break
|
||||||
|
yield command, value[index + 1], value[index + 2]
|
||||||
|
index += 3
|
||||||
|
continue
|
||||||
|
if index + 1 >= len(value):
|
||||||
|
break
|
||||||
|
yield command, value[index + 1], None
|
||||||
|
index += 2
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _nested_log_values(cls, values):
|
||||||
|
nested_old = {}
|
||||||
|
nested_new = {}
|
||||||
|
for field_name, value in values.items():
|
||||||
|
field = cls._fields.get(field_name)
|
||||||
|
if not field or not hasattr(field, 'get_target'):
|
||||||
|
continue
|
||||||
|
commands = list(cls._iter_log_commands(value) or [])
|
||||||
|
write_commands = [
|
||||||
|
(ids, command_values)
|
||||||
|
for command, ids, command_values in commands
|
||||||
|
if command == 'write' and command_values]
|
||||||
|
if not write_commands:
|
||||||
|
continue
|
||||||
|
Target = field.get_target()
|
||||||
|
field_old = {}
|
||||||
|
field_new = {}
|
||||||
|
for ids, command_values in write_commands:
|
||||||
|
target_ids = [int(i) for i in ids]
|
||||||
|
field_names = list(sorted(command_values.keys()))
|
||||||
|
with without_check_access():
|
||||||
|
rows = Target.read(target_ids, field_names)
|
||||||
|
for row in rows:
|
||||||
|
record_id = str(row['id'])
|
||||||
|
field_old.setdefault(record_id, {}).update({
|
||||||
|
name: row.get(name)
|
||||||
|
for name in field_names
|
||||||
|
})
|
||||||
|
field_new.setdefault(record_id, {}).update(command_values)
|
||||||
|
if field_old or field_new:
|
||||||
|
nested_old[field_name] = field_old
|
||||||
|
nested_new[field_name] = field_new
|
||||||
|
return nested_old, nested_new
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(cls, vlist):
|
def create(cls, vlist):
|
||||||
'''
|
'''
|
||||||
@@ -304,11 +370,16 @@ class ModelStorage(Model):
|
|||||||
}
|
}
|
||||||
for row in cls.read(
|
for row in cls.read(
|
||||||
[r.id for r in records], fields_names)}
|
[r.id for r in records], fields_names)}
|
||||||
|
nested_old, nested_new = cls._nested_log_values(values)
|
||||||
for record in records:
|
for record in records:
|
||||||
|
record_old_values = old_values.get(record.id, {})
|
||||||
|
record_new_values = values.copy()
|
||||||
|
record_old_values.update(nested_old)
|
||||||
|
record_new_values.update(nested_new)
|
||||||
cls.log([record], 'write', ','.join(fields_names),
|
cls.log([record], 'write', ','.join(fields_names),
|
||||||
old_values=cls._log_value_text(
|
old_values=cls._log_value_text(
|
||||||
old_values.get(record.id, {})),
|
record_old_values),
|
||||||
new_values=cls._log_value_text(values))
|
new_values=cls._log_value_text(record_new_values))
|
||||||
|
|
||||||
ModelAccess.check(cls.__name__, 'write')
|
ModelAccess.check(cls.__name__, 'write')
|
||||||
ModelFieldAccess.check(cls.__name__, all_fields, 'write')
|
ModelFieldAccess.check(cls.__name__, all_fields, 'write')
|
||||||
|
|||||||
Reference in New Issue
Block a user