The fixed amount_off coupon only nets $1 for a quantity of one, and the offer is meant for genuinely new signups. A lapsed account that kept several workspaces and re-subscribes through onboarding would otherwise be charged N*price - amount_off (not $1), and a returning customer could whittle down to one workspace to claim the discount again. Apply the coupon only when the paid first month is enabled, the account bills a single workspace, and it has never subscribed before; every other checkout falls back to allowing promotion codes at the full price.
58 lines
2.2 KiB
PHP
58 lines
2.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Support\Billing;
|
|
|
|
use App\Models\Account;
|
|
use Laravel\Cashier\SubscriptionBuilder;
|
|
use RuntimeException;
|
|
|
|
final class FirstMonthCheckoutDiscount
|
|
{
|
|
/**
|
|
* Configure a subscription checkout to charge $1 for the first invoice via
|
|
* a `duration: once` Stripe coupon, so a real charge validates the card
|
|
* instead of a $0 trial authorization. Stripe rejects a Checkout Session
|
|
* that sets both `discounts` and `allow_promotion_codes`, so checkouts that
|
|
* don't qualify for the paid first month keep the promotion-code field.
|
|
*
|
|
* @throws RuntimeException when a qualifying checkout has the paid first
|
|
* month enabled but no coupon configured — failing
|
|
* loudly beats silently charging full price.
|
|
*/
|
|
public static function apply(SubscriptionBuilder $subscription, Account $account): SubscriptionBuilder
|
|
{
|
|
if (! self::qualifiesForPaidFirstMonth($account)) {
|
|
return $subscription->allowPromotionCodes();
|
|
}
|
|
|
|
$couponId = config('cashier.first_month_coupon_id');
|
|
|
|
if (! is_string($couponId) || $couponId === '') {
|
|
throw new RuntimeException(
|
|
'STRIPE_FIRST_MONTH_COUPON_ID must be set when REQUIRE_CARD_FOR_TRIAL is enabled, '
|
|
.'otherwise checkout would charge the full price instead of the $1 first month.'
|
|
);
|
|
}
|
|
|
|
return $subscription->withCoupon($couponId);
|
|
}
|
|
|
|
/**
|
|
* The fixed-amount first-month coupon only applies to a genuinely new
|
|
* customer checking out a single workspace: the fixed `amount_off` is only
|
|
* correct for a quantity of one, and the $1 offer is for first-time signups
|
|
* — not a returning account re-subscribing with workspaces it kept from a
|
|
* lapsed subscription.
|
|
*/
|
|
private static function qualifiesForPaidFirstMonth(Account $account): bool
|
|
{
|
|
if (! (bool) config('trypost.billing.require_card_for_trial', true)) {
|
|
return false;
|
|
}
|
|
|
|
return $account->workspaces()->count() === 1
|
|
&& ! $account->subscriptions()->exists();
|
|
}
|
|
}
|