##############################################################################
#
# Copyright (c) 2005-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
#
# $Id: project.py 1011 2005-07-26 08:11:45Z nicoe $
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
##############################################################################

from mx import DateTime
from mx.DateTime import now
import time

import netsvc
from osv import fields, osv
import ir

class project(osv.osv):
	_name = "project.project"
	_description = "Project"

	def _calc_effective(self, cr, uid, ids, name, args, context):
		res = {}
		projs = self.browse(cr, uid, ids)
		for proj in projs:
			if proj.id not in res:
				res[proj.id] = 0
				for child in proj.child_id:
					res[proj.id] += child.effective_hours
				for task in proj.tasks:
					res[proj.id] += task.effective_hours
		return res	

	def _calc_planned(self, cr, uid, ids, name, args, context):
		res = {}
		projs = self.browse(cr, uid, ids)
		for proj in projs:
			if proj.id not in res:
				res[proj.id] = 0
				for child in proj.child_id:
					res[proj.id] += child.planned_hours
				for task in proj.tasks:
					res[proj.id] += task.planned_hours
		return res

	def onchange_partner_id(self, cr, uid, ids, part):
		if not part:
			return {'value':{'contact_id': False, 'pricelist_id': False}}
		addr = self.pool.get('res.partner').address_get(cr, uid, [part], ['contact'])
		print part, self.pool.get('res.partner').browse(cr, uid, part).property_product_pricelist

		pricelist = self.pool.get('res.partner').browse(cr, uid, part).property_product_pricelist[0]
		return {'value':{'contact_id': addr['contact'], 'pricelist_id': pricelist}}

	_columns = {
		 'name': fields.char("Project name", size=128, required=True),
		 'active': fields.boolean('Active'),
		 'category_id': fields.many2one('account.analytic.account','Analytic Account'),
		 'priority': fields.integer('Priority'),
		 'manager': fields.many2one('res.users', 'Project manager', relate=True),
		 'warn_manager': fields.boolean('Warn manager'),
		 'members': fields.many2many('res.users', 'project_user_rel', 'project_id', 'uid', 'Project members'),
		 'tasks': fields.one2many('project.task', 'project_id', "Project tasks"),
		 'parent_id': fields.many2one('project.project', 'Parent project'),
		 'child_id': fields.one2many('project.project', 'parent_id', 'Subproject'),
		 'planned_hours': fields.function(_calc_planned, method=True, string='Hours planned'),
		 'effective_hours': fields.function(_calc_effective, method=True, string='Hours spent'),
		 'date_start': fields.date('Project started on'),
		 'date_end': fields.date('Project should end on'),
		 'tariff': fields.float('Sales price'),
		 'mode': fields.selection([('project', 'By project'), ('hour', 'By hour'), ('effective', 'By effective hour')], 'Price setting mode'),
		 'partner_id': fields.many2one('res.partner', 'Customer'),
		 'contact_id': fields.many2one('res.partner.address', 'Contact'),
		 'pricelist_id': fields.many2one('product.pricelist', 'Pricelist'),
		 'tax_ids': fields.many2many('account.tax', 'project_account_tax_rel', 'project_id','tax_id', 'Applicable taxes'),
		 'warn_customer': fields.boolean('Warn customer'),
		 'warn_header': fields.text('Mail header'),
		 'warn_footer': fields.text('Mail footer'),
		 'notes': fields.text('Notes'),
		 'timesheet_id': fields.many2one('hr.timesheet.group', 'Timesheet'),
 		 'state': fields.selection([('draft', 'Draft'), ('finished', 'Finished'), ('open', 'Opened')]),
	 }
	
	_defaults = {
		'active': lambda *a: True,
		'manager': lambda object,cr,uid,context: uid,
		'priority': lambda *a: 1,
		'date_start': lambda *a: time.strftime('%Y-%m-%d'),
	}
	
	_order = "priority"

	# toggle activity of projects, their sub projects and their tasks
#CHECKME: it might be better to simply override the write method
	def toggleActive(self, cr, uid, ids, context={}):
		for proj in self.browse(cr, uid, ids, context):
			self.setActive(cr, uid, proj.id, not proj.active, context)
 		return True

	# set active value for a project, its sub projects and its tasks
	def setActive(self, cr, uid, id, value, context={}):
		proj = self.browse(cr, uid, id, context)
		self.write(cr, uid, [id], {'active': value}, context)
		self.pool.get('project.task').write(cr, uid,
			[task.id for task in proj.tasks],
			{'active': value}, context)
		for child in proj.child_id:
			self.setActive(cr, uid, child.id, value, context)
 		return True
project()

class project_task_type(osv.osv):
	_name = 'project.task.type'
	_description = 'Project task type'
	_columns = {
		'name': fields.char('Type', required=True, size=64),
		'description': fields.text('Description'),
	}
project_task_type()

