def test_unsaved_contact(admin_user):
    payment_method = get_default_payment_method()
    _assign_component_for_service(payment_method, [PersonContact.get_default_group()])
    person = PersonContact(name="Kalle")
    source = _get_source_for_contact(admin_user, payment_method)
    source.customer = person
    assert not person.pk and not source.customer.pk
    _test_service_availability(source, payment_method, False)
Example #2
0
def test_discount_for_logged_in_contacts(rf):
    default_price = 10
    request, product = _init_test_for_product(rf, default_price)
    assert request.customer == AnonymousContact()

    product_discount_amount = 2
    Discount.objects.create(
        shop=request.shop,
        active=True,
        contact_group=PersonContact.get_default_group(),
        discount_amount_value=product_discount_amount,
    )
    Discount.objects.create(
        shop=request.shop,
        active=True,
        contact_group=CompanyContact.get_default_group(),
        discount_amount_value=product_discount_amount,
    )
    assert product.get_price_info(request).price == request.shop.create_price(
        default_price)

    # setting customer to request should apply the discount
    request.customer = factories.create_random_person()
    assert product.get_price_info(request).price == request.shop.create_price(
        default_price - product_discount_amount)

    # Company as customer should work too
    request.customer = factories.create_random_company()
    assert product.get_price_info(request).price == request.shop.create_price(
        default_price - product_discount_amount)
def test_unsaved_contact(admin_user):
    payment_method = get_default_payment_method()
    _assign_component_for_service(payment_method, [PersonContact.get_default_group()])
    person = PersonContact(name="Kalle")
    source = _get_source_for_contact(admin_user, payment_method)
    source.customer = person
    assert not person.pk and not source.customer.pk
    _test_service_availability(source, payment_method, False)
Example #4
0
def _init_test():
    shop = factories.get_default_shop()
    supplier = factories.get_default_supplier()
    contact = factories.create_random_person()
    group = PersonContact.get_default_group()
    category = factories.get_default_category()
    contact.groups.add(group)
    return shop, supplier, contact, group, category
Example #5
0
def test_product_catalog_category_discount():
    shop = factories.get_default_shop()
    supplier = factories.get_default_supplier()
    contact = factories.create_random_person()
    group = PersonContact.get_default_group()
    category = factories.get_default_category()
    contact.groups.add(group)
    product1 = factories.create_product("p1",
                                        shop=shop,
                                        supplier=supplier,
                                        default_price=Decimal("10"))
    product2 = factories.create_product("p2",
                                        shop=shop,
                                        supplier=supplier,
                                        default_price=Decimal("20"))
    product3 = factories.create_product("p3",
                                        shop=shop,
                                        supplier=supplier,
                                        default_price=Decimal("30"))
    product1.get_shop_instance(shop).categories.add(category)
    product3.get_shop_instance(shop).categories.add(category)

    # create a 10% discount for the category
    Discount.objects.create(
        shop=shop,
        category=category,
        discount_percentage=Decimal(0.1),
        start_datetime=timezone.now(),
        end_datetime=timezone.now() + timedelta(days=1),
    )

    catalog = ProductCatalog(context=ProductCatalogContext(
        purchasable_only=False))
    ProductCatalog.index_product(product1)
    ProductCatalog.index_product(product2)
    ProductCatalog.index_product(product3)

    _assert_products_queryset(
        catalog,
        [
            (product1.pk, Decimal("10"), Decimal("9")),
            (product2.pk, Decimal("20"), None),
            (product3.pk, Decimal("30"), Decimal("27")),
        ],
    )
    _assert_shop_products_queryset(
        catalog,
        [
            (product1.get_shop_instance(shop).pk, Decimal("10"), Decimal("9")),
            (product2.get_shop_instance(shop).pk, Decimal("20"), None),
            (product3.get_shop_instance(shop).pk, Decimal("30"),
             Decimal("27")),
        ],
    )
    _assert_price(product1, shop, Decimal("9"), Decimal("10"))
    _assert_price(product2, shop, Decimal("20"), Decimal("20"))
    _assert_price(product3, shop, Decimal("27"), Decimal("30"))
