def _get_session(): global _session global _last_gc # Indexing some session data by the USER_HASH will help to avoid # maintaining sessions between two different databases. This could lead to # some errors in the POS in which the user making the sale does not exist. session_file = os.path.join( get_application_dir(), 'session-{}.db'.format(_get_user_hash())) if os.path.exists(session_file): with open(session_file, 'rb') as f: try: _session = pickle.load(f) except Exception: _session = {} else: _session = {} # From time to time remove old entries from the session dict now = localnow() if now - (_last_gc or datetime.datetime.min) > _expire_time: for k, v in list(_session.items()): if now - v['date'] > _expire_time: del _session[k] _last_gc = localnow() yield _session with open(session_file, 'wb') as f: pickle.dump(_session, f)
def test_get_interest(self): method = PaymentMethod.get_by_name(self.store, u"check") payment = Payment( value=currency(100), branch=self.create_branch(), due_date=localnow(), open_date=localnow(), method=method, group=None, till=None, category=None, payment_type=Payment.TYPE_OUT, store=self.store, ) for day, expected_value in [(0, 0), (-1, 0), (-30, 0), (30, 0)]: payment.due_date = self._get_relative_day(day) self.assertEqual(payment.get_interest(), currency(expected_value)) method.daily_interest = Decimal(1) for day, expected_value in [(0, 0), (-1, 1), (-30, 30), (30, 0)]: payment.due_date = self._get_relative_day(day) self.assertEqual(payment.get_interest(), currency(expected_value)) due_date = self._get_relative_day(-15) paid_date = self._get_relative_day(-5) payment.due_date = payment.open_date = due_date method.daily_interest = Decimal(2) self.assertEqual(payment.get_interest(paid_date.date()), currency(20)) self.assertEqual(payment.get_interest(due_date.date()), currency(0)) for day in (18, -18): paid_date = self._get_relative_day(day) self.assertRaises(ValueError, payment.get_interest, paid_date.date())
def wrapper(*args, **kwargs): session_id = request.headers.get('stoq-session', None) # FIXME: Remove this once all frontends are updated. if session_id is None: abort(401, 'No session id provided in header') user_id = request.headers.get('stoq-user', None) with api.new_store() as store: user = store.get(LoginUser, user_id or session_id) if user: provide_utility(ICurrentUser, user, replace=True) return f(*args, **kwargs) with _get_session() as s: session_data = s.get(session_id, None) if session_data is None: abort(401, 'Session does not exist') if localnow() - session_data['date'] > _expire_time: abort(401, 'Session expired') # Refresh last date to avoid it expiring while being used session_data['date'] = localnow() session['user_id'] = session_data['user_id'] with api.new_store() as store: user = store.get(LoginUser, session['user_id']) provide_utility(ICurrentUser, user, replace=True) return f(*args, **kwargs)
def test_sync(self): results = self.store.find(BranchSynchronization, branch=self.branch) self.assertEqual(results.count(), 0) t1 = localnow() # Datetime columns doesn't store microseconds t1 = t1.replace(microsecond=0) obj = BranchSynchronization(branch=self.branch, policy=u"shop", sync_time=t1, store=self.store) results = self.store.find(BranchSynchronization, branch=self.branch) self.assertEqual(results.count(), 1) self.assertEqual(results[0], obj) # FIXME: Storm is not using the right resolution self.assertEqual(obj.sync_time.date(), t1.date()) self.assertEqual(obj.policy, u"shop") self.assertEqual(obj.branch, self.branch) t2 = localnow() # Datetime columns doesn't store microseconds t2 = t2.replace(microsecond=0) obj.sync_time = t2 results = self.store.find(BranchSynchronization, branch=self.branch) self.assertEqual(results.count(), 1) self.assertEqual(results[0], obj) # FIXME: Storm is not using the right resolution self.assertEqual(obj.sync_time.date(), t2.date()) self.assertEqual(obj.policy, u"shop") self.assertEqual(obj.branch, self.branch)
def on_object_changed(self, attr, old_value, value): if attr == 'cost': self.cost_last_updated = localnow() if self.product: self.product.update_product_cost(value) elif attr == 'base_price': self.price_last_updated = localnow()
def test_get_interest(self): method = PaymentMethod.get_by_name(self.store, u'check') payment = Payment(value=currency(100), branch=self.create_branch(), station=self.current_station, due_date=localnow(), open_date=localnow(), method=method, group=None, category=None, payment_type=Payment.TYPE_OUT, store=self.store) for day, expected_value in [(0, 0), (-1, 0), (-30, 0), (30, 0)]: payment.due_date = self._get_relative_day(day) self.assertEqual(payment.get_interest(), currency(expected_value)) method.daily_interest = Decimal(1) for day, expected_value in [(0, 0), (-1, 1), (-30, 30), (30, 0)]: payment.due_date = self._get_relative_day(day) self.assertEqual(payment.get_interest(), currency(expected_value)) due_date = self._get_relative_day(-15) paid_date = self._get_relative_day(-5) payment.due_date = payment.open_date = due_date method.daily_interest = Decimal(2) self.assertEqual(payment.get_interest(paid_date.date()), currency(20)) self.assertEqual(payment.get_interest(due_date.date()), currency(0)) for day in (18, -18): paid_date = self._get_relative_day(day) self.assertRaises(ValueError, payment.get_interest, paid_date.date())
def on_object_changed(self, attr, old_value, value): if attr == 'cost': self.cost_last_updated = localnow() if (self.product and sysparam.get_bool('UPDATE_PRODUCT_COST_ON_COMPONENT_UPDATE')): self.product.update_production_cost(value) elif attr == 'base_price': self.price_last_updated = localnow()
def on_object_changed(self, attr, old_value, value): if attr == 'cost': self.cost_last_updated = localnow() if (self.product and sysparam.get_bool( 'UPDATE_PRODUCT_COST_ON_COMPONENT_UPDATE')): self.product.update_production_cost(value) elif attr == 'base_price': self.price_last_updated = localnow()
def create_fiscal_day_history(self): from stoqlib.domain.devices import FiscalDayHistory return FiscalDayHistory(emission_date=localnow(), reduction_date=localnow(), serial=u"123456", serial_id=12345, coupon_start=1, coupon_end=100, cro=1, crz=1, period_total=100, total=100, station=self.create_station(), store=self.store)
def test_get_paid_date_string(self): method = PaymentMethod.get_by_name(self.store, u'check') payment = Payment(value=currency(100), branch=self.create_branch(), due_date=localnow(), method=method, group=None, category=None, payment_type=Payment.TYPE_OUT, store=self.store) today = localnow().strftime(u'%x') self.failIf(payment.get_paid_date_string() == today) payment.set_pending() payment.pay() self.failUnless(payment.get_paid_date_string() == today)
def test_new(self): with self.assertRaises(TypeError): Payment(due_date=localnow(), branch=self.create_branch(), payment_type=Payment.TYPE_OUT, store=self.store) payment = Payment(value=currency(10), due_date=localnow(), branch=self.create_branch(), method=None, group=None, category=None, payment_type=Payment.TYPE_OUT, store=self.store) self.failUnless(payment.status == Payment.STATUS_PREVIEW)
def test_new(self): with self.assertRaises(TypeError): Payment(due_date=localnow(), branch=self.create_branch(), payment_type=Payment.TYPE_OUT, store=self.store) payment = Payment(value=currency(10), due_date=localnow(), branch=self.create_branch(), method=None, group=None, category=None, payment_type=Payment.TYPE_OUT, store=self.store) self.assertTrue(payment.status == Payment.STATUS_PREVIEW)
def receive(self): """Receive the package on the :attr:`.destination_branch` This will mark the package as received in the branch to receive it there. Note that it's only possible to call this on the same branch as :attr:`.destination_branch`. When calling this, the work orders' :attr:`WorkOrder.current_branch` will be set to :attr:`.destination_branch`, since receiving means they got to their destination. """ assert self.can_receive() if self.destination_branch != get_current_branch(self.store): raise ValueError( _("This package's destination branch is %s and you are in %s. " "It's not possible to receive a package outside the " "destination branch") % ( self.destination_branch, get_current_branch(self.store))) for order in [item.order for item in self.package_items]: assert order.current_branch is None # The order is in destination branch now order.current_branch = self.destination_branch self.receive_date = localnow() self.status = self.STATUS_RECEIVED
def send(self): """Send the package to the :attr:`.destination_branch` This will mark the package as sent. Note that it's only possible to call this on the same branch as :attr:`.source_branch`. When calling this, the work orders' :attr:`WorkOrder.current_branch` will be ``None``, since they are on a package and not on any branch. """ assert self.can_send() if self.source_branch != get_current_branch(self.store): raise ValueError( _("This package's source branch is %s and you are in %s. " "It's not possible to send a package outside the " "source branch") % ( self.source_branch, get_current_branch(self.store))) workorders = [item.order for item in self.package_items] if not len(workorders): raise ValueError(_("There're no orders to send")) for order in workorders: assert order.current_branch == self.source_branch # The order is going to leave the current_branch order.current_branch = None self.send_date = localnow() self.status = self.STATUS_SENT
def on_confirm(self): if self._is_default_salesperson_role(): if self.salesperson: if not self.salesperson.is_active: self.salesperson.activate() else: store = self.store self.salesperson = SalesPerson(person=self.person, store=store) elif self.salesperson: if self.salesperson.is_active: self.salesperson.inactivate() old_salary = self.employee.salary self.employee.salary = self.model.salary if (self.model.role is not self.employee.role or old_salary != self.model.salary): self.employee.role = self.model.role if self.current_role_history: self.current_role_history.salary = old_salary self.current_role_history.ended = localnow() self.current_role_history.is_active = False else: # XXX This will prevent problems when you can't update # the connection. self.store.remove(self.model)
def undo(self, reason): """Undo this returned sale. This includes removing the returned items from stock again (updating the quantity decreased on the sale). :param reason: The reason for this operation. """ assert self.can_undo() for item in self.get_items(): item.undo() # We now need to create a new in payment for the total amount of this # returned sale. method_name = self._guess_payment_method() method = PaymentMethod.get_by_name(self.store, method_name) description = _(u'%s return undone for sale %s') % ( method.description, self.sale.identifier) payment = method.create_payment(Payment.TYPE_IN, payment_group=self.group, branch=self.branch, value=self.returned_total, description=description) payment.set_pending() payment.pay() self.status = self.STATUS_CANCELLED self.cancel_date = localnow() self.undo_reason = reason # if the sale status is returned, we must reset it to confirmed (only # confirmed sales can be returned) if self.sale.is_returned(): self.sale.set_not_returned()
def test_is_p_cred_sn_valid(self): icms_template = self.create_product_icms_template(crt=1) self.assertTrue(icms_template.is_p_cred_sn_valid()) expire_date = localnow() icms_template.p_cred_sn_valid_until = expire_date self.assertTrue(icms_template.is_p_cred_sn_valid()) expire_date = localnow() + relativedelta(days=+1) icms_template.p_cred_sn_valid_until = expire_date self.assertTrue(icms_template.is_p_cred_sn_valid()) expire_date = localnow() + relativedelta(days=-1) icms_template.p_cred_sn_valid_until = expire_date self.assertFalse(icms_template.is_p_cred_sn_valid())
def create_inventory(cls, store, branch, responsible, query=None): """Create a inventory with products that match the given query :param store: A store to open the inventory in :param query: A query to restrict the products that should be in the inventory. """ inventory = cls(store=store, open_date=localnow(), branch_id=branch.id, responsible_id=responsible.id) for data in cls.get_sellables_for_inventory(store, branch, query): sellable, product, storable, batch, stock_item = data quantity = stock_item and stock_item.quantity or 0 if storable.is_batch: # This used to test 'stock_item.quantity > 0' too to avoid # creating inventory items for old batches not used anymore. # We can't do that since that would make it impossible to # adjust a batch that was wrongly set to 0. We need to find a # way to mark the batches as "not used anymore" because they # tend to grow to very large proportions and we are duplicating # everyone here if batch and stock_item: inventory.add_storable(storable, quantity, batch=batch) else: inventory.add_storable(storable, quantity) return inventory
def createInPayments(self, no=3): sale = self.create_sale() d = localnow() method = PaymentMethod.get_by_name(self.store, self.method_type) payments = method.create_payments(Payment.TYPE_IN, sale.group, sale.branch, Decimal(100), [d] * no) return payments
def receive(self): """Receive the package on the :attr:`.destination_branch` This will mark the package as received in the branch to receive it there. Note that it's only possible to call this on the same branch as :attr:`.destination_branch`. When calling this, the work orders' :attr:`WorkOrder.current_branch` will be set to :attr:`.destination_branch`, since receiving means they got to their destination. """ assert self.can_receive() if self.destination_branch != get_current_branch(self.store): raise ValueError( _("This package's destination branch is %s and you are in %s. " "It's not possible to receive a package outside the " "destination branch") % (self.destination_branch, get_current_branch(self.store))) for order in [item.order for item in self.package_items]: assert order.current_branch is None # The order is in destination branch now order.current_branch = self.destination_branch self.receive_date = localnow() self.status = self.STATUS_RECEIVED
def on_confirm(self): if self._is_default_salesperson_role(): if self.sales_person: if not self.sales_person.is_active: self.sales_person.activate() else: store = self.store self.sales_person = SalesPerson(person=self.person, store=store) elif self.sales_person: if self.sales_person.is_active: self.sales_person.inactivate() old_salary = self.employee.salary self.employee.salary = self.model.salary if (self.model.role is not self.employee.role or old_salary != self.model.salary): self.employee.role = self.model.role if self.current_role_history: self.current_role_history.salary = old_salary self.current_role_history.ended = localnow() self.current_role_history.is_active = False else: # XXX This will prevent problems when you can't update # the connection. self.store.remove(self.model)
def create_account_transaction(self, account=None, value=1, source=None, incoming=False): from stoqlib.domain.account import AccountTransaction if account is None: account = self.create_account() if source: source_id = source.id else: source_id = sysparam.get_object_id('IMBALANCE_ACCOUNT') if incoming: operation_type = AccountTransaction.TYPE_IN else: operation_type = AccountTransaction.TYPE_OUT return AccountTransaction( description=u"Test Account Transaction", code=u"Code", date=localnow(), value=value, account=account, source_account_id=source_id, operation_type=operation_type, store=self.store)
def add_payments(self, obj, method_type=u'money', installments=1, date=None): from stoqlib.domain.payment.payment import Payment from stoqlib.domain.purchase import PurchaseOrder from stoqlib.domain.sale import Sale from stoqlib.domain.stockdecrease import StockDecrease assert installments > 0 if not date: date = localnow() elif isinstance(date, datetime.date): date = localdate(date.year, date.month, date.day) if isinstance(obj, (Sale, StockDecrease)): if isinstance(obj, Sale): value = obj.get_total_sale_amount() else: value = obj.get_total_cost() payment_type = Payment.TYPE_IN elif isinstance(obj, PurchaseOrder): value = obj.get_purchase_total() payment_type = Payment.TYPE_OUT else: raise ValueError(obj) method = self.get_payment_method(method_type) payments = method.create_payments( payment_type=payment_type, group=obj.group, branch=obj.branch, value=value, due_dates=self.create_installment_dates(date, installments)) for p in payments: p.open_date = date return payments
def orm_get_random(column): if isinstance(column, Reference): return None variable = column.variable_factory.func if issubclass(variable, UnicodeVariable): value = u'' elif issubclass(variable, RawStrVariable): value = '' elif issubclass(variable, DateTimeVariable): value = localnow() elif issubclass(variable, IntVariable): value = None elif issubclass(variable, PriceVariable): value = currency(20) elif issubclass(variable, BoolVariable): value = False elif isinstance(variable, QuantityVariable): value = decimal.Decimal(1) elif issubclass(variable, DecimalVariable): value = decimal.Decimal(1) else: raise ValueError(column) return value
def add_payments(self, obj, method_type=u'money', installments=1, date=None): from stoqlib.domain.payment.payment import Payment from stoqlib.domain.purchase import PurchaseOrder from stoqlib.domain.sale import Sale from stoqlib.domain.stockdecrease import StockDecrease assert installments > 0 if not date: date = localnow() elif isinstance(date, datetime.date): date = localdate(date.year, date.month, date.day) if isinstance(obj, (Sale, StockDecrease)): if isinstance(obj, Sale): value = obj.get_total_sale_amount() else: value = obj.get_total_cost() payment_type = Payment.TYPE_IN elif isinstance(obj, PurchaseOrder): value = obj.get_purchase_total() payment_type = Payment.TYPE_OUT else: # pragma: nocover raise ValueError(obj) method = self.get_payment_method(method_type) payments = method.create_payments( payment_type=payment_type, group=obj.group, branch=obj.branch, value=value, due_dates=self.create_installment_dates(date, installments)) for p in payments: p.open_date = date return payments
def send(self): """Send the package to the :attr:`.destination_branch` This will mark the package as sent. Note that it's only possible to call this on the same branch as :attr:`.source_branch`. When calling this, the work orders' :attr:`WorkOrder.current_branch` will be ``None``, since they are on a package and not on any branch. """ assert self.can_send() if self.source_branch != get_current_branch(self.store): raise ValueError( _("This package's source branch is %s and you are in %s. " "It's not possible to send a package outside the " "source branch") % (self.source_branch, get_current_branch(self.store))) workorders = [item.order for item in self.package_items] if not len(workorders): raise ValueError(_("There're no orders to send")) for order in workorders: assert order.current_branch == self.source_branch # The order is going to leave the current_branch order.current_branch = None self.send_date = localnow() self.status = self.STATUS_SENT
def test_is_p_cred_sn_valid(self): icms_template = self.create_product_icms_template() self.assertTrue(icms_template.is_p_cred_sn_valid()) expire_date = localnow() icms_template.p_cred_sn_valid_until = expire_date self.assertTrue(icms_template.is_p_cred_sn_valid()) expire_date = localnow() + relativedelta(days=+1) icms_template.p_cred_sn_valid_until = expire_date self.assertTrue(icms_template.is_p_cred_sn_valid()) expire_date = localnow() + relativedelta(days=-1) icms_template.p_cred_sn_valid_until = expire_date self.assertFalse(icms_template.is_p_cred_sn_valid())
def price(self): if self.on_sale_price: today = localnow() start_date = self.on_sale_start_date end_date = self.on_sale_end_date if is_date_in_interval(today, start_date, end_date): return self.on_sale_price return self.base_price
def __init__(self, store): self.open_date = localnow() self.branch = api.get_current_branch(store) self.branch_name = self.branch.get_description() self.user = api.get_current_user(store) self.product_manufacturer = None self.product_brand = None self.product_family = None
def get_opening_date(self): # self.till is None only in the special case that the user added the ECF # to Stoq with a pending reduce Z, so we need to close the till on the # ECF, but not on Stoq. # Return a date in the past if not self.till: return localnow() - timedelta(1) return self.till.opening_date
def createOutPayments(self, no=3): purchase = self.create_purchase_order() d = localnow() method = PaymentMethod.get_by_name(self.store, self.method_type) payments = method.create_payments(Payment.TYPE_OUT, purchase.group, purchase.branch, Decimal(100), [d] * no) return payments
def test_needs_closing(self): till = Till(station=self.create_station(), store=self.store) self.failIf(till.needs_closing()) till.open_till() self.failIf(till.needs_closing()) till.opening_date = localnow() - datetime.timedelta(1) self.failUnless(till.needs_closing()) till.close_till() self.failIf(till.needs_closing())
def test_calls(self): person = self.create_person() user = self.create_user() self.assertEquals(len(list(person.calls)), 0) call = Calls(store=self.store, date=localnow(), description=u'', message=u'', person=person, attendant=user) self.assertEquals(len(list(person.calls)), 1) self.assertEquals(list(person.calls)[0], call)
def approve(self): """Approves this work order Approving means that the |client| has accepted the work's quote and it's cost and it can now start. """ assert self.can_approve() self.approve_date = localnow() self.status = self.STATUS_APPROVED
def is_on_sale(self): """Check if the price is currently on sale. :return: ``True`` if it is on sale, ``False`` otherwise """ if not self.on_sale_price: return False return is_date_in_interval( localnow(), self.on_sale_start_date, self.on_sale_end_date)
def cancel(self, responsible, cancel_date=None): """Cancel a transfer order""" assert self.can_cancel() for item in self.get_items(): item.cancel() self.cancel_date = cancel_date or localnow() self.cancel_responsible_id = responsible.id self.status = self.STATUS_CANCELLED
def testIsPCredSnValid(self): tax_template = ProductTaxTemplate( store=self.store, tax_type=ProductTaxTemplate.TYPE_ICMS) icms_template = ProductIcmsTemplate(store=self.store, product_tax_template=tax_template) self.assertTrue(icms_template.is_p_cred_sn_valid()) expire_date = localnow() icms_template.p_cred_sn_valid_until = expire_date self.assertTrue(icms_template.is_p_cred_sn_valid()) expire_date = localnow() + relativedelta(days=+1) icms_template.p_cred_sn_valid_until = expire_date self.assertTrue(icms_template.is_p_cred_sn_valid()) expire_date = localnow() + relativedelta(days=-1) icms_template.p_cred_sn_valid_until = expire_date self.assertFalse(icms_template.is_p_cred_sn_valid())
def is_on_sale(self): """Check if the price is currently on sale. :return: ``True`` if it is on sale, ``False`` otherwise """ if not self.on_sale_price: return False return is_date_in_interval(localnow(), self.on_sale_start_date, self.on_sale_end_date)
def confirm(self, login_user): """Receive the returned_sale_items from a pending |returned_sale| :param user: the |login_user| that received the pending returned sale """ assert self.status == self.STATUS_PENDING self._return_items() self.status = self.STATUS_CONFIRMED self.confirm_responsible = login_user self.confirm_date = localnow()
def receive(self, responsible, receival_date=None): """Confirms the receiving of the transfer order. """ assert self.can_receive() for item in self.get_items(): item.receive() self.receival_date = receival_date or localnow() self.destination_responsible = responsible self.status = self.STATUS_RECEIVED
def test_needs_closing(self): till = Till(station=self.create_station(), store=self.store) self.assertFalse(till.needs_closing()) # Till is opened today, no need to close till.open_till() self.assertFalse(till.needs_closing()) # till was onpened yesterday. Should close till.opening_date = localnow() - datetime.timedelta(1) self.assertTrue(till.needs_closing()) # Till was opened yesterday, but there is a tolerance tolerance = int((localnow() - localtoday()).seconds / (60 * 60)) + 1 with self.sysparam(TILL_TOLERANCE_FOR_CLOSING=tolerance): self.assertFalse(till.needs_closing()) # Till is now closed, no need to close again till.close_till() self.assertFalse(till.needs_closing())
def test_till_open_previously_not_closed(self): yesterday = localnow() - datetime.timedelta(1) # Open a till, set the opening_date to yesterday till = Till(station=get_current_station(self.store), store=self.store) till.open_till() till.opening_date = yesterday till.close_till() till.closing_date = None self.assertRaises(TillError, till.open_till)
def finish(self): """Finishes this work order's task The :obj:`.execution_responsible` has finished working on this order's task. It's possible now to give the equipment back to the |client| and create a |sale| so we are able to :meth:`close <.close>` this order. """ assert self.can_finish() self.finish_date = localnow() self.status = self.STATUS_WORK_FINISHED