List all the credit cards and the ability to add more cards

This commit is contained in:
amalelshihaby 2021-08-12 12:28:19 +02:00
commit 1c3d3efb3a
22 changed files with 528 additions and 158 deletions

View file

@ -58,7 +58,7 @@ class StripeCustomer(models.Model):
class StripeCreditCard(models.Model):
owner = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
card_name = models.CharField(null=False, max_length=128, default="My credit card")
card_name = models.CharField(null=False, max_length=128, default="")
card_id = models.CharField(null=False, max_length=32)
last4 = models.CharField(null=False, max_length=4)
brand = models.CharField(null=False, max_length=64)
@ -76,6 +76,16 @@ class StripeCreditCard(models.Model):
def __str__(self):
return f"{self.card_name}: {self.brand} {self.last4} ({self.expiry_date})"
def delete(self, **kwargs):
uncloud_pay.stripe.delete_card(self.card_id)
super().delete(**kwargs)
def activate(self):
StripeCreditCard.objects.filter(owner=self.owner, active=True).update(active=False)
self.active = True
self.save()
class Payment(models.Model):
owner = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
type = models.CharField(max_length=256,
@ -125,6 +135,7 @@ class Payment(models.Model):
return cls.objects.create(owner=owner, type="withdraw", amount=amount,
currency=currency, notes=notes)
# See https://docs.djangoproject.com/en/dev/ref/models/fields/#field-choices-enum-types
class RecurringPeriodDefaultChoices(models.IntegerChoices):

View file

@ -2,6 +2,7 @@ from django.contrib.auth import get_user_model
from rest_framework import serializers
from uncloud_auth.serializers import UserSerializer
from django.utils.translation import gettext_lazy as _
from stripe.error import CardError
from .models import *
import uncloud_pay.stripe as uncloud_stripe
@ -25,13 +26,17 @@ class PaymentSerializer(serializers.ModelSerializer):
read_only_fields = [ "external_reference", "source", "timestamp" ]
def validate(self, data):
payment_intent = uncloud_stripe.charge_customer(data['owner'],
data['amount'])
data["external_reference"] = payment_intent["id"]
data["source"] = "stripe"
return data
def create(self, validated_data):
try:
if validated_data['type'] == 'deposit':
return Payment.deposit(validated_data['owner'], validated_data['amount'], validated_data['source'], currency=validated_data['currency'], notes=validated_data['notes'])
else:
return Payment.objects.create(**validated_data)
except CardError as err:
raise serializers.ValidationError(err.user_message)
class BalanceSerializer(serializers.Serializer):
balance = serializers.DecimalField(max_digits=AMOUNT_MAX_DIGITS, decimal_places=AMOUNT_DECIMALS)

View file

@ -94,8 +94,11 @@ def get_card_from_payment(user, payment_method_id):
@handle_stripe_error
def attach_payment_method(payment_method_id, customer_id):
return stripe.PaymentMethod.attach(payment_method_id, customer=customer_id)
def attach_payment_method(payment_method_id, user):
customer_id = get_customer_id_for(user)
ret = stripe.PaymentMethod.attach(payment_method_id, customer=customer_id)
sync_cards_for_user(user)
return ret
@handle_stripe_error
def create_customer(name, email):
@ -107,7 +110,6 @@ def get_customer(customer_id):
@handle_stripe_error
def get_customer_cards(customer_id):
print(f"getting cards for: {customer_id}")
cards = []
stripe_cards = stripe.PaymentMethod.list(
@ -127,6 +129,10 @@ def get_customer_cards(customer_id):
return cards
@handle_stripe_error
def delete_card(card_id):
return stripe.PaymentMethod.detach(card_id)
def sync_cards_for_user(user):
customer_id = get_customer_id_for(user)
cards = get_customer_cards(customer_id)

9
uncloud_pay/urls.py Normal file
View file

@ -0,0 +1,9 @@
from django.urls import path, include
from django.conf import settings
from .views import *
app_name = 'uncloud_pay'
urlpatterns = [
path('cards/activate', CardActivateView.as_view(), name='card_activate'),
]

View file

@ -38,14 +38,32 @@ logger = logging.getLogger(__name__)
class PricingView(View):
def get(self, request, **args):
address = get_billing_address_for_user(self.request.user)
vat_rate = False
vat_validation_status = False
if address:
vat_rate = VATRate.get_vat_rate(address)
vat_validation_status = "verified" if address.vat_number_validated_on and address.vat_number_verified else False
pricing = get_order_total_with_vat(
request.GET.get('cores'),
request.GET.get('memory'),
request.GET.get('storage'),
pricing_name = args['name']
pricing_name = args['name'],
vat_rate = vat_rate * 100,
vat_validation_status = vat_validation_status
)
return JsonResponse(pricing)
class CardActivateView(View):
def post(self, request, **args):
card_id = request.POST.get('card_id')
if card_id:
matched_card = StripeCreditCard.objects.filter(owner=self.request.user, card_id=card_id).first()
matched_card.activate()
return JsonResponse({'success': 1})
else:
return JsonResponse({'error': "Please select a card"})
class RegisterCard(TemplateView):
template_name = "uncloud_pay/register_stripe.html"
@ -55,7 +73,6 @@ class RegisterCard(TemplateView):
def get_context_data(self, **kwargs):
customer_id = uncloud_stripe.get_customer_id_for(self.request.user)
setup_intent = uncloud_stripe.create_setup_intent(customer_id)
context = super().get_context_data(**kwargs)