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
=== modified file 'external/sqlobject/viewable.py'
--- external/sqlobject/viewable.py 2011-02-28 15:29:21 +0000
+++ external/sqlobject/viewable.py 2011-03-04 18:09:29 +0000
@@ -149,7 +149,7 @@
149149
150 setup_attributes(cls, new_attrs)150 setup_attributes(cls, new_attrs)
151151
152 columns = new_attrs['columns']152 columns = new_attrs.get('columns', getattr(cls, 'columns', None))
153 if not columns:153 if not columns:
154 return154 return
155155
156156
=== modified file 'stoqlib/domain/sellable.py'
--- stoqlib/domain/sellable.py 2011-02-08 14:06:58 +0000
+++ stoqlib/domain/sellable.py 2011-03-04 18:09:29 +0000
@@ -378,6 +378,10 @@
378378
379 commission = property(_get_commission, _set_commission)379 commission = property(_get_commission, _set_commission)
380380
381 #
382 # Accessors
383 #
384
381 def can_be_sold(self):385 def can_be_sold(self):
382 """Whether the sellable is available and can be sold.386 """Whether the sellable is available and can be sold.
383 @returns: if the item can be sold387 @returns: if the item can be sold
@@ -401,6 +405,19 @@
401 raise ValueError('This sellable is already unavailable')405 raise ValueError('This sellable is already unavailable')
402 self.status = self.STATUS_UNAVAILABLE406 self.status = self.STATUS_UNAVAILABLE
403407
408 def is_closed(self):
409 """Whether the sellable is closed or not.
410
411 @returns: True if closed, False otherwise.
412 """
413 return self.status == Sellable.STATUS_CLOSED
414
415 def close(self):
416 """Mark the sellable as closed"""
417 if self.is_closed():
418 raise ValueError('This sellable is already closed')
419 self.status = Sellable.STATUS_CLOSED
420
404 def cancel(self):421 def cancel(self):
405 """Cancel the sellable"""422 """Cancel the sellable"""
406 if self.can_be_sold():423 if self.can_be_sold():
407424
=== modified file 'stoqlib/domain/test/test_sellable.py'
--- stoqlib/domain/test/test_sellable.py 2011-02-08 14:06:58 +0000
+++ stoqlib/domain/test/test_sellable.py 2011-03-04 18:09:29 +0000
@@ -29,6 +29,9 @@
29 SellableCategory)29 SellableCategory)
30from stoqlib.domain.product import Product30from stoqlib.domain.product import Product
31from stoqlib.domain.test.domaintest import DomainTest31from stoqlib.domain.test.domaintest import DomainTest
32from stoqlib.domain.views import (ProductFullStockView,
33 ProductFullWithClosedStockView,
34 ProductClosedStockView)
3235
3336
34class TestSellableCategory(DomainTest):37class TestSellableCategory(DomainTest):
@@ -230,3 +233,52 @@
230 constant3 = self.create_sellable_tax_constant()233 constant3 = self.create_sellable_tax_constant()
231 sellable.tax_constant = constant3234 sellable.tax_constant = constant3
232 self.assertEquals(sellable.get_tax_constant(), constant3)235 self.assertEquals(sellable.get_tax_constant(), constant3)
236
237 def testClose(self):
238 results_not_closed = ProductFullStockView.select(connection=self.trans)
239 results_with_closed = ProductFullWithClosedStockView.select(
240 connection=self.trans)
241 results_only_closed = ProductClosedStockView.select(
242 connection=self.trans)
243 # Count the already there results. ProductClosedStockView should
244 # not have any.
245 # obs. Using len(list(res)) instead of res.count() because of a bug
246 # on sqlobject that returns wrong count() on that views.
247 count_not_closed = len(list(results_not_closed))
248 count_with_closed = len(list(results_with_closed))
249 count_only_closed = len(list(results_only_closed))
250 self.assertEqual(count_only_closed, 0)
251
252 # Here we create a sellable. It should show on
253 # ProductFullStockView and ProductFullWithClosedStock View,
254 # but not on ProductClosedStockView.
255 sellable = self.create_sellable()
256 self.assertEqual(len(list(results_not_closed)), count_not_closed + 1L)
257 self.assertEqual(len(list(results_with_closed)), count_with_closed + 1L)
258 self.assertEqual(len(list(results_only_closed)), count_only_closed)
259 ids = [result.id for result in results_not_closed]
260 self.failIf(sellable.id not in ids)
261 ids = [result.id for result in results_with_closed]
262 self.failIf(sellable.id not in ids)
263 ids = [result.id for result in results_only_closed]
264 self.failIf(sellable.id in ids)
265
266 # Here we close that sellable. It should now show on
267 # ProductClosedStockViewand ProductFullWithClosedStock View,
268 # but not on ProductFullStockView.
269 sellable.close()
270 self.assertEquals(sellable.status, Sellable.STATUS_CLOSED)
271 self.assertTrue(sellable.is_closed())
272 self.assertEqual(len(list(results_not_closed)), count_not_closed)
273 self.assertEqual(len(list(results_with_closed)), count_with_closed + 1L)
274 self.assertEqual(len(list(results_only_closed)), count_only_closed + 1L)
275 ids = [result.id for result in results_not_closed]
276 self.failIf(sellable.id in ids)
277 ids = [result.id for result in results_with_closed]
278 self.failIf(sellable.id not in ids)
279 ids = [result.id for result in results_only_closed]
280 self.failIf(sellable.id not in ids)
281
282 # When trying to close an already closed sellable, it should
283 # raise a ValueError.
284 self.assertRaises(ValueError, sellable.close)
233285
=== modified file 'stoqlib/domain/views.py'
--- stoqlib/domain/views.py 2011-02-15 10:21:17 +0000
+++ stoqlib/domain/views.py 2011-03-04 18:09:29 +0000
@@ -79,6 +79,8 @@
79 )79 )
8080
81 joins = [81 joins = [
82 INNERJOINOn(None, BaseSellableInfo,
83 BaseSellableInfo.q.id == Sellable.q.base_sellable_infoID),
82 # Tax Constant84 # Tax Constant
83 LEFTJOINOn(None, SellableTaxConstant,85 LEFTJOINOn(None, SellableTaxConstant,
84 SellableTaxConstant.q.id == Sellable.q.tax_constantID),86 SellableTaxConstant.q.id == Sellable.q.tax_constantID),
@@ -96,9 +98,7 @@
96 ProductAdaptToStorable.q.id),98 ProductAdaptToStorable.q.id),
97 ]99 ]
98100
99 clause = AND(101 clause = Sellable.q.status != Sellable.STATUS_CLOSED
100 BaseSellableInfo.q.id == Sellable.q.base_sellable_infoID,
101 )
102102
103 @classmethod103 @classmethod
104 def select_by_branch(cls, query, branch, having=None, connection=None):104 def select_by_branch(cls, query, branch, having=None, connection=None):
@@ -154,6 +154,19 @@
154 return sellable.price154 return sellable.price
155155
156156
157class ProductFullWithClosedStockView(ProductFullStockView):
158 """Stores information about products, showing the closed ones too.
159 """
160
161 clause = None
162
163class ProductClosedStockView(ProductFullWithClosedStockView):
164 """Stores information about products that were closed.
165 """
166
167 clause = Sellable.q.status == Sellable.STATUS_CLOSED
168
169
157class ProductComponentView(ProductFullStockView):170class ProductComponentView(ProductFullStockView):
158 columns = ProductFullStockView.columns171 columns = ProductFullStockView.columns
159 clause = AND(ProductFullStockView.clause,172 clause = AND(ProductFullStockView.clause,
160173
=== modified file 'stoqlib/gui/editors/sellableeditor.py'
--- stoqlib/gui/editors/sellableeditor.py 2011-03-02 15:16:10 +0000
+++ stoqlib/gui/editors/sellableeditor.py 2011-03-04 18:09:29 +0000
@@ -236,23 +236,34 @@
236 code = u'%d' % self._sellable.id236 code = u'%d' % self._sellable.id
237 self.code.update(code)237 self.code.update(code)
238 self.setup_widgets()238 self.setup_widgets()
239 if model and self._sellable.can_remove():
240 button = self.add_button('Remove', 'gtk-delete')
241 button.connect('clicked', self._on_delete_button__activate)
242239
243 self.set_description(240 self.set_description(
244 self.model.sellable.base_sellable_info.description)241 self.model.sellable.base_sellable_info.description)
245242
246 def _on_delete_button__activate(self, button):243 self._setup_delete_close_reopen_button()
247 msg = _(u"This will delete '%s' from the database. Are you sure?"244
248 % self._sellable.get_description())245 def _add_extra_button(self, label, stock=None,
249 if not yesno(msg, gtk.RESPONSE_NO, _(u"Delete"), _(u"Don't Delete")):246 callback_func=None, connect_on='clicked'):
250 return247 button = self.add_button(label, stock)
251248 if callback_func:
252 self._sellable.remove()249 button.connect(connect_on, callback_func, label)
253 # We don't call self.confirm since it will call validate_confirm250
254 self.cancel()251 def _setup_delete_close_reopen_button(self):
255 self.main_dialog.retval = True252 if self.model and self._sellable.can_remove():
253 self._add_extra_button(_('Remove'), 'gtk-delete',
254 self._on_delete_button__clicked)
255 elif self.model and self._sellable.is_unavailable():
256 label = (self._sellable.product and
257 _('Close Product') or _('Close Service'))
258
259 self._add_extra_button(label, None,
260 self._on_close_sellable_button__clicked)
261 elif self.model and self._sellable.is_closed():
262 label = (self._sellable.product and
263 _('Reopen Product') or _('Reopen Service'))
264
265 self._add_extra_button(label, None,
266 self._on_reopen_sellable_button__clicked)
256267
257 def add_extra_tab(self, tabname, tabslave):268 def add_extra_tab(self, tabname, tabslave):
258 self.sellable_notebook.set_show_tabs(True)269 self.sellable_notebook.set_show_tabs(True)
@@ -402,6 +413,41 @@
402 # Kiwi handlers413 # Kiwi handlers
403 #414 #
404415
416 def _on_delete_button__clicked(self, button, parent_button_label=None):
417 msg = _(u"This will delete '%s' from the database. Are you sure?"
418 % self._sellable.get_description())
419 if not yesno(msg, gtk.RESPONSE_NO, _(u"Delete"), _(u"Don't Delete")):
420 return
421
422 self._sellable.remove()
423 # We don't call self.confirm since it will call validate_confirm
424 self.cancel()
425 self.main_dialog.retval = True
426
427 def _on_close_sellable_button__clicked(self, button,
428 parent_button_label=None):
429 msg = _(u"Do you really want to close '%s'?\n"
430 u"Please note that when it's closed, you won't be able to "
431 u"commercialize it anymore." % self._sellable.get_description())
432 if not yesno(msg, gtk.RESPONSE_NO,
433 parent_button_label, _(u"Don't Close")):
434 return
435
436 self._sellable.close()
437 self.confirm()
438
439 def _on_reopen_sellable_button__clicked(self, button,
440 parent_button_label=None):
441 msg = _(u"Do you really want to reopen '%s'?\n"
442 u"Note that when it's opened, you will be able to "
443 u"commercialize it again." % self._sellable.get_description())
444 if not yesno(msg, gtk.RESPONSE_NO,
445 parent_button_label, _(u"Keep Closed")):
446 return
447
448 self._sellable.set_unavailable()
449 self.confirm()
450
405 def on_tax_constant__changed(self, combo):451 def on_tax_constant__changed(self, combo):
406 self._update_tax_value()452 self._update_tax_value()
407453
408454
=== modified file 'stoqlib/gui/search/productsearch.py'
--- stoqlib/gui/search/productsearch.py 2011-02-15 10:21:17 +0000
+++ stoqlib/gui/search/productsearch.py 2011-03-04 18:09:29 +0000
@@ -37,7 +37,9 @@
37from stoqlib.domain.product import Product37from stoqlib.domain.product import Product
38from stoqlib.domain.sellable import Sellable38from stoqlib.domain.sellable import Sellable
39from stoqlib.domain.views import (ProductFullStockView, ProductQuantityView,39from stoqlib.domain.views import (ProductFullStockView, ProductQuantityView,
40 ProductFullStockItemView, SoldItemView)40 ProductFullStockItemView, SoldItemView,
41 ProductFullWithClosedStockView,
42 ProductClosedStockView)
41from stoqlib.gui.base.dialogs import run_dialog43from stoqlib.gui.base.dialogs import run_dialog
42from stoqlib.gui.base.gtkadds import change_button_appearance44from stoqlib.gui.base.gtkadds import change_button_appearance
43from stoqlib.gui.base.search import (SearchDialog, SearchEditor,45from stoqlib.gui.base.search import (SearchDialog, SearchEditor,
@@ -50,8 +52,8 @@
50from stoqlib.lib.translation import stoqlib_gettext52from stoqlib.lib.translation import stoqlib_gettext
51from stoqlib.lib.validators import format_quantity, get_formatted_cost53from stoqlib.lib.validators import format_quantity, get_formatted_cost
52from stoqlib.reporting.product import (ProductReport, ProductQuantityReport,54from stoqlib.reporting.product import (ProductReport, ProductQuantityReport,
53 ProductPriceReport,55 ProductClosedStockReport,
54 ProductStockReport,56 ProductPriceReport, ProductStockReport,
55 ProductsSoldReport)57 ProductsSoldReport)
5658
57_ = stoqlib_gettext59_ = stoqlib_gettext
@@ -61,7 +63,7 @@
61 title = _('Product Search')63 title = _('Product Search')
62 table = Product64 table = Product
63 size = (775, 450)65 size = (775, 450)
64 search_table = ProductFullStockView66 search_table = ProductFullWithClosedStockView
65 editor_class = ProductEditor67 editor_class = ProductEditor
66 footer_ok_label = _('Add products')68 footer_ok_label = _('Add products')
67 searchbar_result_strings = (_('product'), _('products'))69 searchbar_result_strings = (_('product'), _('products'))
@@ -413,3 +415,46 @@
413 if branch is not None:415 if branch is not None:
414 branch = PersonAdaptToBranch.get(branch, connection=conn)416 branch = PersonAdaptToBranch.get(branch, connection=conn)
415 return self.table.select_by_branch(query, branch, connection=conn)417 return self.table.select_by_branch(query, branch, connection=conn)
418
419
420class ProductClosedStockSearch(ProductSearch):
421 """A SearchEditor for Closed Products"""
422
423 title = _('Closed Product Stock Search')
424 table = search_table = ProductClosedStockView
425 has_new_button = False
426
427 def __init__(self, conn, hide_footer=True, hide_toolbar=True,
428 selection_mode=gtk.SELECTION_BROWSE,
429 hide_cost_column=True, use_product_statuses=None,
430 hide_price_column=True):
431 ProductSearch.__init__(self, conn, hide_footer, hide_toolbar,
432 selection_mode, hide_cost_column,
433 use_product_statuses, hide_price_column)
434
435 def create_filters(self):
436 self.set_text_field_columns(['description', 'barcode',
437 'category_description'])
438 self.executer.set_query(self.executer_query)
439
440 # Branch
441 branch_filter = self.create_branch_filter(_('In branch:'))
442 branch_filter.select(None)
443 self.add_filter(branch_filter, columns=[])
444 self.branch_filter = branch_filter
445
446 def _setup_print_slave(self):
447 pass
448
449 def _has_rows(self, results, obj):
450 SearchEditor._has_rows(self, results, obj)
451
452 #
453 # SearchDialog Hooks
454 #
455
456 def on_print_button_clicked(self, widget):
457 print_report(ProductClosedStockReport, self.results,
458 filters=self.search.get_search_filters(),
459 branch_name=self.branch_filter.combo.get_active_text())
460
416461
=== modified file 'stoqlib/reporting/product.py'
--- stoqlib/reporting/product.py 2011-02-15 10:21:17 +0000
+++ stoqlib/reporting/product.py 2011-03-04 18:09:29 +0000
@@ -32,9 +32,9 @@
32from stoqlib.lib.validators import format_quantity, get_formatted_price32from stoqlib.lib.validators import format_quantity, get_formatted_price
33from stoqlib.lib.translation import stoqlib_gettext as _33from stoqlib.lib.translation import stoqlib_gettext as _
34from stoqlib.domain.product import ProductHistory34from stoqlib.domain.product import ProductHistory
35from stoqlib.domain.views import (ProductFullStockView,35from stoqlib.domain.views import (SoldItemView, ProductFullStockView,
36 ProductFullStockItemView,36 ProductFullStockItemView,
37 SoldItemView)37 ProductClosedStockView)
3838
3939
40class ProductReport(ObjectListReport):40class ProductReport(ObjectListReport):
@@ -237,3 +237,13 @@
237237
238 self.add_object_table(self._stock_products, self.get_columns(),238 self.add_object_table(self._stock_products, self.get_columns(),
239 summary_row=self.get_summary_row())239 summary_row=self.get_summary_row())
240
241
242class ProductClosedStockReport(ProductStockReport):
243 report_name = _("Closed Product Stock Report")
244 main_object_name = _("closed products")
245 obj_type = ProductClosedStockView
246
247 def _setup_table(self):
248 self.add_object_table(self._stock_products, self.get_columns(),
249 summary_row=self.get_summary_row())

Subscribers

People subscribed via source and target branches