Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 #This file is part of Tryton. The COPYRIGHT file at the top level of | 1 #This file is part of Tryton. The COPYRIGHT file at the top level of |
2 #this repository contains the full copyright notices and license terms. | 2 #this repository contains the full copyright notices and license terms. |
3 "Sales extension for managing leads and opportunities" | 3 "Sales extension for managing leads and opportunities" |
4 from trytond.model import ModelView, ModelSQL, ModelWorkflow, fields | 4 from trytond.model import ModelView, ModelSQL, ModelWorkflow, fields |
5 from trytond.pyson import Equal, Eval, Not, In | 5 from trytond.pyson import Equal, Eval, Not, In, If, Get |
6 import datetime | 6 import datetime |
7 | 7 |
8 STATES = [('lead', 'Open Lead'), | 8 STATES = [('lead', 'Lead'), |
ced
2010/01/26 20:12:22
double space after =
sharoonthomas
2010/01/26 21:30:35
Done.
| |
9 ('opportunity', 'Opportunity'), | 9 ('opportunity', 'Opportunity'), |
10 ('converted', 'Converted'), | 10 ('converted', 'Converted'), |
11 ('cancel', 'Cancelled'), | 11 ('cancel', 'Cancelled'), |
12 ('lost', 'Lost'), | 12 ('lost', 'Lost'), |
13 ] | 13 ] |
yangoon1
2010/01/26 20:39:16
I am still not quite sure about states:
according
| |
14 _STATES_LEAD = {'readonly': Not(Equal(Eval('state'), 'lead')), } | |
15 _STATES_CONVERTED = {'readonly': Equal(Eval('state'), 'converted'), } | |
16 | |
14 class SaleOpportunity(ModelWorkflow, ModelSQL, ModelView): | 17 class SaleOpportunity(ModelWorkflow, ModelSQL, ModelView): |
15 'Sale Leads & opportunities' | 18 'Sale Opportunity' |
yangoon1
2010/01/26 20:39:16
Like we discussed in chat, would be for me just:
'
sharoonthomas
2010/01/26 21:30:35
Done.
| |
16 _name = "sale.opportunity" | 19 _name = "sale.opportunity" |
17 _description = __doc__ | 20 _description = __doc__ |
18 _rec_name = "title" | 21 _rec_name = "title" |
19 _history = True | 22 _history = True |
20 ···· | 23 ···· |
21 title = fields.Char('Title', required=True, translate=True, select=1, | 24 title = fields.Char('Title', required=True, translate=True, select=1, |
22 states={ | 25 states=_STATES_CONVERTED, depends=['state']) |
23 'readonly': Equal(Eval('state'), 'converted'), | |
24 },depends=['state']) | |
ced
2010/01/26 20:12:22
You remove 8cols of indentation to be aligned with
sharoonthomas
2010/01/26 21:30:35
Done.
| |
25 description = fields.Text('Description', select=2, | 26 description = fields.Text('Description', select=2, |
26 states={ | 27 states=_STATES_CONVERTED, depends=['state']) |
27 'readonly': Equal(Eval('state'), 'converted'), | |
28 },depends=['state']) | |
29 date = fields.DateTime('Date', required=True, select=1, | 28 date = fields.DateTime('Date', required=True, select=1, |
30 states={ | 29 states=_STATES_LEAD, depends=['state']) |
31 'readonly': Not(Equal(Eval('state'), 'lead')), | |
32 },depends=['state']) | |
33 end_date = fields.DateTime('End Date', select=2, readonly=True, | 30 end_date = fields.DateTime('End Date', select=2, readonly=True, |
34 states={ | 31 states={ |
35 'invisible': In(Eval('state'), ['lead', 'opportunity']), | 32 'invisible': In(Eval('state'), ['lead', 'opportunity']), |
36 }, depends=['state']) | 33 }, depends=['state']) |
37 party = fields.Many2One('party.party', 'Party', required=True, select=1, | 34 party = fields.Many2One('party.party', 'Party', required=True, select=1, |
38 states={ | 35 states=_STATES_CONVERTED, depends=['state']) |
39 'readonly': Equal(Eval('state'), 'converted'), | 36 company = fields.Many2One('company.company', 'Company', required=True, |
40 },depends=['state'])· | 37 states=_STATES_CONVERTED, domain=[ |
41 address = fields.Many2One('party.address', 'Address', domain=[('party', '=', Eval('party'))],· | 38 ('id', If(In('company', Eval('context', {})), '=', '!='), |
ced
2010/01/26 20:12:22
still 80cols
sharoonthomas
2010/01/26 21:30:35
Done.
| |
42 select=2, depends=['party','state'], | 39 Get(Eval('context', {}), 'company', 0)), |
43 states={ | 40 ]) |
44 'readonly': Equal(Eval('state'), 'converted'), | 41 employee = fields.Many2One('company.employee', 'Employee', required=True, |
45 }) | 42 states=_STATES_CONVERTED, domain=[('company', '=', Eval('company'))], |
43 depends=['company']) | |
44 address = fields.Many2One('party.address', 'Address', | |
45 domain=[('party', '=', Eval('party'))], | |
46 select=2, depends=['party', 'state'], | |
47 states=_STATES_CONVERTED) | |
46 lines = fields.One2Many('sale.opportunity.lines', 'opportunity', 'Lines', | 48 lines = fields.One2Many('sale.opportunity.lines', 'opportunity', 'Lines', |
47 states={ | 49 states=_STATES_CONVERTED, depends=['state']) |
48 'readonly': Equal(Eval('state'), 'converted'), | |
49 },depends=['state']) | |
50 state = fields.Selection(STATES, 'State', required=True, select=1, sort=Fals e, readonly=True) | 50 state = fields.Selection(STATES, 'State', required=True, select=1, sort=Fals e, readonly=True) |
51 probability = fields.Integer('Conversion Probability', | 51 probability = fields.Integer('Conversion Probability', |
52 states={ | 52 states={ |
53 'required': Equal(Eval('state'), 'opportunity'), | 53 'required': Equal(Eval('state'), 'opportunity'), |
54 'readonly': Not(In(Eval('state'), ['opportunity', 'lead' ])), | 54 'readonly': Not(In(Eval('state'), ['opportunity', 'lead'])), |
55 }, depends=['state'], select=2, | 55 }, depends=['state'], select=2, |
56 help="Percentage between 0 and 100") | 56 help="Percentage between 0 and 100") |
57 history_lines = fields.One2Many('sale.opportunity.history.lines', 'sale_oppo rtunity', 'History') | 57 history_lines = fields.One2Many('sale.opportunity.history.lines', 'sale_oppo rtunity', 'History') |
58 lost_reason = fields.Text('Reason for loss', states={ | 58 lost_reason = fields.Text('Reason for loss', |
59 'invisible': Not(Equal(Eval('state'), 'lost')), | 59 states={ |
60 }, depends=['state']) | 60 'invisible': Not(Equal(Eval('state'), 'lost')), |
61 }, depends=['state']) | |
61 ···· | 62 ···· |
62 def __init__(self): | 63 def __init__(self): |
63 super(SaleOpportunity, self).__init__() | 64 super(SaleOpportunity, self).__init__() |
64 self._order[0] = ('date', 'DESC') | 65 self._order[0] = ('date', 'DESC') |
65 self._sql_constraints += [ | 66 self._sql_constraints += [ |
66 ('check_percentage','CHECK(probability >= 0 AND probability <= 100)' , 'Probability must be between 0 and 100!') | 67 ('check_percentage',· |
68 'CHECK(probability >= 0 AND probability <= 100)', | |
69 'Probability must be between 0 and 100!') | |
67 ] | 70 ] |
68 ···· | 71 ···· |
69 def default_state(self, cursor, user, context=None): | 72 def default_state(self, cursor, user, context=None): |
70 return 'lead' | 73 return 'lead' |
71 ···· | 74 ···· |
72 def default_date(self, cursor, user, context=None): | 75 def default_date(self, cursor, user, context=None): |
73 return datetime.datetime.today() | 76 return datetime.datetime.today() |
74 ···· | 77 ···· |
75 def default_probability(self, cursor, user, context=None): | 78 def default_probability(self, cursor, user, context=None): |
76 return 50 | 79 return 50 |
77 ···· | 80 ···· |
81 def default_company(self, cursor, user, context=None): | |
82 if context is None: | |
83 context = {} | |
84 if context.get('company'): | |
85 return context['company'] | |
86 return False | |
87 ···· | |
88 def default_employee(self, cursor, user_id, context=None): | |
89 user_obj = self.pool.get('res.user') | |
90 employee_obj = self.pool.get('company.employee') | |
91 | |
92 if context is None: | |
93 context = {} | |
94 employee_id = None | |
95 if context.get('employee'): | |
96 employee_id = context['employee'] | |
97 else: | |
98 user = user_obj.browse(cursor, user_id, user_id, context=context) | |
99 if user.employee: | |
100 employee_id = user.employee.id | |
101 if employee_id: | |
102 return employee_id | |
103 return False | |
104 ···· | |
78 def end_lead(self, cursor, user, opp_id, context=None): | 105 def end_lead(self, cursor, user, opp_id, context=None): |
ced
2010/01/26 20:12:22
Better to use ids
:param ids: a list of opportunit
sharoonthomas
2010/01/26 21:30:35
But the workflow passes an ID as argument
On 2010/
| |
79 """ | 106 """ |
80 This will fill the end_date for a lead/opportunity | 107 This will fill the end_date for a lead/opportunity |
81 :param cursor: the database cursor | 108 :param cursor: the database cursor |
82 :param user: the user id | 109 :param user: the user id |
83 :param opp_id: id of the record to be flagged with the current datetime | 110 :param opp_id: id of the record to be flagged with the current datetime |
84 :param context: the context· | 111 :param context: the context· |
85 """ | 112 """ |
86 self.write(cursor, user, opp_id, { | 113 self.write(cursor, user, opp_id, { |
87 'end_date':datetime.datetime.today(), | 114 'end_date':datetime.datetime.today(), |
ced
2010/01/26 20:12:22
indent 4cols
| |
88 'state': 'converted', | 115 'state': 'converted', |
89 },context=context) | 116 }, context=context) |
90 ···· | 117 ···· |
91 SaleOpportunity() | 118 SaleOpportunity() |
92 | 119 |
93 | 120 |
94 class SaleOpportunityLines(ModelSQL, ModelView): | 121 class SaleOpportunityLines(ModelSQL, ModelView): |
95 'Sale Opportunity Lines/Items' | 122 'Sale Opportunity Lines' |
96 _name = "sale.opportunity.lines" | 123 _name = "sale.opportunity.lines" |
97 _description = __doc__ | 124 _description = __doc__ |
98 _rec_name = "product" | 125 _rec_name = "product" |
99 ···· | 126 ···· |
100 opportunity = fields.Many2One('sale.opportunity', 'Opportunity') | 127 opportunity = fields.Many2One('sale.opportunity', 'Opportunity') |
101 product = fields.Many2One('product.product', 'Product', required=True) | 128 product = fields.Many2One('product.product', 'Product', required=True) |
102 quantity = fields.Float('Quantity') | 129 quantity = fields.Float('Quantity') |
ced
2010/01/26 20:12:22
Add an empty line
sharoonthomas
2010/01/26 21:30:35
Done.
| |
130 ···· | |
103 SaleOpportunityLines() | 131 SaleOpportunityLines() |
104 | 132 |
105 | 133 |
106 class SaleOpportunityHistoryLines(ModelSQL, ModelView): | 134 class SaleOpportunityHistoryLines(ModelSQL, ModelView): |
107 'Sale Opportunity History Lines' | 135 'Sale Opportunity History Lines' |
108 _name = 'sale.opportunity.history.lines' | 136 _name = 'sale.opportunity.history.lines' |
109 _description = __doc__ | 137 _description = __doc__ |
110 | 138 |
111 sale_opportunity = fields.Many2One('sale.opportunity', 'Sale Opportunity') | 139 sale_opportunity = fields.Many2One('sale.opportunity', 'Sale Opportunity') |
112 date = fields.DateTime('Change Date') | 140 date = fields.DateTime('Change Date') |
(...skipping 12 matching lines...) Expand all Loading... | |
125 id as sale_opportunity, | 153 id as sale_opportunity, |
126 __id as id,· | 154 __id as id,· |
127 create_date, | 155 create_date, |
128 write_date,· | 156 write_date,· |
129 create_uid, | 157 create_uid, |
130 write_uid, | 158 write_uid, |
131 COALESCE(write_date, create_date) AS date, | 159 COALESCE(write_date, create_date) AS date, |
132 COALESCE(write_uid,create_uid) AS user, | 160 COALESCE(write_uid,create_uid) AS user, |
133 title,· | 161 title,· |
134 state,· | 162 state,· |
135 probability | 163 probability """ |
136 FROM """ + opportunity_object._table + """__history | 164 'FROM "%s__history"' % opportunity_object._table |
ced
2010/01/26 20:12:22
Quote table name
sharoonthomas
2010/01/26 21:30:35
Done.
| |
137 """, []) | 165 , []) |
138 | 166 |
139 SaleOpportunityHistoryLines() | 167 SaleOpportunityHistoryLines() |
LEFT | RIGHT |