Merge lp:~bellini666/stoqlib/closed_product into lp:~stoq-dev/stoqlib/master

Proposed by Thiago Bellini
Status: Merged
Merged at revision: 3331
Proposed branch: lp:~bellini666/stoqlib/closed_product
Merge into: lp:~stoq-dev/stoqlib/master
Diff against target: 364 lines (+206/-23)
7 files modified
external/sqlobject/viewable.py (+1/-1)
stoqlib/domain/sellable.py (+17/-0)
stoqlib/domain/test/test_sellable.py (+52/-0)
stoqlib/domain/views.py (+16/-3)
stoqlib/gui/editors/sellableeditor.py (+59/-13)
stoqlib/gui/search/productsearch.py (+49/-4)
stoqlib/reporting/product.py (+12/-2)
To merge this branch: bzr merge lp:~bellini666/stoqlib/closed_product
Reviewer Review Type Date Requested Status
Ronaldo Maia Pending
Review via email: mp+50754@code.launchpad.net

Description of the change

Opção de ter produtos inativos.
Correções para o #4304

To post a comment you must log in.
3321. By Thiago Bellini

Quick Fix: Correcting a traceback on POS app when checkout payment method was 'check' or 'bill'

3322. By Thiago Bellini

Quick fix: Hope this will fix all problems when using a payment slave.

3323. By Gabriel Gerga

Exportar vendas a vista para NF-e. r=romaia

3324. By Ronaldo Maia

Viewable select results didn't include objects created inside a transaction,
even when selecting from that transaction.

Fix a test afected by this

3325. By Ronaldo Maia

Update a few report tests pdfs

3326. By Thiago Bellini

Make the labels of the 'yesno' dialog buttons more useful.

3327. By Gabriel Gerga

Corrected values used in payments editor according freight, surcharge and discount. r=romaia

3328. By Thiago Bellini

