-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[BE] RO-1085 - add coupon model (#11)
* [BE] RO-1085 - add coupon model * Lint * Run isort * Return save * CR * Correct typo * Migrate Subscription.coupon * Isort * RO-1087 - [BE] remove coupon from Stripe after is_deleted is set to True (#12) * RO-1087 - [BE] remove coupon from Stripe after is_deleted is set to True * Pepify * CR * CR * RO-1089 - [BE] set is_deleted flag to True after coupon was deleted @stripe (#13) * RO-1089 - [BE] set is_deleted flag to True after coupon was deleted @stripe * Add __init__.py to tests/ * Correct * CR * CR * CR * RO-1088 - [BE] create and update coupons in admin after change @stripe (#14) * RO-1088 - [BE] create and update coupons in admin after change @stripe * CR
- Loading branch information
Showing
9 changed files
with
756 additions
and
24 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
from django import forms | ||
from django.utils.translation import ugettext_lazy as _ | ||
|
||
from aa_stripe.models import StripeCoupon | ||
|
||
|
||
class StripeCouponForm(forms.ModelForm): | ||
def clean_coupon_id(self): | ||
coupon_id = self.cleaned_data.get("coupon_id") | ||
if coupon_id: | ||
if StripeCoupon.objects.filter(coupon_id=coupon_id, is_deleted=False).exists(): | ||
raise forms.ValidationError(_("Coupon with this id already exists")) | ||
|
||
return coupon_id | ||
|
||
def clean_duration_in_months(self): | ||
duration = self.cleaned_data.get("duration") | ||
duration_in_months = self.cleaned_data.get("duration_in_months") | ||
if duration == StripeCoupon.DURATION_REPEATING and not duration_in_months: | ||
raise forms.ValidationError(_("Cannot be empty with when duration is set to repeating")) | ||
|
||
if duration_in_months and duration != StripeCoupon.DURATION_REPEATING: | ||
raise forms.ValidationError(_("Cannot be set when duration is not set to repeating")) | ||
|
||
return duration_in_months | ||
|
||
def clean(self): | ||
if self.instance.pk: | ||
return self.cleaned_data | ||
|
||
discount_list = [self.cleaned_data.get("amount_off"), self.cleaned_data.get("percent_off")] | ||
if not any(discount_list) or all(discount_list): | ||
raise forms.ValidationError(_("Coupon must specify amount_off or percent_off")) | ||
|
||
return self.cleaned_data | ||
|
||
class Meta: | ||
model = StripeCoupon | ||
fields = [ | ||
"coupon_id", "amount_off", "currency", "duration", "duration_in_months", "livemode", "max_redemptions", | ||
"metadata", "percent_off", "redeem_by", "times_redeemed", "valid", "is_deleted" | ||
] |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
# -*- coding: utf-8 -*- | ||
# Generated by Django 1.11.3 on 2017-08-22 10:04 | ||
from __future__ import unicode_literals | ||
|
||
from datetime import datetime | ||
|
||
import django.db.models.deletion | ||
import jsonfield.fields | ||
import stripe | ||
from django.conf import settings | ||
from django.db import migrations, models | ||
from django.utils import timezone | ||
|
||
|
||
def migrate_subcription(apps, schema_editor): | ||
StripeSubscription = apps.get_model("aa_stripe", "StripeSubscription") | ||
StripeCoupon = apps.get_model("aa_stripe", "StripeCoupon") | ||
stripe.api_key = settings.STRIPE_API_KEY | ||
|
||
for subscription in StripeSubscription.objects.all(): | ||
if StripeCoupon.objects.filter(coupon_id=subscription.coupon_code, is_deleted=False).exists(): | ||
# do not allow duplicates | ||
continue | ||
|
||
try: | ||
coupon = stripe.Coupon.retrieve(id=subscription.coupon_code) | ||
except stripe.error.InvalidRequestError: | ||
print("Coupon {} does not exist, cannot migrate".format(subscription.coupon_code)) | ||
continue | ||
|
||
subscription.coupon = StripeCoupon.objects.create( | ||
coupon_id=coupon.get("id"), stripe_response=coupon, amount_off=coupon.get("amount_off"), | ||
currency=coupon.get("currency"), duration=coupon.get("duration"), | ||
duration_in_months=coupon.get("duration_in_month"), livemode=coupon.get("livemode"), | ||
max_redemptions=coupon.get("max_redemptions"), metadata=coupon.get("metadata"), | ||
percent_off=coupon.get("percent_off"), redeem_by=coupon.get("redeem_by"), | ||
times_redeemed=coupon.get("times_redeemed"), valid=coupon.get("valid"), | ||
created=timezone.make_aware(datetime.fromtimestamp(coupon.get("created"))), | ||
is_created_at_stripe=True | ||
) | ||
subscription.save() | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
('aa_stripe', '0009_auto_20170725_1205'), | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name='StripeCoupon', | ||
fields=[ | ||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('updated', models.DateTimeField(auto_now=True)), | ||
('stripe_response', jsonfield.fields.JSONField(default=dict)), | ||
('coupon_id', models.CharField(help_text='Identifier for the coupon', max_length=255)), | ||
('amount_off', models.PositiveIntegerField(blank=True, help_text='Amount (in the currency specified) that will be taken off the subtotal ofany invoices for this customer.', null=True)), | ||
('currency', models.CharField(default='usd', help_text='If amount_off has been set, the three-letter ISO code for thecurrency of the amount to take off.', max_length=3)), | ||
('duration', models.CharField(choices=[('forever', 'forever'), ('once', 'once'), ('repeating', 'repeating')], help_text='Describes how long a customer who applies this coupon will get the discount.', max_length=255)), | ||
('duration_in_months', models.PositiveIntegerField(blank=True, help_text='If duration is repeating, the number of months the coupon applies.Null if coupon duration is forever or once.', null=True)), | ||
('livemode', models.BooleanField(default=False, help_text='Flag indicating whether the object exists in live mode or test mode.')), | ||
('max_redemptions', models.PositiveIntegerField(blank=True, help_text='Maximum number of times this coupon can be redeemed, in total, before it is no longer valid.', null=True)), | ||
('metadata', jsonfield.fields.JSONField(default=dict, help_text='Set of key/value pairs that you can attach to an object. It can be useful forstoring additional information about the object in a structured format.')), | ||
('percent_off', models.PositiveIntegerField(blank=True, help_text='Percent that will be taken off the subtotal of any invoicesfor this customer for the duration ofthe coupon. For example, a coupon with percent_off of 50 will make a $100 invoice $50 instead.', null=True)), | ||
('redeem_by', models.DateTimeField(blank=True, help_text='Date after which the coupon can no longer be redeemed.', null=True)), | ||
('times_redeemed', models.PositiveIntegerField(default=0, help_text='Number of times this coupon has been applied to a customer.')), | ||
('valid', models.BooleanField(default=False, help_text='Taking account of the above properties, whether this coupon can still be applied to a customer.')), | ||
('created', models.DateTimeField()), | ||
('is_deleted', models.BooleanField(default=False)), | ||
('is_created_at_stripe', models.BooleanField(default=False)), | ||
], | ||
options={ | ||
'abstract': False, | ||
}, | ||
), | ||
migrations.RenameField( | ||
model_name='stripesubscription', | ||
old_name='coupon', | ||
new_name='coupon_code', | ||
), | ||
migrations.AddField( | ||
model_name='stripesubscription', | ||
name='coupon', | ||
field=models.ForeignKey(blank=True, help_text='https://stripe.com/docs/api/python#create_subscription-coupon', null=True, on_delete=django.db.models.deletion.SET_NULL, to='aa_stripe.StripeCoupon'), | ||
), | ||
migrations.RunPython( | ||
code=migrate_subcription, | ||
hints={'target_db': 'default'} | ||
), | ||
migrations.RemoveField( | ||
model_name='stripesubscription', | ||
name='coupon_code' | ||
) | ||
] |
Oops, something went wrong.