mirror of
https://github.com/pretix/pretix.git
synced 2025-12-13 12:42:26 +00:00
Compare commits
6 Commits
a11y-valid
...
api-create
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4619901a37 | ||
|
|
ee921a6331 | ||
|
|
3310e9670b | ||
|
|
93570d42c7 | ||
|
|
598527073c | ||
|
|
d011651565 |
@@ -75,8 +75,9 @@ positions list of objects List of order p
|
|||||||
fees list of objects List of fees included in the order total. By default, only
|
fees list of objects List of fees included in the order total. By default, only
|
||||||
non-canceled fees are included.
|
non-canceled fees are included.
|
||||||
├ id integer Internal ID of the fee record
|
├ id integer Internal ID of the fee record
|
||||||
├ fee_type string Type of fee (currently ``payment``, ``passbook``,
|
├ fee_type string Type of fee (currently ``payment``, ``shipping``,
|
||||||
``other``)
|
``service``, ``cancellation``, ``insurance``, ``late``,
|
||||||
|
``other``, ``giftcard``)
|
||||||
├ value money (string) Fee amount
|
├ value money (string) Fee amount
|
||||||
├ description string Human-readable string with more details (can be empty)
|
├ description string Human-readable string with more details (can be empty)
|
||||||
├ internal_type string Internal string (i.e. ID of the payment provider),
|
├ internal_type string Internal string (i.e. ID of the payment provider),
|
||||||
@@ -2244,6 +2245,9 @@ otherwise, such as splitting an order or changing fees.
|
|||||||
|
|
||||||
* ``cancel_fees``: A list of objects with the single key ``fee`` specifying an order fee ID.
|
* ``cancel_fees``: A list of objects with the single key ``fee`` specifying an order fee ID.
|
||||||
|
|
||||||
|
* ``create_fees``: A list of objects describing new order fees with the fields ``fee_type``, ``value``, ``description``,
|
||||||
|
``internal_type``, ``tax_rule``
|
||||||
|
|
||||||
* ``recalculate_taxes``: If set to ``"keep_net"``, all taxes will be recalculated based on the tax rule and invoice
|
* ``recalculate_taxes``: If set to ``"keep_net"``, all taxes will be recalculated based on the tax rule and invoice
|
||||||
address, the net price will be kept. If set to ``"keep_gross"``, the gross price will be kept. If set to ``null``
|
address, the net price will be kept. If set to ``"keep_gross"``, the gross price will be kept. If set to ``null``
|
||||||
(the default) the taxes are not recalculated.
|
(the default) the taxes are not recalculated.
|
||||||
@@ -2263,17 +2267,12 @@ otherwise, such as splitting an order or changing fees.
|
|||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
|
|
||||||
{
|
{
|
||||||
"cancel_positions": [
|
|
||||||
{
|
|
||||||
"position": 12373
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"patch_positions": [
|
"patch_positions": [
|
||||||
{
|
{
|
||||||
"position": 12374,
|
"position": 12374,
|
||||||
"body": {
|
"body": {
|
||||||
"item": 12,
|
"item": 12,
|
||||||
"variation": None,
|
"variation": null,
|
||||||
"subevent": 562,
|
"subevent": 562,
|
||||||
"seat": "seat-guid-2",
|
"seat": "seat-guid-2",
|
||||||
"price": "99.99",
|
"price": "99.99",
|
||||||
@@ -2281,6 +2280,11 @@ otherwise, such as splitting an order or changing fees.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"cancel_positions": [
|
||||||
|
{
|
||||||
|
"position": 12373
|
||||||
|
}
|
||||||
|
],
|
||||||
"split_positions": [
|
"split_positions": [
|
||||||
{
|
{
|
||||||
"position": 12375
|
"position": 12375
|
||||||
@@ -2289,7 +2293,7 @@ otherwise, such as splitting an order or changing fees.
|
|||||||
"create_positions": [
|
"create_positions": [
|
||||||
{
|
{
|
||||||
"item": 12,
|
"item": 12,
|
||||||
"variation": None,
|
"variation": null,
|
||||||
"subevent": 562,
|
"subevent": 562,
|
||||||
"seat": "seat-guid-2",
|
"seat": "seat-guid-2",
|
||||||
"price": "99.99",
|
"price": "99.99",
|
||||||
@@ -2297,12 +2301,7 @@ otherwise, such as splitting an order or changing fees.
|
|||||||
"attendee_name": "Peter",
|
"attendee_name": "Peter",
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"cancel_fees": [
|
"patch_fees": [
|
||||||
{
|
|
||||||
"fee": 49
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"change_fees": [
|
|
||||||
{
|
{
|
||||||
"fee": 51,
|
"fee": 51,
|
||||||
"body": {
|
"body": {
|
||||||
@@ -2310,6 +2309,20 @@ otherwise, such as splitting an order or changing fees.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"cancel_fees": [
|
||||||
|
{
|
||||||
|
"fee": 49
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"create_fees": [
|
||||||
|
{
|
||||||
|
"fee_type": "other",
|
||||||
|
"value": "1.50",
|
||||||
|
"description": "Example Fee",
|
||||||
|
"internal_type": "",
|
||||||
|
"tax_rule": 15
|
||||||
|
}
|
||||||
|
],
|
||||||
"reissue_invoice": true,
|
"reissue_invoice": true,
|
||||||
"send_email": true,
|
"send_email": true,
|
||||||
"recalculate_taxes": "keep_gross"
|
"recalculate_taxes": "keep_gross"
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ from rest_framework.exceptions import ValidationError
|
|||||||
|
|
||||||
from pretix.api.serializers.order import (
|
from pretix.api.serializers.order import (
|
||||||
AnswerCreateSerializer, AnswerSerializer, CompatibleCountryField,
|
AnswerCreateSerializer, AnswerSerializer, CompatibleCountryField,
|
||||||
OrderPositionCreateSerializer,
|
OrderFeeCreateSerializer, OrderPositionCreateSerializer,
|
||||||
)
|
)
|
||||||
from pretix.base.models import ItemVariation, Order, OrderFee, OrderPosition
|
from pretix.base.models import ItemVariation, Order, OrderFee, OrderPosition
|
||||||
from pretix.base.services.orders import OrderError
|
from pretix.base.services.orders import OrderError
|
||||||
@@ -104,6 +104,54 @@ class OrderPositionCreateForExistingOrderSerializer(OrderPositionCreateSerialize
|
|||||||
raise ValidationError(str(e))
|
raise ValidationError(str(e))
|
||||||
|
|
||||||
|
|
||||||
|
class OrderFeeCreateForExistingOrderSerializer(OrderFeeCreateSerializer):
|
||||||
|
order = serializers.SlugRelatedField(slug_field='code', queryset=Order.objects.none(), required=True, allow_null=False)
|
||||||
|
value = serializers.DecimalField(required=True, allow_null=False, decimal_places=2,
|
||||||
|
max_digits=13)
|
||||||
|
internal_type = serializers.CharField(required=False, default="")
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = OrderFee
|
||||||
|
fields = ('order', 'fee_type', 'value', 'description', 'internal_type', 'tax_rule')
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
if not self.context:
|
||||||
|
return
|
||||||
|
self.fields['order'].queryset = self.context['event'].orders.all()
|
||||||
|
self.fields['tax_rule'].queryset = self.context['event'].tax_rules.all()
|
||||||
|
if 'order' in self.context:
|
||||||
|
del self.fields['order']
|
||||||
|
|
||||||
|
def validate(self, data):
|
||||||
|
data = super().validate(data)
|
||||||
|
if 'order' in self.context:
|
||||||
|
data['order'] = self.context['order']
|
||||||
|
return data
|
||||||
|
|
||||||
|
def create(self, validated_data):
|
||||||
|
ocm = self.context['ocm']
|
||||||
|
|
||||||
|
try:
|
||||||
|
f = OrderFee(
|
||||||
|
order=validated_data['order'],
|
||||||
|
fee_type=validated_data['fee_type'],
|
||||||
|
value=validated_data.get('value'),
|
||||||
|
description=validated_data.get('description'),
|
||||||
|
internal_type=validated_data.get('internal_type'),
|
||||||
|
tax_rule=validated_data.get('tax_rule'),
|
||||||
|
)
|
||||||
|
f._calculate_tax()
|
||||||
|
ocm.add_fee(f)
|
||||||
|
if self.context.get('commit', True):
|
||||||
|
ocm.commit()
|
||||||
|
return validated_data['order'].fees.order_by('-pk').first()
|
||||||
|
else:
|
||||||
|
return OrderFee() # fake to appease DRF
|
||||||
|
except OrderError as e:
|
||||||
|
raise ValidationError(str(e))
|
||||||
|
|
||||||
|
|
||||||
class OrderPositionInfoPatchSerializer(serializers.ModelSerializer):
|
class OrderPositionInfoPatchSerializer(serializers.ModelSerializer):
|
||||||
answers = AnswerSerializer(many=True)
|
answers = AnswerSerializer(many=True)
|
||||||
country = CompatibleCountryField(source='*')
|
country = CompatibleCountryField(source='*')
|
||||||
@@ -401,6 +449,9 @@ class OrderChangeOperationSerializer(serializers.Serializer):
|
|||||||
self.fields['split_positions'] = SelectPositionSerializer(
|
self.fields['split_positions'] = SelectPositionSerializer(
|
||||||
many=True, required=False, context=self.context
|
many=True, required=False, context=self.context
|
||||||
)
|
)
|
||||||
|
self.fields['create_fees'] = OrderFeeCreateForExistingOrderSerializer(
|
||||||
|
many=True, required=False, context=self.context
|
||||||
|
)
|
||||||
self.fields['patch_fees'] = PatchFeeSerializer(
|
self.fields['patch_fees'] = PatchFeeSerializer(
|
||||||
many=True, required=False, context=self.context
|
many=True, required=False, context=self.context
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -63,7 +63,8 @@ from pretix.api.serializers.order import (
|
|||||||
)
|
)
|
||||||
from pretix.api.serializers.orderchange import (
|
from pretix.api.serializers.orderchange import (
|
||||||
BlockNameSerializer, OrderChangeOperationSerializer,
|
BlockNameSerializer, OrderChangeOperationSerializer,
|
||||||
OrderFeeChangeSerializer, OrderPositionChangeSerializer,
|
OrderFeeChangeSerializer, OrderFeeCreateForExistingOrderSerializer,
|
||||||
|
OrderPositionChangeSerializer,
|
||||||
OrderPositionCreateForExistingOrderSerializer,
|
OrderPositionCreateForExistingOrderSerializer,
|
||||||
OrderPositionInfoPatchSerializer,
|
OrderPositionInfoPatchSerializer,
|
||||||
)
|
)
|
||||||
@@ -988,6 +989,12 @@ class EventOrderViewSet(OrderViewSetMixin, viewsets.ModelViewSet):
|
|||||||
ocm.cancel_fee(r['fee'])
|
ocm.cancel_fee(r['fee'])
|
||||||
canceled_fees.add(r['fee'])
|
canceled_fees.add(r['fee'])
|
||||||
|
|
||||||
|
for r in serializer.validated_data.get('create_fees', []):
|
||||||
|
pos_serializer = OrderFeeCreateForExistingOrderSerializer(
|
||||||
|
context={'ocm': ocm, 'commit': False, 'event': request.event, **self.get_serializer_context()},
|
||||||
|
)
|
||||||
|
pos_serializer.create(r)
|
||||||
|
|
||||||
for r in serializer.validated_data.get('patch_fees', []):
|
for r in serializer.validated_data.get('patch_fees', []):
|
||||||
if r['fee'] in canceled_fees:
|
if r['fee'] in canceled_fees:
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -1797,6 +1797,13 @@ def test_order_change_cancel_and_create(token_client, organizer, event, order, q
|
|||||||
'price': '99.99'
|
'price': '99.99'
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
'create_fees': [
|
||||||
|
{
|
||||||
|
'value': '5.99',
|
||||||
|
'fee_type': 'service',
|
||||||
|
'description': 'Service fee',
|
||||||
|
},
|
||||||
|
],
|
||||||
'cancel_fees': [
|
'cancel_fees': [
|
||||||
{
|
{
|
||||||
'fee': f.pk,
|
'fee': f.pk,
|
||||||
@@ -1818,6 +1825,11 @@ def test_order_change_cancel_and_create(token_client, organizer, event, order, q
|
|||||||
assert p_new.price == Decimal('99.99')
|
assert p_new.price == Decimal('99.99')
|
||||||
f.refresh_from_db()
|
f.refresh_from_db()
|
||||||
assert f.canceled
|
assert f.canceled
|
||||||
|
f_new = order.all_fees.get(fee_type=OrderFee.FEE_TYPE_SERVICE)
|
||||||
|
assert f_new.value == Decimal('5.99')
|
||||||
|
assert f_new.description == "Service fee"
|
||||||
|
assert f_new.internal_type == ""
|
||||||
|
assert f_new.tax_value == Decimal('0.00')
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
|
|||||||
Reference in New Issue
Block a user