def test_run_dialog(self): observations = ( u"Mussum ipsum cacilds, vidis litro abertis. " "Consetis adipiscings elitis. Pra la , depois " "divoltis porris, paradis. Paisis, filhis, " "espiritis santis. Me faiz elementum girarzis, " "nisi eros vermeio, in elementis me pra quem e " "amistosis quis leo. Manduma pindureta quium dia " "nois paga. Sapien in monti palavris qui num " "significa nadis i pareci latim. Interessantiss " "quisso pudia ce receita de bolis, mais bolis eu num gostis.") till = self.create_till() till.open_till() till.close_till(observations) model = self.store.find(TillClosedView, id=till.id).one() self.assertEquals(observations, model.observations) self.assertEquals(get_current_user(self.store).get_description(), model.responsible_open_name) self.assertEquals(get_current_user(self.store).get_description(), model.responsible_close_name) self.assertEquals(observations, model.observations) dialog = TillClosedSearch(self.store) dialog.search.refresh() self.assertNotSensitive(dialog._details_slave, ['details_button']) with mock.patch("stoqlib.gui.search.tillsearch.run_dialog") as r_dialog: dialog.results.select(model) self.assertSensitive(dialog._details_slave, ['details_button']) self.click(dialog._details_slave.details_button) r_dialog.assert_called_once_with(TillDetailsDialog, dialog, dialog.store, model)
def test_run_dialog(self): observations = ( u"Mussum ipsum cacilds, vidis litro abertis. " "Consetis adipiscings elitis. Pra la , depois " "divoltis porris, paradis. Paisis, filhis, " "espiritis santis. Me faiz elementum girarzis, " "nisi eros vermeio, in elementis me pra quem e " "amistosis quis leo. Manduma pindureta quium dia " "nois paga. Sapien in monti palavris qui num " "significa nadis i pareci latim. Interessantiss " "quisso pudia ce receita de bolis, mais bolis eu num gostis.") till = self.create_till() till.open_till() till.close_till(observations) model = self.store.find(TillClosedView, id=till.id).one() self.assertEquals(observations, model.observations) self.assertEquals( get_current_user(self.store).get_description(), model.responsible_open_name) self.assertEquals( get_current_user(self.store).get_description(), model.responsible_close_name) self.assertEquals(observations, model.observations) dialog = TillClosedSearch(self.store) dialog.search.refresh() self.assertNotSensitive(dialog._details_slave, ['details_button']) with mock.patch( "stoqlib.gui.search.tillsearch.run_dialog") as r_dialog: dialog.results.select(model) self.assertSensitive(dialog._details_slave, ['details_button']) self.click(dialog._details_slave.details_button) r_dialog.assert_called_once_with(TillDetailsDialog, dialog, dialog.store, model)
def test_trade_without_sale(self): # With discount branch = get_current_branch(self.store) returned_sale = ReturnedSale(store=self.store, responsible=get_current_user(self.store), branch=branch) storable = self.create_storable(branch=branch, stock=10) ReturnedSaleItem(store=self.store, quantity=1, price=10, sellable=storable.product.sellable, returned_sale=returned_sale) new_sale = self.create_sale() returned_sale.new_sale = new_sale balance_before_trade = storable.get_balance_for_branch(branch) with self.sysparam(USE_TRADE_AS_DISCOUNT=True): returned_sale.trade() self.assertEqual(new_sale.discount_value, currency(10)) self.assertEqual(returned_sale.status, ReturnedSale.STATUS_CONFIRMED) self.assertEqual(storable.get_balance_for_branch(branch), balance_before_trade + 1) # Without discount returned_sale2 = ReturnedSale(store=self.store, responsible=get_current_user(self.store), branch=branch) storable = self.create_storable(branch=branch, stock=10) ReturnedSaleItem(store=self.store, quantity=1, price=10, sellable=storable.product.sellable, returned_sale=returned_sale2) new_sale = self.create_sale() returned_sale2.new_sale = new_sale balance_before_trade = storable.get_balance_for_branch(branch) returned_sale2.trade() self.assertEqual(returned_sale.status, ReturnedSale.STATUS_CONFIRMED) self.assertEqual(new_sale.discount_value, currency(0)) group = new_sale.group payment = group.payments[0] self.assertEqual(group.payments.count(), 1) self.assertEqual(payment.value, returned_sale2.returned_total) self.assertEqual(storable.get_balance_for_branch(branch), balance_before_trade + 1)
def confirm(self, confirm_date=None): """Confirms the purchase order :param confirm_data: optional, datetime """ if confirm_date is None: confirm_date = TransactionTimestamp() if self.status not in [PurchaseOrder.ORDER_PENDING, PurchaseOrder.ORDER_CONSIGNED]: raise ValueError( _(u'Invalid order status, it should be ' u'ORDER_PENDING or ORDER_CONSIGNED, got %s') % ( self.get_status_str(), )) transaction = IPaymentTransaction(self) transaction.confirm() if self.supplier: self.group.recipient = self.supplier.person self.responsible = get_current_user(self.store) self.status = PurchaseOrder.ORDER_CONFIRMED self.confirm_date = confirm_date Event.log(Event.TYPE_ORDER, _(u"Order %s, total value %2.2f, supplier '%s' " u"is now confirmed") % (self.identifier, self.get_purchase_total(), self.supplier.person.name))
def create_for_receiving_order(cls, receiving_order): store = receiving_order.store current_user = get_current_user(store) employee = current_user.person.employee cfop_id = sysparam.get_object_id('DEFAULT_STOCK_DECREASE_CFOP') return_stock_decrease = cls( store=store, receiving_order=receiving_order, branch=get_current_branch(store), responsible=current_user, removed_by=employee, cfop_id=cfop_id) for receiving_item in receiving_order.get_items(with_children=False): if receiving_item.is_totally_returned(): # Exclude items already totally returned continue if receiving_item.children_items.count(): for child in receiving_item.children_items: StockDecreaseItem.create_for_receiving_item( return_stock_decrease, child) else: StockDecreaseItem.create_for_receiving_item(return_stock_decrease, receiving_item) return return_stock_decrease
def _update_te(self): user = get_current_user(self.store) station = get_current_station(self.store) self.te_modified.te_time = TransactionTimestamp() self.te_modified.user_id = user and user.id self.te_modified.station_id = station and station.id
def open_till(self): """Open the till. It can only be done once per day. The final cash amount of the previous till will be used as the initial value in this one after opening it. """ if self.status == Till.STATUS_OPEN: raise TillError(_('Till is already open')) # Make sure that the till has not been opened today today = localtoday().date() if not self.store.find(Till, And(Date(Till.opening_date) >= today, Till.station_id == self.station.id)).is_empty(): raise TillError(_("A till has already been opened today")) last_till = self._get_last_closed_till() if last_till: if not last_till.closing_date: raise TillError(_("Previous till was not closed")) initial_cash_amount = last_till.final_cash_amount else: initial_cash_amount = 0 self.initial_cash_amount = initial_cash_amount self.opening_date = TransactionTimestamp() self.status = Till.STATUS_OPEN self.responsible_open = get_current_user(self.store)
def test_on_confirm_without_discount(self): events_before = self.store.find(Event).count() sale_item = self.create_sale_item() current_user = get_current_user(self.store) current_user.profile.max_discount = Decimal('5') # A manager to authorize the discount manager = self.create_user() manager.profile.max_discount = Decimal('10') editor = SaleQuoteItemEditor(self.store, sale_item) slave = editor.item_slave # Try applying 10% of discount slave.price.update(currency('9.00')) # The user is not allowed to give 10% discount self.assertNotSensitive(editor.main_dialog, ['ok_button']) # Lets call the manager and ask for permission with mock.patch('stoq.lib.gui.editors.saleeditor.run_dialog') as rd: rd.return_value = manager slave.price.emit('icon-press', Gtk.EntryIconPosition.PRIMARY, None) # Forget about the discount slave.price.update(currency('10')) # This will not trigger an event self.click(editor.main_dialog.ok_button) events_after = self.store.find(Event).count() # The number of events doesn't changed self.assertEqual(events_after, events_before)
def create_for_receiving_order(cls, receiving_order): store = receiving_order.store current_user = get_current_user(store) employee = current_user.person.employee cfop_id = sysparam.get_object_id('DEFAULT_STOCK_DECREASE_CFOP') return_stock_decrease = cls(store=store, receiving_order=receiving_order, branch=get_current_branch(store), responsible=current_user, removed_by=employee, cfop_id=cfop_id) for receiving_item in receiving_order.get_items(with_children=False): if receiving_item.is_totally_returned(): # Exclude items already totally returned continue if receiving_item.children_items.count(): for child in receiving_item.children_items: StockDecreaseItem.create_for_receiving_item( return_stock_decrease, child) else: StockDecreaseItem.create_for_receiving_item( return_stock_decrease, receiving_item) return return_stock_decrease
def confirm(self, confirm_date=None): """Confirms the purchase order :param confirm_data: optional, datetime """ if confirm_date is None: confirm_date = TransactionTimestamp() if self.status not in [PurchaseOrder.ORDER_PENDING, PurchaseOrder.ORDER_CONSIGNED]: raise ValueError( _(u'Invalid order status, it should be ' u'ORDER_PENDING or ORDER_CONSIGNED, got %s') % ( self.get_status_str(), )) transaction = IPaymentTransaction(self) transaction.confirm() if self.supplier: self.group.recipient = self.supplier.person self.responsible = get_current_user(self.store) self.status = PurchaseOrder.ORDER_CONFIRMED self.confirm_date = confirm_date Event.log(self.store, Event.TYPE_ORDER, _(u"Order %s, total value %2.2f, supplier '%s' " u"is now confirmed") % (self.identifier, self.get_purchase_total(), self.supplier.person.name))
def create_loan(self, branch=None, client=None): from stoqlib.domain.loan import Loan user = get_current_user(self.store) return Loan(responsible=user, client=client, branch=branch or get_current_branch(self.store), store=self.store)
def _update_wizard_model(self): wizard_model = self.wizard.model if wizard_model: # We are replacing the model. Remove old one for item in wizard_model.returned_items: item.delete(item.id, store=item.store) wizard_model.delete(wizard_model.id, store=wizard_model.store) sale_view = self.slave.results.get_selected() # FIXME: Selecting a sale and then clicking on unknown_sale_check # will not really deselect it, not until the results are sensitive # again. This should be as simple as 'if sale_view'. if sale_view and not self.unknown_sale_check.get_active(): sale = self.store.fetch(sale_view.sale) model = sale.create_sale_return_adapter() for item in model.returned_items: _adjust_returned_sale_item(item) else: assert self._allow_unknown_sales() model = ReturnedSale( store=self.store, responsible=get_current_user(self.store), branch=get_current_branch(self.store), ) self.wizard.model = model
def create_payment_renegotiation(self, group=None): from stoqlib.domain.payment.renegotiation import PaymentRenegotiation return PaymentRenegotiation(responsible=get_current_user(self.store), branch=get_current_branch(self.store), group=group or self.create_payment_group(), client=self.create_client(), store=self.store)
def confirm(self, confirm_date=None): """Confirms the purchase order :param confirm_data: optional, datetime """ if confirm_date is None: confirm_date = TransactionTimestamp() if self.status not in [PurchaseOrder.ORDER_PENDING, PurchaseOrder.ORDER_CONSIGNED]: fmt = _(u'Invalid order status, it should be ' u'ORDER_PENDING or ORDER_CONSIGNED, got %s') raise ValueError(fmt % (self.status_str, )) # In consigned purchases there is no payments at this point. if self.status != PurchaseOrder.ORDER_CONSIGNED and self.group: for payment in self.payments: payment.set_pending() if self.supplier and self.group: self.group.recipient = self.supplier.person self.responsible = get_current_user(self.store) self.status = PurchaseOrder.ORDER_CONFIRMED self.confirm_date = confirm_date Event.log(self.store, Event.TYPE_ORDER, _(u"Order %s, total value %2.2f, supplier '%s' " u"is now confirmed") % (self.identifier, self.purchase_total, self.supplier.person.name))
def test_on_confirm_with_discount(self): events_before = self.store.find(Event).count() sale_item = self.create_sale_item() sale_item.sale.identifier = 333123 current_user = get_current_user(self.store) current_user.profile.max_discount = Decimal('5') # A manager to authorize the discount manager = self.create_user() manager.profile.max_discount = Decimal('10') editor = SaleQuoteItemEditor(self.store, sale_item) # Try applying 9% of discount editor.price.update(currency('9.10')) # The user is not allowed to give 10% discount self.assertNotSensitive(editor.main_dialog, ['ok_button']) # Lets call the manager and ask for permission with mock.patch('stoqlib.gui.editors.saleeditor.run_dialog') as rd: rd.return_value = manager editor.price.emit('icon-press', gtk.ENTRY_ICON_PRIMARY, None) # Now it should be possible to confirm self.click(editor.main_dialog.ok_button) events_after = self.store.find(Event).count() self.assertEquals(events_after, events_before + 1) last_event = self.store.find(Event).order_by(Event.id).last() expected = (u'Sale 333123: User username authorized 9.00 % ' u'of discount changing\n Description value from $10.00 to $9.10.') self.assertEquals(last_event.description, expected)
def test_on_confirm_without_discount(self): events_before = self.store.find(Event).count() sale_item = self.create_sale_item() current_user = get_current_user(self.store) current_user.profile.max_discount = Decimal('5') # A manager to authorize the discount manager = self.create_user() manager.profile.max_discount = Decimal('10') editor = SaleQuoteItemEditor(self.store, sale_item) # Try applying 10% of discount editor.price.update(currency('9.00')) # The user is not allowed to give 10% discount self.assertNotSensitive(editor.main_dialog, ['ok_button']) # Lets call the manager and ask for permission with mock.patch('stoqlib.gui.editors.saleeditor.run_dialog') as rd: rd.return_value = manager editor.price.emit('icon-press', gtk.ENTRY_ICON_PRIMARY, None) # Forget about the discount editor.price.update(currency('10')) # This will not trigger an event self.click(editor.main_dialog.ok_button) events_after = self.store.find(Event).count() # The number of events doesn't changed self.assertEquals(events_after, events_before)
def orm_get_unittest_value(klass, test, tables_dict, name, column): value = None if isinstance(column, PropertyColumn): if column.variable_factory.keywords['value'] is not Undef: value = column.variable_factory.keywords['value'] else: try: value = orm_get_random(column) except ValueError: raise ORMTestError(u"No default for %r" % (column, )) elif isinstance(column, Reference): if name == 'te': return None if isinstance(column._remote_key, basestring): cls = tables_dict[column._remote_key.split('.')[0]] else: cls = column._remote_key[0].cls if cls.__name__ == 'LoginUser': # Avoid unique problems on domains that defines 2 references # to LoginUser (e.g. WorkOrder) from stoqlib.database.runtime import get_current_user value = get_current_user(test.store) elif cls.__name__ == 'StorableBatch': # StorableBatch needs some very specific information, that is # related to other objects. Thus, it cannot be created with random # value. value = None else: value = test.create_by_type(cls) if value is None: raise ORMTestError(u"No example for %s" % cls) return value
def confirm(self, confirm_date=None): """Confirms the purchase order :param confirm_data: optional, datetime """ if confirm_date is None: confirm_date = TransactionTimestamp() if self.status not in [PurchaseOrder.ORDER_PENDING, PurchaseOrder.ORDER_CONSIGNED]: fmt = _(u'Invalid order status, it should be ' u'ORDER_PENDING or ORDER_CONSIGNED, got %s') raise ValueError(fmt % (self.status_str, )) # In consigned purchases there is no payments at this point. if self.status != PurchaseOrder.ORDER_CONSIGNED: for payment in self.payments: payment.set_pending() if self.supplier: self.group.recipient = self.supplier.person self.responsible = get_current_user(self.store) self.status = PurchaseOrder.ORDER_CONFIRMED self.confirm_date = confirm_date Event.log(self.store, Event.TYPE_ORDER, _(u"Order %s, total value %2.2f, supplier '%s' " u"is now confirmed") % (self.identifier, self.purchase_total, self.supplier.person.name))
def open_till(self): """Open the till. It can only be done once per day. The final cash amount of the previous till will be used as the initial value in this one after opening it. """ if self.status == Till.STATUS_OPEN: raise TillError(_('Till is already open')) # Make sure that the till has not been opened today today = localtoday().date() if not self.store.find( Till, And( Date(Till.opening_date) >= today, Till.station_id == self.station.id)).is_empty(): raise TillError(_("A till has already been opened today")) last_till = self._get_last_closed_till() if last_till: if not last_till.closing_date: raise TillError(_("Previous till was not closed")) initial_cash_amount = last_till.final_cash_amount else: initial_cash_amount = 0 self.initial_cash_amount = initial_cash_amount self.opening_date = TransactionTimestamp() self.status = Till.STATUS_OPEN self.responsible_open = get_current_user(self.store)
def orm_get_unittest_value(klass, test, tables_dict, name, column): value = None if isinstance(column, PropertyColumn): if column.variable_factory.keywords['value'] is not Undef: value = column.variable_factory.keywords['value'] else: try: value = orm_get_random(column) except ValueError: raise ORMTestError(u"No default for %r" % (column, )) elif isinstance(column, Reference): if name == 'te': return None if isinstance(column._remote_key, str): cls = tables_dict[column._remote_key.split('.')[0]] else: cls = column._remote_key[0].cls if cls.__name__ == 'LoginUser': # Avoid unique problems on domains that defines 2 references # to LoginUser (e.g. WorkOrder) from stoqlib.database.runtime import get_current_user value = get_current_user(test.store) elif cls.__name__ == 'StorableBatch': # StorableBatch needs some very specific information, that is # related to other objects. Thus, it cannot be created with random # value. value = None else: value = test.create_by_type(cls) if value is None: raise ORMTestError(u"No example for %s" % cls) return value
def _update_te(self): user = get_current_user(self.store) station = get_current_station(self.store) self.te.dirty = True self.te.te_time = StatementTimestamp() self.te.user_id = user and user.id self.te.station_id = station and station.id
def create_purchase_order(self, supplier=None, branch=None): from stoqlib.domain.purchase import PurchaseOrder group = self.create_payment_group() return PurchaseOrder(supplier=supplier or self.create_supplier(), branch=branch or self.create_branch(), group=group, responsible=get_current_user(self.store), store=self.store)
def set_consigned(self): if self.status != PurchaseOrder.ORDER_PENDING: raise ValueError( _(u'Invalid order status, it should be ' u'ORDER_PENDING, got %s') % (self.status_str, )) self.responsible = get_current_user(self.store) self.status = PurchaseOrder.ORDER_CONSIGNED
def apply(self): if self.test_type == ProductQualityTest.TYPE_BOOLEAN: value = self.model.boolean_value else: value = self.model.decimal_value for item in self._items: result = item.set_test_result_value(self.model.quality_test, value, get_current_user(self.store)) self.emit('test-updated', item, self.model.quality_test, result)
def test_set_consigned(self): order = self.create_purchase_order() order.status = PurchaseOrder.ORDER_PENDING order.set_consigned() current = get_current_user(store=self.store) self.assertEquals(current, order.responsible) self.assertEquals(order.status, order.ORDER_CONSIGNED) order.status = PurchaseOrder.ORDER_CONFIRMED with self.assertRaises(ValueError): order.set_consigned()
def _logout(self): from stoqlib.database.runtime import (get_current_user, get_default_store) log.debug('Logging out the current user') try: user = get_current_user(get_default_store()) if user: user.logout() except StoqlibError: pass
def increase_stock(self, quantity, branch, type, object_id, unit_cost=None, batch=None): """When receiving a product, update the stock reference for this new item on a specific |branch|. :param quantity: amount to increase :param branch: |branch| that stores the stock :param type: the type of the stock increase. One of the StockTransactionHistory.types :param object_id: the id of the object responsible for the transaction :param unit_cost: unit cost of the new stock or `None` :param batch: The batch of the storable. Should be not ``None`` if self.is_batch is ``True`` """ assert isinstance(type, int) if quantity <= 0: raise ValueError(_(u"quantity must be a positive number")) if branch is None: raise ValueError(u"branch cannot be None") stock_item = self.get_stock_item(branch, batch) # If the stock_item is missing create a new one if stock_item is None: store = self.store stock_item = ProductStockItem(store=store, storable=self, batch=batch, branch=store.fetch(branch)) # Unit cost must be updated here as # 1) we need the stock item which might not exist # 2) it needs to be updated before we change the quantity of the # stock item if unit_cost is not None: stock_item.update_cost(quantity, unit_cost) old_quantity = stock_item.quantity stock_item.quantity += quantity StockTransactionHistory(product_stock_item=stock_item, quantity=quantity, stock_cost=stock_item.stock_cost, responsible=get_current_user(self.store), type=type, object_id=object_id, store=self.store) ProductStockUpdateEvent.emit(self.product, branch, old_quantity, stock_item.quantity)
def decrease_stock(self, quantity, branch, type, object_id, cost_center=None): """When receiving a product, update the stock reference for the sold item this on a specific |branch|. Returns the stock item that was decreased. :param quantity: amount to decrease :param branch: a |branch| :param type: the type of the stock increase. One of the StockTransactionHistory.types :param object_id: the id of the object responsible for the transaction :param cost_center: the |costcenter| to which this stock decrease is related, if any """ # FIXME: Put this back once 1.6 is released #assert isinstance(type, int) if quantity <= 0: raise ValueError(_(u"quantity must be a positive number")) if branch is None: raise ValueError(u"branch cannot be None") stock_item = self.get_stock_item(branch) if stock_item is None or quantity > stock_item.quantity: raise StockError( _('Quantity to sell is greater than the available stock.')) old_quantity = stock_item.quantity stock_item.quantity -= quantity # We emptied the entire stock in all branches, we need to change # the status of the sellable to unavailable as we cannot sell # it anymore if not self.store.find(ProductStockItem, storable=self).sum(ProductStockItem.quantity): sellable = self.product.sellable if sellable: sellable.set_unavailable() stock_transaction = StockTransactionHistory( product_stock_item=stock_item, quantity=-quantity, stock_cost=stock_item.stock_cost, responsible=get_current_user(self.store), type=type, object_id=object_id, store=self.store) if cost_center is not None: cost_center.add_stock_transaction(stock_transaction) ProductStockUpdateEvent.emit(self.product, branch, old_quantity, stock_item.quantity) return stock_item
def _on_object_added(self, obj_info): store = obj_info.get("store") store.block_implicit_flushes() user = get_current_user(store) station = get_current_station(store) store.unblock_implicit_flushes() self.te = TransactionEntry(store=store, te_time=StatementTimestamp(), user_id=user and user.id, station_id=station and station.id)
def decrease_stock(self, quantity, branch, type, object_id, cost_center=None, batch=None): """When receiving a product, update the stock reference for the sold item this on a specific |branch|. Returns the stock item that was decreased. :param quantity: amount to decrease :param branch: a |branch| :param type: the type of the stock increase. One of the StockTransactionHistory.types :param object_id: the id of the object responsible for the transaction :param cost_center: the |costcenter| to which this stock decrease is related, if any :param batch: The batch of the storable. Should be not ``None`` if self.is_batch is ``True`` """ # FIXME: Put this back once 1.6 is released # assert isinstance(type, int) if quantity <= 0: raise ValueError(_(u"quantity must be a positive number")) if branch is None: raise ValueError(u"branch cannot be None") stock_item = self.get_stock_item(branch, batch) if stock_item is None or quantity > stock_item.quantity: raise StockError( _('Quantity to sell is greater than the available stock.')) old_quantity = stock_item.quantity stock_item.quantity -= quantity stock_transaction = StockTransactionHistory( product_stock_item=stock_item, quantity=-quantity, stock_cost=stock_item.stock_cost, responsible=get_current_user(self.store), type=type, object_id=object_id, store=self.store) if cost_center is not None: cost_center.add_stock_transaction(stock_transaction) ProductStockUpdateEvent.emit(self.product, branch, old_quantity, stock_item.quantity) return stock_item
def test_api(): store = api.get_default_store() assert store is get_default_store() assert api.get_current_user(store) is get_current_user(store) assert api.db_settings is db_settings assert api.user_settings is get_settings() assert isinstance(api.device_manager, DeviceManager) with pytest.raises(NotImplementedError): assert isinstance(api.config, IStoqConfig) assert api.is_developer_mode() is is_developer_mode() assert api.get_l10n_field('CPF') is get_l10n_field('CPF')
def increase_stock(self, quantity, branch, type, object_id, unit_cost=None): """When receiving a product, update the stock reference for this new item on a specific |branch|. :param quantity: amount to increase :param branch: |branch| that stores the stock :param type: the type of the stock increase. One of the StockTransactionHistory.types :param object_id: the id of the object responsible for the transaction :param unit_cost: unit cost of the new stock or `None` """ assert isinstance(type, int) if quantity <= 0: raise ValueError(_(u"quantity must be a positive number")) if branch is None: raise ValueError(u"branch cannot be None") stock_item = self.get_stock_item(branch) # If the stock_item is missing create a new one if stock_item is None: store = self.store stock_item = ProductStockItem( storable=self, branch=store.fetch(branch), store=store) # Unit cost must be updated here as # 1) we need the stock item which might not exist # 2) it needs to be updated before we change the quantity of the # stock item if unit_cost is not None: stock_item.update_cost(quantity, unit_cost) old_quantity = stock_item.quantity stock_item.quantity += quantity # If previously lacked quantity change the status of the sellable if not old_quantity: sellable = self.product.sellable if sellable: sellable.can_sell() StockTransactionHistory(product_stock_item=stock_item, quantity=quantity, stock_cost=stock_item.stock_cost, responsible=get_current_user(self.store), type=type, object_id=object_id, store=self.store) ProductStockUpdateEvent.emit(self.product, branch, old_quantity, stock_item.quantity)
def create_stock_decrease(self, branch=None, user=None, reason=u'', group=None): from stoqlib.domain.stockdecrease import StockDecrease employee = self.create_employee() cfop = self.create_cfop_data() return StockDecrease(responsible=user or get_current_user(self.store), removed_by=employee, branch=branch or get_current_branch(self.store), status=StockDecrease.STATUS_INITIAL, cfop=cfop, reason=reason, group=group, store=self.store)
def create_stock_transaction_history(self, product_stock_item=None, stock_cost=0, quantity=0, type=StockTransactionHistory.TYPE_SELL): from stoqlib.domain.product import StockTransactionHistory if product_stock_item is None: product_stock_item = self.create_product_stock_item() return StockTransactionHistory(product_stock_item=product_stock_item, responsible=get_current_user(store=self.store), stock_cost=stock_cost, quantity=quantity, type=type, store=self.store)
def create_receiving_order(self, purchase_order=None, branch=None, user=None): from stoqlib.domain.receiving import ReceivingOrder if purchase_order is None: purchase_order = self.create_purchase_order() cfop = self.create_cfop_data() cfop.code = u'1.102' return ReceivingOrder(store=self.store, invoice_number=222, supplier=purchase_order.supplier, responsible=user or get_current_user(self.store), purchase=purchase_order, branch=branch or get_current_branch(self.store), cfop=cfop)
def _on_object_added(self, obj_info): store = obj_info.get("store") store.block_implicit_flushes() user = get_current_user(store) station = get_current_station(store) store.unblock_implicit_flushes() self.te = TransactionEntry(store=store, te_time=StatementTimestamp(), user_id=user and user.id, station_id=station and station.id) store.add_created_object(self)
def test_branch_combo_items(self): branch = get_current_branch(self.store) user = get_current_user(self.store) product = self.create_product(with_supplier=True) supplier_info = product.get_main_supplier_info() with mock.patch.object(user.profile, 'check_app_permission') as is_admin: # Admin user can set the supplier for any branch is_admin.side_effect = [True, False] editor = ProductSupplierEditor(self.store, supplier_info) self.assertEqual(len(editor.branch_combo.get_model_items()), 2) # Regular user can only set to the current branch editor = ProductSupplierEditor(self.store, supplier_info) items = list(editor.branch_combo.get_model_items().values()) self.assertEqual(len(items), 1) self.assertEqual(items[0], branch)
def _create_domain(self): self.clean_domain([ StockTransactionHistory, ProductSupplierInfo, ProductStockItem, Storable, Product ]) branch = get_current_branch(self.store) user = get_current_user(self.store) self.today = localtoday() product = self.create_product() Storable(store=self.store, product=product, minimum_quantity=3, maximum_quantity=20) product.sellable.code = u'1' product.sellable.description = u'Luvas' product.brand = u'Rawlings' product.internal_use = True product2 = self.create_product() Storable(store=self.store, product=product2, minimum_quantity=4, maximum_quantity=20) product2.sellable.code = u'2' product2.sellable.description = u'Botas' product2.brand = u'Aventura' # Purchase order = self.create_purchase_order(branch=branch) order.identifier = 111 order.open_date = self.today order.status = PurchaseOrder.ORDER_PENDING p_item = order.add_item(product.sellable, 10) p2_item = order.add_item(product2.sellable, 15) order.confirm(self.current_user) # Receiving receiving = self.create_receiving_order(order, branch, user) receiving.identifier = 222 receiving.receival_date = self.today self.create_receiving_order_item(receiving, product.sellable, p_item, 8) self.create_receiving_order_item(receiving, product2.sellable, p2_item, 12) receiving.confirm(self.current_user)
def create_trade(self, trade_value=100): from stoqlib.domain.returnedsale import ReturnedSale, ReturnedSaleItem branch = get_current_branch(self.store) returned_sale = ReturnedSale(store=self.store, responsible=get_current_user(self.store), branch=branch) ReturnedSaleItem(store=self.store, quantity=1, price=trade_value, sellable=self.create_sellable(), returned_sale=returned_sale) new_sale = self.create_sale() product_price = trade_value * 2 self.add_product(new_sale, price=product_price) new_sale.discount_value = trade_value returned_sale.new_sale = new_sale return returned_sale
def _create_domain(self): self.clean_domain([ProductHistory]) branch = get_current_branch(self.store) user = get_current_user(self.store) self.today = localtoday() product = self.create_product() Storable(store=self.store, product=product) product.sellable.code = u'1' product.sellable.description = u'Luvas' product2 = self.create_product() Storable(store=self.store, product=product2) product2.sellable.code = u'2' product2.sellable.description = u'Botas' # Purchase order = self.create_purchase_order(branch=branch) order.identifier = 111 order.open_date = self.today order.status = PurchaseOrder.ORDER_PENDING p_item = order.add_item(product.sellable, 10) p2_item = order.add_item(product2.sellable, 15) order.confirm(self.current_user) # Receiving receiving = self.create_receiving_order(order, branch, user) receiving.identifier = 222 receiving.receival_date = self.today self.create_receiving_order_item(receiving, product.sellable, p_item, 8) self.create_receiving_order_item(receiving, product2.sellable, p2_item, 12) receiving.confirm(self.current_user) # Sale sale = self.create_sale(branch=branch) sale.identifier = 123 sale.open_date = self.today sale.add_sellable(product.sellable, 3) sale.add_sellable(product2.sellable, 5) sale.order(self.current_user) self.add_payments(sale, date=self.today) sale.confirm(self.current_user)
def _create_domain(self): self.clean_domain([ProductHistory]) branch = get_current_branch(self.store) user = get_current_user(self.store) self.today = localtoday() product = self.create_product() Storable(store=self.store, product=product) product.sellable.code = u'1' product.sellable.description = u'Luvas' product2 = self.create_product() Storable(store=self.store, product=product2) product2.sellable.code = u'2' product2.sellable.description = u'Botas' # Purchase order = self.create_purchase_order(branch=branch) order.identifier = 111 order.open_date = self.today order.status = PurchaseOrder.ORDER_PENDING p_item = order.add_item(product.sellable, 10) p2_item = order.add_item(product2.sellable, 15) order.confirm() # Receiving receiving = self.create_receiving_order(order, branch, user) receiving.identifier = 222 receiving.receival_date = self.today self.create_receiving_order_item(receiving, product.sellable, p_item, 8) self.create_receiving_order_item(receiving, product2.sellable, p2_item, 12) receiving.confirm() # Sale sale = self.create_sale(branch=branch) sale.identifier = 123 sale.open_date = self.today sale.add_sellable(product.sellable, 3) sale.add_sellable(product2.sellable, 5) sale.order() self.add_payments(sale, date=self.today) sale.confirm()
def close_till(self, observations=u""): """This method close the current till operation with the confirmed sales associated. If there is a sale with a differente status than SALE_CONFIRMED, a new 'pending' till operation is created and these sales are associated with the current one. """ if self.status == Till.STATUS_CLOSED: raise TillError(_("Till is already closed")) if self.get_balance() < 0: raise ValueError(_("Till balance is negative, but this should not " "happen. Contact Stoq Team if you need " "assistance")) self.final_cash_amount = self.get_balance() self.closing_date = TransactionTimestamp() self.status = Till.STATUS_CLOSED self.observations = observations self.responsible_close = get_current_user(self.store)
def close_till(self, observations=u""): """This method close the current till operation with the confirmed sales associated. If there is a sale with a differente status than SALE_CONFIRMED, a new 'pending' till operation is created and these sales are associated with the current one. """ if self.status == Till.STATUS_CLOSED: raise TillError(_("Till is already closed")) if self.get_balance() < 0: raise ValueError( _("Till balance is negative, but this should not " "happen. Contact Stoq Team if you need " "assistance")) self.final_cash_amount = self.get_balance() self.closing_date = TransactionTimestamp() self.status = Till.STATUS_CLOSED self.observations = observations self.responsible_close = get_current_user(self.store)
def open_till(self): """Open the till. It can only be done once per day. The final cash amount of the previous till will be used as the initial value in this one after opening it. """ if self.status == Till.STATUS_OPEN: raise TillError(_('Till is already open')) manager = get_plugin_manager() # The restriction to only allow opening the till only once per day comes from # the (soon to be obsolete) ECF devices. if manager.is_active('ecf'): # Make sure that the till has not been opened today today = localtoday().date() if not self.store.find( Till, And( Date(Till.opening_date) >= today, Till.station_id == self.station.id)).is_empty(): raise TillError(_("A till has already been opened today")) last_till = self._get_last_closed_till() if last_till: if not last_till.closing_date: raise TillError(_("Previous till was not closed")) initial_cash_amount = last_till.final_cash_amount else: initial_cash_amount = 0 self.initial_cash_amount = initial_cash_amount self.opening_date = TransactionTimestamp() self.status = Till.STATUS_OPEN self.responsible_open = get_current_user(self.store) assert self.responsible_open is not None TillOpenedEvent.emit(self)