[POS-commit] r1975 - in stoq/trunk/stoq: gui/pos gui/till lib
Henrique Romano
henrique at async.com.br
Fri Dec 23 14:49:26 BRST 2005
Author: henrique
Date: Fri Dec 23 14:49:26 2005
New Revision: 1975
Modified:
stoq/trunk/stoq/gui/pos/pos.py
stoq/trunk/stoq/gui/till/till.py
stoq/trunk/stoq/lib/drivers.py
Log:
Fix for bug #2364: Implements support for concomitant impression of
fiscal coupons.
Initial implementation.
r=evandro
Modified: stoq/trunk/stoq/gui/pos/pos.py
==============================================================================
--- stoq/trunk/stoq/gui/pos/pos.py (original)
+++ stoq/trunk/stoq/gui/pos/pos.py Fri Dec 23 14:49:26 2005
@@ -43,6 +43,7 @@
from stoq.lib.runtime import new_transaction
from stoq.lib.validators import (format_quantity, get_price_format_str)
from stoq.lib.parameters import sysparam
+from stoq.lib.drivers import FiscalCoupon
from stoq.domain.sellable import AbstractSellable, FancySellable
from stoq.domain.service import ServiceSellableItem
from stoq.domain.product import ProductSellableItem, FancyProduct
@@ -82,9 +83,13 @@
'header_label',
'pos_vbox',
'search_box',
- 'SalesMenu') + client_widgets + product_widgets +
- sellable_widgets)
-
+ 'SalesMenu',
+ 'CancelOrder',
+ 'ResetOrder')
+ + client_widgets
+ + product_widgets
+ + sellable_widgets)
+
def __init__(self, app):
AppWindow.__init__(self, app)
self.conn = new_transaction()
@@ -94,6 +99,7 @@
self.app.shutdown()
self.max_results = get_max_search_results()
self.client_table = Person.getAdapterClass(IClient)
+ self.coupon = None
self._setup_widgets()
self._setup_proxies()
self._clear_order()
@@ -107,6 +113,8 @@
self.order_list.clear()
self.sale = None
self.client_proxy.new_model(self.sale, relax_type=True)
+ self.CancelOrder.set_sensitive(False)
+ self.ResetOrder.set_sensitive(True)
def _delete_sellable_item(self, item):
self.order_list.remove(item)
@@ -146,7 +154,6 @@
self._setup_entry_completion()
# Waiting for bug 2319
self.client_details_button.set_sensitive(False)
-
def _update_totals(self, *args):
self.summary_label.update_total()
@@ -190,6 +197,8 @@
self.order_list.append(sellable_item)
self.order_list.select(sellable_item)
self.product.set_text('')
+ if not sysparam(self.conn).CONFIRM_SALES_ON_TILL:
+ self.coupon.add_item(sellable_item)
def _get_sellable(self):
if self.product_proxy.model:
@@ -233,8 +242,24 @@
self.header_box.hide()
self.pos_vbox.set_sensitive(True)
self.product.grab_focus()
+ self.ResetOrder.set_sensitive(False)
+ self.CancelOrder.set_sensitive(True)
else:
rollback_and_begin(self.conn)
+ if sysparam(self.conn).CONFIRM_SALES_ON_TILL:
+ return
+ if not self.coupon:
+ self.coupon = FiscalCoupon(self.conn, self.sale)
+ if self.sale.client:
+ self.coupon.identify_customer(self.sale.client.get_adapted())
+ while not self.coupon.open():
+ if warning(
+ _("It is not possible open a fiscal coupon"),
+ _("It is not possible start a new sale since a "
+ "fiscal does not can be opened."),
+ buttons=((_("Confirm later"), gtk.RESPONSE_CANCEL),
+ (_("Try Again"), gtk.RESPONSE_OK))) != gtk.RESPONSE_OK:
+ self.app.shutdown()
def _update_widgets(self):
has_sellables = len(self.order_list[:]) >= 1
@@ -341,12 +366,17 @@
def on_remove_item_button__clicked(self, *args):
item = self.order_list.get_selected()
+ if (not sysparam(self.conn).CONFIRM_SALES_ON_TILL
+ and not self.coupon.remove_item(item)):
+ return
self._delete_sellable_item(item)
self.select_first_item()
self._update_widgets()
def _on_cancel_order_action_clicked(self, *args):
- pass
+ self._clear_order()
+ if not sysparam(self.conn).CONFIRM_SALES_ON_TILL:
+ self.coupon.cancel()
def _on_resetorder_action__clicked(self, *args):
self._new_order()
@@ -382,6 +412,11 @@
param.SET_PAYMENT_METHODS_ON_TILL)
if self.run_dialog(SaleWizard, self.conn, self.sale,
skip_payment_step=skip_payment_step):
+ if not skip_payment_step and not param.CONFIRM_SALES_ON_TILL:
+ if (not self.coupon.totalize()
+ or not self.coupon.setup_payments()
+ or not self.coupon.close()):
+ return
self.conn.commit()
self._clear_order()
Modified: stoq/trunk/stoq/gui/till/till.py
==============================================================================
--- stoq/trunk/stoq/gui/till/till.py (original)
+++ stoq/trunk/stoq/gui/till/till.py Fri Dec 23 14:49:26 2005
@@ -224,7 +224,7 @@
return
sale.confirm_sale()
- if not emit_coupon(self.conn, sale):
+ if not emit_coupon(sale, self.conn):
return
self.conn.commit()
self.searchbar.search_items()
Modified: stoq/trunk/stoq/lib/drivers.py
==============================================================================
--- stoq/trunk/stoq/lib/drivers.py (original)
+++ stoq/trunk/stoq/lib/drivers.py Fri Dec 23 14:49:26 2005
@@ -33,6 +33,7 @@
import socket
import gtk
+from zope.interface import implements
from sqlobject.sqlbuilder import OR
from stoqlib.exceptions import DatabaseInconsistency
from stoqlib.exceptions import _warn
@@ -45,13 +46,11 @@
from stoq.domain.drivers import PrinterSettings
from stoq.domain.interfaces import (IIndividual, IPaymentGroup,
- IMoneyPM, ICheckPM)
+ IMoneyPM, ICheckPM, IContainer)
_ = gettext.gettext
_printer = None
-MAX_DIALOG_MESSAGE_LEN = 70
-
def get_printer_settings_by_hostname(conn, hostname):
""" Returns the PrinterSettings object associated with the given
hostname or None if there is not settings for it.
@@ -86,15 +85,6 @@
% socket.gethostname()))
return _printer
-def _cancel(printer):
- """ @returns: True if the reduce Z has been emitted, False otherwise.
- """
- try:
- printer.cancel()
- except DriverError:
- return False
- return True
-
def _emit_reading(conn, cmd):
printer = _get_fiscalprinter(conn)
if not printer:
@@ -113,86 +103,159 @@
def emit_reduce_Z(conn):
return _emit_reading(conn, 'close_till')
-def emit_coupon(conn, sale):
+def emit_coupon(sale, conn):
""" Emit a coupon for a Sale instance.
@returns: True if the coupon has been emitted, False otherwise.
"""
- printer = _get_fiscalprinter(conn)
- if not printer:
- return False
-
+ coupon = FiscalCoupon(conn, sale)
person = sale.client.get_adapted()
- address = person.get_main_address().get_address_string()
- individual = IIndividual(person, connection=person.get_connection())
- if individual is None:
- raise DatabaseInconsistency("The client must have a Individual facet")
- cpf = individual.cpf
+ if person:
+ coupon.identify_customer(person)
+ if not coupon.open():
+ return False
+ map(coupon.add_item, sale.get_items())
+ if not coupon.totalize():
+ return False
+ if not coupon.setup_payments():
+ return False
+ return coupon.close()
- printer.identify_customer(person.name, address, cpf)
- while True:
- try:
- printer.open()
- break
- except CouponOpenError:
- if not _cancel(printer):
- return False
- except OutofPaperError:
- if warning(
- _("The printer has run out of paper"),
- _("The printer %s has run out of paper.\nAdd more paper "
- "before continuing." % printer.get_printer_name()),
- buttons=((_("Confirm later"), gtk.RESPONSE_CANCEL),
- (_("Resume"), gtk.RESPONSE_OK))) != gtk.RESPONSE_OK:
- return False
- return emit_coupon(conn, sale)
- except PrinterOfflineError:
- if warning(
- _("The printer is offline"),
- _("The printer %s is offline, turn it on and try again"
- % printer.get_printer_name()),
- buttons=((_("Confirm later"), gtk.RESPONSE_CANCEL),
- (_("Resume"), gtk.RESPONSE_OK))) != gtk.RESPONSE_OK:
- return False
- return emit_coupon(conn, sale)
- except DriverError, details:
- warning(_("It's not possible to emit the coupon"), str(details))
- return False
+#
+# Class definitions
+#
+
+class FiscalCoupon:
+ """ This class is used just to allow us cancel an item with base in a
+ AbstractSellable object.
+ """
+ implements(IContainer)
+
+ #
+ # IContainer implementation
+ #
+
+ def __init__(self, conn, sale):
+ self.sale = sale
+ self.conn = conn
+ self.printer = _get_fiscalprinter(conn)
+ if not self.printer:
+ raise ValueError
+ self._item_ids = {}
- for item in sale.get_items():
+ def add_item(self, item):
sellable = item.sellable
+ description = sellable.base_sellable_info.description
# FIXME: TAX_NONE is a HACK, waiting for bug #2269
# FIXME: UNIT_EMPTY is temporary and will be remove when bug #2247
# is fixed.
- printer.add_item(sellable.code, item.quantity, item.price,
- UNIT_EMPTY, sellable.base_sellable_info.description,
- TAX_NONE, 0, 0)
-
- printer.totalize(sale.discount_value, sale.charge_value, TAX_NONE)
-
- group = IPaymentGroup(sale, connection=conn)
- if group.default_method == group.METHOD_GIFT_CERTIFICATE:
- printer.add_payment(MONEY_PM, sale.get_total_sale_amount(), '')
- else:
- for payment in group.get_items():
- if ICheckPM.providedBy(payment.method):
- money_type = CHEQUE_PM
- elif IMoneyPM.providedBy(payment.method):
- money_type = MONEY_PM
- # FIXME: A default value, this is wrong but can't be better right
- # now, since stoqdrivers doesn't have support for any payment
- # method diferent than money and cheque. This will be improved
- # when bug #2246 is fixed.
- else:
- _warn(_("The payment type %d isn't supported yet. "
- "The default, MONEY_PM, will be used.")
- % payment.method)
- money_type = MONEY_PM
- printer.add_payment(money_type, payment.value, '')
+ item_id = self.printer.add_item(sellable.code, item.quantity,
+ item.price, UNIT_EMPTY,
+ description, TAX_NONE, 0, 0)
+ self._item_ids[item] = item_id
+
+ def get_items(self):
+ return self._item_ids.values()
+
+ def remove_item(self, sellable):
+ item_id = self._item_ids[sellable]
+ try:
+ self.printer.cancel_item(item_id)
+ except DriverError:
+ return False
+ del self._item_ids[sellable]
+ return True
+
+ #
+ # Fiscal coupon related functions
+ #
+
+ def identify_customer(self, person):
+ address = person.get_main_address().get_address_string()
+ individual = IIndividual(person, connection=person.get_connection())
+ if individual is None:
+ raise DatabaseInconsistency("The client must have a "
+ "Individual facet")
+ cpf = individual.cpf
+ self.printer.identify_customer(person.name, address, cpf)
+
+ def open(self):
+ while True:
+ try:
+ self.printer.open()
+ break
+ except CouponOpenError:
+ if not self.cancel():
+ return False
+ except OutofPaperError:
+ if warning(
+ _("The printer has run out of paper"),
+ _("The printer %s has run out of paper.\nAdd more paper "
+ "before continuing." % printer.get_printer_name()),
+ buttons=((_("Confirm later"), gtk.RESPONSE_CANCEL),
+ (_("Resume"), gtk.RESPONSE_OK))) != gtk.RESPONSE_OK:
+ return False
+ return self.open()
+ except PrinterOfflineError:
+ if warning(
+ _("The printer is offline"),
+ _("The printer %s is offline, turn it on and try again"
+ % printer.get_printer_name()),
+ buttons=((_("Confirm later"), gtk.RESPONSE_CANCEL),
+ (_("Resume"), gtk.RESPONSE_OK))) != gtk.RESPONSE_OK:
+ return False
+ return self.open()
+ except DriverError, details:
+ warning(_("It's not possible to emit the coupon"), str(details))
+ return False
+ return True
+
+ def totalize(self):
+ self.printer.totalize(self.sale.discount_value,
+ self.sale.charge_value, TAX_NONE)
+ return True
+
+ def cancel(self):
+ try:
+ self.printer.cancel()
+ except DriverError:
+ return False
+ return True
+
+ def setup_payments(self):
+ """ Add the payments defined in the sale to the coupon. Note that this
+ function must be called after all the payments has been created.
+ """
+ sale = self.sale
+ group = IPaymentGroup(sale, connection=self.conn)
+ if not group:
+ raise ValueError("The sale object must have a PaymentGroup facet at "
+ "this point.")
+ if group.default_method == group.METHOD_GIFT_CERTIFICATE:
+ printer.add_payment(MONEY_PM, sale.get_total_sale_amount(), '')
+ else:
+ for payment in group.get_items():
+ if ICheckPM.providedBy(payment.method):
+ money_type = CHEQUE_PM
+ elif IMoneyPM.providedBy(payment.method):
+ money_type = MONEY_PM
+ # FIXME: A default value, this is wrong but can't be better right
+ # now, since stoqdrivers doesn't have support for any payment
+ # method diferent than money and cheque. This will be improved
+ # when bug #2246 is fixed.
+ else:
+ _warn(_("The payment type %d isn't supported yet. The default, "
+ "MONEY_PM, will be used.")
+ % payment.method)
+ money_type = MONEY_PM
+ self.printer.add_payment(money_type, payment.value, '')
+ return True
+
+ def close(self):
+ try:
+ self.printer.close()
+ except DriverError, details:
+ warning(_("It's not possible to close the coupon"), str(details))
+ return False
+ return True
- try:
- printer.close()
- except DriverError, details:
- warning(_("It's not possible to close the coupon"), str(details))
- return False
- return True
More information about the POS-commit
mailing list