[POS-commit] r7083 - in stoqlib/trunk: data/glade stoqlib/domain stoqlib/domain/test stoqlib/gui/dialogs stoqlib/gui/search

Johan Dahlin jdahlin at async.com.br
Fri Aug 3 14:08:40 BRT 2007


Author: jdahlin
Date: Fri Aug  3 14:08:40 2007
New Revision: 7083

Added:
   stoqlib/trunk/data/glade/SupplierDetailsDialog.glade
   stoqlib/trunk/stoqlib/gui/dialogs/supplierdetails.py
Modified:
   stoqlib/trunk/stoqlib/domain/person.py
   stoqlib/trunk/stoqlib/domain/purchase.py
   stoqlib/trunk/stoqlib/domain/test/test_person.py
   stoqlib/trunk/stoqlib/gui/search/personsearch.py

Log:
#3507: Add a supplier details dialog

Added: stoqlib/trunk/data/glade/SupplierDetailsDialog.glade
==============================================================================
--- (empty file)
+++ stoqlib/trunk/data/glade/SupplierDetailsDialog.glade	Fri Aug  3 14:08:40 2007
@@ -0,0 +1,181 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://gazpacho.sicem.biz/gazpacho-0.1.dtd">
+<glade-interface domain="stoqlib">
+    <widget class="GtkWindow" id="SupplierDetailsDialog">
+        <property name="border_width">6</property>
+        <property name="default_height">250</property>
+        <property name="default_width">440</property>
+        <property name="visible">True</property>
+        <child>
+            <widget class="GtkVBox" id="vbox1">
+                <property name="visible">True</property>
+                <child>
+                    <widget class="GtkTable" id="table1">
+                        <property name="column_spacing">6</property>
+                        <property name="n_columns">4</property>
+                        <property name="n_rows">2</property>
+                        <property name="row_spacing">6</property>
+                        <property name="visible">True</property>
+                        <child>
+                            <widget class="GtkLabel" id="label1">
+                                <property name="label" context="yes" translatable="yes">Supplier:</property>
+                                <property name="visible">True</property>
+                                <property name="xalign">1.0</property>
+                            </widget>
+                        </child>
+                        <child>
+                            <widget class="GtkLabel" id="label2">
+                                <property name="label" context="yes" translatable="yes">Last Purchase Date:</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>
+                            </packing>
+                        </child>
+                        <child>
+                            <widget class="ProxyLabel" id="supplier">
+                                <property name="data_type">unicode</property>
+                                <property name="model_attribute">name</property>
+                                <property name="visible">True</property>
+                                <property name="xalign">0.0</property>
+                            </widget>
+                            <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                            </packing>
+                        </child>
+                        <child>
+                            <widget class="ProxyLabel" id="last_purchase_date">
+                                <property name="data_type">date</property>
+                                <property name="model_attribute">last_purchase_date</property>
+                                <property name="visible">True</property>
+                                <property name="xalign">0.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>
+                            </packing>
+                        </child>
+                        <child>
+                            <widget class="GtkLabel" id="label3">
+                                <property name="label" context="yes" translatable="yes">Status:</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>
+                            </packing>
+                        </child>
+                        <child>
+                            <placeholder/>
+                            <packing>
+                                <property name="left_attach">2</property>
+                                <property name="right_attach">3</property>
+                                <property name="top_attach">1</property>
+                                <property name="bottom_attach">2</property>
+                            </packing>
+                        </child>
+                        <child>
+                            <widget class="ProxyLabel" id="status">
+                                <property name="data_type">str</property>
+                                <property name="model_attribute">status_string</property>
+                                <property name="visible">True</property>
+                                <property name="xalign">0.0</property>
+                            </widget>
+                            <packing>
+                                <property name="left_attach">3</property>
+                                <property name="right_attach">4</property>
+                            </packing>
+                        </child>
+                        <child>
+                            <widget class="GtkHBox" id="hbox1">
+                                <property name="visible">True</property>
+                                <child>
+                                    <placeholder/>
+                                </child>
+                                <child>
+                                    <placeholder/>
+                                    <packing>
+                                        <property name="position">1</property>
+                                    </packing>
+                                </child>
+                                <child>
+                                    <widget class="GtkButton" id="further_details_button">
+                                        <property name="is_focus">True</property>
+                                        <property name="label" context="yes" translatable="yes">Further Details</property>
+                                        <property name="visible">True</property>
+                                    </widget>
+                                    <packing>
+                                        <property name="expand">False</property>
+                                        <property name="position">2</property>
+                                    </packing>
+                                </child>
+                            </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>
+                            </packing>
+                        </child>
+                    </widget>
+                    <packing>
+                        <property name="expand">False</property>
+                    </packing>
+                </child>
+                <child>
+                    <widget class="GtkNotebook" id="notebook1">
+                        <property name="is_focus">True</property>
+                        <property name="visible">True</property>
+                        <child>
+                            <widget class="GtkVBox" id="purchases_vbox">
+                                <property name="visible">True</property>
+                                <child>
+                                    <widget class="ObjectList" id="purchases_list">
+                                        <property name="visible">True</property>
+                                    </widget>
+                                </child>
+                                <child>
+                                    <placeholder/>
+                                    <packing>
+                                        <property name="expand">False</property>
+                                        <property name="position">1</property>
+                                    </packing>
+                                </child>
+                            </widget>
+                            <packing>
+                                <property name="tab_label" context="yes" translatable="yes">Purchases</property>
+                            </packing>
+                        </child>
+                        <child>
+                            <widget class="ObjectList" id="product_list">
+                                <property name="visible">True</property>
+                            </widget>
+                            <packing>
+                                <property name="position">1</property>
+                                <property name="tab_label" context="yes" translatable="yes">Products</property>
+                            </packing>
+                        </child>
+                        <child>
+                            <widget class="ObjectList" id="payments_list">
+                                <property name="visible">True</property>
+                            </widget>
+                            <packing>
+                                <property name="position">2</property>
+                                <property name="tab_label" context="yes" translatable="yes">Payments</property>
+                            </packing>
+                        </child>
+                    </widget>
+                    <packing>
+                        <property name="position">1</property>
+                    </packing>
+                </child>
+            </widget>
+        </child>
+    </widget>
+</glade-interface>

