Ejemplo n.º 1
0
    def test_can_remove(self):
        branch = get_current_branch(self.store)
        sellable = self.create_sellable()
        storable = Storable(product=sellable.product, store=self.store)
        self.failUnless(sellable.can_remove())

        storable.increase_stock(1, branch, 0, None)
        sale = self.create_sale()
        sale.status = Sale.STATUS_QUOTE
        sale.branch = branch
        sale.add_sellable(sellable)
        self.failIf(sellable.can_remove())

        # Can't remove the sellable if it's in a purchase.
        from stoqlib.domain.purchase import PurchaseItem
        sellable = self.create_sellable()
        Storable(product=sellable.product, store=self.store)
        self.assertTrue(sellable.can_remove())
        PurchaseItem(store=self.store,
                     quantity=8, quantity_received=0,
                     cost=125, base_cost=125,
                     sellable=sellable,
                     order=self.create_purchase_order())
        self.assertFalse(sellable.can_remove())

        # The delivery service cannot be removed.
        sellable = sysparam(self.store).DELIVERY_SERVICE.sellable
        self.failIf(sellable.can_remove())
Ejemplo n.º 2
0
    def _create_domain(self):
        self.clean_domain([SaleItem])

        branch = get_current_branch(self.store)
        self.today = datetime.date.today()

        product = self.create_product()
        storable = Storable(store=self.store, product=product)
        ProductStockItem(storable=storable,
                         branch=branch,
                         quantity=5,
                         store=self.store)
        product.sellable.code = u'1'
        product.sellable.description = u'Luvas'

        product2 = self.create_product()
        storable2 = Storable(store=self.store, product=product2)
        ProductStockItem(storable=storable2,
                         branch=branch,
                         quantity=5,
                         store=self.store)
        product2.sellable.code = u'2'
        product2.sellable.description = u'Botas'

        # Sale
        sale = self.create_sale(123, branch=branch)
        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()
Ejemplo n.º 3
0
    def test_add_purchase_item(self):
        receiving_order = self.create_receiving_order()
        purchase = receiving_order.purchase_orders.find()[0]
        item = self.create_purchase_order_item()

        receiving_order = self.create_receiving_order()
        item = self.create_purchase_order_item(purchase)

        with self.assertRaisesRegex(
                ValueError, "The quantity must be higher "
                "than 0 and lower than the "
                "purchase item's quantity"):
            receiving_order.add_purchase_item(item, quantity=0)

        receiving_order = self.create_receiving_order()
        purchase = receiving_order.purchase_orders.find()[0]
        item = self.create_purchase_order_item(purchase)
        item.quantity_received = 2
        with self.assertRaisesRegex(
                ValueError, "The quantity must be lower "
                "than the item's pending "
                "quantity"):
            receiving_order.add_purchase_item(item, quantity=8)

        storable = Storable(store=self.store, product=item.sellable.product)
        storable.is_batch = True
        p = receiving_order.add_purchase_item(item, batch_number=u'12')
        self.assertEqual(p.batch.batch_number, u'12')
Ejemplo n.º 4
0
    def test_quality_tests(self):
        product = self.create_product()
        Storable(product=product, store=self.store)

        # There are still no tests for this product
        self.assertEqual(product.quality_tests.count(), 0)

        test1 = ProductQualityTest(store=self.store,
                                   product=product,
                                   test_type=ProductQualityTest.TYPE_BOOLEAN,
                                   success_value=u'True')
        # Now there sould be one
        self.assertEqual(product.quality_tests.count(), 1)
        # and it should be the one we created
        self.assertTrue(test1 in product.quality_tests)

        # Different product
        product2 = self.create_product()
        Storable(product=product2, store=self.store)

        # With different test
        test2 = ProductQualityTest(store=self.store,
                                   product=product2,
                                   test_type=ProductQualityTest.TYPE_BOOLEAN,
                                   success_value=u'True')

        # First product still should have only one
        self.assertEqual(product.quality_tests.count(), 1)
        # And it should not be the second test.
        self.assertTrue(test2 not in product.quality_tests)
Ejemplo n.º 5
0
    def test_can_remove(self):
        branch = get_current_branch(self.store)
        sellable = self.create_sellable()
        storable = Storable(product=sellable.product, store=self.store)
        self.failUnless(sellable.can_remove())

        storable.increase_stock(1, branch, 0, None)
        sale = self.create_sale()
        sale.status = Sale.STATUS_QUOTE
        sale.branch = branch
        sale.add_sellable(sellable)
        self.failIf(sellable.can_remove())

        # Can't remove the sellable if it's in a purchase.
        from stoqlib.domain.purchase import PurchaseItem
        sellable = self.create_sellable()
        Storable(product=sellable.product, store=self.store)
        self.assertTrue(sellable.can_remove())
        PurchaseItem(store=self.store,
                     quantity=8, quantity_received=0,
                     cost=125, base_cost=125,
                     sellable=sellable,
                     order=self.create_purchase_order())
        self.assertFalse(sellable.can_remove())

        # The delivery service cannot be removed.
        sellable = sysparam(self.store).DELIVERY_SERVICE.sellable
        self.failIf(sellable.can_remove())
Ejemplo n.º 6
0
    def test_add_purchase_item(self):
        receiving_order = self.create_receiving_order()
        item = self.create_purchase_order_item()

        with self.assertRaisesRegexp(ValueError, "The purchase item must be on "
                                     "the same purchase of this receiving"):
            receiving_order.add_purchase_item(item)

        receiving_order = self.create_receiving_order()
        item = self.create_purchase_order_item(receiving_order.purchase)

        with self.assertRaisesRegexp(ValueError, "The quantity must be higher "
                                                 "than 0 and lower than the "
                                                 "purchase item's quantity"):
            receiving_order.add_purchase_item(item, quantity=0)

        receiving_order = self.create_receiving_order()
        item = self.create_purchase_order_item(receiving_order.purchase)
        item.quantity_received = 2
        with self.assertRaisesRegexp(ValueError, "The quantity must be lower "
                                                 "than the item's pending "
                                                 "quantity"):
            receiving_order.add_purchase_item(item, quantity=8)

        storable = Storable(store=self.store, product=item.sellable.product)
        storable.is_batch = True
        p = receiving_order.add_purchase_item(item, batch_number=u'12')
        self.assertEqual(p.batch.batch_number, u'12')
