details: https://code.tryton.org/tryton/commit/f1bdafb36719
branch: default
user: Cédric Krier <[email protected]>
date: Tue Apr 07 16:58:15 2026 +0200
description:
Use the EXTRACT function to calculate the cost of the timesheet work
diffstat:
modules/project_revenue/work.py | 21 +++++++++++----------
1 files changed, 11 insertions(+), 10 deletions(-)
diffs (55 lines):
diff -r f2642fe60c20 -r f1bdafb36719 modules/project_revenue/work.py
--- a/modules/project_revenue/work.py Tue Apr 07 16:46:21 2026 +0200
+++ b/modules/project_revenue/work.py Tue Apr 07 16:58:15 2026 +0200
@@ -1,18 +1,21 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
-import datetime as dt
from collections import defaultdict
from decimal import Decimal
from sql.aggregate import Sum
+from sql.conditionals import Coalesce
+from sql.functions import Extract
from sql.operators import Concat
+from trytond import backend
from trytond.model import fields
from trytond.modules.currency.fields import Monetary
from trytond.modules.product import price_digits, round_price
from trytond.pool import Pool, PoolMeta
from trytond.pyson import Bool, Eval, If
+from trytond.tools import sqlite_apply_types
from trytond.transaction import Transaction
@@ -98,21 +101,19 @@
work = Work.__table__()
line = Line.__table__()
+ cost = line.cost_price * Extract('EPOCH', line.duration) / (60 * 60)
where = fields.SQL_OPERATORS['in'](table.id, map(int, works))
- cursor.execute(*table.join(work,
+ query = (table.join(work,
condition=(
Concat(cls.__name__ + ',', table.id) == work.origin)
).join(line, condition=line.work == work.id
- ).select(table.id, Sum(line.cost_price * line.duration),
+ ).select(table.id, Sum(Coalesce(cost, 0)).as_('cost'),
where=where,
group_by=[table.id]))
- for work_id, cost in cursor:
- # SQLite stores timedelta as float
- if isinstance(cost, dt.timedelta):
- cost = cost.total_seconds()
- # Convert from seconds
- cost /= 60 * 60
- yield work_id, Decimal(str(cost))
+ if backend.name == 'sqlite':
+ sqlite_apply_types(query, [None, 'NUMERIC'])
+ cursor.execute(*query)
+ yield from cursor
@classmethod
def _purchase_cost(cls, works):