From 0bf157cc019a5aefd27a5c6a6cd28297df735fb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 22 Sep 2015 19:26:13 +0200 Subject: [PATCH] Store cost price on timesheet line issue4977 review23421002 --- CHANGELOG | 4 ++- INSTALL | 2 ++ company.py | 49 ++++++------------------------------- company.xml | 33 +++++++++++++++++++++++++ setup.py | 2 +- timesheet.py | 67 ++++++++++++++++++++++++++++++++++++++++++--------- timesheet.xml | 22 +++++++++++++++++ tryton.cfg | 2 ++ 8 files changed, 126 insertions(+), 55 deletions(-) create mode 100644 timesheet.xml diff --git a/CHANGELOG b/CHANGELOG index 1b06dc3d47..874cf4a35c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,5 @@ +* Store cost price on timesheet line + Version 3.6.0 - 2015-04-20 * Bug fixes (see mercurial logs for details) * Add support for PyPy @@ -8,4 +10,4 @@ Version 3.2.0 - 2014-04-21 * Bug fixes (see mercurial logs for details) Version 3.0.0 - 2013-10-21 -* Initial release \ No newline at end of file +* Initial release diff --git a/INSTALL b/INSTALL index dfd0a5a374..87ed3d7294 100644 --- a/INSTALL +++ b/INSTALL @@ -5,8 +5,10 @@ Prerequisites ------------- * Python 2.7 or later (http://www.python.org/) + * python-sql 0.4 or later (http://pypi.python.org/pypi/python-sql) * trytond (http://www.tryton.org/) * trytond_timesheet (http://www.tryton.org/) + * trytond_party (http://www.tryton.org/) * trytond_company (http://www.tryton.org/) Installation diff --git a/company.py b/company.py index 76df8d7aba..0f6fbd667e 100644 --- a/company.py +++ b/company.py @@ -2,25 +2,26 @@ # this repository contains the full copyright notices and license terms. from decimal import Decimal from trytond.model import ModelView, ModelSQL, fields, Unique -from trytond.pyson import Eval from trytond.cache import Cache from trytond.transaction import Transaction from trytond.pool import Pool, PoolMeta from trytond import backend +from trytond.config import config -__all__ = ['Employee', 'EmployeeCostPrice'] +__all__ = ['Employee', 'EmployeeCostPrice', 'price_digits'] __metaclass__ = PoolMeta +price_digits = (16, config.getint( + 'timesheet_cost', 'price_decimal', default=4)) + class Employee: __name__ = 'company.employee' cost_price = fields.Function(fields.Numeric('Cost Price', - digits=(16, Eval('currency_digits', 2)), depends=['currency_digits'], - help="Hourly cost price for this Employee"), 'get_cost_price') + digits=price_digits, + help="Hourly cost price for this Employee"), 'get_cost_price') cost_prices = fields.One2Many('company.employee_cost_price', 'employee', 'Cost Prices', help="List of hourly cost price over time") - currency_digits = fields.Function(fields.Integer('Currency Digits'), - 'on_change_with_currency_digits') _cost_prices_cache = Cache('company_employee.cost_prices') def get_cost_price(self, name): @@ -68,21 +69,6 @@ class Employee: break return cost - @fields.depends('company') - def on_change_with_currency_digits(self, name=None): - if self.company: - return self.company.currency.digits - return 2 - - @staticmethod - def default_currency_digits(): - Company = Pool().get('company.company') - company = Transaction().context.get('company') - if company: - company = Company(company) - return company.currency.digits - return 2 - class EmployeeCostPrice(ModelSQL, ModelView): 'Employee Cost Price' @@ -90,12 +76,8 @@ class EmployeeCostPrice(ModelSQL, ModelView): _rec_name = 'date' date = fields.Date('Date', required=True, select=True) cost_price = fields.Numeric('Cost Price', - digits=(16, Eval('currency_digits', 2)), - required=True, depends=['currency_digits'], - help="Hourly cost price") + digits=price_digits, required=True, help="Hourly cost price") employee = fields.Many2One('company.employee', 'Employee') - currency_digits = fields.Function(fields.Integer('Currency Digits'), - 'on_change_with_currency_digits') @classmethod def __register__(cls, module_name): @@ -145,18 +127,3 @@ class EmployeeCostPrice(ModelSQL, ModelView): Employee = Pool().get('company.employee') super(EmployeeCostPrice, cls).write(*args) Employee._cost_prices_cache.clear() - - @fields.depends('employee') - def on_change_with_currency_digits(self, name=None): - if self.employee: - return self.employee.company.currency.digits - return 2 - - @staticmethod - def default_currency_digits(): - Company = Pool().get('company.company') - company = Transaction().context.get('company') - if company: - company = Company(company) - return company.currency.digits - return 2 diff --git a/company.xml b/company.xml index 1c3fdbf3cb..a5ded29fab 100644 --- a/company.xml +++ b/company.xml @@ -20,5 +20,38 @@ this repository contains the full copyright notices and license terms. --> employee_form + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/setup.py b/setup.py index 57b51fc716..491a800ecc 100644 --- a/setup.py +++ b/setup.py @@ -41,7 +41,7 @@ if minor_version % 2: 'hg+http://hg.tryton.org/modules/%s#egg=%s-%s' % ( name[8:], name, version)) -requires = [] +requires = ['python-sql >= 0.4'] for dep in info.get('depends', []): if not re.match(r'(ir|res|webdav)(\W|$)', dep): requires.append(get_require_version('trytond_%s' % dep)) diff --git a/timesheet.py b/timesheet.py index 367da06115..9c8af79acb 100644 --- a/timesheet.py +++ b/timesheet.py @@ -1,8 +1,12 @@ # This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. -from decimal import Decimal +from sql import Null + from trytond.transaction import Transaction from trytond.pool import Pool, PoolMeta +from trytond.model import fields + +from .company import price_digits __all__ = ['TimesheetLine'] __metaclass__ = PoolMeta @@ -11,17 +15,56 @@ __metaclass__ = PoolMeta class TimesheetLine: __name__ = 'timesheet.line' - def compute_cost(self): - Currency = Pool().get('currency.currency') + cost_price = fields.Numeric('Cost Price', + digits=price_digits, required=True, readonly=True) - cost_price = self.employee.compute_cost_price(date=self.date) + @classmethod + def __register__(cls, module_name): + pool = Pool() + Employee = pool.get('company.employee') - line_company = self.employee.company - work_company = self.work.company - if (line_company != work_company and - line_company.currency != work_company.currency): - with Transaction().set_context(date=self.date): - cost_price = Currency.compute(line_company.currency, - cost_price, work_company.currency) + cursor = Transaction().cursor + table = cls.__table__() - return Decimal(str(self.hours)) * cost_price + super(TimesheetLine, cls).__register__(module_name) + + # Migration from 3.6: add cost_price + cursor.execute(*table.select(table.id, table.employee, table.date, + where=(table.cost_price == Null) + & (table.employee != Null) + & (table.date != Null))) + for line_id, employee_id, date in cursor.fetchall(): + employee = Employee(employee_id) + cost_price = employee.compute_cost_price(date=date) + cursor.execute(*table.update( + [table.cost_price], + [cost_price], + where=table.id == line_id)) + + @classmethod + def default_cost_price(cls): + # Needed at creation as cost_price is required + return 0 + + @classmethod + def create(cls, vlist): + lines = super(TimesheetLine, cls).create(vlist) + cls.sync_cost(lines) + return lines + + @classmethod + def write(cls, *args): + super(TimesheetLine, cls).write(*args) + cls.sync_cost(sum(args[0:None:2], [])) + + @classmethod + def sync_cost(cls, lines): + with Transaction().set_context(_check_access=False): + to_write = [] + lines = cls.browse(lines) + for line in lines: + cost_price = line.employee.compute_cost_price(date=line.date) + if cost_price != line.cost_price: + to_write.extend([[line], {'cost_price': cost_price}]) + if to_write: + cls.write(*to_write) diff --git a/timesheet.xml b/timesheet.xml new file mode 100644 index 0000000000..c8b33c898c --- /dev/null +++ b/timesheet.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + diff --git a/tryton.cfg b/tryton.cfg index fc4d3c7c8f..05ba5feca5 100644 --- a/tryton.cfg +++ b/tryton.cfg @@ -3,6 +3,8 @@ version=3.7.0 depends: ir company + party timesheet xml: company.xml + timesheet.xml