Ejemplo n.º 7
0
    def test_can_remove(self):
        sellable = Sellable(store=self.store)
        self.assertTrue(sellable.can_remove())

        sellable = self.create_sellable()
        storable = Storable(product=sellable.product, store=self.store)
        self.assertTrue(sellable.can_remove())

        storable.increase_stock(1, self.current_branch,
                                StockTransactionHistory.TYPE_INITIAL, None,
                                self.current_user)
        sale = self.create_sale()
        sale.status = Sale.STATUS_QUOTE
        sale.branch = self.current_branch
        sale.add_sellable(sellable)
        self.assertFalse(sellable.can_remove())

        # Can't remove the sellable if it's in a purchase.
        from stoqlib.domain.purchase import PurchaseItem
        sellable = self.create_sellable()
        Storable(product=sellable.product, store=self.store)
        self.assertTrue(sellable.can_remove())
        PurchaseItem(store=self.store,
                     quantity=8,
                     quantity_received=0,
                     cost=125,
                     base_cost=125,
                     sellable=sellable,
                     order=self.create_purchase_order())
        self.assertFalse(sellable.can_remove())

        # The delivery service cannot be removed.
        sellable = sysparam.get_object(self.store, 'DELIVERY_SERVICE').sellable
        self.assertFalse(sellable.can_remove())
Ejemplo n.º 8
0
    def _create_domain(self):
        self.clean_domain([SaleItem])

        branch = get_current_branch(self.store)
        self.today = localtoday()

        product = self.create_product()
        storable = Storable(store=self.store, product=product)
        self.create_product_stock_item(storable=storable,
                                       branch=branch,
                                       quantity=5)
        product.sellable.code = u'1'
        product.sellable.description = u'Luvas'

        product2 = self.create_product()
        storable2 = Storable(store=self.store, product=product2)
        self.create_product_stock_item(storable=storable2,
                                       branch=branch,
                                       quantity=5)
        product2.sellable.code = u'2'
        product2.sellable.description = u'Botas'

        # 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)
Ejemplo n.º 9
0
 def add_product(self, sale, price=None, quantity=1):
     from stoqlib.domain.product import Storable
     product = self.create_product(price=price)
     sellable = product.sellable
     sellable.tax_constant = self.create_sellable_tax_constant()
     sale.add_sellable(sellable, quantity=quantity)
     storable = Storable(product=product, store=self.store)
     storable.increase_stock(100, get_current_branch(self.store), 0, 0)
     return sellable
Ejemplo n.º 10
0
 def add_product(self, sale, price=None, quantity=1):
     from stoqlib.domain.product import Storable
     product = self.create_product(price=price)
     sellable = product.sellable
     sellable.tax_constant = self.create_sellable_tax_constant()
     sale.add_sellable(sellable, quantity=quantity)
     storable = Storable(product=product, store=self.store)
     storable.increase_stock(100, get_current_branch(self.store), 0, 0)
     return sellable
Ejemplo n.º 11
0
    def create_loan_item(self, loan=None, quantity=1):
        from stoqlib.domain.loan import LoanItem
        from stoqlib.domain.product import Storable, StockTransactionHistory

        loan = loan or self.create_loan()
        sellable = self.create_sellable()
        storable = Storable(product=sellable.product, store=self.store)
        storable.increase_stock(10, loan.branch, type=StockTransactionHistory.TYPE_INITIAL, object_id=None)
        return LoanItem(loan=loan, sellable=sellable, price=10, quantity=quantity, store=self.store)
Ejemplo n.º 12
0
    def _create_sale(self, invoice_number, due_date=None):
        sale = self.create_sale()
        sale.invoice.invoice_number = invoice_number
        sale.branch = get_current_branch(self.store)
        tax_types = cycle(['aliq', 'nt', 'outr'])
        # [0] - Description
        # [1] - Code
        # [2] - Price
        # [3] - Quantity
        # [4] - Base price
        for tax_type, data in zip(
                tax_types,
            [(u"Laranja", u"1", Decimal(1), Decimal(10), Decimal('1.5')),
             (u"Limão", u"2", Decimal('0.5'), Decimal(15), Decimal('0.3')),
             (u"Abacaxi", u"3", Decimal(3), Decimal(1), Decimal('3.3')),
             (u"Cenoura", u"4", Decimal('1.5'), Decimal(6), Decimal('1.9')),
             (u"Pêssego", u"5", Decimal('3.5'), Decimal(3), Decimal('3.0'))]):
            sellable = self._create_sellable(data[0], data[1], data[2])
            storable = Storable(product=sellable.product, store=self.store)
            storable.increase_stock(data[3], get_current_branch(self.store),
                                    StockTransactionHistory.TYPE_INITIAL,
                                    sale.id, self.current_user)

            sale_item = sale.add_sellable(sellable, data[3])
            if tax_type == 'aliq':
                self._add_aliq(sale_item)
            elif tax_type == 'nt':
                self._add_nt(sale_item)
            elif tax_type == 'outr':
                self._add_outr(sale_item)

            # Set the base price to test the discount in NF-e.
            sale_item.base_price = data[4]
            icms_info = sale_item.icms_info
            icms_info.csosn = 201
            icms_info.p_icms_st = 1

            self._update_taxes(sale_item)

        sale.client = self.create_client()
        self._create_address(sale.client.person,
                             street=u"Rua dos Tomates",
                             streetnumber=2666,
                             postal_code=u'87654-321')
        sale.order(self.current_user)

        method = PaymentMethod.get_by_name(self.store, u'money')
        method.create_payment(sale.branch,
                              sale.station,
                              Payment.TYPE_IN,
                              sale.group,
                              sale.get_sale_subtotal(),
                              due_date=due_date)
        sale.confirm(self.current_user)

        return sale