Quick Fix: Forgot a closing ')' on sellableeditor. Sorry! :(

3329. By Ronaldo Maia

Adicionando suporte experimental para boletos bancários

- Importando Projeto Pyboleto (com algumas mudanças nosssas)
- Adicionando opção de imprimir boletos (no formato carnê) a partir dos
  detalhes de uma venda

3335. By Thiago Bellini

Removing the editor from Closed Products Search and code adjustments.

3336. By Thiago Bellini

Code corrections.

3337. By Thiago Bellini

Add tests for new methods and views.

3338. By Thiago Bellini

Code corrections.

3339. By Thiago Bellini

More code corrections.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'external/sqlobject/viewable.py'
2--- external/sqlobject/viewable.py 2011-02-28 15:29:21 +0000
3+++ external/sqlobject/viewable.py 2011-03-04 18:09:29 +0000
4@@ -149,7 +149,7 @@
5
6 setup_attributes(cls, new_attrs)
7
8- columns = new_attrs['columns']
9+ columns = new_attrs.get('columns', getattr(cls, 'columns', None))
10 if not columns:
11 return
12
13
14=== modified file 'stoqlib/domain/sellable.py'
15--- stoqlib/domain/sellable.py 2011-02-08 14:06:58 +0000
16+++ stoqlib/domain/sellable.py 2011-03-04 18:09:29 +0000
17@@ -378,6 +378,10 @@
18
19 commission = property(_get_commission, _set_commission)
20
21+ #
22+ # Accessors
23+ #
24+
25 def can_be_sold(self):
26 """Whether the sellable is available and can be sold.
27 @returns: if the item can be sold
28@@ -401,6 +405,19 @@
29 raise ValueError('This sellable is already unavailable')
30 self.status = self.STATUS_UNAVAILABLE
31
32+ def is_closed(self):
33+ """Whether the sellable is closed or not.
34+
35+ @returns: True if closed, False otherwise.
36+ """
37+ return self.status == Sellable.STATUS_CLOSED
38+
39+ def close(self):
40+ """Mark the sellable as closed"""
41+ if self.is_closed():
42+ raise ValueError('This sellable is already closed')
43+ self.status = Sellable.STATUS_CLOSED
44+
45 def cancel(self):
46 """Cancel the sellable"""
47 if self.can_be_sold():
48
49=== modified file 'stoqlib/domain/test/test_sellable.py'
50--- stoqlib/domain/test/test_sellable.py 2011-02-08 14:06:58 +0000
51+++ stoqlib/domain/test/test_sellable.py 2011-03-04 18:09:29 +0000
52@@ -29,6 +29,9 @@
53 SellableCategory)
54 from stoqlib.domain.product import Product
55 from stoqlib.domain.test.domaintest import DomainTest
56+from stoqlib.domain.views import (ProductFullStockView,
57+ ProductFullWithClosedStockView,
58+ ProductClosedStockView)
59
60
61 class TestSellableCategory(DomainTest):
62@@ -230,3 +233,52 @@
63 constant3 = self.create_sellable_tax_constant()
64 sellable.tax_constant = constant3
65 self.assertEquals(sellable.get_tax_constant(), constant3)
66+
67+ def testClose(self):
68+ results_not_closed = ProductFullStockView.select(connection=self.trans)
69+ results_with_closed = ProductFullWithClosedStockView.select(
70+ connection=self.trans)
71+ results_only_closed = ProductClosedStockView.select(
72+ connection=self.trans)
73+ # Count the already there results. ProductClosedStockView should
74+ # not have any.
75+ # obs. Using len(list(res)) instead of res.count() because of a bug
76+ # on sqlobject that returns wrong count() on that views.
77+ count_not_closed = len(list(results_not_closed))
78+ count_with_closed = len(list(results_with_closed))
79+ count_only_closed = len(list(results_only_closed))
80+ self.assertEqual(count_only_closed, 0)
81+
82+ # Here we create a sellable. It should show on
83+ # ProductFullStockView and ProductFullWithClosedStock View,
84+ # but not on ProductClosedStockView.
85+ sellable = self.create_sellable()
86+ self.assertEqual(len(list(results_not_closed)), count_not_closed + 1L)
87+ self.assertEqual(len(list(results_with_closed)), count_with_closed + 1L)
88+ self.assertEqual(len(list(results_only_closed)), count_only_closed)
89+ ids = [result.id for result in results_not_closed]
90+ self.failIf(sellable.id not in ids)
91+ ids = [result.id for result in results_with_closed]
92+ self.failIf(sellable.id not in ids)
93+ ids = [result.id for result in results_only_closed]
94+ self.failIf(sellable.id in ids)
95+
96+ # Here we close that sellable. It should now show on
97+ # ProductClosedStockViewand ProductFullWithClosedStock View,
98+ # but not on ProductFullStockView.
99+ sellable.close()
100+ self.assertEquals(sellable.status, Sellable.STATUS_CLOSED)
101+ self.assertTrue(sellable.is_closed())
102+ self.assertEqual(len(list(results_not_closed)), count_not_closed)
103+ self.assertEqual(len(list(results_with_closed)), count_with_closed + 1L)
104+ self.assertEqual(len(list(results_only_closed)), count_only_closed + 1L)
105+ ids = [result.id for result in results_not_closed]
106+ self.failIf(sellable.id in ids)
107+ ids = [result.id for result in results_with_closed]
108+ self.failIf(sellable.id not in ids)
109+ ids = [result.id for result in results_only_closed]
110+ self.failIf(sellable.id not in ids)
111+
112+ # When trying to close an already closed sellable, it should
113+ # raise a ValueError.
114+ self.assertRaises(ValueError, sellable.close)
115
116=== modified file 'stoqlib/domain/views.py'
117--- stoqlib/domain/views.py 2011-02-15 10:21:17 +0000
118+++ stoqlib/domain/views.py 2011-03-04 18:09:29 +0000
119@@ -79,6 +79,8 @@
120 )
121
122 joins = [
123+ INNERJOINOn(None, BaseSellableInfo,
124+ BaseSellableInfo.q.id == Sellable.q.base_sellable_infoID),
125 # Tax Constant
126 LEFTJOINOn(None, SellableTaxConstant,
127 SellableTaxConstant.q.id == Sellable.q.tax_constantID),
128@@ -96,9 +98,7 @@
129 ProductAdaptToStorable.q.id),
130 ]
131
132- clause = AND(
133- BaseSellableInfo.q.id == Sellable.q.base_sellable_infoID,
134- )
135+ clause = Sellable.q.status != Sellable.STATUS_CLOSED
136
137 @classmethod
138 def select_by_branch(cls, query, branch, having=None, connection=None):
139@@ -154,6 +154,19 @@
140 return sellable.price
141
142
143+class ProductFullWithClosedStockView(ProductFullStockView):
144+ """Stores information about products, showing the closed ones too.
145+ """
146+
147+ clause = None
148+
149+class ProductClosedStockView(ProductFullWithClosedStockView):
150+ """Stores information about products that were closed.
151+ """
152+
153+ clause = Sellable.q.status == Sellable.STATUS_CLOSED
154+
155+
156 class ProductComponentView(ProductFullStockView):
157 columns = ProductFullStockView.columns
158 clause = AND(ProductFullStockView.clause,
159
160=== modified file 'stoqlib/gui/editors/sellableeditor.py'
161--- stoqlib/gui/editors/sellableeditor.py 2011-03-02 15:16:10 +0000
162+++ stoqlib/gui/editors/sellableeditor.py 2011-03-04 18:09:29 +0000
163@@ -236,23 +236,34 @@
164 code = u'%d' % self._sellable.id
165 self.code.update(code)
166 self.setup_widgets()
167- if model and self._sellable.can_remove():
168- button = self.add_button('Remove', 'gtk-delete')
169- button.connect('clicked', self._on_delete_button__activate)
170
171 self.set_description(
172 self.model.sellable.base_sellable_info.description)
173
174- def _on_delete_button__activate(self, button):
175- msg = _(u"This will delete '%s' from the database. Are you sure?"
176- % self._sellable.get_description())
177- if not yesno(msg, gtk.RESPONSE_NO, _(u"Delete"), _(u"Don't Delete")):
178- return
179-
180- self._sellable.remove()
181- # We don't call self.confirm since it will call validate_confirm
182- self.cancel()
183- self.main_dialog.retval = True
184+ self._setup_delete_close_reopen_button()
185+
186+ def _add_extra_button(self, label, stock=None,
187+ callback_func=None, connect_on='clicked'):
188+ button = self.add_button(label, stock)
189+ if callback_func:
190+ button.connect(connect_on, callback_func, label)
191+
192+ def _setup_delete_close_reopen_button(self):
193+ if self.model and self._sellable.can_remove():
194+ self._add_extra_button(_('Remove'), 'gtk-delete',
195+ self._on_delete_button__clicked)
196+ elif self.model and self._sellable.is_unavailable():
197+ label = (self._sellable.product and
198+ _('Close Product') or _('Close Service'))
199+
200+ self._add_extra_button(label, None,
201+ self._on_close_sellable_button__clicked)
202+ elif self.model and self._sellable.is_closed():
203+ label = (self._sellable.product and
204+ _('Reopen Product') or _('Reopen Service'))
205+
206+ self._add_extra_button(label, None,
207+ self._on_reopen_sellable_button__clicked)
208
209 def add_extra_tab(self, tabname, tabslave):
210 self.sellable_notebook.set_show_tabs(True)
211@@ -402,6 +413,41 @@
212 # Kiwi handlers
213 #
214
215+ def _on_delete_button__clicked(self, button, parent_button_label=None):
216+ msg = _(u"This will delete '%s' from the database. Are you sure?"
217+ % self._sellable.get_description())
218+ if not yesno(msg, gtk.RESPONSE_NO, _(u"Delete"), _(u"Don't Delete")):
219+ return
220+
221+ self._sellable.remove()
222+ # We don't call self.confirm since it will call validate_confirm
223+ self.cancel()
224+ self.main_dialog.retval = True
225+
226+ def _on_close_sellable_button__clicked(self, button,
227+ parent_button_label=None):
228+ msg = _(u"Do you really want to close '%s'?\n"
229+ u"Please note that when it's closed, you won't be able to "
230+ u"commercialize it anymore." % self._sellable.get_description())
231+ if not yesno(msg, gtk.RESPONSE_NO,
232+ parent_button_label, _(u"Don't Close")):
233+ return
234+
235+ self._sellable.close()
236+ self.confirm()
237+
238+ def _on_reopen_sellable_button__clicked(self, button,
239+ parent_button_label=None):
240+ msg = _(u"Do you really want to reopen '%s'?\n"
241+ u"Note that when it's opened, you will be able to "
242+ u"commercialize it again." % self._sellable.get_description())
243+ if not yesno(msg, gtk.RESPONSE_NO,
244+ parent_button_label, _(u"Keep Closed")):
245+ return
246+
247+ self._sellable.set_unavailable()
248+ self.confirm()
249+
250 def on_tax_constant__changed(self, combo):
251 self._update_tax_value()
252
253
254=== modified file 'stoqlib/gui/search/productsearch.py'
255--- stoqlib/gui/search/productsearch.py 2011-02-15 10:21:17 +0000
256+++ stoqlib/gui/search/productsearch.py 2011-03-04 18:09:29 +0000
257@@ -37,7 +37,9 @@
258 from stoqlib.domain.product import Product
259 from stoqlib.domain.sellable import Sellable
260 from stoqlib.domain.views import (ProductFullStockView, ProductQuantityView,
261- ProductFullStockItemView, SoldItemView)
262+ ProductFullStockItemView, SoldItemView,
263+ ProductFullWithClosedStockView,
264+ ProductClosedStockView)
265 from stoqlib.gui.base.dialogs import run_dialog
266 from stoqlib.gui.base.gtkadds import change_button_appearance
267 from stoqlib.gui.base.search import (SearchDialog, SearchEditor,
268@@ -50,8 +52,8 @@
269 from stoqlib.lib.translation import stoqlib_gettext
270 from stoqlib.lib.validators import format_quantity, get_formatted_cost
271 from stoqlib.reporting.product import (ProductReport, ProductQuantityReport,
272- ProductPriceReport,
273- ProductStockReport,
274+ ProductClosedStockReport,
275+ ProductPriceReport, ProductStockReport,
276 ProductsSoldReport)
277
278 _ = stoqlib_gettext
279@@ -61,7 +63,7 @@
280 title = _('Product Search')
281 table = Product
282 size = (775, 450)
283- search_table = ProductFullStockView
284+ search_table = ProductFullWithClosedStockView
285 editor_class = ProductEditor
286 footer_ok_label = _('Add products')
287 searchbar_result_strings = (_('product'), _('products'))
288@@ -413,3 +415,46 @@
289 if branch is not None:
290 branch = PersonAdaptToBranch.get(branch, connection=conn)
291 return self.table.select_by_branch(query, branch, connection=conn)
292+
293+
294+class ProductClosedStockSearch(ProductSearch):
295+ """A SearchEditor for Closed Products"""
296+
297+ title = _('Closed Product Stock Search')
298+ table = search_table = ProductClosedStockView
299+ has_new_button = False
300+
301+ def __init__(self, conn, hide_footer=True, hide_toolbar=True,
302+ selection_mode=gtk.SELECTION_BROWSE,
303+ hide_cost_column=True, use_product_statuses=None,
304+ hide_price_column=True):
305+ ProductSearch.__init__(self, conn, hide_footer, hide_toolbar,
306+ selection_mode, hide_cost_column,
307+ use_product_statuses, hide_price_column)
308+
309+ def create_filters(self):
310+ self.set_text_field_columns(['description', 'barcode',
311+ 'category_description'])
312+ self.executer.set_query(self.executer_query)
313+
314+ # Branch
315+ branch_filter = self.create_branch_filter(_('In branch:'))
316+ branch_filter.select(None)
317+ self.add_filter(branch_filter, columns=[])
318+ self.branch_filter = branch_filter
319+
320+ def _setup_print_slave(self):
321+ pass
322+
323+ def _has_rows(self, results, obj):
324+ SearchEditor._has_rows(self, results, obj)
325+
326+ #
327+ # SearchDialog Hooks
328+ #
329+
330+ def on_print_button_clicked(self, widget):
331+ print_report(ProductClosedStockReport, self.results,
332+ filters=self.search.get_search_filters(),
333+ branch_name=self.branch_filter.combo.get_active_text())
334+
335
336=== modified file 'stoqlib/reporting/product.py'
337--- stoqlib/reporting/product.py 2011-02-15 10:21:17 +0000
338+++ stoqlib/reporting/product.py 2011-03-04 18:09:29 +0000
339@@ -32,9 +32,9 @@
340 from stoqlib.lib.validators import format_quantity, get_formatted_price
341 from stoqlib.lib.translation import stoqlib_gettext as _
342 from stoqlib.domain.product import ProductHistory
343-from stoqlib.domain.views import (ProductFullStockView,
344+from stoqlib.domain.views import (SoldItemView, ProductFullStockView,
345 ProductFullStockItemView,
346- SoldItemView)
347+ ProductClosedStockView)
348
349
350 class ProductReport(ObjectListReport):
351@@ -237,3 +237,13 @@
352
353 self.add_object_table(self._stock_products, self.get_columns(),
354 summary_row=self.get_summary_row())
355+
356+
357+class ProductClosedStockReport(ProductStockReport):
358+ report_name = _("Closed Product Stock Report")
359+ main_object_name = _("closed products")
360+ obj_type = ProductClosedStockView
361+
362+ def _setup_table(self):
363+ self.add_object_table(self._stock_products, self.get_columns(),
364+ summary_row=self.get_summary_row())

Subscribers

People subscribed via source and target branches