def update_subscription_choices(subscription_id): """Subscriber can update their subscription choices""" # Get plan from subscription subscription = Subscription.query.get(subscription_id) plan = subscription.plan if request.method == "POST": chosen_option_ids = [] for choice_group_id in request.form.keys(): for option_id in request.form.getlist(choice_group_id): chosen_option_ids.append(option_id) # Update chosen choices chosen_options = [] for option_id in chosen_option_ids: option = Option.query.get(option_id) # Store as ChosenOption because option may change after order has processed # This preserves integrity of the actual chosen options chosen_option = ChosenOption() chosen_option.option_title = option.title chosen_option.choice_group_title = option.choice_group.title chosen_option.choice_group_id = ( option.choice_group.id ) # Used for grouping latest choice chosen_options.append(chosen_option) subscription.chosen_options = chosen_options database.session.add(subscription) database.session.commit() flash("Your choices have been saved.") return redirect(url_for("subscriber.subscriptions")) else: return render_template("subscriber/update_choices.html", plan=plan)
def new_customer(): plan = Plan.query.filter_by(uuid=request.args["plan"]).first() session["plan"] = plan.uuid # Fetch selected options, if present chosen_options = [] if session.get("chosen_option_ids", None): for option_id in session["chosen_option_ids"]: option = Option.query.get(option_id) if option is not None: # We will store as ChosenOption because option may change after the order # noqa # has processed. This preserves integrity of the actual chosen options chosen_option = ChosenOption() chosen_option.option_title = option.title chosen_option.choice_group_title = option.choice_group.title chosen_options.append(chosen_option) else: logging.error( f"Failed to get Open from session option_id: {option_id}") package = request.args.get("plan", "not set") session["package"] = package plan = Plan.query.filter_by(uuid=request.args.get("plan")).first() form = CustomerForm() return render_template( "new_customer.html", form=form, package=package, plan=plan, chosen_options=chosen_options, )
def create_subscription( email=None, package=None, chosen_option_ids=None, subscribie_checkout_session_id=None, stripe_external_id=None, stripe_subscription_id=None, ) -> Subscription: """Create subscription model Note: A subscription model is also created if a plan only has one up_front payment (no recuring subscription). This allows the storing of chosen options againt their plan choice. Chosen option ids may be passed via webhook or through session """ log.info("Creating Subscription model if needed") subscription = None # Initalize subscription model to None # Store Subscription against Person locally if email is None: email = session["email"] if package is None: package = session["package"] person = database.session.query(Person).filter_by(email=email).one() # subscribie_checkout_session_id can be passed by stripe metadata (webhook) or # via session (e.g. when session only with no up-front payment) if subscribie_checkout_session_id is None: subscribie_checkout_session_id = session.get( "subscribie_checkout_session_id", None) log.info( f"subscribie_checkout_session_id is: {subscribie_checkout_session_id}") # Verify Subscription not already created (e.g. stripe payment webhook) # another hook or mandate only payment may have already created the Subscription # model, if so, fetch it via its subscribie_checkout_session_id if subscribie_checkout_session_id is not None: subscription = (Subscription.query.filter_by( subscribie_checkout_session_id=subscribie_checkout_session_id). filter(Subscription.person.has(email=email)).first()) if subscription is None: log.info( "No existing subscription model found, creating Subscription model" ) # Create new subscription model subscription = Subscription( sku_uuid=package, person=person, subscribie_checkout_session_id=subscribie_checkout_session_id, stripe_external_id=stripe_external_id, stripe_subscription_id=stripe_subscription_id, ) # Add chosen options (if any) if chosen_option_ids is None: chosen_option_ids = session.get("chosen_option_ids", None) if chosen_option_ids: log.info( f"Applying chosen_option_ids to subscription: {chosen_option_ids}" ) chosen_options = [] for option_id in chosen_option_ids: log.info(f"Locating option id: {option_id}") option = Option.query.get(option_id) # Store as ChosenOption because options may change after the order # has processed. This preserves integrity of the actual chosen options chosen_option = ChosenOption() if option is not None: chosen_option.option_title = option.title chosen_option.choice_group_title = option.choice_group.title chosen_option.choice_group_id = ( option.choice_group.id ) # Used for grouping latest choice chosen_options.append(chosen_option) else: log.error( f"Failed to get Open from session option_id: {option_id}" ) subscription.chosen_options = chosen_options else: log.info("No chosen_option_ids were found or applied.") database.session.add(subscription) database.session.commit() session["subscription_uuid"] = subscription.uuid # If subscription plan has cancel_at set, modify Stripe subscription # charge_at property stripe.api_key = get_stripe_secret_key() connect_account_id = get_stripe_connect_account_id() if subscription.plan.cancel_at: cancel_at = subscription.plan.cancel_at try: stripe.Subscription.modify( sid=subscription.stripe_subscription_id, stripe_account=connect_account_id, cancel_at=cancel_at, ) subscription.stripe_cancel_at = cancel_at database.session.commit() except Exception as e: # noqa log.error("Could not set cancel_at: {e}") newSubscriberEmailNotification() return subscription