コード例 #1
0
    def create(self, request, *args, **kwargs):
        basket = self.get_basket()
        serializer = self.get_serializer_class()(data=request.data)
        serializer.is_valid(raise_exception=True)
        try:
            product = serializer.validated_data['product']
            product.get_shop_instance(shop=self.request.shop)
        except ObjectDoesNotExist:
            return ValidationError({
                'code': 'product_not_available',
                'error': [_('The requested product does not exists or is not available in the current store')]
            })
        try:
            handle_add(PricingContext(self.request.shop, basket.customer),
                       basket, product.id, serializer.validated_data['quantity'])
            basket.save()
        except ShopMismatchBasketCompatibilityError:
            raise ValidationError({
                'code': 'shop_mismatch',
                'error': _('The requested belongs to another shop')
            })

        # trigger reload, otherwise we have a cached version
        new_basket = self.get_basket()
        return Response(APIBasketSerializer(new_basket, context={'request': self.request}).data)
コード例 #2
0
ファイル: general.py プロジェクト: tmskrtsz/shuup
def _get_best_selling_products(cutoff_days, n_products, orderable_only, request, sale_items_only):  # noqa (C901)
    data = get_best_selling_product_info(
        shop_ids=[request.shop.pk],
        cutoff_days=cutoff_days
    )
    combined_variation_products = defaultdict(int)
    for product_id, parent_id, qty in data:
        if parent_id:
            combined_variation_products[parent_id] += qty
        else:
            combined_variation_products[product_id] += qty

    # get all the product ids
    product_ids = [
        d[0] for
        d in sorted(six.iteritems(combined_variation_products), key=lambda i: i[1], reverse=True)
    ]

    products = []
    suppliers = []
    if orderable_only:
        # get suppliers for later use
        suppliers = Supplier.objects.enabled().filter(shops__in=[request.shop])

    if sale_items_only:
        from shuup.core.pricing import PricingContext
        pricing_context = PricingContext(shop=request.shop, customer=request.customer)

    # group product ids in groups of n_products
    # to prevent querying ALL products at once
    for grouped_product_ids in _group_list_items(product_ids, n_products):
        for product in Product.objects.filter(id__in=grouped_product_ids):
            if len(products) == n_products:
                break

            if sale_items_only and not _is_sale_item(product, pricing_context):
                continue

            try:
                shop_product = product.get_shop_instance(request.shop, allow_cache=True)
            except ShopProduct.DoesNotExist:
                continue

            if orderable_only:
                for supplier in suppliers:
                    if shop_product.is_orderable(supplier, request.customer, shop_product.minimum_purchase_quantity):
                        products.append(product)
                        break

            elif shop_product.is_visible(request.customer):
                products.append(product)

        if len(products) == n_products:
            break

    products = cache_product_things(request, products)
    products = sorted(products, key=lambda p: product_ids.index(p.id))  # pragma: no branch
    return products
コード例 #3
0
ファイル: basket.py プロジェクト: teury/shuup_public_api
 def update_line(self, data_line, **kwargs):
     line = BasketLine.from_dict(self, data_line)
     new_quantity = kwargs.pop("quantity", None)
     if new_quantity is not None:
         line.set_quantity(new_quantity)
     line.update(**kwargs)
     line.cache_info(PricingContext(self.shop, self.customer))
     self._add_or_replace_line(line)
     return line
コード例 #4
0
def _assert_price(product,
                  shop,
                  expected_price,
                  expected_base_price,
                  customer=None):
    context = PricingContext(shop=shop,
                             customer=customer or AnonymousContact())
    price = product.get_price_info(context)
    assert price.price.value == expected_price
    assert price.base_price.value == expected_base_price
コード例 #5
0
 def apply_for_basket(self, order_source):
     from shuup.campaigns.models import CatalogCampaign
     discounted_base_amount = order_source.total_price_of_products
     context = PricingContext(order_source.shop, order_source.customer)
     for line in order_source.get_product_lines():
         product = line.product
         if CatalogCampaign.get_matching(
                 context, product.get_shop_instance(order_source.shop)):
             discounted_base_amount -= line.price
     return (discounted_base_amount * self.value)
コード例 #6
0
    def matches(self, basket, lines):
        from shuup.campaigns.models import CatalogCampaign

        total_undiscounted_price_value = basket.total_price_of_products.value
        shop = basket.shop
        context = PricingContext(shop, basket.customer)
        for line in basket.get_product_lines():
            if CatalogCampaign.get_matching(
                    context, line.product.get_shop_instance(shop)):
                total_undiscounted_price_value -= line.price.value
        return (total_undiscounted_price_value >= self.amount_value)
コード例 #7
0
    def apply_for_basket(self, order_source):
        from shuup.campaigns.models import CatalogCampaign

        campaign = self.campaign
        supplier = campaign.supplier if hasattr(campaign, "supplier") and campaign.supplier else None
        discounted_base_amount = get_total_price_of_products(order_source, campaign)

        context = PricingContext(order_source.shop, order_source.customer)
        for line in order_source.get_product_lines():
            if supplier and line.supplier != supplier:
                continue

            product = line.product
            if CatalogCampaign.get_matching(context, product.get_shop_instance(order_source.shop)):
                discounted_base_amount -= line.price
        return discounted_base_amount * self.value
