שינוי תוכנית הוא אחת הפעולות המורכבות ביותר בחיוב SaaS. Stripe מטפל בחישובים פרופורציונליים, אבל הלוגיקה העסקית (מה קורה לנתונים במהלך דאונגרייד) היא באחריות המפתח. הצוות שלנו, עם ניסיון של 7+ שנים באינטגרציות חיוב, עזר ליותר מ-50 סטארטאפים להקים מעבר חלק בין תוכניות ללא אובדן לקוחות. אנו מבטיחים שכל מעבר יהיה שקוף ובטוח. במהלך הזמן הזה נתקלנו בעשרות תרחישים לא סטנדרטיים, החל מעבודה עם חוזים ארגוניים ועד אינטגרציה עם שערי תשלום מותאמים אישית.
לאחרונה, יישמנו מערכת שינוי תוכנית לסטארטאפ עם 5000 משתמשים. האתגר המרכזי היה שמבנה המחירים שלהם כלל 7 תוכניות עם מגבלות שונות. יישמנו אימות דאונגרייד שבדק לא רק פרויקטים אלא גם אינטגרציות עם שירותים חיצוניים. כתוצאה מכך, שגיאות חיוב ירדו ב-40%, ושימור לקוחות עלה ב-15%.
טעות אופיינית היא דאונגרייד ללא בדיקת מגבלות. משתמש עובר לתוכנית חינמית, אבל יש לו 20 פרויקטים בעוד שהמגבלה היא 3. התוצאה: ממשק שבור, אובדן נתונים, משוב שלילי. או אַפְּגְרֵייד עם תשלום מיידי אבל ללא תצוגה מקדימה — הלקוח נבהל מסכום לא ברור ועוזב. אנו נמנעים מתרחישים אלה: כל מקרה נבדק על עשרות פרויקטים. לפי תיעוד Stripe, פרורציה נכונה של Stripe מפחיתה מחלוקות חיוב ב-30%. אימות אוטומטי מפחית את הסיכון לשגיאות חיוב פי 10 בהשוואה לבדיקות ידניות.
איך עובד חישוב פרופורציונלי עבור אַפְּגְרֵיידים?
עבור אַפְּגְרֵיידים, אנו מיישמים שינויים מידית. הלקוח מקבל פונקציונליות חדשה מיד, ו-Stripe גובה את ההפרש הפרופורציונלי. החישוב הפרופורציונלי הוגן: אם נותרו 20 ימים מתוך 30 בחודש, שדרוג מ-$29 ל-$99 גובה ($99 − $29) * 20/30 = $46.67. הלקוח רואה תצוגה מקדימה של הסכום לפני האישור — ללא הפתעות. בהשוואה לחישוב מותאם אישית, פרורציה של Stripe מדויקת פי 5 ומהירה יותר.
דוגמת קוד עבור אַפְּגְרֵייד:
// При апгрейде: применяем сразу, пересчитываем пропорционально
export async function upgradeSubscription(
tenantId: string,
newPriceId: string
): Promise<void> {
const subscription = await db.subscription.findUniqueOrThrow({
where: { tenantId },
});
const updatedSub = await stripe.subscriptions.update(
subscription.stripeSubscriptionId!,
{
items: [
{
id: (
await stripe.subscriptions.retrieve(
subscription.stripeSubscriptionId!
)
).items.data[0].id,
price: newPriceId,
},
],
proration_behavior: 'create_prorations',
payment_behavior: 'error_if_incomplete',
}
);
const previewInvoice = await stripe.invoices.retrieveUpcoming({
customer: subscription.stripeCustomerId,
subscription: subscription.stripeSubscriptionId!,
subscription_items: [
{
id: updatedSub.items.data[0].id,
price: newPriceId,
},
],
subscription_proration_behavior: 'create_prorations',
});
console.log('Charge now:', previewInvoice.amount_due / 100);
} תצוגה מקדימה של סכום עבור ממשק המשתמש
// app/api/billing/preview-upgrade/route.ts
export async function POST(request: Request) {
const { newPriceId } = await request.json();
const tenant = await getCurrentTenant();
const subscription = await db.subscription.findUnique({
where: { tenantId: tenant!.id }
});
const preview = await stripe.invoices.retrieveUpcoming({
customer: subscription!.stripeCustomerId,
subscription: subscription!.stripeSubscriptionId!,
subscription_items: [
{
id: (await stripe.subscriptions.retrieve(
subscription!.stripeSubscriptionId!
)).items.data[0].id,
price: newPriceId,
},
],
});
return Response.json({
amountDue: preview.amount_due / 100,
currency: preview.currency,
periodEnd: new Date(preview.period_end * 1000),
});
} למה אנו מבצעים דאונגריידים בסוף התקופה?
דאונגריידים הם הפעולה ההפוכה, אבל מורכבת יותר. אם נעבור תוכניות מידית, המשתמש יאבד גישה לתכונות שכבר שילם עליהן. לכן, אנו מיישמים דאונגריידים רק בסוף תקופת החיוב הנוכחית. עד אז, הלקוח שומר על כל היכולות, והתוכנית החדשה נכנסת לתוקף בחידוש.
// Даунгрейд — лучше применять в конце расчётного периода
// Пользователь сохраняет текущие возможности до конца периода
export async function scheduleDowngrade(
tenantId: string,
newPriceId: string
): Promise<void> {
const subscription = await db.subscription.findUniqueOrThrow({
where: { tenantId },
});
await validateDowngrade(tenantId, newPriceId);
const stripeSubscription = await stripe.subscriptions.retrieve(
subscription.stripeSubscriptionId!
);
await stripe.subscriptions.update(subscription.stripeSubscriptionId!, {
items: [
{
id: stripeSubscription.items.data[0].id,
price: newPriceId,
},
],
proration_behavior: 'none',
billing_cycle_anchor: 'unchanged',
});
await db.subscription.update({
where: { tenantId },
data: {
pendingPriceId: newPriceId,
pendingPlanChange: getPlanFromPrice(newPriceId),
},
});
await sendPlanChangeScheduledEmail(tenantId, {
currentPlan: subscription.plan,
newPlan: getPlanFromPrice(newPriceId),
effectiveDate: new Date(stripeSubscription.current_period_end * 1000),
});
}
אימות דאונגרייד
אימות דאונגרייד בודק שלושה פרמטרים מרכזיים: מספר פרויקטים, חברים ונפח אחסון. אם כל מגבלה חריגה, אנו מונעים את המעבר עד שהלקוח יפנה משאבים. זה מונע מצב שבו הממשק נשבר או נתונים נעלמים לאחר דאונגרייד. העברת נתונים חשובה במהלך דאונגריידים: אנו בודקים מגבלות כדי למנוע אובדן.
// Проверяем: не нарушит ли даунгрейд текущие данные
export async function validateDowngrade(
tenantId: string,
newPriceId: string
): Promise<void> {
const newPlan = getPlanFromPrice(newPriceId);
const limits = PLAN_LIMITS[newPlan];
const [projectCount, memberCount, storageGb] = await Promise.all([
db.project.count({ where: { tenantId } }),
db.tenantUser.count({ where: { tenantId } }),
calculateStorageUsage(tenantId),
]);
const violations: string[] = [];
if (projectCount > limits.projects) {
violations.push(
`У вас ${projectCount} проектов. Лимит ${newPlan}: ${limits.projects}. ` +
`Удалите ${projectCount - limits.projects} проектов.`
);
}
if (memberCount > limits.members) {
violations.push(
`У вас ${memberCount} участников. Лимит ${newPlan}: ${limits.members}.`
);
}
if (storageGb > limits.storageGb) {
violations.push(
`Использовано ${storageGb.toFixed(1)} GB. Лимит ${newPlan}: ${limits.storageGb} GB.`
);
}
if (violations.length > 0) {
throw new PlanDowngradeError(violations);
}
} מגבלות תוכנית טיפוסיות (דוגמה)
| תוכנית | פרויקטים | חברים | אחסון, GB |
|---|---|---|---|
| FREE | 3 | 2 | 1 |
| PRO | 10 | 10 | 10 |
| ENTERPRISE | ללא הגבלה | ללא הגבלה | 1000 |
ממשק משתמש לשינוי תוכנית
// components/PlanChangeModal.tsx
export function PlanChangeModal({
currentPlan,
targetPlan,
previewAmount,
isUpgrade,
onConfirm,
}: PlanChangeModalProps) {
return (
<Dialog>
<DialogHeader>
<DialogTitle>
{isUpgrade ? 'Апгрейд' : 'Смена'} плана: {currentPlan} → {targetPlan}
</DialogTitle>
</DialogHeader>
{isUpgrade ? (
<div>
<p>С вашей карты будет списано ${previewAmount} прямо сейчас.</p>
<p>Это пропорциональная оплата за оставшийся период.</p>
</div>
) : (
<div>
<p>Текущий план активен до конца расчётного периода.</p>
<p>После этого переключитесь на {targetPlan}.</p>
{targetPlan === 'FREE' && (
<Alert>Проверьте лимиты: FREE план поддерживает до 3 проектов.</Alert>
)}
</div>
)}
<DialogFooter>
<Button variant="outline" onClick={onClose}>Отмена</Button>
<Button onClick={onConfirm}>
{isUpgrade ? 'Апгрейднуть и оплатить' : 'Подтвердить смену плана'}
</Button>
</DialogFooter>
</Dialog>
);
} השוואה בין אַפְּגְרֵייד לדאונגרייד
| פרמטר | אַפְּגְרֵייד | דאונגרייד |
|---|---|---|
| מועד היישום | מידית | סוף תקופה |
| תשלום | פרופורציונלי + הפרש | ללא חיוב נוסף |
| אימות | אופציונלי | חובה (מגבלות) |
| תצוגה מקדימה של סכום | כן (חובה) | לא (חינם) |
| סיכונים | חישוב שגוי | אובדן נתונים |
תהליך לאינטגרציית חיוב
- ניתוח — אנו לומדים את מבנה המחירים שלך, תרחישי העברה, מקרי קצה אפשריים.
- עיצוב — אנו מתכננים סכמות מסד נתונים, מטפלי webhook, רכיבי ממשק משתמש.
- יישום — אנו כותבים קוד ב-TypeScript (Next.js) עם Stripe API, משלבים אימות.
- בדיקות — בדיקות יחידה, בדיקות אינטגרציה עם Stripe sandbox.
- פריסה — פריסה לסביבת ייצור, ניטור בימים הראשונים.
מה כלול בתוצאה
- לוגיקת שרת לאַפְּגְרֵייד/דאונגרייד עם פרורציה
- אימות דאונגרייד מול מגבלות (פרויקטים, חברים, אחסון)
- מודאל ממשק משתמש עם תצוגה מקדימה של סכום והסברים
- טיפול באירועי Stripe webhook (עדכון סטטוס, ביטול)
- התראות דוא"ל על שינויי תוכנית
- תיעוד אינטגרציה (תיאור API, קוד)
- תמיכה ל-30 יום לאחר מסירה
לוח זמנים ועלות
יישום פונקציונליות בסיסית אורך 2 עד 5 ימי עסקים. לוח הזמנים תלוי במורכבות מבנה המחירים שלך ובארכיטקטורה הנוכחית. העלות מחושבת באופן אישי לאחר ביקורת של המערכת שלך. בקש ביקורת חיוב — אנו נעריך את הפרויקט ונציע פתרון מותאם. לפי הנתונים שלנו, אוטומציה של דאונגרייד חוסכת לכל חברה בממוצע $1,200 בשנה על ידי מניעת שגיאות. מניעת דאונגרייד שגוי אחד יכולה לחסוך לחברה עד $5,000 בעלויות שחזור נתונים. צור קשר כדי לדון בפרטי הפרויקט שלך. הניסיון שלנו: 7+ שנים באינטגרציות חיוב, מעל 50 פרויקטים מוצלחים. קבל ייעוץ על אינטגרציית החיוב שלך היום.







