def post(self, request, campaign_id, *args, **kwargs): # Validate request and campaign status try: campaign = Campaign.objects.get(id=campaign_id) except Campaign.DoesNotExist: return HttpResponseBadRequest("Campaign with ID {campaign_id} does not exist.".format(campaign_id=campaign_id)) else: if not campaign.open(): return HttpResponseBadRequest("This campaign is no longer accepting investments.") form = PaymentChargeForm(request.POST, campaign=campaign) if not form.is_valid(): return HttpResponseBadRequest(unicode(form.errors)) d = form.cleaned_data # Get card and customer card = d['card'] customer = customers.get_customer_for_user(request.user) if not customer: customer = customers.create(request.user, card=card, plan=None, charge_immediately=False) # Create charge num_shares = d['num_shares'] amount = decimal.Decimal(campaign.total(num_shares)) try: charge = charges.create(amount=amount, customer=customer.stripe_id) except CardError as e: return HttpResponseBadRequest(e.message) Investment.objects.create(charge=charge, campaign=campaign, num_shares=num_shares) return HttpResponse(status=205)
def post(self, request, campaign_id, *args, **kwargs): # Validate request and campaign status try: campaign = Campaign.objects.get(id=campaign_id) except Campaign.DoesNotExist: return Response( "Campaign with ID {campaign_id} does not exist.".format( campaign_id=campaign_id), status=status.HTTP_400_BAD_REQUEST, ) else: if not campaign.open(): return Response( "This campaign is no longer accepting investments.", status=status.HTTP_400_BAD_REQUEST, ) form = PaymentChargeForm(request.data, campaign=campaign) if not form.is_valid(): return Response(str(form.errors), status=status.HTTP_400_BAD_REQUEST) d = form.cleaned_data # Get card and customer card = d["card"] customer = customers.get_customer_for_user(request.user) if not customer: customer = customers.create(request.user, card=card, plan=None, charge_immediately=False) card = Card.objects.get(customer=customer) else: # Check if we have the card the user is using # and if not, create it card_fingerprint = stripe.Token.retrieve( card)["card"]["fingerprint"] cards_with_fingerprint = Card.objects.filter( customer=customer, fingerprint=card_fingerprint) if cards_with_fingerprint.exists(): card = cards_with_fingerprint[0] else: card = sources.create_card(customer=customer, token=card) # Create charge num_shares = d["num_shares"] amount = decimal.Decimal(campaign.total(num_shares)) try: charge = charges.create(amount=amount, customer=customer.stripe_id, source=card) except stripe.CardError as e: return Response(e.message, status=status.HTTP_400_BAD_REQUEST) Investment.objects.create(charge=charge, campaign=campaign, num_shares=num_shares) return Response(status=status.HTTP_205_RESET_CONTENT)
def stripe_sub_status(store): stripe_customer = get_customer_for_user(store) active = has_active_subscription(customer=stripe_customer) subscription = Subscription.objects.filter(customer=stripe_customer).order_by('-start').first() if not subscription: plan = "No plan" else: plan = subscription.plan.name if active: return "<span class='label label-success'>Stripe: Active - " + str(plan)+ "</span>" else: return "<span class='label label-default'>Stripe: Inactive - " + str(plan)+ "</span>"
def invoice_list(request, *args, **kwargs): with request.user.session: template = "main_app/invoice_list.html" stripe_customer = get_customer_for_user(request.user) table = CustomerInvoiceTable(Invoice.objects.filter(customer=stripe_customer).order_by('date')) RequestConfig(request, paginate={'per_page': 50}).configure(table) return render(request, template, { 'table': table, })
def process_request(self, request): # TODO Add messages limit check. is_authenticated = request.user.is_authenticated if django.VERSION < (1, 10): is_authenticated = is_authenticated() if is_authenticated and not request.user.is_staff: url_name = resolve(request.path).url_name if url_name in settings.PINAX_STRIPE_SUBSCRIPTION_REQUIRED_URLS: customer = customers.get_customer_for_user(request.user) user_plan = UserPlan.objects.filter(user=request.user)[0] if not subscriptions.has_active_subscription( customer) and user_plan.exceeded_limit( ) or user_plan.exceeded_limit(): return redirect( settings.PINAX_STRIPE_SUBSCRIPTION_REQUIRED_REDIRECT)
def post(self, request, campaign_id, *args, **kwargs): # Validate request and campaign status try: campaign = Campaign.objects.get(id=campaign_id) except Campaign.DoesNotExist: return Response( "Campaign with ID {campaign_id} does not exist.".format(campaign_id=campaign_id), status=status.HTTP_400_BAD_REQUEST ) else: if not campaign.open(): return Response( "This campaign is no longer accepting investments.", status=status.HTTP_400_BAD_REQUEST ) form = PaymentChargeForm(request.data, campaign=campaign) if not form.is_valid(): return Response(str(form.errors), status=status.HTTP_400_BAD_REQUEST) d = form.cleaned_data # Get card and customer card = d['card'] customer = customers.get_customer_for_user(request.user) if not customer: customer = customers.create(request.user, card=card, plan=None, charge_immediately=False) card = Card.objects.get(customer=customer) else: # Check if we have the card the user is using # and if not, create it card_fingerprint = stripe.Token.retrieve(card)['card']['fingerprint'] cards_with_fingerprint = Card.objects.filter(customer=customer, fingerprint=card_fingerprint) if cards_with_fingerprint.exists(): card = cards_with_fingerprint[0] else: card = sources.create_card(customer=customer, token=card) # Create charge num_shares = d['num_shares'] amount = decimal.Decimal(campaign.total(num_shares)) try: charge = charges.create(amount=amount, customer=customer.stripe_id, source=card) except stripe.CardError as e: return Response(e.message, status=status.HTTP_400_BAD_REQUEST) Investment.objects.create(charge=charge, campaign=campaign, num_shares=num_shares) return Response(status=status.HTTP_205_RESET_CONTENT)
def ask_for_review(domain): try: store = models.AuthAppShopUser.objects.get(myshopify_domain=domain) except ObjectDoesNotExist: logging.warning("Review-Check-Task-No-User: "******"created_at") if store.userprofile.setup_required == False and stripe_customer and cards: # Send an email ctx = { "myshopify_domain": store.myshopify_domain, } subject = render_to_string("main_app/email/review_subject.txt", ctx) subject = subject.strip() message = render_to_string("main_app/email/review_body.txt", ctx) email = store.userprofile.shop_contact_email num_sent = EmailMessage( subject, message, to=[email], from_email=settings.PINAX_STRIPE_INVOICE_FROM_EMAIL).send() store.userprofile.review_email_sent = True store.userprofile.save() return else: return
def admin_store_transfers(request, *args, **kwargs): template = "main_app/admin_store_transfers.html" active_menu = "stores" # Get store from kwargs store = get_object_or_404(AuthAppShopUser, pk=kwargs.get('pk', None)) stripe_customer = get_customer_for_user(store) table = InvoiceTable(Invoice.objects.filter(customer=stripe_customer).order_by('-period_start')) RequestConfig(request, paginate={'per_page': 50}).configure(table) return render(request, template, { 'active_menu': active_menu, 'table': table, 'store': store })
def payment_information(request, *args, **kwargs): with request.user.session: # Get the current stores stripe customer info. stripe_customer = get_customer_for_user(request.user) # Get all the current customers/stores payment methods cards = Card.objects.filter(customer=stripe_customer).order_by("created_at") STRIPE_PUBLIC_KEY = settings.PINAX_STRIPE_PUBLIC_KEY if request.method == "POST": stripe_customer = process_stripe_user(request.user, request.POST.get('stripeToken', None), existing_cards=cards) create_stripe_user_subscription(store=request.user, stripe_customer=stripe_customer) messages.success(request, "The payment method was changed.") return redirect('main_app:payment_information', store_url=request.user.store_url_str()) return render(request, "main_app/payment_information.html", {'cards':cards, 'STRIPE_PUBLIC_KEY': STRIPE_PUBLIC_KEY} )
def create_stripe_user_subscription(store, stripe_customer=None): if not stripe_customer: stripe_customer = get_customer_for_user(store) if subscriptions.has_active_subscription(stripe_customer): return True plan, reason = estimate_donation_volume(store) subscription = subscriptions.create(stripe_customer, plan) StripeCustomerSubReason.objects.update_or_create(store=store, defaults={ "subscription": subscription, 'reason': reason }) return True
def process_stripe_user(store, card_token, existing_cards=None): # Get the current stores stripe customer info. stripe_customer = get_customer_for_user(store) # Get all the current customers/stores payment methods if not existing_cards: existing_cards = Card.objects.filter( customer=stripe_customer).order_by("created_at") stripe_card_token = card_token # If the store has no stripe customer, create one. if not stripe_customer: stripe_customer = create_without_account_custom(store, card=stripe_card_token) else: # Save the new card to the existing user, and delete old cards. for card in existing_cards: delete_card(stripe_customer, card.stripe_id) create_card(stripe_customer, token=stripe_card_token) return stripe_customer
def handle_user_pre_delete(sender, **kwargs): user = kwargs.get('instance') customer = customers.get_customer_for_user(user=user) if customer: customers.purge(customer=customer)
def admin_store_detail(request, *args, **kwargs): template = "main_app/admin_store_detail.html" active_menu = "stores" # Get store from kwargs store = get_object_or_404(AuthAppShopUser, pk=kwargs.get('pk', None)) try: with shopify.Session.temp(store.myshopify_domain, store.token): shop_details = Shop.current() except (UnauthorizedAccess, ClientError): shop_details = None # Get dashboard details round_up_count = RoundUpOrders.objects.exclude( shopify_payment_status=RoundUpOrders.SHOPIFY_PAYMENT_STATUS.REFUNDED).filter(store=store).count() round_up_total = [ Money(data['order_roundup_total__sum'], data['order_roundup_total_currency']) for data in RoundUpOrders.objects.exclude( shopify_payment_status=RoundUpOrders.SHOPIFY_PAYMENT_STATUS.REFUNDED).filter(store=store).values( 'order_roundup_total_currency').annotate(Sum('order_roundup_total')).order_by() ] if round_up_total and len(round_up_total) == 1: round_up_total = round_up_total[0] else: round_up_total = Money(0.0, settings.DEFAULT_CURRENCY) stripe_customer = get_customer_for_user(store) stripe_invoice_count = Invoice.objects.filter(customer=stripe_customer, paid=True).count() stripe_invoice_sum = Invoice.objects.filter(customer=stripe_customer, paid=True).aggregate(Sum('total')) try: stripe_invoice_sum = Money(stripe_invoice_sum['total__sum'], settings.DEFAULT_CURRENCY) except (KeyError, InvalidOperation): stripe_invoice_sum = Money(0.0, settings.DEFAULT_CURRENCY) pending_round_up_count = RoundUpOrders.objects.exclude( shopify_payment_status=RoundUpOrders.SHOPIFY_PAYMENT_STATUS.REFUNDED).filter(store=store, state__in=[ RoundUpOrders.STATE.PENDING, RoundUpOrders.STATE.PROCESSING_STRIPE_TRANSFER, RoundUpOrders.STATE.FAILED] ).count() pending_round_up_total = [ Money(data['order_roundup_total__sum'], data['order_roundup_total_currency']) for data in RoundUpOrders.objects.exclude( shopify_payment_status=RoundUpOrders.SHOPIFY_PAYMENT_STATUS.REFUNDED).filter(store=store, state__in=[ RoundUpOrders.STATE.PENDING, RoundUpOrders.STATE.PROCESSING_STRIPE_TRANSFER, RoundUpOrders.STATE.FAILED] ).values( 'order_roundup_total_currency').annotate(Sum('order_roundup_total')).order_by() ] converted_currency_USD = None if pending_round_up_total and len(pending_round_up_total) == 1: pending_round_up_total = pending_round_up_total[0] try: if str(pending_round_up_total.currency) != settings.DEFAULT_CURRENCY: exchange = Fixer(base=str(pending_round_up_total.currency), symbols=[settings.DEFAULT_CURRENCY]) response = exchange.convert() converted_currency_USD = Money(Decimal(pending_round_up_total.amount * Decimal(response['rates'][settings.DEFAULT_CURRENCY])), settings.DEFAULT_CURRENCY) except Exception: pass else: pending_round_up_total = Money(0.0, settings.DEFAULT_CURRENCY) subscription = Subscription.objects.filter(customer=stripe_customer).order_by('-start').first() if request.POST: subscription_lock = request.POST.get('sub-lock', None) switch_high = request.POST.get('switch-high', None) switch_low = request.POST.get('switch-low', None) if subscription_lock: if store.stripe_sub_reason.plan_locked == True: store.stripe_sub_reason.plan_locked = False store.stripe_sub_reason.save() elif store.stripe_sub_reason.plan_locked == False: store.stripe_sub_reason.plan_locked = True store.stripe_sub_reason.save() if switch_high: high_plan = Plan.objects.get(stripe_id=settings.PINAX_STRIPE_HIGH_VOLUME_PLAN) update(subscription, plan=high_plan, prorate=False) # Clear subscription reason models.StripeCustomerSubReason.objects.update_or_create( store=store, defaults={"subscription": subscription, 'reason': "On {0} Vesey manually moved this customer from the low usage plan to the high usage plan.".format(str(timezone.now()))} ) store.stripe_sub_reason.reset_compliance() if switch_low: low_plan = Plan.objects.get(stripe_id=settings.PINAX_STRIPE_DEFAULT_PLAN) update(subscription, plan=low_plan, prorate=False) models.StripeCustomerSubReason.objects.update_or_create( store=store, defaults={"subscription": subscription, 'reason': "On {0} Vesey manually moved this customer from the high usage plan to the low usage plan.".format(str(timezone.now()))} ) store.stripe_sub_reason.reset_compliance() redirect('main_app:admin_store_detail', pk=store.id) return render(request, template, { 'active_menu': active_menu, 'store': store, 'shopify_details': shop_details, 'round_up_count': round_up_count, 'round_up_total': round_up_total, 'stripe_invoice_count': stripe_invoice_count, 'stripe_invoice_sum': stripe_invoice_sum, 'pending_round_up_count': pending_round_up_count, 'pending_round_up_total': pending_round_up_total, 'converted_currency_USD': converted_currency_USD, 'subscription': subscription })
def app_uninstall_task(data, **kwargs): try: user = models.AuthAppShopUser.objects.get( myshopify_domain=kwargs['domain']) user.token = '00000000000000000000000000000000' user.save() # Cancel any Stripe subscriptions try: stripe_customer = get_customer_for_user(user) if subscriptions.has_active_subscription(stripe_customer): user_subscriptions = models.Subscription.objects.filter( customer=stripe_customer).filter( Q(ended_at__isnull=True) | Q(ended_at__gt=timezone.now())) for subscription in user_subscriptions: subscriptions.cancel(subscription, at_period_end=False) # Clear subscription reason models.StripeCustomerSubReason.objects.update_or_create( store=user, defaults={ "subscription": None, 'reason': None }) # Clear stripe cards user_cards = Card.objects.filter( customer=stripe_customer).order_by("created_at") for card in user_cards: delete_card(stripe_customer, card.stripe_id) except StripeError as e: logging.error(str(e.message)) # Send an email to the user to welcome them try: ctx = { "myshopify_domain": user.myshopify_domain, } subject = render_to_string("main_app/email/uninstall_subject.txt", ctx) subject = subject.strip() message = render_to_string("main_app/email/uninstall_body.txt", ctx) email = user.userprofile.shop_contact_email num_sent = EmailMessage( subject, message, to=[email], from_email=settings.PINAX_STRIPE_INVOICE_FROM_EMAIL).send() except Exception: pass # Invalidate any existing user sessions. user.clear_user_sessions() connection.close() except ObjectDoesNotExist: if kwargs['domain']: logging.warning("App-Uninstall-Webhook-No-User-Found: " + str(kwargs['domain'])) return except Exception as e: logging.error("App-Uninstall-Webhook-Unknown-Exception: " + str(e.message)) raise e
def check_user_onboarding_progress(domain): try: store = models.AuthAppShopUser.objects.get(myshopify_domain=domain) except ObjectDoesNotExist: logging.warning("Onboarding-Check-Task-No-User: "******"created_at") if not stripe_customer or not cards: required_steps_string = '- Please add your payment information to the Round Up App payment settings (Required to make donations).\n' # Does the customer have a charity selected? try: if not store.store_charity.selected_charity: required_steps_string = '- Please select a Charity in the Round Up app.\n' except ObjectDoesNotExist: required_steps_string = '- Please select a Charity in the Round Up app.\n' # Has the customer signalled that they have included the setup stuff? try: if not store.userprofile.install_user_verified: required_steps_string = '- Please ensure that you have modified your Cart page theme to include the Round Up app code snippet.\n' except ObjectDoesNotExist: required_steps_string = '- Please ensure that you have modified your Cart page theme to include the Round Up app code snippet.\n' if required_steps_string != '': # Send an email ctx = { "myshopify_domain": store.myshopify_domain, "required_steps_string": required_steps_string } subject = render_to_string( "main_app/email/required_steps_subject.txt", ctx) subject = subject.strip() message = render_to_string( "main_app/email/required_steps_body.txt", ctx) email = store.userprofile.shop_contact_email num_sent = EmailMessage( subject, message, to=[email], from_email=settings.PINAX_STRIPE_INVOICE_FROM_EMAIL).send() store.userprofile.onboarding_email_sent = True store.userprofile.save() return else: return
def customer(self): if not hasattr(self, "_customer"): self._customer = customers.get_customer_for_user(self.request.user) if self._customer is None: self._customer = customers.create(self.request.user) return self._customer