Example #6
0
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_file = MediaFile.objects.create(file=filer_image)
    media_file.shops.add(shop)

    media = ProductMedia.objects.create(product=product,
                                        kind=ProductMediaKind.IMAGE,
                                        file=filer_image)
    media.save()
    media.shops.add(shop)
    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,
    )
    supplier = get_default_supplier(shop)
    supplier.stock_managed = False
    supplier.save()
    sp.categories.set(shop.categories.all())
    sp.suppliers.add(supplier)

    # configure prices
    if "shuup.customer_group_pricing" in settings.INSTALLED_APPS:
        from shuup.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
Example #7
0
 def _create_contact_from_address(self, billing_address, is_company):
     name = billing_address.get("name", None)
     phone = billing_address.get("phone", "")
     email = billing_address.get("email", "")
     fields = {"name": name, "phone": phone, "email": email}
     if is_company:
         tax_number = billing_address.get("tax_number", None)
         fields.update({"tax_number": tax_number})
         customer = CompanyContact(**fields)
     else:
         customer = PersonContact(**fields)
     return customer
Example #8
0
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_file = MediaFile.objects.create(file=filer_image)
    media_file.shops.add(shop)

    media = ProductMedia.objects.create(
        product=product,
        kind=ProductMediaKind.IMAGE,
        file=filer_image
    )
    media.save()
    media.shops.add(shop)
    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 "shuup.customer_group_pricing" in settings.INSTALLED_APPS:
        from shuup.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
Example #9
0
def test_display_queryset(regular_user):
    shop = get_default_shop()
    anonymous_group = AnonymousContact().get_default_group()
    PersonContact().get_default_group()
    CompanyContact().get_default_group()
    assert get_groups_for_price_display_create(shop).count() == 3
    assert get_price_displays_for_shop(None).count() == 3
    assert get_price_displays_for_shop(shop).count() == 3

    get_person_contact(regular_user)

    assert get_price_displays_for_shop(shop).count() == 3

    # create new group display (from admin usually)
    ContactGroupPriceDisplay.objects.create(group=anonymous_group, shop=shop)

    for_create = get_groups_for_price_display_create(shop)
    assert for_create.count() == 2
    assert anonymous_group not in for_create

    items = get_price_displays_for_shop(shop)
    assert items.count() == 3
    for item in items:
        if item.group == anonymous_group:
            assert item.shop
        else:
            assert not item.shop
        assert item.group.identifier in PROTECTED_CONTACT_GROUP_IDENTIFIERS

    new_group = ContactGroup.objects.create(identifier="test", shop=shop)

    items = get_price_displays_for_shop(shop)
    assert items.count() == 4
    for item in items:
        if item.group in [new_group, anonymous_group]:
            assert item.shop
        else:
            assert not item.shop
        if item.group != new_group:
            assert item.group.identifier in PROTECTED_CONTACT_GROUP_IDENTIFIERS
        else:
            assert item.group.identifier == "test"
Example #10
0
def test_discount_for_person_contacts(rf):
    default_price = 10
    request, product = _init_test_for_product(rf, default_price)
    assert request.customer == AnonymousContact()

    product_discount_amount = 2
    Discount.objects.create(
        shop=request.shop,
        active=True,
        contact_group=PersonContact.get_default_group(),
        discount_amount_value=product_discount_amount,
    )
    assert product.get_price_info(request).price == request.shop.create_price(
        default_price)

    # Setting customer to request activates the discount
    request.customer = factories.create_random_person()
    assert product.get_price_info(request).price == request.shop.create_price(
        default_price - product_discount_amount)

    # Using company contact as customer means no discount
    request.customer = factories.create_random_company()
    assert product.get_price_info(request).price == request.shop.create_price(
        default_price)
