Source code for stoqlib.gui.dialogs.missingitemsdialog

# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4

##
## Copyright (C) 2005-2013 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 Lesser 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>
##

import gtk

from kiwi.python import Settable
from kiwi.ui.objectlist import Column

from stoqlib.api import api
from stoqlib.database.runtime import get_current_branch
from stoqlib.domain.production import ProductionMaterial, ProductionOrder
from stoqlib.domain.sale import Sale, SaleItem
from stoqlib.gui.base.dialogs import run_dialog
from stoqlib.gui.base.lists import SimpleListDialog
from stoqlib.lib.message import info
from stoqlib.lib.translation import stoqlib_gettext as _


[docs]class MissingItemsDialog(SimpleListDialog): """This dialog shows a list of missing products to confirm a stock operation Unless the user cancel the dialog, if the operation is a Sale, it will change the status from QUOTE to ORDERED. Also, for all productis missing that are composed, a new production order will be created. If it's not a Sale, the dialog is just informative and does not change anything. """ def __init__(self, order, missing): self.order = order self._is_sale_quote = (isinstance(order, Sale) and order.status == Sale.STATUS_QUOTE) self.missing = missing msg = '<b>%s</b>' % ( api.escape(_("The following items don't have enough stock to " "confirm."))) SimpleListDialog.__init__(self, self._get_columns(), missing, hide_cancel_btn=not self._is_sale_quote, title=_('Missing items'), header_text=msg) if self._is_sale_quote: label = gtk.Label(_('Do you want to order the sale instead?')) self.notice.add(label) label.show() self.set_ok_label(_('Order sale')) def _get_columns(self): return [Column('description', title=_(u'Product'), data_type=str, expand=True), Column('ordered', title=_(u'Ordered'), data_type=int), Column('stock', title=_(u'Stock'), data_type=int)] def _create_production_order(self, store): desc = _(u'Production for Sale order %s') % self.order.identifier if self.order.client: desc += ' (%s)' % self.order.client.get_name() user = api.get_current_user(store) employee = user.person.employee prod_order = ProductionOrder(branch=store.fetch(self.order.branch), status=ProductionOrder.ORDER_WAITING, responsible=employee, description=desc, store=store) materials = {} for item in self.missing: product = store.fetch(item.storable.product) components = list(product.get_components()) if not components: continue qty = item.ordered - item.stock prod_order.add_item(product.sellable, qty) # Merge possible duplicate components from different products for component in components: materials.setdefault(component.component, 0) materials[component.component] += component.quantity * qty for material, needed in materials.items(): ProductionMaterial(needed=needed, order=prod_order, product=material, store=store) if materials: info(_('A new production was created for the missing composed ' 'products')) else: store.remove(prod_order)
[docs] def confirm(self, *args): if self._is_sale_quote: store = api.new_store() sale = store.fetch(self.order) self._create_production_order(store) sale.order() store.confirm(True) store.close() return SimpleListDialog.confirm(self, *args)
[docs]def get_missing_items(order, store): """ Fetch missing items, the returning object has the following attributes set: - storable: A |storable| for the missing item; - description: A description for the missing item; - ordered: The quantity ordered of the missing item; - stock: The stock available of the missing item. :returns: a list of Settable items with the attributes mentioned above """ # Lets confirm that we can create the sale, before opening the coupon prod_sold = {} prod_desc = {} for item in order.get_items(): # Skip services, since we don't need stock to sell. if isinstance(item, SaleItem) and item.is_service(): continue storable = item.sellable.product_storable # There are some products that we dont control the stock if not storable: continue prod_sold.setdefault(storable, 0) prod_sold[storable] += item.quantity if isinstance(item, SaleItem): prod_sold[storable] -= item.quantity_decreased prod_desc[storable] = item.sellable.get_description() branch = get_current_branch(store) missing = [] for storable in prod_sold.keys(): stock = storable.get_balance_for_branch(branch) if stock < prod_sold[storable]: missing.append(Settable( storable=storable, description=prod_desc[storable], ordered=prod_sold[storable], stock=stock)) return missing
if __name__ == '__main__': # pragma nocover ec = api.prepare_test() sale_ = ec.create_sale() sale_.status = Sale.STATUS_QUOTE missingitems = [Settable(description='foo', ordered=False, stock=True)] run_dialog(MissingItemsDialog, None, sale_, missingitems)