Modified: stoqlib/trunk/stoqlib/domain/person.py
==============================================================================
--- stoqlib/trunk/stoqlib/domain/person.py	(original)
+++ stoqlib/trunk/stoqlib/domain/person.py	Fri Aug  3 14:08:40 2007
@@ -587,6 +587,19 @@
         query = cls.q.status == cls.STATUS_ACTIVE
         return cls.select(query, connection=conn)
 
+    def get_supplier_purchases(self):
+        """
+        @returns: a list of PurchaseOrderViews representing all purchases
+          done from this supplier.
+        """
+        from stoqlib.domain.purchase import PurchaseOrderView
+        return PurchaseOrderView.select(
+            # FIXME: should of course use id, fix this
+            #        when migrating PurchaseOrderView from views.sql
+            PurchaseOrderView.q.supplier_name == self.person.name,
+            connection=self.get_connection(),
+            orderBy=PurchaseOrderView.q.open_date)
+
 Person.registerFacet(PersonAdaptToSupplier, ISupplier)
 
 class PersonAdaptToEmployee(PersonAdapter):

Modified: stoqlib/trunk/stoqlib/domain/purchase.py
==============================================================================
--- stoqlib/trunk/stoqlib/domain/purchase.py	(original)
+++ stoqlib/trunk/stoqlib/domain/purchase.py	Fri Aug  3 14:08:40 2007
@@ -571,3 +571,6 @@
     @property
     def purchase(self):
         return PurchaseOrder.get(self.id)
