-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(promotion): handle promotion buy X get X scenario #9002
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
6 Skipped Deployments
|
|
I just pulled this PR locally to test and I had a question, is each promotions only supposed to apply once or is it supposed to continue applying each promotion while remainingQtyToApply gte minimumBuyQuantity? |
Each promotion is applied only once. We don't support applying multiple times per cart yet. |
ok. There's still a computational error here. see image below. The amount is shown correctly on the line_item but cart summary does not show the correct amounts. Should be a total of $150 + tax. Second promo is being applied across entire amount 1050. instead of just the 1000 and charging for the 50. |
@420coupe, we're fixing the cart summary totals in a separate PR. I've added some more test cases and from the looks of it the promotions is spitting out the correct totals. Let me know if you see more irregularities from the promotion module. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM as far as I could understand the code, but it is quite complex and difficult to follow so I am not 100% confident :)
@riqwan math still isn't mathing. Totals are correct, but summary is wrong. |
@420coupe maybe I misunderstood, which summary are you talking about? Can you share the full cart context? |
The discount amount is more than the cost, but shows 160.50 as total. Adjustment should be $2700-$2550= $150 then add the taxes which is shown correctly and total is right. Discount is what is incorrect. |
@riqwan {
"id": "order_01J7EB8HVY8RD4C01EHX2Z63GE",
"status": "pending",
"created_at": "2024-09-10T16:11:28.015Z",
"canceled_at": null,
"email": "420coupe@gmail.com",
"display_id": 84,
"currency_code": "usd",
"total": 160.5,
"subtotal": 2700,
"shipping_total": 0,
"shipping_tax_total": 0,
"tax_total": 10.5,
"summary": {
"paid_total": 0,
"difference_sum": 0,
"raw_paid_total": {
"value": "0",
"precision": 20
},
"refunded_total": 0,
"transaction_total": 0,
"pending_difference": 160.5,
"raw_difference_sum": {
"value": "0",
"precision": 20
},
"raw_refunded_total": {
"value": "0",
"precision": 20
},
"current_order_total": 160.5,
"original_order_total": 160.5,
"raw_transaction_total": {
"value": "0",
"precision": 20
},
"raw_pending_difference": {
"value": "160.5",
"precision": 20
},
"raw_current_order_total": {
"value": "160.5",
"precision": 20
},
"raw_original_order_total": {
"value": "160.5",
"precision": 20
}
},
"version": 2,
"customer_id": "cus_01J7C48H2C2DJE3A38EF656EC3",
"sales_channel_id": "sc_01J4VWQ8M0HWZ9TWP6SNWKJSA0",
"items": [
{
"id": "ordli_01J7EB8HWAWSMYP8X5G53MGQFZ",
"title": "Test 2 - FCKCANCER",
"subtitle": "Test 2 - FCKCANCER",
"thumbnail": "https://bswoomuofvjncykvpasn.supabase.co/storage/v1/object/public/derftuned/fuckCancer-reduced-01J5WAXVQSZXYY0JF83QB304TV.png",
"variant_id": "variant_01J5WAY0RQH4GJ3MPT8WM2DZAV",
"product_id": "prod_01J5WAY0AEQ6S6FS5Z3WG8214A",
"product_title": "Test 2 - FCKCANCER",
"product_description": "FCK CANCER VINYL DECAL",
"product_subtitle": "FCK CANCER",
"product_type": null,
"product_collection": null,
"product_handle": "test-2-fckcancer",
"variant_sku": null,
"variant_barcode": null,
"variant_title": "Test 2 - FCKCANCER",
"variant_option_values": null,
"requires_shipping": true,
"is_discountable": true,
"is_tax_inclusive": false,
"raw_compare_at_unit_price": null,
"raw_unit_price": {
"value": "2.5",
"precision": 20
},
"is_custom_price": false,
"metadata": {},
"created_at": "2024-09-10T16:11:28.017Z",
"updated_at": "2024-09-10T16:11:28.018Z",
"deleted_at": null,
"tax_lines": [
{
"id": "ordlitxl_01J7EB8HW51233Z6Q6H7V2YPVA",
"description": "Sales Tax",
"tax_rate_id": "txr_01J4W4H06MC7ZZFE82X4TNFZ2N",
"code": "",
"raw_rate": {
"value": "7",
"precision": 20
},
"provider_id": "system",
"created_at": "2024-09-10T16:11:28.027Z",
"updated_at": "2024-09-10T16:11:28.027Z",
"deleted_at": null,
"item_id": "ordli_01J7EB8HWAWSMYP8X5G53MGQFZ",
"rate": 7,
"total": 10.5,
"subtotal": 189,
"raw_total": {
"value": "10.5",
"precision": 20
},
"raw_subtotal": {
"value": "189",
"precision": 20
}
}
],
"adjustments": [
{
"id": "ordliadj_01J7EB8HW8JQBFTSSJ8CKDP1ZQ",
"description": null,
"promotion_id": "promo_01J61AWQCF6E5Y9D0MK6APVJXS",
"code": "Buy10Get20",
"raw_amount": {
"value": "50",
"precision": 20
},
"provider_id": "promo_01J61AWQCF6E5Y9D0MK6APVJXS",
"created_at": "2024-09-10T16:11:28.027Z",
"updated_at": "2024-09-10T16:11:28.027Z",
"deleted_at": null,
"item_id": "ordli_01J7EB8HWAWSMYP8X5G53MGQFZ",
"amount": 50,
"subtotal": 50,
"total": 53.5,
"raw_subtotal": {
"value": "50",
"precision": 20
},
"raw_total": {
"value": "53.5",
"precision": 20
}
},
{
"id": "ordliadj_01J7EB8HW93SC3ZAVGDDDEP6QF",
"description": null,
"promotion_id": "promo_01J707N4AEGZBJN98DXT2NXYAK",
"code": "BUY50GET1000",
"raw_amount": {
"value": "2500",
"precision": 20
},
"provider_id": "promo_01J707N4AEGZBJN98DXT2NXYAK",
"created_at": "2024-09-10T16:11:28.028Z",
"updated_at": "2024-09-10T16:11:28.028Z",
"deleted_at": null,
"item_id": "ordli_01J7EB8HWAWSMYP8X5G53MGQFZ",
"amount": 2500,
"subtotal": 2500,
"total": 2675,
"raw_subtotal": {
"value": "2500",
"precision": 20
},
"raw_total": {
"value": "2675",
"precision": 20
}
}
],
"compare_at_unit_price": null,
"unit_price": 2.5,
"quantity": 1080,
"raw_quantity": {
"value": "1080",
"precision": 20
},
"detail": {
"id": "orditem_01J7EB8N052BM5Y9252PVAG509",
"order_id": "order_01J7EB8HVY8RD4C01EHX2Z63GE",
"version": 2,
"item_id": "ordli_01J7EB8HWAWSMYP8X5G53MGQFZ",
"raw_quantity": {
"value": "1080",
"precision": 20
},
"raw_fulfilled_quantity": {
"value": "1080",
"precision": 20
},
"raw_shipped_quantity": {
"value": "0",
"precision": 20
},
"raw_return_requested_quantity": {
"value": "0",
"precision": 20
},
"raw_return_received_quantity": {
"value": "0",
"precision": 20
},
"raw_return_dismissed_quantity": {
"value": "0",
"precision": 20
},
"raw_written_off_quantity": {
"value": "0",
"precision": 20
},
"metadata": null,
"created_at": "2024-09-10T16:11:31.332Z",
"updated_at": "2024-09-10T16:11:31.332Z",
"deleted_at": null,
"quantity": 1080,
"fulfilled_quantity": 1080,
"shipped_quantity": 0,
"return_requested_quantity": 0,
"return_received_quantity": 0,
"return_dismissed_quantity": 0,
"written_off_quantity": 0
},
"subtotal": 2700,
"total": 160.5,
"original_total": 2889,
"discount_total": 2728.5,
"discount_subtotal": 2550,
"discount_tax_total": 178.5,
"tax_total": 10.5,
"original_tax_total": 189,
"refundable_total_per_unit": -0.02638888888888889,
"refundable_total": -28.5,
"fulfilled_total": 160.5,
"shipped_total": 0,
"return_requested_total": 0,
"return_received_total": 0,
"return_dismissed_total": 0,
"write_off_total": 0,
"raw_subtotal": {
"value": "2700",
"precision": 20
},
"raw_total": {
"value": "160.5",
"precision": 20
},
"raw_original_total": {
"value": "2889",
"precision": 20
},
"raw_discount_total": {
"value": "2728.5",
"precision": 20
},
"raw_discount_subtotal": {
"value": "2550",
"precision": 20
},
"raw_discount_tax_total": {
"value": "178.5",
"precision": 20
},
"raw_tax_total": {
"value": "10.5",
"precision": 20
},
"raw_original_tax_total": {
"value": "189",
"precision": 20
},
"raw_refundable_total_per_unit": {
"value": "-0.02638888888888888889",
"precision": 20
},
"raw_refundable_total": {
"value": "-28.500000000000000001",
"precision": 20
},
"raw_fulfilled_total": {
"value": "160.5",
"precision": 20
},
"raw_shipped_total": {
"value": "0",
"precision": 20
},
"raw_return_requested_total": {
"value": "0",
"precision": 20
},
"raw_return_received_total": {
"value": "0",
"precision": 20
},
"raw_return_dismissed_total": {
"value": "0",
"precision": 20
},
"raw_write_off_total": {
"value": "0",
"precision": 20
},
"variant": {
"id": "variant_01J5WAY0RQH4GJ3MPT8WM2DZAV",
"title": "Test 2 - FCKCANCER",
"sku": null,
"barcode": null,
"ean": null,
"upc": null,
"allow_backorder": true,
"manage_inventory": true,
"hs_code": null,
"origin_country": "us",
"mid_code": null,
"material": "Vinyl",
"weight": null,
"length": null,
"height": null,
"width": null,
"metadata": {
"fieldId": "fuckCancer-reduced-01J5WAXVQSZXYY0JF83QB304TV.png"
},
"variant_rank": 0,
"product_id": "prod_01J5WAY0AEQ6S6FS5Z3WG8214A",
"product": {
"id": "prod_01J5WAY0AEQ6S6FS5Z3WG8214A",
"title": "Test 2 - FCKCANCER",
"handle": "test-2-fckcancer",
"subtitle": "FCK CANCER",
"description": "FCK CANCER VINYL DECAL",
"is_giftcard": false,
"status": "published",
"thumbnail": "https://bswoomuofvjncykvpasn.supabase.co/storage/v1/object/public/derftuned/fuckCancer-reduced-01J5WAXVQSZXYY0JF83QB304TV.png",
"weight": null,
"length": null,
"height": null,
"width": null,
"origin_country": null,
"hs_code": null,
"mid_code": null,
"material": "Vinyl Decal",
"collection_id": null,
"collection": null,
"type_id": null,
"discountable": true,
"external_id": null,
"created_at": "2024-08-22T06:03:40.684Z",
"updated_at": "2024-08-22T06:03:40.684Z",
"deleted_at": null,
"metadata": {
"fieldID": "fuckCancer-reduced-01J5WAXVQSZXYY0JF83QB304TV.png"
},
"type": null
},
"created_at": "2024-08-22T06:03:41.208Z",
"updated_at": "2024-08-22T06:03:41.208Z",
"deleted_at": null,
"options": [
{
"id": "optval_01J5WAY0FHBJ9R52ED13J71D00",
"value": "default",
"option_id": "opt_01J5WAY0D0V3NMHE4TQ6JHF43N",
"option": {
"id": "opt_01J5WAY0D0V3NMHE4TQ6JHF43N",
"product_id": null
},
"metadata": null,
"created_at": "2024-08-22T06:03:40.684Z",
"updated_at": "2024-08-22T06:03:40.684Z",
"deleted_at": null
}
],
"inventory_items": [
{
"required_quantity": 0,
"variant_id": "variant_01J5WAY0RQH4GJ3MPT8WM2DZAV",
"inventory_item_id": "iitem_01J5WAY17ST31NAPXAZ9SC1MEQ",
"inventory": {
"id": "iitem_01J5WAY17ST31NAPXAZ9SC1MEQ",
"created_at": "2024-08-22T06:03:41.690Z",
"updated_at": "2024-08-22T06:03:41.690Z",
"deleted_at": null,
"sku": null,
"origin_country": null,
"hs_code": null,
"mid_code": null,
"material": null,
"weight": null,
"length": null,
"height": null,
"width": null,
"requires_shipping": true,
"description": "Test 2 - FCKCANCER",
"title": "Test 2 - FCKCANCER",
"thumbnail": null,
"metadata": null
}
}
]
}
}
],
"shipping_address": {
"id": "caaddr_01J7EB7A0P262BKF316FD4FZT9",
"customer_id": null,
"company": "",
"first_name": "Test",
"last_name": "User",
"address_1": "123 Fake Street",
"address_2": "",
"city": "Miami",
"country_code": "us",
"province": "FL",
"postal_code": "33342",
"phone": "3055555555",
"metadata": null,
"created_at": "2024-09-10T16:10:47.191Z",
"updated_at": "2024-09-10T16:10:47.191Z"
},
"billing_address": {
"id": "caaddr_01J7EB7A0PC1QGZHHVHHBB3EJ2",
"customer_id": null,
"company": "",
"first_name": "Test",
"last_name": "User",
"address_1": "123 Fake Street",
"address_2": "",
"city": "Miami",
"country_code": "us",
"province": "FL",
"postal_code": "33342",
"phone": "3055555555",
"metadata": null,
"created_at": "2024-09-10T16:10:47.191Z",
"updated_at": "2024-09-10T16:10:47.191Z"
},
"shipping_methods": [
{
"id": "ordsm_01J7EB8HVXVEC8T45TWANHKBB4",
"name": "Digital Products",
"description": null,
"raw_amount": {
"value": "0",
"precision": 20
},
"is_tax_inclusive": false,
"is_custom_amount": false,
"shipping_option_id": "so_01J5BSXYZ03TZY4NR98XSW8P25",
"data": {},
"metadata": null,
"created_at": "2024-09-10T16:11:28.024Z",
"updated_at": "2024-09-10T16:11:28.024Z",
"deleted_at": null,
"tax_lines": [
{
"id": "ordsmtxl_01J7EB8HVWA1WC4RC745TY6NDX",
"description": "Sales Tax",
"tax_rate_id": "txr_01J4W4H06MC7ZZFE82X4TNFZ2N",
"code": "",
"raw_rate": {
"value": "7",
"precision": 20
},
"provider_id": "system",
"created_at": "2024-09-10T16:11:28.026Z",
"updated_at": "2024-09-10T16:11:28.026Z",
"deleted_at": null,
"shipping_method_id": "ordsm_01J7EB8HVXVEC8T45TWANHKBB4",
"rate": 7
}
],
"adjustments": [],
"amount": 0,
"order_id": "order_01J7EB8HVY8RD4C01EHX2Z63GE",
"detail": {
"id": "ordspmv_01J7EB8N071AFEASMRKRG4JJ19",
"order_id": "order_01J7EB8HVY8RD4C01EHX2Z63GE",
"version": 2,
"shipping_method_id": "ordsm_01J7EB8HVXVEC8T45TWANHKBB4",
"created_at": "2024-09-10T16:11:28.025Z",
"updated_at": "2024-09-10T16:11:28.025Z",
"deleted_at": null
},
"subtotal": 0,
"total": 0,
"original_total": 0,
"discount_total": 0,
"discount_subtotal": 0,
"discount_tax_total": 0,
"tax_total": 0,
"original_tax_total": 0,
"raw_subtotal": {
"value": "0",
"precision": 20
},
"raw_total": {
"value": "0",
"precision": 20
},
"raw_original_total": {
"value": "0",
"precision": 20
},
"raw_discount_total": {
"value": "0",
"precision": 20
},
"raw_discount_subtotal": {
"value": "0",
"precision": 20
},
"raw_discount_tax_total": {
"value": "0",
"precision": 20
},
"raw_tax_total": {
"value": "0",
"precision": 20
},
"raw_original_tax_total": {
"value": "0",
"precision": 20
}
}
],
"customer": {
"id": "cus_01J7C48H2C2DJE3A38EF656EC3",
"company_name": null,
"first_name": null,
"last_name": null,
"email": "420coupe@gmail.com",
"phone": null,
"has_account": false,
"metadata": null,
"created_at": "2024-09-09T19:30:38.286Z",
"updated_at": "2024-09-09T19:30:38.286Z",
"deleted_at": null,
"created_by": null
},
"sales_channel": {
"id": "sc_01J4VWQ8M0HWZ9TWP6SNWKJSA0",
"name": "DerfTuned.com",
"description": "e-commerce store front",
"is_disabled": false,
"created_at": "2024-08-09T15:39:37.986Z",
"metadata": null,
"updated_at": "2024-08-12T07:45:35.861Z",
"deleted_at": null
},
"fulfillments": [
{
"id": "ful_01J7EB8M4QEJVVDG38J48XBJMC",
"location_id": "sloc_01J4WFVFM3HHXGA5NNGM6SCT7B",
"packed_at": "2024-09-10T16:11:30.265Z",
"shipped_at": null,
"marked_shipped_by": null,
"created_by": null,
"delivered_at": null,
"canceled_at": null,
"data": {},
"provider_id": "digital_digital",
"shipping_option_id": "so_01J5BSXYZ03TZY4NR98XSW8P25",
"metadata": null,
"shipping_option": {
"id": "so_01J5BSXYZ03TZY4NR98XSW8P25"
},
"delivery_address": {
"id": "fuladdr_01J7EB8M4M1AE5MGMPNV7D2VN1"
},
"created_at": "2024-09-10T16:11:30.329Z",
"updated_at": "2024-09-10T16:11:30.329Z",
"deleted_at": null,
"provider": {
"id": "digital_digital"
},
"items": [
{
"id": "fulit_01J7EB8M4PW12412PCSSA1GNXJ",
"title": "Test 2 - FCKCANCER",
"sku": "",
"barcode": "",
"raw_quantity": {
"value": "1080",
"precision": 20
},
"line_item_id": "ordli_01J7EB8HWAWSMYP8X5G53MGQFZ",
"inventory_item_id": null,
"fulfillment_id": "ful_01J7EB8M4QEJVVDG38J48XBJMC",
"created_at": "2024-09-10T16:11:30.330Z",
"updated_at": "2024-09-10T16:11:30.330Z",
"deleted_at": null,
"quantity": 1080
}
],
"labels": []
}
],
"payment_collections": [
{
"id": "pay_col_01J7EB7W1V1H945X8EGEDFSZ41",
"currency_code": "usd",
"raw_amount": {
"value": "160.5",
"precision": 20
},
"raw_authorized_amount": {
"value": "160.5",
"precision": 20
},
"raw_captured_amount": {
"value": "160.5",
"precision": 20
},
"raw_refunded_amount": {
"value": "0",
"precision": 20
},
"region_id": "reg_01J4WE7JHSS32T9WKDWHPF1YKY",
"created_at": "2024-09-10T16:11:05.660Z",
"updated_at": "2024-09-10T16:11:27.037Z",
"deleted_at": null,
"completed_at": null,
"status": "authorized",
"metadata": null,
"payments": [
{
"id": "pay_01J7EB8FTBX4953S1Y7HJ3Y8JM",
"raw_amount": {
"value": "160.5",
"precision": 20
},
"currency_code": "usd",
"provider_id": "pp_stripe_stripe",
"cart_id": null,
"order_id": null,
"customer_id": null,
"data": {
"id": "pi_3PxWelK6QjZA3FWk1zQN3B25",
"amount": 16050,
"object": "payment_intent",
"review": null,
"source": null,
"status": "succeeded",
"created": 1725984667,
"invoice": null,
"currency": "usd",
"customer": "cus_QpB0xKgGpmyysH",
"livemode": false,
"metadata": {
"session_id": "payses_01J7EB7WMBGR9214FYX2E1N8Z6"
},
"shipping": null,
"processing": null,
"application": null,
"canceled_at": null,
"description": null,
"next_action": null,
"on_behalf_of": null,
"client_secret": "pi_3PxWelK6QjZA3FWk1zQN3B25_secret_QHwEyhid9QSg5oeQ0HTzJxxrN",
"latest_charge": "ch_3PxWelK6QjZA3FWk1FzIt8Tf",
"receipt_email": null,
"transfer_data": null,
"amount_details": {
"tip": {}
},
"capture_method": "automatic",
"payment_method": "pm_1PxWf1K6QjZA3FWkP7E6d8pw",
"transfer_group": null,
"amount_received": 16050,
"amount_capturable": 0,
"last_payment_error": null,
"setup_future_usage": null,
"cancellation_reason": null,
"confirmation_method": "automatic",
"payment_method_types": [
"card",
"klarna",
"link",
"affirm",
"cashapp",
"amazon_pay"
],
"statement_descriptor": null,
"application_fee_amount": null,
"payment_method_options": {
"card": {
"network": null,
"installments": null,
"mandate_options": null,
"request_three_d_secure": "automatic"
},
"link": {
"persistent_token": null
},
"affirm": {},
"klarna": {
"preferred_locale": null
},
"cashapp": {},
"amazon_pay": {
"express_checkout_element_session_id": null
}
},
"automatic_payment_methods": {
"enabled": true,
"allow_redirects": "always"
},
"statement_descriptor_suffix": null,
"payment_method_configuration_details": {
"id": "pmc_1PoE5nK6QjZA3FWk3b502P3b",
"parent": null
}
},
"metadata": null,
"created_at": "2024-09-10T16:11:25.902Z",
"updated_at": "2024-09-10T16:11:26.747Z",
"deleted_at": null,
"captured_at": "2024-09-10T16:11:26.322Z",
"canceled_at": null,
"payment_collection_id": "pay_col_01J7EB7W1V1H945X8EGEDFSZ41",
"payment_session": {
"id": "payses_01J7EB7WMBGR9214FYX2E1N8Z6"
},
"refunds": [],
"amount": 160.5
}
],
"amount": 160.5,
"authorized_amount": 160.5,
"captured_amount": 160.5,
"refunded_amount": 0
}
],
"payment_status": "captured",
"fulfillment_status": "fulfilled"
}``` |
Here's an example of it being correct with a similar example. Your cart summary totals are correct as well, you should be using |
So should OrderDTO have discount_subtotal first class var added to it? it currently only has discount_total as a first class which is giving back that total discount amount. |
@420coupe good point, yes it should. Do you wanna give opening a PR a shot? |
yeah i'll submit a PR with the class change now. |
what:
When a buy get promotion is created where the target and the buy item is the same, we don't handle this scenario correctly as we would end up applying the promotion on the same items that cause it to qualify for the promotion.
This PR removes the qualified items from the buy side when applying promotions on the target.
RESOLVES CC-416