diff --git a/app/saas/src/main/java/stirling/software/saas/payg/policy/PricingPolicy.java b/app/saas/src/main/java/stirling/software/saas/payg/policy/PricingPolicy.java index 9581177369..d28b0fd09d 100644 --- a/app/saas/src/main/java/stirling/software/saas/payg/policy/PricingPolicy.java +++ b/app/saas/src/main/java/stirling/software/saas/payg/policy/PricingPolicy.java @@ -114,6 +114,19 @@ public class PricingPolicy implements Serializable { @Column(name = "stripe_price_id", nullable = false, length = 128) private Set stripePriceIds = new HashSet<>(); + /** + * One-time Stripe Price id for prepaid-bundle checkout — same {@code unit_amount} as the + * metered price (Stripe {@code currency_options} cover all currencies on one Price). Read by + * the create-payg-bundle-checkout edge fn via {@code payg_get_bundle_checkout_context}. Null = + * bundles not offered for this policy. Money lives in Stripe; this is just the handle. + */ + @Column(name = "bundle_stripe_price_id", length = 128) + private String bundleStripePriceId; + + /** Stripe coupon id applying the 12-for-10 prepaid discount. Null = bundles not offered. */ + @Column(name = "bundle_coupon_id", length = 128) + private String bundleCouponId; + /** * Exactly one row in the table has {@code is_default = true}; enforced by partial unique idx. */ diff --git a/app/saas/src/main/resources/db/migration/saas/V42__payg_bundle_pricing_policy.sql b/app/saas/src/main/resources/db/migration/saas/V42__payg_bundle_pricing_policy.sql new file mode 100644 index 0000000000..92369fdc33 --- /dev/null +++ b/app/saas/src/main/resources/db/migration/saas/V42__payg_bundle_pricing_policy.sql @@ -0,0 +1,22 @@ +-- Prepaid-bundle Stripe objects on the pricing policy — same home as the metered price ids +-- (pricing_policy_stripe_price). The bundle is bought at a one-time Price whose unit_amount matches +-- the meter, discounted by a coupon; both are per-policy config so ops can point a policy at its +-- Stripe objects without an env var or code change. +-- +-- * bundle_stripe_price_id — the ONE-TIME Price (Stripe currency_options cover all currencies on a +-- single Price, so one id per policy, exactly like the metered price). +-- * bundle_coupon_id — the "12 months for the price of 10" coupon. +-- +-- NULL on both = bundles not offered for that policy; the create-payg-bundle-checkout edge fn refuses +-- to mint a session. Additive + idempotent. Money still lives in Stripe — these are just the handles. + +ALTER TABLE stirling_pdf.pricing_policy + ADD COLUMN IF NOT EXISTS bundle_stripe_price_id VARCHAR(128); +ALTER TABLE stirling_pdf.pricing_policy + ADD COLUMN IF NOT EXISTS bundle_coupon_id VARCHAR(128); + +COMMENT ON COLUMN stirling_pdf.pricing_policy.bundle_stripe_price_id IS + 'One-time Stripe Price id for prepaid-bundle checkout (same unit_amount as the metered price). ' + 'NULL = bundles not offered for this policy.'; +COMMENT ON COLUMN stirling_pdf.pricing_policy.bundle_coupon_id IS + 'Stripe coupon id applying the 12-for-10 prepaid discount. NULL = bundles not offered.';