+
+    def get_status_name(self):
+        return self.purchase.translate_status(self.status)

Modified: stoqlib/trunk/stoqlib/domain/test/test_person.py
==============================================================================
--- stoqlib/trunk/stoqlib/domain/test/test_person.py	(original)
+++ stoqlib/trunk/stoqlib/domain/test/test_person.py	Fri Aug  3 14:08:40 2007
@@ -55,6 +55,7 @@
                                    PersonAdaptToTransporter)
 from stoqlib.domain.product import Product
 from stoqlib.domain.profile import UserProfile
+from stoqlib.domain.purchase import PurchaseOrder
 from stoqlib.domain.sale import Sale
 from stoqlib.domain.test.domaintest import DomainTest
 from stoqlib.lib.translation import stoqlib_gettext
@@ -64,14 +65,15 @@
 
 
 class TestEmployeeRoleHistory(DomainTest):
-     def testCreate(self):
-          EmployeeRole(connection=self.trans, name='ajudante')
+    def testCreate(self):
+         EmployeeRole(connection=self.trans, name='ajudante')
+
+    def testHasRole(self):
+         role = EmployeeRole(connection=self.trans, name='role')
+         self.failIf(role.has_other_role('Role'))
+         role = EmployeeRole(connection=self.trans, name='Role')
+         self.failUnless(role.has_other_role('role'))
 
-     def testHasRole(self):
-          role = EmployeeRole(connection=self.trans, name='role')
-          self.failIf(role.has_other_role('Role'))
-          role = EmployeeRole(connection=self.trans, name='Role')
-          self.failUnless(role.has_other_role('role'))
 
 class TestEmployeeRole(DomainTest):
     def test_get_description(self):
@@ -79,6 +81,7 @@
         role.name =  'manager'
         self.assertEquals(role.name, role.get_description())
 
+
 class TestPerson(DomainTest):
 
     def testGetMainAddress(self):
@@ -365,9 +368,9 @@
     facet = PersonAdaptToSupplier
 
     def testGetActiveSuppliers(self):