Example #11
0
    def _create_contact_from_address(self, billing_address, is_company):
        name = billing_address.get("name", None)
        if not name:
            self.add_error(
                ValidationError(_("Name is required for customer"),
                                code="no_name"))
            return

        phone = billing_address.get("phone", "")
        email = billing_address.get("email", "")
        fields = {"name": name, "phone": phone, "email": email}
        if is_company:
            tax_number = billing_address.get("tax_number", None)
            if not tax_number:
                self.add_error(
                    ValidationError(_("Tax number is not set for company."),
                                    code="no_tax_number"))
                return

            fields.update({"tax_number": tax_number})
            customer = CompanyContact(**fields)
        else:
            customer = PersonContact(**fields)
        return customer
Example #12
0
def test_product_catalog_cgp_with_variations():
    shop = factories.get_default_shop()
    supplier = factories.get_default_supplier()
    contact = factories.create_random_person()
    group = PersonContact.get_default_group()
    contact.groups.add(group)
    parent = factories.create_product("p1",
                                      shop=shop,
                                      supplier=supplier,
                                      default_price=Decimal("10"))
    child1 = factories.create_product("p2",
                                      shop=shop,
                                      supplier=supplier,
                                      default_price=Decimal("20"))
    child2 = factories.create_product("p3",
                                      shop=shop,
                                      supplier=supplier,
                                      default_price=Decimal("40"))
    child3 = factories.create_product("p4",
                                      shop=shop,
                                      supplier=supplier,
                                      default_price=Decimal("50"))

    child1.link_to_parent(parent)
    child2.link_to_parent(parent)
    child3.link_to_parent(parent)

    # set a price for child2
    CgpPrice.objects.create(shop=shop,
                            product=child2,
                            group=group,
                            price_value=Decimal("5"))
    # create a discount for child3
    CgpDiscount.objects.create(shop=shop,
                               product=child3,
                               group=group,
                               discount_amount_value=Decimal("35"))

    catalog = ProductCatalog(
        context=ProductCatalogContext(purchasable_only=False, contact=contact))
    ProductCatalog.index_product(parent)

    _assert_products_queryset(
        catalog,
        [
            (child2.pk, Decimal("5"), None),
            (parent.pk, Decimal("10"), None),
            (child1.pk, Decimal("20"), None),
            (child3.pk, Decimal("50"), Decimal("15")),
        ],
    )
    _assert_shop_products_queryset(
        catalog,
        [
            (child2.get_shop_instance(shop).pk, Decimal("5"), None),
            (parent.get_shop_instance(shop).pk, Decimal("10"), None),
            (child1.get_shop_instance(shop).pk, Decimal("20"), None),
            (child3.get_shop_instance(shop).pk, Decimal("50"), Decimal("15")),
        ],
    )
    # no customer
    _assert_price(parent, shop, Decimal("10"), Decimal("10"))
    _assert_price(child1, shop, Decimal("20"), Decimal("20"))
    _assert_price(child2, shop, Decimal("40"), Decimal("40"))
    _assert_price(child3, shop, Decimal("50"), Decimal("50"))
    # with the customer in the group
    _assert_price(parent, shop, Decimal("10"), Decimal("10"), customer=contact)
    _assert_price(child1, shop, Decimal("20"), Decimal("20"), customer=contact)
    _assert_price(child2, shop, Decimal("5"), Decimal("40"), customer=contact)
    _assert_price(child3, shop, Decimal("15"), Decimal("50"), customer=contact)
Example #13
0
def test_default_person_contact_group_repr_and_str():
    pdg = PersonContact.get_default_group()
    assert repr(pdg) == '<ContactGroup:%d-default_person_group>' % pdg.pk
    assert str(pdg) == 'Person Contacts'
Example #14
0
def test_person_name_init_by_first_and_last_name():
    john = PersonContact(first_name="John", last_name="Smith")
    assert john.name == "John Smith"
    assert john.first_name == "John"
    assert john.last_name == "Smith"
