Merge pull request #30674 from overleaf/oa-import-coupons

[web] Simplify and allow multiple promotion codes

GitOrigin-RevId: 6ac1115bcdf4298579df33b3896ee0b786720bac
This commit is contained in:
Olzhas Askar
2026-01-14 09:54:35 +01:00
committed by Copybot
parent 69f3f29f50
commit 3f7555e5a0

View File

@@ -1,6 +1,7 @@
#!/usr/bin/env node
import minimist from 'minimist'
import { setTimeout } from 'node:timers/promises'
import { scriptRunner } from '../lib/ScriptRunner.mjs'
import { getRegionClient } from '../../modules/subscriptions/app/src/StripeClient.mjs'
// eslint-disable-next-line import/no-unresolved
@@ -17,7 +18,7 @@ import { readFile } from 'node:fs/promises'
* --region=us|uk Required. Stripe region to process (us or uk)
*
* CSV Format:
* id,name,percent_off,duration,code,max_redemptions
* name,percent_off,duration,code,max_redemptions
*/
async function main(trackProgress) {
@@ -33,50 +34,43 @@ async function main(trackProgress) {
)
const file = await readFile(inputCSV, { encoding: 'utf8' })
const couponsPlannedToCreate = csv.parse(file, { columns: true })
const couponsToCreate = csv.parse(file, { columns: true })
await trackProgress(
`Successfully parsed "${inputCSV}" CSV file with ${couponsPlannedToCreate.length} coupons to create`
`Successfully parsed "${inputCSV}" CSV file with ${couponsToCreate.length} coupons and promotion codes to create`
)
const client = getRegionClient(region)
const existingCoupons = await client.stripe.coupons.list({ limit: 100 })
const existingIdsAndNames = existingCoupons.data.map(ec => ({
id: ec.id,
name: ec.name,
}))
const stripeCoupons = await client.stripe.coupons.list({ limit: 100 })
const existingCoupons = stripeCoupons.data.reduce((acc, curr) => {
acc[curr.name] = curr.id
return acc
}, {})
await trackProgress(
`Successfully parsed ${existingIdsAndNames.length} existing coupons for verification`
`Successfully parsed ${Object.keys(existingCoupons).length} existing coupons for verification`
)
const couponsToCreate = couponsPlannedToCreate.filter(
c => !existingIdsAndNames.some(e => e.id === c.id || e.name === c.name)
)
if (couponsToCreate.length === 0) {
await trackProgress(`There are no coupons to create`)
} else if (couponsToCreate.length < couponsPlannedToCreate.length) {
const filteredOut = couponsPlannedToCreate
.filter(c =>
existingIdsAndNames.some(e => e.id === c.id || e.name === c.name)
)
.map(c => c.name)
await trackProgress(
`Successfully filtered out: ${filteredOut.join(', ')} existing coupons from the ones to create`
)
}
let couponsCreated = 0
let promotionCodesCreated = 0
let promotionCodesExisted = 0
const errors = []
for (const toCreate of couponsToCreate) {
try {
const createdCoupon = await client.stripe.coupons.create({
id: toCreate.id,
name: toCreate.name,
percent_off: parseFloat(toCreate.percent_off),
duration: toCreate.duration,
})
let targetCouponId = existingCoupons[toCreate.name]
if (!targetCouponId) {
const createdCoupon = await client.stripe.coupons.create({
name: toCreate.name,
percent_off: parseFloat(toCreate.percent_off),
duration: toCreate.duration,
})
targetCouponId = createdCoupon.id
existingCoupons[toCreate.name] = targetCouponId
couponsCreated++
}
const promotionPayload = {
coupon: createdCoupon.id,
coupon: targetCouponId,
code: toCreate.code,
}
const maxRedemptions = parseInt(toCreate.max_redemptions, 10)
@@ -85,15 +79,31 @@ async function main(trackProgress) {
}
await client.stripe.promotionCodes.create(promotionPayload)
promotionCodesCreated++
} catch (error) {
if (
error.message.includes('promotion code') &&
error.message.includes('already exists')
) {
promotionCodesExisted++
} else {
await trackProgress(`Failed to create coupon "${toCreate}"`)
await trackProgress(error.message)
errors.push(toCreate.name)
}
}
if (promotionCodesCreated > 10 && promotionCodesCreated % 10 === 0) {
await trackProgress(
`Failed to create coupon "${toCreate.name}" (${toCreate.id})`,
error.message
`Promotion codes created: ${promotionCodesCreated}, existed: ${promotionCodesExisted}`
)
errors.push(toCreate.name)
await setTimeout(10)
}
}
await trackProgress(`\n\nCoupons created: ${couponsCreated}`)
await trackProgress(`Promotion codes created: ${promotionCodesCreated}`)
await trackProgress(`Promotion codes existed: ${promotionCodesExisted}`)
if (errors.length > 0) {
await trackProgress(
`Could not create the following coupons: ${errors.join(', ')}`