@@ -1,3 +1,4 @@
|
||||
* Display cost of works
|
||||
|
||||
Version 6.8.0 - 2023-05-01
|
||||
--------------------------
|
||||
|
||||
@@ -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::
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user