Migrated from Redmine #1184 | Author: Thomas Luzat
Status: New | Priority: High, I’m very impatient | Created: 2024-03-01
I noticed some problems with coupons. The worst one is that codes can be applied multiple times and customers can baiscally order for free.
When accessing /admin/promotions/coupons?filter[code]=CODE using the REST API, I get a result such as:
{
"data": [
{
"id": 4672,
"promotion": {
"id": 3587,
"name": "XXXX",
"description": "",
"file_id": null,
"picture_preview": null,
"picture_large": null,
"is_active": true,
"position": 5996,
"price": 0.0,
"currency": "EUR",
"tax": null,
"promotion_type": "discount",
"discount_type": "fixed_amount",
"discount": 209.3,
"duration_type": "month",
"duration": 1,
"client_type": "all",
"allow_usage_count": 1,
"is_unlimited": false,
"affect_services": true,
"affect_products": true,
"affect_paid_attributes": true,
"affect_memberships": false,
"affected_packages": false,
"service_restrictions": [],
"booking_restrictions": [],
"product_restrictions": [],
"paid_attribute_restrictions": [],
"memberships_restrictions": [],
"package_restrictions": [],
"print_template_id": 1,
"bonus_is_enabled": false,
"bonus_amount": 0
},
"start_date": null,
"expired_date": "2027-02-25",
"is_used": true,
"can_be_used": true,
"can_be_used_count": -1,
"code": "XXXX",
"client_id": null,
"client": null,
"user_id": "1",
"user": {
…
},
"status": "used",
"used_count": "2",
"used_amount": "337.3000",
"rest_amount": null,
"allowed_to_use_full_amount": true
}
],
"metadata": {
…
}
}
There are some minor and some major problems (3. is the worst one):
- used_amount is either null or a string. Why not always a float (like promotion.discount), either 0.0 or some value? Similar for rest_amount, used_count, user_id. Other values are integers, such as can_be_used_count …
- rest_amount is null for coupons? It would be nice to have it go from 209.3 down to 0.0, somewhat similar to gift cards.
- I was able to apply this code to two orders using /admin/invoices/…/apply-promo-code and the price was in sum reduced by 337.30 € (as indicated by used_amount), even though it should have been limited to 209.30 €. Expected: Discount should be used to reduce order 1 fully (e.g. by 190 €) and partially for order 2 (e.g. by 19.30 € which are still left, 200+19.30 = 209.30). According to the SimplyBook interface, fixed discount coupons should be usable across multiple orders like gift cards if there is value left.
- Values are completely broken now: can_be_used is still true, can_be_used_count is negative, used_count > allow_usage_count. Not sure what allowed_to_use_full_amount indicates.
What I expect:
- used_amount and rest_amount should always be valid floats except for percentage discounts, where they should be zero. integers should preferably also be represented as integers, not strings.
- The discount should only apply at most rest_amount if it has already been partially applied. Also, can_be_used should be false when rest_amount reaches 0.0.
A valid rest_amount and can_be_used would allow to easier provide a better custom interface for booking. Currently I use something like:
if (can_be_used && (used_amount === null || promotion_type.discount > parseFloat(used_amount))) { show(rest_amount) }
I would prefer:
if (can_be_used) { show(rest_amount) }
or similar, but the worst problem is obviously that the code is applied multiple times with too much of a value.
There seems to be some broken logic for the shown configuration in apply-promo-code and in the coupons endpoint. It might even be that I can still use the coupon shown above.