Merge lp:~vrt-openerp/openobject-addons/vrt-openerp into lp:openobject-addons

Proposed by Stuart Longland
Status: Superseded
Proposed branch: lp:~vrt-openerp/openobject-addons/vrt-openerp
Merge into: lp:openobject-addons
Diff against target: 517 lines (+241/-55)
8 files modified
crm/report/crm_lead_report.py (+4/-0)
crm/report/crm_lead_report_view.xml (+93/-3)
hr_timesheet_sheet/hr_timesheet_sheet_view.xml (+1/-1)
project/project.py (+7/-2)
project/project_view.xml (+3/-0)
project_long_term/project_long_term.py (+24/-2)
resource/faces/pcalendar.py (+10/-1)
resource/resource.py (+99/-46)
To merge this branch: bzr merge lp:~vrt-openerp/openobject-addons/vrt-openerp
Reviewer Review Type Date Requested Status
Olivier Dony (Odoo) branch content Needs Resubmitting
Review via email: mp+93763@code.launchpad.net

This proposal has been superseded by a proposal from 2012-03-23.

Description of the change

This branch includes a number of in-house changes to OpenERP 6.1 trunk that fix some issues discovered in the move across. Updates include:

- Long term planning:
  - Fix to working hours; converting the user's working hours to UTC for scheduling in Faces
  - Allowing the "Schedule Phases" to also schedule tasks within each phase
  - Enable assignment of a work-load for a task in percent; this is passed through to Faces for scheduling purposes
- CRM module:
  - Create a new "Leads" field (taken from partner_name), for leads that do not have a partner defined yet (otherwise all these "leads" get filed under the "Undefined" partner)

To post a comment you must log in.
6624. By Launchpad Translations on behalf of openerp

Launchpad automatic translations update.

6625. By Launchpad Translations on behalf of openerp

Launchpad automatic translations update.

6626. By Jean-Christophe VASSORT

[FIX] opw 383657: hr_expense: When unit quantity or factor value is zero > get divide by zero error

6627. By Launchpad Translations on behalf of openerp

Launchpad automatic translations update.

6628. By Raphael Collet (OpenERP)

[MERGE] lp:931523 (fix error message when pushing on Documents)

6629. By Quentin (OpenERP) <email address hidden>

[MERGE] merge the branch from Numérigraphe with a better label for the address of direct delivery on PO.

6630. By Launchpad Translations on behalf of openerp

Launchpad automatic translations update.

6631. By Nicolas Vanhoren (OpenERP)

[merge] refactoring in web client

6632. By Quentin (OpenERP) <email address hidden>

[FIX] account, cash statement: creation through web client

6633. By Quentin (OpenERP) <email address hidden>

[MERGE] lp:909124. Conflict between account_bank_statement_extension and point_of_sale

6634. By Quentin (OpenERP) <email address hidden>

[FIX] account: cannot iter on a boolean. stupid me

6635. By Fabien Meghazi (OpenERP)

[FIX] Edi: webclient's template name has been changed from 'Interface' to 'WebClient'

6636. By Quentin (OpenERP) <email address hidden>

[IMP] account_payment: improved the module description to tackle the most common pitfall linked to this module + rst compliancy of few other modules

6637. By Quentin (OpenERP) <email address hidden>

[IMP] account_payment: improved the module description to tackle the most common pitfall linked to this module

6638. By Quentin (OpenERP) <email address hidden>

[MERGE] lp:930528

6639. By Launchpad Translations on behalf of openerp

Launchpad automatic translations update.

6640. By Quentin (OpenERP) <email address hidden>

[MERGE] lp:880844

6641. By Quentin (OpenERP) <email address hidden>

[REM] hr_timesheet_invoice: removed unused report cost ledger. It was duplicated code of the same report defined in account module AND calling its rml.

6642. By Quentin (OpenERP) <email address hidden>

[MERGE] fix of lp:901089

6643. By Launchpad Translations on behalf of openerp

Launchpad automatic translations update.

6644. By Launchpad Translations on behalf of openerp

Launchpad automatic translations update.

6645. By Launchpad Translations on behalf of openerp

Launchpad automatic translations update.

6646. By Launchpad Translations on behalf of openerp

Launchpad automatic translations update.

6647. By Launchpad Translations on behalf of openerp

Launchpad automatic translations update.

6648. By Olivier Dony (Odoo)

[MERGE] Latest bugfixes from 6.1

6649. By Nicolas Vanhoren (OpenERP)

[imp] adaptation to .js due to changes in web

6650. By Fabien Meghazi (OpenERP)

[FIX] Fixed broken web addon due to webclient's new layout

6651. By Fabien Meghazi (OpenERP)

[FIX] web_livechat: Fixed broken addon due to webclient's layout change

6652. By Launchpad Translations on behalf of openerp

Launchpad automatic translations update.

6653. By Fabien Meghazi (OpenERP)

[IMP] web addons: Use webclient's Systray tooltips

6654. By Quentin (OpenERP) <email address hidden>

[MERGE] merged the branch containing the refactoring of event module and the new modules event_moodle and event_sale

6655. By Launchpad Translations on behalf of openerp

Launchpad automatic translations update.

6656. By Launchpad Translations on behalf of openerp

Launchpad automatic translations update.

6671. By Stuart Longland

Rewrite and Merge with upstream changes.

6672. By Stuart Longland