def test_admin_custom_customer_price_updates(rf, admin_user):
    shop = factories.get_default_shop()
    supplier = factories.get_default_supplier()
    contact = factories.create_random_person()
    group = PersonContact.get_default_group()
    contact.groups.add(group)
    product_type = factories.get_default_product_type()
    tax_class = factories.get_default_tax_class()
    sales_unit = factories.get_default_sales_unit()

    view = ProductEditView.as_view()
    group_price = "10.0"
    default_price = "15.0"

    payload = {
        "base-name__en": "My Product",
        "base-type": product_type.pk,
        "base-sku": "p1",
        "base-shipping_mode": ShippingMode.NOT_SHIPPED.value,
        "base-tax_class": tax_class.pk,
        "base-sales_unit": sales_unit.pk,
        "base-width": "0",
        "base-height": "0",
        "base-depth": "0",
        "base-net_weight": "0",
        "base-gross_weight": "0",
        f"shop{shop.pk}-default_price_value": default_price,
        f"shop{shop.pk}-visibility":
        ShopProductVisibility.ALWAYS_VISIBLE.value,
        f"shop{shop.pk}-visibility_limit":
        ProductVisibility.VISIBLE_TO_ALL.value,
        f"shop{shop.pk}-minimum_purchase_quantity": "1",
        f"shop{shop.pk}-purchase_multiple": "1",
        f"shop{shop.pk}-suppliers": [supplier.pk],
        f"customer_group_pricing-s_{shop.pk}_g_{group.pk}":
        group_price,  # set price for the group
    }

    # create a new product
    request = apply_request_middleware(rf.post("/", data=payload),
                                       shop=shop,
                                       user=admin_user)
    with patch("django.db.transaction.on_commit", new=atomic_commit_mock):
        response = view(request, pk=None)

    assert response.status_code == 302

    anon_catalog = ProductCatalog(context=ProductCatalogContext(
        purchasable_only=False))
    customer_catalog = ProductCatalog(
        context=ProductCatalogContext(purchasable_only=False, contact=contact))

    product = Product.objects.first()
    _assert_products_queryset(anon_catalog,
                              [(product.pk, Decimal(default_price), None)])
    _assert_products_queryset(customer_catalog,
                              [(product.pk, Decimal(group_price), None)])

    payload.update({
        # remove the customer group price
        f"customer_group_pricing-s_{shop.pk}_g_{group.pk}": "",
        "media-TOTAL_FORMS": 0,
        "media-INITIAL_FORMS": 0,
        "media-MIN_NUM_FORMS": 0,
        "media-MAX_NUM_FORMS": 1000,
        "images-TOTAL_FORMS": 0,
        "images-INITIAL_FORMS": 0,
        "images-MIN_NUM_FORMS": 0,
        "images-MAX_NUM_FORMS": 1000,
    })

    request = apply_request_middleware(rf.post("/", data=payload),
                                       shop=shop,
                                       user=admin_user)
    with patch("django.db.transaction.on_commit", new=atomic_commit_mock):
        response = view(request, pk=product.get_shop_instance(shop).pk)
    assert response.status_code == 302

    # default price for both
    _assert_products_queryset(anon_catalog,
                              [(product.pk, Decimal(default_price), None)])
    _assert_products_queryset(customer_catalog,
                              [(product.pk, Decimal(default_price), None)])
Example #16
0
 def filter(self):
     return json.dumps({"groups": [PersonContact.get_default_group().pk]})
Example #17
0
 def filter(self):
     return json.dumps({"groups": [PersonContact.get_default_group().pk]})
Example #18
0
def test_default_person_contact_group_repr_and_str():
    pdg = PersonContact.get_default_group()
    assert repr(pdg) == '<ContactGroup:%d-default_person_group>' % pdg.pk
    assert str(pdg) == 'Person Contacts'
