Set one payment method as primary, allow updates

This commit is contained in:
fnux 2020-03-05 15:19:25 +01:00
parent f2a797874a
commit 89c705f7d2
4 changed files with 45 additions and 13 deletions

View File

@ -0,0 +1,18 @@
# Generated by Django 3.0.3 on 2020-03-05 13:54
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('uncloud_pay', '0002_auto_20200305_1524.py'),
]
operations = [
migrations.AlterField(
model_name='paymentmethod',
name='primary',
field=models.BooleanField(default=False, editable=False),
),
]

View File

@ -4,9 +4,7 @@ from django.contrib.auth import get_user_model
from django.core.validators import MinValueValidator from django.core.validators import MinValueValidator
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.utils import timezone from django.utils import timezone
from django.dispatch import receiver
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
import django.db.models.signals as signals
import uuid import uuid
from functools import reduce from functools import reduce
@ -106,7 +104,7 @@ class PaymentMethod(models.Model):
), ),
default='stripe') default='stripe')
description = models.TextField() description = models.TextField()
primary = models.BooleanField(default=True) primary = models.BooleanField(default=False, editable=False)
# Only used for "Stripe" source # Only used for "Stripe" source
stripe_payment_method_id = models.CharField(max_length=32, blank=True, null=True) stripe_payment_method_id = models.CharField(max_length=32, blank=True, null=True)
@ -149,22 +147,24 @@ class PaymentMethod(models.Model):
else: else:
raise Exception('This payment method is unsupported/cannot be charged.') raise Exception('This payment method is unsupported/cannot be charged.')
def set_as_primary_for(self, user):
methods = PaymentMethod.objects.filter(owner=user, primary=True)
for method in methods:
print(method)
method.primary = False
method.save()
self.primary = True
self.save()
def get_primary_for(user): def get_primary_for(user):
methods = PaymentMethod.objects.filter(owner=user) methods = PaymentMethod.objects.filter(owner=user)
for method in methods: for method in methods:
# Do we want to do something with non-primary method? if method.primary:
if method.active and method.primary:
return method return method
return None return None
class Meta:
# TODO: limit to one primary method per user.
# unique_together is no good since it won't allow more than one
# non-primary method.
pass
### ###
# Bills. # Bills.

View File

@ -20,7 +20,7 @@ class PaymentMethodSerializer(serializers.ModelSerializer):
class UpdatePaymentMethodSerializer(serializers.ModelSerializer): class UpdatePaymentMethodSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = PaymentMethod model = PaymentMethod
fields = ['description', 'primary'] fields = ['description']
class ChargePaymentMethodSerializer(serializers.Serializer): class ChargePaymentMethodSerializer(serializers.Serializer):
amount = serializers.DecimalField(max_digits=10, decimal_places=2) amount = serializers.DecimalField(max_digits=10, decimal_places=2)
@ -29,7 +29,8 @@ class CreatePaymentMethodSerializer(serializers.ModelSerializer):
please_visit = serializers.CharField(read_only=True) please_visit = serializers.CharField(read_only=True)
class Meta: class Meta:
model = PaymentMethod model = PaymentMethod
fields = ['source', 'description', 'primary', 'please_visit'] fields = ['uuid', 'primary', 'source', 'description', 'please_visit']
read_only_field = ['uuid', 'primary']
### ###
# Orders & Products. # Orders & Products.

View File

@ -64,6 +64,10 @@ class PaymentMethodViewSet(viewsets.ModelViewSet):
serializer = self.get_serializer(data=request.data) serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
# Set newly created method as primary if no other method is.
if PaymentMethod.get_primary_for(request.user) == None:
serializer.validated_data['primary'] = True
if serializer.validated_data['source'] == "stripe": if serializer.validated_data['source'] == "stripe":
# Retrieve Stripe customer ID for user. # Retrieve Stripe customer ID for user.
customer_id = uncloud_stripe.get_customer_id_for(request.user) customer_id = uncloud_stripe.get_customer_id_for(request.user)
@ -109,6 +113,7 @@ class PaymentMethodViewSet(viewsets.ModelViewSet):
@action(detail=True, methods=['get'], url_path='register-stripe-cc', renderer_classes=[TemplateHTMLRenderer]) @action(detail=True, methods=['get'], url_path='register-stripe-cc', renderer_classes=[TemplateHTMLRenderer])
def register_stripe_cc(self, request, pk=None): def register_stripe_cc(self, request, pk=None):
payment_method = self.get_object() payment_method = self.get_object()
if payment_method.source != 'stripe': if payment_method.source != 'stripe':
return Response( return Response(
{'error': 'This is not a Stripe-based payment method.'}, {'error': 'This is not a Stripe-based payment method.'},
@ -163,6 +168,14 @@ class PaymentMethodViewSet(viewsets.ModelViewSet):
error = 'Could not fetch payment method from stripe. Please try again.' error = 'Could not fetch payment method from stripe. Please try again.'
return Response({'error': error}) return Response({'error': error})
@action(detail=True, methods=['post'], url_path='set-as-primary')
def set_as_primary(self, request, pk=None):
payment_method = self.get_object()
payment_method.set_as_primary_for(request.user)
serializer = self.get_serializer(payment_method)
return Response(serializer.data)
### ###
# Bills and Orders. # Bills and Orders.