class task(osv.osv):
	_name = "project.task"
	_description = "Task"
	def _hours_effect(self, cr, uid, ids, name, args, context):
		res = {}
		for task in self.browse(cr, uid, ids, context=context):
			tot = 0
			for work in task.work_ids:
				tot += work.hours
			res[task.id] = tot
		return res

	_columns = {
		'name': fields.char('Task summary', size=128, required=True),
		'active': fields.boolean('Active'),
		'description': fields.text('Description'),
		'cust_desc': fields.text("Description for the customer"),
		'priority' : fields.selection([('4','Very Low'), ('3','Low'), ('2','Medium'), ('1','Urgent'), ('0','Very urgent')], 'Priority'),
		'sequence': fields.integer('Sequence'),
		'type': fields.many2one('project.task.type', 'Type'),
		'state': fields.selection([('open', 'Open'), ('progress', 'In progress'), ('cancelled', 'Cancelled'), ('done', 'Done')], 'State', readonly=True),
		'date_start': fields.datetime('Date Start'),
		'date_deadline': fields.datetime('Deadline'),
		'date_close': fields.datetime('Date Closed', readonly=True),
		'project_id': fields.many2one('project.project', 'Project', ondelete='cascade'),
		'notes': fields.text('Notes'),
		'start_sequence': fields.boolean('Wait for previous sequences'),
		'planned_hours': fields.float('Planned hours'),
		'effective_hours': fields.function(_hours_effect, method=True, string='Effective hours'),
		'progress': fields.integer('Progress (0-100)'),
		'billable': fields.boolean('To be invoiced'),
		'invoice_id': fields.many2one('account.invoice','Generated Invoice'),
		'user_id': fields.many2one('res.users', 'Assigned to', relate=True),
		'partner_id': fields.many2one('res.partner', 'Customer'),
		'work_ids': fields.one2many('project.task.work', 'task_id', 'Work done'),
		'procurement_id': fields.many2one('mrp.procurement', 'Procurement', ondelete='set null')
	}
	_defaults = {
		'user_id': lambda obj,cr,uid,context: uid,
		'state': lambda *a: 'open',
		'priority': lambda *a: '1',
		'progress': lambda *a: 0,
		'sequence': lambda *a: 10,
		'active': lambda *a: True,
	}
	_order = "state, sequence, priority, date_deadline, id"

	def do_close(self, cr, uid, ids, *args):
		request = self.pool.get('res.request')
		tasks = self.browse(cr, uid, ids)
		for task in tasks:
			project = task.project_id
			if project: 
				if project.warn_manager and project.manager and (project.manager.id != uid):
					request.create(cr, uid, {
						'name': "Task '%s' closed" % task.name,
						'state': 'waiting',
						'act_from': uid,
						'act_to': project.manager.id,
						'ref_partner_id': task.partner_id.id,
						'ref_doc1': 'project.task,%d'% (task.id,),
						'ref_doc2': 'project.project,%d'% (project.id,),
					})
			self.write(cr, uid, [task.id], {'state': 'done', 'date_close':time.strftime('%Y-%m-%d %H:%M:%S'), 'progress': 100})
			if task.procurement_id:
				wf_service = netsvc.LocalService("workflow")
				wf_service.trg_validate(uid, 'mrp.procurement', task.procurement_id.id, 'subflow.done', cr)
		return True

	def do_reopen(self, cr, uid, ids, *args):
		request = self.pool.get('res.request')
		tasks = self.browse(cr, uid, ids)
		for task in tasks:
			project = task.project_id
			if project.warn_manager and project.manager.id and (project.manager.id != uid):
				request.create(cr, uid, {
					'name': "Task '%s' reopened" % task.name,
					'state': 'waiting',
					'act_from': uid,
					'act_to': project.manager.id,
					'ref_partner_id': task.partner_id.id,
					'ref_doc1': 'project.task,%d' % task.id,
					'ref_doc2': 'project.project,%d' % project.id,
				})

			self.write(cr, uid, [task.id], {'state': 'open'})
		return True

	def do_cancel(self, cr, uid, ids, *args):
		request = self.pool.get('res.request')
		tasks = self.browse(cr, uid, ids)
		for task in tasks:
			project = task.project_id
			if project.warn_manager and project.manager and (project.manager.id != uid):
				request.create(cr, uid, {
					'name': "Task '%s' cancelled" % task.name,
					'state': 'waiting',
					'act_from': uid,
					'act_to': project.manager.id,
					'ref_partner_id': task.partner_id.id,
					'ref_doc1': 'project.task,%d' % task.id,
					'ref_doc2': 'project.project,%d' % project.id,
				})
			self.write(cr, uid, [task.id], {'state': 'cancelled'})
			if task.procurement_id:
				wf_service = netsvc.LocalService("workflow")
				wf_service.trg_validate(uid, 'mrp.procurement', task.procurement_id.id, 'subflow.cancel', cr)
		return True
task()

class project_work(osv.osv):
	_name = "project.task.work"
	_description = "Task Work"
	_columns = {
		'name': fields.char('Work summary', size=128),
		'date': fields.datetime('Date start'),
		'task_id': fields.many2one('project.task', 'Task', ondelete='cascade'),
		'hours': fields.float('Hours spent'),
		'user_id': fields.many2one('res.users', 'Done by', required=True, relate=True),
	}
	_defaults = {
		'user_id': lambda obj,cr,uid,context: uid,
		'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S')
	}
	_order = "date desc"
project_work()