Example #19
0
def test_product_catalog_discounted_price():
    shop = factories.get_default_shop()
    supplier = factories.get_default_supplier()
    contact = factories.create_random_person()
    group = PersonContact.get_default_group()
    contact.groups.add(group)
    product1 = factories.create_product("p1",
                                        shop=shop,
                                        supplier=supplier,
                                        default_price=Decimal("50"))
    product2 = factories.create_product("p2",
                                        shop=shop,
                                        supplier=supplier,
                                        default_price=Decimal("30"))

    # set price for product2
    CgpPrice.objects.create(shop=shop,
                            product=product2,
                            group=group,
                            price_value=Decimal(25))
    # create a discount for product2
    CgpDiscount.objects.create(shop=shop,
                               product=product2,
                               group=group,
                               discount_amount_value=Decimal(7))

    anon_catalog = ProductCatalog(context=ProductCatalogContext(
        purchasable_only=False))
    customer_catalog = ProductCatalog(
        context=ProductCatalogContext(purchasable_only=False, contact=contact))
    ProductCatalog.index_product(product1)
    ProductCatalog.index_product(product2)

    _assert_products_queryset(
        anon_catalog,
        [
            (product2.pk, Decimal("30"), None),
            (product1.pk, Decimal("50"), None),
        ],
    )
    _assert_products_queryset(
        customer_catalog,
        [
            (product2.pk, Decimal("25"), Decimal("23")),
            (product1.pk, Decimal("50"), None),
        ],
    )
    _assert_shop_products_queryset(
        anon_catalog,
        [
            (product2.get_shop_instance(shop).pk, Decimal("30"), None),
            (product1.get_shop_instance(shop).pk, Decimal("50"), None),
        ],
    )
    _assert_shop_products_queryset(
        customer_catalog,
        [
            (product2.get_shop_instance(shop).pk, Decimal("25"),
             Decimal("23")),
            (product1.get_shop_instance(shop).pk, Decimal("50"), None),
        ],
    )
    # no customer
    _assert_price(product1, shop, Decimal("50"), Decimal("50"))
    _assert_price(product2, shop, Decimal("30"), Decimal("30"))
    # with the customer in the group
    _assert_price(product1,
                  shop,
                  Decimal("50"),
                  Decimal("50"),
                  customer=contact)
    _assert_price(product2,
                  shop,
                  Decimal("18"),
                  Decimal("30"),
                  customer=contact)
Example #20
0
    def save(self, commit=True):
        def populate_address(needle):
            data = {}
            delete = []
            for k, value in six.iteritems(self.cleaned_data):
                if k.startswith(needle):
                    key = k.replace(needle, "")
                    data[key] = value
                    delete.append(k)

            # sweep unneeded keys
            for k in delete:
                del self.cleaned_data[k]

            return data

        contact_address_data = populate_address("contact_")
        company_address_data = populate_address("company_")
        user = super(CompanyRegistrationForm, self).save(commit)

        website = company_address_data.pop("www")

        contact_address = MutableAddress.from_data(contact_address_data)
        contact_address.save()
        company_address = MutableAddress.from_data(company_address_data)
        company_address.save()

        contact = PersonContact()
        contact.is_active = False
        contact.user = user
        contact.email = user.email
        contact.default_shipping_address = contact_address
        contact.default_billing_address = contact_address
        contact.first_name = contact_address_data["first_name"]
        contact.last_name = contact_address_data["last_name"]
        contact.phone = contact_address.phone
        contact.save()

        company = CompanyContact()
        company.default_shipping_address = company_address
        company.default_billing_address = company_address
        company.is_active = False
        company.phone = company_address.phone
        company.www = website
        company.name = company_address_data["name"]
        company.name_ext = company_address_data["name_ext"]
        company.tax_number = company_address_data["tax_number"]
        company.email = company_address_data["email"]
        company.save()
        company.members.add(contact)
        return user