fix(billing): backfill finite image quota after free-plan rebuild
Expired paid users were rebuilt as free with period_images_limit=0, which the quota system treats as unlimited. Write the catalog quota on rebuild and repair existing finite plans on schema ensure. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -57,6 +57,16 @@ async function columnExists(pool, table, column) {
|
||||
return rows.length > 0;
|
||||
}
|
||||
|
||||
async function tableExists(pool, table) {
|
||||
const [rows] = await pool.query(
|
||||
`SELECT 1 FROM information_schema.TABLES
|
||||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ?
|
||||
LIMIT 1`,
|
||||
[table],
|
||||
);
|
||||
return rows.length > 0;
|
||||
}
|
||||
|
||||
async function indexExists(pool, table, index) {
|
||||
const [rows] = await pool.query(
|
||||
`SELECT 1 FROM information_schema.STATISTICS
|
||||
@@ -943,10 +953,23 @@ export async function migrateSchema(pool) {
|
||||
|
||||
// Back-fill free subscriptions for existing users who pre-date the subscription system.
|
||||
// Idempotent: only inserts where no active subscription exists.
|
||||
// period_images_limit defaults to 0 (= unlimited). Always write the catalog
|
||||
// quota when the column exists, otherwise expired paid users become unlimited
|
||||
// on the next Portal/Plaza start.
|
||||
const hasImageLimit = await columnExists(pool, 'h5_subscriptions', 'period_images_limit');
|
||||
const hasCatalog = await tableExists(pool, 'h5_plan_catalog');
|
||||
const tokenSelect = hasCatalog ? 'COALESCE(c.period_tokens, 150000)' : '150000';
|
||||
const imageSelect = hasCatalog ? 'COALESCE(c.period_images, 10)' : '10';
|
||||
const catalogJoin = hasCatalog ? "LEFT JOIN h5_plan_catalog c ON c.plan_type = 'free'" : '';
|
||||
const imageCols = hasImageLimit
|
||||
? 'period_images_limit, period_images_used, period_images_bonus,'
|
||||
: '';
|
||||
const imageVals = hasImageLimit ? `${imageSelect}, 0, 0,` : '';
|
||||
await pool.query(`
|
||||
INSERT INTO h5_subscriptions
|
||||
(id, user_id, plan_type, status,
|
||||
period_tokens_limit, period_tokens_used,
|
||||
${imageCols}
|
||||
period_start, period_end, expires_at, overage_rate,
|
||||
operator_id, note, created_at, updated_at)
|
||||
SELECT
|
||||
@@ -954,7 +977,8 @@ export async function migrateSchema(pool) {
|
||||
u.id,
|
||||
'free',
|
||||
'active',
|
||||
150000, 0,
|
||||
${tokenSelect}, 0,
|
||||
${imageVals}
|
||||
UNIX_TIMESTAMP() * 1000,
|
||||
(UNIX_TIMESTAMP() + 30 * 86400) * 1000,
|
||||
(UNIX_TIMESTAMP() + 30 * 86400) * 1000,
|
||||
@@ -964,6 +988,7 @@ export async function migrateSchema(pool) {
|
||||
UNIX_TIMESTAMP() * 1000,
|
||||
UNIX_TIMESTAMP() * 1000
|
||||
FROM h5_users u
|
||||
${catalogJoin}
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM h5_subscriptions s
|
||||
WHERE s.user_id = u.id AND s.status = 'active'
|
||||
|
||||
Reference in New Issue
Block a user