Display cost of production works

Closes #11001
This commit is contained in:
Adrià Tarroja Caubet
2023-05-03 14:29:57 +02:00
parent b2f90a89e0
commit 65c6380cad
6 changed files with 41 additions and 31 deletions
+1
View File
@@ -1,3 +1,4 @@
* Display cost of works
Version 6.8.0 - 2023-05-01
--------------------------
+4 -30
View File
@@ -1,16 +1,10 @@
# 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.aggregate import Sum
from trytond.i18n import gettext
from trytond.model import ModelView, Workflow, fields
from trytond.model.exceptions import AccessError
from trytond.modules.product import round_price
from trytond.pool import Pool, PoolMeta
from trytond.pyson import Bool, Eval
from trytond.transaction import Transaction
class Production(metaclass=PoolMeta):
@@ -36,30 +30,10 @@ class Production(metaclass=PoolMeta):
])
def get_cost(self, name):
pool = Pool()
Work = pool.get('production.work')
Cycle = pool.get('production.work.cycle')
table = self.__table__()
work = Work.__table__()
cycle = Cycle.__table__()
cursor = Transaction().connection.cursor()
cost = super(Production, self).get_cost(name)
cursor.execute(*table.join(work, 'LEFT',
condition=work.production == table.id
).join(cycle, 'LEFT', condition=cycle.work == work.id
).select(Sum(cycle.cost),
where=(cycle.state == 'done')
& (table.id == self.id)))
cycle_cost, = cursor.fetchone()
if cycle_cost is not None:
# SQLite uses float for SUM
if not isinstance(cycle_cost, Decimal):
cycle_cost = Decimal(cycle_cost)
cost += cycle_cost
return round_price(cost)
cost = super().get_cost(name)
for work in self.works:
cost += work.cost
return cost
@classmethod
@ModelView.button
@@ -244,6 +244,10 @@ Check production cost::
>>> production.reload()
>>> production.cost
Decimal('17.0000')
>>> work1.cost
Decimal('10.0000')
>>> work2.cost
Decimal('5.0000')
Do the production::
+2 -1
View File
@@ -17,7 +17,8 @@ this repository contains the full copyright notices and license terms. -->
<button name="stop" icon="tryton-ok"/>
</group>
<field name="cycles" colspan="4"/>
<label id="empty" colspan="2"/>
<label name="cost"/>
<field name="cost"/>
<label name="state"/>
<field name="state"/>
</form>
@@ -5,5 +5,6 @@ this repository contains the full copyright notices and license terms. -->
<field name="production" expand="1"/>
<field name="operation" expand="1"/>
<field name="work_center" expand="1"/>
<field name="cost" optional="0"/>
<field name="state"/>
</tree>
+29
View File
@@ -2,9 +2,13 @@
# this repository contains the full copyright notices and license terms.
import datetime
import random
from collections import defaultdict
from decimal import Decimal
from functools import wraps
from sql.aggregate import Sum
from sql.conditionals import Coalesce
from trytond.i18n import gettext
from trytond.model import (
DeactivableMixin, Index, ModelSQL, ModelView, Workflow, fields,
@@ -13,6 +17,7 @@ from trytond.model.exceptions import AccessError
from trytond.modules.product import price_digits, round_price
from trytond.pool import Pool
from trytond.pyson import Bool, Eval, If, TimeDelta
from trytond.tools import grouped_slice, reduce_ids
from trytond.transaction import Transaction
from .exceptions import PickerError
@@ -128,6 +133,8 @@ class Work(sequence_ordered(), ModelSQL, ModelView):
filter=[
('state', '=', 'running'),
])
cost = fields.Function(fields.Numeric(
"Cost", digits=price_digits), 'get_cost')
company = fields.Many2One('company.company', "Company", required=True)
warehouse = fields.Function(fields.Many2One('stock.location', 'Warehouse'),
'on_change_with_warehouse')
@@ -244,6 +251,28 @@ class Work(sequence_ordered(), ModelSQL, ModelView):
('production.rec_name',) + tuple(clause[1:]),
]
@classmethod
def get_cost(cls, works, name):
pool = Pool()
Cycle = pool.get('production.work.cycle')
cycle = Cycle.__table__()
cursor = Transaction().connection.cursor()
costs = defaultdict(Decimal)
for sub_works in grouped_slice(works):
red_sql = reduce_ids(cycle.work, [w.id for w in sub_works])
cursor.execute(*cycle.select(
cycle.work, Sum(Coalesce(cycle.cost, 0)),
where=red_sql & (cycle.state == 'done'),
group_by=cycle.work))
costs.update(cursor)
for cost in costs:
if not isinstance(cost, Decimal):
costs[cost] = Decimal(str(costs[cost]))
costs[cost] = round_price(costs[cost])
return costs
@classmethod
def create(cls, values):
works = super(Work, cls).create(values)