diff --git a/addons/account/account_installer.xml b/addons/account/account_installer.xml
index a9de51c3afb..a3570fae79a 100644
--- a/addons/account/account_installer.xml
+++ b/addons/account/account_installer.xml
@@ -73,7 +73,7 @@
- Add extra Accounting Addons to the ones already installed. Remember you can always install them at a later stage.
+ Add extra Accounting functionalities to the ones already installed.Configure
diff --git a/addons/account/partner_view.xml b/addons/account/partner_view.xml
index d53fb9fe80a..ca489acd9bd 100644
--- a/addons/account/partner_view.xml
+++ b/addons/account/partner_view.xml
@@ -72,7 +72,7 @@
2
-
+
diff --git a/addons/association/profile_association.py b/addons/association/profile_association.py
index f102d710fd8..eb9ac398500 100644
--- a/addons/association/profile_association.py
+++ b/addons/association/profile_association.py
@@ -27,13 +27,18 @@ class profile_association_config_install_modules_wizard(osv.osv_memory):
_inherit = 'res.config.installer'
_columns = {
- 'hr_expense':fields.boolean('Expenses Tracking', help="Tracks the personal expenses process, from the employee expense encoding, to the reimbursement of the employee up to the reinvoicing to the final customer."),
- 'project':fields.boolean('Project Management'),
- 'event_project':fields.boolean('Organization and management of Events', help="This module allows you to create retro planning for managing your events."),
+ 'hr_expense':fields.boolean('Expenses Tracking', help="Tracks and manages employee expenses, and can "
+ "automatically re-invoice clients if the expenses are "
+ "project-related."),
+ 'project':fields.boolean('Project Management',
+ help="Helps you manage your projects and tasks by tracking them, "
+ "generating plannings, etc..."),
+ 'event_project':fields.boolean('Events', help="Helps you to manage and organize your events."),
'project_gtd':fields.boolean('Getting Things Done',
help="GTD is a methodology to efficiently organise yourself and your tasks. This module fully integrates GTD principle with OpenERP's project management."),
- 'wiki': fields.boolean('Wiki',
- help="An integrated wiki content management system. This is really usefull to manage FAQ, quality manuals, etc.")
+ 'wiki': fields.boolean('Wiki', help="Lets you create wiki pages and page groups in order "
+ "to keep track of business knowledge and share it with "
+ "and between your employees."),
}
profile_association_config_install_modules_wizard()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/base_action_rule/base_action_rule_view.xml b/addons/base_action_rule/base_action_rule_view.xml
index 526fe55f4a3..755f6680d34 100644
--- a/addons/base_action_rule/base_action_rule_view.xml
+++ b/addons/base_action_rule/base_action_rule_view.xml
@@ -14,11 +14,13 @@
form
diff --git a/addons/base_setup/installer.py b/addons/base_setup/installer.py
index 0c8478ba57d..f415447e5fb 100644
--- a/addons/base_setup/installer.py
+++ b/addons/base_setup/installer.py
@@ -58,7 +58,7 @@ class base_setup_installer(osv.osv_memory):
help="Helps you manage your purchase-related processes such as "
"requests for quotations, supplier invoices, etc..."),
'hr':fields.boolean('Human Resources',
- help="Helps you manage your human resources by encoding your employees structure, generating work sheets, tracking attendance and more"),
+ help="Helps you manage your human resources by encoding your employees structure, generating work sheets, tracking attendance and more."),
'point_of_sale':fields.boolean('Point of Sales',
help="Helps you get the most out of your points of sales with "
"fast sale encoding, simplified payment mode encoding, "
@@ -74,7 +74,7 @@ class base_setup_installer(osv.osv_memory):
# Vertical modules
'product_expiry':fields.boolean('Food Industry',
help="Installs a preselected set of OpenERP applications "
- "which will help you manage your industry"),
+ "which will help you manage your industry."),
'association':fields.boolean('Associations',
help="Installs a preselected set of OpenERP "
"applications which will help you manage your association "
diff --git a/addons/caldav/caldav_node.py b/addons/caldav/caldav_node.py
index 63e683bafb7..55be22f198e 100644
--- a/addons/caldav/caldav_node.py
+++ b/addons/caldav/caldav_node.py
@@ -103,7 +103,12 @@ class node_calendar_collection(nodes.node_dir):
class node_calendar(nodes.node_class):
our_type = 'collection'
DAV_PROPS = {
- "http://calendarserver.org/ns/" : ('getctag',),
+ "DAV:": ('principal-collection-set'),
+ "http://cal.me.com/_namespace/" : ('user-state'),
+ "http://calendarserver.org/ns/" : (
+ 'dropbox-home-URL',
+ 'notification-URL',
+ 'getctag',),
'http://groupdav.org/': ('resourcetype',),
"urn:ietf:params:xml:ns:caldav" : (
'calendar-description',
@@ -114,6 +119,7 @@ class node_calendar(nodes.node_class):
'schedule-outbox-URL',)}
DAV_M_NS = {
"DAV:" : '_get_dav',
+ "http://cal.me.com/_namespace/": '_get_dav',
'http://groupdav.org/': '_get_gdav',
"http://calendarserver.org/ns/" : '_get_dav',
"urn:ietf:params:xml:ns:caldav" : '_get_caldav'}
@@ -134,6 +140,35 @@ class node_calendar(nodes.node_class):
result = self._get_ttag(cr) + ':' + str(time.time())
return str(result)
+ def _get_dav_dropbox_home_URL(self, cr):
+ import xml.dom.minidom
+ import urllib
+ uid = self.context.uid
+ ctx = self.context.context.copy()
+ ctx.update(self.dctx)
+ calendar_obj = self.context._dirobj.pool.get('basic.calendar')
+ calendar = calendar_obj.browse(cr, uid, self.calendar_id, context=ctx)
+ res = '%s/%s' %(calendar.collection_id.name, calendar.name)
+ url = urllib.quote('/%s/%s' % (cr.dbname, res))
+ return url
+
+ def _get_dav_notification_URL(self, cr):
+ import xml.dom.minidom
+ import urllib
+ uid = self.context.uid
+ ctx = self.context.context.copy()
+ ctx.update(self.dctx)
+ calendar_obj = self.context._dirobj.pool.get('basic.calendar')
+ calendar = calendar_obj.browse(cr, uid, self.calendar_id, context=ctx)
+ res = '%s/%s' %(calendar.collection_id.name, calendar.name)
+ url = urllib.quote('/%s/%s' % (cr.dbname, res))
+ return url
+
+ def _get_dav_user_state(self, cr):
+ #TODO
+ return True
+
+
def get_dav_resourcetype(self, cr):
res = [ ('collection', 'DAV:'),
(str(self.cal_type + '-collection'), 'http://groupdav.org/'),
@@ -258,6 +293,86 @@ class node_calendar(nodes.node_class):
def rmcol(self, cr):
return False
+
+ def _get_caldav_calendar_data(self, cr):
+ res = []
+ for child in self.children(cr):
+ res.append(child._get_caldav_calendar_data(cr))
+ return res
+
+ def _get_caldav_calendar_description(self, cr):
+ uid = self.context.uid
+ calendar_obj = self.context._dirobj.pool.get('basic.calendar')
+ ctx = self.context.context.copy()
+ ctx.update(self.dctx)
+ calendar = calendar_obj.browse(cr, uid, self.calendar_id, context=ctx)
+ return calendar.description
+
+ def _get_dav_principal_collection_set(self, uri):
+ import urllib
+ uid = self.context.uid
+ ctx = self.context.context.copy()
+ ctx.update(self.dctx)
+ calendar_obj = self.context._dirobj.pool.get('basic.calendar')
+ calendar = calendar_obj.browse(cr, uid, self.calendar_id, context=ctx)
+ res = '%s/%s' %(calendar.collection_id.name, calendar.name)
+ doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None)
+ href = doc.documentElement
+ href.tagName = 'D:href'
+ huri = doc.createTextNode(urllib.quote('/%s/%s' % (cr.dbname, res)))
+ href.appendChild(huri)
+ return href
+
+ def _get_caldav_calendar_home_set(self, cr):
+ import xml.dom.minidom
+ import urllib
+ uid = self.context.uid
+ ctx = self.context.context.copy()
+ ctx.update(self.dctx)
+ doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None)
+
+ calendar_obj = self.context._dirobj.pool.get('basic.calendar')
+ calendar = calendar_obj.browse(cr, uid, self.calendar_id, context=ctx)
+ huri = doc.createTextNode(urllib.quote('/%s/%s' % (cr.dbname, calendar.collection_id.name)))
+ href = doc.documentElement
+ href.tagName = 'D:href'
+ href.appendChild(huri)
+ return href
+
+ def _get_caldav_calendar_user_address_set(self, cr):
+ import xml.dom.minidom
+ dirobj = self.context._dirobj
+ uid = self.context.uid
+ ctx = self.context.context.copy()
+ ctx.update(self.dctx)
+ user_obj = self.context._dirobj.pool.get('res.users')
+ user = user_obj.browse(cr, uid, uid, context=ctx)
+ doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None)
+ href = doc.documentElement
+ href.tagName = 'D:href'
+ huri = doc.createTextNode('MAILTO:' + str(user.email) or str(user.name))
+ href.appendChild(huri)
+ return href
+
+ def _get_caldav_schedule_outbox_URL(self, cr):
+ return self._get_caldav_schedule_inbox_URL(cr)
+
+ def _get_caldav_schedule_inbox_URL(self, cr):
+ import xml.dom.minidom
+ import urllib
+ uid = self.context.uid
+ ctx = self.context.context.copy()
+ ctx.update(self.dctx)
+ calendar_obj = self.context._dirobj.pool.get('basic.calendar')
+ calendar = calendar_obj.browse(cr, uid, self.calendar_id, context=ctx)
+ res = '%s/%s' %(calendar.collection_id.name, calendar.name)
+ doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None)
+ href = doc.documentElement
+ href.tagName = 'D:href'
+ huri = doc.createTextNode(urllib.quote('/%s/%s' % (cr.dbname, res)))
+ href.appendChild(huri)
+ return href
+
class res_node_calendar(nodes.node_class):
our_type = 'file'
@@ -309,6 +424,9 @@ class res_node_calendar(nodes.node_class):
context.update({'model': self.model, 'res_id':self.res_id})
res = calendar_obj.export_cal(cr, uid, [self.calendar_id], context=context)
return res
+
+ def _get_caldav_calendar_data(self, cr):
+ return self.get_data(cr)
def get_data_len(self, cr, fil_obj = None):
return self.content_length
@@ -327,67 +445,6 @@ class res_node_calendar(nodes.node_class):
res = '%d' % (self.calendar_id)
return res
- def _get_caldav_calendar_data(self, cr):
- return self.get_data(cr)
-
-
- def _get_caldav_calendar_description(self, cr):
- uid = self.context.uid
- calendar_obj = self.context._dirobj.pool.get('basic.calendar')
- ctx = self.context.context.copy()
- ctx.update(self.dctx)
- calendar = calendar_obj.browse(cr, uid, self.calendar_id, context=ctx)
- return calendar.description
-
-
- def _get_caldav_calendar_home_set(self, cr):
- import xml.dom.minidom
- import urllib
- uid = self.context.uid
- ctx = self.context.context.copy()
- ctx.update(self.dctx)
- doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None)
-
- calendar_obj = self.context._dirobj.pool.get('basic.calendar')
- calendar = calendar_obj.browse(cr, uid, self.calendar_id, context=ctx)
- huri = doc.createTextNode(urllib.quote('/%s/%s' % (cr.dbname, calendar.collection_id.name)))
- href = doc.documentElement
- href.tagName = 'D:href'
- href.appendChild(huri)
- return href
-
- def _get_caldav_calendar_user_address_set(self, cr):
- import xml.dom.minidom
- dirobj = self.context._dirobj
- uid = self.context.uid
- ctx = self.context.context.copy()
- ctx.update(self.dctx)
- user_obj = self.context._dirobj.pool.get('res.users')
- user = user_obj.browse(cr, uid, uid, context=ctx)
- doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None)
- href = doc.documentElement
- href.tagName = 'D:href'
- huri = doc.createTextNode('MAILTO:' + user.email)
- href.appendChild(huri)
- return href
-
-
- def _get_caldav_schedule_inbox_URL(self, cr):
- import xml.dom.minidom
- import urllib
- uid = self.context.uid
- ctx = self.context.context.copy()
- ctx.update(self.dctx)
- calendar_obj = self.context._dirobj.pool.get('basic.calendar')
- calendar = calendar_obj.browse(cr, uid, self.calendar_id, context=ctx)
- res = '%s/%s' %(calendar.name, calendar.collection_id.name)
- doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None)
- href = doc.documentElement
- href.tagName = 'D:href'
- huri = doc.createTextNode(urllib.quote('/%s/%s' % (cr.dbname, res)))
- href.appendChild(huri)
- return href
-
def rm(self, cr):
uid = self.context.uid
@@ -401,7 +458,6 @@ class res_node_calendar(nodes.node_class):
return res
- def _get_caldav_schedule_outbox_URL(self, cr):
- return self._get_caldav_schedule_inbox_URL(cr)
+
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4
diff --git a/addons/caldav/calendar.py b/addons/caldav/calendar.py
index 01c35880fbb..4f9afb034a4 100644
--- a/addons/caldav/calendar.py
+++ b/addons/caldav/calendar.py
@@ -453,7 +453,7 @@ class CalDAV(object):
else:
for key1, val1 in self.ical_get(field, 'mapping').items():
if val1 == data[map_field]:
- vevent.add(field).value = key1
+ vevent.add(field).value = key1.upper()
return vevent
def check_import(self, cr, uid, vals, context=None):
diff --git a/addons/crm/crm.py b/addons/crm/crm.py
index c8dde37d9e5..9b4f9e2ef96 100644
--- a/addons/crm/crm.py
+++ b/addons/crm/crm.py
@@ -587,7 +587,7 @@ class crm_case_categ(osv.osv):
_description = "Category of case"
_columns = {
- 'name': fields.char('Case Category Name', size=64, required=True, translate=True),
+ 'name': fields.char('Name', size=64, required=True, translate=True),
'section_id': fields.many2one('crm.case.section', 'Sales Team'),
'object_id': fields.many2one('ir.model', 'Object Name'),
}
@@ -636,7 +636,7 @@ class crm_case_stage(osv.osv):
'section_id': fields.many2one('crm.case.section', 'Sales Team'),
'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of case stages."),
'object_id': fields.many2one('ir.model', 'Object Name'),
- 'probability': fields.float('Probability (%)', required=True),
+ 'probability': fields.float('Probability (%)', required=True, help="This percentage depicts the default/average probability of the Case for this stage to be a success"),
'on_change': fields.boolean('Change Probability Automatically', \
help="Change Probability on next and previous stages."),
'requirements': fields.text('Requirements')
diff --git a/addons/crm/crm_installer.py b/addons/crm/crm_installer.py
index 6797afc62e0..3860a69b51c 100644
--- a/addons/crm/crm_installer.py
+++ b/addons/crm/crm_installer.py
@@ -33,15 +33,15 @@ class crm_installer(osv.osv_memory):
_columns = {
'name': fields.char('Name', size=64),
- 'crm_helpdesk': fields.boolean('Helpdesk', help="Manages an Helpdesk service."),
+ 'crm_helpdesk': fields.boolean('Helpdesk', help="Manages a Helpdesk service."),
'crm_fundraising': fields.boolean('Fundraising', help="This may help associations in their fundraising process and tracking."),
'crm_claim': fields.boolean('Claims', help="Manages the suppliers and customers claims, including your corrective or preventive actions."),
'crm_caldav': fields.boolean('Calendar Synchronizing', help="Helps you to synchronize the meetings with other calendar clients and mobiles."),
'sale_crm': fields.boolean('Opportunity to Quotation', help="This module relates sale from opportunity cases in the CRM."),
- 'fetchmail': fields.boolean('Fetch Emails', help="Fetchmail Server."),
- 'thunderbird': fields.boolean('Thunderbird', help="Allows you to link your e-mail to OpenERP's documents. You can attach it to any existing one in OpenERP or create a new one"),
- 'outlook': fields.boolean('MS-Outlook', help="Allows you to link your e-mail to OpenERP's documents. You can attach it to any existing one in OpenERP or create a new one"),
- 'wiki_sale_faq': fields.boolean('Sale FAQ', help="Sale FAQ."),
+ 'fetchmail': fields.boolean('Fetch Emails', help="Allows you to receive E-Mails from POP/IMAP server."),
+ 'thunderbird': fields.boolean('Thunderbird', help="Allows you to link your e-mail to OpenERP's documents. You can attach it to any existing one in OpenERP or create a new one."),
+ 'outlook': fields.boolean('MS-Outlook', help="Allows you to link your e-mail to OpenERP's documents. You can attach it to any existing one in OpenERP or create a new one."),
+ 'wiki_sale_faq': fields.boolean('Sale FAQ', help="Helps you manage wiki pages for Frequently Asked Questions on Sales Application."),
}
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
diff --git a/addons/crm/crm_installer_view.xml b/addons/crm/crm_installer_view.xml
index 5fad3f41a3d..ece3bae31ec 100644
--- a/addons/crm/crm_installer_view.xml
+++ b/addons/crm/crm_installer_view.xml
@@ -16,7 +16,7 @@
- Enhance your CRM basic Application with additional Addons.
+ Enhance your core CRM Application with additional functionalities.13
diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py
index da09795547a..0a552a4165a 100644
--- a/addons/crm/crm_lead.py
+++ b/addons/crm/crm_lead.py
@@ -125,6 +125,7 @@ class crm_lead(crm_case, osv.osv):
domain="['|',('section_id','=',section_id),('section_id','=',False)]"),
'channel_id': fields.many2one('res.partner.canal', 'Channel'),
+ 'contact_name': fields.char('Contact Name', size=64),
'partner_name': fields.char("Partner Name", size=64),
'optin': fields.boolean('Opt-In'),
'optout': fields.boolean('Opt-Out'),
diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml
index 41d41ef0502..2df1369bbb1 100644
--- a/addons/crm/crm_lead_view.xml
+++ b/addons/crm/crm_lead_view.xml
@@ -55,7 +55,7 @@
-
@@ -235,8 +238,8 @@
-
-
+
+
@@ -299,7 +302,7 @@
-
+
@@ -337,6 +340,7 @@
help="Show Sales Team"/>
+
@@ -365,7 +369,7 @@
-
diff --git a/addons/crm/crm_meeting_view.xml b/addons/crm/crm_meeting_view.xml
index 55ef2c7d5e3..06cb0280567 100644
--- a/addons/crm/crm_meeting_view.xml
+++ b/addons/crm/crm_meeting_view.xml
@@ -317,32 +317,31 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/crm/crm_opportunity_view.xml b/addons/crm/crm_opportunity_view.xml
index 8101a0bcfb2..c2713b91f89 100644
--- a/addons/crm/crm_opportunity_view.xml
+++ b/addons/crm/crm_opportunity_view.xml
@@ -133,7 +133,7 @@
-
+
-
-
@@ -272,7 +272,7 @@
+
+
+
-
-
-
-
+
diff --git a/addons/crm/crm_phonecall_menu.xml b/addons/crm/crm_phonecall_menu.xml
index 481e92ec134..8585ddc7fe4 100644
--- a/addons/crm/crm_phonecall_menu.xml
+++ b/addons/crm/crm_phonecall_menu.xml
@@ -13,7 +13,8 @@
groups="base.group_extended"
/>
-
+
diff --git a/addons/crm/crm_phonecall_view.xml b/addons/crm/crm_phonecall_view.xml
index 4f60b91b3c2..0832c0a16ee 100644
--- a/addons/crm/crm_phonecall_view.xml
+++ b/addons/crm/crm_phonecall_view.xml
@@ -16,19 +16,6 @@
-
-
-
- Phonecall Campaigns
- crm.case.resource.type
- form
-
-
-
-
-
@@ -47,9 +34,10 @@
@@ -94,7 +82,7 @@
@@ -121,7 +109,7 @@
states="draft,pending" type="object"
icon="gtk-go-forward" />
+ states="open" type="object" icon="gtk-media-pause" />
@@ -172,7 +160,7 @@
@@ -219,10 +207,14 @@
string="Type" />
+
-
-
-
-
+ context="{'group_by':'date'}" help="Date of Call" />
diff --git a/addons/crm/crm_view.xml b/addons/crm/crm_view.xml
index db248be7492..061888d02fb 100644
--- a/addons/crm/crm_view.xml
+++ b/addons/crm/crm_view.xml
@@ -113,7 +113,7 @@
diff --git a/addons/crm_claim/crm_claim.py b/addons/crm_claim/crm_claim.py
index 81a98a7e326..de77c842aa6 100644
--- a/addons/crm_claim/crm_claim.py
+++ b/addons/crm_claim/crm_claim.py
@@ -46,10 +46,8 @@ class crm_claim(crm.crm_case, osv.osv):
'ref' : fields.reference('Reference', selection=crm._links_get, size=128),
'ref2' : fields.reference('Reference 2', selection=crm._links_get, size=128),
'canal_id': fields.many2one('res.partner.canal', 'Channel', \
- help="The channels represent the different communication"\
- "modes available with the customer." \
- " With each commercial opportunity, you can indicate the"\
- "canall which is this opportunity source."),
+ help="The channels represent the different communication \
+ modes available with the customer."),
'planned_revenue': fields.float('Planned Revenue'),
'planned_cost': fields.float('Planned Costs'),
'categ_id': fields.many2one('crm.case.categ', 'Category', \
diff --git a/addons/crm_claim/crm_claim_view.xml b/addons/crm_claim/crm_claim_view.xml
index 44b1eb34fd8..a341915bc39 100644
--- a/addons/crm_claim/crm_claim_view.xml
+++ b/addons/crm_claim/crm_claim_view.xml
@@ -35,21 +35,6 @@
-
-
-
- Claim Resource Type
- crm.case.resource.type
- form
-
- [('object_id.model', '=', 'crm.claim')]
- {'object_id':'crm.claim'}
-
-
-
-
@@ -57,7 +42,7 @@
crm.claimtree
-
+
@@ -168,7 +153,7 @@
-
+
-
+
@@ -205,7 +190,7 @@
-
@@ -269,7 +254,7 @@
@@ -339,6 +325,7 @@
context="{'default_partner_address_id': active_id}"
id="act_claim_partner_address"
name="Report a Claim"
+ view_mode="form,tree"
res_model="crm.claim"
src_model="res.partner.address"/>
diff --git a/addons/crm_claim/i18n/en_US.po b/addons/crm_claim/i18n/en_US.po
index 27818261434..b67bd61d7f9 100644
--- a/addons/crm_claim/i18n/en_US.po
+++ b/addons/crm_claim/i18n/en_US.po
@@ -87,8 +87,8 @@ msgstr "Day"
#. module: crm_claim
#: help:crm.claim,canal_id:0
-msgid "The channels represent the different communicationmodes available with the customer. With each commercial opportunity, you can indicate thecanall which is this opportunity source."
-msgstr "The channels represent the different communicationmodes available with the customer. With each commercial opportunity, you can indicate thecanall which is this opportunity source."
+msgid "The channels represent the different communication modes available with the customer."
+msgstr "The channels represent the different communication modes available with the customer."
#. module: crm_claim
#: help:crm.claim,section_id:0
diff --git a/addons/crm_claim/report/crm_claim_report.py b/addons/crm_claim/report/crm_claim_report.py
index fed4026aa02..e0dc7244f14 100644
--- a/addons/crm_claim/report/crm_claim_report.py
+++ b/addons/crm_claim/report/crm_claim_report.py
@@ -74,6 +74,8 @@ class crm_claim_report(osv.osv):
'type_id': fields.many2one('crm.case.resource.type', 'Claim Type',\
domain="[('section_id','=',section_id),\
('object_id.model', '=', 'crm.claim')]"),
+ 'date_closed': fields.date('Closed', readonly=True),
+ 'delay_expected': fields.float('Overpassed Deadline',digits=(16,2),readonly=True, group_operator="avg"),
}
def init(self, cr):
@@ -87,9 +89,10 @@ class crm_claim_report(osv.osv):
create or replace view crm_claim_report as (
select
min(c.id) as id,
- to_char(c.create_date, 'YYYY') as name,
- to_char(c.create_date, 'MM') as month,
- to_char(c.create_date, 'YYYY-MM-DD') as day,
+ to_char(c.date, 'YYYY') as name,
+ to_char(c.date, 'MM') as month,
+ to_char(c.date, 'YYYY-MM-DD') as day,
+ to_char(c.date_closed, 'YYYY-MM-DD') as date_closed,
c.state,
c.user_id,
c.stage_id,
@@ -101,13 +104,14 @@ class crm_claim_report(osv.osv):
c.priority as priority,
c.type_id as type_id,
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_closed-c.create_date)))/(3600*24) as delay_close,
+ extract('epoch' from (c.date_deadline - c.date_closed))/(3600*24) as delay_expected
from
crm_claim c
- group by to_char(c.create_date, 'YYYY'), to_char(c.create_date, 'MM'), \
+ group by to_char(c.date, 'YYYY'), to_char(c.date, 'MM'),to_char(c.date, 'YYYY-MM-DD'),\
c.state, c.user_id,c.section_id, c.stage_id,\
- c.categ_id,c.partner_id,c.company_id,c.create_date,to_char(c.create_date, 'YYYY-MM-DD')
- ,c.priority,c.type_id
+ c.categ_id,c.partner_id,c.company_id,c.create_date,
+ c.priority,c.type_id,c.date_deadline,c.date_closed
)""")
crm_claim_report()
diff --git a/addons/crm_claim/report/crm_claim_report_view.xml b/addons/crm_claim/report/crm_claim_report_view.xml
index edb3dc2b6db..db5973c1867 100644
--- a/addons/crm_claim/report/crm_claim_report_view.xml
+++ b/addons/crm_claim/report/crm_claim_report_view.xml
@@ -19,6 +19,7 @@
+
@@ -42,6 +43,7 @@
+
@@ -75,14 +77,17 @@
-
+
-
+
-
+
-
+ help="My team" />
-
+
-
+
@@ -139,42 +143,41 @@
-
-
-
-
-
+
-
-
-
+
-
-
-
+
+
+
+
+ domain="[]" context="{'group_by':'day'}"
+ help="Date of claim"/>
+ domain="[]" context="{'group_by':'month'}"
+ help="Month of claim"/>
+ domain="[]" context="{'group_by':'name'}"
+ help="Year of claim"/>
-
@@ -182,7 +185,7 @@
- Claims
+ Claims Analysiscrm.claim.reportformtree,graph
diff --git a/addons/crm_fundraising/crm_fundraising.py b/addons/crm_fundraising/crm_fundraising.py
index df7bc4a0789..0050642a5db 100644
--- a/addons/crm_fundraising/crm_fundraising.py
+++ b/addons/crm_fundraising/crm_fundraising.py
@@ -71,10 +71,8 @@ class crm_fundraising(crm.crm_case, osv.osv):
'ref': fields.reference('Reference', selection=crm._links_get, size=128),
'ref2': fields.reference('Reference 2', selection=crm._links_get, size=128),
'canal_id': fields.many2one('res.partner.canal', 'Channel', \
- help="The channels represent the different communication "\
- "modes available with the customer." \
- " With each commercial opportunity, you can indicate\
- the canall which is this opportunity source."),
+ help="The channels represent the different communication \
+ modes available with the customer."),
'state': fields.selection(crm.AVAILABLE_STATES, 'State', size=16, readonly=True,
help='The state is set to \'Draft\', when a case is created.\
\nIf the case is in progress the state is set to \'Open\'.\
diff --git a/addons/crm_fundraising/crm_fundraising_view.xml b/addons/crm_fundraising/crm_fundraising_view.xml
index 84af1b141c9..2021245c1f5 100644
--- a/addons/crm_fundraising/crm_fundraising_view.xml
+++ b/addons/crm_fundraising/crm_fundraising_view.xml
@@ -37,24 +37,6 @@
id="menu_crm_fundraising_stage_act"
parent="menu_config_fundrising" />
-
-
-
-
- Fundraising Resource Type
- crm.case.resource.type
- form
-
- [('object_id.model', '=', 'crm.fundraising')]
- {'object_id':'crm.fundraising'}
-
-
-
-
-
@@ -63,7 +45,7 @@
tree
+ colors="blue:state=='pending';grey:state in ('cancel', 'done')">
@@ -159,7 +141,7 @@
-
+
-
-
diff --git a/addons/hr/hr_installer.xml b/addons/hr/hr_installer.xml
index ef7e3e4aad7..490523b4e12 100644
--- a/addons/hr/hr_installer.xml
+++ b/addons/hr/hr_installer.xml
@@ -19,7 +19,7 @@
- You can enhance the base HR Application by installing few HR-related modules.
+ You can enhance the base HR Application by installing few HR-related functionalities.
diff --git a/addons/hr/installer.py b/addons/hr/installer.py
index f4ee1e99aba..1d650d814e9 100644
--- a/addons/hr/installer.py
+++ b/addons/hr/installer.py
@@ -35,7 +35,7 @@ class hr_installer(osv.osv_memory):
help="Helps you manage and streamline your recruitment process."),
'hr_timesheet_sheet':fields.boolean('Timesheets',
help="Tracks and helps employees encode and validate timesheets "
- "and attendance."),
+ "and attendances."),
'hr_contract': fields.boolean("Employee's Contracts",
help="Extends employee profiles to help manage their contracts."),
'hr_evaluation': fields.boolean('Periodic Evaluations',
@@ -44,7 +44,7 @@ class hr_installer(osv.osv_memory):
'hr_attendance': fields.boolean('Attendances',
help="Simplifies the management of employee's attendances."),
'hr_payroll': fields.boolean('Payroll',
- help="Generic Payroll system"),
+ help="Generic Payroll system."),
'hr_payroll_account': fields.boolean('Payroll Accounting',
help="Generic Payroll system Integrated with Accountings."),
}
diff --git a/addons/hr_recruitment/hr_recruitment_view.xml b/addons/hr_recruitment/hr_recruitment_view.xml
index 57141b34212..149636de112 100644
--- a/addons/hr_recruitment/hr_recruitment_view.xml
+++ b/addons/hr_recruitment/hr_recruitment_view.xml
@@ -142,7 +142,7 @@
-
+
-
+
@@ -180,7 +180,7 @@
-
diff --git a/addons/mrp/installer.py b/addons/mrp/installer.py
index eeb00ece494..407d401e463 100644
--- a/addons/mrp/installer.py
+++ b/addons/mrp/installer.py
@@ -28,7 +28,7 @@ class mrp_installer(osv.osv_memory):
# Manufacturing Resource Planning
'stock_location': fields.boolean('Advanced Routes',
help="Manages product routes and paths within and between "
- "locations (e.g. warehouses)"),
+ "locations (e.g. warehouses)."),
'mrp_jit': fields.boolean('Just In Time Scheduling',
help="Enables Just In Time computation of procurement orders."
"\n\nWhile it's more resource intensive than the default "
@@ -37,7 +37,7 @@ class mrp_installer(osv.osv_memory):
"procurement scheduler manually."),
'mrp_operations': fields.boolean('Manufacturing Operations',
help="Enhances production orders with readiness states as well "
- "as the date of start and end of execution of the order."),
+ "as the start date and end date of execution of the order."),
'mrp_subproduct': fields.boolean('MRP Subproducts',
help="Enables multiple product output from a single production "
"order: without this, a production order can have only one "
diff --git a/addons/process/process_view.xml b/addons/process/process_view.xml
index b743c82f84f..f33af42c533 100644
--- a/addons/process/process_view.xml
+++ b/addons/process/process_view.xml
@@ -35,7 +35,7 @@
-
+
@@ -74,14 +74,14 @@
-
+
-
+
@@ -114,7 +114,7 @@
-
+
@@ -160,7 +160,7 @@
-
+
@@ -199,7 +199,7 @@
-
+
@@ -220,8 +220,8 @@
-
-
+
+
@@ -261,9 +261,8 @@
form
-
+
-
@@ -308,11 +307,13 @@
+
diff --git a/addons/profile_tools/installer.py b/addons/profile_tools/installer.py
index 1e2ff655353..06be50a903f 100644
--- a/addons/profile_tools/installer.py
+++ b/addons/profile_tools/installer.py
@@ -25,9 +25,9 @@ class misc_tools_installer(osv.osv_memory):
_inherit = 'res.config.installer'
_columns = {
- 'lunch':fields.boolean('Lunch',help='Helps to manage Lunch Orders'),
- 'subscription':fields.boolean('Recurring Documents',help='Helps to add subscription on documents'),
- 'survey':fields.boolean('Survey',help='Manages Custom Surveys'),
+ 'lunch':fields.boolean('Lunch',help='Helps to manage Lunch Orders.'),
+ 'subscription':fields.boolean('Recurring Documents',help='Helps to add subscription on documents.'),
+ 'survey':fields.boolean('Survey',help='Manages Custom Surveys.'),
'idea':fields.boolean('Idea',help='Manages ideas and votes'),
'audittrail':fields.boolean('Audit Trail',help="Lets you to track user's operations on specific Objects."),
}
diff --git a/addons/project/installer.py b/addons/project/installer.py
index ef2c2b5e8c8..4662ebeda5d 100644
--- a/addons/project/installer.py
+++ b/addons/project/installer.py
@@ -31,32 +31,29 @@ class project_installer(osv.osv_memory):
'Long Term Planning',
help="Enables long-term projects tracking, including "
"multiple-phase projects and resource allocation handling."),
- 'project_wiki': fields.boolean('Specifications in a Wiki',
- help=""),
'hr_timesheet_sheet': fields.boolean('Timesheets',
help="Tracks and helps employees encode and validate timesheets "
- "and attendance."),
+ "and attendances."),
'hr_timesheet_invoice': fields.boolean('Invoice Based on Hours',
- help="Helps generate invoice based on human resources "
+ help="Helps generate invoices based on human resources "
"costs and general expenses."),
'account_budget': fields.boolean('Budgets',
help="Helps accountants manage analytic and crossover budgets."),
'project_messages': fields.boolean('Project Messages',
help="Lets employees send messages to other members of the "
"projects they're working on."),
- 'project_crm': fields.boolean('Issues Tracker',
+ 'project_issue': fields.boolean('Issues Tracker',
help="Automatically synchronizes project tasks and crm cases."),
# Methodologies
'project_scrum': fields.boolean('SCRUM',
help="Implements and tracks the concepts and task types defined "
"in the SCRUM methodology."),
'project_gtd': fields.boolean('Getting Things Done',
- help="Embeds the 'Getting Things Done concepts' into OpenERP's "
- "project management."),
+ help="GTD is a methodology to efficiently organise yourself and your tasks. This module fully integrates GTD principle with OpenERP's project management."),
}
_defaults={
- 'project_crm': True,
+ 'project_issue': True,
}
project_installer()
diff --git a/addons/project/project.py b/addons/project/project.py
index 6959a19fd03..274263682a6 100644
--- a/addons/project/project.py
+++ b/addons/project/project.py
@@ -251,7 +251,7 @@ class project(osv.osv):
context['active_test'] = False
default['state'] = 'open'
if not default.get('name', False):
- default['name'] = proj.name+_(' (copy)')
+ default['name'] = proj.name + _(' (copy)')
res = super(project, self).copy(cr, uid, id, default, context)
return res
@@ -393,6 +393,8 @@ class task(osv.osv):
if not default.get('remaining_hours', False):
default['remaining_hours'] = float(self.read(cr, uid, id, ['planned_hours'])['planned_hours'])
default['active'] = True
+ if not default.get('name', False):
+ default['name'] = self.browse(cr, uid, id, context=context).name + _(' (copy)')
return super(task, self).copy_data(cr, uid, id, default, context)
def _check_dates(self, cr, uid, ids, context=None):
@@ -401,7 +403,7 @@ class task(osv.osv):
if task['date_start'] > task['date_end']:
return False
return True
-
+
def _is_template(self, cr, uid, ids, field_name, arg, context=None):
res = {}
for task in self.browse(cr, uid, ids, context=context):
@@ -415,7 +417,7 @@ class task(osv.osv):
'active': fields.function(_is_template, method=True, store=True, string='Not a Template Task', type='boolean', help="This field is computed automatically and have the same behavior than the boolean 'active' field: if the task is linked to a template or unactivated project, it will be hidden unless specifically asked."),
'name': fields.char('Task Summary', size=128, required=True),
'description': fields.text('Description'),
- 'priority' : fields.selection([('4','Very Low'), ('3','Low'), ('2','Medium'), ('1','Urgent'), ('0','Very urgent')], 'Importance'),
+ 'priority' : fields.selection([('4','Very Low'), ('3','Low'), ('2','Medium'), ('1','Urgent'), ('0','Very urgent')], 'Priority'),
'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of tasks."),
'type_id': fields.many2one('project.task.type', 'Stage',),
'state': fields.selection([('draft', 'Draft'),('open', 'In Progress'),('pending', 'Pending'), ('cancelled', 'Cancelled'), ('done', 'Done')], 'State', readonly=True, required=True,
@@ -425,8 +427,7 @@ class task(osv.osv):
'date_start': fields.datetime('Starting Date'),
'date_end': fields.datetime('Ending Date'),
'date_deadline': fields.date('Deadline'),
- 'project_id': fields.many2one('project.project', 'Project', ondelete='cascade',
- help="If you have [?] in the project name, it means there are no analytic account linked to this project."),
+ 'project_id': fields.many2one('project.project', 'Project', ondelete='cascade'),
'parent_ids': fields.many2many('project.task', 'project_task_parent_rel', 'task_id', 'parent_id', 'Parent Tasks'),
'child_ids': fields.many2many('project.task', 'project_task_parent_rel', 'parent_id', 'task_id', 'Delegated Tasks'),
'notes': fields.text('Notes'),
@@ -457,15 +458,15 @@ class task(osv.osv):
}
_order = "sequence, priority, date_start, id"
-
+
def _check_recursion(self, cr, uid, ids):
obj_task = self.browse(cr, uid, ids[0])
parent_ids = [x.id for x in obj_task.parent_ids]
children_ids = [x.id for x in obj_task.child_ids]
-
+
if (obj_task.id in children_ids) or (obj_task.id in parent_ids):
return False
-
+
while(ids):
cr.execute('SELECT DISTINCT task_id '\
'FROM project_task_parent_rel '\
@@ -518,6 +519,26 @@ class task(osv.osv):
res['fields'][f]['string'] = res['fields'][f]['string'].replace('Hours',tm)
return res
+ def action_close(self, cr, uid, ids, context=None):
+ # This action open wizard to send email to partner or project manager after close task.
+ project_id = len(ids) and ids[0] or False
+ if not project_id: return False
+ task = self.browse(cr, uid, project_id, context=context)
+ project = task.project_id
+ res = self.do_close(cr, uid, [project_id], context=context)
+ if project.warn_manager or project.warn_customer:
+ return {
+ 'name': _('Send Email after close task'),
+ 'view_type': 'form',
+ 'view_mode': 'form',
+ 'res_model': 'project.task.close',
+ 'type': 'ir.actions.act_window',
+ 'target': 'new',
+ 'nodestroy': True,
+ 'context': {'active_id': task.id}
+ }
+ return res
+
def do_close(self, cr, uid, ids, context=None):
"""
Close Task
@@ -539,7 +560,7 @@ class task(osv.osv):
'ref_doc1': 'project.task,%d'% (task.id,),
'ref_doc2': 'project.project,%d'% (project.id,),
})
-
+
for parent_id in task.parent_ids:
if parent_id.state in ('pending','draft'):
reopen = True
diff --git a/addons/project/project_installer.xml b/addons/project/project_installer.xml
index e12fa4d3815..2c22a4b6743 100644
--- a/addons/project/project_installer.xml
+++ b/addons/project/project_installer.xml
@@ -24,9 +24,8 @@
Configure
-
+
-
diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml
index 421729ccda5..f8fe814e218 100644
--- a/addons/project/project_view.xml
+++ b/addons/project/project_view.xml
@@ -21,8 +21,8 @@
-
-
+
+
@@ -43,12 +43,13 @@
+
-
+
-
+
-
+
@@ -239,7 +240,7 @@
-
+
@@ -300,8 +301,11 @@
+
+
+
-
-
+
@@ -369,8 +372,8 @@
-
-
+
+
-
+
@@ -397,9 +400,10 @@
+
+
-
@@ -414,10 +418,7 @@
{"search_default_project_id":project_id, "search_default_user_id":uid, "search_default_current": 1}
- In OpenERP, a project is made of a set of activities (or tasks) for completion.A list view allows the manager to quickly check for task status and make it evolve, delegate task, etc. A search tool allows a multi-criteria sort of activities.
-
-Issues like bugs in a system, client complain, materials breakdown are collected here.A list view allows the manager to quickly check for them, assign them, make their status evolved.
-
+ In OpenERP, a project is made of a set of activities (or tasks) for completion. A list view allows the manager to quickly check for task status and make it evolve, delegate task, etc. A search tool allows a multi-criteria sort of activities.
@@ -486,10 +487,10 @@ Issues like bugs in a system, client complain, materials breakdown are collected
-
+
-
-
+
+
diff --git a/addons/project/report/project_report.py b/addons/project/report/project_report.py
index b9c22faee8b..e411248db4b 100644
--- a/addons/project/report/project_report.py
+++ b/addons/project/report/project_report.py
@@ -49,7 +49,7 @@ class report_project_task_user(osv.osv):
'delay_endings_days': fields.float('Overpassed Deadline', digits=(16,2), readonly=True),
'nbr': fields.integer('# of tasks', readonly=True),
'priority' : fields.selection([('4','Very Low'), ('3','Low'), ('2','Medium'), ('1','Urgent'),
-('0','Very urgent')], 'Importance', readonly=True),
+('0','Very urgent')], 'Priority', readonly=True),
'month':fields.selection([('01','January'), ('02','February'), ('03','March'), ('04','April'), ('05','May'), ('06','June'), ('07','July'), ('08','August'), ('09','September'), ('10','October'), ('11','November'), ('12','December')], 'Month', readonly=True),
'state': fields.selection([('draft', 'Draft'), ('open', 'In Progress'), ('pending', 'Pending'), ('cancelled', 'Cancelled'), ('done', 'Done')],'State', readonly=True),
'company_id': fields.many2one('res.company', 'Company', readonly=True, groups="base.group_multi_company"),
diff --git a/addons/project/report/project_report_view.xml b/addons/project/report/project_report_view.xml
index f269399877c..1ae5adc489a 100644
--- a/addons/project/report/project_report_view.xml
+++ b/addons/project/report/project_report_view.xml
@@ -58,18 +58,18 @@
-
-
+
+ domain="[('date_start','<=', time.strftime('%%Y-%%m-%%d')),('date_start','>=',time.strftime('%%Y-%%m-01'))]"
+ help="Current Month"/>
+ domain="[('date_start','<=', (datetime.date (int(time.strftime('%%Y')), datetime.date.today().month, 1) - datetime.timedelta (days = 1)).strftime('%%Y-%%m-%%d')),('date_start','>',(datetime.date (int(time.strftime('%%Y')), datetime.date.today().month-1, 1)).strftime('%%Y-%%m-%%d'))]"
+ help="Previous Month"/>
-
-
-
+
+
+
-
-
-
+
+
+
diff --git a/addons/project/security/project_security.xml b/addons/project/security/project_security.xml
index f968ffc51a3..97453dcb33b 100644
--- a/addons/project/security/project_security.xml
+++ b/addons/project/security/project_security.xml
@@ -6,6 +6,10 @@
Project / Financial Manager
+
+ Project / Financial User
+
+
Project / Manager
@@ -43,5 +47,12 @@
['|','|','|',('user_id','=',False),('user_id','=',user.id),('project_id.members','in', [user.id]),('project_id.user_id','=',user.id)]
+
+ Projects According to User
+
+
+ [('user_id','=',user.id)]
+
+
diff --git a/addons/project/wizard/project_task_close.py b/addons/project/wizard/project_task_close.py
index 99b6caef308..78ffa5a8338 100644
--- a/addons/project/wizard/project_task_close.py
+++ b/addons/project/wizard/project_task_close.py
@@ -56,24 +56,18 @@ class project_task_close(osv.osv_memory):
partner = task.partner_id or task.project_id.partner_id
if 'description' in fields:
- res.update({'description': task.description})
+ res.update({'description': task.description or False})
if 'manager_warn' in fields:
- res.update({'manager_warn': project.warn_manager})
+ res.update({'manager_warn': project.warn_manager or False})
if 'partner_warn' in fields:
- res.update({'partner_warn': project.warn_customer})
+ res.update({'partner_warn': project.warn_customer or False})
if 'manager_email' in fields:
res.update({'manager_email': manager and manager.user_email or False})
if partner and len(partner.address) and 'partner_email' in fields:
res.update({'partner_email': partner.address[0].email})
return res
- def done(self, cr, uid, ids, context=None):
- task_pool = self.pool.get('project.task')
- task_id = context.get('active_id', False)
- res = task_pool.do_close(cr, uid, [task_id], context=context)
- return res
-
- def confirm(self, cr, uid, ids, context=None):
+ def send(self, cr, uid, ids, context=None):
if context is None:
context = {}
@@ -83,7 +77,6 @@ class project_task_close(osv.osv_memory):
return {}
task = task_pool.browse(cr, uid, task_id, context=context)
for data in self.browse(cr, uid, ids, context=context):
- res = task_pool.do_close(cr, uid, [task.id], context=context)
if res:
# Send Warn Message by Email to Manager and Customer
if data.manager_warn and not data.manager_email:
diff --git a/addons/project/wizard/project_task_close_view.xml b/addons/project/wizard/project_task_close_view.xml
index 9692fe9a733..6c064784827 100644
--- a/addons/project/wizard/project_task_close_view.xml
+++ b/addons/project/wizard/project_task_close_view.xml
@@ -3,34 +3,32 @@
- Done Task
+ Send Emailproject.task.closeform
-
-
+
-
+
-
+
-
-
-
+
+
- Done Task
+ Send Emailir.actions.act_windowproject.task.closeform
diff --git a/addons/project/wizard/project_task_delegate.py b/addons/project/wizard/project_task_delegate.py
index 2ce74ceefc8..2430b8a0896 100644
--- a/addons/project/wizard/project_task_delegate.py
+++ b/addons/project/wizard/project_task_delegate.py
@@ -30,7 +30,7 @@ class project_task_delegate(osv.osv_memory):
_columns = {
'name': fields.char('Delegated Title', size=64, required=True, help="New title of the task delegated to the user"),
- 'prefix': fields.char('Your Task Title', size=64, required=True, help="New title of your own task to validate the work done"),
+ 'prefix': fields.char('Your Task Title', size=64, required=True, help="Title for your validation task"),
'user_id': fields.many2one('res.users', 'Assign To', required=True, help="User you want to delegate this task to"),
'new_task_description': fields.text('New Task Description', help="Reinclude the description of the task in the task of the user"),
'planned_hours': fields.float('Planned Hours', help="Estimated time to close this task by the delegated user"),
@@ -51,7 +51,7 @@ class project_task_delegate(osv.osv_memory):
project = task.project_id
manager = project.user_id or False
partner = task.partner_id or task.project_id.partner_id
-
+
if 'name' in fields:
if task.name.startswith(_('CHECK: ')):
newname = str(task.name).replace(_('CHECK: '), '')
diff --git a/addons/project/wizard/project_task_delegate_view.xml b/addons/project/wizard/project_task_delegate_view.xml
index 7bedecd8f53..dc299826419 100644
--- a/addons/project/wizard/project_task_delegate_view.xml
+++ b/addons/project/wizard/project_task_delegate_view.xml
@@ -15,17 +15,17 @@
-
+
-
+
-
+
-
+
diff --git a/addons/project/wizard/project_task_reevaluate_view.xml b/addons/project/wizard/project_task_reevaluate_view.xml
index 5e0e7c89069..db7bda3afe7 100644
--- a/addons/project/wizard/project_task_reevaluate_view.xml
+++ b/addons/project/wizard/project_task_reevaluate_view.xml
@@ -1,7 +1,7 @@
-
+
Re-evaluate Taskproject.task.reevaluate
@@ -14,7 +14,7 @@
-
+
diff --git a/addons/project_gtd/project_gtd.py b/addons/project_gtd/project_gtd.py
index 46031048ae9..f29780126e0 100644
--- a/addons/project_gtd/project_gtd.py
+++ b/addons/project_gtd/project_gtd.py
@@ -114,7 +114,7 @@ class project_task(osv.osv):
if res['type'] == 'search':
tt = timebox_obj.browse(cr, uid, timebox_obj.search(cr,uid,[]))
search_extended ='''''' % (len(tt)+7,_('Getting Things Done'))
- search_extended += '''''' % (_('Inbox'),)
+ search_extended += '''''' % (_('Inbox'),)
search_extended += ''''''
for time in tt:
if time.icon:
diff --git a/addons/project_gtd/project_gtd_view.xml b/addons/project_gtd/project_gtd_view.xml
index 5672fdafa7c..99e87fcb325 100644
--- a/addons/project_gtd/project_gtd_view.xml
+++ b/addons/project_gtd/project_gtd_view.xml
@@ -19,7 +19,7 @@
form
-
+
@@ -53,7 +53,7 @@
-
+
diff --git a/addons/project_issue/project_issue.py b/addons/project_issue/project_issue.py
index 5c5a8907dc9..05e047914b7 100644
--- a/addons/project_issue/project_issue.py
+++ b/addons/project_issue/project_issue.py
@@ -70,7 +70,7 @@ class project_issue(crm.crm_case, osv.osv):
message = _('Issue ') + " '" + name + "' "+ _("is Closed.")
self.log(cr, uid, id, message)
return res
-
+
def _compute_day(self, cr, uid, ids, fields, args, context=None):
if context is None:
context = {}
@@ -152,7 +152,7 @@ class project_issue(crm.crm_case, osv.osv):
domain="[('partner_id','=',partner_id)]"),
'company_id': fields.many2one('res.company', 'Company'),
'description': fields.text('Description'),
- 'state': fields.selection([('draft', 'Draft'), ('open', 'Todo'), ('cancel', 'Cancelled'), ('done', 'Closed'),('pending', 'Pending'), ], 'State', size=16, readonly=True,
+ 'state': fields.selection([('draft', 'Draft'), ('open', 'To Do'), ('cancel', 'Cancelled'), ('done', 'Closed'),('pending', 'Pending'), ], 'State', size=16, readonly=True,
help='The state is set to \'Draft\', when a case is created.\
\nIf the case is in progress the state is set to \'Open\'.\
\nWhen the case is over, the state is set to \'Done\'.\
@@ -409,7 +409,7 @@ class project(osv.osv):
'project_escalation_id' : fields.many2one('project.project','Project Escalation', help='If any issue is escalated from the current Project, it will be listed under the project selected here.', states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
'reply_to' : fields.char('Reply-To Email Address', size=256)
}
-
+
def _check_escalation(self, cr, uid, ids):
project_obj = self.browse(cr, uid, ids[0])
if project_obj.project_escalation_id:
diff --git a/addons/project_issue/project_issue_data.xml b/addons/project_issue/project_issue_data.xml
index 1c7f5c73c77..b5fa80b96bd 100644
--- a/addons/project_issue/project_issue_data.xml
+++ b/addons/project_issue/project_issue_data.xml
@@ -22,19 +22,16 @@
Version 4.2
- Version 5.0
- Version 6.0
-
diff --git a/addons/project_issue/project_issue_menu.xml b/addons/project_issue/project_issue_menu.xml
index 9c074ed2fd3..df76e808bff 100644
--- a/addons/project_issue/project_issue_menu.xml
+++ b/addons/project_issue/project_issue_menu.xml
@@ -12,10 +12,10 @@
formtree,calendar
-
+ {"search_default_user_id": uid, "search_default_current":1, "search_default_project_id":project_id}
- Issues like bugs in a system, client complain, materials breakdown are collected here.A list view allows the manager to quickly check for them, assign them, make their status evolved.
+ Issues like bugs in a system, client complain, materials breakdown are collected here. A list view allows the manager to quickly check for them, assign them, make their status evolved.
@@ -40,7 +40,7 @@
-
+
@@ -75,10 +75,10 @@
-
+
-
+
-
+
@@ -117,7 +117,7 @@
-
@@ -157,13 +157,13 @@
project.issuetree
-
+
-
+
@@ -174,11 +174,12 @@
-
+
+
@@ -190,8 +191,8 @@
-
-
+
+
@@ -204,25 +205,31 @@
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+ domain="[]" context="{'group_by':'create_date'}" help="Creation Month"/>
@@ -254,7 +261,7 @@
-
+
@@ -316,6 +323,6 @@
-
+
diff --git a/addons/project_issue/report/project_issue_report.py b/addons/project_issue/report/project_issue_report.py
index bf8085ba932..41ebaa3243e 100644
--- a/addons/project_issue/report/project_issue_report.py
+++ b/addons/project_issue/report/project_issue_report.py
@@ -87,7 +87,7 @@ class project_issue_report(osv.osv):
'company_id' : fields.many2one('res.company', 'Company'),
'priority': fields.selection(crm.AVAILABLE_PRIORITIES, 'Priority'),
'project_id':fields.many2one('project.project', 'Project',readonly=True),
- 'type_id': fields.many2one('crm.case.resource.type', 'Version', domain="[('object_id.model', '=', 'project.issue')]"),
+ 'type_id': fields.many2one('crm.case.resource.type', 'Version'),
'assigned_to' : fields.many2one('res.users', 'Assigned to',readonly=True),
'partner_id': fields.many2one('res.partner','Partner',domain="[('object_id.model', '=', 'project.issue')]"),
'canal_id': fields.many2one('res.partner.canal', 'Channel',readonly=True),
diff --git a/addons/project_issue/report/project_issue_report_view.xml b/addons/project_issue/report/project_issue_report_view.xml
index 9ceded378ba..d1b421d59ca 100644
--- a/addons/project_issue/report/project_issue_report_view.xml
+++ b/addons/project_issue/report/project_issue_report_view.xml
@@ -54,14 +54,16 @@
-
+
-
-
-
+
+
@@ -83,7 +86,7 @@
+ help="My Sale Team" />
@@ -96,7 +99,7 @@
-
+
@@ -108,45 +111,42 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
-
+
+
-
-
-
-
+ domain="[]" context="{'group_by':'day'}" help="Current Day"/>
+ domain="[]" context="{'group_by':'month'}" help="Current Month"/>
+ domain="[]" context="{'group_by':'name'}" help="Current Year"/>
-
diff --git a/addons/project_long_term/project_long_term.py b/addons/project_long_term/project_long_term.py
index 79baff679cc..79837416d97 100644
--- a/addons/project_long_term/project_long_term.py
+++ b/addons/project_long_term/project_long_term.py
@@ -21,9 +21,10 @@
import time
from datetime import date, datetime, timedelta
-
from tools.translate import _
from osv import fields, osv
+from resource.faces import task as Task
+import operator
class project_phase(osv.osv):
_name = "project.phase"
@@ -181,38 +182,55 @@ class project_phase(osv.osv):
uom_obj = self.pool.get('product.uom')
if context is None:
context = {}
+ res = super(project_phase, self).write(cr, uid, ids, vals, context=context)
if context.get('scheduler',False):
- return super(project_phase, self).write(cr, uid, ids, vals, context=context)
+ return res
# Consider calendar and efficiency if the phase is performed by a resource
# otherwise consider the project's working calendar
+
+ #TOCHECK : why need this ?
if isinstance(ids, (int, long)):
ids = [ids]
- phase = self.browse(cr, uid, ids[0], context=context)
- calendar_id = phase.project_id.resource_calendar_id and phase.project_id.resource_calendar_id.id or False
- resource_id = resource_obj.search(cr, uid, [('user_id', '=', phase.responsible_id.id)],context=context)
- if resource_id:
+ default_uom_id = self._get_default_uom_id(cr, uid)
+ for phase in self.browse(cr, uid, ids, context=context):
+ calendar_id = phase.project_id.resource_calendar_id and phase.project_id.resource_calendar_id.id or False
+ resource_id = resource_obj.search(cr, uid, [('user_id', '=', phase.responsible_id.id)],context=context)
+ if resource_id:
cal_id = resource_obj.browse(cr, uid, resource_id[0], context=context).calendar_id.id
if cal_id:
calendar_id = cal_id
- default_uom_id = self._get_default_uom_id(cr, uid)
- avg_hours = uom_obj._compute_qty(cr, uid, phase.product_uom.id, phase.duration, default_uom_id)
- # Change the date_start and date_end
- # for previous and next phases respectively based on valid condition
- if vals.get('date_start', False) and vals['date_start'] < phase.date_start:
+
+ avg_hours = uom_obj._compute_qty(cr, uid, phase.product_uom.id, phase.duration, default_uom_id)
+ # Change the date_start and date_end
+ # for previous and next phases respectively based on valid condition
+ if vals.get('date_start', False) and vals['date_start'] < phase.date_start:
dt_start = datetime.strptime(vals['date_start'], '%Y-%m-%d')
work_times = resource_calendar_obj.interval_get(cr, uid, calendar_id, dt_start, avg_hours or 0.0, resource_id and resource_id[0] or False)
if work_times:
vals['date_end'] = work_times[-1][1].strftime('%Y-%m-%d')
for prv_phase in phase.previous_phase_ids:
+ if prv_phase.id == phase.id:
+ continue
self._check_date_start(cr, uid, prv_phase, dt_start, context=context)
- if vals.get('date_end', False) and vals['date_end'] > phase.date_end:
+
+ if vals.get('date_end', False) and vals['date_end'] > phase.date_end:
dt_end = datetime.strptime(vals['date_end'], '%Y-%m-%d')
work_times = resource_calendar_obj.interval_min_get(cr, uid, calendar_id, dt_end, avg_hours or 0.0, resource_id and resource_id[0] or False)
if work_times:
vals['date_start'] = work_times[0][0].strftime('%Y-%m-%d')
for next_phase in phase.next_phase_ids:
+ if next_phase.id == phase.id:
+ continue
self._check_date_end(cr, uid, next_phase, dt_end, context=context)
- return super(project_phase, self).write(cr, uid, ids, vals, context=context)
+
+ return res
+
+ def copy(self, cr, uid, id, default=None, context=None):
+ if default is None:
+ default = {}
+ if not default.get('name', False):
+ default['name'] = self.browse(cr, uid, id, context=context).name + _(' (copy)')
+ return super(project_phase, self).copy(cr, uid, id, default, context)
def set_draft(self, cr, uid, ids, *args):
self.write(cr, uid, ids, {'state': 'draft'})
@@ -234,6 +252,118 @@ class project_phase(osv.osv):
self.write(cr, uid, ids, {'state': 'done'})
return True
+ def generate_resources(self, cr, uid, ids, context=None):
+ """
+ Return a list of Resource Class objects for the resources allocated to the phase.
+ """
+ res = {}
+ if context is None:
+ context = {}
+ resource_pool = self.pool.get('resource.resource')
+ for phase in self.browse(cr, uid, ids, context=context):
+ user_ids = map(lambda x:x.resource_id.user_id.id, phase.resource_ids)
+ project = phase.project_id
+ calendar_id = project.resource_calendar_id and project.resource_calendar_id.id or False
+ resource_objs = resource_pool.generate_resources(cr, uid, user_ids, calendar_id, context=context)
+ res[phase.id] = resource_objs
+ return res
+
+ def generate_schedule(self, cr, uid, ids, start_date, calendar_id=False, context=None):
+ """
+ Schedule phase with the start date till all the next phases are completed.
+ @param: start_dsate : start date for the phase
+ @param: calendar_id : working calendar of the project
+ """
+ if context is None:
+ context = {}
+ resource_pool = self.pool.get('resource.resource')
+ uom_pool = self.pool.get('product.uom')
+ phase_resource = False
+ if context is None:
+ context = {}
+ default_uom_id = self._get_default_uom_id(cr, uid)
+ for phase in self.browse(cr, uid, ids, context=context):
+ if not phase.responsible_id:
+ raise osv.except_osv(_('No responsible person assigned !'),_("You must assign a responsible person for phase '%s' !") % (phase.name,))
+
+ phase_resource_obj = resource_pool.generate_resources(cr, uid, [phase.responsible_id.id], calendar_id, context=context)
+ avg_hours = uom_pool._compute_qty(cr, uid, phase.product_uom.id, phase.duration, default_uom_id)
+ duration = str(avg_hours) + 'H'
+ # Create a new project for each phase
+ def Project():
+ start = start_date
+ minimum_time_unit = 1
+ resource = phase_resource_obj
+ # If project has working calendar then that
+ # else the default one would be considered
+ if calendar_id:
+ working_days = resource_pool.compute_working_calendar(cr, uid, calendar_id, context=context)
+ vacation = tuple(resource_pool.compute_vacation(cr, uid, calendar_id))
+
+ def phase():
+ effort = duration
+
+ project = Task.BalancedProject(Project)
+ s_date = project.phase.start.to_datetime()
+ e_date = project.phase.end.to_datetime()
+ # Recalculate date_start and date_end
+ # according to constraints on date start and date end on phase
+ if phase.constraint_date_start and str(s_date) < phase.constraint_date_start:
+ start_date = datetime.strptime(phase.constraint_date_start, '%Y-%m-%d')
+ else:
+ start_date = s_date
+ if phase.constraint_date_end and str(e_date) > phase.constraint_date_end:
+ end_date= datetime.strptime(phase.constraint_date_end, '%Y-%m-%d')
+ date_start = phase.constraint_date_end
+ else:
+ end_date = e_date
+ date_start = end_date
+ # Write the calculated dates back
+ ctx = context.copy()
+ ctx.update({'scheduler': True})
+ self.write(cr, uid, [phase.id], {
+ 'date_start': start_date.strftime('%Y-%m-%d'),
+ 'date_end': end_date.strftime('%Y-%m-%d')
+ }, context=ctx)
+
+ # Recursive call till all the next phases scheduled
+ for phase in phase.next_phase_ids:
+ if phase.state in ['draft', 'open', 'pending']:
+ id_cal = phase.project_id.resource_calendar_id and phase.project_id.resource_calendar_id.id or False
+ self.generate_schedule(cr, uid, [phase.id], date_start, id_cal, context=context)
+ else:
+ continue
+ return True
+
+ def schedule_tasks(self, cr, uid, ids, context=None):
+ """
+ Schedule the tasks according to resource available and priority.
+ """
+ task_pool = self.pool.get('project.task')
+ resource_pool = self.pool.get('resource.resource')
+ if context is None:
+ context = {}
+ resources_list = self.generate_resources(cr, uid, ids, context=context)
+ return_msg = {}
+ for phase in self.browse(cr, uid, ids, context=context):
+ start_date = phase.date_start
+ if not start_date and phase.project_id.date_start:
+ start_date = phase.project_id.date_start
+ if not start_date:
+ start_date = datetime.now().strftime("%Y-%m-%d")
+ resources = resources_list.get(phase.id, [])
+ calendar_id = phase.project_id.resource_calendar_id.id
+ task_ids = map(lambda x : x.id, (filter(lambda x : x.state in ['open', 'draft', 'pending'] , phase.task_ids)))
+ if task_ids:
+ task_pool.generate_schedule(cr, uid, task_ids, resources, calendar_id, start_date, context=context)
+
+ if not task_ids:
+ warning_msg = _("No tasks to compute for Phase '%s'.") % (phase.name)
+ if "warning" not in return_msg:
+ return_msg["warning"] = warning_msg
+ else:
+ return_msg["warning"] = return_msg["warning"] + "\n" + warning_msg
+ return return_msg
project_phase()
class project_resource_allocation(osv.osv):
@@ -259,14 +389,172 @@ class project(osv.osv):
'phase_ids': fields.one2many('project.phase', 'project_id', "Project Phases"),
'resource_calendar_id': fields.many2one('resource.calendar', 'Working Time', help="Timetable working hours to adjust the gantt diagram report", states={'close':[('readonly',True)]} ),
}
+ def generate_members(self, cr, uid, ids, context=None):
+ """
+ Return a list of Resource Class objects for the resources allocated to the phase.
+ """
+ res = {}
+ resource_pool = self.pool.get('resource.resource')
+ if context is None:
+ context = {}
+ for project in self.browse(cr, uid, ids, context=context):
+ user_ids = map(lambda x:x.id, project.members)
+ calendar_id = project.resource_calendar_id and project.resource_calendar_id.id or False
+ resource_objs = resource_pool.generate_resources(cr, uid, user_ids, calendar_id, context=context)
+ res[project.id] = resource_objs
+ return res
+
+ def schedule_phases(self, cr, uid, ids, context=None):
+ """
+ Schedule the phases.
+ """
+ if context is None:
+ context = {}
+ if type(ids) in (long, int,):
+ ids = [ids]
+ phase_pool = self.pool.get('project.phase')
+ for project in self.browse(cr, uid, ids, context=context):
+ phase_ids = phase_pool.search(cr, uid, [('project_id', '=', project.id),
+ ('state', 'in', ['draft', 'open', 'pending']),
+ ('previous_phase_ids', '=', False)
+ ])
+ start_date = project.date_start
+ if not start_date:
+ start_date = datetime.now().strftime("%Y-%m-%d")
+ start_dt = datetime.strftime((datetime.strptime(start_date, "%Y-%m-%d")), "%Y-%m-%d %H:%M")
+ calendar_id = project.resource_calendar_id and project.resource_calendar_id.id or False
+ phase_pool.generate_schedule(cr, uid, phase_ids, start_dt, calendar_id, context=context)
+ return True
+
+ def schedule_tasks(self, cr, uid, ids, context=None):
+ """
+ Schedule the tasks according to resource available and priority.
+ """
+ if type(ids) in (long, int,):
+ ids = [ids]
+ user_pool = self.pool.get('res.users')
+ task_pool = self.pool.get('project.task')
+ resource_pool = self.pool.get('resource.resource')
+ if context is None:
+ context = {}
+
+ resources_list = self.generate_members(cr, uid, ids, context=context)
+ return_msg = {}
+ for project in self.browse(cr, uid, ids, context=context):
+ start_date = project.date_start
+ if not start_date:
+ start_date = datetime.now().strftime("%Y-%m-%d")
+ resources = resources_list.get(project.id, [])
+ calendar_id = project.resource_calendar_id.id
+ task_ids = task_pool.search(cr, uid, [('project_id', '=', project.id),
+ ('state', 'in', ['draft', 'open', 'pending'])
+ ])
+
+
+ if task_ids:
+ task_pool.generate_schedule(cr, uid, task_ids, resources, calendar_id, start_date, context=context)
+ else:
+ warning_msg = _("No tasks to compute for Project '%s'.") % (project.name)
+ if "warning" not in return_msg:
+ return_msg["warning"] = warning_msg
+ else:
+ return_msg["warning"] = return_msg["warning"] + "\n" + warning_msg
+
+ return return_msg
project()
-class task(osv.osv):
+class resource_resource(osv.osv):
+ _inherit = "resource.resource"
+ def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False):
+ if context is None:
+ context = {}
+ if context.get('project_id',False):
+ project_pool = self.pool.get('project.project')
+ project_rec = project_pool.browse(cr, uid, context['project_id'])
+ user_ids = [user_id.id for user_id in project_rec.members]
+ args.append(('user_id','in',user_ids))
+ return super(resource_resource, self).search(cr, uid, args, offset, limit, order, context, count)
+
+resource_resource()
+
+class project_task(osv.osv):
_inherit = "project.task"
_columns = {
'phase_id': fields.many2one('project.phase', 'Project Phase'),
}
+
+ def generate_schedule(self, cr, uid, ids, resources, calendar_id, start_date, context=None):
+ """
+ Schedule the tasks according to resource available and priority.
+ """
+ if not ids:
+ return False
+ if context is None:
+ context = {}
+ user_pool = self.pool.get('res.users')
+ project_pool = self.pool.get('project.project')
+ priority_dict = {'0': 1000, '1': 800, '2': 500, '3': 300, '4': 100}
+ # Create dynamic no of tasks with the resource specified
+ def create_tasks(task_number, eff, priorty=500, obj=False):
+ def task():
+ """
+ task is a dynamic method!
+ """
+ effort = eff
+ if obj:
+ resource = obj
+ priority = priorty
+ task.__doc__ = "TaskNO%d" %task_number
+ task.__name__ = "task%d" %task_number
+ return task
-task()
+ # Create a 'Faces' project with all the tasks and resources
+ def Project():
+ title = "Project"
+ start = datetime.strftime(datetime.strptime(start_date, "%Y-%m-%d"), "%Y-%m-%d %H:%M")
+ try:
+ resource = reduce(operator.or_, resources)
+ except:
+ raise osv.except_osv(_('Error'), _('Should have Resources Allocation or Project Members!'))
+ minimum_time_unit = 1
+ if calendar_id: # If project has working calendar
+ working_days = resource_pool.compute_working_calendar(cr, uid, calendar_id, context=context)
+ vacation = tuple(resource_pool.compute_vacation(cr, uid, calendar_id, context=context))
+ # Dynamic creation of tasks
+ task_number = 0
+ for openobect_task in self.browse(cr, uid, ids, context=context):
+ hours = str(openobect_task.planned_hours )+ 'H'
+ if openobect_task.priority in priority_dict.keys():
+ priorty = priority_dict[openobect_task.priority]
+ real_resource = False
+ if openobect_task.user_id:
+ for task_resource in resources:
+ if task_resource.__name__ == task_resource:
+ real_resource = task_resource
+ break
+
+ task = create_tasks(task_number, hours, priorty, real_resource)
+ task_number += 1
+
+
+ face_projects = Task.BalancedProject(Project)
+ loop_no = 0
+ # Write back the computed dates
+ for face_project in face_projects:
+ s_date = face_project.start.to_datetime()
+ e_date = face_project.end.to_datetime()
+ if loop_no > 0:
+ ctx = context.copy()
+ ctx.update({'scheduler': True})
+ user_id = user_pool.search(cr, uid, [('name', '=', face_project.booked_resource[0].__name__)])
+ self.write(cr, uid, [ids[loop_no-1]], {
+ 'date_start': s_date.strftime('%Y-%m-%d %H:%M:%S'),
+ 'date_end': e_date.strftime('%Y-%m-%d %H:%M:%S'),
+ 'user_id': user_id[0]
+ }, context=ctx)
+
+ loop_no += 1
+ return True
+project_task()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/project_long_term/project_long_term_demo.xml b/addons/project_long_term/project_long_term_demo.xml
index 7718048dc05..30acac99377 100644
--- a/addons/project_long_term/project_long_term_demo.xml
+++ b/addons/project_long_term/project_long_term_demo.xml
@@ -1,741 +1,393 @@
-
-
-
-
-
- en_US
- Demo User1
-
- Mr Demo
-
-
-
-
-
- demo1
- demo1
-
-
-
-
-
- en_US
- Manager1
+
+
+
+
+ Phoung
-
-
-
-
-
- manager1
- manager1
-
+ phu
+ phu
-
-
-
- en_US
- Manager2
+
+ Anthony
-
-
-
-
-
- manager2
- manager2
-
+ al
+ al
-
-
-
- en_US
- user1
+
+ Qwintin
-
-
-
-
-
- user1
- USER1
-
+ qdp
+ qdp
-
-
-
- en_US
- user2
+
+ Francois
-
-
-
-
-
- user2
- user2
-
+ fpi
+ fpi
-
-
-
- en_US
- user_finance
+
+ Julien
+
+ jth
+ jth
+
+
+ Alien
+
+ apr
+ apr
+
+
+ Fabian
-
-
-
-
-
- user_finance
- user_finance
-
+ fbs
+ fbs
-
-
- en_US
- user_design1
-
-
-
-
-
-
- user_design1
- user_design1
-
-
-
-
-
- en_US
- user_design2
-
-
-
-
-
-
- user_design2
- user_design2
-
-
-
-
-
- en_US
- user_developer1
-
-
-
-
-
-
- user_developer1
- user_developer1
-
-
-
-
-
- en_US
- user_developer2
-
-
-
-
-
-
- user_developer2
- user_developer1
-
-
-
-
-
- en_US
- user_tester1
-
-
-
-
-
-
- user_tester1
- user_tester1
-
-
-
-
-
- en_US
- user_tester2
-
-
-
-
-
-
- user_tester2
- user_tester2
-
-
-
-
-
- en_US
- user_analyst
-
-
-
-
-
-
- user_analyst
- user_analyst
-
-
-
-
-
-
-
-
+
+
+ Analyst
-
-
- user
-
-
-
- Programmer
-
-
+
+
+ Project Manager
- user
-
-
-
+
+
+ Technical Leader
+
+
+
+
+
+ Developer
+
+
+
+
+
+ Designer
+
+
+
+
+ Tester
-
-
- user
-
-
-
- Web Designer
-
-
+
+
+ Project Finacial Manager
- user
+
+
-
-
-
-
-
-
-
-
-
+
+ opennormal
- Develop an OpenERP Website.
-
-
-
-
-
- OpenERP Website Development
+ Integrate an Sale and Warehouse Management.
+
+
+ Integrate an Sale and Warehouse Management.
-
+
- Information Gathering and Understanding
+ Collect Requirement and Make SRS
-
-
-
- draft
-
-
-
-
-
+
+ 30
+
+
-
-
- Planning
+
+
+ Design Model
-
-
-
- draft
-
-
-
-
-
+
+ 20
+
+
-
-
- Web Design
+
+
+ Planning and compute Risk analysis, Time chart
-
-
-
- draft
-
-
-
-
-
+
+ 20
+
+
-
-
- Development, Integration and Testing
+
+
+ Development and Integration
-
-
-
- draft
-
-
-
-
-
+
+ 90
+
+
-
-
- Website Deployment
+
+
+ Review and Testing
-
-
-
- draft
-
-
-
-
-
+
+ 30
+
+
+
+
+
+
+ Deployement and Training
+
+
+ 10
+
+
-
-
-
-
+
+
+
-
-
-
-
+
+
+
-
-
-
-
+
+
+
-
-
-
-
+
+
+
-
-
-
-
+
+
+
-
-
-
-
+
+
+
-
-
-
-
+
+
+
-
-
-
-
+
+
+
-
-
-
-
-
+
+
+
+
-
-
+
+
-
- open
-
-
+ 2
-
-
-
-
+ Prepare Requirements Document
-
-
-
-
+
-
-
+
-
- open
-
-
+ 2
-
-
-
-
- Define Website Goals, Purposes and Target Audience
-
-
-
-
+
+ Make SRS
+
-
-
+
-
- open
-
-
+ 2
-
-
-
-
- Use Cases
-
-
-
-
+
+ Design Use Cases
+
-
-
+
-
- open
-
-
+ 2
-
-
-
-
+ Budget Planning
-
-
-
-
+
-
-
+
-
- open
-
-
+ 2
-
-
-
-
+ Quality Planning
-
-
-
-
+
-
-
+
-
- open
-
-
+ 2
-
-
-
-
+ Risk Management Planning
-
-
-
-
+
-
-
+
-
- open
-
-
+ 2
-
-
-
-
+ Create Project Schedules
-
-
-
-
+
-
-
+
-
- open
-
-
+ 2
-
-
-
-
+ Dataflow Design
-
-
-
-
+
-
-
+
-
- open
-
-
+ 2
-
-
-
-
+ User Interface Design
-
-
-
-
+
-
-
+
-
- open
-
-
+ 2
-
-
-
-
- Task Level WBS
-
-
-
-
+
+ Develop Module in Sale Management
+
-
-
+
-
- open
-
-
+ 2
-
-
-
-
- Modular Programming
-
-
-
-
+
+ Develop module in Warehouse
+
-
-
+
-
- open
-
-
+ 2
-
-
-
-
+ Integrate Modules
-
-
-
-
+
-
-
+
-
- open
-
-
+ 2
-
-
-
-
+ Unit Testing
-
-
-
-
+
-
-
+
-
- open
-
-
+ 2
-
-
-
-
+ Regression Test
-
-
-
-
+
-
-
+
-
- open
-
-
+ 2
-
-
-
-
+ Documentation
-
-
-
-
+
-
+
-
- open
-
-
+ 2
-
-
-
-
+ Performance Tuning
-
-
-
-
+
-
-
+
-
- open
-
-
+ 2
-
-
-
-
- Deploy Website
-
-
-
-
+
+ Deploy and Review on Customer System
+
-
-
+
-
- open
-
-
+ 2
-
-
-
-
- Presentation
-
-
-
-
+
+ Training and Presentation
+
+
+
+
+
+
diff --git a/addons/project_long_term/project_long_term_view.xml b/addons/project_long_term/project_long_term_view.xml
index ee763b759b6..a3ff3b39669 100644
--- a/addons/project_long_term/project_long_term_view.xml
+++ b/addons/project_long_term/project_long_term_view.xml
@@ -30,7 +30,7 @@
-
+
@@ -60,8 +60,9 @@
-
+
+
@@ -89,16 +90,21 @@
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -115,9 +121,9 @@
-
-
+
+
@@ -184,7 +190,7 @@
tree
-
+
@@ -228,23 +234,26 @@
-
+
-
+
-
-
-
+
-
+
+
+
+
+
+
@@ -257,7 +266,7 @@
tree,form,gantt,calendar{'search_default_responsible_id':uid}
- You can subdivide your larger projects into several phases. For each phase, you can define your resources allocation (humans or engine), describe de differend task and link your phase with previous and next one, add constraints date and scheduling. A gantt view of your project phase is also available from this menu. Gantt view is a graphically draw of the project plan; it includes any task dependencies by visually adjusting task durations and priorities, and by linking tasks to each other.
+ You can subdivide your larger projects into several phases. For each phase, you can define your resources allocation (humans or engine), describe de differend task and link your phase with previous and next one, add constraints date and scheduling. A gantt view of your project phase is also available from this menu. Gantt view is a graphically draw of the project plan; it includes any task dependencies by visually adjusting task durations and priorities, and by linking tasks to each other.
@@ -297,10 +306,10 @@
res_model="project.task"
src_model="project.phase"
view_mode="tree,form"
- domain="[('phase_id','=',active_id)]"/>
+ context="{'search_default_phase_id': [active_id]}"/>
diff --git a/addons/project_long_term/security/ir.model.access.csv b/addons/project_long_term/security/ir.model.access.csv
index 3653cd375f1..7af7984d7e6 100644
--- a/addons/project_long_term/security/ir.model.access.csv
+++ b/addons/project_long_term/security/ir.model.access.csv
@@ -1,9 +1,10 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
-"access_project_phase","project.phase","model_project_phase",project.group_project_user,1,1,1,0
-"access_project_resource_allocation","project.resource.allocation","model_project_resource_allocation",project.group_project_user,1,1,1,0
-"access_project_phase_manager","project.phase manager","model_project_phase",project.group_project_manager,1,0,0,0
-"access_project_resource_allocation_manager","project.resource.allocation manager","model_project_resource_allocation",project.group_project_manager,1,0,0,0
-"access_project_resource_allocation_system","project.resource.allocation system","model_project_resource_allocation",base.group_system,1,0,0,0
-"access_project_phase_system","project.phase system","model_project_phase",base.group_system,1,0,0,0
-"access_resource_resource_user","resource.resource user","resource.model_resource_resource",project.group_project_user,1,1,1,1
+"access_project_phase","project.phase","model_project_phase","project.group_project_user",1,1,1,0
+"access_project_resource_allocation","project.resource.allocation","model_project_resource_allocation","project.group_project_user",1,1,1,0
+"access_project_phase_manager","project.phase manager","model_project_phase","project.group_project_manager",1,0,0,0
+"access_project_resource_allocation_manager","project.resource.allocation manager","model_project_resource_allocation","project.group_project_manager",1,0,0,0
+"access_project_resource_allocation_system","project.resource.allocation system","model_project_resource_allocation","base.group_system",1,0,0,0
+"access_project_phase_system","project.phase system","model_project_phase","base.group_system",1,0,0,0
+"access_resource_resource_user","resource.resource user","resource.model_resource_resource","project.group_project_user",1,0,1,1
"access_resource_calendar_leaves_user","resource.calendar.leaves user","resource.model_resource_calendar_leaves","project.group_project_user",1,1,1,1
+"access_resource_resource_manager","resource.resource manager","resource.model_resource_resource","project.group_project_manager",1,1,1,1
diff --git a/addons/project_long_term/test/schedule_phase_tasks.yml b/addons/project_long_term/test/schedule_phase_tasks.yml
index 323d9cbc8f2..150d80af822 100644
--- a/addons/project_long_term/test/schedule_phase_tasks.yml
+++ b/addons/project_long_term/test/schedule_phase_tasks.yml
@@ -2,32 +2,31 @@
Create project 'Develop an outlook-openerp synchronization plugin'
-
!record {model: project.project, id: project_project_project0}:
- company_id: base.main_company
- name: Project123
+ name: Develop an outlook-openerp synchronization plugin
members:
- - project_long_term.res_users_manager0
- - project_long_term.res_users_user0
- - project_long_term.res_users_userfinance0
- - project_long_term.res_users_userdesign0
- - project_long_term.res_users_userdeveloper0
- - project_long_term.res_users_usertester0
- - project_long_term.res_users_useranalyst0
+ - project_long_term.res_users_project_manager
+ - project_long_term.res_users_technical_leader
+ - project_long_term.res_users_developer
+ - project_long_term.res_users_designer
+ - project_long_term.res_users_tester
+ - project_long_term.res_users_analyst
+ - project_long_term.res_users_finacial_manager
-
Create phase 'Develop GUI' in Outlook
-
!record {model: project.phase, id: project_phase_phase0}:
date_start: '2010-06-02'
duration: 200.0
- name: phase123
+ name: Develop GUI in Outlook
product_uom: product.uom_day
project_id: project_project_project0
state: draft
resource_ids:
- - resource_id: project_long_term.resource_resource_analyst0
+ - resource_id: project_long_term.resource_analyst
useability: 80.0
- - resource_id: project_long_term.resource_resource_programmer0
+ - resource_id: project_long_term.resource_developer
useability: 30.0
- - resource_id: project_long_term.resource_resource_webdesigner0
+ - resource_id: project_long_term.resource_designer
useability: 30.0
@@ -35,66 +34,60 @@
Create the phase task 'Develop GUI for Server Configuration'
-
!record {model: project.task, id: project_task_t0}:
- name: t1
+ name: Develop GUI for Server Configuration
planned_hours: 20.0
remaining_hours: 20.0
state: draft
phase_id: project_phase_phase0
project_id: project_project_project0
- user_id: project_long_term.res_users_userdeveloper0
+ user_id: project_long_term.res_users_developer
-
Create the phase task 'Develop GUI for Modules Configuration'
-
!record {model: project.task, id: project_task_t1}:
- name: t2
+ name: Develop GUI for Modules Configuration
planned_hours: 25.0
remaining_hours: 25.0
state: draft
phase_id: project_phase_phase0
project_id: project_project_project0
- user_id: project_long_term.res_users_userdeveloper0
+ user_id: project_long_term.res_users_developer
-
Create the phase task 'Develop GUI for OpenERP Synchronisation'
-
!record {model: project.task, id: project_task_t2}:
- name: t3
+ name: Develop GUI for OpenERP Synchronisation
planned_hours: 30.0
remaining_hours: 30.0
state: draft
phase_id: project_phase_phase0
project_id: project_project_project0
- user_id: project_long_term.res_users_userdeveloper0
+ user_id: project_long_term.res_users_developer
-
- Create the phase task 'Develop required Menus'
+ Create the phase task 'Design required GUI/Menus'
-
!record {model: project.task, id: project_task_3}:
- name: t4
+ name: Design required GUI/Menus
planned_hours: 25.0
remaining_hours: 25.0
state: draft
phase_id: project_phase_phase0
project_id: project_project_project0
- user_id: project_long_term.res_users_userdesign0
+ user_id: project_long_term.res_users_designer
-
Schedule phase tasks
-
- !python {model: project.schedule.tasks}: |
- res = self.compute_date(cr, uid, {"lang": "en_US", "tz": False,
- "active_id": ref("project_phase_phase0"),
- # rest may be obsolete:
- # "active_model": "project.phase", "active_ids": [ref("project_phase_phase0")],
- # "record_id": 138, "project_id": ref("project_project_project0"),
- })
- print res
+ !python {model: project.phase}: |
+ res = self.schedule_tasks(cr, uid, [ref("project_phase_phase0")])
-
Check if tasks scheduled, check that either of task's start_date, end_date and user_id is not null
-
!python {model: project.phase}: |
- phase=self.browse(cr, uid, [ref("project_phase_phase0")])[0]
+ phase = self.browse(cr, uid, [ref("project_phase_phase0")])[0]
for task in phase.task_ids:
if (not task.user_id) or (not task.date_start) or (not task.date_end):
raise AssertionError("Phase Tasks not scheduled: %d uid=%r start=%r end=%r" % \
- (task.id, task.user_id, task.date_start, task.date_end))
\ No newline at end of file
+ (task.id, task.user_id, task.date_start, task.date_end))
diff --git a/addons/project_long_term/test/schedule_project_phases.yml b/addons/project_long_term/test/schedule_project_phases.yml
index 66bca5ff97d..e06feaaa4ca 100644
--- a/addons/project_long_term/test/schedule_project_phases.yml
+++ b/addons/project_long_term/test/schedule_project_phases.yml
@@ -2,7 +2,6 @@
Create a project 'World Bank's Project'
-
!record {model: project.project, id: project_project_worldbanksproject0}:
- company_id: base.main_company
name: "World Bank's Project"
priority: 4
@@ -15,7 +14,6 @@
name: "Defining Client's Basic Idea of Project"
product_uom: product.uom_day
project_id: project_project_worldbanksproject0
- state: draft
-
@@ -27,7 +25,6 @@
name: Establishing Project Feasibility
product_uom: product.uom_day
project_id: project_project_worldbanksproject0
- state: draft
-
Create project phase 'Preparation of Engineering Designs'
@@ -38,7 +35,6 @@
name: Preparation of Engineering Designs
product_uom: product.uom_hour
project_id: project_project_worldbanksproject0
- state: draft
-
@@ -50,7 +46,6 @@
name: Procurement of Works and Goods
product_uom: product.uom_hour
project_id: project_project_worldbanksproject0
- state: draft
-
@@ -62,7 +57,6 @@
name: Project Construction
product_uom: product.uom_hour
project_id: project_project_worldbanksproject0
- state: draft
-
@@ -74,7 +68,6 @@
name: Project Completion
product_uom: product.uom_hour
project_id: project_project_worldbanksproject0
- state: draft
-
Set previous phase for phase 'Establishing Project Feasibility'
@@ -125,11 +118,8 @@
-
Schedule project phases
-
- !python {model: project.compute.phases}: |
- self.check_selection(cr, uid, [ref("project_compute_phases_0")], {"lang": "en_US",
- "project_id": False, "tz": False, "active_model": "ir.ui.menu", "department_id":
- False, "section_id": False, "record_id": 279, "active_ids": [ref("project_long_term.menu_compute_phase")],
- "active_id": ref("project_long_term.menu_compute_phase"), })
+ !python {model: project.project}: |
+ self.schedule_phases(cr, uid, ref("project_project_worldbanksproject0"))
-
Check if phases scheduled, check that either of phase's start_date, end_date and user_id is not null
@@ -140,4 +130,4 @@
if (not phase.responsible_id) or (not phase.date_start) or (not phase.date_end):
raise AssertionError("Tasks not scheduled")
-
\ No newline at end of file
+
diff --git a/addons/project_long_term/test/schedule_project_tasks.yml b/addons/project_long_term/test/schedule_project_tasks.yml
index b1cd70487f7..dfc4cf1fc5e 100644
--- a/addons/project_long_term/test/schedule_project_tasks.yml
+++ b/addons/project_long_term/test/schedule_project_tasks.yml
@@ -2,103 +2,93 @@
Create project 'Develop a thunderbird-openerp synchronization plugin'
-
!record {model: project.project, id: project_project_project1}:
- company_id: base.main_company
- name: Project2
+ name: Develop a thunderbird-openerp synchronization plugin
members:
- - project_long_term.res_users_manager0
- - project_long_term.res_users_user0
- - project_long_term.res_users_userfinance0
- - project_long_term.res_users_userdesign0
- - project_long_term.res_users_userdeveloper0
- - project_long_term.res_users_usertester0
- - project_long_term.res_users_useranalyst0
+ - project_long_term.res_users_project_manager
+ - project_long_term.res_users_technical_leader
+ - project_long_term.res_users_developer
+ - project_long_term.res_users_designer
+ - project_long_term.res_users_tester
+ - project_long_term.res_users_analyst
+ - project_long_term.res_users_finacial_manager
-
- Create phase 'Develop GUI' in Thunderbird
+ Create phase 'Develop GUI' in thunderbird
-
!record {model: project.phase, id: project_phase_phase1}:
date_start: '2010-06-02'
- duration: 100.0
- name: phase22
+ duration: 200.0
+ name: Develop GUI in thunderbird
product_uom: product.uom_day
project_id: project_project_project1
state: draft
resource_ids:
- - resource_id: project_long_term.resource_resource_analyst0
+ - resource_id: project_long_term.resource_analyst
useability: 80.0
- - resource_id: project_long_term.resource_resource_programmer0
+ - resource_id: project_long_term.resource_developer
useability: 30.0
- - resource_id: project_long_term.resource_resource_webdesigner0
+ - resource_id: project_long_term.resource_designer
useability: 30.0
-
Create the phase task 'Develop GUI for Server Configuration'
-
- !record {model: project.task, id: project_task_t00}:
- name: t1
+ !record {model: project.task, id: project_task_t10}:
+ name: Develop GUI for Server Configuration
planned_hours: 20.0
remaining_hours: 20.0
state: draft
phase_id: project_phase_phase1
project_id: project_project_project1
- user_id: project_long_term.res_users_userdeveloper0
+ user_id: project_long_term.res_users_developer
-
Create the phase task 'Develop GUI for Modules Configuration'
-
!record {model: project.task, id: project_task_t11}:
- name: t2
+ name: Develop GUI for Modules Configuration
planned_hours: 25.0
remaining_hours: 25.0
state: draft
phase_id: project_phase_phase1
project_id: project_project_project1
- user_id: project_long_term.res_users_userdeveloper0
+ user_id: project_long_term.res_users_developer
-
Create the phase task 'Develop GUI for OpenERP Synchronisation'
-
- !record {model: project.task, id: project_task_t22}:
- name: t3
+ !record {model: project.task, id: project_task_t12}:
+ name: Develop GUI for OpenERP Synchronisation
planned_hours: 30.0
remaining_hours: 30.0
state: draft
phase_id: project_phase_phase1
project_id: project_project_project1
-
-
+ user_id: project_long_term.res_users_developer
-
- Create the phase task 'Develop required Menus'
+ Create the phase task 'Design required GUI/Menus'
-
- !record {model: project.task, id: project_task_t33}:
- name: t4
+ !record {model: project.task, id: project_task_13}:
+ name: Design required GUI/Menus
planned_hours: 25.0
remaining_hours: 25.0
state: draft
phase_id: project_phase_phase1
project_id: project_project_project1
-
--
- Get the project to schedule the tasks
--
- !record {model: project.compute.tasks, id: project_compute_tasks_0}:
- project_id: project_project_project1
+ user_id: project_long_term.res_users_designer
-
Schedule tasks
-
- !python {model: project.compute.tasks}: |
- self.compute_date(cr, uid, [ref("project_compute_tasks_0")], {"lang": "en_US", "tz": False,
- "active_id": ref("project_long_term.menu_compute_tasks"),
- "active_model": "ir.ui.menu", "active_ids": [ref("project_long_term.menu_compute_tasks")],
- })
+ !python {model: project.project}: |
+ self.schedule_tasks(cr, uid, ref("project_project_project1"))
-
Check if tasks scheduled, check that either of task's start_date, end_date and user_id is not null
-
!python {model: project.project}: |
- prj=self.browse(cr, uid, [ref("project_project_project1")])[0]
+ prj = self.browse(cr, uid, [ref("project_project_project1")])[0]
for task in prj.tasks:
if (not task.user_id) or (not task.date_start) or (not task.date_end):
raise AssertionError("Project Tasks not scheduled")
diff --git a/addons/project_long_term/wizard/__init__.py b/addons/project_long_term/wizard/__init__.py
index 5056cad3b77..c1e6d838111 100644
--- a/addons/project_long_term/wizard/__init__.py
+++ b/addons/project_long_term/wizard/__init__.py
@@ -22,6 +22,5 @@
import project_compute_phases
import project_compute_tasks
import project_schedule_tasks
-import working_calendar
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/project_long_term/wizard/project_compute_phases.py b/addons/project_long_term/wizard/project_compute_phases.py
index 75631fb3d18..c43dea56e91 100644
--- a/addons/project_long_term/wizard/project_compute_phases.py
+++ b/addons/project_long_term/wizard/project_compute_phases.py
@@ -18,18 +18,11 @@
# along with this program. If not, see .
#
##############################################################################
-
import datetime
-from resource.faces import *
-from new import classobj
-
from tools.translate import _
from osv import fields, osv
-import working_calendar as wkcal
-
class project_compute_phases(osv.osv_memory):
-
_name = 'project.compute.phases'
_description = 'Project Compute Phases'
_columns = {
@@ -48,118 +41,24 @@ class project_compute_phases(osv.osv_memory):
data_select = self.read(cr, uid, ids, ['target_project'])[0]
return self.compute_date(cr, uid, ids, context=context)
- def _phase_schedule(self, cr, uid, phase, start_date, calendar_id=False, context=None):
- if context is None:
- context = {}
- """Schedule phase with the start date till all the next phases are completed.
-
- Arguements: start_dsate -- start date for the phase
- calendar_id -- working calendar of the project
-
- """
- phase_obj = self.pool.get('project.phase')
- resource_obj = self.pool.get('resource.resource')
- uom_obj = self.pool.get('product.uom')
- phase_resource_obj = False
- if context is None:
- context = {}
- if phase:
- leaves = []
- time_efficiency = 1.0
- resource_id = resource_obj.search(cr, uid, [('user_id', '=', phase.responsible_id.id)])
-
- if resource_id:
- # Create a new resource object with
- # all the attributes of the Resource Class
- resource = resource_obj.browse(cr, uid, resource_id, context=context)[0]
- time_efficiency = resource.time_efficiency
- leaves = wkcal.compute_leaves(cr, uid, calendar_id , resource.id, resource.calendar_id.id)
- if not phase.responsible_id:
- raise osv.except_osv(_('No responsible person assigned !'),_("You must assign a responsible person for phase '%s' !") % (phase.name,))
- phase_resource_obj = classobj((phase.responsible_id.name.encode('utf8')), (Resource,),{
- '__doc__': phase.responsible_id.name,
- '__name__': phase.responsible_id.name,
- 'vacation': tuple(leaves),
- 'efficiency': time_efficiency
- })
- default_uom_id = phase_obj._get_default_uom_id(cr, uid)
- avg_hours = uom_obj._compute_qty(cr, uid, phase.product_uom.id, phase.duration, default_uom_id)
- duration = str(avg_hours) + 'H'
- # Create a new project for each phase
- def Project():
- start = start_date
- minimum_time_unit = 1
- resource = phase_resource_obj
- # If project has working calendar then that
- # else the default one would be considered
- if calendar_id:
- working_days = wkcal.compute_working_calendar(cr, uid, calendar_id, context=context)
- vacation = tuple(wkcal.compute_leaves(cr, uid, calendar_id))
-
- def phase():
- effort = duration
-
- project = BalancedProject(Project)
- s_date = project.phase.start.to_datetime()
- e_date = project.phase.end.to_datetime()
- # Recalculate date_start and date_end
- # according to constraints on date start and date end on phase
- if phase.constraint_date_start and str(s_date) < phase.constraint_date_start:
- start_date = datetime.datetime.strptime(phase.constraint_date_start, '%Y-%m-%d')
- else:
- start_date = s_date
- if phase.constraint_date_end and str(e_date) > phase.constraint_date_end:
- end_date= datetime.datetime.strptime(phase.constraint_date_end, '%Y-%m-%d')
- date_start = phase.constraint_date_end
- else:
- end_date = e_date
- date_start = end_date
- # Write the calculated dates back
- ctx = context.copy()
- ctx.update({'scheduler': True})
- phase_obj.write(cr, uid, [phase.id], {
- 'date_start': start_date.strftime('%Y-%m-%d'),
- 'date_end': end_date.strftime('%Y-%m-%d')
- }, context=ctx)
-
- # Recursive call till all the next phases scheduled
- for phase in phase.next_phase_ids:
- if phase.state in ['draft', 'open', 'pending']:
- id_cal = phase.project_id.resource_calendar_id and phase.project_id.resource_calendar_id.id or False
- self._phase_schedule(cr, uid, phase, date_start, id_cal, context=context)
- else:
- continue
-
+
def compute_date(self, cr, uid, ids, context=None):
"""
Compute the phases for scheduling.
"""
-
if context is None:
context = {}
- phase_obj = self.pool.get('project.phase')
+ project_pool = self.pool.get('project.project')
data = self.read(cr, uid, ids, [], context=context)[0]
if not data['project_id'] and data['target_project'] == 'one':
raise osv.except_osv(_('Error!'), _('Please Specify Project to be schedule'))
+
if data['project_id']: # If project mentioned find its phases
- project_id = data['project_id']
- phase_ids = phase_obj.search(cr, uid, [('project_id', '=', project_id),
- ('state', 'in', ['draft', 'open', 'pending']),
- ('previous_phase_ids', '=', False)
- ])
+ project_ids = [data['project_id']]
else: # Else take all the draft,open,pending states phases
- phase_ids = phase_obj.search(cr, uid,[('state', 'in', ['draft', 'open', 'pending']),
- ('previous_phase_ids', '=', False)
- ], context=context)
- phase_ids.sort()
- phases = phase_obj.browse(cr, uid, phase_ids, context=context)
- for phase in phases:
- start_date = phase.project_id.date_start
- if not phase.project_id.date_start:
- start_date = datetime.datetime.now().strftime("%Y-%m-%d")
- start_dt = datetime.datetime.strftime((datetime.datetime.strptime(start_date, "%Y-%m-%d")), "%Y-%m-%d %H:%M")
- calendar_id = phase.project_id.resource_calendar_id and phase.project_id.resource_calendar_id.id or False
- self._phase_schedule(cr, uid, phase, start_dt, calendar_id, context=context)
+ project_ids = project_pool.search(cr, uid, [], context=context)
+
+ project_pool.schedule_phases(cr, uid, project_ids, context=context)
return self._open_phases_list(cr, uid, data, context=context)
def _open_phases_list(self, cr, uid, data, context=None):
@@ -173,10 +72,7 @@ class project_compute_phases(osv.osv_memory):
result = mod_obj._get_id(cr, uid, 'project_long_term', 'act_project_phase_list')
id = mod_obj.read(cr, uid, [result], ['res_id'])[0]['res_id']
result = act_obj.read(cr, uid, [id], context=context)[0]
- result['domain'] = [('state', 'not in', ['cancelled','done'])]
- if data['project_id']:
- result['domain'] = [('project_id', '=', data['project_id']),
- ('state', 'not in', ['cancelled','done'])]
+ result['context'] = {"search_default_project_id":data['project_id'], "search_default_responsible_id":uid, "search_default_current": 1}
return result
project_compute_phases()
diff --git a/addons/project_long_term/wizard/project_compute_phases_view.xml b/addons/project_long_term/wizard/project_compute_phases_view.xml
index 8818684e8fa..9d5754af09c 100644
--- a/addons/project_long_term/wizard/project_compute_phases_view.xml
+++ b/addons/project_long_term/wizard/project_compute_phases_view.xml
@@ -16,7 +16,7 @@
-
+
diff --git a/addons/project_long_term/wizard/project_compute_tasks.py b/addons/project_long_term/wizard/project_compute_tasks.py
index 8e98f26b353..cb74649502f 100644
--- a/addons/project_long_term/wizard/project_compute_tasks.py
+++ b/addons/project_long_term/wizard/project_compute_tasks.py
@@ -20,14 +20,10 @@
##############################################################################
import datetime
-from resource.faces import *
-from new import classobj
-import operator
from tools.translate import _
from osv import osv, fields
-import working_calendar as wkcal
class project_compute_tasks(osv.osv_memory):
_name = 'project.compute.tasks'
@@ -40,108 +36,32 @@ class project_compute_tasks(osv.osv_memory):
"""
Schedule the tasks according to resource available and priority.
"""
- project_obj = self.pool.get('project.project')
+ project_pool = self.pool.get('project.project')
task_pool = self.pool.get('project.task')
- resource_obj = self.pool.get('resource.resource')
- user_obj = self.pool.get('res.users')
-
if context is None:
context = {}
-
+ context['compute_by'] = 'project'
data = self.read(cr, uid, ids, [])[0]
project_id = data['project_id']
- project = project_obj.browse(cr, uid, project_id, context=context)
- task_ids = task_pool.search(cr, uid, [('project_id', '=', project_id),
- ('state', 'in', ['draft', 'open', 'pending'])
- ])
- if task_ids:
- task_ids.sort()
- tasks = task_pool.browse(cr, uid, task_ids, context=context)
- calendar_id = project.resource_calendar_id and project.resource_calendar_id.id or False
- start_date = project.date_start
- if not project.date_start:
- start_date = datetime.datetime.now().strftime("%Y-%m-%d")
- date_start = datetime.datetime.strftime(datetime.datetime.strptime(start_date, "%Y-%m-%d"), "%Y-%m-%d %H:%M")
- # Create Resource Class objects which are the Project Members
- resources = []
- for user in project.members:
- leaves = []
- time_efficiency = 1.0
- resource_id = resource_obj.search(cr, uid, [('user_id', '=', user.id)], context=context)
- if resource_id:
-# resource = resource_obj.browse(cr, uid, resource_id, context=context)[0]
- resource = resource_obj.read(cr, uid, resource_id, ['calendar_id', 'time_efficiency'], context=context)[0]
- if resource.get('calendar_id', False):
- leaves = wkcal.compute_leaves(cr, uid, calendar_id , resource_id[0], resource['calendar_id'] and resource['calendar_id'][0] or False)
- time_efficiency = resource.get('time_efficiency')
- resources.append(classobj((user.name.encode('utf8')), (Resource,), {
- '__doc__': user.name,
- '__name__': user.name,
- 'vacation': tuple(leaves),
- 'efficiency': time_efficiency
- }))
- priority_dict = {'0': 1000, '1': 800, '2': 500, '3': 300,'4': 100}
- # Create dynamic no of tasks with the resource specified
- def create_tasks(j, eff, priorty=500, obj=None):
- def task():
- """
- task is a dynamic method!
- """
- effort = eff
- if obj:
- resource = obj
- priority = priorty
- task.__doc__ = "TaskNO%d" %j
- task.__name__ = "task%d" %j
- return task
+ project_pool.schedule_tasks(cr, uid, [project_id], context=context)
+ return self._open_task_list(cr, uid, data, context=context)
- # Create a 'Faces' project with all the tasks and resources
- def Project():
- title = project.name
- start = date_start
- try:
- resource = reduce(operator.or_, resources)
- except:
- raise osv.except_osv(_('Error'), _('Project must have members assigned !'))
- minimum_time_unit = 1
- if calendar_id: # If project has calendar
- working_days = wkcal.compute_working_calendar(cr, uid, calendar_id)
- vacation = tuple(wkcal.compute_leaves(cr, uid, calendar_id))
- # Dynamic Creation of tasks
- i = 0
- for each_task in tasks:
- hours = str(each_task.planned_hours )+ 'H'
- if each_task.priority in priority_dict.keys():
- priorty = priority_dict[each_task.priority]
- rcre = False
- if each_task.user_id:
- for resrce in resources:
- if resrce.__name__ == each_task.user_id.name: # check me!!
- rcre = resrce
- break
- task = create_tasks(i, hours, priorty, rcre)
- i += 1
-
- project = BalancedProject(Project)
- loop_no = 0
- # Write back the computed dates
- for t in project:
- s_date = t.start.to_datetime()
- e_date = t.end.to_datetime()
- if loop_no == 0:
- project_obj.write(cr, uid, [project_id], {'date': e_date}, context=context)
- else:
- ctx = context.copy()
- ctx.update({'scheduler': True})
- user_id = user_obj.search(cr, uid, [('name', '=', t.booked_resource[0].__name__)])
- task_pool.write(cr, uid, [tasks[loop_no-1].id], {
- 'date_start': s_date.strftime('%Y-%m-%d %H:%M:%S'),
- 'date_end': e_date.strftime('%Y-%m-%d %H:%M:%S'),
- 'user_id': user_id[0]
- }, context=ctx)
-
- loop_no +=1
- return {}
+ def _open_task_list(self, cr, uid, data, context=None):
+ """
+ Return the scheduled task list.
+ """
+ if context is None:
+ context = {}
+ mod_obj = self.pool.get('ir.model.data')
+ act_obj = self.pool.get('ir.actions.act_window')
+ result = mod_obj._get_id(cr, uid, 'project', 'action_view_task')
+ id = mod_obj.read(cr, uid, [result], ['res_id'])[0]['res_id']
+ result = {}
+ if not id:
+ return result
+ result = act_obj.read(cr, uid, [id], context=context)[0]
+ result['context'] = {"search_default_project_id":data['project_id'], "search_default_user_id":uid, "search_default_current": 1}
+ return result
project_compute_tasks()
diff --git a/addons/project_long_term/wizard/project_compute_tasks_view.xml b/addons/project_long_term/wizard/project_compute_tasks_view.xml
index e0cd30d5622..e6540fafff9 100644
--- a/addons/project_long_term/wizard/project_compute_tasks_view.xml
+++ b/addons/project_long_term/wizard/project_compute_tasks_view.xml
@@ -9,13 +9,13 @@
-
+
-
+
diff --git a/addons/project_long_term/wizard/project_schedule_tasks.py b/addons/project_long_term/wizard/project_schedule_tasks.py
index c64e800c9c6..0d9e9f381f1 100644
--- a/addons/project_long_term/wizard/project_schedule_tasks.py
+++ b/addons/project_long_term/wizard/project_schedule_tasks.py
@@ -20,17 +20,9 @@
##############################################################################
import datetime
-from resource.faces import *
-from new import classobj
-import operator
-
from tools.translate import _
-from osv import osv, fields
-
-import working_calendar as wkcal
-
+from osv import fields, osv
class project_schedule_task(osv.osv_memory):
-
_name = "project.schedule.tasks"
_description = 'project.schedule.tasks'
_columns = {
@@ -46,126 +38,17 @@ class project_schedule_task(osv.osv_memory):
res = super(project_schedule_task, self).default_get(cr, uid, fields_list, context)
self.compute_date(cr, uid, context=context)
return res
-
- def create_resources(self, cr, uid, phase, context=None):
- """
- Return a list of Resource Class objects for the resources allocated to the phase.
- """
- resource_objs = []
-
- if context is None:
- context = {}
-
- for resource in phase.resource_ids:
- res = resource.resource_id
- leaves = []
- resource_eff = res.time_efficiency
- resource_cal = res.calendar_id.id
- if resource_cal:
- cal_id = phase.project_id.resource_calendar_id and phase.project_id.resource_calendar_id.id or False
- leaves = wkcal.compute_leaves(cr, uid, cal_id, res.id, resource_cal, context=context)
- resource_objs.append(classobj(res.user_id.name.encode('utf8'), (Resource,),{
- '__doc__': res.user_id.name,
- '__name__': res.user_id.name,
- 'vacation': tuple(leaves),
- 'efficiency': resource_eff,
- }))
- return resource_objs
-
+
def compute_date(self, cr, uid, context=None):
"""
Schedule the tasks according to resource available and priority.
"""
-
- phase_obj = self.pool.get('project.phase')
- task_obj = self.pool.get('project.task')
- user_obj = self.pool.get('res.users')
-
+ phase_pool = self.pool.get('project.phase')
if context is None:
- # It makes no sense to continue on empty context
- return { 'warning': _("You must select some project phase to compute on")}
-
+ context = {}
if not 'active_id' in context:
return {}
- phase = phase_obj.browse(cr, uid, context['active_id'], context=context)
- task_ids = map(lambda x : x.id, (filter(lambda x : x.state in ['open', 'draft', 'pending'] , phase.task_ids)))
- if task_ids:
- task_ids.sort()
- tasks = task_obj.browse(cr, uid, task_ids, context=context)
- start_date = str(phase.date_start)
- if not phase.date_start:
- if not phase.project_id.date_start:
- start_date = datetime.datetime.now().strftime("%Y-%m-%d")
- else:
- start_date = phase.project_id.date_start
- date_start = datetime.datetime.strftime(datetime.datetime.strptime(start_date, "%Y-%m-%d"), "%Y-%m-%d %H:%M")
- calendar_id = phase.project_id.resource_calendar_id.id
- resources = self.create_resources(cr, uid, phase)
- priority_dict = {'0': 1000, '1': 800, '2': 500, '3': 300, '4': 100}
- # Create dynamic no of tasks with the resource specified
- def create_tasks(j, eff, priorty=500, obj=False):
- def task():
- """
- task is a dynamic method!
- """
- effort = eff
- if obj:
- resource = obj
- priority = priorty
- task.__doc__ = "TaskNO%d" %j
- task.__name__ = "task%d" %j
- return task
-
- # Create a 'Faces' project with all the tasks and resources
- def Project():
- title = "Project"
- start = date_start
- try:
- resource = reduce(operator.or_, resources)
- except:
- raise osv.except_osv(_('Error'), _('Phase must have resources assigned !'))
- minimum_time_unit = 1
- if calendar_id: # If project has working calendar
- working_days = wkcal.compute_working_calendar(cr, uid, calendar_id)
- vacation = tuple(wkcal.compute_leaves(cr, uid, calendar_id))
- # Dynamic creation of tasks
- i = 0
- for each_task in tasks:
- hours = str(each_task.planned_hours )+ 'H'
- if each_task.priority in priority_dict.keys():
- priorty = priority_dict[each_task.priority]
- resc = False
- if each_task.user_id:
- for resrce in resources:
- if resrce.__name__ == each_task.user_id.name:
- resc = resrce
- break
-
- task = create_tasks(i, hours, priorty, resc)
- i += 1
-
- project = BalancedProject(Project)
-
- loop_no = 0
- # Write back the computed dates
- for t in project:
- s_date = t.start.to_datetime()
- e_date = t.end.to_datetime()
- if loop_no > 0:
- ctx = context.copy()
- ctx.update({'scheduler': True})
- user_id = user_obj.search(cr, uid, [('name', '=', t.booked_resource[0].__name__)])
- task_obj.write(cr, uid, [tasks[loop_no-1].id], {
- 'date_start': s_date.strftime('%Y-%m-%d %H:%M:%S'),
- 'date_end': e_date.strftime('%Y-%m-%d %H:%M:%S'),
- 'user_id': user_id[0]
- }, context=ctx)
-
- loop_no += 1
- else:
- return {"warning": _("No tasks to compute for this phase") }
- return {}
-
+ return phase_pool.schedule_tasks(cr, uid, [context['active_id']], context=context)
project_schedule_task()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/project_long_term/wizard/working_calendar.py b/addons/project_long_term/wizard/working_calendar.py
deleted file mode 100644
index 139875b6236..00000000000
--- a/addons/project_long_term/wizard/working_calendar.py
+++ /dev/null
@@ -1,124 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2009 Tiny SPRL ().
-#
-# 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 .
-#
-##############################################################################
-
-import datetime
-
-import pooler
-
-def convert_timeformat(cr, uid, time_string, context=None):
- if context is None:
- context = {}
- """ Convert input time string: 8.5 to output time string 8:30."""
-
- split_list = str(time_string).split('.')
- hour_part = split_list[0]
- mins_part = split_list[1]
- round_mins = int(round(float(mins_part) * 60,-2))
- converted_string = hour_part + ':' + str(round_mins)[0:2]
- return converted_string
-
-def compute_leaves(cr, uid, calendar_id, resource_id=False, resource_calendar=False, context=None):
-
- if context is None:
- context = {}
-
- """Compute the leaves from the working calendar of the resource.
-
- Arguements: calendar_id -- working calendar of the project
- resource_id -- resource working on phase/task
- resource_calendar -- working calendar of the resource
-
- """
-
- pool = pooler.get_pool(cr.dbname)
- resource_calendar_leaves_obj = pool.get('resource.calendar.leaves')
- leave_list = []
- if resource_id:
- leave_ids = resource_calendar_leaves_obj.search(cr, uid, ['|', ('calendar_id', '=', calendar_id),
- ('calendar_id', '=', resource_calendar),
- ('resource_id', '=', resource_id)
- ], context=context)
- else:
- leave_ids = resource_calendar_leaves_obj.search(cr, uid, [('calendar_id', '=', calendar_id),
- ('resource_id', '=', False)
- ], context=context)
- leaves = resource_calendar_leaves_obj.read(cr, uid, leave_ids, ['date_from', 'date_to'], context=context)
- for i in range(len(leaves)):
- dt_start = datetime.datetime.strptime(leaves[i]['date_from'], '%Y-%m-%d %H:%M:%S')
- dt_end = datetime.datetime.strptime(leaves[i]['date_to'], '%Y-%m-%d %H:%M:%S')
- no = dt_end - dt_start
- [leave_list.append((dt_start + datetime.timedelta(days=x)).strftime('%Y-%m-%d')) for x in range(int(no.days + 1))]
- leave_list.sort()
- return leave_list
-
-def compute_working_calendar(cr, uid, calendar_id, context=None):
-
- if context is None:
- context = {}
-
- """Change the format of working calendar from 'Openerp' format to bring it into 'Faces' format.
-
- Arguement: calendar_id -- working calendar of the project
-
- """
-
- pool = pooler.get_pool(cr.dbname)
- resource_attendance_obj = pool.get('resource.calendar.attendance')
- time_range = "8:00-8:00"
- non_working = ""
- week_days = {"0": "mon", "1": "tue", "2": "wed","3": "thu", "4": "fri", "5": "sat", "6": "sun"}
- wk_days = {}
- wk_time = {}
- wktime_list = []
- wktime_cal = []
- week_ids = resource_attendance_obj.search(cr, uid, [('calendar_id', '=', calendar_id)], context=context)
- weeks = resource_attendance_obj.read(cr, uid, week_ids, ['dayofweek', 'hour_from', 'hour_to'], context=context)
- # Convert time formats into appropriate format required
- # and create a list like [('mon', '8:00-12:00'), ('mon', '13:00-18:00')]
- for week in weeks:
- res_str = ""
- if week_days.has_key(week['dayofweek']):
- day = week_days[week['dayofweek']]
- wk_days[week['dayofweek']] = week_days[week['dayofweek']]
- hour_from_str = convert_timeformat(cr, uid, week['hour_from'])
- hour_to_str = convert_timeformat(cr, uid, week['hour_to'])
- res_str = hour_from_str + '-' + hour_to_str
- wktime_list.append((day, res_str))
- # Convert into format like [('mon', '8:00-12:00', '13:00-18:00')]
- for item in wktime_list:
- if wk_time.has_key(item[0]):
- wk_time[item[0]].append(item[1])
- else:
- wk_time[item[0]] = [item[0]]
- wk_time[item[0]].append(item[1])
- for k,v in wk_time.items():
- wktime_cal.append(tuple(v))
- # Add for the non-working days like: [('sat, sun', '8:00-8:00')]
- for k, v in wk_days.items():
- if week_days.has_key(k):
- week_days.pop(k)
- for v in week_days.itervalues():
- non_working += v + ','
- if non_working:
- wktime_cal.append((non_working[:-1], time_range))
- return wktime_cal
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/project_mailgate/project_mailgate_view.xml b/addons/project_mailgate/project_mailgate_view.xml
index b31eb85328e..8c8816ebbd5 100644
--- a/addons/project_mailgate/project_mailgate_view.xml
+++ b/addons/project_mailgate/project_mailgate_view.xml
@@ -8,9 +8,9 @@
-
+
-
+