Set one payment method as primary, allow updates
This commit is contained in:
parent
f2a797874a
commit
89c705f7d2
4 changed files with 45 additions and 13 deletions
|
@ -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),
|
||||||
|
),
|
||||||
|
]
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue