From 99f8785e454fb053370b90a6cfca8506b6c004d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Szyma=C5=84ski?= Date: Fri, 10 May 2024 12:59:27 +0200 Subject: [PATCH] Fix discounts resolver to work like in docs (#15882) * Fix discounts resolver to work like in docs * order payload generator takes voucher type into account when returning discounts --- saleor/graphql/core/types/taxes.py | 12 +-- .../test_create_deliveries_for_taxes.py | 60 +++++++++++++- saleor/webhook/payloads.py | 3 + saleor/webhook/tests/test_webhook_payloads.py | 82 ++++++++++++++++++- 4 files changed, 149 insertions(+), 8 deletions(-) diff --git a/saleor/graphql/core/types/taxes.py b/saleor/graphql/core/types/taxes.py index 293e8f22862..7f504fff716 100644 --- a/saleor/graphql/core/types/taxes.py +++ b/saleor/graphql/core/types/taxes.py @@ -375,16 +375,16 @@ def resolve_discounts(root: Union[Checkout, Order], info: ResolveInfo): if isinstance(root, Checkout): def calculate_checkout_discounts(checkout_info): - is_shipping_voucher = ( - checkout_info.voucher.type == VoucherType.SHIPPING - if checkout_info.voucher - else False - ) checkout = checkout_info.checkout discount_name = checkout.discount_name return ( [{"name": discount_name, "amount": checkout.discount}] - if checkout.discount and not is_shipping_voucher + if checkout.discount + and ( + checkout_info.voucher + and checkout_info.voucher.type == VoucherType.ENTIRE_ORDER + and not checkout_info.voucher.apply_once_per_order + ) else [] ) diff --git a/saleor/plugins/webhook/tests/subscription_webhooks/test_create_deliveries_for_taxes.py b/saleor/plugins/webhook/tests/subscription_webhooks/test_create_deliveries_for_taxes.py index 4123427174f..3b98fe36ed8 100644 --- a/saleor/plugins/webhook/tests/subscription_webhooks/test_create_deliveries_for_taxes.py +++ b/saleor/plugins/webhook/tests/subscription_webhooks/test_create_deliveries_for_taxes.py @@ -190,7 +190,7 @@ def test_checkout_calculate_taxes_with_free_shipping_voucher( @freeze_time("2020-03-18 12:00:00") -def test_checkout_calculate_taxes_with_voucher( +def test_checkout_calculate_taxes_with_entire_order_voucher( checkout_with_voucher, webhook_app, permission_handle_taxes, @@ -244,6 +244,64 @@ def test_checkout_calculate_taxes_with_voucher( } +@freeze_time("2020-03-18 12:00:00") +def test_checkout_calculate_taxes_with_entire_order_voucher_once_per_order( + voucher, + checkout_with_voucher, + webhook_app, + permission_handle_taxes, +): + # given + webhook_app.permissions.add(permission_handle_taxes) + webhook = Webhook.objects.create( + name="Webhook", + app=webhook_app, + target_url="http://www.example.com/any", + subscription_query=TAXES_SUBSCRIPTION_QUERY, + ) + event_type = WebhookEventSyncType.CHECKOUT_CALCULATE_TAXES + webhook.events.create(event_type=event_type) + voucher.apply_once_per_order = True + voucher.save() + + # when + deliveries = create_delivery_for_subscription_sync_event( + event_type, checkout_with_voucher, webhook + ) + + # then + assert json.loads(deliveries.payload.payload) == { + "__typename": "CalculateTaxes", + "taxBase": { + "address": None, + "currency": "USD", + "discounts": [], + "channel": {"id": to_global_id_or_none(checkout_with_voucher.channel)}, + "lines": [ + { + "chargeTaxes": True, + "productName": "Test product", + "productSku": "123", + "quantity": 3, + "sourceLine": { + "id": to_global_id_or_none(checkout_with_voucher.lines.first()), + "__typename": "CheckoutLine", + }, + "totalPrice": {"amount": 20.0}, + "unitPrice": {"amount": 6.67}, + "variantName": "", + } + ], + "pricesEnteredWithTax": True, + "shippingPrice": {"amount": 0.0}, + "sourceObject": { + "id": to_global_id_or_none(checkout_with_voucher), + "__typename": "Checkout", + }, + }, + } + + @freeze_time("2020-03-18 12:00:00") def test_checkout_calculate_taxes_with_shipping_voucher( checkout_with_voucher, diff --git a/saleor/webhook/payloads.py b/saleor/webhook/payloads.py index afb92652c99..6ddaf414ab3 100644 --- a/saleor/webhook/payloads.py +++ b/saleor/webhook/payloads.py @@ -1406,6 +1406,9 @@ def generate_order_payload_for_tax_calculation(order: "Order"): discounts = order.discounts.all() discounts_dict = [] for discount in discounts: + if discount.voucher and discount.voucher.type == VoucherType.ENTIRE_ORDER: + if discount.voucher.apply_once_per_order: + continue quantize_price_fields(discount, ("amount_value",), order.currency) discount_amount = quantize_price(discount.amount_value, order.currency) discounts_dict.append({"name": discount.name, "amount": discount_amount}) diff --git a/saleor/webhook/tests/test_webhook_payloads.py b/saleor/webhook/tests/test_webhook_payloads.py index 9d07910c06f..540ec96f05e 100644 --- a/saleor/webhook/tests/test_webhook_payloads.py +++ b/saleor/webhook/tests/test_webhook_payloads.py @@ -20,7 +20,7 @@ from ...checkout.fetch import fetch_checkout_info, fetch_checkout_lines from ...core.prices import quantize_price from ...core.utils.json_serializer import CustomJsonEncoder -from ...discount import DiscountType, DiscountValueType +from ...discount import DiscountType, DiscountValueType, VoucherType from ...graphql.utils import get_user_or_app_from_context from ...order import FulfillmentLineData, OrderOrigin from ...order.actions import fulfill_order_lines @@ -306,6 +306,7 @@ def test_generate_order_payload_for_tax_calculation( order_for_payload, prices_entered_with_tax, ): + # given order = order_for_payload tax_configuration = order.channel.tax_configuration @@ -320,7 +321,10 @@ def test_generate_order_payload_for_tax_calculation( discount_1, discount_2 = list(order.discounts.all()) user = order.user + # when payload = json.loads(generate_order_payload_for_tax_calculation(order))[0] + + # then currency = order.currency assert payload == { @@ -371,6 +375,82 @@ def test_generate_order_payload_for_tax_calculation( mocked_order_lines.assert_called_once() +@freeze_time() +@pytest.mark.parametrize("prices_entered_with_tax", [True, False]) +@mock.patch("saleor.webhook.payloads._generate_order_lines_payload_for_tax_calculation") +def test_generate_order_payload_for_tax_calculation_voucher_discounts( + mocked_order_lines, order_for_payload, prices_entered_with_tax, voucher +): + # given + order = order_for_payload + + tax_configuration = order.channel.tax_configuration + tax_configuration.prices_entered_with_tax = prices_entered_with_tax + tax_configuration.save(update_fields=["prices_entered_with_tax"]) + tax_configuration.country_exceptions.all().delete() + + order_lines = '"order_lines"' + mocked_order_lines.return_value = order_lines + + order = order_for_payload + discount_1, discount_2 = list(order.discounts.all()) + voucher.type = VoucherType.ENTIRE_ORDER + voucher.apply_once_per_order = True + voucher.save() + discount_1.voucher = voucher + discount_1.save() + user = order.user + + # when + payload = json.loads(generate_order_payload_for_tax_calculation(order))[0] + + # then + currency = order.currency + + assert payload == { + "type": "Order", + "id": graphene.Node.to_global_id("Order", order.id), + "channel": { + "id": graphene.Node.to_global_id("Channel", order.channel_id), + "type": "Channel", + "slug": order.channel.slug, + "currency_code": order.channel.currency_code, + }, + "address": { + "id": graphene.Node.to_global_id("Address", order.shipping_address_id), + "type": "Address", + "first_name": order.shipping_address.first_name, + "last_name": order.shipping_address.last_name, + "company_name": order.shipping_address.company_name, + "street_address_1": order.shipping_address.street_address_1, + "street_address_2": order.shipping_address.street_address_2, + "city": order.shipping_address.city, + "city_area": order.shipping_address.city_area, + "postal_code": order.shipping_address.postal_code, + "country": order.shipping_address.country.code, + "country_area": order.shipping_address.country_area, + "phone": str(order.shipping_address.phone), + }, + "user_id": graphene.Node.to_global_id("User", user.pk), + "user_public_metadata": user.metadata, + "included_taxes_in_prices": prices_entered_with_tax, + "currency": order.currency, + "shipping_name": order.shipping_method.name, + "shipping_amount": str( + quantize_price(order.base_shipping_price_amount, currency) + ), + "metadata": order.metadata, + "discounts": [ + { + "name": discount_2.name, + "amount": str(quantize_price(discount_2.amount_value, currency)), + }, + ], + "lines": json.loads(order_lines), + } + mocked_order_lines.assert_called_once() + + @freeze_time() @mock.patch("saleor.webhook.payloads.generate_order_lines_payload") @mock.patch("saleor.webhook.payloads.generate_fulfillment_lines_payload")