Example #1
0
    def _get_next_batch_number(self):
        max_db = StorableBatch.get_max_batch_number(self.store)
        max_used = max_value_for(self._get_used_batches() | set([max_db]))
        if not api.sysparam.get_bool('SYNCHRONIZED_MODE'):
            return next_value_for(max_used)

        # On synchronized mode we need to append the branch acronym
        # to avoid conflicts
        max_used_list = max_used.split('-')
        if len(max_used_list) == 1:
            # '123'
            max_used = max_used_list[0]
        elif len(max_used_list) == 2:
            # '123-AB'
            max_used = max_used_list[0]
        else:
            # TODO: Maybe we should allow only one dash in the batch number
            # '123-456-AB'
            max_used = ''.join(max_used_list[:-1])

        branch = api.get_current_branch(self.store)
        if not branch.acronym:
            raise ValueError("branch '%s' needs an acronym since we are on "
                             "synchronized mode" % (branch.get_description(),))
        return '-'.join([next_value_for(max_used), branch.acronym])
Example #2
0
    def get_order_item(self,
                       sellable,
                       price,
                       quantity,
                       batch=None,
                       parent=None):
        if parent:
            if parent.sellable.product.is_package:
                component = self.get_component(parent, sellable)
                quantity = parent.quantity * component.quantity
                price = component.price
            else:
                # Do not add the components if its not a package product
                return

        if batch is not None:
            batch = StorableBatch.get_or_create(
                self.store,
                storable=sellable.product_storable,
                batch_number=batch)

        item = ReturnedSaleItem(store=self.store,
                                quantity=quantity,
                                price=price,
                                sellable=sellable,
                                batch=batch,
                                returned_sale=self.model,
                                parent_item=parent)
        _adjust_returned_sale_item(item)
        WizardAddSellableEvent.emit(self.wizard, item)
        return item
Example #3
0
    def get_order_item(self, sellable, price, quantity, batch=None, parent=None):
        if parent:
            if parent.sellable.product.is_package:
                component = self.get_component(parent, sellable)
                quantity = parent.quantity * component.quantity
                price = component.price
            else:
                # Do not add the components if its not a package product
                return

        if batch is not None:
            batch = StorableBatch.get_or_create(
                self.store,
                storable=sellable.product_storable,
                batch_number=batch)

        item = ReturnedSaleItem(
            store=self.store,
            quantity=quantity,
            price=price,
            sellable=sellable,
            batch=batch,
            returned_sale=self.model,
            parent_item=parent
        )
        _adjust_returned_sale_item(item)
        WizardAddSellableEvent.emit(self.wizard, item)
        return item
    def _get_next_batch_number(self):
        max_db = StorableBatch.get_max_value(self.store,
                                             StorableBatch.batch_number)
        max_used = max_value_for(self._get_used_batches() | set([max_db]))
        if not api.sysparam.get_bool('SYNCHRONIZED_MODE'):
            return next_value_for(max_used)

        # On synchronized mode we need to append the branch acronym
        # to avoid conflicts
        max_used_list = max_used.split('-')
        if len(max_used_list) == 1:
            # '123'
            max_used = max_used_list[0]
        elif len(max_used_list) == 2:
            # '123-AB'
            max_used = max_used_list[0]
        else:
            # '123-456-AB'
            max_used = ''.join(max_used_list[:-1])

        branch = api.get_current_branch(self.store)
        if not branch.acronym:
            raise ValueError("branch '%s' needs an acronym since we are on "
                             "synchronized mode" % (branch.get_description(),))
        return '-'.join([next_value_for(max_used), branch.acronym])
Example #5
0
    def add_sellable(self, sellable, batch_number=None):
        """Add a sellable in this inventory

        Note that the :attr:`item's quantity <InventoryItem.recorded_quantity>`
        will be set based on the registered sellable's stock

        :param sellable: the |sellable| to be added
        :param batch_number: a batch number representing a |batch|
            for the given sellable. It's used like that instead of
            getting the |batch| directly since we may be adding an item
            not registered before
        """
        product = sellable.product
        storable = product.storable
        if storable is None:
            raise TypeError("product %r has no storable" % (product, ))

        if batch_number is not None:
            batch = StorableBatch.get_or_create(self.store,
                                                storable=storable,
                                                batch_number=batch_number)
            quantity = batch.get_balance_for_branch(self.branch)
        else:
            batch = None
            quantity = storable.get_balance_for_branch(self.branch)

        self.validate_batch(batch, sellable)

        return InventoryItem(store=self.store,
                             product=sellable.product,
                             batch=batch,
                             product_cost=sellable.cost,
                             recorded_quantity=quantity,
                             inventory=self)