-        for supplier in PersonAdaptToSupplier.get_active_suppliers(self.trans):
-            self.assertEquals(supplier.status,
-                              PersonAdaptToSupplier.STATUS_ACTIVE)
+         for supplier in PersonAdaptToSupplier.get_active_suppliers(self.trans):
+              self.assertEquals(supplier.status,
+                                PersonAdaptToSupplier.STATUS_ACTIVE)
 
     def testGetAllSuppliers(self):
         query = AND(Person.q.name ==  "test",
@@ -382,6 +385,23 @@
         suppliers = Person.select(query, connection=self.trans)
         self.assertEqual(suppliers.count(), 1)
 
+    def testGetSupplierPurchase(self):
+        supplier = self.create_supplier()
+
+        self.failIf(supplier.get_supplier_purchases())
+
+        order = self.create_receiving_order()
+        order.purchase.supplier = supplier
+        order_item = self.create_receiving_order_item(order)
+        order.purchase.status = PurchaseOrder.ORDER_PENDING
+        order.purchase.confirm()
+        order.confirm()
+        order.set_valid()
+        order.purchase.set_valid()
+
+        self.failUnless(supplier.get_supplier_purchases())
+
+
 class TestEmployee(_PersonFacetTest, DomainTest):
     facet = PersonAdaptToEmployee
 

Added: stoqlib/trunk/stoqlib/gui/dialogs/supplierdetails.py
==============================================================================
--- (empty file)
+++ stoqlib/trunk/stoqlib/gui/dialogs/supplierdetails.py	Fri Aug  3 14:08:40 2007
@@ -0,0 +1,176 @@
+# -*- coding: utf-8 -*-
+# vi:si:et:sw=4:sts=4:ts=4
+
+##
+## Copyright (C) 2006-2007 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):   Lincoln Molica                  <lincolnn at gmail.com>
+##              Ariqueli Tejada Fonseca         <ariqtf at yahoo.com.br>
+##              Evandro Vale Miquelito          <evandro at async.com.br>
+##              Johan Dahlin                    <jdahlin at async.com.br>
+##
+##
+""" Classes for supplier details """
+
+import datetime
+
+import gtk
+from kiwi.python import Settable
+from kiwi.ui.objectlist import Column, ColoredColumn
+from kiwi.datatypes import currency
+from kiwi.ui.widgets.list import SummaryLabel
+
+from stoqlib.domain.interfaces import ISupplier, IPaymentGroup
+from stoqlib.domain.purchase import PurchaseOrder
+from stoqlib.gui.editors.baseeditor import BaseEditor
+from stoqlib.gui.editors.personeditor import SupplierEditor
+from stoqlib.gui.wizards.personwizard import run_person_role_dialog
+from stoqlib.lib.translation import stoqlib_gettext
+from stoqlib.lib.defaults import payment_value_colorize
+
+
+_ = stoqlib_gettext
+
+class SupplierDetailsDialog(BaseEditor):
+    """This dialog shows some important details about suppliers like:
+        - history of purchases
+        - all products tied with purchases
+        - all payments already created
+    """
+    title = _(u"Supplier Details")
+    hide_footer = True
+    size = (780, 400)
+    model_iface = ISupplier
+    gladefile = "SupplierDetailsDialog"
+    proxy_widgets = ('supplier',
+                     'last_purchase_date',
+                     'status')
+
+    def __init__(self, conn, model):
+        BaseEditor.__init__(self, conn, model)
+        self._setup_widgets()
+
+    def _build_data(self, purchases):
+        self.payments = []
+        product_dict = {}
+        for purchase_view in purchases:
+            purchase = PurchaseOrder.get(purchase_view.id, connection=self.conn)
+            group = IPaymentGroup(purchase)
+            self.payments.extend(group.get_items())
+            for purchase_item in purchase.get_items():
+                qty = purchase_item.quantity
+                cost = purchase_item.cost
+                total_value = cost * qty
+                unit = purchase_item.sellable.get_unit_description()
+                qty_str = '%s %s' % (qty, unit)
+                product_codes = [item.code for item in product_dict.values()]
+                sellable = purchase_item.sellable
+                if not sellable.id in product_codes:
+                    desc = sellable.base_sellable_info.description
+                    obj = Settable(code=sellable.id, description=desc,
+                                   _total_qty=qty, total_value=total_value,
+                                   qty_str=qty_str, unit=unit, cost=cost)
+                    product_dict[sellable] = obj
+                else:
+                    product_dict[sellable]._total_qty += qty
+                    table = product_dict[sellable]
+                    table.qty_str = '%s %s' % (table._total_qty, table.unit)
+                    table.total_value  = table._total_qty * table.cost
+        self.products = product_dict.values()
+
+    def _setup_widgets(self):
+        self.purchases_list.set_columns(self._get_purchase_columns())
+        self.product_list.set_columns(self._get_product_columns())
+        self.payments_list.set_columns(self._get_payments_columns())
+
+        purchases = self.model.get_supplier_purchases()
+        self.purchases_list.add_list(purchases)
+
+        self._build_data(purchases)
+        self.product_list.add_list(self.products)
+        self.payments_list.add_list(self.payments)
+
+        value_format = '<b>%s</b>'
+        total_label = "<b>%s</b>" % _("Total:")
+        purchases_summary_label = SummaryLabel(klist=self.purchases_list,
+                                              column='total',
+                                              label=total_label,
+                                              value_format=value_format)
+
+        purchases_summary_label.show()
+        self.purchases_vbox.pack_start(purchases_summary_label, False)
+
+    def _get_purchase_columns(self):
+        return [Column("id", title=_("#"),
+                       data_type=int, justify=gtk.JUSTIFY_RIGHT,
+                       format='%04d', width=90, sorted=True),
+                Column("open_date", title=_("Date"), data_type=datetime.date,
+                       justify=gtk.JUSTIFY_RIGHT, width=80),
+                Column("status_name", title=_("Status"), width=80,
+                      data_type=str),
+                Column("total", title=_("Total"), justify=gtk.JUSTIFY_RIGHT,
+                       data_type=currency, width=100)]
+
+    def _get_product_columns(self):
+        return [Column("code", title=_("Code"), data_type=int,
+                       format='%04d', justify=gtk.JUSTIFY_RIGHT,
+                       width=90, sorted=True),
+                Column("description", title=_("Description"), data_type=str,
+                       expand=True, searchable=True),
+                Column("qty_str", title=_("Total Quantity"),
+                       data_type=str, width=120, justify=gtk.JUSTIFY_RIGHT),
+                Column("total_value", title=_("Total Value"), width=80,
+                       data_type=currency, justify=gtk.JUSTIFY_RIGHT,)]
+
+    def _get_payments_columns(self):
+        return [Column("id", title=_("#"),
+                       data_type=int, justify=gtk.JUSTIFY_RIGHT,
+                       format='%04d', width=50),
+                Column("method.description", title=_("Type"),
+                       data_type=str, width=90),
+                Column("description", title=_("Description"),
+                       data_type=str, searchable=True, width=190,
+                       expand=True),
+                Column("due_date", title=_("Due Date"), width=110,
+                       data_type=datetime.date, sorted=True),
+                Column("status_str", title=_("Status"), width=80,
+                       data_type=str),
+                ColoredColumn("base_value", title=_("Value"),
+                              justify=gtk.JUSTIFY_RIGHT, data_type=currency,
+                              color='red', width=100,
+                              data_func=payment_value_colorize),
+                Column("days_late", title=_("Days Late"), width=110,
+                       format_func=(lambda days_late: days_late and
+                                    str(days_late) or u""),
+                       justify=gtk.JUSTIFY_RIGHT, data_type=str)]
+
+    #
+    # BaseEditor Hooks
+    #
+
+    def setup_proxies(self):
+        self.add_proxy(self.model, self.proxy_widgets)
+
+    #
+    # Callbacks
+    #
+
+    def on_further_details_button__clicked(self, *args):
+        run_person_role_dialog(SupplierEditor, self, self.conn,
+                               self.model, visual_mode=True)
+

Modified: stoqlib/trunk/stoqlib/gui/search/personsearch.py
==============================================================================
--- stoqlib/trunk/stoqlib/gui/search/personsearch.py	(original)
+++ stoqlib/trunk/stoqlib/gui/search/personsearch.py	Fri Aug  3 14:08:40 2007
@@ -42,6 +42,7 @@
 from stoqlib.gui.base.search import SearchEditor
 from stoqlib.gui.base.dialogs import run_dialog
 from stoqlib.gui.dialogs.clientdetails import ClientDetailsDialog
+from stoqlib.gui.dialogs.supplierdetails import SupplierDetailsDialog
 from stoqlib.domain.person import (EmployeeRole,
                                    PersonAdaptToBranch, BranchView,
                                    PersonAdaptToClient, ClientView,
@@ -133,6 +134,15 @@
                        width=180),
                 Column('cnpj', _('CNPJ'), str, width=140)]
 
+    def on_details_button_clicked(self, *args):
+        selected = self.results.get_selected()
+        run_dialog(SupplierDetailsDialog, self, self.conn, selected.supplier)
+
+    def update_widgets(self, *args):
+        supplier_view = self.results.get_selected()
+        self.set_details_button_sensitive(supplier_view is not None)
+        self.set_edit_button_sensitive(supplier_view is not None)
+
     def get_editor_model(self, supplier_view):
         return supplier_view.supplier
 


More information about the POS-commit mailing list