Ejemplo n.º 13
0
    def create_model(self, store):
        self._model_created = True
        sellable = Sellable(store=store)
        model = Product(store=store, sellable=sellable)
        no_storable = [Product.TYPE_WITHOUT_STOCK, Product.TYPE_PACKAGE]
        if not self._product_type in no_storable:
            storable = Storable(product=model, store=store)

        if self._product_type == Product.TYPE_BATCH:
            storable.is_batch = True
        elif self._product_type == Product.TYPE_WITHOUT_STOCK:
            model.manage_stock = False
        elif self._product_type == Product.TYPE_CONSIGNED:
            model.consignment = True
        elif self._product_type == Product.TYPE_GRID:
            model.is_grid = True
            # Configurable products should not manage stock
            model.manage_stock = False
        elif self._product_type == Product.TYPE_PACKAGE:
            model.is_package = True
            # Package products should not manage stock
            model.manage_stock = False

        if self._template is not None:
            sellable.tax_constant = self._template.sellable.tax_constant
            sellable.unit = self._template.sellable.unit
            sellable.category = self._template.sellable.category
            sellable.base_price = self._template.sellable.base_price
            sellable.cost = self._template.sellable.cost
            sellable.default_sale_cfop = self._template.sellable.default_sale_cfop

            model.manufacturer = self._template.manufacturer
            model.brand = self._template.brand
            model.model = self._template.model
            model.family = self._template.family
            model.ncm = self._template.ncm
            model.set_icms_template(self._template._icms_template)
            model.set_ipi_template(self._template._ipi_template)
            model.set_pis_template(self._template._pis_template)
            model.set_cofins_template(self._template._cofins_template)

            for product_attr in self._template.attributes:
                ProductAttribute(store=self.store,
                                 product_id=model.id,
                                 attribute_id=product_attr.attribute.id)
            for supplier_info in self._template.suppliers:
                ProductSupplierInfo(store=self.store,
                                    product=model,
                                    supplier=supplier_info.supplier)
        else:
            sellable.tax_constant = sysparam.get_object(
                self.store, 'DEFAULT_PRODUCT_TAX_CONSTANT')
            sellable.unit_id = sysparam.get_object_id('SUGGESTED_UNIT')

        return model
Ejemplo n.º 14
0
 def add_product(self, sale, price=None, quantity=1, code=u''):
     from stoqlib.domain.product import Storable, StockTransactionHistory
     product = self.create_product(price=price, code=code)
     sellable = product.sellable
     sellable.tax_constant = self.create_sellable_tax_constant()
     sale.add_sellable(sellable, quantity=quantity)
     storable = Storable(product=product, store=self.store)
     storable.increase_stock(100, get_current_branch(self.store),
                             type=StockTransactionHistory.TYPE_INITIAL,
                             object_id=None)
     return sellable
Ejemplo n.º 15
0
    def create_storable(self, product=None, branch=None, stock=0, unit_cost=None, is_batch=False):
        from stoqlib.domain.product import Storable, StockTransactionHistory

        if not product:
            sellable = self.create_sellable()
            product = sellable.product
        storable = Storable(product=product, store=self.store, is_batch=is_batch)
        if branch and stock:
            storable.increase_stock(
                stock, branch, type=StockTransactionHistory.TYPE_INITIAL, object_id=None, unit_cost=unit_cost
            )
        return storable
Ejemplo n.º 16
0
    def _create_sale(self, invoice_number, due_date=None):
        sale = self.create_sale()
        sale.invoice_number = invoice_number
        sale.branch = get_current_branch(self.store)
        tax_types = cycle(['aliq', 'nt', 'outr'])
        # [0] - Description
        # [1] - Code
        # [2] - Price
        # [3] - Quantity
        # [4] - Base price
        for tax_type, data in zip(tax_types, [
                (u"Laranja", u"1", Decimal(1), Decimal(10), Decimal('1.5')),
                (u"Limão", u"2", Decimal('0.5'), Decimal(15), Decimal('0.3')),
                (u"Abacaxi", u"3", Decimal(3), Decimal(1), Decimal('3.3')),
                (u"Cenoura", u"4", Decimal('1.5'), Decimal(6), Decimal('1.9')),
                (u"Pêssego", u"5", Decimal('3.5'), Decimal(3), Decimal('3.0'))]):
            sellable = self._create_sellable(data[0], data[1], data[2])
            storable = Storable(product=sellable.product,
                                store=self.store)
            storable.increase_stock(data[3], get_current_branch(self.store),
                                    StockTransactionHistory.TYPE_INITIAL,
                                    sale.id)

            sale_item = sale.add_sellable(sellable, data[3])
            if tax_type == 'aliq':
                self._add_aliq(sale_item)
            elif tax_type == 'nt':
                self._add_nt(sale_item)
            elif tax_type == 'outr':
                self._add_outr(sale_item)

            # Set the base price to test the discount in NF-e.
            sale_item.base_price = data[4]
            icms_info = sale_item.icms_info
            icms_info.csosn = 201
            icms_info.p_icms_st = 1

            self._update_taxes(sale_item)

        sale.client = self.create_client()
        self._create_address(sale.client.person,
                             street=u"Rua dos Tomates",
                             streetnumber=2666,
                             postal_code=u'87654-321')
        sale.order()

        method = PaymentMethod.get_by_name(self.store, u'money')
        method.create_payment(Payment.TYPE_IN, sale.group, sale.branch,
                              sale.get_sale_subtotal(),
                              due_date=due_date)
        sale.confirm()

        return sale