Example #6
0
    def add_storable(self, storable, quantity,
                     batch_number=None, batch=None):
        """Add a storable to this inventory.

        The parameters product, storable and batch are passed here to avoid
        future queries, increase the performance when opening the inventory

        :param storable: the |storable| to be added
        :param quantity: the current quantity of the product in stock
        :param batch_number: a batch number representing a |batch|
            for the given sellable. It's used like that instead of
            getting the |batch| directly since we may be adding an item
            not registered before
        :param batch: the corresponding batch to the batch_number
        """
        if batch_number is not None and not batch:
            batch = StorableBatch.get_or_create(self.store,
                                                storable=storable,
                                                batch_number=batch_number)

        product = storable.product
        sellable = product.sellable
        self.validate_batch(batch, sellable, storable=storable)
        return InventoryItem(store=self.store,
                             product=product,
                             batch=batch,
                             product_cost=sellable.cost,
                             recorded_quantity=quantity,
                             inventory=self)
Example #7
0
    def add_storable(self, storable, quantity, batch_number=None, batch=None):
        """Add a storable to this inventory.

        The parameters product, storable and batch are passed here to avoid
        future queries, increase the performance when opening the inventory

        :param storable: the |storable| to be added
        :param quantity: the current quantity of the product in stock
        :param batch_number: a batch number representing a |batch|
            for the given sellable. It's used like that instead of
            getting the |batch| directly since we may be adding an item
            not registered before
        :param batch: the corresponding batch to the batch_number
        """
        if batch_number is not None and not batch:
            batch = StorableBatch.get_or_create(self.store,
                                                storable=storable,
                                                batch_number=batch_number)

        product = storable.product
        sellable = product.sellable
        self.validate_batch(batch, sellable, storable=storable)
        return InventoryItem(store=self.store,
                             product=product,
                             batch=batch,
                             product_cost=sellable.cost,
                             recorded_quantity=quantity,
                             inventory=self)
Example #8
0
    def add_sellable(self, sellable, batch_number=None):
        """Add a sellable in this inventory

        Note that the :attr:`item's quantity <InventoryItem.recorded_quantity>`
        will be set based on the registered sellable's stock

        :param sellable: the |sellable| to be added
        :param batch_number: a batch number representing a |batch|
            for the given sellable. It's used like that instead of
            getting the |batch| directly since we may be adding an item
            not registered before
        """
        product = sellable.product
        storable = product.storable
        if storable is None:
            raise TypeError("product %r has no storable" % (product, ))

        if batch_number is not None:
            batch = StorableBatch.get_or_create(self.store,
                                                storable=storable,
                                                batch_number=batch_number)
            quantity = batch.get_balance_for_branch(self.branch)
        else:
            batch = None
            quantity = storable.get_balance_for_branch(self.branch)

        self.validate_batch(batch, sellable)

        return InventoryItem(store=self.store,
                             product=sellable.product,
                             batch=batch,
                             product_cost=sellable.cost,
                             recorded_quantity=quantity,
                             inventory=self)
Example #9
0
 def create_storable_batch(self, storable=None, batch_number=u'1'):
     from stoqlib.domain.product import StorableBatch
     if not storable:
         storable = self.create_storable()
     return StorableBatch(store=self.store,
                          storable=storable,
                          batch_number=batch_number)
Example #10
0
    def validate_entry(self, entry):
        batch_number = str(entry.get_text())
        if not batch_number:
            return

        available = StorableBatch.is_batch_number_available(
            self.store, batch_number, exclude_storable=self.model)
        if (not available or
            batch_number in self._get_used_batches(exclude=batch_number)):
            return ValidationError(_("'%s' is already in use") % batch_number)
    def validate_entry(self, entry):
        batch_number = unicode(entry.get_text())
        if not batch_number:
            return

        available = StorableBatch.is_batch_number_available(
            self.store, batch_number, exclude_storable=self.model)
        if (not available or
            batch_number in self._get_used_batches(exclude=batch_number)):
            return ValidationError(_("'%s' is already in use") % batch_number)
