def test_sample_data_wizard_pane(rf, admin_user, settings): settings.WSHOP_SETUP_WIZARD_PANE_SPEC = [ "wshop.admin.modules.sample_data.views.SampleObjectsWizardPane" ] shop = get_default_shop() get_default_tax_class() data = { 'pane_id': 'sample', 'sample-business_segment': 'default', 'sample-categories': True, 'sample-products': True, 'sample-carousel': True } request = apply_request_middleware(rf.post("/", data=data), user=admin_user) response = WizardView.as_view()(request) assert response.status_code == 200 assert Product.objects.count() == len( BUSINESS_SEGMENTS["default"]["products"]) anon_contact = AnonymousContact() supplier = get_default_supplier() # check for the injected plugin using the carousel assert Carousel.objects.count() == 1 carousel = Carousel.objects.first() assert Slide.objects.count() == len( BUSINESS_SEGMENTS["default"]["carousel"]["slides"]) svc = SavedViewConfig.objects.first() assert svc.view_name == "IndexView" layout = svc.get_layout_data("front_content") assert layout['rows'][0]['cells'][0]['config']['carousel'] == carousel.pk assert layout['rows'][0]['cells'][0]['plugin'] == CarouselPlugin.identifier for product in Product.objects.all(): # all products must be orderable and have images assert product.get_shop_instance(shop).is_orderable( supplier=supplier, customer=anon_contact, quantity=1) assert product.primary_image is not None assert Category.objects.count() == len( BUSINESS_SEGMENTS["default"]["categories"]) request = apply_request_middleware(rf.get("/"), user=admin_user) response = WizardView.as_view()(request) assert response.status_code == 302 assert response["Location"] == reverse("wshop_admin:dashboard")
def test_custom_payment_processor_cash_service(choice_identifier, expected_payment_status): shop = get_default_shop() product = get_default_product() supplier = get_default_supplier() processor = CustomPaymentProcessor.objects.create() payment_method = PaymentMethod.objects.create( shop=shop, payment_processor=processor, choice_identifier=choice_identifier, tax_class=get_default_tax_class()) order = create_order_with_product( product=product, supplier=supplier, quantity=1, taxless_base_unit_price=Decimal('5.55'), shop=shop) order.taxful_total_price = TaxfulPrice(Decimal('5.55'), u'EUR') order.payment_method = payment_method order.save() assert order.payment_status == PaymentStatus.NOT_PAID processor.process_payment_return_request(choice_identifier, order, None) assert order.payment_status == expected_payment_status processor.process_payment_return_request(choice_identifier, order, None) assert order.payment_status == expected_payment_status
def test_order_package_children_taxes(): """ Test OrderCreator creates package parent links for child lines. """ tax_class = get_default_tax_class() tax = Tax.objects.create(rate='0.25', name="Da Tax") TaxRule.objects.create(tax=tax).tax_classes.add(tax_class) source = get_order_source_with_a_package() assert source.get_lines()[0].tax_class == tax_class order = OrderCreator().create_order(source) lines_and_taxes = [] for line in order.lines.all(): lines_and_taxes.append(prettify_order_line(line)) for line_tax in line.taxes.all(): lines_and_taxes.append(' %s' % (line_tax,)) assert lines_and_taxes == [ '#0 10 x PackageParent', ' Da Tax: 20.000000000 EUR on 80.000000000 EUR', '#1 10 x PackageChild-0, child of #0', '#2 20 x PackageChild-1, child of #0', '#3 30 x PackageChild-2, child of #0', '#4 40 x PackageChild-3, child of #0', ]
def test_method_creation(rf, admin_user, view, model, service_provider_attr, get_provider): """ To make things little bit more simple let's use only english as an language. """ with override_settings(LANGUAGES=[("en", "en")]): view = view.as_view() service_provider_field = "base-%s" % service_provider_attr data = { service_provider_field: get_provider().id, "base-choice_identifier": "manual", "base-name__en": "Custom method", "base-shop": get_default_shop().id, "base-tax_class": get_default_tax_class().id, "base-enabled": True, } # Default provider CustomCarrier/CustomPaymentProcessor should be set in form init methods_before = model.objects.count() url = "/?provider=%s" % get_provider().id request = apply_request_middleware(rf.post(url, data=data), user=admin_user) response = view(request, pk=None) if hasattr(response, "render"): response.render() assert response.status_code in [200, 302] assert model.objects.count() == (methods_before + 1)
def _get_template_engine_and_context(product_sku='6.0745'): engine = django.template.engines['jinja2'] assert isinstance(engine, django_jinja.backend.Jinja2) shop = get_default_shop() shop.currency = 'USD' shop.prices_include_tax = False shop.save() request = RequestFactory().get('/') request.shop = shop request.customer = AnonymousContact() request.person = request.customer PriceDisplayOptions(include_taxes=False).set_for_request(request) tax = get_default_tax() create_default_tax_rule(tax) tax_class = get_default_tax_class() order, order_line = _get_order_and_order_line(request) product = create_product(sku=product_sku, shop=shop, tax_class=tax_class) context = { 'request': request, 'prod': product, # TODO: Test also with variant products 'sline': _get_source_line(request), 'bline': _get_basket_line(request), 'oline': order_line, 'order': order } return (engine, context)
def test_custom_payment_processor_defaults(choice_identifier, default_behavior_components): shop = get_default_shop() processor = CustomPaymentProcessor.objects.create() service = processor.create_service(choice_identifier, shop=shop, tax_class=get_default_tax_class()) assert service.behavior_components.count() == len(default_behavior_components) for behavior in default_behavior_components: assert ServiceBehaviorComponent.objects.instance_of(behavior).count() == 1
def _get_shipping_method_with_phase(): carrier = CarrierWithCheckoutPhase.objects.create( identifier="carrier_with_phase", enabled=True) assert isinstance(carrier, CarrierWithCheckoutPhase) return carrier.create_service(None, identifier="carrier_with_phase", shop=get_default_shop(), name="Test method with phase", enabled=True, tax_class=get_default_tax_class())
def _get_payment_method_with_phase(): processor = PaymentWithCheckoutPhase.objects.create( identifier="processor_with_phase", enabled=True) assert isinstance(processor, PaymentWithCheckoutPhase) return processor.create_service(None, identifier="payment_with_phase", shop=get_default_shop(), name="Test method with phase", enabled=True, tax_class=get_default_tax_class())
def test_process_payment_return_request(rf, get_payment_processor, expected_final_payment_status): """ Order payment with default payment method with ``CustomPaymentProcessor`` provider should remain NOT_PAID. Order payment with default payment method with ``PaymentWithCheckoutPhase`` provider should become DEFERRED. Payment can't be processed if method doesn't have provider or provider is not enabled or payment method is not enabled. """ payment_processor = get_payment_processor() pm = PaymentMethod.objects.create(shop=get_default_shop(), name="Test method", enabled=False, tax_class=get_default_tax_class()) product = create_product(sku="test-sku", shop=get_default_shop(), default_price=100) order = create_order_with_product(product=product, supplier=get_default_supplier(), quantity=1, taxless_base_unit_price=Decimal('5.55'), shop=get_default_shop()) order.payment_method = pm order.save() assert order.payment_status == PaymentStatus.NOT_PAID with pytest.raises( ValueError): # Can't process payment with unusable method order.payment_method.process_payment_return_request(order, rf.get("/")) assert order.payment_status == PaymentStatus.NOT_PAID pm.payment_processor = payment_processor pm.payment_processor.enabled = False pm.save() with pytest.raises( ValueError): # Can't process payment with unusable method order.payment_method.process_payment_return_request(order, rf.get("/")) assert order.payment_status == PaymentStatus.NOT_PAID pm.payment_processor.enabled = True pm.save() with pytest.raises( ValueError): # Can't process payment with unusable method order.payment_method.process_payment_return_request(order, rf.get("/")) assert order.payment_status == PaymentStatus.NOT_PAID pm.enabled = True pm.save() # Add payment data for checkout phase order.payment_data = {"input_value": True} order.payment_method.process_payment_return_request(order, rf.get("/")) assert order.payment_status == expected_final_payment_status
def get_expensive_sweden_shipping_method(): carrier = CustomCarrier.objects.create(name="Sveede Sheep") sm = carrier.create_service(None, shop=get_default_shop(), enabled=True, tax_class=get_default_tax_class(), name="Expenseefe-a Svedee Sheepping") sm.behavior_components.add( ExpensiveSwedenBehaviorComponent.objects.create(), WeightLimitsBehaviorComponent.objects.create(min_weight="0.11", max_weight="3"), ) return sm
def test_product_create(browser, admin_user, live_server, settings): activate("en") shop = get_default_shop() get_default_product_type() get_default_sales_unit() get_default_tax_class() configuration.set(None, "wshop_product_tour_complete", True) object_created.connect(_add_custom_product_created_message, sender=Product, dispatch_uid="object_created_signal_test") initialize_admin_browser_test(browser, live_server, settings) browser.driver.set_window_size(1920, 1080) url = reverse("wshop_admin:shop_product.new") browser.visit("%s%s" % (live_server, url)) sku = "testsku" name = "Some product name" price_value = 10 short_description = "short but gold" browser.fill("base-sku", sku) browser.fill("base-name__en", name) browser.fill("base-short_description__en", short_description) browser.fill("shop%s-default_price_value" % shop.pk, price_value) configuration.set(None, "wshop_category_tour_complete", True) _add_primary_category(browser, shop) _add_additional_category(browser, shop) click_element(browser, "button[form='product_form']") wait_until_appeared(browser, "div[class='message success']") product = Product.objects.filter(sku=sku).first() assert product.log_entries.filter( identifier=OBJECT_CREATED_LOG_IDENTIFIER).count() == 1 object_created.disconnect(sender=Product, dispatch_uid="object_created_signal_test") shop_product = product.get_shop_instance(shop) assert shop_product.categories.count() == 2
def test_service_methods_with_long_name(rf): """ Make sure that service methods with long names (up to the max length of shipping or payment method names) don't cause exceptions when creating an order. """ MAX_LENGTH = 100 long_name = "X" * MAX_LENGTH assert len(long_name) == MAX_LENGTH sm = ShippingMethod.objects.language("en").create( shop=get_default_shop(), name=long_name, enabled=True, tax_class=get_default_tax_class()) pm = PaymentMethod.objects.language("en").create( shop=get_default_shop(), name=long_name, enabled=True, tax_class=get_default_tax_class()) order = create_empty_order() order.shipping_method = sm order.payment_method = pm order.full_clean() order.save()
def test_weight_limits(): carrier = CustomCarrier.objects.create() sm = carrier.create_service(None, shop=get_default_shop(), enabled=True, tax_class=get_default_tax_class()) sm.behavior_components.add( WeightLimitsBehaviorComponent.objects.create(min_weight=100, max_weight=500)) source = BasketishOrderSource(get_default_shop()) assert any(ve.code == "min_weight" for ve in sm.get_unavailability_reasons(source)) source.add_line(type=OrderLineType.PRODUCT, weight=600) assert any(ve.code == "max_weight" for ve in sm.get_unavailability_reasons(source))
def test_tax_edit_view_works_at_all(rf, admin_user): get_default_shop() # We need a shop to exists request = apply_request_middleware(rf.get("/")) request.user = admin_user default_tax_class = get_default_tax_class() with replace_modules([TaxModule]): with admin_only_urls(): view_func = TaxClassEditView.as_view() response = view_func(request, pk=default_tax_class.pk) response.render() assert (default_tax_class.name in force_text(response.content)) response = view_func(request, pk=None) # "new mode" response.render() assert response.content
def create_sample_product(name, description, business_segment, image_file, shop): product = Product.objects.create(name=name, description=description, type=get_default_product_type(), tax_class=get_default_tax_class(), sales_unit=SalesUnit.objects.first(), sku=fuzzy.FuzzyText(length=10).fuzz()) image_file_path = os.path.join(SAMPLE_IMAGES_BASE_DIR, image_file) path = "ProductImages/Samples/%s" % business_segment.capitalize() filer_image = _filer_image_from_file_path(image_file_path, path) media = ProductMedia.objects.create(product=product, kind=ProductMediaKind.IMAGE, file=filer_image) media.shops = Shop.objects.all() media.save() product.primary_image = media product.save() # create the price and round it to the number of decimals of the currency price = shop.create_price( decimal.Decimal(random.random() * random.randrange(0, 500))).as_rounded() sp = ShopProduct.objects.create( product=product, purchasable=True, visibility=ShopProductVisibility.ALWAYS_VISIBLE, default_price_value=price, shop=shop, shop_primary_image=media) sp.categories = shop.categories.all() sp.suppliers.add(get_default_supplier()) # configure prices if "wshop.customer_group_pricing" in settings.INSTALLED_APPS: from wshop.customer_group_pricing.models import CgpPrice CgpPrice.objects.create(product=product, price_value=random.randint(15, 340), shop=shop, group=PersonContact.get_default_group()) return product
def _get_order(prices_include_tax=False, include_basket_campaign=False, include_catalog_campaign=False): shop = get_shop(prices_include_tax=prices_include_tax) supplier = get_simple_supplier() if include_basket_campaign: _add_basket_campaign(shop) if include_catalog_campaign: _add_catalog_campaign(shop) _add_taxes() source = BasketishOrderSource(shop) source.status = get_initial_order_status() ctx = get_pricing_module().get_context_from_data(shop, AnonymousContact()) for product_data in _get_product_data(): quantity = product_data.pop("quantity") product = create_product( sku=product_data.pop("sku"), shop=shop, supplier=supplier, stock_behavior=StockBehavior.STOCKED, tax_class=get_default_tax_class(), **product_data) shop_product = product.get_shop_instance(shop) shop_product.categories.add(get_default_category()) shop_product.save() supplier.adjust_stock(product.id, INITIAL_PRODUCT_QUANTITY) pi = product.get_price_info(ctx) source.add_line( type=OrderLineType.PRODUCT, product=product, supplier=supplier, quantity=quantity, base_unit_price=pi.base_unit_price, discount_amount=pi.discount_amount ) oc = OrderCreator() order = oc.create_order(source) order.create_payment(Money("1", "EUR")) assert not order.has_refunds() assert order.can_create_refund() assert order.shipping_status == ShippingStatus.NOT_SHIPPED assert order.payment_status == PaymentStatus.PARTIALLY_PAID return order
def _get_custom_order(regular_user, **kwargs): prices_include_tax = kwargs.pop("prices_include_tax", False) include_basket_campaign = kwargs.pop("include_basket_campaign", False) include_catalog_campaign = kwargs.pop("include_catalog_campaign", False) shop = get_shop(prices_include_tax=prices_include_tax) supplier = get_simple_supplier() if include_basket_campaign: _add_basket_campaign(shop) if include_catalog_campaign: _add_catalog_campaign(shop) _add_taxes() contact = get_person_contact(regular_user) source = BasketishOrderSource(shop) source.status = get_initial_order_status() source.customer = contact ctx = get_pricing_module().get_context_from_data(shop, contact) for product_data in _get_product_data(): quantity = product_data.pop("quantity") product = create_product(sku=product_data.pop("sku"), shop=shop, supplier=supplier, stock_behavior=StockBehavior.STOCKED, tax_class=get_default_tax_class(), **product_data) shop_product = product.get_shop_instance(shop) shop_product.categories.add(get_default_category()) shop_product.save() supplier.adjust_stock(product.id, INITIAL_PRODUCT_QUANTITY) pi = product.get_price_info(ctx) source.add_line(type=OrderLineType.PRODUCT, product=product, supplier=supplier, quantity=quantity, base_unit_price=pi.base_unit_price, discount_amount=pi.discount_amount) oc = OrderCreator() order = oc.create_order(source) return order
def _get_product_sample_data(): return { # translations "translations": { "en": { "name": "Product Name", "description": "Product Description", "slug": "product_sku", "keywords": "keyword1, k3yw0rd2", "status_text": "available soon", "variation_name": "Product RED" }, "pt-br": { "name": "Nome do Produto", "description": "Descrição do Produto", "slug": "product_sku_em_portugues", "keywords": "chave1, chavez2", "status_text": "disponivel logo", "variation_name": "Produto Vermelho" } }, # others "stock_behavior": StockBehavior.STOCKED.value, "shipping_mode": ShippingMode.SHIPPED.value, "sales_unit": get_default_sales_unit().pk, "tax_class": get_default_tax_class().pk, "type": get_default_product_type().pk, "sku": "sku12345", "gtin": "789456132", "barcode": "7896899123456", "accounting_identifier": "cbe6a7d67a8bdae", "profit_center": "prooofit!", "cost_center": "space ghost", "width": 150.0, "height": 230.0, "depth": 450.4, "net_weight": 13.2, "gross_weight": 20.3 }
def test_admin_cash_order(rf, admin_user, price, target, mode): activate("en") get_initial_order_status() # Needed for the API shop = get_default_shop() contact = create_random_person(locale="en_US", minimum_name_comp_len=5) processor = CustomPaymentProcessor.objects.create(rounding_mode=mode) cash_method = PaymentMethod.objects.create( shop=shop, payment_processor=processor, choice_identifier="cash", tax_class=get_default_tax_class(), name="Cash") state = get_frontend_order_state(contact, cash_method, price) order = get_order_from_state(state, admin_user) assert order.payment_method == cash_method assert order.lines.count( ) == 5 # 2 submitted, two for the shipping and payment method, and a rounding line assert order.creator == admin_user assert order.customer == contact assert order.taxful_total_price == shop.create_price(target)
def test_shipping_report(rf): shop = get_default_shop() tax_class = get_default_tax_class() creator = OrderCreator() carrier1 = CustomCarrier.objects.create(name="Carrier1") sm1 = carrier1.create_service(None, shop=get_default_shop(), enabled=True, tax_class=tax_class, name="SM #1") sm1.behavior_components.add( FixedCostBehaviorComponent.objects.create(price_value=Decimal(10))) sm2 = carrier1.create_service(None, shop=get_default_shop(), enabled=True, tax_class=tax_class, name="SM #2") sm2.behavior_components.add( FixedCostBehaviorComponent.objects.create(price_value=Decimal(99))) sm2.behavior_components.add( FixedCostBehaviorComponent.objects.create(price_value=Decimal(4))) carrier2 = CustomCarrier.objects.create(name="Carrier2") sm3 = carrier2.create_service(None, shop=get_default_shop(), enabled=True, tax_class=tax_class, name="SM #3") sm3.behavior_components.add( FixedCostBehaviorComponent.objects.create(price_value=Decimal(5))) source1 = seed_source(sm1) source2 = seed_source(sm1) source3 = seed_source(sm2) source4 = seed_source(sm3) creator.create_order(source1) creator.create_order(source2) creator.create_order(source3) creator.create_order(source4) # pay orders [o.create_payment(o.taxful_total_price) for o in Order.objects.all()] data = { "report": ShippingReport.get_name(), "shop": shop.pk, "date_range": DateRangeChoices.ALL_TIME, "writer": "json", "force_download": 1, } report = ShippingReport(**data) writer = get_writer_instance(data["writer"]) response = writer.get_response(report=report) if hasattr(response, "render"): response.render() json_data = json.loads(response.content.decode("utf-8")) assert force_text(ShippingReport.title) in json_data.get("heading") data = json_data.get("tables")[0].get("data") assert len(data) == 3 expected_result = [ { "carrier": carrier1.name, "shipping_method": sm1.name, "order_count": 2, "total_charged": sum([bc.price_value for bc in sm1.behavior_components.all()]) * 2 # 2 orders }, { "carrier": carrier1.name, "shipping_method": sm2.name, "order_count": 1, "total_charged": sum([bc.price_value for bc in sm2.behavior_components.all()]) }, { "carrier": carrier2.name, "shipping_method": sm3.name, "order_count": 1, "total_charged": sum([bc.price_value for bc in sm3.behavior_components.all()]) } ] for ix, shipping in enumerate(data): assert shipping["carrier"] == expected_result[ix]["carrier"] assert shipping["shipping_method"] == expected_result[ix][ "shipping_method"] assert shipping["order_count"] == str( expected_result[ix]["order_count"]) assert shipping["total_charged"] == str( expected_result[ix]["total_charged"].quantize(Decimal("0.01")))
def test_refunds_report(rf): shop = get_default_shop() get_default_tax_class() creator = OrderCreator() source1 = seed_source() source2 = seed_source() source3 = seed_source() source4 = seed_source() order1 = creator.create_order(source1) order2 = creator.create_order(source2) order3 = creator.create_order(source3) order4 = creator.create_order(source4) # pay orders [o.create_payment(o.taxful_total_price) for o in Order.objects.all()] order1.create_full_refund() order2.create_refund([{ "line": order2.lines.first(), "amount": order2.taxful_total_price.amount * Decimal(0.5), "quantity": 1 }]) order3.create_refund([{ "line": order3.lines.first(), "amount": order3.taxful_total_price.amount * Decimal(0.3), "quantity": 1 }]) order4.create_refund([{ "line": order4.lines.first(), "amount": order4.taxful_total_price.amount * Decimal(0.1), "quantity": 1 }]) total_refunded = (order1.get_total_refunded_amount() + order2.get_total_refunded_amount() + order3.get_total_refunded_amount() + order4.get_total_refunded_amount()) data = { "report": RefundedSalesReport.get_name(), "shop": shop.pk, "date_range": DateRangeChoices.ALL_TIME, "writer": "json", "force_download": 1, } report = RefundedSalesReport(**data) writer = get_writer_instance(data["writer"]) response = writer.get_response(report=report) if hasattr(response, "render"): response.render() json_data = json.loads(response.content.decode("utf-8")) assert force_text(RefundedSalesReport.title) in json_data.get("heading") data = json_data.get("tables")[0].get("data") assert len(data) == 1 data = data[0] expected_data = { "refunded_orders": "4", "total_refunded": str(total_refunded.value) } for k, v in expected_data.items(): assert data[k] == v
def test_coupons_usage_report(rf): shop = get_default_shop() tax_class = get_default_tax_class() creator = OrderCreator() coupon1 = Coupon.objects.create(code="coupon1", active=True) coupon2 = Coupon.objects.create(code="coupon2", active=True) campaign1 = get_default_campaign(coupon1, "10") campaign2 = get_default_campaign(coupon2, "25") source1 = seed_source(coupon1) source2 = seed_source(coupon1) source3 = seed_source(coupon1) source4 = seed_source(coupon2) creator.create_order(source1) creator.create_order(source2) creator.create_order(source3) creator.create_order(source4) # pay orders [o.create_payment(o.taxful_total_price) for o in Order.objects.all()] data = { "report": CouponsUsageReport.get_name(), "shop": shop.pk, "date_range": DateRangeChoices.ALL_TIME, "writer": "json", "force_download": 1, } report = CouponsUsageReport(**data) writer = get_writer_instance(data["writer"]) response = writer.get_response(report=report) if hasattr(response, "render"): response.render() json_data = json.loads(response.content.decode("utf-8")) assert force_text(CouponsUsageReport.title) in json_data.get("heading") data = json_data.get("tables")[0].get("data") assert len(data) == Order.objects.count() expected_data = [] orders = Order.objects.all().order_by("order_date") for order in orders: discount = order.shop.create_price(0) for dt in order.lines.discounts(): discount += dt.taxful_price expected_data.append({ "date": format_date(order.order_date, locale=get_current_babel_locale()), "coupon": order.codes[0], "order": str(order), "taxful_total": str(order.taxful_total_price.as_rounded().value), "taxful_subtotal": str((order.taxful_total_price - discount).as_rounded().value), "total_discount": str(discount.as_rounded().value) }) assert len(expected_data) == len(data) for ix, d in enumerate(data): for k, v in d.items(): assert expected_data[ix][k] == v