def send_ride_receipt_email(customer, ride): user = customer.user account_email = customer.ride_account.email if customer.ride_account else None to_name = user.first_name if user.profile.on_behalf else customer.first_name to_email = customer.email if customer.email else account_email if account_email else user.email d = { 'ride': ride, 'customer': customer, 'to_name': to_name } msg_plain = render_to_string('billing/email/ride_receipt_email.txt', d) msg_html = render_to_string('billing/email/ride_receipt_email.html', d) send_mail( 'Thanks for riding with Arrive!', msg_plain, settings.DEFAULT_FROM_EMAIL, [to_email], html_message=msg_html, ) new_touch = Touch( customer=customer, date=timezone.now(), type=Touch.EMAIL, notes='Sent ride receipt email (from balance)' ) new_touch.full_clean() new_touch.save()
def invoice(request): event = json.loads(request.body) event_type = event['type'] stripe_invoice = event['data']['object'] stripe_cust_id = stripe_invoice['customer'] customer = None try: invoice = get_object_or_404(Invoice, stripe_id=stripe_invoice['id']) invoice.invoiced = stripe_invoice['attempted'] invoice.attempt_count = stripe_invoice['attempt_count'] invoice.total = stripe_invoice['total'] / 100 invoice.paid = stripe_invoice['paid'] invoice_type = 'Ride' if event_type == 'invoice.sent': invoice.invoiced_date = timezone.now() if event_type == 'invoice.payment_succeeded': invoice.paid_date = timezone.now() # apparently the invoice is sent and paid at the same time usually if not invoice.invoiced_date: invoice.invoiced_date = invoice.paid_date invoice.full_clean() invoice.save() customer = invoice.customer except: # okay, this isn't an invoice associated with a ride. that means it must be # a customer (a subscription payment), so we need to find the customer stripe_customer = get_object_or_404(StripeCustomer, stripe_id=stripe_cust_id) if stripe_customer.subscription_customer.count(): customer = stripe_customer.subscription_customer.first() if stripe_customer.subscription_group_plan.count(): customer = stripe_customer.subscription_group_plan.first() if stripe_customer.ride_customer.count(): customer = stripe_customer.ride_customer.first() invoice_type = 'Subscription' new_touch = Touch( customer=customer, date=timezone.now(), type=Touch.BILLING, notes='{}: ${} ({} payment) [Stripe ID {}]'.format(event_type, stripe_invoice['total'] / 100, invoice_type, stripe_invoice['id']) ) new_touch.full_clean() new_touch.save() return HttpResponse(status=200)
def send_welcome_email(user): msg_plain = render_to_string('registration/welcome_email.txt', {'user': user}) msg_html = render_to_string('registration/welcome_email.html', {'user': user}) send_mail( 'Welcome to Arrive Rides!', msg_plain, settings.DEFAULT_FROM_EMAIL, [user.email], html_message=msg_html, ) new_touch = Touch( customer=user.get_customer(), date=timezone.now(), type=Touch.EMAIL, notes='Sent welcome email after registration' ) new_touch.full_clean() new_touch.save()
def send_subscription_receipt_email(user): from billing.utils import get_stripe_subscription customer = user.get_customer() account = customer.subscription_account plan = customer.plan subscription = get_stripe_subscription(customer) next_bill_date = formats.date_format(datetime.fromtimestamp(subscription.current_period_end), "DATE_FORMAT") d = { 'account': account, 'plan': plan, 'next_bill_date': next_bill_date } msg_plain = render_to_string('registration/email/subscription_receipt_email.txt', d) msg_html = render_to_string('registration/email/subscription_receipt_email.html', d) to_email = account.email if account.email else user.email send_mail( 'Arrive Membership Confirmation', msg_plain, settings.DEFAULT_FROM_EMAIL, [to_email], html_message=msg_html, ) new_touch = Touch( customer=user.get_customer(), date=timezone.now(), type=Touch.EMAIL, notes='Sent receipt email after payment' ) new_touch.full_clean() new_touch.save()
def invoice_customer_rides(account, customers, request): from accounts.helpers import send_included_rides_email success_included = [] success_billed = [] success_total = 0 errors = [] total = 0 included_rides = [] billable_rides = [] stripe_id = account.stripe_id if account else None if stripe_id or [customer.balance for customer in customers]: for customer, rides in customers.iteritems(): for ride in rides: try: # the ride cost something if ride.total_cost_estimate == 0: # including, no fees: no billing ride.total_cost = 0 ride.complete = True ride.invoiced = True included_rides.append(ride) success_included.append(ride.id) success_total += 1 else: ride.total_cost = ride.total_cost_estimate cost_to_bill = ride.total_cost # if customer has an account if hasattr(customer, 'balance'): if customer.balance.amount >= ride.total_cost: # customer balance can cover ride ride.invoiced = True ride.full_clean() ride.save() cost_to_bill = None customer.balance.amount -= ride.total_cost customer.balance.save() send_ride_receipt_email(customer, ride) new_touch = Touch( customer=customer, date=timezone.now(), type=Touch.BILLING, notes='Balance debit: ${} (Ride payment)'. format(ride.total_cost)) new_touch.full_clean() new_touch.save() else: # ride cost more than balance if stripe_id: # charge overage to ride account cost_to_bill = ride.total_cost - customer.balance.amount customer.balance.amount = 0 else: # ruh roh, they're in the red. cost_to_bill = None ride.invoiced = True ride.full_clean() ride.save() customer.balance.amount -= ride.total_cost customer.balance.save() if customer.balance.amount < settings.BALANCE_ALERT_THRESHOLD_1 and not customer.subscription_account: send_balance_alerts( customer, last_action='Ride {}, {}'.format( ride.id, ride.description)) if cost_to_bill: invoiceitem = stripe.InvoiceItem.create( customer=stripe_id, amount=int(cost_to_bill * 100), currency="usd", description=ride.description, idempotency_key='{}{}'.format( customer.id, datetime.datetime.now().isoformat())) ride.invoice_item_id = invoiceitem.id billable_rides.append(ride) success_billed.append(ride.id) success_total += 1 ride.invoiced_by = request.user ride.save() except Exception as ex: errors.append('Ride {}: {}'.format(ride.id, ex.message)) continue total += 1 if billable_rides: # step out of loop to create one invoice for whole account stripe_invoice = stripe.Invoice.create(customer=stripe_id) # get back in loop to generate invoices per-customer for customer in customers: try: new_invoice = Invoice( stripe_id=stripe_invoice.id, customer=customer, created_date=timezone.now(), period_start=datetime_from_timestamp( stripe_invoice.period_start), period_end=datetime_from_timestamp( stripe_invoice.period_end), ) new_invoice.full_clean() new_invoice.save() except Exception as ex: errors.append('Customer {}: {}'.format( customer.id, ex.message)) continue for ride in billable_rides: try: ride.invoice = new_invoice ride.invoiced = True ride.full_clean() ride.save() except Exception as ex: errors.append('Ride {}: {}'.format(ride.id, ex.message)) else: errors.append( 'Customer {} has no Ride Account specified (no credit card to bill) and/or no funds in their account.' .format(customer)) total = 1 if included_rides: send_included_rides_email(customer, included_rides) return { 'success_included': success_included, 'success_billed': success_billed, 'success_total': success_total, 'errors': errors, 'total': total }
def debit_customer_balance(customer): # if an inactive customer got in here somehow, skip them if not customer.is_active or not customer.plan: return False try: monthly_cost = customer.plan.monthly_cost available_balance = customer.balance.amount if available_balance >= monthly_cost: customer.balance.amount -= monthly_cost customer.balance.save() if customer.balance.amount < settings.BALANCE_ALERT_THRESHOLD_1 and not customer.subscription_account: send_balance_alerts(customer, last_action='Monthly Subscription') funds_touch = Touch( customer=customer, date=timezone.now(), type=Touch.FUNDS, notes='Debited subscription from customer balance') funds_touch.full_clean() funds_touch.save() else: deficit = monthly_cost - available_balance if customer.subscription_account: invoiceitem = stripe.InvoiceItem.create( customer=customer.subscription_account.stripe_id, amount=int(deficit * 100), currency="usd", description="Monthly Subscription", idempotency_key='{}{}'.format( customer.id, datetime.datetime.now().isoformat())) funds_touch1 = Touch( customer=customer, date=timezone.now(), type=Touch.FUNDS, notes= 'Charged subscription card for monthly balance shortfall of {}' .format(deficit)) funds_touch1.full_clean() funds_touch1.save() # If they have an Arrive subscription in addition to a Stripe one, we need to # deactivate their Arrive subscription so they don't get double-charged. # Monthly Billing will now be handled by Stripe. if customer.subscription: customer.subscription.is_active = False customer.subscription.save() funds_touch2 = Touch( customer=customer, date=timezone.now(), type=Touch.FUNDS, notes= 'Deactivated empty Arrive subscription account in favor of subscription card payments' ) funds_touch2.full_clean() funds_touch2.save() else: # this will be negative: customer.balance.amount -= monthly_cost customer.balance.save() send_balance_alerts(customer, last_action='Monthly Subscription') funds_touch3 = Touch( customer=customer, date=timezone.now(), type=Touch.FUNDS, notes='Customer has a negative balance and no backup card!' ) funds_touch3.full_clean() funds_touch3.save() return True except Exception as ex: msg_plain = 'Customer {}, Exception: {}'.format(customer, ex.message) send_mail('[Arrive] Problem with subscription balance ', msg_plain, settings.DEFAULT_FROM_EMAIL, ['*****@*****.**']) return False