Replace history by revision on client
There is no need to use a custom Model to show history of record since client manage revision of any historized model. issue5020 review16711002
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
* Replace history by revision on client
|
||||
|
||||
Version 3.8.0 - 2015-11-02
|
||||
* Bug fixes (see mercurial logs for details)
|
||||
* Fix origin migration from 3.4
|
||||
|
||||
@@ -11,7 +11,6 @@ def register():
|
||||
Pool.register(
|
||||
SaleOpportunity,
|
||||
SaleOpportunityLine,
|
||||
SaleOpportunityHistory,
|
||||
SaleOpportunityEmployee,
|
||||
OpenSaleOpportunityEmployeeStart,
|
||||
SaleOpportunityMonthly,
|
||||
|
||||
+5
-104
@@ -2,22 +2,21 @@
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
"Sales extension for managing leads and opportunities"
|
||||
import datetime
|
||||
import time
|
||||
|
||||
from sql import Column, Literal, Null
|
||||
from sql.aggregate import Min, Max, Count, Sum
|
||||
from sql.conditionals import Coalesce, Case
|
||||
from sql import Literal, Null
|
||||
from sql.aggregate import Max, Count, Sum
|
||||
from sql.conditionals import Case
|
||||
from sql.functions import Extract
|
||||
|
||||
from trytond.model import ModelView, ModelSQL, Workflow, fields, Check
|
||||
from trytond.wizard import Wizard, StateView, StateAction, Button
|
||||
from trytond import backend
|
||||
from trytond.pyson import Equal, Eval, Not, In, If, Get, PYSONEncoder
|
||||
from trytond.pyson import Eval, In, If, Get, PYSONEncoder
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.pool import Pool
|
||||
|
||||
__all__ = ['SaleOpportunity', 'SaleOpportunityLine',
|
||||
'SaleOpportunityHistory', 'SaleOpportunityEmployee',
|
||||
'SaleOpportunityEmployee',
|
||||
'OpenSaleOpportunityEmployeeStart', 'OpenSaleOpportunityEmployee',
|
||||
'SaleOpportunityMonthly', 'SaleOpportunityEmployeeMonthly']
|
||||
|
||||
@@ -94,8 +93,6 @@ class SaleOpportunity(Workflow, ModelSQL, ModelView):
|
||||
['opportunity', 'lead', 'converted']),
|
||||
},
|
||||
depends=['state'], help="Percentage between 0 and 100")
|
||||
history = fields.One2Many('sale.opportunity.history', 'opportunity',
|
||||
'History', readonly=True)
|
||||
lost_reason = fields.Text('Reason for loss', states={
|
||||
'invisible': Eval('state') != 'lost',
|
||||
}, depends=['state'])
|
||||
@@ -244,7 +241,6 @@ class SaleOpportunity(Workflow, ModelSQL, ModelView):
|
||||
default = {}
|
||||
default = default.copy()
|
||||
default.setdefault('reference', None)
|
||||
default.setdefault('history', None)
|
||||
default.setdefault('sales', None)
|
||||
return super(SaleOpportunity, cls).copy(opportunities, default=default)
|
||||
|
||||
@@ -495,101 +491,6 @@ class SaleOpportunityLine(ModelSQL, ModelView):
|
||||
return sale_line
|
||||
|
||||
|
||||
class SaleOpportunityHistory(ModelSQL, ModelView):
|
||||
'Sale Opportunity History'
|
||||
__name__ = 'sale.opportunity.history'
|
||||
date = fields.DateTime('Change Date')
|
||||
opportunity = fields.Many2One('sale.opportunity', 'Sale Opportunity')
|
||||
user = fields.Many2One('res.user', 'User')
|
||||
party = fields.Many2One('party.party', 'Party', datetime_field='date')
|
||||
address = fields.Many2One('party.address', 'Address',
|
||||
datetime_field='date')
|
||||
company = fields.Many2One('company.company', 'Company',
|
||||
datetime_field='date')
|
||||
employee = fields.Many2One('company.employee', 'Employee',
|
||||
datetime_field='date')
|
||||
start_date = fields.Date('Start Date')
|
||||
end_date = fields.Date('End Date')
|
||||
description = fields.Char('Description')
|
||||
comment = fields.Text('Comment')
|
||||
lines = fields.Function(fields.One2Many('sale.opportunity.line', None,
|
||||
'Lines', datetime_field='date'), 'get_lines')
|
||||
amount = fields.Numeric('Amount', digits=(16, Eval('currency_digits', 2)),
|
||||
depends=['currency_digits'])
|
||||
currency = fields.Function(fields.Many2One('currency.currency',
|
||||
'Currency'), 'get_currency')
|
||||
currency_digits = fields.Function(fields.Integer('Currency Digits'),
|
||||
'get_currency_digits')
|
||||
state = fields.Selection(STATES, 'State')
|
||||
probability = fields.Integer('Conversion Probability')
|
||||
lost_reason = fields.Text('Reason for loss', states={
|
||||
'invisible': Not(Equal(Eval('state'), 'lost')),
|
||||
}, depends=['state'])
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(SaleOpportunityHistory, cls).__setup__()
|
||||
cls._order.insert(0, ('date', 'DESC'))
|
||||
|
||||
def get_currency(self, name):
|
||||
return self.company.currency.id
|
||||
|
||||
def get_currency_digits(self, name):
|
||||
return self.company.currency.digits
|
||||
|
||||
@classmethod
|
||||
def table_query(cls):
|
||||
Opportunity = Pool().get('sale.opportunity')
|
||||
opportunity_history = Opportunity.__table_history__()
|
||||
columns = [
|
||||
Min(Column(opportunity_history, '__id')).as_('id'),
|
||||
opportunity_history.id.as_('opportunity'),
|
||||
Min(Coalesce(opportunity_history.write_date,
|
||||
opportunity_history.create_date)).as_('date'),
|
||||
Coalesce(opportunity_history.write_uid,
|
||||
opportunity_history.create_uid).as_('user'),
|
||||
]
|
||||
group_by = [
|
||||
opportunity_history.id,
|
||||
Coalesce(opportunity_history.write_uid,
|
||||
opportunity_history.create_uid),
|
||||
]
|
||||
for name, field in cls._fields.iteritems():
|
||||
if name in ('id', 'opportunity', 'date', 'user'):
|
||||
continue
|
||||
if hasattr(field, 'set'):
|
||||
continue
|
||||
column = Column(opportunity_history, name)
|
||||
columns.append(column.as_(name))
|
||||
group_by.append(column)
|
||||
|
||||
return opportunity_history.select(*columns, group_by=group_by)
|
||||
|
||||
def get_lines(self, name):
|
||||
Line = Pool().get('sale.opportunity.line')
|
||||
# We will always have only one id per call due to datetime_field
|
||||
lines = Line.search([
|
||||
('opportunity', '=', self.opportunity.id),
|
||||
])
|
||||
return [l.id for l in lines]
|
||||
|
||||
@classmethod
|
||||
def read(cls, ids, fields_names=None):
|
||||
res = super(SaleOpportunityHistory, cls).read(ids,
|
||||
fields_names=fields_names)
|
||||
|
||||
# Remove microsecond from timestamp
|
||||
for values in res:
|
||||
if 'date' in values:
|
||||
if isinstance(values['date'], basestring):
|
||||
values['date'] = datetime.datetime(
|
||||
*time.strptime(values['date'],
|
||||
'%Y-%m-%d %H:%M:%S.%f')[:6])
|
||||
values['date'] = values['date'].replace(microsecond=0)
|
||||
values['date'] += datetime.timedelta(seconds=1)
|
||||
return res
|
||||
|
||||
|
||||
class SaleOpportunityReportMixin:
|
||||
number = fields.Integer('Number')
|
||||
converted = fields.Integer('Converted')
|
||||
|
||||
@@ -249,52 +249,6 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<field name="perm_delete" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="opportunity_history_view_form">
|
||||
<field name="model">sale.opportunity.history</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">opportunity_history_form</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="opportunity_history_view_tree">
|
||||
<field name="model">sale.opportunity.history</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="name">opportunity_history_tree</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.model.access" id="access_opportunity_history">
|
||||
<field name="model" search="[('model', '=', 'sale.opportunity.history')]"/>
|
||||
<field name="perm_read" eval="False"/>
|
||||
<field name="perm_write" eval="False"/>
|
||||
<field name="perm_create" eval="False"/>
|
||||
<field name="perm_delete" eval="False"/>
|
||||
</record>
|
||||
<record model="ir.model.access" id="access_opportunity_history_sale">
|
||||
<field name="model" search="[('model', '=', 'sale.opportunity.history')]"/>
|
||||
<field name="group" ref="sale.group_sale"/>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="False"/>
|
||||
<field name="perm_create" eval="False"/>
|
||||
<field name="perm_delete" eval="False"/>
|
||||
</record>
|
||||
<record model="ir.model.access" id="access_opportunity_history_opportunity">
|
||||
<field name="model" search="[('model', '=', 'sale.opportunity.history')]"/>
|
||||
<field name="group" ref="group_opportunity"/>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="True"/>
|
||||
<field name="perm_create" eval="True"/>
|
||||
<field name="perm_delete" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.rule.group" id="rule_group_opportunity_history">
|
||||
<field name="model" search="[('model', '=', 'sale.opportunity.history')]"/>
|
||||
<field name="global_p" eval="True"/>
|
||||
</record>
|
||||
<record model="ir.rule" id="rule_group_opportunity_history1">
|
||||
<field name="domain"
|
||||
eval="[('company', '=', Eval('user', {}).get('company', None))]"
|
||||
pyson="1"/>
|
||||
<field name="rule_group" ref="rule_group_opportunity_history"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="opportunity_employee_view_tree">
|
||||
<field name="model">sale.opportunity_employee</field>
|
||||
<field name="type">tree</field>
|
||||
|
||||
@@ -57,8 +57,5 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<page name="sales">
|
||||
<field name="sales" colspan="4"/>
|
||||
</page>
|
||||
<page name="history">
|
||||
<field name="history"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</form>
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<form string="History">
|
||||
<label name="opportunity"/>
|
||||
<field name="opportunity" colspan="3"/>
|
||||
<label name="user"/>
|
||||
<field name="user"/>
|
||||
<label name="date"/>
|
||||
<field name="date"/>
|
||||
<label name="party"/>
|
||||
<field name="party"/>
|
||||
<label name="address"/>
|
||||
<field name="address"/>
|
||||
<label name="description"/>
|
||||
<field name="description"/>
|
||||
<label name="amount"/>
|
||||
<group col="2" id="amount_currency">
|
||||
<field name="amount"/>
|
||||
<field name="currency"/>
|
||||
</group>
|
||||
<label name="probability"/>
|
||||
<field name="probability"/>
|
||||
<notebook colspan="4">
|
||||
<page string="Lead/Opportunity" id="opportunity">
|
||||
<label name="company"/>
|
||||
<field name="company"/>
|
||||
<label name="employee"/>
|
||||
<field name="employee"/>
|
||||
<label name="start_date"/>
|
||||
<field name="start_date"/>
|
||||
<label name="end_date"/>
|
||||
<field name="end_date"/>
|
||||
<separator name="comment" colspan="4"/>
|
||||
<field name="comment" colspan="4"/>
|
||||
<separator name="lost_reason" colspan="4"/>
|
||||
<field name="lost_reason" colspan="4"/>
|
||||
<group col="2" colspan="2" id="state">
|
||||
<label name="state"/>
|
||||
<field name="state"/>
|
||||
</group>
|
||||
</page>
|
||||
<page name="lines">
|
||||
<field name="lines"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</form>
|
||||
@@ -1,16 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<tree string="History">
|
||||
<field name="date" widget="date"/>
|
||||
<field name="date" widget="time" string="Change Time"/>
|
||||
<field name="user"/>
|
||||
<field name="start_date"/>
|
||||
<field name="end_date"/>
|
||||
<field name="description"/>
|
||||
<field name="party"/>
|
||||
<field name="amount"/>
|
||||
<field name="currency"/>
|
||||
<field name="state"/>
|
||||
<field name="probability"/>
|
||||
</tree>
|
||||
Reference in New Issue
Block a user