[MERGE]: Merge with lp:openobject-trunk-dev-addons2

bzr revid: ksa@tinyerp.co.in-20100927044952-f6k0wizrmnz03ny0
This commit is contained in:
ksa (Open ERP)
2010-09-27 10:19:52 +05:30
29 changed files with 1045 additions and 1532 deletions
@@ -23,15 +23,6 @@
-
!assert {model: account.invoice, id: account_invoice_currency, string: Customer Invoice is in Draft state}:
- state == 'draft'
-
I change the state of invoice to proforma2 by clicking PRO-FORMA button
-
!workflow {model: account.invoice, action: invoice_proforma2, ref: account_invoice_currency}
-
I check that now customer invoice is in the "proforma2" state
-
!assert {model: account.invoice, id: account_invoice_currency}:
- state == 'proforma2'
-
Now I select USD as new currency
-
@@ -49,6 +40,15 @@
"active_model": "account.invoice", "tz": False, "record_id": 4, "active_ids":
[ref("account_invoice_currency")], "type": "out_invoice", "active_id": ref("account_invoice_currency"),
})
-
I change the state of invoice to proforma2 by clicking PRO-FORMA button
-
!workflow {model: account.invoice, action: invoice_proforma2, ref: account_invoice_currency}
-
I check that now customer invoice is in the "proforma2" state
-
!assert {model: account.invoice, id: account_invoice_currency}:
- state == 'proforma2'
-
I can't change the currency of invoice when it is not in draft state so i change the state to cancel
-
@@ -28,6 +28,210 @@ class account_analytic_account(osv.osv):
_name = "account.analytic.account"
_inherit = "account.analytic.account"
def _analysis_all(self, cr, uid, ids, fields, arg, context=None):
dp = 2
res = dict([(i, {}) for i in ids])
parent_ids = tuple(self.search(cr, uid, [('parent_id', 'child_of', ids)]))
accounts = self.browse(cr, uid, ids, context=context)
for f in fields:
if f == 'user_ids':
cr.execute('SELECT MAX(id) FROM res_users')
max_user = cr.fetchone()[0]
if parent_ids:
cr.execute('SELECT DISTINCT("user") FROM account_analytic_analysis_summary_user ' \
'WHERE account_id IN %s AND unit_amount <> 0.0', (parent_ids,))
result = cr.fetchall()
else:
result = []
for id in ids:
res[id][f] = [int((id * max_user) + x[0]) for x in result]
elif f == 'month_ids':
if parent_ids:
cr.execute('SELECT DISTINCT(month_id) FROM account_analytic_analysis_summary_month ' \
'WHERE account_id IN %s AND unit_amount <> 0.0', (parent_ids,))
result = cr.fetchall()
else:
result = []
for id in ids:
res[id][f] = [int(id * 1000000 + int(x[0])) for x in result]
elif f == 'last_worked_invoiced_date':
for id in ids:
res[id][f] = 0.0
if parent_ids:
cr.execute("select account_analytic_line.account_id, max(date) \
from account_analytic_line \
where account_id IN %s \
and invoice_id is not null \
GROUP BY account_analytic_line.account_id;", (parent_ids,))
for account_id, sum in cr.fetchall():
res[account_id][f] = sum
for account in accounts:
for child in account.child_ids:
if res[account.id].get(f, '') < res.get(child.id, {}).get(f, ''):
res[account.id][f] = res.get(child.id, {}).get(f, '')
elif f == 'ca_to_invoice':
for id in ids:
res[id][f] = 0.0
res2 = {}
if parent_ids:
# Amount uninvoiced hours to invoice at sale price
# Warning
# This computation doesn't take care of pricelist !
# Just consider list_price
cr.execute("""SELECT account_analytic_account.id, \
COALESCE(sum (product_template.list_price * \
account_analytic_line.unit_amount * \
((100-hr_timesheet_invoice_factor.factor)/100)),0.0) \
AS ca_to_invoice \
FROM product_template \
join product_product \
on product_template.id = product_product.product_tmpl_id \
JOIN account_analytic_line \
on account_analytic_line.product_id = product_product.id \
JOIN account_analytic_journal \
on account_analytic_line.journal_id = account_analytic_journal.id \
JOIN account_analytic_account \
on account_analytic_account.id = account_analytic_line.account_id \
JOIN hr_timesheet_invoice_factor \
on hr_timesheet_invoice_factor.id = account_analytic_account.to_invoice \
WHERE account_analytic_account.id IN %s \
AND account_analytic_line.invoice_id is null \
AND account_analytic_line.to_invoice IS NOT NULL \
and account_analytic_journal.type in ('purchase','general') \
GROUP BY account_analytic_account.id;""", (parent_ids,))
for account_id, sum in cr.fetchall():
res[account_id][f] = round(sum, dp)
for account in accounts:
#res.setdefault(account.id, 0.0)
res2.setdefault(account.id, 0.0)
for child in account.child_ids:
if child.id != account.id:
res[account.id][f] += res.get(child.id, {}).get(f, 0.0)
res2[account.id] += res2.get(child.id, 0.0)
# sum both result on account_id
for id in ids:
res[id][f] = round(res.get(id, {}).get(f, 0.0), dp) + round(res2.get(id, 0.0), 2)
elif f == 'last_invoice_date':
for id in ids:
res[id][f] = ''
if parent_ids:
cr.execute ("select account_analytic_line.account_id, \
date(max(account_invoice.date_invoice)) \
from account_analytic_line \
join account_invoice \
on account_analytic_line.invoice_id = account_invoice.id \
where account_analytic_line.account_id IN %s \
and account_analytic_line.invoice_id is not null \
GROUP BY account_analytic_line.account_id",(parent_ids,))
for account_id, sum in cr.fetchall():
res[account_id] = sum
for account in accounts:
for child in account.child_ids:
if res[account.id][f] < res.get(child.id, {}).get(f, ''):
res[account.id][f] = res.get(child.id, {}).get(f, '')
elif f == 'last_worked_date':
for id in ids:
res[id][f] = ''
if parent_ids:
cr.execute("select account_analytic_line.account_id, max(date) \
from account_analytic_line \
where account_id IN %s \
and invoice_id is null \
GROUP BY account_analytic_line.account_id" ,(parent_ids,))
for account_id, sum in cr.fetchall():
res[account_id][f] = sum
for account in accounts:
for child in account.child_ids:
if res[account.id][f] < res.get(child.id, {}).get(f, ''):
res[account.id][f] = res.get(child.id, {}).get(f, '')
elif f == 'hours_qtt_non_invoiced':
for id in ids:
res[id][f] = 0.0
if parent_ids:
cr.execute("select account_analytic_line.account_id, COALESCE(sum(unit_amount),0.0) \
from account_analytic_line \
join account_analytic_journal \
on account_analytic_line.journal_id = account_analytic_journal.id \
where account_analytic_line.account_id IN %s \
and account_analytic_journal.type='general' \
and invoice_id is null \
AND to_invoice IS NOT NULL \
GROUP BY account_analytic_line.account_id;",(parent_ids,))
for account_id, sum in cr.fetchall():
res[account_id][f] = round(sum, dp)
for account in accounts:
for child in account.child_ids:
if account.id != child.id:
res[account.id][f] += res.get(child.id, {}).get(f, 0.0)
for id in ids:
res[id][f] = round(res[id][f], dp)
elif f == 'hours_quantity':
for id in ids:
res[id][f] = 0.0
if parent_ids:
cr.execute("select account_analytic_line.account_id,COALESCE(SUM(unit_amount),0.0) \
from account_analytic_line \
join account_analytic_journal \
on account_analytic_line.journal_id = account_analytic_journal.id \
where account_analytic_line.account_id IN %s \
and account_analytic_journal.type='general' \
GROUP BY account_analytic_line.account_id",(parent_ids,))
ff = cr.fetchall()
for account_id, sum in ff:
res[account_id][f] = round(sum, dp)
for account in accounts:
for child in account.child_ids:
if account.id != child.id:
res[account.id][f] += res.get(child.id, {}).get(f, 0.0)
for id in ids:
res[id][f] = round(res[id][f], dp)
elif f == 'ca_theorical':
# TODO Take care of pricelist and purchase !
for id in ids:
res[id][f] = 0.0
res2 = {}
# Warning
# This computation doesn't take care of pricelist !
# Just consider list_price
if parent_ids:
cr.execute("""select account_analytic_line.account_id as account_id, \
COALESCE(sum((account_analytic_line.unit_amount * pt.list_price) \
- (account_analytic_line.unit_amount * pt.list_price \
* hr.factor)),0.0) as somme
from account_analytic_line \
left join account_analytic_journal \
on (account_analytic_line.journal_id = account_analytic_journal.id) \
join product_product pp \
on (account_analytic_line.product_id = pp.id) \
join product_template pt \
on (pp.product_tmpl_id = pt.id) \
join account_analytic_account a \
on (a.id=account_analytic_line.account_id) \
join hr_timesheet_invoice_factor hr \
on (hr.id=a.to_invoice) \
where account_analytic_line.account_id IN %s \
and a.to_invoice IS NOT NULL \
and account_analytic_journal.type IN ('purchase','general')
GROUP BY account_analytic_line.account_id""",(parent_ids,))
for account_id, sum in cr.fetchall():
res2[account_id] = round(sum, dp)
for account in accounts:
res2.setdefault(account.id, 0.0)
for child in account.child_ids:
if account.id != child.id:
res[account.id][f] += res.get(child.id, {}).get(f, 0.0)
res[account.id][f] += res2.get(child.id, 0.0)
# sum both result on account_id
for id in ids:
res[id][f] = round(res[id][f], dp) + round(res2.get(id, 0.0), dp)
return res
def _ca_invoiced_calc(self, cr, uid, ids, name, arg, context=None):
res = {}
parent_ids = tuple(self.search(cr, uid, [('parent_id', 'child_of', ids)]))
@@ -44,101 +248,6 @@ class account_analytic_account(osv.osv):
return self._compute_currency_for_level_tree(cr, uid, ids, parent_ids, res, context)
def _ca_to_invoice_calc(self, cr, uid, ids, name, arg, context=None):
res = {}
res2 = {}
parent_ids = tuple(self.search(cr, uid, [('parent_id', 'child_of', ids)]))
if parent_ids:
# Amount uninvoiced hours to invoice at sale price
# Warning
# This computation doesn't take care of pricelist !
# Just consider list_price
cr.execute("""SELECT account_analytic_account.id, \
COALESCE(sum (product_template.list_price * \
account_analytic_line.unit_amount * \
((100-hr_timesheet_invoice_factor.factor)/100)),0.0) \
AS ca_to_invoice \
FROM product_template \
join product_product \
on product_template.id = product_product.product_tmpl_id \
JOIN account_analytic_line \
on account_analytic_line.product_id = product_product.id \
JOIN account_analytic_journal \
on account_analytic_line.journal_id = account_analytic_journal.id \
JOIN account_analytic_account \
on account_analytic_account.id = account_analytic_line.account_id \
JOIN hr_timesheet_invoice_factor \
on hr_timesheet_invoice_factor.id = account_analytic_account.to_invoice \
WHERE account_analytic_account.id IN %s \
AND account_analytic_line.invoice_id is null \
AND account_analytic_line.to_invoice IS NOT NULL \
and account_analytic_journal.type in ('purchase','general') \
GROUP BY account_analytic_account.id;""",(parent_ids,))
for account_id, sum in cr.fetchall():
res[account_id] = round(sum,2)
for obj_id in ids:
res.setdefault(obj_id, 0.0)
res2.setdefault(obj_id, 0.0)
for child_id in self.search(cr, uid,
[('parent_id', 'child_of', [obj_id])]):
if child_id != obj_id:
res[obj_id] += res.get(child_id, 0.0)
res2[obj_id] += res2.get(child_id, 0.0)
# sum both result on account_id
for id in ids:
res[id] = round(res.get(id, 0.0),2) + round(res2.get(id, 0.0),2)
return res
def _hours_qtt_non_invoiced_calc (self, cr, uid, ids, name, arg, context=None):
res = {}
parent_ids = tuple(self.search(cr, uid, [('parent_id', 'child_of', ids)]))
if parent_ids:
cr.execute("select account_analytic_line.account_id, COALESCE(sum(unit_amount),0.0) \
from account_analytic_line \
join account_analytic_journal \
on account_analytic_line.journal_id = account_analytic_journal.id \
where account_analytic_line.account_id IN %s \
and account_analytic_journal.type='general' \
and invoice_id is null \
AND to_invoice IS NOT NULL \
GROUP BY account_analytic_line.account_id;",(parent_ids,))
for account_id, sum in cr.fetchall():
res[account_id] = round(sum,2)
for obj_id in ids:
res.setdefault(obj_id, 0.0)
for child_id in self.search(cr, uid,
[('parent_id', 'child_of', [obj_id])]):
if child_id != obj_id:
res[obj_id] += res.get(child_id, 0.0)
for id in ids:
res[id] = round(res.get(id, 0.0),2)
return res
def _hours_quantity_calc(self, cr, uid, ids, name, arg, context=None):
res = {}
parent_ids = tuple(self.search(cr, uid, [('parent_id', 'child_of', ids)]))
if parent_ids:
cr.execute("select account_analytic_line.account_id,COALESCE(SUM(unit_amount),0.0) \
from account_analytic_line \
join account_analytic_journal \
on account_analytic_line.journal_id = account_analytic_journal.id \
where account_analytic_line.account_id IN %s \
and account_analytic_journal.type='general' \
GROUP BY account_analytic_line.account_id",(parent_ids,))
ff = cr.fetchall()
for account_id, sum in ff:
res[account_id] = round(sum,2)
for obj_id in ids:
res.setdefault(obj_id, 0.0)
for child_id in self.search(cr, uid,
[('parent_id', 'child_of', [obj_id])]):
if child_id != obj_id:
res[obj_id] += res.get(child_id, 0.0)
for id in ids:
res[id] = round(res.get(id, 0.0),2)
return res
def _total_cost_calc(self, cr, uid, ids, name, arg, context=None):
res = {}
parent_ids = tuple(self.search(cr, uid, [('parent_id', 'child_of', ids)]))
@@ -155,117 +264,6 @@ class account_analytic_account(osv.osv):
res[account_id] = round(sum,2)
return self._compute_currency_for_level_tree(cr, uid, ids, parent_ids, res, context)
# TODO Take care of pricelist and purchase !
def _ca_theorical_calc(self, cr, uid, ids, name, arg, context=None):
res = {}
res2 = {}
parent_ids = tuple(self.search(cr, uid, [('parent_id', 'child_of', ids)]))
# Warning
# This computation doesn't take care of pricelist !
# Just consider list_price
if parent_ids:
cr.execute("""select account_analytic_line.account_id as account_id, \
COALESCE(sum((account_analytic_line.unit_amount * pt.list_price) \
- (account_analytic_line.unit_amount * pt.list_price \
* hr.factor)),0.0) as somme
from account_analytic_line \
left join account_analytic_journal \
on (account_analytic_line.journal_id = account_analytic_journal.id) \
join product_product pp \
on (account_analytic_line.product_id = pp.id) \
join product_template pt \
on (pp.product_tmpl_id = pt.id) \
join account_analytic_account a \
on (a.id=account_analytic_line.account_id) \
join hr_timesheet_invoice_factor hr \
on (hr.id=a.to_invoice) \
where account_analytic_line.account_id IN %s \
and a.to_invoice IS NOT NULL \
and account_analytic_journal.type IN ('purchase','general')
GROUP BY account_analytic_line.account_id""",(parent_ids,))
for account_id, sum in cr.fetchall():
res2[account_id] = round(sum,2)
for obj_id in ids:
res.setdefault(obj_id, 0.0)
res2.setdefault(obj_id, 0.0)
for child_id in self.search(cr, uid,
[('parent_id', 'child_of', [obj_id])]):
if child_id != obj_id:
res[obj_id] += res.get(child_id, 0.0)
res[obj_id] += res2.get(child_id, 0.0)
# sum both result on account_id
for id in ids:
res[id] = round(res.get(id, 0.0),2) + round(res2.get(id, 0.0),2)
return res
def _last_worked_date_calc (self, cr, uid, ids, name, arg, context=None):
res = {}
parent_ids = tuple(self.search(cr, uid, [('parent_id', 'child_of', ids)]))
if parent_ids:
cr.execute("select account_analytic_line.account_id, max(date) \
from account_analytic_line \
where account_id IN %s \
and invoice_id is null \
GROUP BY account_analytic_line.account_id" ,(parent_ids,))
for account_id, sum in cr.fetchall():
res[account_id] = sum
for obj_id in ids:
res.setdefault(obj_id, '')
for child_id in self.search(cr, uid,
[('parent_id', 'child_of', [obj_id])]):
if res[obj_id] < res.get(child_id, ''):
res[obj_id] = res.get(child_id, '')
for id in ids:
res[id] = res.get(id, '')
return res
def _last_invoice_date_calc (self, cr, uid, ids, name, arg, context=None):
res = {}
parent_ids = tuple(self.search(cr, uid, [('parent_id', 'child_of', ids)]))
if parent_ids:
cr.execute ("select account_analytic_line.account_id, \
date(max(account_invoice.date_invoice)) \
from account_analytic_line \
join account_invoice \
on account_analytic_line.invoice_id = account_invoice.id \
where account_analytic_line.account_id IN %s \
and account_analytic_line.invoice_id is not null \
GROUP BY account_analytic_line.account_id",(parent_ids,))
for account_id, sum in cr.fetchall():
res[account_id] = sum
for obj_id in ids:
res.setdefault(obj_id, '')
for child_id in self.search(cr, uid,
[('parent_id', 'child_of', [obj_id])]):
if res[obj_id] < res.get(child_id, ''):
res[obj_id] = res.get(child_id, '')
for id in ids:
res[id] = res.get(id, '')
return res
def _last_worked_invoiced_date_calc (self, cr, uid, ids, name, arg, context=None):
res = {}
parent_ids = tuple(self.search(cr, uid, [('parent_id', 'child_of', ids)]))
if parent_ids:
cr.execute("select account_analytic_line.account_id, max(date) \
from account_analytic_line \
where account_id IN %s \
and invoice_id is not null \
GROUP BY account_analytic_line.account_id;",(parent_ids,))
for account_id, sum in cr.fetchall():
res[account_id] = sum
for obj_id in ids:
res.setdefault(obj_id, '')
for child_id in self.search(cr, uid,
[('parent_id', 'child_of', [obj_id])]):
if res[obj_id] < res.get(child_id, ''):
res[obj_id] = res.get(child_id, '')
for id in ids:
res[id] = res.get(id, '')
return res
def _remaining_hours_calc(self, cr, uid, ids, name, arg, context=None):
res = {}
for account in self.browse(cr, uid, ids):
@@ -338,42 +336,16 @@ class account_analytic_account(osv.osv):
res[id] = round(res.get(id, 0.0),2)
return res
def _month(self, cr, uid, ids, name, arg, context=None):
res = {}
for id in ids:
parent_ids = tuple(self.search(cr, uid, [('parent_id', 'child_of', ids)]))
if parent_ids:
cr.execute('SELECT DISTINCT(month_id) FROM account_analytic_analysis_summary_month ' \
'WHERE account_id IN %s AND unit_amount <> 0.0',(parent_ids,))
res[id] = [int(id * 1000000 + int(x[0])) for x in cr.fetchall()]
else:
res[id] = []
return res
def _user(self, cr, uid, ids, name, arg, context=None):
res = {}
cr.execute('SELECT MAX(id) FROM res_users')
max_user = cr.fetchone()[0]
for id in ids:
parent_ids = tuple(self.search(cr, uid, [('parent_id', 'child_of', ids)]))
if parent_ids:
cr.execute('SELECT DISTINCT("user") FROM account_analytic_analysis_summary_user ' \
'WHERE account_id IN %s AND unit_amount <> 0.0',(parent_ids,))
res[id] = [int((id * max_user) + x[0]) for x in cr.fetchall()]
else:
res[id] = []
return res
_columns ={
'ca_invoiced': fields.function(_ca_invoiced_calc, method=True, type='float', string='Invoiced Amount', help="Total customer invoiced amount for this account."),
'total_cost': fields.function(_total_cost_calc, method=True, type='float', string='Total Costs', help="Total of costs for this account. It includes real costs (from invoices) and indirect costs, like time spent on timesheets."),
'ca_to_invoice': fields.function(_ca_to_invoice_calc, method=True, type='float', string='Uninvoiced Amount', help="If invoice from analytic account, the remaining amount you can invoice to the customer based on the total costs."),
'ca_theorical': fields.function(_ca_theorical_calc, method=True, type='float', string='Theorical Revenue', help="Based on the costs you had on the project, what would have been the revenue if all these costs have been invoiced at the normal sale price provided by the pricelist."),
'hours_quantity': fields.function(_hours_quantity_calc, method=True, type='float', string='Hours Tot', help="Number of hours you spent on the analytic account (from timesheet). It computes on all journal of type 'general'."),
'last_invoice_date': fields.function(_last_invoice_date_calc, method=True, type='date', string='Last Invoice Date', help="Date of the last invoice created for this analytic account."),
'last_worked_invoiced_date': fields.function(_last_worked_invoiced_date_calc, method=True, type='date', string='Date of Last Invoiced Cost', help="If invoice from the costs, this is the date of the latest work or cost that have been invoiced."),
'last_worked_date': fields.function(_last_worked_date_calc, method=True, type='date', string='Date of Last Cost/Work', help="Date of the latest work done on this account."),
'hours_qtt_non_invoiced': fields.function(_hours_qtt_non_invoiced_calc, method=True, type='float', string='Uninvoiced Hours', help="Number of hours (from journal of type 'general') that can be invoiced if you invoice based on analytic account."),
'ca_to_invoice': fields.function(_analysis_all, method=True, multi='analytic_analysis', type='float', string='Uninvoiced Amount', help="If invoice from analytic account, the remaining amount you can invoice to the customer based on the total costs."),
'ca_theorical': fields.function(_analysis_all, method=True, multi='analytic_analysis', type='float', string='Theorical Revenue', help="Based on the costs you had on the project, what would have been the revenue if all these costs have been invoiced at the normal sale price provided by the pricelist."),
'hours_quantity': fields.function(_analysis_all, method=True, multi='analytic_analysis', type='float', string='Hours Tot', help="Number of hours you spent on the analytic account (from timesheet). It computes on all journal of type 'general'."),
'last_invoice_date': fields.function(_analysis_all, method=True, multi='analytic_analysis', type='date', string='Last Invoice Date', help="Date of the last invoice created for this analytic account."),
'last_worked_invoiced_date': fields.function(_analysis_all, method=True, multi='analytic_analysis', type='date', string='Date of Last Invoiced Cost', help="If invoice from the costs, this is the date of the latest work or cost that have been invoiced."),
'last_worked_date': fields.function(_analysis_all, method=True, multi='analytic_analysis', type='date', string='Date of Last Cost/Work', help="Date of the latest work done on this account."),
'hours_qtt_non_invoiced': fields.function(_analysis_all, method=True, multi='analytic_analysis', type='float', string='Uninvoiced Hours', help="Number of hours (from journal of type 'general') that can be invoiced if you invoice based on analytic account."),
'hours_qtt_invoiced': fields.function(_hours_qtt_invoiced_calc, method=True, type='float', string='Invoiced Hours', help="Number of hours that can be invoiced plus those that already have been invoiced."),
'remaining_hours': fields.function(_remaining_hours_calc, method=True, type='float', string='Remaining Hours', help="Computed using the formula: Maximum Quantity - Hours Tot."),
'remaining_ca': fields.function(_remaining_ca_calc, method=True, type='float', string='Remaining Revenue', help="Computed using the formula: Max Invoice Price - Invoiced Amount."),
@@ -381,8 +353,8 @@ class account_analytic_account(osv.osv):
'real_margin': fields.function(_real_margin_calc, method=True, type='float', string='Real Margin', help="Computed using the formula: Invoiced Amount - Total Costs."),
'theorical_margin': fields.function(_theorical_margin_calc, method=True, type='float', string='Theorical Margin', help="Computed using the formula: Theorial Revenue - Total Costs"),
'real_margin_rate': fields.function(_real_margin_rate_calc, method=True, type='float', string='Real Margin Rate (%)', help="Computes using the formula: (Real Margin / Total Costs) * 100."),
'month_ids': fields.function(_month, method=True, type='many2many', relation='account_analytic_analysis.summary.month', string='Month'),
'user_ids': fields.function(_user, method=True, type="many2many", relation='account_analytic_analysis.summary.user', string='User'),
'month_ids': fields.function(_analysis_all, method=True, multi='analytic_analysis', type='many2many', relation='account_analytic_analysis.summary.month', string='Month'),
'user_ids': fields.function(_analysis_all, method=True, multi='analytic_analysis', type="many2many", relation='account_analytic_analysis.summary.user', string='User'),
}
account_analytic_account()
@@ -155,7 +155,7 @@
<para style="terp_default_Centre_8">[[ company.currency_id.name ]]</para>
</td>
<td>
<para style="terp_default_Centre_8"><font>[[ setTag('font','font',{'face':o.font_style,'color':o.color_font.name,'backColor':o.color_back.name}) ]] [[o.name]]</font></para>
<para style="terp_default_Centre_8"><font>[[ setTag('font','font',{'face':o.font_style or "Helvetica",'color':o.color_font.name or "black",'backColor':o.color_back.name or "white"}) ]] [[o.name]]</font></para>
</td>
</tr>
</blockTable>
+14 -14
View File
@@ -35,16 +35,16 @@ class account_analytic_account(osv.osv):
cr.execute("SELECT a.id, r.currency_id FROM account_analytic_account a INNER JOIN res_company r ON (a.company_id = r.id) where a.id IN %s" , (tuple(ids2),))
currency = dict(cr.fetchall())
res_currency= self.pool.get('res.currency')
for id in ids:
if id not in ids2:
for account in self.browse(cr, uid, ids, context=context):
if account.id not in ids2:
continue
for child in self.search(cr, uid, [('parent_id', 'child_of', [id])]):
if child != id:
res.setdefault(id, 0.0)
if currency[child]!=currency[id]:
res[id] += res_currency.compute(cr, uid, currency[child], currency[id], res.get(child, 0.0), context=context)
for child in account.child_ids:
if child.id != account.id:
res.setdefault(account.id, 0.0)
if currency[child.id] != currency[account.id]:
res[account.id] += res_currency.compute(cr, uid, currency[child.id], currency[account.id], res.get(child.id, 0.0), context=context)
else:
res[id] += res.get(child, 0.0)
res[account.id] += res.get(child.id, 0.0)
cur_obj = res_currency.browse(cr, uid, currency.values(), context=context)
cur_obj = dict([(o.id, o) for o in cur_obj])
@@ -145,13 +145,13 @@ class account_analytic_account(osv.osv):
for account_id, sum in cr.fetchall():
res[account_id] = sum
for id in ids:
if id not in parent_ids:
for account in self.browse(cr, uid, ids, context=context):
if account.id not in parent_ids:
continue
for child in self.search(cr, uid, [('parent_id', 'child_of', [id])]):
if child != id:
res.setdefault(id, 0.0)
res[id] += res.get(child, 0.0)
for child in account.child_ids:
if child.id != account.id:
res.setdefault(account.id, 0.0)
res[account.id] += res.get(child.id, 0.0)
return dict([(i, res[i]) for i in ids])
def name_get(self, cr, uid, ids, context=None):
@@ -89,14 +89,17 @@
<separator orientation="vertical" />
<filter icon="terp-check"
string="To Do"
domain="[('state','in',('draft','open'))]"/>
string="Todo"
domain="[('state','in',('draft','open'))]"
help="Phone calls which are in draft and open state"/>
<filter icon="gtk-media-pause"
string="Pending"
domain="[('state','=','pending')]"/>
<filter icon="terp-dialog-close"
string="Done"
domain="[('state','=','done')]"/>
string="Not Held"
domain="[('state','=','pending')]"
help="Phone calls which are in pending state"/>
<filter icon="terp-camera_test"
string="Held"
domain="[('state','=','done')]"
help="Phone calls which are in closed state"/>
<separator orientation="vertical" />
<field name="section_id" string="Sales Team"
default="context.get('section_id', False)"
@@ -121,7 +124,6 @@
context="{'group_by':'section_id'}" />
<separator orientation="vertical" />
<filter string="Stage" icon="terp-stage" domain="[]" context="{'group_by':'stage_id'}"/>
<filter string="Priority" icon="terp-rating-rated" domain="[]" context="{'group_by':'priority'}" />
<filter string="Type" icon="terp-stock_symbol-selection"
domain="[]" context="{'group_by':'categ_id'}" />
@@ -145,7 +147,6 @@
<group expand="0" string="Extended Filters..." groups="base.group_extended">
<field name="partner_id"/>
<separator orientation="vertical"/>
<field name="stage_id" widget="selection" domain="[('object_id.model', '=', 'crm.phonecall')]"/>
<field string="Type" name="categ_id" widget="selection" domain="[('object_id.model', '=', 'crm.phonecall')]"/>
<separator orientation="vertical"/>
<field name="company_id" groups="base.group_multi_company"/>
+1 -78
View File
@@ -113,87 +113,10 @@ class res_users(osv.osv):
_inherit = 'res.users'
_description = 'User'
def _parent_compute(self, cr, uid, ids, name, args, context=None):
if context is None:
context = {}
result = {}
obj_dept = self.pool.get('hr.department')
for user_id in ids:
emp_ids = self.pool.get('hr.employee').search(cr, uid, [('user_id', '=', user_id)], context=context)
cr.execute('SELECT emp.department_id FROM hr_employee AS emp \
JOIN resource_resource AS res ON res.id = emp.resource_id \
JOIN hr_department as dept ON dept.id = emp.department_id \
WHERE res.user_id = %s AND emp.department_id IS NOT NULL AND dept.manager_id IS NOT NULL', (user_id,))
ids_dept = [x[0] for x in cr.fetchall()]
parent_ids = []
if ids_dept:
data_dept = obj_dept.read(cr, uid, ids_dept, ['manager_id'], context=context)
parent_ids = map(lambda x: x['manager_id'][0], data_dept)
cr.execute('SELECT res.user_id FROM hr_employee AS emp JOIN resource_resource AS res ON res.id=emp.resource_id \
WHERE emp.id IN %s AND res.user_id IS NOT NULL', (tuple(parent_ids),))
parent_ids = [x[0] for x in cr.fetchall()]
result[user_id] = parent_ids
return result
def _parent_search(self, cr, uid, obj, name, args, context=None):
if context is None:
context = {}
parent = []
for arg in args:
if arg[0] == 'parent_id':
parent = arg[2]
child_ids = self._child_compute(cr, uid, parent, name, args, context=context)
if not child_ids:
return [('id', 'in', [0])]
return [('id', 'in', child_ids.get(uid, []))]
def _child_compute(self, cr, uid, ids, name, args, context=None):
if context is None:
context = {}
obj_dept = self.pool.get('hr.department')
obj_user = self.pool.get('res.users')
result = {}
for user_id in ids:
child_ids = []
cr.execute('SELECT dept.id FROM hr_department AS dept \
LEFT JOIN hr_employee AS emp ON dept.manager_id = emp.id \
WHERE emp.id IN \
(SELECT emp.id FROM hr_employee \
JOIN resource_resource r ON r.id = emp.resource_id WHERE r.user_id=' + str(user_id) + ') ')
mgnt_dept_ids = [x[0] for x in cr.fetchall()]
ids_dept = obj_dept.search(cr, uid, [('id', 'child_of', mgnt_dept_ids)], context=context)
if ids_dept:
data_dept = obj_dept.read(cr, uid, ids_dept, ['member_ids'], context=context)
childs = map(lambda x: x['member_ids'], data_dept)
childs = tools.flatten(childs)
childs = obj_user.search(cr, uid, [('id', 'in', childs),('active', '=', True)], context=context)
if user_id in childs:
childs.remove(user_id)
child_ids.extend(tools.flatten(childs))
set = {}
map(set.__setitem__, child_ids, [])
child_ids = set.keys()
result[user_id] = child_ids
return result
def _child_search(self, cr, uid, obj, name, args, context=None):
if context is None:
context = {}
parent = []
for arg in args:
if arg[0] == 'child_ids':
parent = arg[2]
child_ids = self._child_compute(cr, uid, parent, name, args, context=context)
if not child_ids:
return [('id', 'in', [0])]
return [('id', 'in', child_ids.get(uid, []))]
_columns = {
'parent_id': fields.function(_parent_compute, relation='res.users', fnct_search=_parent_search, method=True, string="Managers", type='many2many'),
'child_ids': fields.function(_child_compute, relation='res.users', fnct_search=_child_search, method=True, string="Subordinates", type='many2many'),
'context_department_id': fields.many2one('hr.department', 'Departments'),
}
res_users()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
-4
View File
@@ -87,10 +87,6 @@
<notebook position="inside">
<page string="Departments" groups="base.group_extended">
<field name="context_department_id" completion="1" widget="selection" string="Department"/>
<separator string="Managers" colspan="4"/>
<field name="parent_id" nolabel="1" colspan="4"/>
<separator string="Subordinates" colspan="4"/>
<field name="child_ids" nolabel="1" colspan="4"/>
</page>
</notebook>
</field>
+1 -1
View File
@@ -259,7 +259,7 @@
<para style="terp_default_9">
<font color="white"> </font>
</para>
<para style="terp_default_9">[[ o.note or '' ]] [[ setTag('para','xpre') ]]</para>
<para style="terp_default_9">[[ setTag('para','xpre') ]] [[ o.note or '' ]] </para>
<para style="terp_default_9">
<font color="white"> </font>
</para>
+1
View File
@@ -784,6 +784,7 @@ class hr_payslip(osv.osv):
'contract_id':fields.many2one('hr.contract', 'Contract', required=False),
'igross': fields.float('Calculaton Field', readonly=True, digits=(16, 2), help="Calculation field used for internal calculation, do not place this on form"),
'inet': fields.float('Calculaton Field', readonly=True, digits=(16, 2), help="Calculation field used for internal calculation, do not place this on form"),
'period_id': fields.many2one('account.period', 'Force Period', domain=[('state','<>','done')], help="Keep empty to use the period of the validation(Payslip) date."),
}
_defaults = {
'date': lambda *a: time.strftime('%Y-%m-%d'),
+1 -1
View File
@@ -500,12 +500,12 @@
</notebook>
<group col="10" colspan="4">
<field name="state"/>
<button string="Cancel" icon="terp-dialog-close" name="cancel_sheet" states="draft,hr_check,confirm"/>
<button string="Compute Sheet" icon="terp-stock_format-scientific" name="compute_sheet" states="new"/>
<button string="Recompute Sheet" icon="terp-stock_format-scientific" name="compute_sheet" type="object" states="draft"/>
<button string="Verify Sheet" icon="terp-camera_test" name="verify_sheet" states="draft"/>
<button string="Approve Sheet" icon="terp-camera_test" name="final_verify_sheet" states="hr_check"/>
<button string="Pay Salary" icon="terp-dolar_ok!" name="process_sheet" states="confirm"/>
<button string="Cancel" icon="terp-dialog-close" name="cancel_sheet" states="draft,hr_check,confirm"/>
<button string="Set to Draft" icon="terp-stock_effects-object-colorize" name="set_to_draft" states="cancel"/>
</group>
</form>
+1 -1
View File
@@ -77,7 +77,7 @@ class report_custom(report_rml):
<amount>%.2f</amount>
</time-element>
'''
rpt_obj = pooler.get_pool(cr.dbname).get('hr.holidays')
rpt_obj = pooler.get_pool(cr.dbname).get('hr.employee')
rml_obj=report_sxw.rml_parse(cr, uid, rpt_obj._name,context)
header_xml = '''
<header>
@@ -97,7 +97,7 @@ class report_custom(report_rml):
# Computing the xml
#Without this, report don't show non-ascii characters (TO CHECK)
date_xml = '\n'.join(date_xml)
rpt_obj = pooler.get_pool(cr.dbname).get('hr.holidays')
rpt_obj = pooler.get_pool(cr.dbname).get('hr.employee')
rml_obj=report_sxw.rml_parse(cr, uid, rpt_obj._name,context)
header_xml = '''
<header>
@@ -44,17 +44,22 @@ class account_analytic_account(osv.osv):
if context is None:
context = {}
res = {}
cr.execute('select account_id as account_id, l.invoice_id from hr_analytic_timesheet h left join account_analytic_line l on (h.line_id=l.id)')
account_to_invoice_map = {}
for rec in cr.dictfetchall():
account_to_invoice_map.setdefault(rec['account_id'], []).append(rec['invoice_id'])
for account in self.browse(cr, uid, ids, context=context):
invoiced = {}
cr.execute('select distinct(l.invoice_id) from hr_analytic_timesheet h left join account_analytic_line l on (h.line_id=l.id) where account_id=%s', (account.id,))
invoice_ids = filter(None, map(lambda x: x[0], cr.fetchall()))
invoice_ids = filter(None, list(set(account_to_invoice_map.get(account.id, []))))
for invoice in obj_invoice.browse(cr, uid, invoice_ids, context=context):
res.setdefault(account.id, 0.0)
res[account.id] += invoice.amount_untaxed
for id in ids:
res[id] = round(res.get(id, 0.0),2)
return res
return res
_inherit = "account.analytic.account"
_columns = {
+6 -1
View File
@@ -14,7 +14,12 @@
<field name="name">Repairs workshop</field>
<field name="calendar_id" ref="resource.timesheet_group1"/>
</record>
<!--
Resource: res.company
-->
<record id="stock.res_company_tinyshop0" model="res.company">
<field eval="1.0" name="manufacturing_lead"/>
</record>
<!--
Resource: mrp.property.group
-->
+296 -15
View File
@@ -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,48 @@ 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:
@@ -241,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):
@@ -266,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:
@@ -1,741 +1,393 @@
<?xml version="1.0" ?>
<openerp>
<data noupdate="1">
<!-- Users -->
<record id="res_users_demouser1" model="res.users">
<field model="ir.actions.actions" name="menu_id" search="[('name', '=', u'Menu')]"/>
<field name="address_id" ref="base.main_address"/>
<field name="context_lang">en_US</field>
<field name="name">Demo User1</field>
<field eval="[(6, 0, [ref('base.group_user')])]" name="groups_id"/>
<field name="signature">Mr Demo</field>
<field name="company_id" ref="base.main_company"/>
<field eval="[(6, 0, [])]" name="roles_id"/>
<field eval="[(6, 0, [])]" name="rules_id"/>
<field eval="1" name="active"/>
<field model="ir.actions.actions" name="action_id" search="[('name', '=', u'Setup')]"/>
<field name="login">demo1</field>
<field name="password">demo1</field>
<field eval="[(6, 0, [])]" name="company_ids"/>
</record>
<record id="res_users_manager0" model="res.users">
<field model="ir.actions.actions" name="menu_id" search="[('name', '=', u'Menu')]"/>
<field name="context_lang">en_US</field>
<field name="name">Manager1</field>
<!--
This Demo data file includes Users, Human Resources, Projects and it' members list, Phases and Resources,Tasks allocation and also run scheduling of phase and tasks.
-->
<!-- Users -->
<record id="res_users_analyst" model="res.users">
<field name="name">Phoung</field>
<field eval="[(6, 0, [ref('base.group_user'), ref('project.group_project_manager')])]" name="groups_id"/>
<field name="company_id" ref="base.main_company"/>
<field eval="[(6, 0, [])]" name="roles_id"/>
<field eval="[(6, 0, [])]" name="rules_id"/>
<field eval="1" name="active"/>
<field model="ir.actions.actions" name="action_id" search="[('name', '=', u'Menu')]"/>
<field name="login">manager1</field>
<field name="password">manager1</field>
<field eval="[(6, 0, [])]" name="company_ids"/>
<field name="login">phu</field>
<field name="password">phu</field>
</record>
<record id="res_users_manager1" model="res.users">
<field model="ir.actions.actions" name="menu_id" search="[('name', '=', u'Menu')]"/>
<field name="context_lang">en_US</field>
<field name="name">Manager2</field>
<record id="res_users_project_manager" model="res.users">
<field name="name">Anthony</field>
<field eval="[(6, 0, [ref('base.group_user'), ref('project.group_project_manager')])]" name="groups_id"/>
<field name="company_id" ref="base.main_company"/>
<field eval="[(6, 0, [])]" name="roles_id"/>
<field eval="[(6, 0, [])]" name="rules_id"/>
<field eval="1" name="active"/>
<field model="ir.actions.actions" name="action_id" search="[('name', '=', u'Menu')]"/>
<field name="login">manager2</field>
<field name="password">manager2</field>
<field eval="[(6, 0, [])]" name="company_ids"/>
<field name="login">al</field>
<field name="password">al</field>
</record>
<record id="res_users_user0" model="res.users">
<field model="ir.actions.actions" name="menu_id" search="[('name', '=', u'Menu')]"/>
<field name="context_lang">en_US</field>
<field name="name">user1</field>
<record id="res_users_technical_leader" model="res.users">
<field name="name">Qwintin</field>
<field eval="[(6, 0, [ref('base.group_user'), ref('project.group_project_user')])]" name="groups_id"/>
<field name="company_id" ref="base.main_company"/>
<field eval="[(6, 0, [])]" name="roles_id"/>
<field eval="[(6, 0, [])]" name="rules_id"/>
<field eval="1" name="active"/>
<field model="ir.actions.actions" name="action_id" search="[('name', '=', u'Menu')]"/>
<field name="login">user1</field>
<field name="password">USER1</field>
<field eval="[(6, 0, [])]" name="company_ids"/>
<field name="login">qdp</field>
<field name="password">qdp</field>
</record>
<record id="res_users_user1" model="res.users">
<field model="ir.actions.actions" name="menu_id" search="[('name', '=', u'Menu')]"/>
<field name="context_lang">en_US</field>
<field name="name">user2</field>
<record id="res_users_developer" model="res.users">
<field name="name">Francois</field>
<field eval="[(6, 0, [ref('base.group_user'), ref('project.group_project_user')])]" name="groups_id"/>
<field name="company_id" ref="base.main_company"/>
<field eval="[(6, 0, [])]" name="roles_id"/>
<field eval="[(6, 0, [])]" name="rules_id"/>
<field eval="1" name="active"/>
<field model="ir.actions.actions" name="action_id" search="[('name', '=', u'Menu')]"/>
<field name="login">user2</field>
<field name="password">user2</field>
<field eval="[(6, 0, [])]" name="company_ids"/>
<field name="login">fpi</field>
<field name="password">fpi</field>
</record>
<record id="res_users_userfinance0" model="res.users">
<field model="ir.actions.actions" name="menu_id" search="[('name', '=', u'Menu')]"/>
<field name="context_lang">en_US</field>
<field name="name">user_finance</field>
<record id="res_users_designer" model="res.users">
<field name="name">Julien</field>
<field eval="[(6, 0, [ref('base.group_user'), ref('project.group_project_user')])]" name="groups_id"/>
<field name="login">jth</field>
<field name="password">jth</field>
</record>
<record id="res_users_tester" model="res.users">
<field name="name">Alien</field>
<field eval="[(6, 0, [ref('base.group_user'), ref('project.group_project_user')])]" name="groups_id"/>
<field name="login">apr</field>
<field name="password">apr</field>
</record>
<record id="res_users_finacial_manager" model="res.users">
<field name="name">Fabian</field>
<field eval="[(6, 0, [ref('base.group_user'), ref('project.group_project_finance')])]" name="groups_id"/>
<field name="company_id" ref="base.main_company"/>
<field eval="[(6, 0, [])]" name="roles_id"/>
<field eval="[(6, 0, [])]" name="rules_id"/>
<field eval="1" name="active"/>
<field model="ir.actions.actions" name="action_id" search="[('name', '=', u'Menu')]"/>
<field name="login">user_finance</field>
<field name="password">user_finance</field>
<field eval="[(6, 0, [])]" name="company_ids"/>
<field name="login">fbs</field>
<field name="password">fbs</field>
</record>
<record id="res_users_userdesign0" model="res.users">
<field model="ir.actions.actions" name="menu_id" search="[('name', '=', u'Menu')]"/>
<field name="context_lang">en_US</field>
<field name="name">user_design1</field>
<field eval="[(6, 0, [ref('base.group_user')])]" name="groups_id"/>
<field name="company_id" ref="base.main_company"/>
<field eval="[(6, 0, [])]" name="roles_id"/>
<field eval="[(6, 0, [])]" name="rules_id"/>
<field eval="1" name="active"/>
<field model="ir.actions.actions" name="action_id" search="[('name', '=', u'Menu')]"/>
<field name="login">user_design1</field>
<field name="password">user_design1</field>
<field eval="[(6, 0, [])]" name="company_ids"/>
</record>
<record id="res_users_userdesign1" model="res.users">
<field model="ir.actions.actions" name="menu_id" search="[('name', '=', u'Menu')]"/>
<field name="context_lang">en_US</field>
<field name="name">user_design2</field>
<field eval="[(6, 0, [ref('base.group_user')])]" name="groups_id"/>
<field name="company_id" ref="base.main_company"/>
<field eval="[(6, 0, [])]" name="roles_id"/>
<field eval="[(6, 0, [])]" name="rules_id"/>
<field eval="1" name="active"/>
<field model="ir.actions.actions" name="action_id" search="[('name', '=', u'Menu')]"/>
<field name="login">user_design2</field>
<field name="password">user_design2</field>
<field eval="[(6, 0, [])]" name="company_ids"/>
</record>
<record id="res_users_userdeveloper0" model="res.users">
<field model="ir.actions.actions" name="menu_id" search="[('name', '=', u'Menu')]"/>
<field name="context_lang">en_US</field>
<field name="name">user_developer1</field>
<field eval="[(6, 0, [ref('base.group_user')])]" name="groups_id"/>
<field name="company_id" ref="base.main_company"/>
<field eval="[(6, 0, [])]" name="roles_id"/>
<field eval="[(6, 0, [])]" name="rules_id"/>
<field eval="1" name="active"/>
<field model="ir.actions.actions" name="action_id" search="[('name', '=', u'Menu')]"/>
<field name="login">user_developer1</field>
<field name="password">user_developer1</field>
<field eval="[(6, 0, [])]" name="company_ids"/>
</record>
<record id="res_users_userdeveloper1" model="res.users">
<field model="ir.actions.actions" name="menu_id" search="[('name', '=', u'Menu')]"/>
<field name="context_lang">en_US</field>
<field name="name">user_developer2</field>
<field eval="[(6, 0, [ref('base.group_user')])]" name="groups_id"/>
<field name="company_id" ref="base.main_company"/>
<field eval="[(6, 0, [])]" name="roles_id"/>
<field eval="[(6, 0, [])]" name="rules_id"/>
<field eval="1" name="active"/>
<field model="ir.actions.actions" name="action_id" search="[('name', '=', u'Menu')]"/>
<field name="login">user_developer2</field>
<field name="password">user_developer1</field>
<field eval="[(6, 0, [])]" name="company_ids"/>
</record>
<record id="res_users_usertester0" model="res.users">
<field model="ir.actions.actions" name="menu_id" search="[('name', '=', u'Menu')]"/>
<field name="context_lang">en_US</field>
<field name="name">user_tester1</field>
<field eval="[(6,0,[ref('base.group_user')])]" name="groups_id"/>
<field name="company_id" ref="base.main_company"/>
<field eval="[(6, 0, [])]" name="roles_id"/>
<field eval="[(6, 0, [])]" name="rules_id"/>
<field eval="1" name="active"/>
<field model="ir.actions.actions" name="action_id" search="[('name', '=', u'Menu')]"/>
<field name="login">user_tester1</field>
<field name="password">user_tester1</field>
<field eval="[(6, 0, [])]" name="company_ids"/>
</record>
<record id="res_users_usertester1" model="res.users">
<field model="ir.actions.actions" name="menu_id" search="[('name', '=', u'Menu')]"/>
<field name="context_lang">en_US</field>
<field name="name">user_tester2</field>
<field eval="[(6, 0, [ref('base.group_user')])]" name="groups_id"/>
<field name="company_id" ref="base.main_company"/>
<field eval="[(6, 0, [])]" name="roles_id"/>
<field eval="[(6, 0, [])]" name="rules_id"/>
<field eval="1" name="active"/>
<field model="ir.actions.actions" name="action_id" search="[('name', '=', u'Menu')]"/>
<field name="login">user_tester2</field>
<field name="password">user_tester2</field>
<field eval="[(6, 0, [])]" name="company_ids"/>
</record>
<record id="res_users_useranalyst0" model="res.users">
<field model="ir.actions.actions" name="menu_id" search="[('name', '=', u'Menu')]"/>
<field name="context_lang">en_US</field>
<field name="name">user_analyst</field>
<field eval="[(6, 0, [ref('base.group_user')])]" name="groups_id"/>
<field name="company_id" ref="base.main_company"/>
<field eval="[(6, 0, [])]" name="roles_id"/>
<field eval="[(6, 0, [])]" name="rules_id"/>
<field eval="1" name="active"/>
<field model="ir.actions.actions" name="action_id" search="[('name', '=', u'Menu')]"/>
<field name="login">user_analyst</field>
<field name="password">user_analyst</field>
<field eval="[(6, 0, [])]" name="company_ids"/>
</record>
<!-- Resources -->
<record id="resource_resource_analyst0" model="resource.resource">
<field eval="1.0" name="time_efficiency"/>
<field name="user_id" ref="res_users_useranalyst0"/>
<!-- Human Resources -->
<record id="resource_analyst" model="resource.resource">
<field name="user_id" ref="res_users_analyst"/>
<field name="name">Analyst</field>
<field name="company_id" ref="base.main_company"/>
<field eval="1" name="active"/>
<field name="calendar_id" ref="resource.timesheet_group1"/>
<field name="resource_type">user</field>
</record>
<record id="resource_resource_programmer0" model="resource.resource">
<field eval="1.0" name="time_efficiency"/>
<field name="user_id" ref="res_users_userdeveloper0"/>
<field name="name">Programmer</field>
<field name="company_id" ref="base.main_company"/>
<field eval="1" name="active"/>
<record id="resource_project_manager" model="resource.resource">
<field name="user_id" ref="res_users_project_manager"/>
<field name="name">Project Manager</field>
<field name="calendar_id" ref="resource.timesheet_group1"/>
<field name="resource_type">user</field>
</record>
<record id="resource_resource_tester0" model="resource.resource">
<field eval="1.0" name="time_efficiency"/>
<field name="user_id" ref="res_users_usertester0"/>
<record id="resource_technical_leader" model="resource.resource">
<field name="user_id" ref="res_users_technical_leader"/>
<field name="name">Technical Leader</field>
<field name="calendar_id" ref="resource.timesheet_group1"/>
</record>
<record id="resource_developer" model="resource.resource">
<field name="user_id" ref="res_users_developer"/>
<field name="name">Developer</field>
<field name="calendar_id" ref="resource.timesheet_group1"/>
</record>
<record id="resource_designer" model="resource.resource">
<field name="user_id" ref="res_users_designer"/>
<field name="name">Designer</field>
<field name="calendar_id" ref="resource.timesheet_group1"/>
</record>
<record id="resource_tester" model="resource.resource">
<field name="user_id" ref="res_users_tester"/>
<field name="name">Tester</field>
<field name="company_id" ref="base.main_company"/>
<field eval="1" name="active"/>
<field name="calendar_id" ref="resource.timesheet_group1"/>
<field name="resource_type">user</field>
</record>
<record id="resource_resource_webdesigner0" model="resource.resource">
<field eval="1.0" name="time_efficiency"/>
<field name="user_id" ref="res_users_userdesign0"/>
<field name="name">Web Designer</field>
<field name="company_id" ref="base.main_company"/>
<field eval="1" name="active"/>
<record id="resource_finacial_manager" model="resource.resource">
<field name="user_id" ref="res_users_finacial_manager"/>
<field name="name">Project Finacial Manager</field>
<field name="calendar_id" ref="resource.timesheet_group1"/>
<field name="resource_type">user</field>
</record>
<!-- Projects -->
<record id="project_project_openerpwebsitedevelopment0" model="project.project">
<field eval="10" name="sequence"/>
<field name="company_currency_id" ref="base.EUR"/>
<field eval="1" name="active"/>
<field eval="1" name="warn_manager"/>
<field eval="0" name="warn_customer"/>
<field name="date_start" eval="(DateTime.now()-timedelta(70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field name="company_id" ref="base.main_company"/>
<field eval="1" name="priority"/>
<record id="project_integrate_openerp" model="project.project">
<field name="date_start" eval="time.strftime('%Y-%m-01 10:00:00')"/>
<field name="state">open</field>
<field name="type">normal</field>
<field name="description">Develop an OpenERP Website.</field>
<field eval="[(6, 0, [ref('res_users_manager0'), ref('res_users_user0'), ref('res_users_userfinance0'), ref('res_users_userdesign0'), ref('res_users_userdeveloper0'), ref('res_users_usertester0'), ref('res_users_useranalyst0')])]" name="members"/>
<field name="date" eval="(DateTime.now()+timedelta(60-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field name="user_id" ref="base.user_root"/>
<field name="currency_id" ref="base.EUR"/>
<field eval="[(6, 0, [])]" name="type_ids"/>
<field name="name">OpenERP Website Development</field>
<field name="description">Integrate an Sale and Warehouse Management.</field>
<field eval="[(6, 0, [
ref('res_users_analyst'),
ref('res_users_project_manager'),
ref('res_users_technical_leader'),
ref('res_users_developer'),
ref('res_users_designer'),
ref('res_users_tester'),
ref('res_users_finacial_manager')])]" name="members"/>
<field name="user_id" ref="res_users_project_manager"/>
<field name="name">Integrate an Sale and Warehouse Management.</field>
</record>
<!-- Project Phases -->
<record id="project_phase_informationgatheringandunderstanding0" model="project.phase">
<record id="project_phase_1" model="project.phase">
<field eval="[(6, 0, [])]" name="previous_phase_ids"/>
<field name="name">Information Gathering and Understanding</field>
<field name="name">Collect Requirement and Make SRS</field>
<field name="product_uom" ref="product.uom_day"/>
<field eval="10" name="sequence"/>
<field name="constraint_date_end" eval="(DateTime.now()+timedelta(18-70)).strftime('%Y-%m-%d')"/>
<field name="date_start" eval="(DateTime.now()-timedelta(70)).strftime('%Y-%m-%d')"/>
<field name="state">draft</field>
<field name="responsible_id" ref="res_users_demouser1"/>
<field eval="15.0" name="duration"/>
<field name="project_id" ref="project_project_openerpwebsitedevelopment0"/>
<field name="constraint_date_start" eval="(DateTime.now()+timedelta(2-70)).strftime('%Y-%m-%d')"/>
<field name="date_end" eval="(DateTime.now()+timedelta(15-70)).strftime('%Y-%m-%d')"/>
<field eval="1" name="sequence"/>
<field name="duration">30</field>
<field name="responsible_id" ref="res_users_analyst"/>
<field name="project_id" ref="project_integrate_openerp"/>
</record>
<record id="project_phase_planning0" model="project.phase">
<field eval="[(6, 0, [ref('project_phase_informationgatheringandunderstanding0')])]" name="previous_phase_ids"/>
<field name="name">Planning</field>
<record id="project_phase_2" model="project.phase">
<field eval="[(6, 0, [ref('project_phase_1')])]" name="previous_phase_ids"/>
<field name="name">Design Model</field>
<field name="product_uom" ref="product.uom_day"/>
<field eval="10" name="sequence"/>
<field name="constraint_date_end" eval="(DateTime.now()+timedelta(28-70)).strftime('%Y-%m-%d')"/>
<field name="date_start" eval="(DateTime.now()+timedelta(10-70)).strftime('%Y-%m-%d')"/>
<field name="state">draft</field>
<field name="responsible_id" ref="res_users_manager0"/>
<field eval="15.0" name="duration"/>
<field name="project_id" ref="project_project_openerpwebsitedevelopment0"/>
<field name="constraint_date_start" eval="(DateTime.now()+timedelta(13-70)).strftime('%Y-%m-%d')"/>
<field name="date_end" eval="(DateTime.now()+timedelta(25-70)).strftime('%Y-%m-%d')"/>
<field eval="2" name="sequence"/>
<field name="duration">20</field>
<field name="responsible_id" ref="res_users_project_manager"/>
<field name="project_id" ref="project_integrate_openerp"/>
</record>
<record id="project_phase_webdesign0" model="project.phase">
<field eval="[(6, 0, [ref('project_phase_planning0')])]" name="previous_phase_ids"/>
<field name="name">Web Design </field>
<record id="project_phase_3" model="project.phase">
<field eval="[(6, 0, [ref('project_phase_2')])]" name="previous_phase_ids"/>
<field name="name">Planning and compute Risk analysis, Time chart </field>
<field name="product_uom" ref="product.uom_day"/>
<field eval="10" name="sequence"/>
<field name="constraint_date_end" eval="(DateTime.now()+timedelta(45-70)).strftime('%Y-%m-%d')"/>
<field name="date_start" eval="(DateTime.now()+timedelta(20-70)).strftime('%Y-%m-%d')"/>
<field name="state">draft</field>
<field name="responsible_id" ref="res_users_userdesign0"/>
<field eval="20.0" name="duration"/>
<field name="project_id" ref="project_project_openerpwebsitedevelopment0"/>
<field name="constraint_date_start" eval="(DateTime.now()+timedelta(25-70)).strftime('%Y-%m-%d')"/>
<field name="date_end" eval="(DateTime.now()+timedelta(40-70)).strftime('%Y-%m-%d')"/>
<field eval="3" name="sequence"/>
<field name="duration">20</field>
<field name="responsible_id" ref="res_users_project_manager"/>
<field name="project_id" ref="project_integrate_openerp"/>
</record>
<record id="project_phase_developmentintegrationandtesting0" model="project.phase">
<field eval="[(6, 0, [ref('project_phase_webdesign0')])]" name="previous_phase_ids"/>
<field name="name">Development, Integration and Testing</field>
<record id="project_phase_4" model="project.phase">
<field eval="[(6, 0, [ref('project_phase_2')])]" name="previous_phase_ids"/>
<field name="name">Development and Integration</field>
<field name="product_uom" ref="product.uom_day"/>
<field eval="10" name="sequence"/>
<field name="constraint_date_end" eval="(DateTime.now()+timedelta(57-70)).strftime('%Y-%m-%d')"/>
<field name="date_start" eval="(DateTime.now()+timedelta(30-70)).strftime('%Y-%m-%d')"/>
<field name="state">draft</field>
<field name="responsible_id" ref="res_users_manager0"/>
<field eval="22.0" name="duration"/>
<field name="project_id" ref="project_project_openerpwebsitedevelopment0"/>
<field name="constraint_date_start" eval="(DateTime.now()+timedelta(35-70)).strftime('%Y-%m-%d')"/>
<field name="date_end" eval="(DateTime.now()+timedelta(52-70)).strftime('%Y-%m-%d')"/>
<field eval="4" name="sequence"/>
<field name="duration">90</field>
<field name="responsible_id" ref="res_users_technical_leader"/>
<field name="project_id" ref="project_integrate_openerp"/>
</record>
<record id="project_phase_websitedeployment0" model="project.phase">
<field eval="[(6, 0, [ref('project_phase_developmentintegrationandtesting0')])]" name="previous_phase_ids"/>
<field name="name">Website Deployment</field>
<record id="project_phase_5" model="project.phase">
<field eval="[(6, 0, [ref('project_phase_4')])]" name="previous_phase_ids"/>
<field name="name">Review and Testing</field>
<field name="product_uom" ref="product.uom_day"/>
<field eval="10" name="sequence"/>
<field name="constraint_date_end" eval="(DateTime.now()+timedelta(63-70)).strftime('%Y-%m-%d')"/>
<field name="date_start" eval="(DateTime.now()+timedelta(55-70)).strftime('%Y-%m-%d')"/>
<field name="state">draft</field>
<field name="responsible_id" ref="res_users_manager0"/>
<field eval="5.0" name="duration"/>
<field name="project_id" ref="project_project_openerpwebsitedevelopment0"/>
<field name="constraint_date_start" eval="(DateTime.now()+timedelta(58-70)).strftime('%Y-%m-%d')"/>
<field name="date_end" eval="(DateTime.now()+timedelta(60-70)).strftime('%Y-%m-%d')"/>
<field eval="5" name="sequence"/>
<field name="duration">30</field>
<field name="responsible_id" ref="res_users_project_manager"/>
<field name="project_id" ref="project_integrate_openerp"/>
</record>
<record id="project_phase_6" model="project.phase">
<field eval="[(6, 0, [ref('project_phase_5')])]" name="previous_phase_ids"/>
<field name="name">Deployement and Training</field>
<field name="product_uom" ref="product.uom_day"/>
<field eval="5" name="sequence"/>
<field name="duration">10</field>
<field name="responsible_id" ref="res_users_analyst"/>
<field name="project_id" ref="project_integrate_openerp"/>
</record>
<!-- Project Resource Allocation -->
<record id="project_resource_allocation_0" model="project.resource.allocation">
<field name="resource_id" ref="resource_resource_analyst0"/>
<field name="phase_id" ref="project_phase_informationgatheringandunderstanding0"/>
<field eval="40.0" name="useability"/>
<record id="resource_allocation_1" model="project.resource.allocation">
<field name="resource_id" ref="resource_analyst"/>
<field name="phase_id" ref="project_phase_1"/>
</record>
<record id="project_resource_allocation_1" model="project.resource.allocation">
<field name="resource_id" ref="resource_resource_programmer0"/>
<field name="phase_id" ref="project_phase_informationgatheringandunderstanding0"/>
<field eval="60.0" name="useability"/>
<record id="resource_allocation_2" model="project.resource.allocation">
<field name="resource_id" ref="resource_project_manager"/>
<field name="phase_id" ref="project_phase_2"/>
</record>
<record id="project_resource_allocation_2" model="project.resource.allocation">
<field name="resource_id" ref="resource_resource_tester0"/>
<field name="phase_id" ref="project_phase_informationgatheringandunderstanding0"/>
<field eval="40.0" name="useability"/>
<record id="resource_allocation_3" model="project.resource.allocation">
<field name="resource_id" ref="resource_project_manager"/>
<field name="phase_id" ref="project_phase_3"/>
</record>
<record id="project_resource_allocation_3" model="project.resource.allocation">
<field name="resource_id" ref="resource_resource_analyst0"/>
<field name="phase_id" ref="project_phase_planning0"/>
<field eval="70.0" name="useability"/>
<record id="resource_allocation_4" model="project.resource.allocation">
<field name="resource_id" ref="resource_technical_leader"/>
<field name="phase_id" ref="project_phase_4"/>
</record>
<record id="project_resource_allocation_4" model="project.resource.allocation">
<field name="resource_id" ref="resource_resource_programmer0"/>
<field name="phase_id" ref="project_phase_planning0"/>
<field eval="70.0" name="useability"/>
<record id="resource_allocation_5" model="project.resource.allocation">
<field name="resource_id" ref="resource_developer"/>
<field name="phase_id" ref="project_phase_4"/>
</record>
<record id="project_resource_allocation_5" model="project.resource.allocation">
<field name="resource_id" ref="resource_resource_webdesigner0"/>
<field name="phase_id" ref="project_phase_webdesign0"/>
<field eval="80.0" name="useability"/>
<record id="resource_allocation_6" model="project.resource.allocation">
<field name="resource_id" ref="resource_designer"/>
<field name="phase_id" ref="project_phase_4"/>
</record>
<record id="project_resource_allocation_6" model="project.resource.allocation">
<field name="resource_id" ref="resource_resource_programmer0"/>
<field name="phase_id" ref="project_phase_webdesign0"/>
<field eval="30.0" name="useability"/>
<record id="resource_allocation_7" model="project.resource.allocation">
<field name="resource_id" ref="resource_tester"/>
<field name="phase_id" ref="project_phase_4"/>
</record>
<record id="project_resource_allocation_7" model="project.resource.allocation">
<field name="resource_id" ref="resource_resource_programmer0"/>
<field name="phase_id" ref="project_phase_developmentintegrationandtesting0"/>
<field eval="100.0" name="useability"/>
<record id="resource_allocation_8" model="project.resource.allocation">
<field name="resource_id" ref="resource_project_manager"/>
<field name="phase_id" ref="project_phase_5"/>
</record>
<record id="project_resource_allocation_8" model="project.resource.allocation">
<field name="resource_id" ref="resource_resource_tester0"/>
<field name="phase_id" ref="project_phase_developmentintegrationandtesting0"/>
<field eval="50.0" name="useability"/>
<record id="resource_allocation_9" model="project.resource.allocation">
<field name="resource_id" ref="resource_analyst"/>
<field name="phase_id" ref="project_phase_6"/>
</record>
<!-- Tasks -->
<record id="project_task_preparerequirementsdocument0" model="project.task">
<field eval="15" name="sequence"/>
<record id="project_task_1" model="project.task">
<field eval="100.0" name="planned_hours"/>
<field name="user_id" ref="res_users_user0"/>
<field name="state">open</field>
<field name="date_start" eval="(DateTime.now()-timedelta(70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field name="company_id" ref="base.main_company"/>
<field name="user_id" ref="res_users_analyst"/>
<field name="priority">2</field>
<field name="project_id" ref="project_project_openerpwebsitedevelopment0"/>
<field eval="[(6, 0, [])]" name="child_ids"/>
<field eval="[(6, 0, [])]" name="parent_ids"/>
<field eval="1" name="active"/>
<field name="project_id" ref="project_integrate_openerp"/>
<field name="name">Prepare Requirements Document</field>
<field name="date_deadline" eval="(DateTime.now()+timedelta(55-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field eval="100.0" name="total_hours"/>
<field eval="100.0" name="remaining_hours"/>
<field name="phase_id" ref="project_phase_informationgatheringandunderstanding0"/>
<field name="phase_id" ref="project_phase_1"/>
</record>
<record id="project_task_definewebsitegoalspurposesandtargetaudience0" model="project.task">
<field eval="10" name="sequence"/>
<record id="project_task_2" model="project.task">
<field eval="80.0" name="planned_hours"/>
<field name="user_id" ref="res_users_useranalyst0"/>
<field name="state">open</field>
<field name="date_start" eval="(DateTime.now()-timedelta(70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field name="company_id" ref="base.main_company"/>
<field name="user_id" ref="res_users_analyst"/>
<field name="priority">2</field>
<field name="project_id" ref="project_project_openerpwebsitedevelopment0"/>
<field eval="[(6, 0, [])]" name="child_ids"/>
<field eval="[(6, 0, [])]" name="parent_ids"/>
<field eval="1" name="active"/>
<field name="name">Define Website Goals, Purposes and Target Audience</field>
<field name="date_deadline" eval="(DateTime.now()+timedelta(10-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field eval="80.0" name="total_hours"/>
<field eval="80.0" name="remaining_hours"/>
<field name="phase_id" ref="project_phase_informationgatheringandunderstanding0"/>
<field name="project_id" ref="project_integrate_openerp"/>
<field name="name">Make SRS</field>
<field name="phase_id" ref="project_phase_1"/>
</record>
<record id="project_task_usecases0" model="project.task">
<field eval="17" name="sequence"/>
<record id="project_task_3" model="project.task">
<field eval="40.0" name="planned_hours"/>
<field name="user_id" ref="res_users_userdesign0"/>
<field name="state">open</field>
<field name="date_start" eval="(DateTime.now()+timedelta(48-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field name="company_id" ref="base.main_company"/>
<field name="user_id" ref="res_users_project_manager"/>
<field name="priority">2</field>
<field name="project_id" ref="project_project_openerpwebsitedevelopment0"/>
<field eval="[(6, 0, [])]" name="child_ids"/>
<field eval="[(6, 0, [])]" name="parent_ids"/>
<field eval="1" name="active"/>
<field name="name">Use Cases</field>
<field name="date_deadline" eval="(DateTime.now()+timedelta(55-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field eval="40.0" name="total_hours"/>
<field eval="40.0" name="remaining_hours"/>
<field name="phase_id" ref="project_phase_informationgatheringandunderstanding0"/>
<field name="project_id" ref="project_integrate_openerp"/>
<field name="name">Design Use Cases</field>
<field name="phase_id" ref="project_phase_2"/>
</record>
<record id="project_task_budgetplanning0" model="project.task">
<field eval="10" name="sequence"/>
<record id="project_task_4" model="project.task">
<field eval="25.0" name="planned_hours"/>
<field name="user_id" ref="res_users_userfinance0"/>
<field name="state">open</field>
<field name="date_start" eval="(DateTime.now()+timedelta(10-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field name="company_id" ref="base.main_company"/>
<field name="user_id" ref="res_users_project_manager"/>
<field name="priority">2</field>
<field name="project_id" ref="project_project_openerpwebsitedevelopment0"/>
<field eval="[(6, 0, [])]" name="child_ids"/>
<field eval="[(6, 0, [])]" name="parent_ids"/>
<field eval="1" name="active"/>
<field name="project_id" ref="project_integrate_openerp"/>
<field name="name">Budget Planning</field>
<field name="date_deadline" eval="(DateTime.now()+timedelta(18-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field eval="25.0" name="total_hours"/>
<field eval="25.0" name="remaining_hours"/>
<field name="phase_id" ref="project_phase_planning0"/>
<field name="phase_id" ref="project_phase_3"/>
</record>
<record id="project_task_qualityplanning0" model="project.task">
<field eval="10" name="sequence"/>
<record id="project_task_5" model="project.task">
<field eval="25.0" name="planned_hours"/>
<field name="user_id" ref="res_users_user0"/>
<field name="state">open</field>
<field name="date_start" eval="(DateTime.now()+timedelta(10-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field name="company_id" ref="base.main_company"/>
<field name="user_id" ref="res_users_project_manager"/>
<field name="priority">2</field>
<field name="project_id" ref="project_project_openerpwebsitedevelopment0"/>
<field eval="[(6, 0, [])]" name="child_ids"/>
<field eval="[(6, 0, [])]" name="parent_ids"/>
<field eval="1" name="active"/>
<field name="project_id" ref="project_integrate_openerp"/>
<field name="name">Quality Planning</field>
<field name="date_deadline" eval="(DateTime.now()+timedelta(18-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field eval="25.0" name="total_hours"/>
<field eval="25.0" name="remaining_hours"/>
<field name="phase_id" ref="project_phase_planning0"/>
<field name="phase_id" ref="project_phase_3"/>
</record>
<record id="project_task_riskmanagementplanning0" model="project.task">
<field eval="10" name="sequence"/>
<record id="project_task_6" model="project.task">
<field eval="20.0" name="planned_hours"/>
<field name="user_id" ref="res_users_user1"/>
<field name="state">open</field>
<field name="date_start" eval="(DateTime.now()+timedelta(13-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field name="company_id" ref="base.main_company"/>
<field name="user_id" ref="res_users_project_manager"/>
<field name="priority">2</field>
<field name="project_id" ref="project_project_openerpwebsitedevelopment0"/>
<field eval="[(6, 0, [])]" name="child_ids"/>
<field eval="[(6, 0, [])]" name="parent_ids"/>
<field eval="1" name="active"/>
<field name="project_id" ref="project_integrate_openerp"/>
<field name="name">Risk Management Planning</field>
<field name="date_deadline" eval="(DateTime.now()+timedelta(20-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field eval="20.0" name="total_hours"/>
<field eval="20.0" name="remaining_hours"/>
<field name="phase_id" ref="project_phase_planning0"/>
<field name="phase_id" ref="project_phase_3"/>
</record>
<record id="project_task_createprojectschedules0" model="project.task">
<field eval="10" name="sequence"/>
<record id="project_task_7" model="project.task">
<field eval="30.0" name="planned_hours"/>
<field name="user_id" ref="res_users_manager0"/>
<field name="state">open</field>
<field name="date_start" eval="(DateTime.now()+timedelta(20-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field name="company_id" ref="base.main_company"/>
<field name="user_id" ref="res_users_project_manager"/>
<field name="priority">2</field>
<field name="project_id" ref="project_project_openerpwebsitedevelopment0"/>
<field eval="[(6, 0, [])]" name="child_ids"/>
<field eval="[(6, 0, [])]" name="parent_ids"/>
<field eval="1" name="active"/>
<field name="project_id" ref="project_integrate_openerp"/>
<field name="name">Create Project Schedules</field>
<field name="date_deadline" eval="(DateTime.now()+timedelta(25-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field eval="30.0" name="total_hours"/>
<field eval="30.0" name="remaining_hours"/>
<field name="phase_id" ref="project_phase_planning0"/>
<field name="phase_id" ref="project_phase_3"/>
</record>
<record id="project_task_dataflowdesign0" model="project.task">
<field eval="10" name="sequence"/>
<record id="project_task_8" model="project.task">
<field eval="10.0" name="planned_hours"/>
<field name="user_id" ref="res_users_manager0"/>
<field name="state">open</field>
<field name="date_start" eval="(DateTime.now()+timedelta(20-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field name="company_id" ref="base.main_company"/>
<field name="user_id" ref="res_users_project_manager"/>
<field name="priority">2</field>
<field name="project_id" ref="project_project_openerpwebsitedevelopment0"/>
<field eval="[(6, 0, [])]" name="child_ids"/>
<field eval="[(6, 0, [])]" name="parent_ids"/>
<field eval="1" name="active"/>
<field name="project_id" ref="project_integrate_openerp"/>
<field name="name">Dataflow Design</field>
<field name="date_deadline" eval="(DateTime.now()+timedelta(23-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field eval="10.0" name="total_hours"/>
<field eval="10.0" name="remaining_hours"/>
<field name="phase_id" ref="project_phase_webdesign0"/>
<field name="phase_id" ref="project_phase_3"/>
</record>
<record id="project_task_userinterfacedesign0" model="project.task">
<field eval="10" name="sequence"/>
<record id="project_task_9" model="project.task">
<field eval="50.0" name="planned_hours"/>
<field name="user_id" ref="res_users_userdesign0"/>
<field name="state">open</field>
<field name="date_start" eval="(DateTime.now()+timedelta(22-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field name="company_id" ref="base.main_company"/>
<field name="user_id" ref="res_users_project_manager"/>
<field name="priority">2</field>
<field name="project_id" ref="project_project_openerpwebsitedevelopment0"/>
<field eval="[(6, 0, [])]" name="child_ids"/>
<field eval="[(6, 0, [])]" name="parent_ids"/>
<field eval="1" name="active"/>
<field name="project_id" ref="project_integrate_openerp"/>
<field name="name">User Interface Design</field>
<field name="date_deadline" eval="(DateTime.now()+timedelta(40-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field eval="150.0" name="total_hours"/>
<field eval="150.0" name="remaining_hours"/>
<field name="phase_id" ref="project_phase_webdesign0"/>
<field name="phase_id" ref="project_phase_3"/>
</record>
<record id="project_task_tasklevelwbs0" model="project.task">
<field eval="10" name="sequence"/>
<record id="project_task_10" model="project.task">
<field eval="40.0" name="planned_hours"/>
<field name="user_id" ref="res_users_userdesign0"/>
<field name="state">open</field>
<field name="date_start" eval="(DateTime.now()+timedelta(30-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field name="company_id" ref="base.main_company"/>
<field name="user_id" ref="res_users_developer"/>
<field name="priority">2</field>
<field name="project_id" ref="project_project_openerpwebsitedevelopment0"/>
<field eval="[(6, 0, [])]" name="child_ids"/>
<field eval="[(6, 0, [])]" name="parent_ids"/>
<field eval="1" name="active"/>
<field name="name">Task Level WBS</field>
<field name="date_deadline" eval="(DateTime.now()+timedelta(40-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field eval="40.0" name="total_hours"/>
<field eval="40.0" name="remaining_hours"/>
<field name="phase_id" ref="project_phase_webdesign0"/>
<field name="project_id" ref="project_integrate_openerp"/>
<field name="name">Develop Module in Sale Management</field>
<field name="phase_id" ref="project_phase_4"/>
</record>
<record id="project_task_modularprogramming0" model="project.task">
<field eval="10" name="sequence"/>
<record id="project_task_11" model="project.task">
<field eval="90.0" name="planned_hours"/>
<field name="user_id" ref="res_users_userdeveloper0"/>
<field name="state">open</field>
<field name="date_start" eval="(DateTime.now()+timedelta(30-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field name="company_id" ref="base.main_company"/>
<field name="user_id" ref="res_users_developer"/>
<field name="priority">2</field>
<field name="project_id" ref="project_project_openerpwebsitedevelopment0"/>
<field eval="[(6, 0, [])]" name="child_ids"/>
<field eval="[(6, 0, [])]" name="parent_ids"/>
<field eval="1" name="active"/>
<field name="name">Modular Programming</field>
<field name="date_deadline" eval="(DateTime.now()+timedelta(50-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field eval="90.0" name="total_hours"/>
<field eval="90.0" name="remaining_hours"/>
<field name="phase_id" ref="project_phase_developmentintegrationandtesting0"/>
<field name="project_id" ref="project_integrate_openerp"/>
<field name="name">Develop module in Warehouse</field>
<field name="phase_id" ref="project_phase_4"/>
</record>
<record id="project_task_integratemodules0" model="project.task">
<field eval="10" name="sequence"/>
<record id="project_task_12" model="project.task">
<field eval="20.0" name="planned_hours"/>
<field name="user_id" ref="res_users_userdeveloper1"/>
<field name="state">open</field>
<field name="date_start" eval="(DateTime.now()+timedelta(45-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field name="company_id" ref="base.main_company"/>
<field name="user_id" ref="res_users_developer"/>
<field name="priority">2</field>
<field name="project_id" ref="project_project_openerpwebsitedevelopment0"/>
<field eval="[(6, 0, [])]" name="child_ids"/>
<field eval="[(6, 0, [])]" name="parent_ids"/>
<field eval="1" name="active"/>
<field name="project_id" ref="project_integrate_openerp"/>
<field name="name">Integrate Modules</field>
<field name="date_deadline" eval="(DateTime.now()+timedelta(53-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field eval="20.0" name="total_hours"/>
<field eval="20.0" name="remaining_hours"/>
<field name="phase_id" ref="project_phase_developmentintegrationandtesting0"/>
<field name="phase_id" ref="project_phase_4"/>
</record>
<record id="project_task_unittesting0" model="project.task">
<field eval="10" name="sequence"/>
<record id="project_task_13" model="project.task">
<field eval="50.0" name="planned_hours"/>
<field name="user_id" ref="res_users_usertester0"/>
<field name="state">open</field>
<field name="date_start" eval="(DateTime.now()+timedelta(40-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field name="company_id" ref="base.main_company"/>
<field name="user_id" ref="res_users_tester"/>
<field name="priority">2</field>
<field name="project_id" ref="project_project_openerpwebsitedevelopment0"/>
<field eval="[(6, 0, [])]" name="child_ids"/>
<field eval="[(6, 0, [])]" name="parent_ids"/>
<field eval="1" name="active"/>
<field name="project_id" ref="project_integrate_openerp"/>
<field name="name">Unit Testing</field>
<field name="date_deadline" eval="(DateTime.now()+timedelta(55-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field eval="50.0" name="total_hours"/>
<field eval="50.0" name="remaining_hours"/>
<field name="phase_id" ref="project_phase_developmentintegrationandtesting0"/>
<field name="phase_id" ref="project_phase_4"/>
</record>
<record id="project_task_regressiontest0" model="project.task">
<field eval="10" name="sequence"/>
<record id="project_task_14" model="project.task">
<field eval="30.0" name="planned_hours"/>
<field name="user_id" ref="res_users_usertester0"/>
<field name="state">open</field>
<field name="date_start" eval="(DateTime.now()+timedelta(40-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field name="company_id" ref="base.main_company"/>
<field name="user_id" ref="res_users_tester"/>
<field name="priority">2</field>
<field name="project_id" ref="project_project_openerpwebsitedevelopment0"/>
<field eval="[(6, 0, [])]" name="child_ids"/>
<field eval="[(6, 0, [])]" name="parent_ids"/>
<field eval="1" name="active"/>
<field name="project_id" ref="project_integrate_openerp"/>
<field name="name">Regression Test</field>
<field name="date_deadline" eval="(DateTime.now()+timedelta(55-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field eval="30.0" name="total_hours"/>
<field eval="30.0" name="remaining_hours"/>
<field name="phase_id" ref="project_phase_developmentintegrationandtesting0"/>
<field name="phase_id" ref="project_phase_4"/>
</record>
<record id="project_task_documentation0" model="project.task">
<field eval="10" name="sequence"/>
<record id="project_task_15" model="project.task">
<field eval="15.0" name="planned_hours"/>
<field name="user_id" ref="res_users_demouser1"/>
<field name="state">open</field>
<field name="date_start" eval="(DateTime.now()+timedelta(40-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field name="company_id" ref="base.main_company"/>
<field name="user_id" ref="res_users_developer"/>
<field name="priority">2</field>
<field name="project_id" ref="project_project_openerpwebsitedevelopment0"/>
<field eval="[(6, 0, [])]" name="child_ids"/>
<field eval="[(6, 0, [])]" name="parent_ids"/>
<field eval="1" name="active"/>
<field name="project_id" ref="project_integrate_openerp"/>
<field name="name">Documentation</field>
<field name="date_deadline" eval="(DateTime.now()+timedelta(55-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field eval="15.0" name="total_hours"/>
<field eval="15.0" name="remaining_hours"/>
<field name="phase_id" ref="project_phase_websitedeployment0"/>
<field name="phase_id" ref="project_phase_4"/>
</record>
<record id="project_task_performancetuning0" model="project.task">
<record id="project_task_16" model="project.task">
<field eval="10" name="sequence"/>
<field eval="40.0" name="planned_hours"/>
<field name="user_id" ref="res_users_usertester1"/>
<field name="state">open</field>
<field name="date_start" eval="(DateTime.now()+timedelta(45-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field name="company_id" ref="base.main_company"/>
<field name="user_id" ref="res_users_tester"/>
<field name="priority">2</field>
<field name="project_id" ref="project_project_openerpwebsitedevelopment0"/>
<field eval="[(6, 0, [])]" name="child_ids"/>
<field eval="[(6, 0, [])]" name="parent_ids"/>
<field eval="1" name="active"/>
<field name="project_id" ref="project_integrate_openerp"/>
<field name="name">Performance Tuning</field>
<field name="date_deadline" eval="(DateTime.now()+timedelta(55-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field eval="40.0" name="total_hours"/>
<field eval="40.0" name="remaining_hours"/>
<field name="phase_id" ref="project_phase_developmentintegrationandtesting0"/>
<field name="phase_id" ref="project_phase_4"/>
</record>
<record id="project_task_deploywebsite0" model="project.task">
<field eval="10" name="sequence"/>
<record id="project_task_17" model="project.task">
<field eval="5.0" name="planned_hours"/>
<field name="user_id" ref="res_users_userdeveloper0"/>
<field name="state">open</field>
<field name="date_start" eval="(DateTime.now()+timedelta(55-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field name="company_id" ref="base.main_company"/>
<field name="user_id" ref="res_users_analyst"/>
<field name="priority">2</field>
<field name="project_id" ref="project_project_openerpwebsitedevelopment0"/>
<field eval="[(6, 0, [])]" name="child_ids"/>
<field eval="[(6, 0, [])]" name="parent_ids"/>
<field eval="1" name="active"/>
<field name="name">Deploy Website</field>
<field name="date_deadline" eval="(DateTime.now()+timedelta(60-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field eval="5.0" name="total_hours"/>
<field eval="5.0" name="remaining_hours"/>
<field name="phase_id" ref="project_phase_websitedeployment0"/>
<field name="project_id" ref="project_integrate_openerp"/>
<field name="name">Deploy and Review on Customer System</field>
<field name="phase_id" ref="project_phase_6"/>
</record>
<record id="project_task_presentation0" model="project.task">
<field eval="10" name="sequence"/>
<record id="project_task_18" model="project.task">
<field eval="10.0" name="planned_hours"/>
<field name="user_id" ref="res_users_demouser1"/>
<field name="state">open</field>
<field name="date_start" eval="(DateTime.now()+timedelta(58-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field name="company_id" ref="base.main_company"/>
<field name="user_id" ref="res_users_analyst"/>
<field name="priority">2</field>
<field name="project_id" ref="project_project_openerpwebsitedevelopment0"/>
<field eval="[(6, 0, [])]" name="child_ids"/>
<field eval="[(6, 0, [])]" name="parent_ids"/>
<field eval="1" name="active"/>
<field name="name">Presentation</field>
<field name="date_deadline" eval="(DateTime.now()+timedelta(65-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field eval="10.0" name="total_hours"/>
<field eval="10.0" name="remaining_hours"/>
<field name="phase_id" ref="project_phase_websitedeployment0"/>
<field name="project_id" ref="project_integrate_openerp"/>
<field name="name">Training and Presentation</field>
<field name="phase_id" ref="project_phase_6"/>
</record>
<!-- run scheduling of phase -->
<function model="project.project" name="schedule_phases" eval="(ref('project_integrate_openerp'),)"/>
<!-- run scheduling of tasks -->
<function model="project.project" name="schedule_tasks" eval="(ref('project_integrate_openerp'),)"/>
</data>
</openerp>
@@ -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))
(task.id, task.user_id, task.date_start, task.date_end))
@@ -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")
@@ -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")
@@ -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:
@@ -18,18 +18,11 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
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()
@@ -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()
@@ -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:
@@ -1,124 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
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:
+1 -1
View File
@@ -320,7 +320,7 @@ class project_scrum_meeting(osv.osv):
'question_blocks': fields.text('Blocks encountered'),
'question_backlog': fields.text('Backlog Accurate'),
'task_ids': fields.many2many('project.task', 'meeting_task_rel', 'metting_id', 'task_id', 'Tasks'),
'responsible_id': fields.related('sprint_id', 'scrum_master_id', type='many2one', relation='res.users', string='Responsible'),
'user_id': fields.related('sprint_id', 'scrum_master_id', type='many2one', relation='res.users', string='Responsible', readonly=True),
}
#
# TODO: Find the right sprint thanks to users and date
+37 -4
View File
@@ -245,7 +245,39 @@
</group>
</page>
<page string="Daily Meetings">
<field colspan="4" name="meeting_ids" nolabel="1" widget="one2many_list"/>
<field colspan="4" name="meeting_ids" nolabel="1" widget="one2many_list">
<form string="Scrum Sprint">
<group colspan="4" col="6">
<field name="date"/>
<field name="user_id"/>
</group>
<notebook colspan="4">
<page string="Scrum Meeting">
<separator colspan="4" string="What did you do since the last meeting?"/>
<field colspan="4" name="question_yesterday" nolabel="1"/>
<separator colspan="4" string="What do you plan to do till the next meeting?"/>
<field colspan="4" name="question_today" nolabel="1"/>
<separator colspan="4" string="Are there anything blocking you?"/>
<field colspan="4" name="question_blocks" nolabel="1"/>
<separator colspan="4" string=""/>
<button name="button_send_to_master" type="object" string="Send to Scrum Master" icon="gtk-ok"/>
<button name="button_send_product_owner" type="object" string="Send to Product Owner" icon="gtk-ok"/>
</page>
<page string="Optional Info">
<separator colspan="4" string="Are your Sprint Backlog estimate accurate ?"/>
<field colspan="4" name="question_backlog" nolabel="1"/>
</page>
<page string="Links">
<separator colspan="4" string="Tasks"/>
<field colspan="4" name="task_ids" nolabel="1" domain="[('sprint_id','=',sprint_id)]"/>
</page>
</notebook>
</form>
<tree string="Scrum Meeting">
<field name="date"/>
<field name="user_id"/>
</tree>
</field>
</page>
<page string="Review">
<field colspan="4" name="review" nolabel="1"/>
@@ -319,10 +351,11 @@
<field name="model">project.scrum.meeting</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Scrum Sprint">
<tree string="Scrum Meeting">
<field name="date"/>
<field name="sprint_id"/>
<field name="project_id"/>
<field name="user_id"/>
</tree>
</field>
</record>
@@ -331,11 +364,11 @@
<field name="model">project.scrum.meeting</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Scrum Sprint">
<form string="Scrum Meeting">
<group colspan="4" col="6">
<field name="date"/>
<field name="sprint_id" domain="[('state', '=', 'open')]"/>
<field name="responsible_id"/>
<field name="user_id"/>
</group>
<notebook colspan="4">
<page string="Scrum Meeting">
-4
View File
@@ -41,9 +41,6 @@
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">450</field>
<field name="product_qty">2</field>
<field name="product_uom_qty">3</field>
<field name="product_uos_qty">3</field>
<field name="type">make_to_stock</field>
</record>
<record id="line3_purchase" model="purchase.order.line">
@@ -54,7 +51,6 @@
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">900</field>
<field name="product_qty">1</field>
<field name="type">make_to_stock</field>
</record>
<workflow action="purchase_confirm" model="purchase.order" ref="order_purchase2"/>
+117 -15
View File
@@ -22,10 +22,11 @@
from datetime import datetime, timedelta
import time
import math
from faces import *
from new import classobj
from osv import fields, osv
from tools.translate import _
import tools
class resource_calendar(osv.osv):
_name = "resource.calendar"
_description = "Resource Calendar"
@@ -187,6 +188,14 @@ class resource_calendar_attendance(osv.osv):
_order = 'dayofweek, hour_from'
resource_calendar_attendance()
def convert_timeformat(time_string):
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
class resource_resource(osv.osv):
_name = "resource.resource"
_description = "Resource Detail"
@@ -207,18 +216,7 @@ class resource_resource(osv.osv):
'company_id': lambda self, cr, uid, context: self.pool.get('res.company')._company_default_get(cr, uid, 'resource.resource', context=context)
}
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)
def copy(self, cr, uid, id, default=None, context=None):
if default is None:
default = {}
@@ -226,6 +224,110 @@ class resource_resource(osv.osv):
default['name'] = self.browse(cr, uid, id, context=context).name + _(' (copy)')
return super(resource_resource, self).copy(cr, uid, id, default, context)
def generate_resources(self, cr, uid, user_ids, calendar_id, context=None):
"""
Return a list of Resource Class objects for the resources allocated to the phase.
"""
if context is None:
context = {}
resource_objs = []
user_pool = self.pool.get('res.users')
for user in user_pool.browse(cr, uid, user_ids, context=context):
resource_ids = self.search(cr, uid, [('user_id', '=', user.id)], context=context)
#assert len(resource_ids) < 1, "User should not has more than one resources"
leaves = []
resource_eff = 1.0
if resource_ids:
resource_id = resource_ids[0]
resource = self.browse(cr, uid, resource_id, context=context)
resource_eff = resource.time_efficiency
resource_cal = resource.calendar_id.id
if resource_cal:
leaves = self.compute_vacation(cr, uid, calendar_id, resource.id, resource_cal, context=context)
resource_objs.append(classobj(str(user.name), (Resource,),{
'__doc__': user.name,
'__name__': user.name,
'vacation': tuple(leaves),
'efficiency': resource_eff,
}))
return resource_objs
def compute_vacation(self, cr, uid, calendar_id, resource_id=False, resource_calendar=False, context=None):
"""
Compute the vacation from the working calendar of the resource.
@param calendar_id : working calendar of the project
@param resource_id : resource working on phase/task
@param resource_calendar : working calendar of the resource
"""
if context is None:
context = {}
resource_calendar_leaves_pool = self.pool.get('resource.calendar.leaves')
leave_list = []
if resource_id:
leave_ids = resource_calendar_leaves_pool.search(cr, uid, ['|', ('calendar_id', '=', calendar_id),
('calendar_id', '=', resource_calendar),
('resource_id', '=', resource_id)
], context=context)
else:
leave_ids = resource_calendar_leaves_pool.search(cr, uid, [('calendar_id', '=', calendar_id),
('resource_id', '=', False)
], context=context)
leaves = resource_calendar_leaves_pool.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):
"""
Change the format of working calendar from 'Openerp' format to bring it into 'Faces' format.
@param calendar_id : working calendar of the project
"""
if context is None:
context = {}
resource_attendance_pool = self.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_pool.search(cr, uid, [('calendar_id', '=', calendar_id)], context=context)
weeks = resource_attendance_pool.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
resource_resource()
class resource_calendar_leaves(osv.osv):
@@ -261,4 +363,4 @@ class resource_calendar_leaves(osv.osv):
resource_calendar_leaves()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
-1
View File
@@ -217,7 +217,6 @@
<field name="currency_id" ref="base.EUR"/>
<field eval="1.0" name="po_lead"/>
<field name="partner_id" ref="res_partner_tinyshop1"/>
<field eval="1.0" name="manufacturing_lead"/>
<field name="parent_id" ref="base.main_company"/>
<field eval="80.0" name="schedule_range"/>
<field eval="&quot;&quot;&quot;Shop 2&quot;&quot;&quot;" name="name"/>