Ejemplo n.º 17
0
    def create_model(self, store):
        self._model_created = True
        sellable = Sellable(store=store)
        model = Product(store=store, sellable=sellable)
        no_storable = [Product.TYPE_WITHOUT_STOCK, Product.TYPE_PACKAGE]
        if not self._product_type in no_storable:
            storable = Storable(product=model, store=store)

        if self._product_type == Product.TYPE_BATCH:
            storable.is_batch = True
        elif self._product_type == Product.TYPE_WITHOUT_STOCK:
            model.manage_stock = False
        elif self._product_type == Product.TYPE_CONSIGNED:
            model.consignment = True
        elif self._product_type == Product.TYPE_GRID:
            model.is_grid = True
            # Configurable products should not manage stock
            model.manage_stock = False
        elif self._product_type == Product.TYPE_PACKAGE:
            model.is_package = True
            # Package products should not manage stock
            model.manage_stock = False

        if self._template is not None:
            sellable.tax_constant = self._template.sellable.tax_constant
            sellable.unit = self._template.sellable.unit
            sellable.category = self._template.sellable.category
            sellable.base_price = self._template.sellable.base_price
            sellable.cost = self._template.sellable.cost

            model.manufacturer = self._template.manufacturer
            model.brand = self._template.brand
            model.family = self._template.family
            model.ncm = self._template.ncm
            model.icms_template = self._template.icms_template
            model.ipi_template = self._template.ipi_template

            for product_attr in self._template.attributes:
                ProductAttribute(store=self.store,
                                 product_id=model.id,
                                 attribute_id=product_attr.attribute.id)
            for supplier_info in self._template.suppliers:
                ProductSupplierInfo(
                    store=self.store,
                    product=model,
                    supplier=supplier_info.supplier)
        else:
            sellable.tax_constant_id = sysparam.get_object_id(
                'DEFAULT_PRODUCT_TAX_CONSTANT')
            sellable.unit_id = sysparam.get_object_id('SUGGESTED_UNIT')

        return model
Ejemplo n.º 18
0
 def create_transfer_order_item(self, order=None, quantity=5, sellable=None):
     from stoqlib.domain.product import Product, Storable, StockTransactionHistory
     if not order:
         order = self.create_transfer_order()
     if not sellable:
         sellable = self.create_sellable()
     product = self.store.find(Product, sellable=sellable).one()
     if not product.storable:
         storable = Storable(product=product, store=self.store)
         storable.increase_stock(quantity, order.source_branch,
                                 type=StockTransactionHistory.TYPE_TRANSFER_FROM,
                                 object_id=None)
     return order.add_sellable(sellable, batch=None, quantity=quantity)
Ejemplo n.º 19
0
 def create_storable(self, product=None, branch=None, stock=0,
                     unit_cost=None):
     from stoqlib.domain.product import Storable
     if not product:
         sellable = self.create_sellable()
         product = sellable.product
     storable = Storable(product=product, store=self.store)
     if branch and stock:
         if unit_cost:
             storable.increase_stock(stock, branch, 0, 0, unit_cost)
         else:
             storable.increase_stock(stock, branch, 0, 0)
     return storable
Ejemplo n.º 20
0
 def create_loan_item(self, loan=None, product=None, quantity=1):
     from stoqlib.domain.loan import LoanItem
     from stoqlib.domain.product import Storable
     loan = loan or self.create_loan()
     if not product:
         sellable = self.create_sellable()
         storable = Storable(product=sellable.product,
                             store=self.store)
         storable.increase_stock(10, loan.branch, 0, 0)
     else:
         sellable = product.sellable
         storable = product.storable
     return LoanItem(loan=loan, sellable=sellable, price=10,
                     quantity=quantity, store=self.store)
Ejemplo n.º 21
0
 def create_inventory_item(self, inventory=None, quantity=5):
     from stoqlib.domain.inventory import InventoryItem
     from stoqlib.domain.product import Storable
     if not inventory:
         inventory = self.create_inventory()
     sellable = self.create_sellable()
     product = sellable.product
     storable = Storable(product=product, store=self.store)
     storable.increase_stock(quantity, inventory.branch, 0, 0)
     return InventoryItem(product=product,
                          product_cost=product.sellable.cost,
                          recorded_quantity=quantity,
                          inventory=inventory,
                          store=self.store)
Ejemplo n.º 22
0
 def create_loan_item(self, loan=None, product=None, quantity=1):
     from stoqlib.domain.loan import LoanItem
     from stoqlib.domain.product import Storable
     loan = loan or self.create_loan()
     if not product:
         sellable = self.create_sellable()
         storable = Storable(product=sellable.product,
                             store=self.store)
         storable.increase_stock(10, loan.branch, 0, 0)
     else:
         sellable = product.sellable
         storable = product.storable
     return LoanItem(loan=loan, sellable=sellable, price=10,
                     quantity=quantity, store=self.store)
Ejemplo n.º 23
0
 def create_inventory_item(self, inventory=None, quantity=5):
     from stoqlib.domain.inventory import InventoryItem
     from stoqlib.domain.product import Storable
     if not inventory:
         inventory = self.create_inventory()
     sellable = self.create_sellable()
     product = sellable.product
     storable = Storable(product=product, store=self.store)
     storable.increase_stock(quantity, inventory.branch, 0, 0)
     return InventoryItem(product=product,
                          product_cost=product.sellable.cost,
                          recorded_quantity=quantity,
                          inventory=inventory,
                          store=self.store)
Ejemplo n.º 24
0
    def test_lead_time(self):
        product = self.create_product()
        Storable(product=product, store=self.store)
        branch = get_current_branch(self.store)

        supplier1 = self.create_supplier()
        ProductSupplierInfo(store=self.store,
                            product=product,
                            supplier=supplier1,
                            lead_time=10)

        self.assertEqual(product.get_max_lead_time(1, branch), 10)

        supplier2 = self.create_supplier()
        ProductSupplierInfo(store=self.store,
                            product=product,
                            supplier=supplier2,
                            lead_time=20)
        self.assertEqual(product.get_max_lead_time(1, branch), 20)

        # Now for composed products
        product = self.create_product(create_supplier=False)
        product.is_composed = True
        product.production_time = 5
        Storable(product=product, store=self.store)

        component = self.create_product(create_supplier=False)
        Storable(product=component, store=self.store)
        ProductSupplierInfo(store=self.store,
                            product=component,
                            supplier=supplier1,
                            lead_time=7)
        self.assertEqual(component.get_max_lead_time(1, branch), 7)

        pc = ProductComponent(product=product,
                              component=component,
                              quantity=1,
                              store=self.store)

        self.assertEqual(product.get_max_lead_time(1, branch), 12)

        # Increase the component stock
        component.storable.increase_stock(1, branch, 0, 0)

        self.assertEqual(product.get_max_lead_time(1, branch), 5)

        # Increase the quantity required:
        pc.quantity = 2
        self.assertEqual(product.get_max_lead_time(1, branch), 12)