Rewrite and Merge with upstream changes.

6673. By Stuart Longland

hr_timesheet_sheet: Fix user_id default value

OpenERP 6.1-1 currently fails to fill in the user_id field. On submission of a
timesheet line, the end user finds the system rejects the entered data on the
basis that the user_id field is invalid. Being a hidden field, it is
impossible for the end user to correct this.

The following seems to fix the problem here.

6674. By Stuart Longland

Rewrite and Merge with upstream changes.

6675. By Stuart Longland

crm: Hide "Lead" in search view of Opportunities

They don't have "lead" fields, as the lead has been already converted to
a partner by this stage.

6676. By Stuart Longland

crm: Allow lead report to show individual leads

This allows the end user to navigate to an individual lead (for now via
an intermediate form). The form will need some prettying up, but at
least now if there's a heap of leads in one group, we can differentiate
them now.

This also reverts my earlier commit, which broke things.

6677. By Stuart Longland

crm_lead_report: Fix broken init function

SQL was complaining we specified id twice, so we call the latter
occurance lead_id. That keeps it happy.

Revision history for this message
Olivier Dony (Odoo) (odo-openerp) wrote :

Hello Stuart,

The proposed patches sound good, but the merge proposal is hard to review because it seems to contain a certain number of unrelated changes (CRM stuff). As a rule we prefer to keep only related changesets in each merge proposal, especially for bugfix branches - so they can be independently reviewed and merged.
Perhaps the easiest course is to apply your patch for bug 932584 on a fresh copy of our official addons branch, and submit that as a separate merge proposal.

If you'd like more details, our merge proposal documentation includes a step-by-step guide for this process [1].

Thanks for your contributions to OpenERP!

[1] http://doc.openerp.com/v6.0/contribute/15_guidelines/contribution_guidelines.html#merge-proposal-guidelines

review: Needs Resubmitting (branch content)
Revision history for this message
Stuart Longland (redhatter) wrote :

No worries, I'll split this up.

I've just spent what seems like 10 minutes hunting around for the "Register Branch" link to do exactly this, and Launchpad has "helpfully" removed it and not told anyone (thanks Launchpad).

I'm creating a fresh branch of the trunk code -- when this is done, I should be able to cherry-pick the relevant commits from it and push those into a separate new branch.

Unmerged revisions

6677. By Stuart Longland

crm_lead_report: Fix broken init function

SQL was complaining we specified id twice, so we call the latter
occurance lead_id. That keeps it happy.

6676. By Stuart Longland

crm: Allow lead report to show individual leads

This allows the end user to navigate to an individual lead (for now via
an intermediate form). The form will need some prettying up, but at
least now if there's a heap of leads in one group, we can differentiate
them now.

This also reverts my earlier commit, which broke things.

6675. By Stuart Longland

crm: Hide "Lead" in search view of Opportunities

They don't have "lead" fields, as the lead has been already converted to
a partner by this stage.

6674. By Stuart Longland

Rewrite and Merge with upstream changes.

6673. By Stuart Longland

hr_timesheet_sheet: Fix user_id default value

OpenERP 6.1-1 currently fails to fill in the user_id field. On submission of a
timesheet line, the end user finds the system rejects the entered data on the
basis that the user_id field is invalid. Being a hidden field, it is
impossible for the end user to correct this.

The following seems to fix the problem here.

6672. By Stuart Longland

Rewrite and Merge with upstream changes.

6671. By Stuart Longland

Rewrite and Merge with upstream changes.

6670. By Stuart Longland

Rewrite and Merge with upstream changes.

6669. By Stuart Longland

project_long_term: Skip cancelled or done tasks.

These are skipped when generating the project description for faces to manage,
therefore they should also be skipped when collecting results.

6668. By Stuart Longland

project_long_term.schedule_phases: Skip projects with no phases

Projects that have no phases by definition cannot be scheduled via the "Schedule Phases" algorithm. When one attempts to do this, the following is emitted to Faces:

from resource.faces import *
import datetime

def Project():

resulting in the following stack trace:

[2012-02-17 02:07:29,630][development61] ERROR:web-services:Uncaught exception
Traceback (most recent call last):
  File "/usr/lib64/python2.7/site-packages/openerp-6.1rc1_20120112_173907-py2.7.egg/openerp/osv/osv.py", line 120, in wrapper
    return f(self, dbname, *args, **kwargs)
  File "/usr/lib64/python2.7/site-packages/openerp-6.1rc1_20120112_173907-py2.7.egg/openerp/osv/osv.py", line 175, in execute
    res = self.execute_cr(cr, uid, obj, method, *args, **kw)
  File "/usr/lib64/python2.7/site-packages/openerp-6.1rc1_20120112_173907-py2.7.egg/openerp/osv/osv.py", line 163, in execute_cr
    return getattr(object, method)(cr, uid, *args, **kw)
  File "/usr/lib64/python2.7/site-packages/openerp-6.1rc1_20120112_173907-py2.7.egg/openerp/addons/project_long_term/wizard/project_compute_phases.py", line 39, in check_selection
    return self.compute_date(cr, uid, ids, context=context)
  File "/usr/lib64/python2.7/site-packages/openerp-6.1rc1_20120112_173907-py2.7.egg/openerp/addons/project_long_term/wizard/project_compute_phases.py", line 55, in compute_date
    project_pool.schedule_phases(cr, uid, project_ids, context=context)
  File "/usr/lib64/python2.7/site-packages/openerp-6.1rc1_20120112_173907-py2.7.egg/openerp/addons/project_long_term/project_long_term.py", line 238, in schedule_phases
    exec result in local_dict
  File "<string>", line 5

   ^
