Skip to content

Commit

Permalink
Merge pull request #130 from rebkwok/stripe
Browse files Browse the repository at this point in the history
Stripe
  • Loading branch information
rebkwok authored Sep 18, 2023
2 parents 04cb466 + e4b645f commit eb57ab9
Show file tree
Hide file tree
Showing 124 changed files with 6,040 additions and 622 deletions.
8 changes: 7 additions & 1 deletion .coveragerc
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
[run]
omit=venv/*,booking/management/commands/upload_data.py,booking/management/commands/update_categories.py,../*migrations*,../*tests*,../*wsgi*,../*__init__*,timetable/management/commands/create_pip_hire_sessions.py,manage.py
omit=venv/*,\
booking/management/commands/upload_data.py,\
booking/management/commands/update_categories.py,\
booking/management/commands/check_credits.py,\
booking/management/commands/reactivate_blocks.py,\
../*migrations*,../*tests*,../*wsgi*,../*__init__*,\
timetable/management/commands/create_pip_hire_sessions.py,manage.py
relative_files = True
72 changes: 48 additions & 24 deletions booking/baker_recipes.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from datetime import timedelta, datetime
from datetime import timezone as dt_timezone

from django.conf import settings
from django.contrib.auth.models import User

from django.utils import timezone
Expand Down Expand Up @@ -38,35 +39,43 @@

future_EV = Recipe(Event,
date=future,
event_type=foreign_key(event_type_OE))
event_type=foreign_key(event_type_OE),
paypal_email=settings.DEFAULT_PAYPAL_EMAIL)

future_WS = Recipe(Event,
date=future,
event_type=foreign_key(event_type_WS))
event_type=foreign_key(event_type_WS),
paypal_email=settings.DEFAULT_PAYPAL_EMAIL)

future_PC = Recipe(Event,
date=future,
event_type=foreign_key(event_type_PC))
event_type=foreign_key(event_type_PC),
paypal_email=settings.DEFAULT_PAYPAL_EMAIL)
future_PP = Recipe(Event,
date=future,
event_type=foreign_key(event_type_PP))
event_type=foreign_key(event_type_PP),
paypal_email=settings.DEFAULT_PAYPAL_EMAIL)
future_CL = Recipe(Event,
date=future,
event_type=foreign_key(event_type_OC))
event_type=foreign_key(event_type_OC),
paypal_email=settings.DEFAULT_PAYPAL_EMAIL)
future_RH = Recipe(Event,
date=future,
event_type=foreign_key(event_type_RH))
event_type=foreign_key(event_type_RH),
paypal_email=settings.DEFAULT_PAYPAL_EMAIL)
future_OT = Recipe(Event,
date=future,
event_type=foreign_key(event_type_OT))
event_type=foreign_key(event_type_OT),
paypal_email=settings.DEFAULT_PAYPAL_EMAIL)

# past event
past_event = Recipe(Event,
date=past,
event_type=foreign_key(event_type_WS),
advance_payment_required=True,
cost=10,
payment_due_date=past-timedelta(10)
payment_due_date=past-timedelta(10),
paypal_email=settings.DEFAULT_PAYPAL_EMAIL
)

# past_class
Expand All @@ -75,7 +84,8 @@
event_type=foreign_key(event_type_PC),
advance_payment_required=True,
cost=10,
payment_due_date=past-timedelta(10)
payment_due_date=past-timedelta(10),
paypal_email=settings.DEFAULT_PAYPAL_EMAIL
)

blocktype = Recipe(BlockType, active=True, duration=4)
Expand Down Expand Up @@ -107,37 +117,48 @@
block_type=foreign_key(blocktype10),
start_date=datetime(2015, 1, 1, tzinfo=dt_timezone.utc))

booking = Recipe(Booking, user__email=seq("[email protected]"))
booking_with_user = Recipe(Booking, user=foreign_key(user))
booking = Recipe(
Booking, user__email=seq("[email protected]"),
event__paypal_email=settings.DEFAULT_PAYPAL_EMAIL
)
booking_with_user = Recipe(
Booking, user=foreign_key(user),
event__paypal_email=settings.DEFAULT_PAYPAL_EMAIL
)

past_booking = Recipe(Booking,
event=foreign_key(past_event),
user=foreign_key(user)
)
past_booking = Recipe(
Booking,
event=foreign_key(past_event),
user=foreign_key(user),
event__paypal_email=settings.DEFAULT_PAYPAL_EMAIL
)

fb_app = Recipe(SocialApp,
provider='facebook')

mon_session = Recipe(
Session, event_type=foreign_key(event_type_PC), day=Session.MON,
payment_time_allowed=None
payment_time_allowed=None, paypal_email=settings.DEFAULT_PAYPAL_EMAIL
)
tue_session = Recipe(
Session, event_type=foreign_key(event_type_PC), day=Session.TUE,
payment_time_allowed=None
payment_time_allowed=None, paypal_email=settings.DEFAULT_PAYPAL_EMAIL
)
wed_session = Recipe(
Session, event_type=foreign_key(event_type_PC), day=Session.WED,
payment_time_allowed=None
payment_time_allowed=None, paypal_email=settings.DEFAULT_PAYPAL_EMAIL
)

waiting_list_user = Recipe(WaitingListUser, user=foreign_key(user))

ticketed_event_max10 = Recipe(
TicketedEvent, max_tickets=10, ticket_cost=10, date=future
TicketedEvent, max_tickets=10, ticket_cost=10, date=future,
paypal_email=settings.DEFAULT_PAYPAL_EMAIL
)
ticketed_event_past_max10 = Recipe(
TicketedEvent, max_tickets=10, ticket_cost=10, date=past,
paypal_email=settings.DEFAULT_PAYPAL_EMAIL
)
ticketed_event_past_max10 = Recipe(TicketedEvent, max_tickets=10,
ticket_cost=10, date=past)
ticket_booking = Recipe(TicketBooking, user=foreign_key(user))

online_disclaimer = Recipe(
Expand All @@ -148,8 +169,11 @@
)

event_gift_voucher = Recipe(
EventVoucher, code="abc1234", activated=False, discount=100, max_per_user=1, max_vouchers=1
EventVoucher, code="abc1234", activated=False, discount=100, max_per_user=1, max_vouchers=1,
is_gift_voucher=True
)
block_gift_voucher = Recipe(
BlockVoucher, code="def1234", activated=False, discount=100, max_per_user=1, max_vouchers=1
)
BlockVoucher,
code="def1234", activated=False, discount=100, max_per_user=1, max_vouchers=1,
is_gift_voucher=True
)
3 changes: 2 additions & 1 deletion booking/context_processors.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ def booking(request):
"show_vat": settings.SHOW_VAT,
"vat_number": settings.VAT_NUMBER,
"studio_email": settings.DEFAULT_STUDIO_EMAIL,
"location_count": Event.objects.filter(date__gte=timezone.now()).order_by().distinct("location").count()
"location_count": Event.objects.filter(date__gte=timezone.now()).order_by().distinct("location").count(),
"payment_method": settings.PAYMENT_METHOD,
}
12 changes: 11 additions & 1 deletion booking/management/commands/cancel_unpaid_bookings.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
now - date_booked/rebooked > payment_time_allowed
)
Email user that their booking has been cancelled
BUT excluding bookings with a checkout_time in the past 5 mins
(checkout_time is set when user clicks button to pay with stripe)
'''
import logging
from datetime import timedelta
Expand Down Expand Up @@ -45,6 +48,7 @@ def handle(self, *args, **options):
self.cancel_bookings(now)

def get_bookings_to_cancel(self, now):
checkout_buffer_seconds = 60 * 5
warning_time_buffer = now - timedelta(hours=2)
bookings_qset = Booking.objects.filter(
event__date__gte=now,
Expand All @@ -54,7 +58,13 @@ def get_bookings_to_cancel(self, now):
paid=False,
payment_confirmed=False,
paypal_pending=False,
).exclude(date_warning_sent__gte=warning_time_buffer) # doesn't exclude date_warning_sent==None
).exclude(
# exclude bookings with warning send within past 2 hrs
date_warning_sent__gte=warning_time_buffer # doesn't exclude date_warning_sent==None
).exclude(
# exclude bookings with checkout time within past 5 mins
checkout_time__gte=timezone.now() - timedelta(seconds=checkout_buffer_seconds)
)
for booking in bookings_qset:
if (booking.event.date - timedelta(hours=booking.event.cancellation_period)) < now:
if booking.warning_sent:
Expand Down
16 changes: 12 additions & 4 deletions booking/management/commands/cancel_unpaid_ticket_bookings.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@


class Command(BaseCommand):
help = 'Cancel unpaid ticket bookings that are past payment_due_date or '
'payment time allowed'
help = 'Cancel unpaid ticket bookings that are past payment_due_date or payment time allowed'
def handle(self, *args, **options):
# only cancel between 9am and 10pm; warnings are sent from 7 so this allows a minimum of 2 hrs after warning
# for payment before the next cancel job is run
Expand All @@ -50,6 +49,7 @@ def handle(self, *args, **options):
self.cancel_ticket_bookings(now)

def get_ticket_bookings_to_cancel(self, now):
checkout_buffer_seconds = 60 * 5
warning_sent_buffer = now - timedelta(hours=2)
# get relevant ticketed_events
ticketed_events = TicketedEvent.objects.filter(
Expand All @@ -59,8 +59,16 @@ def get_ticket_bookings_to_cancel(self, now):
advance_payment_required=True,
)
for event in ticketed_events:
# get open unpaid ticket bookings made > with either no warning sent date yet, or warning sent date > 2hrs ago
ticket_bookings = event.ticket_bookings.filter(cancelled=False, paid=False).exclude(date_warning_sent__gte=warning_sent_buffer)
# get open unpaid ticket bookings, exclude those with either no warning sent date yet,
# or warning sent date < 2hrs ago
ticket_bookings = event.ticket_bookings.filter(
cancelled=False, paid=False
).exclude(
date_warning_sent__gte=warning_sent_buffer
).exclude(
# exclude bookings with checkout time within past 5 mins
checkout_time__gte=timezone.now() - timedelta(seconds=checkout_buffer_seconds)
)

# if payment due date is past and warning has been sent, cancel
if event.payment_due_date and event.payment_due_date < now:
Expand Down
6 changes: 5 additions & 1 deletion booking/management/commands/email_ticket_booking_warnings.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
'''
Email warnings for unpaid bookings booked > 2 hrs ago
BUT excluding bookings with a checkout_time in the past 5 mins
(checkout_time is set when user clicks button to pay with stripe)
'''
from datetime import datetime, timedelta
from django.utils import timezone
Expand Down Expand Up @@ -35,13 +38,14 @@ def get_bookings():
payment_open=True,
).values_list("id", flat=True)

checkout_cutoff = timezone.now() - timedelta(seconds=5*60)
return TicketBooking.objects.filter(
ticketed_event__in=ticketed_event_ids,
cancelled=False,
paid=False,
warning_sent=False,
date_booked__lte=timezone.now() - timedelta(hours=2)
)
).exclude(checkout_time__gte=checkout_cutoff)


def send_warning_email(self, upcoming_bookings):
Expand Down
6 changes: 5 additions & 1 deletion booking/management/commands/email_warnings.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
Add warning_sent flags to booking model so
we don't keep sending
BUT excluding bookings with a checkout_time in the past 5 mins
(checkout_time is set when user clicks button to pay with stripe)
'''
from datetime import timedelta
from django.utils import timezone
Expand Down Expand Up @@ -50,6 +53,7 @@ def get_bookings():
rebooked = Q(date_rebooked__isnull=False)
not_rebooked = Q(date_rebooked__isnull=True)
cutoff = timezone.now() - timedelta(hours=2)
checkout_cutoff = timezone.now() - timedelta(seconds=5*60)
rebooked_more_than_2hrs_ago = Q(date_rebooked__lte=cutoff)
booked_more_than_2hrs_ago = Q(date_booked__lte=cutoff)

Expand All @@ -60,7 +64,7 @@ def get_bookings():
paid=False,
payment_confirmed=False,
warning_sent=False,
)
).exclude(checkout_time__gte=checkout_cutoff)


def send_warning_email(self, upcoming_bookings):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Generated by Django 4.1.1 on 2023-09-07 08:39

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('stripe_payments', '0001_initial'),
('booking', '0083_filtercategory_filtercategory_unique_lower_category_and_more'),
]

operations = [
migrations.AddField(
model_name='basevoucher',
name='checkout_time',
field=models.DateTimeField(blank=True, null=True),
),
migrations.AddField(
model_name='basevoucher',
name='invoice',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='vouchers', to='stripe_payments.invoice'),
),
migrations.AddField(
model_name='block',
name='checkout_time',
field=models.DateTimeField(blank=True, null=True),
),
migrations.AddField(
model_name='block',
name='invoice',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='blocks', to='stripe_payments.invoice'),
),
migrations.AddField(
model_name='booking',
name='checkout_time',
field=models.DateTimeField(blank=True, null=True),
),
migrations.AddField(
model_name='booking',
name='invoice',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bookings', to='stripe_payments.invoice'),
),
migrations.AddField(
model_name='ticketbooking',
name='checkout_time',
field=models.DateTimeField(blank=True, null=True),
),
migrations.AddField(
model_name='ticketbooking',
name='invoice',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='ticket_bookings', to='stripe_payments.invoice'),
),
]
28 changes: 28 additions & 0 deletions booking/migrations/0085_alter_blocktype_paypal_email_and_more.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Generated by Django 4.1.1 on 2023-09-07 08:42

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('booking', '0084_basevoucher_checkout_time_basevoucher_invoice_and_more'),
]

operations = [
migrations.AlterField(
model_name='blocktype',
name='paypal_email',
field=models.EmailField(default='[email protected]', help_text='Email for the paypal account to be used for payment. Check this carefully!', max_length=254),
),
migrations.AlterField(
model_name='event',
name='paypal_email',
field=models.EmailField(default='[email protected]', help_text='Email for the paypal account to be used for payment. Check this carefully!', max_length=254),
),
migrations.AlterField(
model_name='ticketedevent',
name='paypal_email',
field=models.EmailField(default='[email protected]', help_text='Email for the paypal account to be used for payment. Check this carefully!', max_length=254),
),
]
23 changes: 23 additions & 0 deletions booking/migrations/0086_block_voucher_code_booking_voucher_code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 4.1.1 on 2023-09-10 15:22

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('booking', '0085_alter_blocktype_paypal_email_and_more'),
]

operations = [
migrations.AddField(
model_name='block',
name='voucher_code',
field=models.CharField(blank=True, max_length=255, null=True),
),
migrations.AddField(
model_name='booking',
name='voucher_code',
field=models.CharField(blank=True, max_length=255, null=True),
),
]
Loading

0 comments on commit eb57ab9

Please sign in to comment.