コード例 #8
0
ファイル: basket_conditions.py プロジェクト: wsmoyer/shuup
    def matches(self, basket, lines):
        from shuup.campaigns.models import CatalogCampaign
        campaign = self.campaign.first()
        total_of_products = get_total_price_of_products(basket, campaign)
        product_lines = basket.get_product_lines()

        if hasattr(campaign, "supplier") and campaign.supplier:
            product_lines = [
                line for line in product_lines
                if line.supplier == campaign.supplier
            ]

        total_undiscounted_price_value = total_of_products.value
        shop = basket.shop
        context = PricingContext(shop, basket.customer)

        for line in product_lines:
            if CatalogCampaign.get_matching(
                    context, line.product.get_shop_instance(shop)):
                total_undiscounted_price_value -= line.price.value
        return (total_undiscounted_price_value >= self.amount_value)
コード例 #9
0
ファイル: general.py プロジェクト: barseghyanartur/shuup
def get_listed_products(context,
                        n_products,
                        ordering=None,
                        filter_dict=None,
                        orderable_only=True,
                        sale_items_only=False):
    """
    Returns all products marked as listed that are determined to be
    visible based on the current context.

    :param context: Rendering context
    :type context: jinja2.runtime.Context
    :param n_products: Number of products to return
    :type n_products: int
    :param ordering: String specifying ordering
    :type ordering: str
    :param filter_dict: Dictionary of filter parameters
    :type filter_dict: dict[str, object]
    :param orderable_only: Boolean limiting results to orderable products
    :type orderable_only: bool
    :rtype: list[shuup.core.models.Product]
    """
    request = context["request"]
    customer = request.customer
    shop = request.shop

    # Todo: Check if this should be cached

    if not filter_dict:
        filter_dict = {}
    products_qs = Product.objects.listed(
        shop=shop,
        customer=customer,
        language=get_language(),
    ).filter(**filter_dict)

    if ordering:
        products_qs = products_qs.order_by(ordering)

    if sale_items_only:
        from shuup.core.pricing import PricingContext
        pricing_context = PricingContext(shop=shop, customer=customer)

    if orderable_only:
        suppliers = Supplier.objects.filter(shops=shop)
        products = []
        for product in products_qs.iterator():
            if len(products) == n_products:
                break
            try:
                shop_product = product.get_shop_instance(shop,
                                                         allow_cache=True)
            except ShopProduct.DoesNotExist:
                continue

            for supplier in suppliers:
                if shop_product.is_orderable(
                        supplier, customer,
                        shop_product.minimum_purchase_quantity):
                    if sale_items_only and not _is_sale_item(
                            product, pricing_context):
                        continue
                    products.append(product)
                    break

        return products

    elif sale_items_only:
        products = []
        for product in products_qs.iterator():
            if len(products) == n_products:
                break
            if _is_sale_item(product, pricing_context):
                products.append(product)
        return products

    return products_qs[:n_products]
コード例 #10
0
ファイル: utils.py プロジェクト: rrosajp/shuup
def index_shop_product_price(
    shop_product: ShopProduct,
    supplier: Supplier,
    contact_groups_ids: Iterable[int] = [],
):
    """
    Index discounts for the shop product
    """
    from shuup.discounts.models import ShopProductCatalogDiscountsLink
    from shuup.discounts.modules import ProductDiscountModule

    default_price = shop_product.default_price_value
    context = PricingContext(shop=shop_product.shop,
                             customer=AnonymousContact(),
                             supplier=supplier)
    discounts = get_potential_discounts_for_product(
        context,
        shop_product.product,
        available_only=False,
        groups_ids=contact_groups_ids,
        all_contacts=True)

    # link this shop product to the potencial discounts
    discounts_link = ShopProductCatalogDiscountsLink.objects.get_or_create(
        shop_product=shop_product)[0]
    discounts_link.discounts.set(discounts)

    if not discounts.exists():
        # delete all discounted prices
        ProductCatalogDiscountedPrice.objects.filter(
            product=shop_product.product,
            shop=shop_product.shop,
            catalog_rule__module_identifier=ProductDiscountModule.identifier,
        ).delete()

    for discount in discounts:
        discount_options = [default_price]

        if discount.discounted_price_value is not None:
            discount_options.append(discount.discounted_price_value)

        if discount.discount_amount_value is not None:
            discount_options.append(default_price -
                                    discount.discount_amount_value)

        if discount.discount_percentage is not None:
            discount_options.append(default_price -
                                    (default_price *
                                     discount.discount_percentage))

        best_discounted_price = max(min(discount_options), 0)
        happy_hours_times = list(
            discount.happy_hours.values_list(
                "time_ranges__from_hour",
                "time_ranges__to_hour",
                "time_ranges__weekday",
            ))

        # if ther is no happy hour configured,
        # let's create one rule without time constraints
        if not happy_hours_times:
            happy_hours_times.append((None, None, None))

        for from_hour, to_hour, weekday in happy_hours_times:
            catalog_rule = ProductCatalogDiscountedPriceRule.objects.get_or_create(
                module_identifier=ProductDiscountModule.identifier,
                contact_group=discount.contact_group,
                contact=discount.contact,
                valid_start_date=discount.start_datetime,
                valid_end_date=discount.end_datetime,
                valid_start_hour=from_hour,
                valid_end_hour=to_hour,
                valid_weekday=weekday,
            )[0]
            ProductCatalogDiscountedPrice.objects.update_or_create(
                product=shop_product.product,
                shop=shop_product.shop,
                supplier=supplier,
                catalog_rule=catalog_rule,
                defaults=dict(discounted_price_value=best_discounted_price),
            )
コード例 #11
0
 def get_lines(self, basket):
     for line in basket.get_lines():
         line.cache_info(PricingContext(basket.shop, basket.customer))
         serializer = APIBasketLineSerializer(
             line, context={'request': self.context['request']})
         yield serializer.data