Example #12
0
    def add_purchase_item(self,
                          item,
                          quantity=None,
                          batch_number=None,
                          parent_item=None,
                          ipi_value=0,
                          icms_st_value=0):
        """Add a |purchaseitem| on this receiving order

        :param item: the |purchaseitem|
        :param decimal.Decimal quantity: the quantity of that item.
            If ``None``, it will be get from the item's pending quantity
        :param batch_number: a batch number that will be used to
            get or create a |batch| it will be get from the item's
            pending quantity or ``None`` if the item's |storable|
            is not controlling batches.
        :raises: :exc:`ValueError` when validating the quantity
            and testing the item's order for equality with :obj:`.order`
        """
        pending_quantity = item.get_pending_quantity()
        if quantity is None:
            quantity = pending_quantity

        if not (0 < quantity <= item.quantity):
            raise ValueError("The quantity must be higher than 0 and lower "
                             "than the purchase item's quantity")
        if quantity > pending_quantity:
            raise ValueError("The quantity must be lower than the item's "
                             "pending quantity")

        sellable = item.sellable
        storable = sellable.product_storable
        if batch_number is not None:
            batch = StorableBatch.get_or_create(self.store,
                                                storable=storable,
                                                batch_number=batch_number)
        else:
            batch = None

        self.validate_batch(batch, sellable)

        return ReceivingOrderItem(store=self.store,
                                  sellable=item.sellable,
                                  batch=batch,
                                  quantity=quantity,
                                  cost=item.cost,
                                  ipi_value=ipi_value,
                                  icms_st_value=icms_st_value,
                                  purchase_item=item,
                                  receiving_order=self,
                                  parent_item=parent_item)
Example #13
0
    def get_order_item(self, sellable, price, quantity, batch=None):
        if batch is not None:
            batch = StorableBatch.get_or_create(
                self.store,
                storable=sellable.product_storable,
                batch_number=batch)

        item = ReturnedSaleItem(
            store=self.store,
            quantity=quantity,
            price=price,
            sellable=sellable,
            batch=batch,
            returned_sale=self.model,
        )
        _adjust_returned_sale_item(item)
        return item
Example #14
0
    def add_purchase_item(self, item, quantity=None, batch_number=None,
                          parent_item=None, ipi_value=0, icms_st_value=0):
        """Add a |purchaseitem| on this receiving order

        :param item: the |purchaseitem|
        :param decimal.Decimal quantity: the quantity of that item.
            If ``None``, it will be get from the item's pending quantity
        :param batch_number: a batch number that will be used to
            get or create a |batch| it will be get from the item's
            pending quantity or ``None`` if the item's |storable|
            is not controlling batches.
        :raises: :exc:`ValueError` when validating the quantity
            and testing the item's order for equality with :obj:`.order`
        """
        pending_quantity = item.get_pending_quantity()
        if quantity is None:
            quantity = pending_quantity

        if not (0 < quantity <= item.quantity):
            raise ValueError("The quantity must be higher than 0 and lower "
                             "than the purchase item's quantity")
        if quantity > pending_quantity:
            raise ValueError("The quantity must be lower than the item's "
                             "pending quantity")

        sellable = item.sellable
        storable = sellable.product_storable
        if batch_number is not None:
            batch = StorableBatch.get_or_create(self.store, storable=storable,
                                                batch_number=batch_number)
        else:
            batch = None

        self.validate_batch(batch, sellable)

        return ReceivingOrderItem(
            store=self.store,
            sellable=item.sellable,
            batch=batch,
            quantity=quantity,
            cost=item.cost,
            ipi_value=ipi_value,
            icms_st_value=icms_st_value,
            purchase_item=item,
            receiving_order=self,
            parent_item=parent_item)
Example #15
0
    def get_order_item(self, sellable, price, quantity, batch=None):
        if batch is not None:
            batch = StorableBatch.get_or_create(
                self.store,
                storable=sellable.product_storable,
                batch_number=batch)

        item = ReturnedSaleItem(
            store=self.store,
            quantity=quantity,
            price=price,
            sellable=sellable,
            batch=batch,
            returned_sale=self.model,
        )
        _adjust_returned_sale_item(item)
        return item
Example #16
0
    def test_is_batch_number_available(self):
        self.assertTrue(StorableBatch.is_batch_number_available(
            self.store, u'123'))
        self.assertTrue(StorableBatch.is_batch_number_available(
            self.store, u'321'))

        storable = self.create_storable(is_batch=True)
        self.create_storable_batch(storable=storable, batch_number=u'123')
        self.create_storable_batch(batch_number=u'321')

        # Should not be available anymore since they now exist
        self.assertFalse(StorableBatch.is_batch_number_available(
            self.store, u'123'))
        self.assertFalse(StorableBatch.is_batch_number_available(
            self.store, u'321'))

        # But when excluding storable, only u'123' should be available
        self.assertTrue(StorableBatch.is_batch_number_available(
            self.store, u'123', exclude_storable=storable))
        self.assertFalse(StorableBatch.is_batch_number_available(
            self.store, u'321', exclude_storable=storable))