Created
September 2, 2020 13:15
-
-
Save miodeqqq/d17605eb79d38e005769a2d16561f732 to your computer and use it in GitHub Desktop.
Django & Stripe
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# managers.py | |
from django.contrib.auth.base_user import BaseUserManager | |
from django.utils.translation import ugettext_lazy as _ | |
class UserManager(BaseUserManager): | |
""" | |
Custom User manager to be used with default auth User model. | |
""" | |
use_in_migrations = True | |
def _create_user(self, email, password, **extra_fields): | |
""" | |
Creates and saves a User with the given email. | |
""" | |
if not email: | |
raise ValueError("The given email must be set") | |
user = self.model(email=self.normalize_email(email), **extra_fields) | |
user.set_password(password) | |
user.save(using=self._db) | |
return user | |
def create_user(self, email, password=None, **extra_fields): | |
""" | |
Creates a user without any permissions. | |
""" | |
extra_fields.setdefault("is_staff", False) | |
extra_fields.setdefault("is_superuser", False) | |
extra_fields.setdefault("is_active", True) | |
return self._create_user(email, password, **extra_fields) | |
def create_superuser(self, email, password, **extra_fields): | |
""" | |
Creates a superuser. | |
""" | |
extra_fields.setdefault("is_staff", True) | |
extra_fields.setdefault("is_superuser", True) | |
extra_fields.setdefault("is_active", True) | |
if extra_fields.get("is_staff") is not True: | |
raise ValueError(_("Superuser must have is_staff=True.")) | |
if extra_fields.get("is_superuser") is not True: | |
raise ValueError(_("Superuser must have is_superuser=True.")) | |
return self.create_user(email, password, **extra_fields) | |
# choices.py | |
from enum import Enum | |
class BaseEnum(Enum): | |
@classmethod | |
def choices(cls): | |
return [(key.name, key.value) for key in cls] | |
class GroupTypeChoices(BaseEnum): | |
EMPLOYEE = "employee" | |
EMPLOYER = "employer" | |
# models.py | |
from django.contrib.auth.base_user import AbstractBaseUser | |
from django.db import models | |
class User(AbstractBaseUser): | |
""" | |
User model. | |
""" | |
USERNAME_FIELD = "email" | |
REQUIRED_FIELDS = ["first_name", "last_name"] | |
email = models.EmailField( | |
verbose_name="E-mail", | |
unique=True | |
) | |
first_name = models.CharField( | |
verbose_name="First name", | |
max_length=30 | |
) | |
last_name = models.CharField( | |
verbose_name="Last name", | |
max_length=40 | |
) | |
city = models.CharField( | |
verbose_name="City", | |
max_length=40 | |
) | |
stripe_id = models.CharField( | |
verbose_name="Stripe ID", | |
unique=True, | |
max_length=50, | |
blank=True, | |
null=True | |
) | |
objects = UserManager() | |
@property | |
def get_full_name(self): | |
return f"{self.first_name} {self.last_name}" | |
class Meta: | |
verbose_name = "User" | |
verbose_name_plural = "Users" | |
class Profile(models.Model): | |
""" | |
User's profile. | |
""" | |
phone_number = models.CharField( | |
verbose_name="Phone number", | |
max_length=15 | |
) | |
date_of_birth = models.DateField( | |
verbose_name="Date of birth" | |
) | |
postal_code = models.CharField( | |
verbose_name="Postal code", | |
max_length=10, | |
blank=True | |
) | |
address = models.CharField( | |
verbose_name="Address", | |
max_length=255, | |
blank=True | |
) | |
class Meta: | |
abstract = True | |
class UserProfile(Profile): | |
""" | |
User's profile model. | |
""" | |
user = models.OneToOneField( | |
to=User, on_delete=models.CASCADE, related_name="profile", | |
) | |
group = models.CharField( | |
verbose_name="Group type", | |
choices=GroupTypeChoices.choices(), | |
max_length=20, | |
default=GroupTypeChoices.EMPLOYEE.name, | |
) | |
def __str__(self): | |
return self.user.email | |
class Meta: | |
unique_together = ("user", "group") | |
# create_users.py | |
# user 1 - employer | |
user1, _ = User.objects.get_or_create( | |
email="[email protected]", | |
first_name="Employer", | |
last_name="Testowy", | |
city="Białystok", | |
) | |
user1.set_unusable_password() | |
group_name = "employer" | |
_profile1, _ = UserProfile.objects.get_or_create( | |
user=user1, | |
date_of_birth=datetime.now() - timedelta(days=6600), | |
group=GroupTypeChoices(group_name).name, | |
address="Myśliwska 14", | |
postal_code="15-569", | |
phone_number="+48100200300", | |
) | |
# user2 - employee | |
user2, _ = User.objects.get_or_create( | |
email="[email protected]", | |
first_name="Employee", | |
last_name="Testowy", | |
city="Białystok", | |
) | |
user2.set_unusable_password() | |
group_name = "employee" | |
_profile2, _ = UserProfile.objects.get_or_create( | |
user=user2, | |
date_of_birth=datetime.now() - timedelta(days=7600), | |
group=GroupTypeChoices(group_name).name, | |
address="Myśliwska 14", | |
postal_code="15-569", | |
phone_number="+48200300400", | |
) | |
# create_customer.py | |
response_customer = stripe.Customer.create( | |
email=user.email, | |
description=f"EMPLOYER - {user.get_full_name}", | |
name=user.get_full_name, | |
phone=user.profile.phone_number, | |
) | |
user1.stripe_id = response_customer.stripe_id | |
user1.save() | |
# create_connect_account.py | |
mcc_code, url = "1520", "https://www.softserveinc.com/" | |
response_ca = stripe.Account.create( | |
type="custom", | |
country="PL", | |
email=user2.email, | |
default_currency="pln", | |
business_type="individual", | |
settings={"payouts": {"schedule": {"interval": "manual", }}}, | |
requested_capabilities=["card_payments", "transfers", ], | |
business_profile={"mcc": mcc_code, "url": url}, | |
individual={ | |
"first_name": user2.first_name, | |
"last_name": user2.last_name, | |
"email": user2.email, | |
"dob": { | |
"day": user2.profile.date_of_birth.day, | |
"month": user2.profile.date_of_birth.month, | |
"year": user2.profile.date_of_birth.year, | |
}, | |
"phone": user2.profile.phone_number, | |
"address": { | |
"city": user2.city, | |
"postal_code": user2.profile.postal_code, | |
"country": "PL", | |
"line1": user2.profile.address, | |
}, | |
}, | |
) | |
user2.stripe_id = response_ca.stripe_id | |
user2.save() | |
# accept_stripe_policy.py | |
tos_acceptance = {"date": int(time.time()), "ip": user_ip}, | |
stripe.Account.modify(user2.stripe_id, tos_acceptance=tos_acceptance) | |
# attach_identity_document.py | |
passport_front = stripe.File.create( | |
purpose="identity_document", | |
file=_file, # ContentFile object | |
stripe_account=user2.stripe_id, | |
) | |
individual = { | |
"verification": { | |
"document": {"front": passport_front.get("id"),}, | |
"additional_document": {"front": passport_front.get("id"),}, | |
} | |
} | |
# add_customer_card.py | |
new_card_source = stripe.Customer.create_source(user1.stripe_id, source=token) | |
stripe.SetupIntent.create( | |
payment_method_types=["card"], | |
customer=user1.stripe_id, | |
description="some description", | |
payment_method=new_card_source.id, | |
) | |
# charge_customer_card.py | |
payment_method = stripe.Customer.retrieve(user1.stripe_id).default_source | |
payment_intent = stripe.PaymentIntent.create( | |
amount=amount, | |
currency="pln", | |
payment_method_types=["card"], | |
capture_method="manual", | |
customer=user1.stripe_id, # customer | |
payment_method=payment_method, | |
application_fee_amount=application_fee_amount, | |
transfer_data={"destination": user2.stripe_id}, # connect account | |
description=description, | |
metadata=metadata, | |
) | |
payment_intent_confirm = stripe.PaymentIntent.confirm( | |
payment_intent.stripe_id, payment_method=payment_method | |
) | |
# charge_customer_card_and_confirm.py | |
stripe.PaymentIntent.capture( | |
payment_intent.id, amount_to_capture=amount | |
) | |
# check_connect_account_balance.py | |
stripe.Balance.retrieve(stripe_account=user2.stripe_id) | |
# decrease_connect_account_balance.py | |
stripe.Charge.create( | |
amount=amount, | |
currency="pln", | |
source=user2.stripe_id, | |
description=description | |
) | |
# refund_money_to_customer.py | |
stripe.PaymentIntent.cancel(payment_intent.id) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment