FEATURE: Allow one-time purchases on products (#18)

Building off the foundation of using the Prices API, this PR adds the ability to create a one-time purchase plan for any product, which then can add a user to the specified plan group.

Some things to be aware of:

    One-time purchases cannot have trials.
    One-time purchases use the Invoice API instead of Subscriptions. Invoices are created then charged immediately.
    Users should receive emails for these invoices directly from Stripe just like subscriptions.
This commit is contained in:
Justin DiRose
2020-07-22 11:06:34 -05:00
committed by GitHub
parent fcc90e4fcc
commit 587661fafb
31 changed files with 272 additions and 533 deletions
@@ -40,30 +40,47 @@
{{input class="plan-amount" type="text" name="name" value=model.plan.amountDollars disabled=planFieldDisabled}}
</p>
<p>
<label for="trial">
{{i18n 'discourse_subscriptions.admin.plans.plan.trial'}}
({{i18n 'discourse_subscriptions.optional'}})
</label>
{{input type="text" name="trial" value=model.plan.trial_period_days}}
<div class="control-instructions">
{{i18n 'discourse_subscriptions.admin.plans.plan.trial_help'}}
</div>
</p>
<p>
<label for="interval">
{{i18n 'discourse_subscriptions.admin.plans.plan.interval'}}
<label for="recurring">
{{i18n 'discourse_subscriptions.admin.plans.plan.recurring'}}
</label>
{{#if planFieldDisabled}}
{{input disabled=true value=selectedInterval}}
{{input disabled=true value=model.plan.isRecurring}}
{{else}}
{{combo-box
valueProperty="name"
content=availableIntervals
value=selectedInterval
onChange=(action (mut selectedInterval))
{{input
type="checkbox"
name="recurring"
checked=model.plan.isRecurring
change=(action 'changeRecurring')
}}
{{/if}}
</p>
{{#if model.plan.isRecurring}}
<p>
<label for="interval">
{{i18n 'discourse_subscriptions.admin.plans.plan.interval'}}
</label>
{{#if planFieldDisabled}}
{{input disabled=true value=selectedInterval}}
{{else}}
{{combo-box
valueProperty="name"
content=availableIntervals
value=selectedInterval
onChange=(action (mut selectedInterval))
}}
{{/if}}
</p>
<p>
<label for="trial">
{{i18n 'discourse_subscriptions.admin.plans.plan.trial'}}
({{i18n 'discourse_subscriptions.optional'}})
</label>
{{input type="text" name="trial" value=model.plan.trial_period_days}}
<div class="control-instructions">
{{i18n 'discourse_subscriptions.admin.plans.plan.trial_help'}}
</div>
</p>
{{/if}}
<p>
<label for="active">
{{i18n 'discourse_subscriptions.admin.plans.plan.active'}}
@@ -53,7 +53,7 @@
{{#each model.plans as |plan|}}
<tr>
<td>{{plan.nickname}}</td>
<td>{{plan.interval}}</td>
<td>{{plan.recurring.interval}}</td>
<td>{{format-unix-date plan.created}}</td>
<td>{{plan.metadata.group_name}}</td>
<td>{{plan.active}}</td>
@@ -1,54 +1,9 @@
{{#if paymentsAllowed}}
<div class="subscribe-buttons">
{{#ds-button
id="discourse-subscriptions-payment-type-plan"
selected=planButtonSelected
action="selectPlans"
class="btn-discourse-subscriptions-payment-type"
}}
{{i18n "discourse_subscriptions.plans.purchase"}}
{{/ds-button}}
{{#ds-button
id="discourse-subscriptions-payment-type-payment"
selected=paymentButtonSelected
action="selectPayments"
class="btn-discourse-subscriptions-payment-type"
}}
{{i18n "discourse_subscriptions.payment.purchase"}}
{{/ds-button}}
</div>
{{/if}}
<hr>
<p>
{{#if planTypeIsSelected}}
{{i18n "discourse_subscriptions.plans.select"}}
{{else}}
{{i18n "discourse_subscriptions.payment.select"}}
{{/if}}
{{i18n "discourse_subscriptions.plans.select"}}
</p>
<div class="subscribe-buttons">
{{#each plans as |plan|}}
{{#ds-button
action="clickPlan"
actionParam=plan
selected=plan.selected
class="btn-discourse-subscriptions-subscribe"
}}
<div class="interval">
{{#if planTypeIsSelected}}
{{i18n (concat "discourse_subscriptions.plans.interval.adverb." plan.recurring.interval)}}
{{else}}
{{i18n "discourse_subscriptions.payment.interval"}}
{{/if}}
</div>
<span class="amount">
{{format-currency plan.currency plan.amountDollars}}
</span>
{{/ds-button}}
{{payment-plan plan=plan selectedPlan=selectedPlan clickPlan=(action "clickPlan")}}
{{/each}}
</div>
@@ -0,0 +1,16 @@
{{#ds-button
action="planClick"
selected=selected
class="btn-discourse-subscriptions-subscribe"
}}
<div class="interval">
{{#if recurringPlan}}
{{i18n (concat "discourse_subscriptions.plans.interval.adverb." plan.recurring.interval)}}
{{else}}
{{i18n "discourse_subscriptions.one_time_payment"}}
{{/if}}
</div>
<span class="amount">
{{format-currency plan.currency plan.amountDollars}}
</span>
{{/ds-button}}
@@ -21,8 +21,7 @@
{{payment-options
plans=model.plans
paymentsAllowed=paymentsAllowed
planTypeIsSelected=planTypeIsSelected
selectedPlan=selectedPlan
}}
<hr>
@@ -32,12 +31,12 @@
{{#if loading}}
{{loading-spinner}}
{{else}}
{{#d-button
{{d-button
disabled=loading
action="stripePaymentHandler"
class="btn btn-primary btn-payment"}}
{{buttonText}}
{{/d-button}}
class="btn btn-primary btn-payment"
label="discourse_subscriptions.plans.payment_button"
}}
{{/if}}
{{/unless}}