IndentationError: expected an indented block

This is a partial fix. The user should be warned as to what projects have been
skipped or at least, given the opportunity to schedule the tasks for those
projects.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'crm/report/crm_lead_report.py'
--- crm/report/crm_lead_report.py 2012-01-31 13:36:57 +0000
+++ crm/report/crm_lead_report.py 2012-03-06 23:39:19 +0000
@@ -74,6 +74,7 @@
74 'delay_close': fields.float('Delay to Close',digits=(16,2),readonly=True, group_operator="avg",help="Number of Days to close the case"),74 'delay_close': fields.float('Delay to Close',digits=(16,2),readonly=True, group_operator="avg",help="Number of Days to close the case"),
75 'delay_expected': fields.float('Overpassed Deadline',digits=(16,2),readonly=True, group_operator="avg"),75 'delay_expected': fields.float('Overpassed Deadline',digits=(16,2),readonly=True, group_operator="avg"),
7676
77 'lead_id':fields.many2one('crm.lead', 'Lead', readonly=True),
77 'user_id':fields.many2one('res.users', 'User', readonly=True),78 'user_id':fields.many2one('res.users', 'User', readonly=True),
78 'country_id':fields.many2one('res.country', 'Country', readonly=True),79 'country_id':fields.many2one('res.country', 'Country', readonly=True),
79 'section_id':fields.many2one('crm.case.section', 'Sales Team', readonly=True),80 'section_id':fields.many2one('crm.case.section', 'Sales Team', readonly=True),
@@ -89,6 +90,7 @@
89 domain="['|',('section_id','=',False),('section_id','=',section_id)]" , readonly=True),90 domain="['|',('section_id','=',False),('section_id','=',section_id)]" , readonly=True),
90 'stage_id': fields.many2one ('crm.case.stage', 'Stage', readonly=True, domain="[('section_ids', '=', section_id)]"),91 'stage_id': fields.many2one ('crm.case.stage', 'Stage', readonly=True, domain="[('section_ids', '=', section_id)]"),
91 'partner_id': fields.many2one('res.partner', 'Partner' , readonly=True),92 'partner_id': fields.many2one('res.partner', 'Partner' , readonly=True),
93 'partner_name': fields.char("Lead", size=64,help='The name of the future partner that will be created while converting the lead into an opportunity', readonly=True),
92 'nbr': fields.integer('# of Cases', readonly=True),94 'nbr': fields.integer('# of Cases', readonly=True),
93 'company_id': fields.many2one('res.company', 'Company', readonly=True),95 'company_id': fields.many2one('res.company', 'Company', readonly=True),
94 'priority': fields.selection(crm.AVAILABLE_PRIORITIES, 'Priority'),96 'priority': fields.selection(crm.AVAILABLE_PRIORITIES, 'Priority'),
@@ -124,6 +126,7 @@
124 to_char(c.date_open, 'YYYY-MM-DD') as opening_date,126 to_char(c.date_open, 'YYYY-MM-DD') as opening_date,
125 to_char(c.date_closed, 'YYYY-mm-dd') as date_closed,127 to_char(c.date_closed, 'YYYY-mm-dd') as date_closed,
126128
129 c.id as lead_id,
127 c.state,130 c.state,
128 c.user_id,131 c.user_id,
129 c.probability,132 c.probability,
@@ -136,6 +139,7 @@
136 c.type_id,139 c.type_id,
137 c.categ_id,140 c.categ_id,
138 c.partner_id,141 c.partner_id,
142 c.partner_name,
139 c.country_id,143 c.country_id,
140 c.planned_revenue,144 c.planned_revenue,
141 c.planned_revenue*(c.probability/100) as probable_revenue,145 c.planned_revenue*(c.probability/100) as probable_revenue,
142146
=== modified file 'crm/report/crm_lead_report_view.xml'
--- crm/report/crm_lead_report_view.xml 2011-11-14 09:27:08 +0000
+++ crm/report/crm_lead_report_view.xml 2012-03-06 23:39:19 +0000
@@ -25,16 +25,52 @@
25 <field name="user_id" invisible="1"/>25 <field name="user_id" invisible="1"/>
26 <field name="company_id" invisible="1"/>26 <field name="company_id" invisible="1"/>
27 <field name="partner_id" invisible="1"/>27 <field name="partner_id" invisible="1"/>
28 <field name="partner_name" invisible="1"/>
28 <field name="country_id" invisible="1"/>29 <field name="country_id" invisible="1"/>
29 <field name="nbr" sum="# Leads"/>30 <field name="nbr" sum="# Leads"/>
30 <field name="email" sum="# Mails"/>31 <field name="email" sum="# Mails"/>
31 <field name="delay_open"/>32 <field name="delay_open"/>
32 <field name="delay_close"/>33 <field name="delay_close"/>
33 <field name="planned_revenue"/>34 <field name="planned_revenue"/>
35 <field name="lead_id"/>
34 </tree>36 </tree>
35 </field>37 </field>
36 </record>38 </record>
3739
40<!-- Leads by user and section Form View -->
41
42 <record id="view_report_crm_lead_form" model="ir.ui.view">
43 <field name="name">crm.lead.report.form</field>
44 <field name="model">crm.lead.report</field>
45 <field name="type">form</field>
46 <field name="arch" type="xml">
47 <form string="Lead Analysis">
48 <field name="lead_id" colspan="4"/>
49 <field name="creation_year"/>
50 <field name="creation_month"/>
51 <field name="creation_day"/>
52 <field name="deadline_month"/>
53 <field name="state"/>
54 <field name="stage_id"/>
55 <field name="categ_id"/>
56 <field name="type_id"/>
57 <field name="channel_id"/>
58 <field name="type"/>
59 <field name="priority"/>
60 <field name="section_id"/>
61 <field name="user_id"/>
62 <field name="company_id"/>
63 <field name="partner_id"/>
64 <field name="partner_name"/>
65 <field name="country_id"/>
66 <field name="email"/>
67 <field name="delay_open"/>
68 <field name="delay_close"/>
69 <field name="planned_revenue"/>
70 </form>
71 </field>
72 </record>
73
38<!-- Leads by user and section Graph View -->74<!-- Leads by user and section Graph View -->
3975
40 <record id="view_report_crm_lead_graph" model="ir.ui.view">76 <record id="view_report_crm_lead_graph" model="ir.ui.view">
@@ -126,6 +162,7 @@
126 <newline/>162 <newline/>
127 <group expand="0" string="Extended Filters..." groups="base.group_extended">163 <group expand="0" string="Extended Filters..." groups="base.group_extended">
128 <field name="partner_id"/>164 <field name="partner_id"/>
165 <field name="partner_name"/>
129 <separator orientation="vertical"/>166 <separator orientation="vertical"/>
130 <field name="stage_id" widget="selection" domain="[('section_ids', '=', 'section_id')]" />167 <field name="stage_id" widget="selection" domain="[('section_ids', '=', 'section_id')]" />
131 <field name="categ_id" widget="selection"/>168 <field name="categ_id" widget="selection"/>
@@ -146,6 +183,7 @@
146 domain="[]"183 domain="[]"
147 context="{'group_by':'section_id'}" />184 context="{'group_by':'section_id'}" />
148 <filter string="Partner" icon="terp-partner" context="{'group_by':'partner_id'}" />185 <filter string="Partner" icon="terp-partner" context="{'group_by':'partner_id'}" />
186 <filter string="Lead" icon="terp-partner" context="{'group_by':'partner_name'}"/>
149 <filter string="Country" icon="terp-go-home" context="{'group_by':'country_id'}" />187 <filter string="Country" icon="terp-go-home" context="{'group_by':'country_id'}" />
150 <filter string="Company" icon="terp-go-home"188 <filter string="Company" icon="terp-go-home"
151 domain="[]"189 domain="[]"
@@ -193,6 +231,7 @@
193 <field name="section_id" invisible="1" groups="base.group_extended"/>231 <field name="section_id" invisible="1" groups="base.group_extended"/>
194 <field name="user_id" invisible="1"/>232 <field name="user_id" invisible="1"/>
195 <field name="partner_id" invisible="1"/>233 <field name="partner_id" invisible="1"/>
234 <field name="partner_name" invisible="1"/>
196 <field name="country_id" invisible="1"/>235 <field name="country_id" invisible="1"/>
197 <field name="state" invisible="1"/>236 <field name="state" invisible="1"/>
198 <field name="stage_id" invisible="1"/>237 <field name="stage_id" invisible="1"/>
@@ -210,18 +249,56 @@
210 <field name="delay_expected"/>249 <field name="delay_expected"/>
211 <field name="probability" widget="progressbar"/>250 <field name="probability" widget="progressbar"/>
212 <field name="probable_revenue"/>251 <field name="probable_revenue"/>
252 <field name="lead_id"/>
213 </tree>253 </tree>
214 </field>254 </field>
215 </record>255 </record>
216256
257<!-- Opportunity form view -->
258
259 <record id="view_report_crm_opportunity_form" model="ir.ui.view">
260 <field name="name">crm.lead.report.form</field>
261 <field name="model">crm.lead.report</field>
262 <field name="type">form</field>
263 <field name="arch" type="xml">
264 <form string="Opportunities Analysis">
265 <field name="lead_id" colspan="4"/>
266 <field name="creation_year"/>
267 <field name="creation_month"/>
268 <field name="creation_day"/>
269 <field name="deadline_month"/>
270 <field name="section_id"/>
271 <field name="user_id"/>
272 <field name="partner_id"/>
273 <field name="partner_name"/>
274 <field name="country_id"/>
275 <field name="state" />
276 <field name="stage_id" />
277 <field name="priority" />
278 <field name="categ_id"/>
279 <field name="type_id"/>
280 <field name="channel_id"/>
281 <field name="type"/>
282 <field name="company_id" />
283 <field name="planned_revenue" />
284 <field name="email" string="# of Emails"/>
285 <field name="delay_open"/>
286 <field name="delay_close"/>
287 <field name="delay_expected"/>
288 <field name="probability" widget="progressbar"/>
289 <field name="probable_revenue"/>
290 </form>
291 </field>
292 </record>
293
217<!-- Leads by user and section Action -->294<!-- Leads by user and section Action -->
218295
219 <record id="action_report_crm_lead" model="ir.actions.act_window">296 <record id="action_report_crm_lead" model="ir.actions.act_window">
220 <field name="name">Leads Analysis</field>297 <field name="name">Leads Analysis</field>
221 <field name="res_model">crm.lead.report</field>298 <field name="res_model">crm.lead.report</field>
222 <field name="view_type">form</field>299 <field name="view_type">form</field>
223 <field name="context">{'search_default_year': 1,'search_default_lead': 1, "search_default_user":1, "search_default_this_month":1, 'group_by_no_leaf':1, 'group_by':[]}</field>300 <field name="context">{'search_default_year': 1,'search_default_lead': 1, "search_default_user":1, "search_default_this_month":1, 'group_by':[]}</field>
224 <field name="view_mode">tree,graph</field>301 <field name="view_mode">tree,graph,form</field>
225 <field name="domain">[]</field>302 <field name="domain">[]</field>
226 <field name="help">Leads Analysis allows you to check different CRM related information. Check for treatment delays, number of responses given and emails sent. You can sort out your leads analysis by different groups to get accurate grained analysis.</field>303 <field name="help">Leads Analysis allows you to check different CRM related information. Check for treatment delays, number of responses given and emails sent. You can sort out your leads analysis by different groups to get accurate grained analysis.</field>
227 </record>304 </record>
@@ -237,12 +314,18 @@
237 <field name="view_id" ref="view_report_crm_lead_graph"/>314 <field name="view_id" ref="view_report_crm_lead_graph"/>
238 <field name="act_window_id" ref="action_report_crm_lead"/>315 <field name="act_window_id" ref="action_report_crm_lead"/>
239 </record>316 </record>
317 <record model="ir.actions.act_window.view" id="action_report_crm_lead_form">
318 <field name="sequence" eval="3"/>
319 <field name="view_mode">form</field>
320 <field name="view_id" ref="view_report_crm_lead_form"/>
321 <field name="act_window_id" ref="action_report_crm_lead"/>
322 </record>
240323
241 <record id="action_report_crm_opportunity" model="ir.actions.act_window">324 <record id="action_report_crm_opportunity" model="ir.actions.act_window">
242 <field name="name">Opportunities Analysis</field>325 <field name="name">Opportunities Analysis</field>
243 <field name="res_model">crm.lead.report</field>326 <field name="res_model">crm.lead.report</field>
244 <field name="view_type">form</field>327 <field name="view_type">form</field>
245 <field name="context">{"search_default_year":1,"search_default_opportunity":1, "search_default_user":1,"search_default_this_month":1,'group_by_no_leaf':1,'group_by':[]}</field>328 <field name="context">{"search_default_year":1,"search_default_opportunity":1, "search_default_user":1,"search_default_this_month":1,'group_by':[]}</field>
246 <field name="view_mode">tree,graph</field>329 <field name="view_mode">tree,graph</field>
247 <field name="help">Opportunities Analysis gives you an instant access to your opportunities with information such as the expected revenue, planned cost, missed deadlines or the number of interactions per opportunity. This report is mainly used by the sales manager in order to do the periodic review with the teams of the sales pipeline.</field>330 <field name="help">Opportunities Analysis gives you an instant access to your opportunities with information such as the expected revenue, planned cost, missed deadlines or the number of interactions per opportunity. This report is mainly used by the sales manager in order to do the periodic review with the teams of the sales pipeline.</field>
248 </record>331 </record>
@@ -261,6 +344,13 @@
261 <field name="act_window_id" ref="action_report_crm_opportunity"/>344 <field name="act_window_id" ref="action_report_crm_opportunity"/>
262 </record>345 </record>
263346
347 <record model="ir.actions.act_window.view" id="action_report_crm_opportunity_form">
348 <field name="sequence" eval="3"/>
349 <field name="view_mode">form</field>
350 <field name="view_id" ref="view_report_crm_opportunity_form"/>
351 <field name="act_window_id" ref="action_report_crm_opportunity"/>
352 </record>
353
264 <menuitem name="Leads Analysis" id="menu_report_crm_leads_tree"354 <menuitem name="Leads Analysis" id="menu_report_crm_leads_tree"
265 groups="base.group_extended"355 groups="base.group_extended"
266 parent="base.next_id_64" action="action_report_crm_lead" sequence="3"/>356 parent="base.next_id_64" action="action_report_crm_lead" sequence="3"/>
267357
=== modified file 'hr_timesheet_sheet/hr_timesheet_sheet_view.xml'
--- hr_timesheet_sheet/hr_timesheet_sheet_view.xml 2012-02-13 15:27:55 +0000
+++ hr_timesheet_sheet/hr_timesheet_sheet_view.xml 2012-03-06 23:39:19 +0000
@@ -95,7 +95,7 @@
95 <button name="sign_out" string="Sign Out" type="object" icon="terp-gtk-jump-to-rtl"/>95 <button name="sign_out" string="Sign Out" type="object" icon="terp-gtk-jump-to-rtl"/>
96 <field name="total_attendance_day" widget="float_time" colspan="4"/>96 <field name="total_attendance_day" widget="float_time" colspan="4"/>
97 </group>97 </group>
98 <field colspan="4" context="{'date':date_current,'user_id':user_id}" domain="[('name','=',date_current)]" name="timesheet_ids" nolabel="1">98 <field colspan="4" context="{'date':date_current,'user_id':uid}" domain="[('name','=',date_current)]" name="timesheet_ids" nolabel="1">
99 <tree editable="top" string="Timesheet Lines">99 <tree editable="top" string="Timesheet Lines">
100 <field invisible="1" name="date"/>100 <field invisible="1" name="date"/>
101 <field domain="[('type','=','normal'), ('state', '&lt;&gt;', 'close')]" name="account_id" on_change="on_change_account_id(account_id)"/>101 <field domain="[('type','=','normal'), ('state', '&lt;&gt;', 'close')]" name="account_id" on_change="on_change_account_id(account_id)"/>
102102
=== modified file 'project/project.py'
--- project/project.py 2012-02-28 14:08:16 +0000
+++ project/project.py 2012-03-06 23:39:19 +0000
@@ -666,6 +666,7 @@
666 'id': fields.integer('ID', readonly=True),666 'id': fields.integer('ID', readonly=True),
667 'color': fields.integer('Color Index'),667 'color': fields.integer('Color Index'),
668 'user_email': fields.related('user_id', 'user_email', type='char', string='User Email', readonly=True),668 'user_email': fields.related('user_id', 'user_email', type='char', string='User Email', readonly=True),
669 'work_load': fields.integer('Workload (%)', help='Indicates how much time each person is to spend working on this task as a percentage of their total working hours. The default is 100%. The value must be greater than 0, else it will be treated as 100%.'),
669 }670 }
670671
671 _defaults = {672 _defaults = {
@@ -676,7 +677,7 @@
676 'sequence': 10,677 'sequence': 10,
677 'active': True,678 'active': True,
678 'user_id': lambda obj, cr, uid, context: uid,679 'user_id': lambda obj, cr, uid, context: uid,
679 'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'project.task', context=c)680 'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'project.task', context=c),
680 }681 }
681682
682 _order = "priority, sequence, date_start, name, id"683 _order = "priority, sequence, date_start, name, id"
@@ -1067,8 +1068,12 @@
1067 continue1068 continue
1068 result += '''1069 result += '''
1069%sdef Task_%s():1070%sdef Task_%s():
1071%s load = %4.2f
1070%s todo = \"%.2fH\"1072%s todo = \"%.2fH\"
1071%s effort = \"%.2fH\"''' % (ident,task.id, ident,task.remaining_hours, ident,task.total_hours)1073%s effort = \"%.2fH\"''' % ( ident,task.id,
1074 ident,((task.work_load / 100.0) if task.work_load else 1.0),
1075 ident,task.remaining_hours,
1076 ident,task.total_hours )
1072 start = []1077 start = []
1073 for t2 in task.parent_ids:1078 for t2 in task.parent_ids:
1074 start.append("up.Task_%s.end" % (t2.id,))1079 start.append("up.Task_%s.end" % (t2.id,))
10751080
=== modified file 'project/project_view.xml'
--- project/project_view.xml 2012-02-13 15:27:55 +0000
+++ project/project_view.xml 2012-03-06 23:39:19 +0000
@@ -228,6 +228,9 @@
228 <field name="total_hours" widget="float_time"/>228 <field name="total_hours" widget="float_time"/>
229 <field name="date_deadline" attrs="{'readonly':[('state','in',['done', 'cancelled'])]}"/>229 <field name="date_deadline" attrs="{'readonly':[('state','in',['done', 'cancelled'])]}"/>
230 <field name="user_id" select="1" attrs="{'readonly':[('state','in',['done', 'cancelled'])]}"/>230 <field name="user_id" select="1" attrs="{'readonly':[('state','in',['done', 'cancelled'])]}"/>
231 <field name="work_load"/>
232 </group>
233 <group colspan="4">
231 <field name="progress" widget="progressbar"/>234 <field name="progress" widget="progressbar"/>
232 </group>235 </group>
233 <notebook colspan="4">236 <notebook colspan="4">
234237
=== modified file 'project_long_term/project_long_term.py'
--- project_long_term/project_long_term.py 2012-01-31 13:36:57 +0000
+++ project_long_term/project_long_term.py 2012-03-06 23:39:19 +0000
@@ -224,9 +224,16 @@
224 ids = [ids]224 ids = [ids]
225 projects = self.browse(cr, uid, ids, context=context)225 projects = self.browse(cr, uid, ids, context=context)
226 result = self._schedule_header(cr, uid, ids, context=context)226 result = self._schedule_header(cr, uid, ids, context=context)
227 do_schedule = False
227 for project in projects:228 for project in projects:
228 result += self._schedule_project(cr, uid, project, context=context)229 if len(project.phase_ids) > 0:
229 result += self.pool.get('project.phase').generate_phase(cr, uid, project.phase_ids, context=context)230 result += self._schedule_project(cr, uid, project, context=context)
231 result += self.pool.get('project.phase').generate_phase(cr, uid, project.phase_ids, context=context)
232 do_schedule = True
233
234 if not do_schedule:
235 # Nothing to do here
236 return True
230237
231 local_dict = {}238 local_dict = {}
232 exec result in local_dict239 exec result in local_dict
@@ -256,6 +263,21 @@
256 'date_start': p.start.strftime('%Y-%m-%d %H:%M:%S'),263 'date_start': p.start.strftime('%Y-%m-%d %H:%M:%S'),
257 'date_end': p.end.strftime('%Y-%m-%d %H:%M:%S')264 'date_end': p.end.strftime('%Y-%m-%d %H:%M:%S')
258 }, context=context)265 }, context=context)
266
267 # Schedule sub-tasks
268 for task in phase.task_ids:
269 if task.state in ('done','cancelled'):
270 continue
271
272 t = getattr(p, 'Task_%d' % (task.id,))
273 self.pool.get('project.task').write(cr, uid, [task.id], {
274 'date_start': t.start.strftime('%Y-%m-%d %H:%M:%S'),
275 'date_end': t.end.strftime('%Y-%m-%d %H:%M:%S'),
276 }, context=context)
277 if (not task.user_id) and (t.booked_resource):
278 self.pool.get('project.task').write(cr, uid, [task.id], {
279 'user_id': int(t.booked_resource[0].name[5:]),
280 }, context=context)
259 return True281 return True
260project()282project()
261283
262284
=== modified file 'resource/faces/pcalendar.py'
--- resource/faces/pcalendar.py 2011-12-19 16:54:40 +0000
+++ resource/faces/pcalendar.py 2012-03-06 23:39:19 +0000
@@ -895,7 +895,16 @@
895 def _recalc_working_time(self):895 def _recalc_working_time(self):
896 def slot_sum_time(day):896 def slot_sum_time(day):
897 slots = self.working_times.get(day, DEFAULT_WORKING_DAYS[day])897 slots = self.working_times.get(day, DEFAULT_WORKING_DAYS[day])
898 return sum(map(lambda slot: slot[1] - slot[0], slots))898 def time_diff(times):
899 (start, end) = times
900 if end == start:
901 return 24*60 # 24 hours
902
903 diff = end - start
904 if end < start:
905 diff += (24*60)
906 return diff
907 return sum(map(time_diff, slots))
899908
900 self.day_times = map(slot_sum_time, range(0, 7))909 self.day_times = map(slot_sum_time, range(0, 7))
901 self.week_time = sum(self.day_times)910 self.week_time = sum(self.day_times)
902911
=== modified file 'resource/resource.py'
--- resource/resource.py 2011-12-21 12:37:24 +0000
+++ resource/resource.py 2012-03-06 23:39:19 +0000
@@ -19,7 +19,7 @@
19#19#
20##############################################################################20##############################################################################
2121
22from datetime import datetime, timedelta22from datetime import datetime, timedelta, time, date
23import math23import math
24from faces import *24from faces import *
25from osv import fields, osv25from osv import fields, osv
@@ -28,6 +28,7 @@
28from itertools import groupby28from itertools import groupby
29from operator import itemgetter29from operator import itemgetter
3030
31import pytz
3132
32class resource_calendar(osv.osv):33class resource_calendar(osv.osv):
33 _name = "resource.calendar"34 _name = "resource.calendar"
@@ -279,8 +280,9 @@
279 hour_part = split_list[0]280 hour_part = split_list[0]
280 mins_part = split_list[1]281 mins_part = split_list[1]
281 round_mins = int(round(float(mins_part) * 60,-2))282 round_mins = int(round(float(mins_part) * 60,-2))
282 converted_string = hour_part + ':' + str(round_mins)[0:2]283 return time(int(hour_part), round_mins)
283 return converted_string284 #converted_string = hour_part + ':' + str(round_mins)[0:2]
285 #return converted_string
284286
285class resource_resource(osv.osv):287class resource_resource(osv.osv):
286 _name = "resource.resource"288 _name = "resource.resource"
@@ -366,51 +368,102 @@
366 Change the format of working calendar from 'Openerp' format to bring it into 'Faces' format.368 Change the format of working calendar from 'Openerp' format to bring it into 'Faces' format.
367 @param calendar_id : working calendar of the project369 @param calendar_id : working calendar of the project
368 """370 """
371 tz = pytz.utc
372 if context and ('tz' in context):
373 tz = pytz.timezone(context['tz'])
374
375 wktime_local = None
376 week_days = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']
369 if not calendar_id:377 if not calendar_id:
370 # Calendar is not specified: working days: 24/7378 # Calendar is not specified: working days: some sane default
371 return [('fri', '8:0-12:0','13:0-17:0'), ('thu', '8:0-12:0','13:0-17:0'), ('wed', '8:0-12:0','13:0-17:0'), 379 wktime_local = [
372 ('mon', '8:0-12:0','13:0-17:0'), ('tue', '8:0-12:0','13:0-17:0')]380 (0, time(8,0), time(12,0)),
373 resource_attendance_pool = self.pool.get('resource.calendar.attendance')381 (0, time(13,0), time(17,0)),
374 time_range = "8:00-8:00"382 (1, time(8,0), time(12,0)),
375 non_working = ""383 (1, time(13,0), time(17,0)),
376 week_days = {"0": "mon", "1": "tue", "2": "wed","3": "thu", "4": "fri", "5": "sat", "6": "sun"}384 (2, time(8,0), time(12,0)),
377 wk_days = {}385 (2, time(13,0), time(17,0)),
378 wk_time = {}386 (3, time(8,0), time(12,0)),
379 wktime_list = []387 (3, time(13,0), time(17,0)),
388 (4, time(8,0), time(12,0)),
389 (4, time(13,0), time(17,0)),
390 ]
391 #return [('fri', '8:0-12:0','13:0-17:0'), ('thu', '8:0-12:0','13:0-17:0'), ('wed', '8:0-12:0','13:0-17:0'),
392 # ('mon', '8:0-12:0','13:0-17:0'), ('tue', '8:0-12:0','13:0-17:0')]
393 else:
394 resource_attendance_pool = self.pool.get('resource.calendar.attendance')
395 non_working = ""
396 wktime_local = []
397
398 week_ids = resource_attendance_pool.search(cr, uid, [('calendar_id', '=', calendar_id)], context=context)
399 weeks = resource_attendance_pool.read(cr, uid, week_ids, ['dayofweek', 'hour_from', 'hour_to'], context=context)
400 # Convert time formats into appropriate format required
401 # and create lists inside wktime_local.
402 for week in weeks:
403 res_str = ""
404 day = None
405 if week['dayofweek']:
406 day = int(week['dayofweek'])
407 else:
408 raise osv.except_osv(_('Configuration Error!'),_('Make sure the Working time has been configured with proper week days!'))
409 hour_from = convert_timeformat(week['hour_from'])
410 hour_to = convert_timeformat(week['hour_to'])
411 wktime_local.append((day, hour_from, hour_to))
412
413 # We now have working hours _in local time_. Non-working days are an
414 # empty list, while working days are a list of tuples, consisting of a
415 # start time and an end time. We will convert these to UTC for time
416 # calculation purposes.
417
418 # We need to get this into a dict
419 # which will be in the following format:
420 # { 'day': [(time(9,0), time(17,0)), ...], ... }
421 wktime_utc = {}
422
423 # NOTE: This may break with regards to DST!
424 for (day, start, end) in wktime_local:
425 # Convert start time to UTC
426 start_dt_local = datetime.combine(date.today(), start.replace(tzinfo=tz))
427 start_dt_utc = start_dt_local.astimezone(pytz.utc)
428 start_dt_day = (day + (start_dt_utc.date() - start_dt_local.date()).days) % 7
429
430 # Convert end time to UTC
431 end_dt_local = datetime.combine(date.today(), end.replace(tzinfo=tz))
432 end_dt_utc = end_dt_local.astimezone(pytz.utc)
433 end_dt_day = (day + (end_dt_utc.date() - end_dt_local.date()).days) % 7
434
435 # Are start and end still on the same day?
436 if start_dt_day == end_dt_day:
437 day_name = week_days[start_dt_day]
438 if day_name not in wktime_utc:
439 wktime_utc[day_name] = []
440 wktime_utc[day_name].append((start_dt_utc.time(), end_dt_utc.time()))
441 else:
442 day_start_name = week_days[start_dt_day]
443 if day_start_name not in wktime_utc:
444 wktime_utc[day_start_name] = []
445 # We go until midnight that day
446 wktime_utc[day_start_name].append((start_dt_utc.time(), time(0,0)))
447
448 day_end_name = week_days[end_dt_day]
449 if day_end_name not in wktime_utc:
450 wktime_utc[day_end_name] = []
451 # Then resume from midnight that day
452 wktime_utc[day_end_name].append((time(0,0), end_dt_utc.time()))
453
454 # Now having gotten a list of times together, generate the final output
380 wktime_cal = []455 wktime_cal = []
381 week_ids = resource_attendance_pool.search(cr, uid, [('calendar_id', '=', calendar_id)], context=context)456 for day, times in wktime_utc.iteritems():
382 weeks = resource_attendance_pool.read(cr, uid, week_ids, ['dayofweek', 'hour_from', 'hour_to'], context=context)457 # Sort the times
383 # Convert time formats into appropriate format required458 times.sort()
384 # and create a list like [('mon', '8:00-12:00'), ('mon', '13:00-18:00')]459 wktime = ['{0}-{1}'.format(s.strftime('%H:%M'), e.strftime('%H:%M')) for (s, e) in times]
385 for week in weeks:460 wktime.insert(0, day)
386 res_str = ""461 wktime_cal.append(tuple(wktime))
387 day = None462 # Finally, add in non-working days
388 if week_days.get(week['dayofweek'],False):463 for day in week_days:
389 day = week_days[week['dayofweek']]464 if day not in wktime_utc:
390 wk_days[week['dayofweek']] = week_days[week['dayofweek']]465 wktime_cal.append((day, None))
391 else:466
392 raise osv.except_osv(_('Configuration Error!'),_('Make sure the Working time has been configured with proper week days!'))
393 hour_from_str = convert_timeformat(week['hour_from'])
394 hour_to_str = convert_timeformat(week['hour_to'])
395 res_str = hour_from_str + '-' + hour_to_str
396 wktime_list.append((day, res_str))
397 # Convert into format like [('mon', '8:00-12:00', '13:00-18:00')]
398 for item in wktime_list:
399 if wk_time.has_key(item[0]):
400 wk_time[item[0]].append(item[1])
401 else:
402 wk_time[item[0]] = [item[0]]
403 wk_time[item[0]].append(item[1])
404 for k,v in wk_time.items():
405 wktime_cal.append(tuple(v))
406 # Add for the non-working days like: [('sat, sun', '8:00-8:00')]
407 for k, v in wk_days.items():
408 if week_days.has_key(k):
409 week_days.pop(k)
410 for v in week_days.itervalues():
411 non_working += v + ','
412 if non_working:
413 wktime_cal.append((non_working[:-1], time_range))
414 return wktime_cal467 return wktime_cal
415468
416resource_resource()469resource_resource()

Subscribers

People subscribed via source and target branches

to all changes: