def test_get_available_sellables_query(self): # Sellable and query without supplier sellable = self.create_sellable() self.create_storable(product=sellable.product, branch=self.create_branch()) self.assertIn( sellable, self.store.find(Sellable, Sellable.get_available_sellables_query(self.store))) sellable.close() self.assertNotIn( sellable, self.store.find(Sellable, Sellable.get_available_sellables_query(self.store))) delivery_sellable = sysparam(self.store).DELIVERY_SERVICE.sellable delivery_sellable.status = Sellable.STATUS_AVAILABLE # Deliveries are treated differently, that's why they should # not be present here self.assertNotIn( sellable, self.store.find(Sellable, Sellable.get_available_sellables_query(self.store)))
def test_with_unblocked_sellables_query(self): # This is used in the purchase wizard and breaks storm from stoqlib.domain.sellable import Sellable p1 = self.create_product() supplier = self.create_supplier() # Product should appear when querying without a supplier query = Sellable.get_unblocked_sellables_query(self.store) results = self.store.find(ProductFullStockView, query) self.assertTrue(p1.id in [p.product_id for p in results]) # But should not appear when querying with a supplier # When querying using the supplier, we should use the # ProductFullStockSupplierView instead. query = Sellable.get_unblocked_sellables_query(self.store, supplier=supplier) results = self.store.find(ProductFullStockItemSupplierView, query) self.assertFalse(p1.id in [p.id for p in results]) # Now relate the two ProductSupplierInfo(store=self.store, supplier=supplier, product=p1, is_main_supplier=True) # And it should appear now query = Sellable.get_unblocked_sellables_query(self.store, supplier=supplier) results = self.store.find(ProductFullStockItemSupplierView, query) self.assertTrue(p1.id in [s.product_id for s in results]) # But should not appear for a different supplier other_supplier = self.create_supplier() query = Sellable.get_unblocked_sellables_query(self.store, supplier=other_supplier) results = self.store.find(ProductFullStockItemSupplierView, query) self.assertFalse(p1.id in [s.product_id for s in results])
def create_model(self, store): tax_constant = SellableTaxConstant.get_by_type(TaxType.SERVICE, self.store) sellable = Sellable(description=u"", price=currency(0), store=store) sellable.tax_constant = tax_constant sellable.unit_id = sysparam.get_object_id("SUGGESTED_UNIT") model = Service(sellable=sellable, store=store) return model
def _update_default_sellable_code(self, category=None): if category: query = (Sellable.category_id == category.id) code = Sellable.get_max_value(self.store, Sellable.code, query=query) else: code = Sellable.get_max_value(self.store, Sellable.code) self.code.update(next_value_for(code))
def test_get_unblocked_by_category(self): s1 = self.create_sellable() s2 = self.create_sellable() s3 = self.create_sellable() c1 = self.create_sellable_category() c2 = self.create_sellable_category() s1.category = c1 s2.category = c2 self.assertEqual( set([s1, s2, s3]), set(Sellable.get_unblocked_by_categories( self.store, [c1, c2], include_uncategorized=True))) self.assertEqual( set([s1, s3]), set(Sellable.get_unblocked_by_categories( self.store, [c1], include_uncategorized=True))) self.assertEqual( set([s1, s3]), set(Sellable.get_unblocked_by_categories( self.store, [c1], include_uncategorized=True))) self.assertEqual( set([s1]), set(Sellable.get_unblocked_by_categories( self.store, [c1], include_uncategorized=False))) self.assertEqual( set([s3]), set(Sellable.get_unblocked_by_categories( self.store, [], include_uncategorized=True)))
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))
def create_service(self, description=u"Description", price=10): from stoqlib.domain.sellable import Sellable, SellableTaxConstant from stoqlib.domain.service import Service tax_constant = SellableTaxConstant.get_by_type(TaxType.SERVICE, self.store) sellable = Sellable(price=price, description=description, store=self.store) sellable.tax_constant = tax_constant service = Service(sellable=sellable, store=self.store) return service
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
def create_model(self, store): tax_constant = SellableTaxConstant.get_by_type(TaxType.SERVICE, self.store) sellable = Sellable(description=u'', price=currency(0), store=store) sellable.status = Sellable.STATUS_AVAILABLE sellable.tax_constant = tax_constant sellable.unit = sysparam(self.store).SUGGESTED_UNIT model = Service(sellable=sellable, store=store) return model
def _set_delivery_default(self, store): if self.has_object("DELIVERY_SERVICE"): return from stoqlib.domain.sellable import Sellable, SellableTaxConstant from stoqlib.domain.service import Service tax_constant = SellableTaxConstant.get_by_type(TaxType.SERVICE, store) sellable = Sellable(store=store, description=_(u"Delivery")) sellable.tax_constant = tax_constant service = Service(sellable=sellable, store=store) self.set_object(store, "DELIVERY_SERVICE", service)
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) # 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
def test_category_name(self): sellable = Sellable(category=None, cost=50, description=u"Test", price=currency(100), store=self.store) sellable.max_discount = 0 cat = self.create_client_category(u'Cat 1') cat_price = ClientCategoryPrice(sellable=sellable, category=cat, price=150, max_discount=0, store=self.store) self.assertEqual(cat_price.category_name, u'Cat 1')
def process_one(self, data, fields, store): tax = store.fetch(self.tax_constant) sellable = Sellable(store=store, description=data.description, price=int(data.price), cost=int(data.cost)) sellable.tax_constant = tax sellable.code = data.barcode sellable.barcode = data.barcode Service(sellable=sellable, store=store)
def test_markup(self): sellable = Sellable(category=None, cost=0, store=self.store) cat = self.create_client_category(u'Cat 1') cat_price = ClientCategoryPrice(sellable=sellable, category=cat, price=150, max_discount=0, store=self.store) self.assertEqual(cat_price.markup, 0) sellable.cost = 10 self.assertEqual(cat_price.markup, 1400) cat_price.markup = 10
def create_delivery_service(self): from stoqlib.domain.sellable import (Sellable, SellableTaxConstant) from stoqlib.domain.service import Service key = u"DELIVERY_SERVICE" store = new_store() tax_constant = SellableTaxConstant.get_by_type(TaxType.SERVICE, store) sellable = Sellable(description=_(u'Delivery'), store=store) sellable.tax_constant = tax_constant service = Service(sellable=sellable, store=store) self._set_schema(key, service.id) store.commit(close=True)
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(sellable=sellable, store=store) 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)
def test_price_on_sale_price_getter(self): sellable = Sellable(category=self._category, cost=50, description=u"Test", price=100, store=self.store) self.assertEquals(sellable.price, 100) sellable.on_sale_price = 80 self.assertEquals(sellable.price, 80) # - Old promotion sellable.on_sale_start_date = localdate(2001, 1, 1) sellable.on_sale_end_date = localdate(2002, 1, 1) self.assertEquals(sellable.price, 100) # - Future promotion sellable.on_sale_start_date = localdate(3001, 1, 1) sellable.on_sale_end_date = localdate(3002, 1, 1) self.assertEquals(sellable.price, 100) # Current promotion sellable.on_sale_start_date = localdate(2001, 1, 1) sellable.on_sale_end_date = localdate(3002, 1, 1) self.assertEquals(sellable.price, 80)
def create_sellable(self, price=None, product=True, description=u"Description"): from stoqlib.domain.product import Product from stoqlib.domain.service import Service from stoqlib.domain.sellable import Sellable tax_constant = sysparam(self.store).DEFAULT_PRODUCT_TAX_CONSTANT if price is None: price = 10 sellable = Sellable(cost=125, price=price, description=description, store=self.store) sellable.tax_constant = tax_constant if product: Product(sellable=sellable, store=self.store) else: Service(sellable=sellable, store=self.store) return sellable
def get_sellable_view_query(self): branch = api.get_current_branch(self.store) branch_query = self.sellable_view.branch_id == branch.id sellable_query = Sellable.get_unblocked_sellables_query(self.store, storable=True) query = And(branch_query, sellable_query) return self.sellable_view, query
def get_sellable_view_query(self): """This method should return a tuple containing the viewable that should be used and a query that should filter the sellables that can and cannot be added to this step. """ return (self.sellable_view, Sellable.get_unblocked_sellables_query(self.store))
def get_sellable_view_query(self): branch = api.get_current_branch(self.store) branch_query = Or(ProductStockItem.branch_id == branch.id, Eq(ProductStockItem.branch_id, None)) query = And(branch_query, Sellable.get_available_sellables_query(self.store)) return self.sellable_view, query
def get_sellable_view_query(self): branch = api.get_current_branch(self.store) branch_query = Or(Field('_stock_summary', 'branch_id') == branch.id, Eq(Field('_stock_summary', 'branch_id'), None)) query = And(branch_query, Sellable.get_available_sellables_query(self.store)) return self.sellable_view, query
def get_sellable_view_query(self): # The stock quantity of consigned products can not be # decreased manually. See bug 5212. query = And(Eq(Product.consignment, False), self.sellable_view.branch_id == self.model.branch_id, Sellable.get_available_sellables_query(self.store)) return self.sellable_view, query
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
def get_sellable_view_query(self): return ( self.sellable_view, # FIXME: How to do this using sellable_view.find_by_branch ? And( Or(ProductStockItem.branch_id == self.model.branch.id, Eq(ProductStockItem.branch_id, None)), Sellable.get_available_sellables_query(self.store)))
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
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()) branch = get_current_branch(self.store) storable.increase_stock(1, branch, StockTransactionHistory.TYPE_INITIAL, None) sale = self.create_sale() sale.status = Sale.STATUS_QUOTE sale.branch = 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())
def test_commission(self): self._category.salesperson_commission = 10 sellable = Sellable(description=u"TX342", category=self._category, store=self.store) self.assertTrue( sellable.commission == self._category.salesperson_commission, (u"Expected salesperson commission: %r, got %r" % (self._category.salesperson_commission, sellable.commission)))
def test_price_based_on_category_markup(self): # When the price isn't defined, but the category and the cost. In this # case the sellable must have the price calculated applying the category's # markup in the sellable's cost. self._category.suggested_markup = 0 sellable = Sellable(description=u"MX123", commission=0, cost=100, category=self._category, store=self.store) sellable.max_discount = 0 self.assertTrue(sellable.markup == self._category.get_markup(), (u"Expected markup: %r, got %r" % (self._category.get_markup(), sellable.markup))) price = sellable.cost * (sellable.markup / currency(100) + 1) self.assertTrue(sellable.price == price, (u"Expected price: %r, got %r" % (price, sellable.price)))
def get_sellable_view_query(self): branch = self.model.branch branch_query = ProductStockItem.branch_id == branch.id # The stock quantity of consigned products can not be # decreased manually. See bug 5212. query = And(branch_query, Product.consignment == False, Sellable.get_available_sellables_query(self.store)) return self.sellable_view, query
def test_price_based_on_specified_markup(self): # When the price isn't defined, but the category, markup and the cost. # In this case the category's markup must be ignored and the price # calculated applying the markup specified in the sellable's cost. sellable = Sellable(description=u"FY123", category=self._category, cost=100, store=self.store) sellable.markup = 5 self.assertEquals(sellable.markup, 5) self.assertEquals(sellable.price, 105) sellable.cost = Decimal('100.33') sellable.markup = 7 self.assertEquals(sellable.price, currency('107.35')) sellable.markup = 8 self.assertEquals(sellable.price, currency('108.36'))
def create_sellable(self, price=None, product=True, description=u'Description'): from stoqlib.domain.product import Product from stoqlib.domain.service import Service from stoqlib.domain.sellable import Sellable tax_constant = sysparam(self.store).DEFAULT_PRODUCT_TAX_CONSTANT if price is None: price = 10 sellable = Sellable(cost=125, price=price, description=description, store=self.store) sellable.tax_constant = tax_constant if product: Product(sellable=sellable, store=self.store) else: Service(sellable=sellable, store=self.store) return sellable
def get_sellable_view_query(self): branch = self.model.branch # Also include products that are not storable branch_query = Or(self.sellable_view.branch_id == branch.id, Eq(self.sellable_view.branch_id, None)) # The stock quantity of consigned products can not be # decreased manually. See bug 5212. query = And(branch_query, Sellable.get_available_sellables_query(self.store)) return self.sellable_view, query
def process_one(self, data, fields, store): base_category = self._get_or_create(SellableCategory, store, suggested_markup=int(data.markup), salesperson_commission=int( data.commission), category=None, description=data.base_category) # create a commission source self._get_or_create(CommissionSource, store, direct_value=int(data.commission), installments_value=int(data.commission2), category=base_category) category = self._get_or_create(SellableCategory, store, description=data.category, suggested_markup=int(data.markup2), category=base_category) sellable = Sellable(store=store, cost=Decimal(data.cost), category=category, description=data.description, price=int(data.price)) sellable.barcode = sellable.code = data.barcode 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 = store.fetch(self.tax_constant) product = Product(sellable=sellable, store=store) 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)
def create_sellable(self, price=None, product=True, description=u'Description', code=u''): from stoqlib.domain.product import Product from stoqlib.domain.service import Service from stoqlib.domain.sellable import Sellable tax_constant_id = sysparam.get_object_id('DEFAULT_PRODUCT_TAX_CONSTANT') if price is None: price = 10 sellable = Sellable(cost=125, price=price, description=description, store=self.store) sellable.code = code sellable.tax_constant_id = tax_constant_id if product: Product(sellable=sellable, store=self.store) else: Service(sellable=sellable, store=self.store) return sellable
def get_sellable_view_query(self): return ( self.sellable_view, # FIXME: How to do this using sellable_view.find_by_branch ? And( Or( Field('_stock_summary', 'branch_id') == self.model.branch.id, Eq(Field('_stock_summary', 'branch_id'), None)), Sellable.get_available_sellables_query(self.store)))
def test_price_based_on_category_markup(self): # When the price isn't defined, but the category and the cost. In this # case the sellable must have the price calculated applying the category's # markup in the sellable's cost. self._category.suggested_markup = 0 sellable = Sellable(description=u"MX123", commission=0, cost=100, category=self._category, store=self.store) sellable.max_discount = 0 self.failUnless(sellable.markup == self._category.get_markup(), (u"Expected markup: %r, got %r" % (self._category.get_markup(), sellable.markup))) price = sellable.cost * (sellable.markup / currency(100) + 1) self.failUnless(sellable.price == price, (u"Expected price: %r, got %r" % (price, sellable.price)))
def test_run_wizard(self, run_dialog, new_store): run_dialog.return_value = None new_store.return_value = self.store query = Sellable.get_unblocked_sellables_query(self.store) dialog = PurchaseSellableSearch(store=self.store, search_spec=ProductFullStockView, search_query=query) with mock.patch.object(self.store, 'commit'): with mock.patch.object(self.store, 'close'): self.click(dialog._toolbar.new_button) run_dialog.assert_called_once_with(ProductCreateWizard, dialog, self.store)
def test_get_unblocked_by_category_query(self): s1 = self.create_sellable() s2 = self.create_sellable() s3 = self.create_sellable() c1 = self.create_sellable_category() c2 = self.create_sellable_category() s1.category = c1 s2.category = c2 query = Sellable.get_unblocked_by_categories_query( self.store, [c1, c2], include_uncategorized=True) self.assertEqual( set([s1, s2, s3]), set(self.store.find(Sellable, query))) query = Sellable.get_unblocked_by_categories_query( self.store, [c1], include_uncategorized=True) self.assertEqual( set([s1, s3]), set(self.store.find(Sellable, query))) query = Sellable.get_unblocked_by_categories_query( self.store, [c1], include_uncategorized=True) self.assertEqual( set([s1, s3]), set(self.store.find(Sellable, query))) query = Sellable.get_unblocked_by_categories_query( self.store, [c1], include_uncategorized=False) self.assertEqual( set([s1]), set(self.store.find(Sellable, query))) query = Sellable.get_unblocked_by_categories_query( self.store, [], include_uncategorized=True) self.assertEqual( set([s3]), set(self.store.find(Sellable, query)))
def test_with_unblocked_sellables_query(self): # This is used in the purchase wizard and breaks storm from stoqlib.domain.product import ProductSupplierInfo from stoqlib.domain.sellable import Sellable p1 = self.create_product() supplier = self.create_supplier() # Product should appear when querying without a supplier query = Sellable.get_unblocked_sellables_query(self.store) results = self.store.find(ProductFullStockView, query) self.assertTrue(p1.id in [p.product_id for p in results]) # But should not appear when querying with a supplier # When querying using the supplier, we should use the # ProductFullStockSupplierView instead. query = Sellable.get_unblocked_sellables_query(self.store, supplier=supplier) results = self.store.find(ProductFullStockItemSupplierView, query) self.assertFalse(p1.id in [p.id for p in results]) # Now relate the two ProductSupplierInfo(store=self.store, supplier=supplier, product=p1, is_main_supplier=True) # And it should appear now query = Sellable.get_unblocked_sellables_query(self.store, supplier=supplier) results = self.store.find(ProductFullStockItemSupplierView, query) self.assertTrue(p1.id in [s.product_id for s in results]) # But should not appear for a different supplier other_supplier = self.create_supplier() query = Sellable.get_unblocked_sellables_query(self.store, supplier=other_supplier) results = self.store.find(ProductFullStockItemSupplierView, query) self.assertFalse(p1.id in [s.product_id for s in results])
def create_sellable(self, product_info, responsible): if product_info.get('is_package') != 'true': raise SellableError( """A criação de produtos somente é permitida para produtos do tipo pacote. Verifique o cache do seu navegador.""") sellable = None if product_info["code"]: sellable = self.store.find(Sellable, Sellable.code == product_info["code"]) if sellable: return sellable = Sellable(store=self.store, description=product_info["description"], cost=Decimal(product_info["cost"]), price=Decimal(product_info["price"])) sellable.code = product_info["code"] sellable.barcode = product_info["barcode"] sellable.notes = "Created via API" + product_info["notes"] sellable.unit_id = product_info["unit_id"] or None sellable.tax_constant_id = product_info["tax_constant"] or None sellable.default_sale_cfop_id = product_info[ "default_sale_cfop_id"] or None sellable.category_id = product_info["category_id"] or None # FIXME Need to get more info from NFe to fill both Product and Storable product = Product(store=self.store, sellable=sellable) product.manage_stock = product_info.get('manage_stock') == 'true' product.is_package = product_info.get('is_package') == 'true' package_quantity = product_info.get('package_quantity') item_ean = product_info.get('item_ean') item = self.store.find(Sellable, barcode=item_ean).one() ProductComponent(product=product, component=item.product, price=sellable.get_price(), quantity=Decimal(package_quantity)) return sellable
def testSell(self): sale = self.create_sale() sellable = Sellable(store=self.store) sellable.barcode = u'xyz' product = Product(sellable=sellable, store=self.store) sale_item = sale.add_sellable(product.sellable) branch = get_current_branch(self.store) storable = self.create_storable(product, branch, 2) stock_item = storable.get_stock_item(branch, None) assert stock_item is not None current_stock = stock_item.quantity if current_stock: storable.decrease_stock(current_stock, branch, 0, 0) assert not storable.get_stock_item(branch, None).quantity sold_qty = 2 storable.increase_stock(sold_qty, branch, 0, 0) assert storable.get_stock_item(branch, None) is not None assert storable.get_stock_item(branch, None).quantity == sold_qty # now setting the proper sold quantity in the sellable item sale_item.quantity = sold_qty sale_item.sell(branch) assert not storable.get_stock_item(branch, None).quantity
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))
def get_sellable_view_query(self): supplier = self.model.supplier if self.wizard.all_products: supplier = None # If we our query includes the supplier, we must use another viewable, # that actually joins with that table if supplier: viewable = ProductFullStockItemSupplierView else: viewable = self.sellable_view query = Sellable.get_unblocked_sellables_query(self.store, supplier=supplier, consigned=self.model.consigned) return viewable, query
def test_run_editor(self, run_dialog, new_store): run_dialog.return_value = None new_store.return_value = self.store query = Sellable.get_unblocked_sellables_query(self.store) dialog = AdvancedSellableSearch(store=self.store, table=ProductFullStockView, query=query) dialog.search.refresh() dialog.results.select(dialog.results[0]) product = dialog.results[0].product with mock.patch.object(self.store, 'commit'): with mock.patch.object(self.store, 'close'): self.click(dialog._toolbar.edit_button) run_dialog.assert_called_once_with(ProductEditor, dialog, self.store, product, visual_mode=False)
def _get_sellables_query(self): categories = [c.category for c in self.category_tree if c.selected and c is not self._uncategorized_products] include_uncategorized = self._uncategorized_products.selected query = Sellable.get_unblocked_by_categories_query( self.store, categories, include_uncategorized) queries = [query] if self.model.product_manufacturer: queries.append(Product.manufacturer == self.model.product_manufacturer) if self.model.product_brand: queries.append(Product.brand == self.model.product_brand) if self.model.product_family: queries.append(Product.family == self.model.product_family) return And(*queries)
def post(self, store): data = self.get_json() if 'product' not in data: abort(400, 'There is no product data on payload') sellable_id = data.get('sellable_id') barcode = data.get('barcode') description = data.get('description') base_price = self._price_validation(data) if sellable_id and store.get(Sellable, sellable_id): abort(400, 'Product with this id already exists') if barcode and store.find(Sellable, barcode=barcode): abort(400, 'Product with this barcode already exists') sellable = Sellable(store=store) if sellable_id: sellable.id = sellable_id sellable.code = barcode sellable.barcode = barcode sellable.description = description # FIXME The sellable is created with STATUS_CLOSED because we need the taxes info # to start selling so this is just a temporary sellable just to save it on the # database so the override can be created sellable.status = Sellable.STATUS_CLOSED sellable.base_price = base_price product_data = data.get('product') product = Product(store=store, sellable=sellable) product.manage_stock = product_data.get('manage_stock', False) return make_response( jsonify({ 'message': 'Product created', 'data': { 'id': sellable.id, 'barcode': sellable.barcode, 'description': sellable.description, 'status': sellable.status, } }), 201)
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)
def _get_sellables(self): selected = [ c.category for c in self.category_tree if c.selected and c is not self._uncategorized_products ] include_uncategorized = self._uncategorized_products.selected sellables = Sellable.get_unblocked_by_categories( self.store, selected, include_uncategorized) if self.model.product_manufacturer: sellables = sellables.find( Product.manufacturer == self.model.product_manufacturer) if self.model.product_brand: sellables = sellables.find( Product.brand == self.model.product_brand) if self.model.product_family: sellables = sellables.find( Product.family == self.model.product_family) return sellables
def _update_default_sellable_code(self): code = Sellable.get_max_value(self.store, Sellable.code) self.code.update(next_value_for(code))
def get_sellable_view_query(self): query = Sellable.get_unblocked_sellables_query(self.store) return self.sellable_view, query
def get_sellable_view_query(self): sellable_query = And( Sellable.get_unblocked_sellables_query(self.store, storable=False), self.sellable_view.branch_id == self.model.source_branch_id) return self.sellable_view, sellable_query
def post(self, store): data = self.get_json() log.debug("POST /sellable station: %s payload: %s", self.get_current_station(store), data) if 'product' not in data: abort(400, 'There is no product data on payload') sellable_id = data.get('sellable_id') barcode = data.get('barcode') description = data.get('description') base_price = self._price_validation(data) sellable = store.get(Sellable, sellable_id) sellable_created_via_sale = sellable and Sellable.NOTES_CREATED_VIA_SALE in sellable.notes if sellable and not sellable_created_via_sale: message = 'Product with id {} already exists'.format(sellable_id) log.warning(message) return make_response(jsonify({ 'message': message, }), 200) if barcode and store.find(Sellable, barcode=barcode): message = 'Product with barcode {} already exists'.format(barcode) log.warning(message) return make_response(jsonify({ 'message': message, }), 200) if not sellable: sellable = Sellable(store=store) if sellable_id: sellable.id = sellable_id sellable.code = barcode sellable.barcode = barcode sellable.description = description # FIXME The sellable is created with STATUS_CLOSED because we need the taxes info # to start selling so this is just a temporary sellable just to save it on the # database so the override can be created sellable.status = Sellable.STATUS_CLOSED sellable.base_price = base_price # If the sellable was pre-created on a sale it has a notes informing it and to # proceed this note is removed sellable.notes = sellable.notes.replace( Sellable.NOTES_CREATED_VIA_SALE, "") product = sellable.product if sellable_created_via_sale else (Product( store=store, sellable=sellable)) product_data = data.get('product') product.manage_stock = product_data.get('manage_stock', False) # For clients that will control their inventory, we have to create a Storable if product.manage_stock and not store.get(Storable, product.id): storable = Storable(store=store, product=product) storable.maximum_quantity = 1000 return make_response( jsonify({ 'message': 'Product created', 'data': { 'id': sellable.id, 'barcode': sellable.barcode, 'description': sellable.description, 'status': sellable.status, } }), 201)