API/Vouchers: Expose "budget" and "budget_used" (Z#286557) (#5325)

Co-authored-by: Richard Schreiber <schreiber@rami.io>
This commit is contained in:
Martin Gross
2025-07-28 18:53:15 +02:00
committed by GitHub
parent f5b0454e9f
commit e1756a1ebb
4 changed files with 23 additions and 8 deletions

View File

@@ -49,6 +49,8 @@ subevent integer ID of the date
show_hidden_items boolean Only if set to ``true``, this voucher allows to buy products with the property ``hide_without_voucher``. Defaults to ``true``. show_hidden_items boolean Only if set to ``true``, this voucher allows to buy products with the property ``hide_without_voucher``. Defaults to ``true``.
all_addons_included boolean If set to ``true``, all add-on products for the product purchased with this voucher are included in the base price. all_addons_included boolean If set to ``true``, all add-on products for the product purchased with this voucher are included in the base price.
all_bundles_included boolean If set to ``true``, all bundled products for the product purchased with this voucher are added without their designated price. all_bundles_included boolean If set to ``true``, all bundled products for the product purchased with this voucher are added without their designated price.
budget money (string) The budget a voucher is allowed to consume before being used up (or ``null``)
budget_used money (string) The amount of budget the voucher has already used up.
===================================== ========================== ======================================================= ===================================== ========================== =======================================================
@@ -99,7 +101,9 @@ Endpoints
"subevent": null, "subevent": null,
"show_hidden_items": false, "show_hidden_items": false,
"all_addons_included": false, "all_addons_included": false,
"all_bundles_included": false "all_bundles_included": false,
"budget": None,
"budget_used": "0.00"
} }
] ]
} }
@@ -169,7 +173,9 @@ Endpoints
"subevent": null, "subevent": null,
"show_hidden_items": false, "show_hidden_items": false,
"all_addons_included": false, "all_addons_included": false,
"all_bundles_included": false "all_bundles_included": false,
"budget": None,
"budget_used": "0.00"
} }
:param organizer: The ``slug`` field of the organizer to fetch :param organizer: The ``slug`` field of the organizer to fetch
@@ -239,7 +245,9 @@ Endpoints
"subevent": null, "subevent": null,
"show_hidden_items": false, "show_hidden_items": false,
"all_addons_included": false, "all_addons_included": false,
"all_bundles_included": false "all_bundles_included": false,
"budget": None,
"budget_used": "0.00"
} }
:param organizer: The ``slug`` field of the organizer to create a voucher for :param organizer: The ``slug`` field of the organizer to create a voucher for
@@ -376,7 +384,9 @@ Endpoints
"subevent": null, "subevent": null,
"show_hidden_items": false, "show_hidden_items": false,
"all_addons_included": false, "all_addons_included": false,
"all_bundles_included": false "all_bundles_included": false,
"budget": None,
"budget_used": "0.00"
} }
:param organizer: The ``slug`` field of the organizer to modify :param organizer: The ``slug`` field of the organizer to modify

View File

@@ -19,6 +19,8 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see # You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>. # <https://www.gnu.org/licenses/>.
# #
from decimal import Decimal
from rest_framework import serializers from rest_framework import serializers
from rest_framework.exceptions import ValidationError from rest_framework.exceptions import ValidationError
@@ -64,14 +66,15 @@ class SeatGuidField(serializers.CharField):
class VoucherSerializer(I18nAwareModelSerializer): class VoucherSerializer(I18nAwareModelSerializer):
seat = SeatGuidField(allow_null=True, required=False) seat = SeatGuidField(allow_null=True, required=False)
budget_used = serializers.DecimalField(read_only=True, max_digits=13, decimal_places=2, min_value=Decimal('0.00'))
class Meta: class Meta:
model = Voucher model = Voucher
fields = ('id', 'code', 'max_usages', 'redeemed', 'min_usages', 'valid_until', 'block_quota', fields = ('id', 'code', 'max_usages', 'redeemed', 'min_usages', 'valid_until', 'block_quota',
'allow_ignore_quota', 'price_mode', 'value', 'item', 'variation', 'quota', 'allow_ignore_quota', 'price_mode', 'value', 'item', 'variation', 'quota',
'tag', 'comment', 'subevent', 'show_hidden_items', 'seat', 'all_addons_included', 'tag', 'comment', 'subevent', 'show_hidden_items', 'seat', 'all_addons_included',
'all_bundles_included') 'all_bundles_included', 'budget', 'budget_used')
read_only_fields = ('id', 'redeemed') read_only_fields = ('id', 'redeemed', 'budget_used')
list_serializer_class = VoucherListSerializer list_serializer_class = VoucherListSerializer
def validate(self, data): def validate(self, data):

View File

@@ -1750,7 +1750,7 @@ def test_event_expand_seat_filter_and_querycount(token_client, organizer, event,
with scope(organizer=organizer): with scope(organizer=organizer):
v0 = event.vouchers.create(item=item, seat=event.seats.get(seat_guid='0-0')) v0 = event.vouchers.create(item=item, seat=event.seats.get(seat_guid='0-0'))
with assert_num_queries(13): with assert_num_queries(14):
resp = token_client.get('/api/v1/organizers/{}/events/{}/seats/' resp = token_client.get('/api/v1/organizers/{}/events/{}/seats/'
'?expand=orderposition&expand=cartposition&expand=voucher&is_available=false' '?expand=orderposition&expand=cartposition&expand=voucher&is_available=false'
.format(organizer.slug, event.slug)) .format(organizer.slug, event.slug))
@@ -1769,7 +1769,7 @@ def test_event_expand_seat_filter_and_querycount(token_client, organizer, event,
v1 = event.vouchers.create(item=item, seat=event.seats.get(seat_guid='0-1')) v1 = event.vouchers.create(item=item, seat=event.seats.get(seat_guid='0-1'))
v2 = event.vouchers.create(item=item, seat=event.seats.get(seat_guid='0-2')) v2 = event.vouchers.create(item=item, seat=event.seats.get(seat_guid='0-2'))
with assert_num_queries(13): with assert_num_queries(16):
resp = token_client.get('/api/v1/organizers/{}/events/{}/seats/' resp = token_client.get('/api/v1/organizers/{}/events/{}/seats/'
'?expand=orderposition&expand=cartposition&expand=voucher&is_available=false' '?expand=orderposition&expand=cartposition&expand=voucher&is_available=false'
.format(organizer.slug, event.slug)) .format(organizer.slug, event.slug))

View File

@@ -81,6 +81,8 @@ TEST_VOUCHER_RES = {
'all_bundles_included': False, 'all_bundles_included': False,
'subevent': None, 'subevent': None,
'seat': None, 'seat': None,
'budget': None,
'budget_used': "0.00",
} }