Skip to content
This repository was archived by the owner on Apr 6, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const getSubscription = require('../../../lib/payments/stripe/getSubscription')
const createSubscription = require('../../../lib/payments/stripe/createSubscription')
const reactivateSubscription = require('../../../lib/payments/stripe/reactivateSubscription')

module.exports = async (_, args, {pgdb, req, t, mail: {sendMailTemplate}}) => {
module.exports = async (_, args, {pgdb, req, t, mail: {sendMailTemplate, enforceSubscriptions}}) => {
const transaction = await pgdb.transactionBegin()
try {
const {
Expand Down Expand Up @@ -111,6 +111,8 @@ module.exports = async (_, args, {pgdb, req, t, mail: {sendMailTemplate}}) => {

await transaction.transactionCommit()

enforceSubscriptions({ pgdb, userId: membership.userId })

return newMembership
} catch (e) {
await transaction.transactionRollback()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,22 +116,6 @@ module.exports = async (_, args, {pgdb, req, t}) => {
pfAliasId = uuid()
}

// buying reduced is only ok if user doesn't have a SUCCESSFUL pledge yet, except donation only
if (donation < 0 && !!(await transaction.public.pledges.findFirst({userId: user.id, status: 'SUCCESSFUL'}))) {
const pledges = await transaction.public.pledges.find({userId: user.id, status: 'SUCCESSFUL'})
if (pledges.length) {
const pledgeOptions = await transaction.public.pledgeOptions.find({pledgeId: pledges.map(p => p.id)})
if (pledgeOptions.length) {
const packageOptions = await transaction.public.packageOptions.find({id: pledgeOptions.map(p => p.templateId)})
const rewards = await pgdb.public.rewards.find({id: packageOptions.map(p => p.rewardId)})
if (rewards.length) {
logger.info('user tried to buy a reduced membership and already pledged before', { req: req._log(), args })
throw new Error(t('api/membership/reduced/alreadyHas'))
}
}
}
}

// MONTHLY_ABO can only be bought if user has no active membership
// and if user did not buy a MONTHLY already (then he has to reactivateMembership)
const userHasActiveMembership = await transaction.public.memberships.findFirst({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
const moment = require('moment')
const { ascending } = require('d3-array')

module.exports = async (memberships, pgdb, dryRun) => {
const membershipTypeIndex = (
await pgdb.public.membershipTypes.findAll()
).reduce(
(index, type) => {
index[type.id] = type
return index
},
{}
)
const packagesIndex = (
await pgdb.public.packages.findAll()
).reduce(
(index, p) => {
index[p.id] = p
return index
},
{}
)

const yearlyMemberships = memberships.filter(m => membershipTypeIndex[m.membershipTypeId].name !== 'MONTHLY_ABO')
if (!yearlyMemberships.length) {
return
}

const membershipPeriods = await pgdb.public.membershipPeriods.find({
membershipId: memberships.map(m => m.id)
})
const unusedMemberships = yearlyMemberships.filter(m => !membershipPeriods.find(p => p.membershipId === m.id))
if (!unusedMemberships.length) {
return
}

const pledges = await pgdb.public.pledges.find({
id: memberships.map(m => m.pledgeId)
})

const inactiveMemberships = unusedMemberships.filter(m => {
const pledge = pledges.find(p => p.id === m.pledgeId)
return packagesIndex[pledge.packageId].name !== 'ABO_GIVE' || !m.voucherCode
})
if (!inactiveMemberships.length) {
return
}

inactiveMemberships.sort((a, b) => ascending(a.sequenceNumber, b.sequenceNumber))

const electedMembership = (
inactiveMemberships.find(m => m.voucherCode === null) ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this line necessary considering || !m.voucherCode in line 43?

Copy link
Contributor Author

@tpreusse tpreusse Feb 23, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes because above it ensures that only none give abos or redeemed give abos are considere for activation. Here it says that a reedemed abo should be used first (same logic as January activation).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, so basically a null voucherCode represents redeemed, while a "normal" membership would have an undefined voucherCode, correct? (Just trying to understand)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

normal inactive memberships have a voucherCode string

inactiveMemberships.find(m => m.reducedPrice) ||
inactiveMemberships.find(m => membershipTypeIndex[m.membershipTypeId].name === 'BENEFACTOR_ABO') ||
inactiveMemberships[0]
)

if (dryRun) {
return electedMembership
}

const beginDate = new Date() // now
const endDate = moment(beginDate).add(1, 'year')
await pgdb.public.memberships.update({
id: electedMembership.id
}, {
active: true,
renew: true,
voucherCode: null,
voucherable: false
})

await pgdb.public.membershipPeriods.insert({
membershipId: electedMembership.id,
beginDate,
endDate
})

return electedMembership
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const { sendMailTemplate } = require('../../../Mail')
const { sendMailTemplate, enforceSubscriptions } = require('../../../Mail')
const activateYearlyMembership = require('../../../activateYearlyMembership')

module.exports = {
eventTypes: ['customer.subscription.updated', 'customer.subscription.deleted'],
Expand Down Expand Up @@ -58,11 +59,18 @@ module.exports = {
updatedAt: new Date()
})

const user = await transaction.public.users.findOne({
id: pledge.userId
})
const nextMembership = await activateYearlyMembership(
await transaction.public.memberships.find({
userId: existingMembership.userId
}),
transaction
)

if (existingMembership.active && !nextMembership) {
const user = await transaction.public.users.findOne({
id: pledge.userId
})

if (existingMembership.active) {
await sendMailTemplate({
to: user.email,
subject: t('api/email/subscription/deactivated/subject'),
Expand All @@ -79,6 +87,8 @@ module.exports = {
}
}
await transaction.transactionCommit()

enforceSubscriptions({ pgdb, userId: pledge.userId })
} catch (e) {
await transaction.transactionRollback()
console.info('transaction rollback', { error: e })
Expand Down
90 changes: 20 additions & 70 deletions servers/republik/script/fixInactiveYearlyMemberships.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
*/
require('@orbiting/backend-modules-env').config()
const PgDb = require('@orbiting/backend-modules-base/lib/pgdb')
const moment = require('moment')
const { enforceSubscriptions } = require('../modules/crowdfundings/lib/Mail')
const activateYearlyMembership = require('../modules/crowdfundings/lib/activateYearlyMembership')

console.log('running activateMemberships.js...')

Expand All @@ -20,6 +20,7 @@ if (dryRun) {
}

PgDb.connect().then(async pgdb => {
const enforceSubscriptionsUserIds = []
const transaction = await pgdb.transactionBegin()
try {
const usersWithMemberships = await transaction.query(`
Expand All @@ -35,88 +36,37 @@ PgDb.connect().then(async pgdb => {
u.id
`)

const membershipTypeIndex = (
await transaction.public.membershipTypes.findAll()
).reduce(
(index, type) => {
index[type.id] = type
return index
},
{}
)
const packagesIndex = (
await transaction.public.packages.findAll()
).reduce(
(index, p) => {
index[p.id] = p
return index
},
{}
)

for (let user of usersWithMemberships) {
if (user.email === 'jefferson@project-r.construction') {
continue
}
if (user.memberships.find(m => m.active)) {
continue
}
const yearlyMemberships = user.memberships.filter(m => membershipTypeIndex[m.membershipTypeId].name !== 'MONTHLY_ABO')
if (!yearlyMemberships.length) {
continue
}

const pledges = await Promise.all(user.memberships.map(m => transaction.public.pledges.findOne({id: m.pledgeId})))

const notGiveYearlyMemberships = yearlyMemberships.filter(m => {
const pledge = pledges.find(p => p.id === m.pledgeId)
return packagesIndex[pledge.packageId].name !== 'ABO_GIVE'
})
if (!notGiveYearlyMemberships.length) {
continue
}

if (notGiveYearlyMemberships.length === 1) {
const membership = notGiveYearlyMemberships[0]
const membership = await activateYearlyMembership(
user.memberships,
transaction,
dryRun
)
if (membership) {
console.log('activating', user.email, membership.sequenceNumber)
if (dryRun) {
continue
}

const beginDate = new Date() // now
const endDate = moment(beginDate).add(1, 'year')
await transaction.public.memberships.update({
id: membership.id
}, {
active: true,
renew: true,
voucherCode: null,
voucherable: false
})

await transaction.public.membershipPeriods.insert({
membershipId: membership.id,
beginDate,
endDate
})

try {
await enforceSubscriptions({
pgdb,
userId: user.id
})
} catch (e) {
console.error('enforceSubscriptions failed for', user.email, e)
}
} else {
console.log('unclear case', user.email)
console.log(user.membership)
console.log(pledges)
enforceSubscriptionsUserIds.push(user.id)
}
}

// commit transaction
await transaction.transactionCommit()

try {
await Promise.all(enforceSubscriptionsUserIds.map(userId =>
enforceSubscriptions({
pgdb,
userId
})
))
} catch (e) {
console.error('enforceSubscriptions failed', enforceSubscriptionsUserIds, e)
}
} catch (e) {
await transaction.transactionRollback()
console.info('transaction rollback', { error: e })
Expand Down