Ejemplo n.º 25
0
    def create_product(self, price=None, create_supplier=True,
                       branch=None, stock=None):
        from stoqlib.domain.product import Storable
        sellable = self.create_sellable(price=price)
        if create_supplier:
            self.create_product_supplier_info(product=sellable.product)
        product = sellable.product
        if not branch:
            branch = get_current_branch(self.store)

        if stock:
            storable = Storable(product=product, store=self.store)
            storable.increase_stock(stock, branch, 0, 0, unit_cost=10)

        return product
Ejemplo n.º 26
0
 def create_transfer_order_item(self, order=None, quantity=5, sellable=None):
     from stoqlib.domain.product import Product, Storable
     from stoqlib.domain.transfer import TransferOrderItem
     if not order:
         order = self.create_transfer_order()
     if not sellable:
         sellable = self.create_sellable()
     product = self.store.find(Product, sellable=sellable).one()
     if not product.storable:
         storable = Storable(product=product, store=self.store)
         storable.increase_stock(quantity, order.source_branch, 0, 0)
     return TransferOrderItem(sellable=sellable,
                              transfer_order=order,
                              quantity=quantity,
                              store=self.store)
Ejemplo n.º 27
0
    def create_product(self, price=None, create_supplier=True,
                       branch=None, stock=None):
        from stoqlib.domain.product import Storable
        sellable = self.create_sellable(price=price)
        if create_supplier:
            self.create_product_supplier_info(product=sellable.product)
        product = sellable.product
        if not branch:
            branch = get_current_branch(self.store)

        if stock:
            storable = Storable(product=product, store=self.store)
            storable.increase_stock(stock, branch, 0, 0, unit_cost=10)

        return product
Ejemplo n.º 28
0
    def test_remove(self):
        # Remove category price and sellable
        sellable = self.create_sellable()
        Storable(product=sellable.product, store=self.store)
        for i in range(10):
            image = self.create_image()
            image.sellable = sellable

        ClientCategoryPrice(sellable=sellable,
                            category=self.create_client_category(),
                            price=100,
                            store=self.store)

        total = self.store.find(ClientCategoryPrice,
                                sellable=sellable.id).count()
        total_sellable = self.store.find(Sellable, id=sellable.id).count()
        total_images = self.store.find(Image, sellable_id=sellable.id).count()

        self.assertEqual(total, 1)
        self.assertEqual(total_sellable, 1)
        self.assertEqual(total_images, 10)

        sellable.remove()
        total = self.store.find(ClientCategoryPrice,
                                sellable=sellable.id).count()
        total_sellable = self.store.find(Sellable, id=sellable.id).count()
        total_images = self.store.find(Image, sellable_id=sellable.id).count()

        self.assertEqual(total, 0)
        self.assertEqual(total_sellable, 0)
        self.assertEqual(total_images, 0)
Ejemplo n.º 29
0
 def create_inventory_item(self, inventory=None, quantity=5):
     from stoqlib.domain.inventory import InventoryItem
     from stoqlib.domain.product import Storable, StockTransactionHistory
     if not inventory:
         inventory = self.create_inventory()
     sellable = self.create_sellable()
     product = sellable.product
     storable = Storable(product=product, store=self.store)
     storable.increase_stock(quantity, inventory.branch,
                             type=StockTransactionHistory.TYPE_INITIAL,
                             object_id=None)
     return InventoryItem(product=product,
                          product_cost=product.sellable.cost,
                          recorded_quantity=quantity,
                          inventory=inventory,
                          store=self.store)
Ejemplo n.º 30
0
 def _get_storables(self):
     self._current_branch = self.model.branch
     # Cache this data, to avoid more queries when building the list of storables.
     self._categories = list(self.store.find(SellableCategory))
     data = Storable.get_initial_stock_data(self.store, self.model.branch)
     for sellable, product, storable in data:
         yield _TemporaryStorableItem(sellable, product, storable)
Ejemplo n.º 31
0
    def test_order_receive_sell(self):
        product = self.create_product()
        storable = Storable(product=product, store=self.store)
        self.failIf(self.store.find(ProductStockItem, storable=storable).one())
        purchase_order = self.create_purchase_order()
        purchase_item = purchase_order.add_item(product.sellable, 1)
        purchase_order.status = purchase_order.ORDER_PENDING
        method = PaymentMethod.get_by_name(self.store, u'money')
        method.create_payment(Payment.TYPE_OUT,
                              purchase_order.group, purchase_order.branch,
                              purchase_order.get_purchase_total())
        purchase_order.confirm()

        receiving_order = self.create_receiving_order(purchase_order)
        receiving_order.branch = get_current_branch(self.store)
        self.create_receiving_order_item(
            receiving_order=receiving_order,
            sellable=product.sellable,
            purchase_item=purchase_item,
            quantity=1)
        self.failIf(self.store.find(ProductStockItem, storable=storable).one())
        receiving_order.confirm()
        product_stock_item = self.store.find(ProductStockItem,
                                             storable=storable).one()
        self.failUnless(product_stock_item)
        self.assertEquals(product_stock_item.quantity, 1)

        sale = self.create_sale()
        sale.add_sellable(product.sellable)
        sale.order()
        method = PaymentMethod.get_by_name(self.store, u'check')
        method.create_payment(Payment.TYPE_IN, sale.group, sale.branch, Decimal(100))
        sale.confirm()
        self.assertEquals(product_stock_item.quantity, 0)
Ejemplo n.º 32
0
    def test_get_unblocked_sellables(self):
        # Sellable and query without supplier
        sellable = self.create_sellable()
        available = Sellable.get_unblocked_sellables(self.store)
        self.assertTrue(sellable in list(available))

        # Sellable without supplier, but querying with one
        supplier = self.create_supplier()
        available = Sellable.get_unblocked_sellables(self.store,
                                                     supplier=supplier)
        self.assertFalse(sellable in list(available))

        # Relate the two
        from stoqlib.domain.product import ProductSupplierInfo
        ProductSupplierInfo(store=self.store,
                            supplier=supplier,
                            product=sellable.product,
                            is_main_supplier=True)

        # Now the sellable should appear in the results
        available = Sellable.get_unblocked_sellables(self.store,
                                                     supplier=supplier)
        self.assertTrue(sellable in list(available))

        # Now the sellable should appear in the results
        storable = Storable(product=sellable.product, store=self.store)
        available = Sellable.get_unblocked_sellables(self.store,
                                                     storable=storable)
        self.assertTrue(sellable in list(available))
Ejemplo n.º 33
0
 def _get_storables(self):
     self._current_branch = self.model.branch
     # Cache this data, to avoid more queries when building the list of storables.
     self._categories = list(self.store.find(SellableCategory))
     data = Storable.get_initial_stock_data(self.store, self.model.branch)
     for sellable, product, storable in data:
         yield _TemporaryStorableItem(sellable, product, storable)
Ejemplo n.º 34
0
    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)
Ejemplo n.º 35
0
    def create_model(self, store):
        self._model_created = True
        sellable = Sellable(store=store)
        sellable.tax_constant_id = sysparam.get_object_id('DEFAULT_PRODUCT_TAX_CONSTANT')
        sellable.unit_id = sysparam.get_object_id('SUGGESTED_UNIT')
        model = Product(store=store, sellable=sellable)
        if self._product_type != Product.TYPE_WITHOUT_STOCK:
            storable = Storable(product=model, store=store)

        if self._product_type == Product.TYPE_BATCH:
            storable.is_batch = True
        elif self._product_type == Product.TYPE_WITHOUT_STOCK:
            model.manage_stock = False
        elif self._product_type == Product.TYPE_CONSIGNED:
            model.consignment = True

        return model
Ejemplo n.º 36
0
    def testCanRemove(self):
        product = self.create_product()
        storable = Storable(product=product, store=self.store)
        self.assertTrue(product.can_remove())

        storable.increase_stock(1, get_current_branch(self.store), 0, 0)
        self.assertFalse(product.can_remove())

        # Product was sold.
        sale = self.create_sale()
        sale.add_sellable(product.sellable, quantity=1, price=10)

        method = PaymentMethod.get_by_name(self.store, u'money')
        method.create_inpayment(sale.group, sale.branch, sale.get_sale_subtotal())

        sale.order()
        sale.confirm()

        self.assertFalse(product.can_remove())

        # Product is a component.
        from stoqlib.domain.product import ProductComponent
        product = self.create_product(10)
        component = self.create_product(5)
        Storable(product=component, store=self.store)
        self.assertTrue(component.can_remove())

        ProductComponent(product=product,
                         component=component,
                         store=self.store)

        self.assertFalse(component.can_remove())

        # Product is used in a production.
        from stoqlib.domain.production import ProductionItem
        product = self.create_product()
        Storable(product=product, store=self.store)
        self.assertTrue(product.can_remove())
        order = self.create_production_order()
        ProductionItem(product=product,
                       order=order,
                       quantity=1,
                       store=self.store)

        self.assertFalse(product.can_remove())
Ejemplo n.º 37
0
 def create_model(self, store):
     self._model_created = True
     tax_constant = sysparam(store).DEFAULT_PRODUCT_TAX_CONSTANT
     sellable = Sellable(store=store)
     sellable.tax_constant = tax_constant
     sellable.unit = sysparam(self.store).SUGGESTED_UNIT
     model = Product(store=store, sellable=sellable)
     Storable(product=model, store=store)
     return model
Ejemplo n.º 38
0
 def _check_item_step(self, uitest=''):
     item_step = self.wizard.get_current_step()
     product = self.create_product()
     Storable(product=product, store=self.store)
     item_step.sellable_selected(product.sellable)
     self.click(item_step.add_sellable_button)
     if uitest:
         self.check_wizard(self.wizard, uitest)
     self.click(self.wizard.next_button)
Ejemplo n.º 39
0
    def _create_domain(self):
        branch = get_current_branch(self.store)

        product = self.create_product()
        storable = Storable(store=self.store, product=product)
        self.create_product_stock_item(
            storable=storable, branch=branch, quantity=2)
        product.brand = u''
        product.sellable.code = u'1'
        product.sellable.description = u'Luvas'

        product2 = self.create_product()
        storable2 = Storable(store=self.store, product=product2)
        self.create_product_stock_item(
            storable=storable2, branch=branch, quantity=4)
        product2.brand = u'brand'
        product.sellable.code = u'2'
        product.sellable.description = u'Botas'
Ejemplo n.º 40
0
    def create_product(self, price=None, with_supplier=True, branch=None, stock=None, storable=False, code=u""):
        from stoqlib.domain.product import Storable, StockTransactionHistory

        sellable = self.create_sellable(price=price, code=code)
        if with_supplier:
            self.create_product_supplier_info(product=sellable.product)
        product = sellable.product
        if not branch:
            branch = get_current_branch(self.store)

        if storable or stock:
            storable = Storable(product=product, store=self.store)
        if stock:
            storable.increase_stock(
                stock, branch, type=StockTransactionHistory.TYPE_INITIAL, object_id=None, unit_cost=10
            )

        return product
Ejemplo n.º 41
0
    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)
