def test_remove(self): workorder = self.create_workorder() product1 = self.create_product(stock=10, branch=workorder.branch) product2 = self.create_product(stock=10, branch=workorder.branch) item1 = WorkOrderItem(self.store, sellable=product1.sellable, quantity=5) item2 = WorkOrderItem(self.store, sellable=product1.sellable, quantity=5) for item in [item1, item2]: self.assertRaises(AssertionError, workorder.remove_item, item) workorder.add_item(item1) workorder.add_item(item2) # Only item1 will sync stock. The other one is to test it being # removed without ever decreasing the stock item1.sync_stock() self.assertEqual( product1.storable.get_balance_for_branch(workorder.branch), 5) self.assertEqual( product2.storable.get_balance_for_branch(workorder.branch), 10) for item in [item1, item2]: with mock.patch.object(self.store, 'remove') as remove: workorder.remove_item(item) remove.assert_called_once_with(item) storable = item.sellable.product.storable # Everything should be back to the stock, like # the item never existed self.assertEqual( storable.get_balance_for_branch(workorder.branch), 10)
def test_get_items(self): sellable = self.create_sellable() item1 = WorkOrderItem(self.store, sellable=sellable) item2 = WorkOrderItem(self.store, sellable=sellable) workorder = self.create_workorder() workorder.add_item(item1) workorder.add_item(item2) self.assertEqual(set(workorder.get_items()), set([item1, item2]))
def on_confirm(self): diff = (self.quantity_reserved.read() - self._original_quantity_decreased) if diff == 0: return elif diff < 0: self.model.return_to_stock(-diff) return storable = self.model.sellable.product_storable # This can only happen for diff > 0. If the product is marked to # control batches, no decreased should have been made without # specifying a batch on the item if storable and storable.is_batch and self.model.batch is None: # The only way self.model.batch is None is that this item # was created on a sale quote and thus it has a sale_item sale_item = self.model.sale_item batches = run_dialog(_WorkOrderItemBatchSelectionDialog, self, self.store, model=storable, quantity=diff) if not batches: return for s_item in [sale_item] + sale_item.set_batches(batches): wo_item = WorkOrderItem.get_from_sale_item(self.store, s_item) if wo_item.batch is not None: wo_item.reserve(wo_item.quantity) elif storable: self.model.reserve(diff)
def remove_items(self, items): # Remove the workorder items first to avoid reference problems for item in items: wo_item = WorkOrderItem.get_from_sale_item(self.store, item) wo_item.order.remove_item(wo_item) super(WorkOrderQuoteItemStep, self).remove_items(items)
def get_order_item(self, sellable, price, quantity, batch=None): sale_item = super(OpticalItemStep, self).get_order_item( sellable, price, quantity, batch=batch) self._setup_patient(sale_item) wo_item = WorkOrderItem.get_from_sale_item(self.store, sale_item) # Now we must remove the products added to the workorders from the # stock and we can associate the category selected to the workorders storable = sale_item.sellable.product_storable if storable: if sale_item.batch is not None: balance = sale_item.batch.get_balance_for_branch( sale_item.sale.branch) else: balance = storable.get_balance_for_branch( sale_item.sale.branch) else: # No storable, consume it all balance = sale_item.quantity quantity_to_reserve = min(balance, sale_item.quantity) if quantity_to_reserve: sale_item.reserve(quantity_to_reserve) wo_item.quantity_decreased = sale_item.quantity_decreased return sale_item
def get_order_item(self, sellable, price, quantity, batch=None): sale_item = super(OpticalItemStep, self).get_order_item( sellable, price, quantity, batch=batch) self._setup_patient(sale_item) wo_item = WorkOrderItem.get_from_sale_item(self.store, sale_item) # Now we must remove the products added to the workorders from the # stock and we can associate the category selected to the workorders storable = sale_item.sellable.product_storable if not storable: return sale_item optical_product = OpticalProduct.get_from_product(storable.product) if optical_product: auto_reserve = optical_product.auto_reserve else: auto_reserve = True if sale_item.batch is not None: balance = sale_item.batch.get_balance_for_branch( sale_item.sale.branch) else: balance = storable.get_balance_for_branch( sale_item.sale.branch) if auto_reserve: quantity_to_reserve = min(balance, sale_item.quantity) if quantity_to_reserve: sale_item.reserve(quantity_to_reserve) wo_item.quantity_decreased = sale_item.quantity_decreased return sale_item
def get_order_item(self, sellable, price, quantity, batch=None, parent=None): if parent: component_quantity = self.get_component_quantity(parent, sellable) price = Decimal('0') quantity = parent.quantity * component_quantity sale_item = super(OpticalItemStep, self).get_order_item( sellable, price, quantity, batch=batch, parent=parent) self._setup_patient(sale_item) wo_item = WorkOrderItem.get_from_sale_item(self.store, sale_item) # Now we must remove the products added to the workorders from the # stock and we can associate the category selected to the workorders storable = sale_item.sellable.product_storable if not storable: return sale_item optical_product = OpticalProduct.get_from_product(storable.product) if optical_product: auto_reserve = optical_product.auto_reserve else: auto_reserve = True if sale_item.batch is not None: balance = sale_item.batch.get_balance_for_branch( sale_item.sale.branch) else: balance = storable.get_balance_for_branch( sale_item.sale.branch) if auto_reserve: quantity_to_reserve = min(balance, sale_item.quantity) if quantity_to_reserve: sale_item.reserve(quantity_to_reserve) wo_item.quantity_decreased = sale_item.quantity_decreased return sale_item
def on_confirm(self): diff = (self.quantity_reserved.read() - self._original_quantity_decreased) if diff == 0: return elif diff < 0: self.model.return_to_stock(-diff) return storable = self.model.sellable.product_storable # This can only happen for diff > 0. If the product is marked to # control batches, no decreased should have been made without # specifying a batch on the item if storable and storable.is_batch and self.model.batch is None: # The only way self.model.batch is None is that this item # was created on a sale quote and thus it has a sale_item sale_item = self.model.sale_item batches = run_dialog( _WorkOrderItemBatchSelectionDialog, self, self.store, model=storable, quantity=diff) if not batches: return for s_item in [sale_item] + sale_item.set_batches(batches): wo_item = WorkOrderItem.get_from_sale_item(self.store, s_item) if wo_item.batch is not None: wo_item.reserve(wo_item.quantity) else: self.model.reserve(diff)
def test_add_item(self): sellable = self.create_sellable() item = WorkOrderItem(self.store, sellable=sellable) workorder = self.create_workorder() workorder.add_item(item) self.assertEqual(item.order, workorder) self.assertRaises(AssertionError, workorder.add_item, item)
def test_remove(self): workorder = self.create_workorder() product1 = self.create_product(stock=10, branch=workorder.branch) product2 = self.create_product(stock=10, branch=workorder.branch) item1 = WorkOrderItem(self.store, sellable=product1.sellable, quantity=5) item2 = WorkOrderItem(self.store, sellable=product1.sellable, quantity=5) for item in [item1, item2]: self.assertRaises(AssertionError, workorder.remove_item, item) workorder.add_item(item1) workorder.add_item(item2) # Only item1 will reserve stock. The other one is to test it being # removed without ever decreasing the stock item1.reserve(item1.quantity) self.assertEqual( product1.storable.get_balance_for_branch(workorder.branch), 5) self.assertEqual( product2.storable.get_balance_for_branch(workorder.branch), 10) for item in [item1, item2]: workorder.remove_item(item) storable = item.sellable.product.storable # Everything should be back to the stock, like # the item never existed self.assertEqual(storable.get_balance_for_branch(workorder.branch), 10) with self.sysparam(SYNCHRONIZED_MODE=True): item = self.create_work_order_item() order = item.order before_remove = self.store.find(WorkOrderItem).count() order.remove_item(item) after_remove = self.store.find(WorkOrderItem).count() # The item should still be on the database self.assertEqual(before_remove, after_remove) # But not related to the loan self.assertEquals( self.store.find(WorkOrderItem, order=order).count(), 0)
def test_get_from_sale_item(self): sale_item = self.create_sale_item() # There is no work order item yet. wo_item = WorkOrderItem.get_from_sale_item(self.store, sale_item) self.assertEquals(wo_item, None) # Create one work order item = WorkOrderItem(store=self.store, sellable=sale_item.sellable) # They are still not related. wo_item = WorkOrderItem.get_from_sale_item(self.store, sale_item) self.assertEquals(wo_item, None) # After relating them, it should be found. item.sale_item = sale_item wo_item = WorkOrderItem.get_from_sale_item(self.store, sale_item) self.assertEquals(wo_item, item)
def test_total(self): sellable = self.create_sellable() workorder = self.create_workorder() workorderitem = WorkOrderItem(self.store, price=10, quantity=15, order=workorder, sellable=sellable) self.assertEqual(workorderitem.total, 150)
def validate_step(self): # When finishing the wizard, make sure that all modifications on # sale items on this step are propagated to their work order items for sale_item in self.model.get_items(): wo_item = WorkOrderItem.get_from_sale_item(self.store, sale_item) wo_item.quantity = sale_item.quantity wo_item.quantity_decreased = sale_item.quantity_decreased wo_item.price = sale_item.price return super(WorkOrderQuoteItemStep, self).validate_step()
def test_remove(self): workorder = self.create_workorder() product1 = self.create_product(stock=10, branch=workorder.branch) product2 = self.create_product(stock=10, branch=workorder.branch) item1 = WorkOrderItem(self.store, sellable=product1.sellable, quantity=5) item2 = WorkOrderItem(self.store, sellable=product1.sellable, quantity=5) for item in [item1, item2]: self.assertRaises(AssertionError, workorder.remove_item, item) workorder.add_item(item1) workorder.add_item(item2) # Only item1 will reserve stock. The other one is to test it being # removed without ever decreasing the stock item1.reserve(item1.quantity) self.assertEqual( product1.storable.get_balance_for_branch(workorder.branch), 5) self.assertEqual( product2.storable.get_balance_for_branch(workorder.branch), 10) for item in [item1, item2]: workorder.remove_item(item) storable = item.sellable.product.storable # Everything should be back to the stock, like # the item never existed self.assertEqual( storable.get_balance_for_branch(workorder.branch), 10) with self.sysparam(SYNCHRONIZED_MODE=True): item = self.create_work_order_item() order = item.order before_remove = self.store.find(WorkOrderItem).count() order.remove_item(item) after_remove = self.store.find(WorkOrderItem).count() # The item should still be on the database self.assertEqual(before_remove, after_remove) # But not related to the loan self.assertEquals(self.store.find(WorkOrderItem, order=order).count(), 0)
def remove_items(self, items): # Remove the workorder items first to avoid reference problems for item in items: wo_item = WorkOrderItem.get_from_sale_item(self.store, item) # If the item's quantity_decreased changed in this step, the # synchronization between the 2 that happens on self.validate_step # would not have happened yet, meaning that order.remove_item # would try to return a wrong quantity to the stock. Force the # synchronization to avoid any problems like that wo_item.quantity_decreased = item.quantity_decreased wo_item.order.remove_item(wo_item) super(WorkOrderQuoteItemStep, self).remove_items(items)
def __init__(self, sale_item): self._sale_item = sale_item self.sellable = sale_item.sellable self.base_price = sale_item.base_price self.price = sale_item.price self.quantity = sale_item.quantity self.total = sale_item.get_total() self.batch = sale_item.batch store = sale_item.store self._work_item = WorkOrderItem.get_from_sale_item(store, sale_item) optical_wo = store.find(OpticalWorkOrder, work_order=self._work_item.order).one() self.patient = optical_wo.patient
def get_order_item(self, sellable, price, quantity, batch=None, parent=None): if parent: component = self.get_component(parent, sellable) price = component.price quantity = parent.quantity * component.quantity elif sellable.product.is_package: price = Decimal('0') sale_item = super(OpticalItemStep, self).get_order_item(sellable, price, quantity, batch=batch, parent=parent) self._setup_patient(sale_item) wo_item = WorkOrderItem.get_from_sale_item(self.store, sale_item) # Now we must remove the products added to the workorders from the # stock and we can associate the category selected to the workorders storable = sale_item.sellable.product_storable if not storable: return sale_item optical_product = OpticalProduct.get_from_product(storable.product) if optical_product: auto_reserve = optical_product.auto_reserve else: auto_reserve = True if sale_item.batch is not None: balance = sale_item.batch.get_balance_for_branch( sale_item.sale.branch) else: balance = storable.get_balance_for_branch(sale_item.sale.branch) if auto_reserve: quantity_to_reserve = min(balance, sale_item.quantity) if quantity_to_reserve: sale_item.reserve(api.get_current_user(self.store), quantity_to_reserve) wo_item.quantity_decreased = sale_item.quantity_decreased return sale_item
def get_saved_items(self): for item in super(WorkOrderQuoteItemStep, self).get_saved_items(): wo_item = WorkOrderItem.get_from_sale_item(self.store, item) item._equipment = wo_item.order.description yield item
def _setup_patient(self, sale_item): wo_item = WorkOrderItem.get_from_sale_item(self.store, sale_item) optical_wo = self.store.find(OpticalWorkOrder, work_order=wo_item.order).one() sale_item._patient = optical_wo.patient
def test_confirm(self, run_person_role_dialog, run_dialog, yesno): WorkOrderCategory(store=self.store, name=u'Category', color=u'#ff0000') client = self.create_client() self.create_address(person=client.person) run_person_role_dialog.return_value = client yesno.return_value = False # Test for reserve without storable sellable = self.create_sellable() sellable.barcode = u'12345678' # Test for reserve with storable sellable2 = self.create_sellable() sellable2.barcode = u'12345679' self.create_storable( product=sellable2.product, branch=api.get_current_branch(self.store), stock=10) # Test for reserve for a batch with storable sellable3 = self.create_sellable() sellable3.barcode = u'12345680' storable, batch = self.create_storable( product=sellable3.product, branch=api.get_current_branch(self.store), is_batch=True, stock=10) # Test for return_to_stock sellable4 = self.create_sellable() sellable4.barcode = u'12345681' self.create_storable(product=sellable4.product) wizard = OpticalSaleQuoteWizard(self.store) step = wizard.get_current_step() self.click(step.create_client) self.assertEquals(run_person_role_dialog.call_count, 1) args, kwargs = run_person_role_dialog.call_args editor, parent, store, model = args self.assertEquals(editor, ClientEditor) self.assertEquals(parent, wizard) self.assertTrue(store is not None) self.assertTrue(model is None) self.click(step.client_details) self.assertEquals(run_dialog.call_count, 1) args, kwargs = run_dialog.call_args dialog, parent, store, model = args self.assertEquals(dialog, ClientDetailsDialog) self.assertEquals(parent, wizard) self.assertTrue(store is not None) self.assertEquals(model, client) run_dialog.return_value = False self.click(step.notes_button) self.assertEquals(run_dialog.call_count, 2) args, kwargs = run_dialog.call_args editor, parent, store, model, comment = args self.assertEquals(editor, NoteEditor) self.assertEquals(parent, wizard) self.assertTrue(store is not None) self.assertTrue(isinstance(model, SaleComment)) self.assertEquals(comment, 'comment') self.assertEquals(kwargs['title'], _("Additional Information")) self.check_wizard(wizard, 'wizard-optical-start-sale-quote-step') self.click(wizard.next_button) step = wizard.get_current_step() slave = step.slaves['WO 1'] slave.patient.update('Patient') slave.estimated_finish.update(localdate(2020, 1, 5)) sale = wizard.model self.check_wizard(wizard, 'wizard-optical-work-order-step') self.click(wizard.next_button) step = wizard.get_current_step() for barcode in [batch.batch_number, sellable.barcode, sellable2.barcode, sellable4.barcode]: step.barcode.set_text(barcode) self.activate(step.barcode) step.quantity.update(1) self.click(step.add_sellable_button) for item in step.slave.klist: if item.sellable == sellable4: wo_item = WorkOrderItem.get_from_sale_item(self.store, item) wo_item.quantity_decreased = 10 self.check_wizard(wizard, 'wizard-optical-item-step', [sale, client] + list(sale.get_items().order_by('te_id'))) module = 'stoqlib.gui.events.SaleQuoteWizardFinishEvent.emit' with mock.patch(module) as emit: with mock.patch.object(self.store, 'commit'): self.click(wizard.next_button) self.assertEquals(emit.call_count, 1) args, kwargs = emit.call_args self.assertTrue(isinstance(args[0], Sale)) self.assertEqual(wizard.model.payments.count(), 0) yesno.assert_called_once_with(_('Would you like to print the quote ' 'details now?'), gtk.RESPONSE_YES, _("Print quote details"), _("Don't print")) # Test get_saved_items, using the existing model here wizard2 = OpticalSaleQuoteWizard(self.store, model=wizard.model) self.click(wizard2.next_button) self.click(wizard2.next_button)
def test_confirm(self, run_dialog, yesno): self._create_work_order_category() client = self.create_client() medic = self.create_optical_medic() self.create_address(person=client.person) yesno.return_value = False # Test for reserve without storable sellable = self.create_sellable() sellable.barcode = u'12345678' # Test for reserve with storable sellable2 = self.create_sellable() sellable2.barcode = u'12345679' self.create_storable(product=sellable2.product, branch=api.get_current_branch(self.store), stock=10) # Test for reserve for a batch with storable sellable3 = self.create_sellable() sellable3.barcode = u'12345680' storable, batch = self.create_storable(product=sellable3.product, branch=api.get_current_branch( self.store), is_batch=True, stock=10) # Test for return_to_stock sellable4 = self.create_sellable() sellable4.barcode = u'12345681' self.create_storable(product=sellable4.product) product = self.create_product(description=u'Package', is_package=True) sellable5 = product.sellable sellable5.barcode = u'666' product2 = self.create_product(description=u'Component', stock=5, storable=True) self.create_product_component(product=product, component=product2, component_quantity=5, price=2) wizard = OpticalSaleQuoteWizard(self.store) # First Step step = wizard.get_current_step() step.client_gadget.set_value(client) run_dialog.return_value = False self.click(step.notes_button) self.assertEqual(run_dialog.call_count, 1) args, kwargs = run_dialog.call_args editor, parent, store, model, comment = args self.assertEqual(editor, NoteEditor) self.assertEqual(parent, wizard) self.assertTrue(store is not None) self.assertTrue(isinstance(model, SaleComment)) self.assertEqual(comment, 'comment') self.assertEqual(kwargs['title'], _("Additional Information")) self.check_wizard(wizard, 'wizard-optical-start-sale-quote-step') self.click(wizard.next_button) # OpticalWorkOrder step step = wizard.get_current_step() slave = step.slaves['WO 1'] slave.patient.update('Patient') slave.medic_combo.update(medic) slave.estimated_finish.update(localdate(2020, 1, 5)) sale = wizard.model self.check_wizard(wizard, 'wizard-optical-work-order-step') self.click(wizard.next_button) # OpticalWorkOrderItem Step step = wizard.get_current_step() for barcode in [ batch.batch_number, sellable.barcode, sellable2.barcode, sellable4.barcode, sellable5.barcode ]: step.barcode.set_text(barcode) self.activate(step.barcode) step.quantity.update(1) self.click(step.add_sellable_button) for item in step.slave.klist: if item.sellable == sellable4: wo_item = WorkOrderItem.get_from_sale_item(self.store, item) wo_item.quantity_decreased = 10 self.check_wizard(wizard, 'wizard-optical-item-step', [sale, client, sale.invoice] + list(sale.get_items().order_by('te_id'))) module = 'stoqlib.gui.events.SaleQuoteWizardFinishEvent.emit' with mock.patch(module) as emit: with mock.patch.object(self.store, 'commit'): self.click(wizard.next_button) self.assertEqual(emit.call_count, 1) args, kwargs = emit.call_args self.assertTrue(isinstance(args[0], Sale)) self.assertEqual(wizard.model.payments.count(), 0) yesno.assert_called_once_with( _('Would you like to print the quote ' 'details now?'), Gtk.ResponseType.YES, _("Print quote details"), _("Don't print")) # Test get_saved_items, using the existing model here wizard2 = OpticalSaleQuoteWizard(self.store, model=wizard.model) self.click(wizard2.next_button) self.click(wizard2.next_button)
def test_confirm(self, run_dialog, yesno): self._create_work_order_category() client = self.create_client() medic = self.create_optical_medic() self.create_address(person=client.person) yesno.return_value = False # Test for reserve without storable sellable = self.create_sellable() sellable.barcode = u'12345678' # Test for reserve with storable sellable2 = self.create_sellable() sellable2.barcode = u'12345679' self.create_storable( product=sellable2.product, branch=api.get_current_branch(self.store), stock=10) # Test for reserve for a batch with storable sellable3 = self.create_sellable() sellable3.barcode = u'12345680' storable, batch = self.create_storable( product=sellable3.product, branch=api.get_current_branch(self.store), is_batch=True, stock=10) # Test for return_to_stock sellable4 = self.create_sellable() sellable4.barcode = u'12345681' self.create_storable(product=sellable4.product) product = self.create_product(description=u'Package', is_package=True) sellable5 = product.sellable sellable5.barcode = u'666' product2 = self.create_product(description=u'Component', stock=5, storable=True) self.create_product_component(product=product, component=product2, component_quantity=5, price=2) wizard = OpticalSaleQuoteWizard(self.store) # First Step step = wizard.get_current_step() step.client_gadget.set_value(client) run_dialog.return_value = False self.click(step.notes_button) self.assertEqual(run_dialog.call_count, 1) args, kwargs = run_dialog.call_args editor, parent, store, model, comment = args self.assertEqual(editor, NoteEditor) self.assertEqual(parent, wizard) self.assertTrue(store is not None) self.assertTrue(isinstance(model, SaleComment)) self.assertEqual(comment, 'comment') self.assertEqual(kwargs['title'], _("Additional Information")) self.check_wizard(wizard, 'wizard-optical-start-sale-quote-step') self.click(wizard.next_button) # OpticalWorkOrder step step = wizard.get_current_step() slave = step.slaves['WO 1'] slave.patient.update('Patient') slave.medic_gadget.set_value(medic) slave.estimated_finish.update(localdate(2020, 1, 5)) sale = wizard.model self.check_wizard(wizard, 'wizard-optical-work-order-step') self.click(wizard.next_button) # OpticalWorkOrderItem Step step = wizard.get_current_step() for barcode in [batch.batch_number, sellable.barcode, sellable2.barcode, sellable4.barcode, sellable5.barcode]: step.barcode.set_text(barcode) self.activate(step.barcode) step.quantity.update(1) self.click(step.add_sellable_button) for item in step.slave.klist: if item.sellable == sellable4: wo_item = WorkOrderItem.get_from_sale_item(self.store, item) wo_item.quantity_decreased = 10 self.check_wizard(wizard, 'wizard-optical-item-step', [sale, client, sale.invoice] + list(sale.get_items().order_by('te_id'))) module = 'stoqlib.gui.events.SaleQuoteWizardFinishEvent.emit' with mock.patch(module) as emit: with mock.patch.object(self.store, 'commit'): self.click(wizard.next_button) self.assertEqual(emit.call_count, 1) args, kwargs = emit.call_args self.assertTrue(isinstance(args[0], Sale)) self.assertEqual(wizard.model.payments.count(), 0) yesno.assert_called_once_with(_('Would you like to print the quote ' 'details now?'), Gtk.ResponseType.YES, _("Print quote details"), _("Don't print")) # Test get_saved_items, using the existing model here wizard2 = OpticalSaleQuoteWizard(self.store, model=wizard.model) self.click(wizard2.next_button) self.click(wizard2.next_button)
def _setup_patient(self, sale_item): wo_item = WorkOrderItem.get_from_sale_item(self.store, sale_item) optical_wo = self.store.find( OpticalWorkOrder, work_order=wo_item.order).one() sale_item._patient = optical_wo.patient
def test_storm_loaded(self): item = WorkOrderItem.__new__(WorkOrderItem) item.quantity = 10 item.__storm_loaded__() self.assertEquals(item._original_quantity, item.quantity)