# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
##
## Copyright (C) 2009 Async Open Source <http://www.async.com.br>
## All rights reserved
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU Lesser 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 Lesser General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., or visit: http://www.gnu.org/.
##
## Author(s): Stoq Team <stoq-devel@async.com.br>
##
""" Production details dialogs """
from decimal import Decimal
import pango
import gtk
from kiwi.ui.objectlist import Column, ColoredColumn
from stoqlib.api import api
from stoqlib.domain.inventory import Inventory
from stoqlib.domain.production import ProductionOrder
from stoqlib.gui.base.dialogs import run_dialog
from stoqlib.gui.editors.baseeditor import BaseEditor
from stoqlib.gui.slaves.productionslave import QualityTestResultSlave
from stoqlib.gui.editors.productioneditor import (ProductionItemProducedEditor,
ProductionMaterialLostEditor,
ProductionMaterialAllocateEditor,
)
from stoqlib.gui.utils.printing import print_report
from stoqlib.lib.translation import stoqlib_gettext
from stoqlib.reporting.production import ProductionOrderReport
_ = stoqlib_gettext
[docs]class ProductionDetailsDialog(BaseEditor):
gladefile = "ProductionDetailsDialog"
model_type = ProductionOrder
title = _("Production Details")
size = (750, 460)
hide_footer = True
proxy_widgets = ('branch',
'identifier',
'open_date',
'close_date',
'responsible_name',
'status_string', )
def _setup_widgets(self):
self.production_items.set_columns(self._get_production_items_columns())
self.materials.set_columns(self._get_material_columns())
self.services.set_columns(self._get_service_columns())
self.produced_items.set_columns(self._get_produced_items_columns())
self.produced_items.set_selection_mode(gtk.SELECTION_MULTIPLE)
def _setup_data(self):
# FIXME: Improve this
self.production_items.clear()
self.materials.clear()
self.services.clear()
self.produced_items.clear()
self.production_items.add_list(self.model.get_items())
self.materials.add_list(self.model.get_material_items())
self.services.add_list(self.model.get_service_items())
self.produced_items.add_list(
self.model.produced_items.order_by(ProductionOrder.identifier))
self.proxy.update_many(['close_date', 'status_string'])
def _get_production_items_columns(self):
return [Column('description',
title=_('Description'),
data_type=str, expand=True, searchable=True,
ellipsize=pango.ELLIPSIZE_END, sorted=True),
Column('unit_description', _("Unit"),
data_type=str, justify=gtk.JUSTIFY_RIGHT),
Column('quantity', title=_('Quantity'),
data_type=Decimal, justify=gtk.JUSTIFY_RIGHT),
Column('produced', title=_('Produced'),
data_type=Decimal, justify=gtk.JUSTIFY_RIGHT),
Column('lost', title=_('Lost'),
data_type=Decimal, justify=gtk.JUSTIFY_RIGHT)]
def _get_material_columns(self):
return [Column('description', title=_('Description'),
data_type=str, expand=True, searchable=True,
ellipsize=pango.ELLIPSIZE_END, sorted=True),
Column('product.location', _("Location"), data_type=str),
Column('unit_description', _("Unit"),
data_type=str, justify=gtk.JUSTIFY_RIGHT),
Column('needed', title=_('Needed'),
data_type=Decimal, justify=gtk.JUSTIFY_RIGHT),
Column('allocated', title=_('Allocated'),
data_type=Decimal, justify=gtk.JUSTIFY_RIGHT),
Column('consumed', title=_('Consumed'),
data_type=Decimal, justify=gtk.JUSTIFY_RIGHT),
Column('lost', title=_('Lost'),
data_type=Decimal, justify=gtk.JUSTIFY_RIGHT),
Column('to_purchase', title=_('To Purchase'),
data_type=Decimal, justify=gtk.JUSTIFY_RIGHT,
visible=False),
Column('to_make', title=_('To Make'),
data_type=Decimal, justify=gtk.JUSTIFY_RIGHT,
visible=False)]
def _get_service_columns(self):
return [Column('description', _("Description"), data_type=str,
expand=True, ellipsize=pango.ELLIPSIZE_END),
Column('quantity', _("Quantity"),
data_type=Decimal, justify=gtk.JUSTIFY_RIGHT),
Column('unit_description', _("Unit"),
data_type=str, justify=gtk.JUSTIFY_RIGHT)]
def _get_test_result(self, item, quality_test):
"""Gets test result from cache, or fetch from database.
"""
hit = self._test_result_cache.get((item.id, quality_test.id), -1)
if hit != -1:
return hit
test_result = item.get_test_result(quality_test)
self._test_result_cache[(item.id, quality_test.id)] = test_result
return test_result
def _format_func(self, item, test):
"""Format function for tests columns.
test is the quality test associated with the column
"""
test_result = self._get_test_result(item, test)
if not test_result:
val = ''
else:
val = test_result.result_value
return val
def _colorize(self, item, test):
"""Set the color for this test result
test is the quality test associated with the column
"""
test_result = self._get_test_result(item, test)
if not test_result:
return False
return not test_result.test_passed
def _get_produced_items_columns(self):
# Create a cache for test results, to avoid quering the database for
# every update.
self._test_result_cache = dict()
columns = [Column('serial_number', title=_('Serial Number'),
data_type=str, expand=True)]
# Add one column for each test from each product.
products = dict()
for item in self.model.get_items():
if item.product in products:
continue
products[item.product] = 1
for test in item.product.quality_tests:
columns.append(
# This wont just the serial number, since we use format_func
# to change the displayed value, but we still need one
# property to create the column
ColoredColumn('serial_number',
data_type=str, title=test.description,
format_func=self._format_func,
format_func_data=test,
color='red', data_func=self._colorize,
use_data_model=True))
columns.extend([
Column('test_passed', title=_('Tests Passed'),
data_type=bool, visible=False),
Column('entered_stock', title=_('Entered Stock'),
data_type=bool, visible=False)])
return columns
#
# BaseEditor hooks
#
[docs] def setup_proxies(self):
self._setup_widgets()
self.proxy = self.add_proxy(self.model, ProductionDetailsDialog.proxy_widgets)
self._setup_data()
[docs] def setup_slaves(self):
self.quality_slave = QualityTestResultSlave(self.store)
self.quality_slave.connect('test-updated',
self._on_quality__test_updated)
self.attach_slave('quality_holder', self.quality_slave)
[docs] def has_open_inventory(self):
has_open = Inventory.has_open(self.store,
api.get_current_branch(self.store))
return bool(has_open)
#
# Actions
#
def _run_editor(self, editor_class, item):
self.store.savepoint('before_run_editor_production')
retval = run_dialog(editor_class, self, self.store, item)
if not retval:
self.store.rollback_to_savepoint('before_run_editor_production')
else:
self.store.commit()
self._setup_data()
def _produce(self):
production_item = self.production_items.get_selected()
self._run_editor(ProductionItemProducedEditor, production_item)
def _add_lost(self):
item = self.materials.get_selected()
self._run_editor(ProductionMaterialLostEditor, item)
def _allocate(self):
item = self.materials.get_selected()
self._run_editor(ProductionMaterialAllocateEditor, item)
#
# Kiwi Callbacks
#
def _on_quality__test_updated(self, slave, produced_item, quality_test,
test_result):
self._test_result_cache[(produced_item.id, quality_test.id)] = test_result
self.produced_items.update(produced_item)
[docs] def on_production_items__selection_changed(self, widget, item):
self.produce_button.set_sensitive(bool(item)
and item.can_produce(Decimal('0.001'))
and not self.has_open_inventory())
[docs] def on_materials__selection_changed(self, widget, item):
self.lost_button.set_sensitive(bool(item) and item.product.manage_stock and
item.can_add_lost(Decimal('0.001')))
self.allocate_button.set_sensitive(bool(item) and item.product.manage_stock and
self.model.status == ProductionOrder.ORDER_PRODUCING
and not self.has_open_inventory())
[docs] def on_produced_items__selection_changed(self, widget, items):
products = set()
for i in items:
products.add(i.product)
is_in_qa = self.model.status in (ProductionOrder.ORDER_PRODUCING,
ProductionOrder.ORDER_QA)
# We can only set test results if only one type of product is selected
if len(products) == 1 and is_in_qa:
self.quality_slave.set_item_tests(items, items[0].product)
else:
self.quality_slave.set_item_tests([], None)
[docs] def on_production_items__row_activated(self, list, row):
if self.produce_button.get_sensitive():
self._produce()