Ejemplo n.º 42
0
    def test_close_returned_in_consignment_wizard(self, run_dialog, info):
        purchase_item = self.create_purchase_order_item()
        self.create_receiving_order_item(purchase_item=purchase_item)

        # Create storable.
        product = purchase_item.sellable.product
        Storable(store=self.store, product=product)
        storable = product.storable
        branch = purchase_item.order.branch
        storable.increase_stock(5, branch,
                                StockTransactionHistory.TYPE_INITIAL, None,
                                self.current_user)
        stock_quantity = storable.get_stock_item(branch, None).quantity
        self.assertEqual(stock_quantity, 5)

        purchase_item.quantity_received = 5
        purchase_item.order.status = PurchaseOrder.ORDER_CONSIGNED
        purchase_item.order.identifier = 334
        purchase_item.order.open_date = localdatetime(2012, 1, 1)
        purchase_item.order.expected_receival_date = localdatetime(2012, 2, 2)

        wizard = CloseInConsignmentWizard(self.store)

        step = wizard.get_current_step()
        self.click(step.search.search_button)

        product_stock_item = self.store.find(ProductStockItem,
                                             storable=storable).one()
        self.check_wizard(wizard, 'wizard-return-consignment-selection-step')

        order_view = step.search.results[0]
        step.search.results.select(order_view)
        self.click(wizard.next_button)

        step = wizard.get_current_step()

        # Select consignment.
        step.consignment_items.emit('row_activated', step.consignment_items[0])
        self.assertEqual(run_dialog.call_count, 1)
        args, kwargs = run_dialog.call_args
        editor, parent, store, item = args
        self.assertEqual(editor, InConsignmentItemEditor)
        self.assertEqual(parent, wizard)
        self.assertEqual(item, purchase_item)
        self.assertTrue(store is not None)

        # Return the total received.
        purchase_item.quantity_returned = 5

        self.click(wizard.next_button)
        # After return. Item quantity in stock must be decreased.
        stock_quantity = storable.get_stock_item(branch, None).quantity
        self.assertEqual(stock_quantity, 0)
        self.check_wizard(wizard,
                          'wizard-close-returned-in-consignment-confirm',
                          [wizard.retval, purchase_item, product_stock_item])
Ejemplo n.º 43
0
    def testRemove(self):
        product = self.create_product()
        Storable(product=product, store=self.store)

        total = self.store.find(Product, id=product.id).count()
        self.assertEquals(total, 1)

        product.remove()
        total = self.store.find(Product, id=product.id).count()
        self.assertEquals(total, 0)
Ejemplo n.º 44
0
    def _create_domain(self):
        self.today = datetime.date.today()

        branch = get_current_branch(self.store)

        product = self.create_product()
        storable = Storable(store=self.store, product=product)
        self.create_product_stock_item(
            storable=storable, branch=branch, quantity=2)
        product.sellable.code = u'1'
        product.sellable.description = u'Luvas'
        product.sellable.status = Sellable.STATUS_CLOSED

        product = self.create_product()
        storable = Storable(store=self.store, product=product)
        self.create_product_stock_item(
            storable=storable, branch=branch, quantity=4)
        product.sellable.code = u'2'
        product.sellable.description = u'Botas'
        product.sellable.status = Sellable.STATUS_CLOSED
Ejemplo n.º 45
0
 def create_model(self, store):
     self._model_created = True
     tax_constant = sysparam(store).DEFAULT_PRODUCT_TAX_CONSTANT
     sellable = Sellable(store=store)
     sellable.tax_constant = tax_constant
     sellable.unit = sysparam(self.store).SUGGESTED_UNIT
     model = Product(store=store, sellable=sellable)
     # FIXME: Instead of creating and then removing, we should only create
     # the Storable if the user chooses to do so, but due to the way the
     # editor is implemented, it is not that easy. Change this once we write
     # the new product editor.
     Storable(product=model, store=store)
     return model
Ejemplo n.º 46
0
    def _create_sale(self, invoice_number, due_date=None):
        sale = self.create_sale()
        sale.invoice_number = invoice_number
        sale.branch = get_current_branch(self.store)

        # [0] - Description
        # [1] - Code
        # [2] - Price
        # [3] - Quantity
        for data in [(u"Laranja", u"1", Decimal(1), Decimal(10)),
                     (u"Limão", u"2", Decimal('0.5'), Decimal(15)),
                     (u"Abacaxi", u"3", Decimal(3), Decimal(1)),
                     (u"Cenoura", u"4", Decimal('1.5'), Decimal(6)),
                     (u"Pêssego", u"5", Decimal('3.5'), Decimal(3))]:
            sellable = self._create_sellable(data[0], data[1], data[2])

            storable = Storable(product=sellable.product,
                                store=self.store)
            storable.increase_stock(data[3], get_current_branch(self.store),
                                    StockTransactionHistory.TYPE_INITIAL,
                                    sale.id)

            sale.add_sellable(sellable, data[3])

        sale.client = self.create_client()
        self._create_address(sale.client.person,
                             street=u"Rua dos Tomates",
                             streetnumber=2666,
                             postal_code=u'87654-321')
        sale.order()

        method = PaymentMethod.get_by_name(self.store, u'money')
        method.create_payment(Payment.TYPE_IN, sale.group, sale.branch,
                              sale.get_sale_subtotal(),
                              due_date=due_date)
        sale.confirm()

        return sale
Ejemplo n.º 47
0
    def test_get_storables_without_stock_item(self):
        self.clean_domain([StockTransactionHistory, ProductStockItem, Storable])

        s0_without_stock = self.create_storable()

        b1 = self.create_branch()
        s1_with_stock = self.create_storable(branch=b1, stock=1)
        s1_without_stock = self.create_storable(branch=b1)

        b2 = self.create_branch()
        s2_with_stock = self.create_storable(branch=b2, stock=1)
        s2_without_stock = self.create_storable(branch=b2)

        # All but s1_with_stock should be here
        self.assertEqual(
            set(Storable.get_storables_without_stock_item(self.store, b1)),
            set([s0_without_stock, s1_without_stock,
                 s2_without_stock, s2_with_stock]))
        # All but s2_with_stock should be here
        self.assertEqual(
            set(Storable.get_storables_without_stock_item(self.store, b2)),
            set([s0_without_stock, s2_without_stock,
                 s1_without_stock, s1_with_stock]))
