[POS-commit] r1127 - in stoq/trunk/stoq: . domain examples
gui/editors gui/editors/glade gui/pos gui/till gui/till/glade lib
Henrique Romano
henrique at async.com.br
Mon Sep 5 10:21:50 BRT 2005
Author: henrique
Date: Mon Sep 5 10:21:49 2005
New Revision: 1127
Added:
stoq/trunk/stoq/domain/payment.py
stoq/trunk/stoq/examples/sale.py
stoq/trunk/stoq/gui/editors/glade/TillClosing.glade
stoq/trunk/stoq/gui/editors/glade/TillOpening.glade
stoq/trunk/stoq/gui/editors/till.py
stoq/trunk/stoq/gui/till/
stoq/trunk/stoq/gui/till/__init__.py
stoq/trunk/stoq/gui/till/app.py
stoq/trunk/stoq/gui/till/glade/
stoq/trunk/stoq/gui/till/glade/till.glade
stoq/trunk/stoq/gui/till/till.py
Modified:
stoq/trunk/stoq/domain/interfaces.py
stoq/trunk/stoq/domain/sale.py
stoq/trunk/stoq/domain/tables.py
stoq/trunk/stoq/examples/createall.py
stoq/trunk/stoq/gui/pos/pos.py
stoq/trunk/stoq/lib/parameters.py
stoq/trunk/stoq/main.py
Log:
Fix for bug #2081: Initial implementation of Till application.
r=evandro
Modified: stoq/trunk/stoq/domain/interfaces.py
==============================================================================
--- stoq/trunk/stoq/domain/interfaces.py (original)
+++ stoq/trunk/stoq/domain/interfaces.py Mon Sep 5 10:21:49 2005
@@ -351,6 +351,44 @@
'comission. This is a reference to another '
'object')
+
+class IInPayment(ConnInterface):
+ """ Interface specification for InPayments. """
+
+ def receive(value=None, paid_date=None):
+ """ Confirm the payment. """
+
+
+class IOutPayment(ConnInterface):
+ """ Interface specification for OutPayments. """
+
+ def pay(value=None, paid_date=None):
+ """ Confirm the payment."""
+
+
+class IPaymentGroup(ConnInterface):
+ """ Interface specification for PaymentGroups. """
+
+ status = Attribute('status',
+ 'int',
+ 'The status of the payment group. ')
+ open_date = Attribute('open_date',
+ 'datetime',
+ 'The open date of the payment group.')
+ close_date = Attribute('close_date',
+ 'datetime',
+ 'The close date of the payment group.')
+ notes = Attribute('notes',
+ 'str',
+ 'Extra notes for the payment group.')
+ payments = Attribute('payments',
+ 'list',
+ 'A list of payments associated to this payment '
+ 'group')
+ thirdparty = Attribute('thirdparty',
+ 'Person',
+ 'The thirdparty associated to this payment group.')
+
class IDelivery(ConnInterface):
""" Specification of a Delivery interface for a sellable. """
Added: stoq/trunk/stoq/domain/payment.py
==============================================================================
--- (empty file)
+++ stoq/trunk/stoq/domain/payment.py Mon Sep 5 10:21:49 2005
@@ -0,0 +1,304 @@
+# -*- Mode: Python; coding: iso-8859-1 -*-
+# vi:si:et:sw=4:sts=4:ts=4
+
+##
+## Copyright (C) 2005 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 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 General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+## USA.
+##
+## Author(s): Henrique Romano <henrique at async.com.br>
+"""
+stoq/domain/payment.py:
+
+ Implementation of classes related to Payment management.
+"""
+
+from datetime import datetime
+import operator
+
+from sqlobject import (IntCol, DateTimeCol, FloatCol, StringCol,
+ ForeignKey)
+from sqlobject.sqlbuilder import AND
+from stoqlib.exceptions import PaymentError, TillError
+
+from stoq.domain.base import (Domain, ModelAdapter,
+ InheritableModelAdapter)
+from stoq.domain.interfaces import IInPayment, IOutPayment, IPaymentGroup
+from stoq.domain.interfaces import IBranch, IContainer
+from stoq.domain.person import Person
+from stoq.lib.parameters import sysparam
+
+
+#
+# Domain Classes
+#
+
+class Payment(Domain):
+ (STATUS_PREVIEW, STATUS_TO_PAY, STATUS_PAID, STATUS_REVIEWING,
+ STATUS_CONFIRMED, STATUS_CANCELLED) = range(6)
+
+ status = IntCol(default=STATUS_PREVIEW)
+ due_date = DateTimeCol()
+ paid_date = DateTimeCol(default=None)
+ paid_value = FloatCol(default=None)
+ value = FloatCol()
+ description = StringCol(default=None)
+
+ method = ForeignKey('PaymentMethod')
+ group = ForeignKey('AbstractPaymentGroup')
+ # XXX: It will not be implemented for now.
+# destination = ForeignKey('Account')
+
+ def is_to_pay(self):
+ return self.status == self.STATUS_TO_PAY
+
+ def pay(self, value=None, paid_date=None):
+ if self.group.get_thirdparty() is None:
+ raise PaymentError("You must have a thirdparty to quit "
+ "the payment")
+
+ self.paid_value = value and value or self.value
+ self.paid_date = paid_date and paid_date or datetime.now()
+ self.status = self.STATUS_PAID
+
+ def cancel(self):
+ if self.status == self.STATUS_CANCELLED:
+ raise PaymentError("This payment is already cancelled")
+
+ self.status = self.STATUS_CANCELLED
+
+
+class PaymentMethod(Domain):
+ description = StringCol()
+
+
+class Till(Domain):
+ STATUS_PENDING, STATUS_OPEN, STATUS_CLOSED = range(3)
+
+ status = IntCol(default=STATUS_PENDING)
+ balance_sent = FloatCol(default=None)
+ initial_cash_amount = FloatCol(default=0.0)
+ final_cash_amount = FloatCol(default=None)
+ opening_date = DateTimeCol(default=datetime.now())
+ closing_date = DateTimeCol(default=None)
+
+ branch = ForeignKey(Person.getAdapterClass(IBranch).__name__)
+
+ def get_balance(self):
+ """ Return the total of all "extra" payments (like cash
+ advance, till complement, ...) associated to this till
+ movimentation *plus* all the payments, which payment method is
+ money, of all the sales associated with this movimentation
+ *plus* the initial cash amount. """
+
+ from stoq.domain.sale import Sale
+
+ conn = self.get_connection()
+
+ query = AND(Sale.q.status == Sale.STATUS_CONFIRMED,
+ Sale.q.tillID == self.id)
+ result = Sale.select(query, connection=conn)
+ payments = []
+ money_payment_method = sysparam(conn).MONEY_PAYMENT_METHOD
+ for sale in result:
+ sale_pg_facet = IPaymentGroup(sale)
+ assert sale_pg_facet, ("The sale associated to this "
+ "till movimentation don't have "
+ "a PaymentGroup facet.")
+ payments.extend([p for p in sale_pg_facet.get_items()
+ if p.method == money_payment_method])
+ pg_facet = IPaymentGroup(self, connection=conn)
+ if pg_facet:
+ payments.extend(pg_facet.get_items())
+
+ total = reduce(operator.add, [p.value for p in payments], 0.0)
+ return total + self.initial_cash_amount
+
+ def open_till(self, opening_date=datetime.now(), initial_cash_amount=0.0):
+ if not initial_cash_amount:
+ last_till = get_last_till_movimentation(self.get_connection())
+ if last_till:
+ self.initial_cash_amount = last_till.final_cash_amount
+ self.opening_date = opening_date
+ self.status = self.STATUS_OPEN
+
+ def close_till(self, balance_to_send=0.0, closing_date=datetime.now()):
+ if self.status != Till.STATUS_OPEN:
+ raise ValueError("This till is already closed. Open a new till "
+ "before close it.")
+
+ from stoq.domain.sale import Sale
+
+ conn = self.get_connection()
+ sales = Sale.selectBy(till=self, connection=conn)
+
+ money_payment_method = sysparam(conn).MONEY_PAYMENT_METHOD
+ for sale in sales:
+ for payment in IPaymentGroup(sale).get_items():
+ if payment.method is money_payment_method:
+ payment.status = Payment.STATUS_REVIEWING
+ else:
+ payment.status = Payment.STATUS_TO_PAY
+
+ current_balance = self.get_balance()
+ if balance_to_send and balance_to_send > current_balance:
+ raise ValueError("The cash amount that you want to send is "
+ "greater than the current balance.")
+ self.status = self.STATUS_CLOSED
+ self.closing_date = closing_date
+ self.final_cash_amount = current_balance - balance_to_send
+ self.balance_sent = balance_to_send
+
+
+#
+# Adapters
+#
+
+class PaymentAdaptToInPayment(ModelAdapter):
+
+ __implements__ = IInPayment
+
+ def receive(self):
+ payment = self.get_adapted()
+ if not payment.is_to_pay():
+ raise ValueError("This payment is already received.")
+ payment.pay()
+
+Payment.registerFacet(PaymentAdaptToInPayment)
+
+
+class PaymentAdaptToOutPayment(ModelAdapter):
+
+ __implements__ = IOutPayment
+
+ def pay(self):
+ payment = self.get_adapted()
+ if not payment.is_to_pay():
+ raise ValueError("This payment is already paid.")
+ payment.pay()
+
+Payment.registerFacet(PaymentAdaptToOutPayment)
+
+
+class AbstractPaymentGroup(InheritableModelAdapter):
+ STATUS_PREVIEW, STATUS_OPEN, STATUS_CLOSED, STATUS_CANCELLED = range(4)
+
+ __implements__ = IPaymentGroup, IContainer
+
+ status = IntCol(default=STATUS_OPEN)
+ open_date = DateTimeCol(default=datetime.now())
+ close_date = DateTimeCol(default=None)
+ notes = StringCol(default='')
+ thirdparty = ForeignKey('Person')
+
+
+ def set_thirdparty(self, person):
+ if not isinstance(person, Person):
+ raise TypeError("A Person object is required for set_thirdparty, "
+ "got %s instead." % type(person))
+ self.thirdparty = person
+
+ def get_thirdparty(self):
+ return self.thirdparty
+
+ def get_balance(self):
+ values = [s.value for s in self.get_items()]
+ return reduce(operator.add, values, 0.0)
+
+ def add_debit(self, value, reason, category, date=None):
+ payment = self.create_payment(value, reason, category, date)
+
+ return payment.addFacet(IOutPayment)
+
+ def add_credit(self, value, reason, category, date=None):
+ payment = self.create_payment(value, reason, category, date)
+
+ return payment.addFacet(IInPayment)
+
+ #
+ # Helper methods
+ #
+
+ def create_payment(self, value, reason, category, date=None):
+ date = date or datetime.now()
+ payment = Payment(due_date=date, value=value, description=reason,
+ category=category, group=self)
+ self.add_item(payment)
+
+ return payment
+
+ #
+ # IPaymentGroup implementation
+ #
+
+ def add_item(self, payment):
+ payment.group = self
+
+ def remove_item(self, payment):
+ if not isinstance(payment, Payment):
+ raise TypeError("A Payment object is required for remove_item, "
+ "got %s instead." % type(payment))
+
+ Payment.delete(payment.id, connection=self.get_connection())
+
+ def get_items(self):
+ result = Payment.selectBy(group=self,
+ connection=self.get_connection())
+ return list(result)
+
+
+class TillAdaptToPaymentGroup(AbstractPaymentGroup):
+ __implements__ = IPaymentGroup
+
+ def add_complement(self, value, reason, category, date=None):
+ # TODO: implement this method
+ pass
+
+ def get_cash_advance(self, value, reason, category, employee, date=None):
+ # TODO: implement this method
+ pass
+
+ def get_cancel_payment(self, payment):
+ # TODO: implement this method
+ pass
+
+Till.registerFacet(TillAdaptToPaymentGroup)
+
+#
+# Functions
+#
+
+def get_current_till_movimentation(conn):
+ result = Till.select(Till.q.status == Till.STATUS_OPEN, connection=conn)
+ if result.count() > 1:
+ raise TillError("You should have only one Till opened. Got %d "
+ "instead." % result.count())
+ elif result.count() == 0:
+ return None
+
+ return result[0]
+
+
+def get_last_till_movimentation(conn):
+ """ The last till movimentation is used to get a initial cash amount
+ to a new till movimentation that will be created, this value is based
+ on the final_cash_amount attribute of the last till movimentation """
+
+ query = AND(Till.q.status == Till.STATUS_CLOSED,
+ Till.q.branchID == sysparam(conn).CURRENT_BRANCH.id)
+ result = Till.select(query, connection=conn)
+ return result.count() and result[-1] or None
Modified: stoq/trunk/stoq/domain/sale.py
==============================================================================
--- stoq/trunk/stoq/domain/sale.py (original)
+++ stoq/trunk/stoq/domain/sale.py Mon Sep 5 10:21:49 2005
@@ -21,6 +21,7 @@
## USA.
##
## Author(s): Evandro Vale Miquelito <evandro at async.com.br>
+## Henrique Romano <henrique at async.com.br>
##
"""
stoq/domain/sale.py:
@@ -28,18 +29,24 @@
Sale object and related objects implementation.
"""
-from sqlobject import ForeignKey
+import gettext
+
+from datetime import datetime
+
from twisted.python.components import implements
+from sqlobject import StringCol, DateTimeCol, ForeignKey, IntCol, FloatCol
from stoq.domain.base import Domain
from stoq.domain.interfaces import IContainer, ISellable, IClient
from stoq.domain.person import Person
from stoq.lib.runtime import get_connection
from stoq.domain.sellable import AbstractSellableItem
+from stoq.domain.payment import AbstractPaymentGroup
__connection__ = get_connection()
+_ = gettext.gettext
#
# Base Domain Classes
@@ -64,7 +71,29 @@
if not client:
raise TypeError("%s cannot be adapted to IClient." % person)
self.client = client
-
+ (STATUS_OPENED,
+ STATUS_CONFIRMED,
+ STATUS_CLOSED,
+ STATUS_CANCELLED,
+ STATUS_REVIEWING) = range(5)
+
+ statuses_name = {STATUS_OPENED: _("Opened"),
+ STATUS_CONFIRMED: _("Confirmed"),
+ STATUS_CLOSED: _("Closed"),
+ STATUS_CANCELLED: _("Cancelled"),
+ STATUS_REVIEWING: _("Reviewing")}
+
+ code = StringCol(default=None)
+ open_date = DateTimeCol(default=datetime.today())
+ close_date = DateTimeCol(default=None)
+ client = ForeignKey('PersonAdaptToClient')
+ status = IntCol(default=STATUS_OPENED)
+ total = FloatCol(default=0.0)
+ till = ForeignKey('Till')
+
+ def get_status_name(self):
+ return self.statuses_name[self.status]
+
#
# IContainer methods
#
@@ -84,3 +113,15 @@
conn = self.get_connection()
table = type(item)
table.delete(item.id, connection=conn)
+
+#
+# Adapters
+#
+
+
+class SaleAdaptToPaymentGroup(AbstractPaymentGroup):
+ pass
+
+Sale.registerFacet(SaleAdaptToPaymentGroup)
+
+
Modified: stoq/trunk/stoq/domain/tables.py
==============================================================================
--- stoq/trunk/stoq/domain/tables.py (original)
+++ stoq/trunk/stoq/domain/tables.py Mon Sep 5 10:21:49 2005
@@ -69,8 +69,16 @@
"PersonAdaptToBranch",
"PersonAdaptToSalesPerson",
)),
+ ('stoq.domain.payment', ("AbstractPaymentGroup",
+ "PaymentMethod",
+ "Payment",
+ "Till",
+ "PaymentAdaptToInPayment",
+ "PaymentAdaptToOutPayment",
+ "TillAdaptToPaymentGroup",
+ )),
('stoq.domain.sale', ("Sale",
- )),
+ "SaleAdaptToPaymentGroup")),
('stoq.domain.sellable', ("AbstractSellableCategory",
"BaseSellableCategory",
"SellableCategory",
Modified: stoq/trunk/stoq/examples/createall.py
==============================================================================
--- stoq/trunk/stoq/examples/createall.py (original)
+++ stoq/trunk/stoq/examples/createall.py Mon Sep 5 10:21:49 2005
@@ -30,13 +30,14 @@
from stoq.examples.person import create_persons
from stoq.examples.product import create_products
from stoq.examples.service import create_services
-
+from stoq.examples.sale import create_sales
if __name__ == "__main__":
print 'Creating example database...'
create_persons()
create_products()
create_services()
+ create_sales()
print '-'*40
print 'done.'
Added: stoq/trunk/stoq/examples/sale.py
==============================================================================
--- (empty file)
+++ stoq/trunk/stoq/examples/sale.py Mon Sep 5 10:21:49 2005
@@ -0,0 +1,134 @@
+# -*- Mode: Python; coding: iso-8859-1 -*-
+# vi:si:et:sw=4:sts=4:ts=4
+
+##
+## Copyright (C) 2005 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 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 General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+## USA.
+##
+## Author(s): Henrique Romano <henrique at async.com.br>
+##
+"""
+stoq/examples/sale.py
+
+ Create a simple sale to an example database.
+"""
+
+import gettext
+import sys
+from datetime import datetime, timedelta
+
+from stoqlib.exceptions import SellError
+
+from stoq.lib.runtime import new_transaction
+from stoq.domain.payment import get_current_till_movimentation
+from stoq.domain.payment import Payment, Till
+from stoq.domain.sale import Sale
+from stoq.domain.product import Product
+from stoq.domain.interfaces import ISellable, IClient, IPaymentGroup
+from stoq.domain.person import Person
+from stoq.lib.parameters import sysparam
+
+_ = gettext.gettext
+
+# Number of installments for the sale
+DEFAULT_PAYMENTS_NUMBER = 4
+
+# Interval between payments (in days)
+DEFAULT_PAYMENTS_INTERVAL = 30
+
+# Number of sales to be created
+DEFAULT_SALE_NUMBER = 4
+
+def get_till(conn):
+ till = get_current_till_movimentation(conn)
+ if till is None:
+ till = Till(connection=conn,
+ branch=sysparam(conn).CURRENT_BRANCH)
+ till.open_till()
+
+ return till
+
+def get_clients(conn):
+ client_table = Person.getAdapterClass(IClient)
+ result = client_table.select(connection=conn)
+ if result.count() <= 0:
+ raise SellError("You must have clients to create a sale!")
+ return list(result)
+
+def get_all_products(conn):
+ result = Product.select(connection=conn)
+ if result.count() <= 0:
+ raise SellError("You have nothing to sale!")
+ sys.exit()
+ return list(result)
+
+#
+# Main
+#
+
+def create_sales():
+ conn = new_transaction()
+ print "Creating Sale... ",
+
+ till = get_till(conn)
+
+ clients = get_clients(conn)
+ if not len(clients) >= DEFAULT_SALE_NUMBER:
+ raise SellError("You don't have clients to create all the sales.")
+
+ product_list = get_all_products(conn)
+ if not len(product_list) >= DEFAULT_SALE_NUMBER:
+ raise SellError("You don't have products to create all the sales.")
+
+ payment_method = sysparam(conn).MONEY_PAYMENT_METHOD
+
+ for i in range(DEFAULT_SALE_NUMBER):
+ #
+ # Setting up the items
+ #
+ sale = Sale(connection=conn, till=till, client=clients[i],
+ code='#%03d' % (i + 1))
+ sellable_facet = ISellable(product_list[i], connection=conn)
+ sellable_facet.add_sellable_item(sale=sale, quantity=1,
+ base_price=sellable_facet.price,
+ price=sellable_facet.price)
+
+ sale.total = sellable_facet.price
+
+ #
+ # Setting up the payments
+ #
+ pg_facet = sale.addFacet(IPaymentGroup, connection=conn,
+ thirdparty=clients[i].get_adapted())
+ each_payment = sale.total / DEFAULT_PAYMENTS_NUMBER
+ due_date = datetime.now()
+ for i in range(DEFAULT_PAYMENTS_NUMBER):
+ payment = Payment(due_date=due_date, value=each_payment,
+ connection=conn,method=payment_method,
+ group=pg_facet)
+ pg_facet.add_item(payment)
+ due_date += timedelta(days=DEFAULT_PAYMENTS_INTERVAL)
+
+ conn.commit()
+
+ print "done."
+
+
+if __name__ == '__main__':
+ create_sales()
+
Added: stoq/trunk/stoq/gui/editors/glade/TillClosing.glade
==============================================================================
--- (empty file)
+++ stoq/trunk/stoq/gui/editors/glade/TillClosing.glade Mon Sep 5 10:21:49 2005
@@ -0,0 +1,116 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://gazpacho.sicem.biz/gazpacho-0.1.dtd">
+<glade-interface>
+ <widget class="GtkWindow" id="TillClosing">
+ <property name="default_height">250</property>
+ <property name="default_width">440</property>
+ <property name="title" context="yes" translatable="yes">Till Closing</property>
+ <child>
+ <widget class="GtkTable" id="table1">
+ <property name="column_spacing">5</property>
+ <property name="row_spacing">5</property>
+ <property name="visible">True</property>
+ <child>
+ <placeholder/>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label1">
+ <property name="label" context="yes" translatable="yes">Closing Date:</property>
+ <property name="visible">True</property>
+ <property name="xalign">1.0</property>
+ </widget>
+ <packing>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label2">
+ <property name="label" context="yes" translatable="yes">Balance To Send:</property>
+ <property name="visible">True</property>
+ <property name="xalign">1.0</property>
+ </widget>
+ <packing>
+ <property name="bottom_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="kiwi+ui+widgets+entry+Entry" id="balance_to_send">
+ <property name="data_type">float</property>
+ <property name="model_attribute">balance_sent</property>
+ <property name="width_chars">11</property>
+ <property name="xalign">1.0</property>
+ </widget>
+ <packing>
+ <property name="bottom_attach">2</property>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label3">
+ <property name="label" context="yes" translatable="yes">Final Balance:</property>
+ <property name="visible">True</property>
+ <property name="xalign">1.0</property>
+ </widget>
+ <packing>
+ <property name="bottom_attach">2</property>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="kiwi+ui+widgets+entry+Entry" id="final_cash_amount">
+ <property name="data_type">float</property>
+ <property name="model_attribute">final_cash_amount</property>
+ <property name="width_chars">11</property>
+ <property name="xalign">1.0</property>
+ </widget>
+ <packing>
+ <property name="bottom_attach">2</property>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="kiwi+ui+widgets+entry+Entry" id="closing_date">
+ <property name="data_type">date</property>
+ <property name="is_focus">True</property>
+ <property name="model_attribute">closing_date</property>
+ <property name="width_chars">10</property>
+ <property name="xalign">1.0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
Added: stoq/trunk/stoq/gui/editors/glade/TillOpening.glade
==============================================================================
--- (empty file)
+++ stoq/trunk/stoq/gui/editors/glade/TillOpening.glade Mon Sep 5 10:21:49 2005
@@ -0,0 +1,71 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://gazpacho.sicem.biz/gazpacho-0.1.dtd">
+<glade-interface>
+ <widget class="GtkWindow" id="TillOpening">
+ <property name="default_height">250</property>
+ <property name="default_width">440</property>
+ <property name="title" context="yes" translatable="yes">Till Opening</property>
+ <child>
+ <widget class="GtkTable" id="table1">
+ <property name="column_spacing">5</property>
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkLabel" id="label1">
+ <property name="label" context="yes" translatable="yes"> Date:</property>
+ <property name="visible">True</property>
+ </widget>
+ <packing>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label2">
+ <property name="justify">right</property>
+ <property name="label" context="yes" translatable="yes"> Initial Cash Amount:</property>
+ <property name="visible">True</property>
+ <property name="xalign">1.0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="kiwi+ui+widgets+entry+Entry" id="open_date">
+ <property name="data_type">date</property>
+ <property name="has_focus">True</property>
+ <property name="is_focus">True</property>
+ <property name="mandatory">True</property>
+ <property name="model_attribute">opening_date</property>
+ <property name="width_chars">10</property>
+ <property name="xalign">1.0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="kiwi+ui+widgets+entry+Entry" id="initial_cash_amount">
+ <property name="data_type">float</property>
+ <property name="mandatory">True</property>
+ <property name="model_attribute">initial_cash_amount</property>
+ <property name="width_chars">12</property>
+ <property name="xalign">1.0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
Added: stoq/trunk/stoq/gui/editors/till.py
==============================================================================
--- (empty file)
+++ stoq/trunk/stoq/gui/editors/till.py Mon Sep 5 10:21:49 2005
@@ -0,0 +1,120 @@
+# -*- Mode: Python; coding: iso-8859-1 -*-
+# vi:si:et:sw=4:sts=4:ts=4
+
+##
+## Copyright (C) 2005 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 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 General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+## USA.
+##
+## Author(s): Henrique Romano <henrique at async.com.br>
+##
+"""
+stoq/gui/editors:
+
+ Editors implementation for open/close operation on till movimentation.
+"""
+
+import gettext
+
+from stoqlib.gui.editors import BaseEditor
+from kiwi.datatypes import ValidationError
+
+from stoq.domain.payment import Till
+
+_ = gettext.gettext
+
+class TillOpeningEditor(BaseEditor):
+ gladefile = 'TillOpening'
+ widgets = ('open_date',
+ 'initial_cash_amount')
+ model_type = Till
+ title = _('Till Opening')
+
+ def __init__(self, conn, model):
+ BaseEditor.__init__(self, conn, model)
+
+ def _setup_widgets(self):
+ self.initial_cash_amount.set_data_format('%.2f')
+
+ #
+ # BaseEditor hooks
+ #
+
+ def setup_proxies(self):
+ self.model.open_till()
+ self._setup_widgets()
+ self.add_proxy(self.model, self.widgets)
+
+
+class TillClosingEditor(BaseEditor):
+ gladefile = 'TillClosing'
+ widgets = ('closing_date',
+ 'final_cash_amount',
+ 'balance_to_send')
+ model_type = Till
+ title = _('Till Closing')
+
+ def __init__(self, conn, model):
+ BaseEditor.__init__(self, conn, model)
+ self.total_balance = model.get_balance()
+
+ def _setup_widgets(self):
+ for widget in (self.balance_to_send, self.final_cash_amount):
+ widget.set_data_format('%.2f')
+
+ def update_final_cash_amount(self):
+ balance_to_send = self.model.balance_sent or 0.0
+ self.model.final_cash_amount = self.total_balance - balance_to_send
+ self.proxy.update('final_cash_amount')
+
+ def update_balance_to_send(self):
+ final_cash_amount = self.model.final_cash_amount or 0.0
+ self.model.balance_sent = self.total_balance - final_cash_amount
+ self.proxy.update('balance_sent')
+
+ #
+ # BaseEditor hooks
+ #
+
+ def setup_proxies(self):
+ self.model.close_till()
+ self.final_cash = self.model.final_cash_amount
+ self._setup_widgets()
+ self.proxy = self.add_proxy(self.model, self.widgets)
+
+ #
+ # Kiwi handlers
+ #
+
+ def after_final_cash_amount__validate(self, widget, value):
+ if value <= self.final_cash:
+ return
+ return ValidationError(_("You can not specifiy a final"
+ " cash amount greater than the "
+ "calculated value."))
+
+ def after_balance_to_send__changed(self, *args):
+ self.handler_block(self.final_cash_amount, 'changed')
+ self.update_final_cash_amount()
+ self.handler_unblock(self.final_cash_amount, 'changed')
+
+ def after_final_cash_amount__changed(self, *args):
+ self.handler_block(self.balance_to_send, 'changed')
+ self.update_balance_to_send()
+ self.handler_unblock(self.balance_to_send, 'changed')
+
+
Modified: stoq/trunk/stoq/gui/pos/pos.py
==============================================================================
--- stoq/trunk/stoq/gui/pos/pos.py (original)
+++ stoq/trunk/stoq/gui/pos/pos.py Mon Sep 5 10:21:49 2005
@@ -40,14 +40,15 @@
from stoqlib.gui.dialogs import notify_dialog
from stoq.gui.application import AppWindow
-from stoq.lib.runtime import get_current_user, new_transaction
+from stoq.lib.runtime import new_transaction
from stoq.lib.validators import format_quantity
from stoq.lib.parameters import sysparam
from stoq.domain.sellable import AbstractSellable, get_formatted_price
from stoq.domain.sale import Sale
-from stoq.domain.product import ProductSellableItem
-from stoq.domain.interfaces import ISellable, IClient
from stoq.domain.service import ServiceSellableItem
+from stoq.domain.product import ProductSellableItem
+from stoq.domain.payment import get_current_till_movimentation
+from stoq.domain.interfaces import ISellable
from stoq.gui.editors.product import ProductEditor, ProductItemEditor
from stoq.gui.editors.delivery import DeliveryEditor
from stoq.gui.editors.service import ServiceEditor
@@ -84,6 +85,12 @@
def __init__(self, app):
AppWindow.__init__(self, app)
self.conn = new_transaction()
+ if not get_current_till_movimentation(self.conn):
+ notify_dialog(_("You need to open the till before start doing "
+ "sales."),
+ _("Error"))
+ self.app.shutdown()
+
self._setup_slaves()
self._setup_signals()
self._setup_proxies()
@@ -181,7 +188,9 @@
self.order_list.select_instance(self.order_list[0])
def reset_order(self):
- self.sale = Sale(connection=self.conn, client=None)
+ self.sale = Sale(connection=self.conn,
+ till=get_current_till_movimentation(self.conn),
+ client=None)
self.person_proxy.new_model(None, relax_type=True)
self.product_proxy.new_model(None, relax_type=True)
items = self.order_list[:]
Added: stoq/trunk/stoq/gui/till/__init__.py
==============================================================================
Added: stoq/trunk/stoq/gui/till/app.py
==============================================================================
--- (empty file)
+++ stoq/trunk/stoq/gui/till/app.py Mon Sep 5 10:21:49 2005
@@ -0,0 +1,37 @@
+# -*- Mode: Python; coding: iso-8859-1 -*-
+# vi:si:et:sw=4:sts=4:ts=4
+
+##
+## Copyright (C) 2005 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 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 General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+## USA.
+##
+## Author(s): Henrique Romano <henrique at async.com.br>
+##
+"""
+stoq/gui/till/app.py:
+
+ Main callsite for Till application.
+"""
+
+from stoq.gui.till.till import TillApp
+from stoq.gui.application import App
+
+def main(config):
+ app = App(TillApp, config)
+ app.run()
+
Added: stoq/trunk/stoq/gui/till/glade/till.glade
==============================================================================
--- (empty file)
+++ stoq/trunk/stoq/gui/till/glade/till.glade Mon Sep 5 10:21:49 2005
@@ -0,0 +1,284 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://gazpacho.sicem.biz/gazpacho-0.1.dtd">
+<glade-interface>
+ <object class="GtkUIManager" id="uimanager">
+ <child>
+ <object class="GtkActionGroup" id="DefaultActions">
+ <child>
+ <object class="GtkAction" id="ChangeUser">
+ <property name="name">ChangeUser</property>
+ <property name="label" translatable="yes">Change User</property>
+ <property name="stock_id">gtk-refresh</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="ClearCookie">
+ <property name="name">ClearCookie</property>
+ <property name="label" translatable="yes">Clear Cookie</property>
+ <property name="stock_id">gtk-clear</property>
+ <signal handler="_clear_cookie" name="activate"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="Copy">
+ <property name="name">Copy</property>
+ <property name="tooltip">Copy selected object into the clipboard</property>
+ <property name="stock_id">gtk-copy</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="CurrentTill">
+ <property name="name">CurrentTill</property>
+ <property name="label" translatable="yes">Current Till</property>
+ <property name="stock_id">gtk-justify-fill</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="Cut">
+ <property name="name">Cut</property>
+ <property name="tooltip">Cut selected object into the clipboard</property>
+ <property name="stock_id">gtk-cut</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="EditMenu">
+ <property name="name">EditMenu</property>
+ <property name="label" translatable="yes">_Edit</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="FileMenu">
+ <property name="name">FileMenu</property>
+ <property name="label" translatable="yes">_File</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="HelpAbout">
+ <property name="name">HelpAbout</property>
+ <property name="label" translatable="yes">About</property>
+ <property name="stock_id">gtk-about</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="HelpMenu">
+ <property name="name">HelpMenu</property>
+ <property name="label" translatable="yes">Help</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="New">
+ <property name="name">New</property>
+ <property name="tooltip">Create a new file</property>
+ <property name="stock_id">gtk-new</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="Open">
+ <property name="name">Open</property>
+ <property name="tooltip">Open a file</property>
+ <property name="stock_id">gtk-open</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="Paste">
+ <property name="name">Paste</property>
+ <property name="tooltip">Paste object from the Clipboard</property>
+ <property name="stock_id">gtk-paste</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="Quit">
+ <property name="name">Quit</property>
+ <property name="tooltip">Quit the program</property>
+ <property name="stock_id">gtk-quit</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="Save">
+ <property name="name">Save</property>
+ <property name="tooltip">Save a file</property>
+ <property name="stock_id">gtk-save</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="SaveAs">
+ <property name="name">SaveAs</property>
+ <property name="tooltip">Save with a different name</property>
+ <property name="stock_id">gtk-save-as</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="StoreCookie">
+ <property name="name">StoreCookie</property>
+ <property name="label" translatable="yes">Store Cookie</property>
+ <property name="stock_id">gtk-save</property>
+ <signal handler="_store_cookie" name="activate"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="TillClose">
+ <property name="name">TillClose</property>
+ <property name="label" translatable="yes">Close Till</property>
+ <property name="stock_id">gtk-close</property>
+ <signal handler="close_till" name="activate"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="TillMenu">
+ <property name="name">TillMenu</property>
+ <property name="label" translatable="yes">Till</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="TillOpen">
+ <property name="name">TillOpen</property>
+ <property name="label" translatable="yes">Open Till</property>
+ <property name="stock_id">gtk-open</property>
+ <signal handler="open_till" name="activate"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="quit_action">
+ <property name="name">quit_action</property>
+ <property name="tooltip">Quit the program</property>
+ <property name="stock_id">gtk-quit</property>
+ <signal handler="_on_quit_action__clicked" name="activate"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkAction" id="users_menu">
+ <property name="name">users_menu</property>
+ <property name="label" translatable="yes">User</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <ui id="initial-state"><![CDATA[<ui><menubar action="menubar" name="menubar">
+
+
+<menu action="TillMenu" name="TillMenu"><menuitem action="TillOpen" name="TillOpen"/><menuitem action="TillClose" name="TillClose"/><separator/><menuitem action="quit_action" name="quit_action"/></menu><menu action="users_menu" name="users_menu"><menuitem action="StoreCookie" name="StoreCookie"/><menuitem action="ClearCookie" name="ClearCookie"/><separator/><menuitem action="ChangeUser" name="ChangeUser"/></menu><menu action="HelpMenu" name="HelpMenu"><menuitem action="HelpAbout" name="HelpAbout"/></menu></menubar><toolbar action="toolbar1" name="toolbar1">
+
+
+
+
+
+
+
+<toolitem action="TillOpen" name="TillOpen"/><toolitem action="TillClose" name="TillClose"/><separator/><toolitem action="CurrentTill" name="CurrentTill"/></toolbar></ui>]]></ui>
+ </object>
+ <widget class="GtkWindow" id="till">
+ <property name="height_request">570</property>
+ <property name="title" context="yes" translatable="yes">STOQ - Till Application</property>
+ <property name="width_request">800</property>
+ <child>
+ <widget class="GtkVBox" id="vbox3">
+ <property name="visible">True</property>
+ <child>
+ <widget constructor="initial-state" class="GtkMenuBar" id="menubar">
+ <property name="visible">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget constructor="initial-state" class="GtkToolbar" id="toolbar1">
+ <property name="visible">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="vbox4">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkEventBox" id="searchbar_holder">
+ <property name="visible">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEventBox" id="klist_holder">
+ <property name="visible">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkTable" id="table1">
+ <property name="border_width">5</property>
+ <property name="column_spacing">5</property>
+ <property name="row_spacing">5</property>
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkButton" id="confirm_order_button">
+ <property name="label">Confirm Order</property>
+ <property name="use_stock">True</property>
+ <property name="visible">True</property>
+ </widget>
+ <packing>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="x_options"><flags 0 of type GtkAttachOptions></property>
+ <property name="y_options"><flags 0 of type GtkAttachOptions></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label2">
+ <property name="label" context="yes" translatable="yes"><span size='x-large'><b>Total: </b></span></property>
+ <property name="use_markup">True</property>
+ <property name="visible">True</property>
+ <property name="xalign">1.0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="kiwi+ui+widgets+label+Label" id="total_label">
+ <property name="data_type">str</property>
+ <property name="label" context="yes" translatable="yes">0,00</property>
+ <property name="xalign">1.0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
Added: stoq/trunk/stoq/gui/till/till.py
==============================================================================
--- (empty file)
+++ stoq/trunk/stoq/gui/till/till.py Mon Sep 5 10:21:49 2005
@@ -0,0 +1,187 @@
+# -*- Mode: Python; coding: iso-8859-1 -*-
+# vi:si:et:sw=4:sts=4:ts=4
+
+##
+## Copyright (C) 2005 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 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 General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+## USA.
+##
+## Author(s): Henrique Romano <henrique at async.com.br>
+##
+"""
+stoq/gui/till/till.py:
+ Implementation of till application.
+"""
+
+import gettext
+from datetime import date
+import gtk
+
+from sqlobject.sqlbuilder import AND
+from kiwi.ui.widgets.list import Column
+from stoqlib.gui.search import BaseListSlave, SearchBar
+from stoqlib.gui.columns import ForeignKeyColumn
+from stoqlib.exceptions import TillError
+from stoqlib.database import rollback_and_begin
+
+from stoq.gui.application import AppWindow
+from stoq.domain.sale import Sale
+from stoq.domain.person import Person, PersonAdaptToClient
+from stoq.domain.payment import get_current_till_movimentation, Till
+from stoq.domain.sellable import get_formatted_price
+from stoq.lib.runtime import new_transaction
+from stoq.lib.parameters import sysparam
+from stoq.gui.editors.till import TillOpeningEditor, TillClosingEditor
+
+_ = gettext.gettext
+
+class TillApp(AppWindow):
+ gladefile = 'till'
+ widgets = ('searchbar_holder',
+ 'klist_holder',
+ 'total_label',
+ 'confirm_order_button',
+ 'TillMenu',
+ 'TillOpen',
+ 'TillClose',
+ 'CurrentTill',
+ 'quit_action')
+
+ def __init__(self, app):
+ AppWindow.__init__(self, app)
+ self.conn = new_transaction()
+ self._setup_widgets()
+ self._setup_slaves()
+
+ def _setup_widgets(self):
+ self._update_widgets()
+ self.total_label.set_size('x-large')
+ self.total_label.set_bold(True)
+ self.total_label.set_text(get_formatted_price(0.00))
+ # TODO: Waiting for bug #1862
+ self.confirm_order_button.set_sensitive(False)
+ # TODO: Implement Current Till movimentation dialog
+ self.CurrentTill.set_sensitive(False)
+
+ def _update_widgets(self):
+ has_till = get_current_till_movimentation(self.conn) is not None
+ self.TillClose.set_sensitive(has_till)
+ self.TillOpen.set_sensitive(not has_till)
+
+ def _setup_slaves(self):
+ list_slave = BaseListSlave(columns=self.get_columns())
+ self.attach_slave('klist_holder', list_slave)
+ self.sale_list = list_slave.klist
+
+ self.searchbar = SearchBar(self, Sale, self.get_columns(),
+ search_lbl_text=_('Find Sales'))
+ self.searchbar.search_items()
+ self.attach_slave('searchbar_holder', self.searchbar)
+
+ #
+ # BaseListSlave hooks
+ #
+
+ def get_columns(self):
+ return [Column('code', title=_('Code'), width=100, data_type=int,
+ sorted=True),
+ Column('open_date', title=_('Date'), width=120,
+ data_type=date, justify=gtk.JUSTIFY_RIGHT),
+ ForeignKeyColumn(Person, 'name', title=_('Client'), expand=True,
+ data_type=str, obj_field='client._original'),
+ Column('status_name', title=_('Status'), width=120,
+ data_type=str, justify=gtk.JUSTIFY_CENTER),
+ Column('total', title=_('Total'), width=150, data_type=float,
+ justify=gtk.JUSTIFY_RIGHT, format='%.2f')]
+
+ def get_extra_query(self):
+ q1 = Sale.q.clientID == PersonAdaptToClient.q.id
+ q2 = PersonAdaptToClient.q._originalID == Person.q.id
+ q3 = Sale.q.status == Sale.STATUS_OPENED
+ return AND(q1, q2, q3)
+
+ def update_klist(self, items=[]):
+ self.sale_list.clear()
+ total_value = 0.00
+
+ for item in items:
+ self.sale_list.add_instance(item)
+ total_value += item.total
+
+ self.total_label.set_text(get_formatted_price(total_value))
+
+ #
+ # Kiwi callbacks
+ #
+
+ def open_till(self, *args):
+ rollback_and_begin(self.conn)
+
+ if get_current_till_movimentation(self.conn) is not None:
+ raise TillError("You already have a till movimentation opened. "
+ "Close the current Till and open another one.")
+
+ # Trying get the movimentation created by the last till
+ # movimentation closed. This movimentation has all the sales
+ # not confirmed in the last movimentation.
+ result = Till.select(Till.q.status == Till.STATUS_PENDING,
+ connection=self.conn)
+ if result.count() == 0:
+ till = Till(connection=self.conn,
+ branch=sysparam(self.conn).CURRENT_BRANCH)
+ elif result.count() == 1:
+ till = result[0]
+ else:
+ raise TillError("You have more than one till operation "
+ "pending.")
+
+ if self.run_dialog(TillOpeningEditor, self.conn, till):
+ self.conn.commit()
+ self._update_widgets()
+ return
+ rollback_and_begin(self.conn)
+
+ def close_till(self, *args):
+ till = get_current_till_movimentation(self.conn)
+ if till is None:
+ raise ValueError("You should have a till operation opened at "
+ "this point")
+
+ if not self.run_dialog(TillClosingEditor, self.conn, till):
+ rollback_and_begin(self.conn)
+ return
+
+ self.conn.commit()
+ self._update_widgets()
+
+ opened_sales = Sale.select(Sale.q.status == Sale.STATUS_OPENED,
+ connection=self.conn)
+ if opened_sales.count() == 0:
+ return
+
+ # A new till object to "store" the sales that weren't
+ # confirmed. Note that this new till operation isn't
+ # opened yet, but it will be considered when opening a
+ # new operation
+ new_till = Till(connection=self.conn,
+ branch=sysparam(self.conn).CURRENT_BRANCH)
+ for sale in opened_sales:
+ sale.till = new_till
+
+ self.conn.commit()
+
+
Modified: stoq/trunk/stoq/lib/parameters.py
==============================================================================
--- stoq/trunk/stoq/lib/parameters.py (original)
+++ stoq/trunk/stoq/lib/parameters.py Mon Sep 5 10:21:49 2005
@@ -54,9 +54,12 @@
adding a new
SellableCategory object.
+ * MONEY_PAYMENT_METHOD(PaymentMethod): Definition of the money payment
+ method.
+
* DELIVERY_SERVICE(ServiceAdaptToSellable): The default delivery service
to the system.
-
+
>> System constants:
@@ -114,7 +117,6 @@
from stoq.domain.base import Domain
from stoq.domain.interfaces import ISupplier, IBranch, ICompany, ISellable
-from stoq.domain.interfaces import IDelivery
from stoq.lib.runtime import get_connection, new_transaction
@@ -254,6 +256,14 @@
return branch
@property
+ def MONEY_PAYMENT_METHOD(self):
+ from stoq.domain.payment import PaymentMethod
+ parameter = get_foreign_key_parameter('MONEY_PAYMENT_METHOD',
+ self.conn)
+ return PaymentMethod.get(parameter.foreign_key,
+ connection=self.conn)
+
+ @property
def DEFAULT_BASE_CATEGORY(self):
from stoq.domain.sellable import BaseSellableCategory
parameter = get_foreign_key_parameter('DEFAULT_BASE_CATEGORY',
@@ -458,6 +468,12 @@
for key, data in values:
set_schema(conn, key, data)
+def ensure_default_payment_method(conn):
+ from stoq.domain.payment import PaymentMethod
+
+ pm = PaymentMethod(description=_('Money'), connection=conn)
+ set_schema(conn, 'MONEY_PAYMENT_METHOD', 'get_default_payment_method',
+ foreign_key=pm.id)
#
@@ -476,6 +492,7 @@
ensure_current_branch(trans)
ensure_current_warehouse(trans)
ensure_city_location(trans)
+ ensure_default_payment_method(trans)
ensure_delivery_service(trans)
trans.commit()
Modified: stoq/trunk/stoq/main.py
==============================================================================
--- stoq/trunk/stoq/main.py (original)
+++ stoq/trunk/stoq/main.py Mon Sep 5 10:21:49 2005
@@ -41,7 +41,7 @@
# A list of subdirectories in stoq/gui/
for dir in ['editors', 'components', 'pos', 'search',
- 'slaves', 'templates']:
+ 'slaves', 'templates', 'till']:
path = os.path.join(module.basedir, "stoq", "gui", dir, "glade")
if os.path.exists(path) and os.path.isdir(path):
environ.add_resource("glade", path)
More information about the POS-commit
mailing list