Source code for salesman.orders.serializers

from django.core.exceptions import ValidationError as DjangoValidationError
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from rest_framework.settings import api_settings

from salesman.checkout.payment import payment_methods_pool
from salesman.checkout.serializers import PaymentMethodSerializer
from salesman.conf import app_settings
from salesman.core.serializers import PriceField

from .models import Order, OrderItem, OrderNote, OrderPayment


[docs]class OrderItemSerializer(serializers.ModelSerializer): """ Serializer for order item. """ product = serializers.JSONField(source='product_data', read_only=True) unit_price = PriceField(read_only=True) subtotal = PriceField(read_only=True) total = PriceField(read_only=True) extra = serializers.JSONField(read_only=True) class Meta: model = OrderItem fields = [ 'id', 'product_type', 'product_id', 'product', 'unit_price', 'quantity', 'subtotal', 'extra_rows', 'total', 'extra', ] read_only_fields = fields
[docs]class OrderPaymentSerializer(serializers.ModelSerializer): """ Serializer for order payment. """ amount = PriceField(read_only=True) class Meta: model = OrderPayment fields = ['amount', 'transaction_id', 'payment_method', 'date_created'] read_only_fields = fields
[docs]class OrderNoteSerializer(serializers.ModelSerializer): """ Serializer for order note. """ class Meta: model = OrderNote fields = ['message', 'date_created'] read_only_fields = ['date_created']
[docs]class OrderSerializer(serializers.ModelSerializer): """ Serializer for order. """ url = serializers.SerializerMethodField() subtotal = PriceField(read_only=True) total = PriceField(read_only=True) amount_paid = PriceField(read_only=True) amount_outstanding = PriceField(read_only=True) extra = serializers.JSONField(read_only=True) items = OrderItemSerializer(many=True, read_only=True) payments = OrderPaymentSerializer(many=True, read_only=True) notes = serializers.SerializerMethodField() class Meta: model = Order fields = [ 'id', 'url', 'ref', 'token', 'status', 'status_display', 'date_created', 'date_updated', 'is_paid', 'user', 'email', 'billing_address', 'shipping_address', 'subtotal', 'extra_rows', 'total', 'amount_paid', 'amount_outstanding', 'extra', 'items', 'payments', 'notes', ] read_only_fields = fields def get_url(self, obj): request = self.context.get('request', None) url = reverse('salesman-order-detail', args=[obj.ref]) return request.build_absolute_uri(url) if request else url def get_notes(self, obj): notes = obj.notes.filter(public=True) return OrderNoteSerializer(notes, many=True).data
[docs]class StatusTransitionSerializer(serializers.Serializer): """ Serializer to display order status with error. """ value = serializers.CharField(read_only=True) label = serializers.CharField(read_only=True) error = serializers.CharField(allow_null=True, read_only=True) def to_representation(self, status): data = super().to_representation(status) order = self.context['order'] try: app_settings.SALESMAN_ORDER_STATUS.validate_transition(status, order) except (ValidationError, DjangoValidationError) as e: error = serializers.as_serializer_error(e) data['error'] = error[api_settings.NON_FIELD_ERRORS_KEY][0] return data
[docs]class OrderStatusSerializer(serializers.ModelSerializer): """ Serializer used to change order status. """ status = serializers.ChoiceField(choices=app_settings.SALESMAN_ORDER_STATUS.choices) # Show status transitions with error on GET. status_transitions = StatusTransitionSerializer( source='statuses', many=True, read_only=True ) class Meta: model = Order fields = ['status', 'status_display', 'status_transitions'] def validate_status(self, status): order = self.context['order'] app_settings.SALESMAN_ORDER_STATUS.validate_transition(status, order) return status def to_representation(self, instance): data = super().to_representation(instance) if self.context['request'].method == 'PUT': del data['status_transitions'] return data
[docs]class OrderPaySerializer(serializers.Serializer): """ Serializer used to pay for existing order via payment method. """ url = serializers.CharField(read_only=True) payment_method = serializers.ChoiceField( choices=payment_methods_pool.get_choices('order'), write_only=True, ) # Show payment methods with error on GET. payment_methods = PaymentMethodSerializer(many=True, read_only=True) def validate_payment_method(self, value): order, request = self.context['order'], self.context['request'] payment = payment_methods_pool.get_payment(value) payment.validate_order(order, request) return payment def save(self): # Process the payment. order, request = self.context['order'], self.context['request'] payment = self.validated_data['payment_method'] url = payment.order_payment(order, request) self.validated_data['url'] = url
[docs]class OrderRefundSerializer(serializers.Serializer): """ Serializer used to issue an order refund. """ refunded = serializers.ListField(read_only=True) failed = serializers.ListField(read_only=True) def validate(self, attrs): order = self.context['order'] if order.status == order.statuses.REFUNDED: raise serializers.ValidationError(_("Order is already marked as Refunded.")) return attrs def save(self): # Process the refund. order = self.context['order'] refunded, failed = [], [] for item in order.payments.all(): payment = payment_methods_pool.get_payment(item.payment_method) serializer = OrderPaymentSerializer(item) if payment and payment.refund_payment(item): refunded.append(serializer.data) else: failed.append(serializer.data) # Set data and change order status. self.validated_data.update({'refunded': refunded, 'failed': failed}) if not failed: order.status = order.statuses.REFUNDED order.save(update_fields=['status'])