Ejemplo n.º 48
0
    def process_one(self, data, fields, store):
        base_category = self._get_or_create(
            SellableCategory,
            store,
            suggested_markup=Decimal(data.markup),
            salesperson_commission=Decimal(data.commission),
            category=None,
            description=data.base_category)

        # create a commission source
        self._get_or_create(CommissionSource,
                            store,
                            direct_value=Decimal(data.commission),
                            installments_value=Decimal(data.commission2),
                            category=base_category)

        category = self._get_or_create(SellableCategory,
                                       store,
                                       description=data.category,
                                       suggested_markup=Decimal(data.markup2),
                                       category=base_category)

        sellable = Sellable(store=store,
                            cost=Decimal(data.cost),
                            category=category,
                            description=data.description,
                            price=Decimal(data.price))
        sellable.barcode = data.barcode
        sellable.code = u'%02d' % self._code
        self._code += 1
        if u'unit' in fields:
            if not data.unit in self.units:
                raise ValueError(u"invalid unit: %s" % data.unit)
            sellable.unit = store.fetch(self.units[data.unit])
        sellable.tax_constant_id = self.tax_constant_id

        product = Product(store=store, sellable=sellable, ncm=data.ncm)

        taxes = self._maybe_create_taxes(store)
        product.set_icms_template(taxes['icms'])
        product.set_pis_template(taxes['pis'])
        product.set_cofins_template(taxes['cofins'])

        supplier = store.fetch(self.supplier)
        ProductSupplierInfo(store=store,
                            supplier=supplier,
                            is_main_supplier=True,
                            base_cost=Decimal(data.cost),
                            product=product)
        Storable(product=product, store=store)
Ejemplo n.º 49
0
    def _create_sale(self, invoice_number, due_date=None):
        sale = self.create_sale()
        sale.invoice_number = invoice_number
        sale.branch = get_current_branch(self.store)

        # [0] - Description
        # [1] - Code
        # [2] - Price
        # [3] - Quantity
        for data in [(u"Laranja", u"1", Decimal(1), Decimal(10)),
                     (u"Limão", u"2", Decimal('0.5'), Decimal(15)),
                     (u"Abacaxi", u"3", Decimal(3), Decimal(1)),
                     (u"Cenoura", u"4", Decimal('1.5'), Decimal(6)),
                     (u"Pêssego", u"5", Decimal('3.5'), Decimal(3))]:
            sellable = self._create_sellable(data[0], data[1], data[2])

            storable = Storable(product=sellable.product,
                                store=self.store)
            storable.increase_stock(data[3], get_current_branch(self.store), 0,
                                    sale.id)

            sale.add_sellable(sellable, data[3])

        sale.client = self.create_client()
        self._create_address(sale.client.person,
                             street=u"Rua dos Tomates",
                             streetnumber=2666,
                             postal_code=u'87654-321')
        sale.order()

        method = PaymentMethod.get_by_name(self.store, u'money')
        method.create_payment(Payment.TYPE_IN, sale.group, sale.branch,
                              sale.get_sale_subtotal(),
                              due_date=due_date)
        sale.confirm()

        return sale
Ejemplo n.º 50
0
    def create_production_item(self, quantity=1, order=None):
        from stoqlib.domain.product import ProductComponent, Storable
        from stoqlib.domain.production import (ProductionItem,
                                               ProductionMaterial)
        product = self.create_product(10)
        Storable(product=product, store=self.store)
        component = self.create_product(5)
        Storable(product=component, store=self.store)
        ProductComponent(product=product,
                         component=component,
                         store=self.store)

        if not order:
            order = self.create_production_order()
        component = list(product.get_components())[0]
        ProductionMaterial(product=component.component,
                           order=order,
                           needed=quantity,
                           store=self.store)

        return ProductionItem(product=product,
                              order=order,
                              quantity=quantity,
                              store=self.store)
Ejemplo n.º 51
0
 def _get_storables(self):
     for s in Storable.get_storables_without_stock_item(self.store,
                                                        self._branch):
         yield _TemporaryStorableItem(s)
Ejemplo n.º 52
0
    def testIncreaseDecreaseStock(self):
        branch = get_current_branch(self.store)
        product = self.create_product()
        storable = Storable(product=product, store=self.store)
        stock_item = storable.get_stock_item(branch)
        self.failIf(stock_item is not None)

        storable.increase_stock(1, branch, 0, 0)
        stock_item = storable.get_stock_item(branch)
        self.assertEquals(stock_item.stock_cost, 0)

        storable.increase_stock(1, branch, 0, 0, unit_cost=10)
        stock_item = storable.get_stock_item(branch)
        self.assertEquals(stock_item.stock_cost, 5)

        stock_item = storable.decrease_stock(1, branch, 0, 0)
        self.assertEquals(stock_item.stock_cost, 5)

        storable.increase_stock(1, branch, 0, 0)
        stock_item = storable.get_stock_item(branch)
        self.assertEquals(stock_item.stock_cost, 5)

        storable.increase_stock(2, branch, 0, 0, unit_cost=15)
        stock_item = storable.get_stock_item(branch)
        self.assertEquals(stock_item.stock_cost, 10)
Ejemplo n.º 53
0
    def test_get_balance(self):
        p = self.create_product()
        b1 = self.create_branch()
        b2 = self.create_branch()
        b3 = self.create_branch()

        storable = Storable(store=self.store, product=p)
        self.assertEqual(storable.get_balance_for_branch(b1), 0)
        self.assertEqual(storable.get_balance_for_branch(b2), 0)
        self.assertEqual(storable.get_balance_for_branch(b3), 0)
        self.assertEqual(storable.get_total_balance(), 0)

        # Only b1 and b2 will increase stock
        storable.increase_stock(5, b1, 0, None)
        storable.increase_stock(10, b2, 0, None)
        self.assertEqual(storable.get_balance_for_branch(b1), 5)
        self.assertEqual(storable.get_balance_for_branch(b2), 10)
        self.assertEqual(storable.get_balance_for_branch(b3), 0)
        self.assertEqual(storable.get_total_balance(), 15)

        # b1 will decrease *all* it's stock
        storable.decrease_stock(5, b1, 0, None)
        self.assertEqual(storable.get_balance_for_branch(b1), 0)
        self.assertEqual(storable.get_balance_for_branch(b2), 10)
        self.assertEqual(storable.get_balance_for_branch(b3), 0)
        self.assertEqual(storable.get_total_balance(), 10)