UNPKG

@wepublish/api

Version:
339 lines 15.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SubscriptionFlowService = void 0; const tslib_1 = require("tslib"); const common_1 = require("@nestjs/common"); const subscription_flow_type_1 = require("./subscription-flow.type"); const client_1 = require("@prisma/client"); const SUBSCRIPTION_EVENT_MAX_DAYS_BEFORE = -25; const SUBSCRIPTION_EVENT_MAX_DAYS_AFTER = 90; let SubscriptionFlowService = exports.SubscriptionFlowService = class SubscriptionFlowService { constructor(prismaService) { this.prismaService = prismaService; } getFlows(defaultFlowOnly, memberPlanId) { return tslib_1.__awaiter(this, void 0, void 0, function* () { let where = {}; if (defaultFlowOnly) { where = { default: true }; } else if (memberPlanId !== undefined) { // do not pass undefined member plan id. where = { OR: [ { memberPlanId }, { memberPlanId: null } ] }; } return yield this.prismaService.subscriptionFlow.findMany({ where, orderBy: { default: 'desc' }, include: { memberPlan: true, paymentMethods: true, intervals: { include: { mailTemplate: true } } } }); }); } createFlow(flow) { return tslib_1.__awaiter(this, void 0, void 0, function* () { if (!flow.periodicities.length || !flow.autoRenewal.length || !flow.paymentMethodIds.length) { throw new common_1.BadRequestException('Its not allowed to create subscription flow with no periodicities OR autoRenewal OR paymentMethods'); } if (yield this.filterHasOverlap(flow.memberPlanId, flow)) { throw new common_1.BadRequestException("You can't create this flow because there is a filter overlap!"); } yield this.prismaService.subscriptionFlow.create({ data: { default: false, memberPlan: { connect: { id: flow.memberPlanId } }, paymentMethods: { connect: flow.paymentMethodIds.map(paymentMethodId => ({ id: paymentMethodId })) }, periodicities: flow.periodicities, autoRenewal: flow.autoRenewal, intervals: { create: [ { daysAwayFromEnding: -14, event: client_1.SubscriptionEvent.INVOICE_CREATION, mailTemplate: undefined }, { daysAwayFromEnding: 5, event: client_1.SubscriptionEvent.DEACTIVATION_UNPAID, mailTemplate: undefined } ] } } }); return this.getFlows(false); }); } updateFlow(flow) { return tslib_1.__awaiter(this, void 0, void 0, function* () { if ((flow.periodicities && !flow.periodicities.length) || (flow.autoRenewal && !flow.autoRenewal.length) || (flow.paymentMethodIds && !flow.paymentMethodIds.length)) { throw new common_1.BadRequestException('Its not allowed to update subscription flow with no periodicities OR autoRenewal OR paymentMethods'); } const originalFlow = yield this.prismaService.subscriptionFlow.findUnique({ where: { id: flow.id }, include: { paymentMethods: true } }); if (!originalFlow) { throw new common_1.NotFoundException(`The subscription flow '${flow.id}' could not be found.`); } if (yield this.filterHasOverlap(originalFlow.memberPlanId, flow)) { throw new common_1.BadRequestException("You can't update this flow because there is a filter overlap!"); } yield this.prismaService.$transaction([ this.prismaService.subscriptionFlow.update({ where: { id: flow.id }, data: { paymentMethods: { disconnect: originalFlow.paymentMethods.map(paymentMethod => ({ id: paymentMethod.id })) } } }), this.prismaService.subscriptionFlow.update({ where: { id: flow.id }, data: { paymentMethods: flow.paymentMethodIds ? { connect: flow.paymentMethodIds.map(paymentMethodId => ({ id: paymentMethodId })) } : undefined, periodicities: flow.periodicities, autoRenewal: flow.autoRenewal } }) ]); return this.getFlows(false); }); } deleteFlow(subscriptionFlowId) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const originalFlow = yield this.prismaService.subscriptionFlow.findUnique({ where: { id: subscriptionFlowId }, include: { paymentMethods: true, intervals: true } }); if (!originalFlow) { throw new common_1.NotFoundException('The given filter is not found!'); } if (originalFlow.default) { throw new common_1.BadRequestException("It's not allowed to delete default flow!"); } yield this.prismaService.$transaction([ this.prismaService.subscriptionFlow.delete({ where: { id: subscriptionFlowId } }), this.prismaService.subscriptionInterval.deleteMany({ where: { id: { in: originalFlow.intervals.map(additionalInterval => additionalInterval.id) } } }) ]); return this.getFlows(false); }); } createInterval(interval) { return tslib_1.__awaiter(this, void 0, void 0, function* () { yield this.isIntervalValid(interval); yield this.prismaService.subscriptionInterval.create({ data: { daysAwayFromEnding: interval.daysAwayFromEnding, subscriptionFlow: { connect: { id: interval.subscriptionFlowId } }, event: interval.event, mailTemplate: interval.mailTemplateId ? { connect: { id: interval.mailTemplateId } } : {} } }); return this.getFlows(false); }); } updateInterval(interval) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const eventToUpdate = yield this.prismaService.subscriptionInterval.findUnique({ where: { id: interval.id } }); if (!eventToUpdate) { throw new common_1.NotFoundException('The given interval not found!'); } yield this.isIntervalValid(Object.assign({ event: eventToUpdate.event, subscriptionFlowId: eventToUpdate.subscriptionFlowId }, interval), false); yield this.prismaService.$transaction([ this.prismaService.subscriptionInterval.update({ where: { id: interval.id }, data: { mailTemplate: { disconnect: true } } }), this.prismaService.subscriptionInterval.update({ where: { id: interval.id }, data: { mailTemplate: interval.mailTemplateId ? { connect: { id: interval.mailTemplateId } } : {}, daysAwayFromEnding: interval.daysAwayFromEnding } }) ]); return this.getFlows(false); }); } deleteInterval(id) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const intervalToDelete = yield this.prismaService.subscriptionInterval.findUnique({ where: { id } }); if (!intervalToDelete) { throw new common_1.NotFoundException('The given interval not found!'); } if (subscription_flow_type_1.subscriptionFlowRequiredEvents.includes(intervalToDelete.event)) { throw new common_1.BadRequestException(`Its not allowed to delete a required ${intervalToDelete.event} event! `); } yield this.prismaService.subscriptionInterval.delete({ where: { id } }); return this.getFlows(false); }); } filterHasOverlap(memberPlanId, newFlow) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const whereClause = memberPlanId ? { memberPlan: { id: memberPlanId } } : {}; const allFlows = yield this.prismaService.subscriptionFlow.findMany({ where: whereClause, select: { id: true, paymentMethods: { select: { id: true } }, periodicities: true, autoRenewal: true } }); for (const flow of allFlows) { // skip itself if (newFlow.id === flow.id) { continue; } const existingPM = new Set(flow.paymentMethods.map(pm => pm.id)); const newPM = new Set((newFlow.paymentMethodIds || []).map(pm => pm)); const existingPe = new Set(flow.periodicities); const newPe = new Set(newFlow.periodicities); const existingAr = new Set(flow.autoRenewal); const newAr = new Set(newFlow.autoRenewal); // find filter values that are the same as the existing filter values const pmIntersection = new Set([...newPM].filter(x => existingPM.has(x))); const peIntersection = new Set([...newPe].filter(x => existingPe.has(x))); const arIntersection = new Set([...newAr].filter(x => existingAr.has(x))); // if any of the filter intersection are not empty, means that the filter combination exists already. if (pmIntersection.size !== 0 && peIntersection.size !== 0 && arIntersection.size !== 0) { return true; } } return false; }); } isIntervalValid(interval, checkEventUniqueConstraint = true) { return tslib_1.__awaiter(this, void 0, void 0, function* () { if (interval.daysAwayFromEnding === null || interval.daysAwayFromEnding === undefined) { if (!subscription_flow_type_1.subscriptionFlowDaysAwayFromEndingNeedToBeNull.includes(interval.event)) { throw new common_1.BadRequestException(`For event ${interval.event} daysAwayFromEnding can not be null!`); } } else if (subscription_flow_type_1.subscriptionFlowDaysAwayFromEndingNeedToBeNull.includes(interval.event)) { throw new common_1.BadRequestException(`For event ${interval.event} daysAwayFromEnding needs to be null!`); } if (checkEventUniqueConstraint && !subscription_flow_type_1.subscriptionFlowNonUniqueEvents.includes(interval.event)) { const dbIntervals = yield this.prismaService.subscriptionInterval.findMany({ where: { subscriptionFlow: { id: interval.subscriptionFlowId } } }); for (const dbInterval of dbIntervals) { if (dbInterval.event === interval.event) { throw new common_1.BadRequestException(`For each subscription flow its not allowed to have more than one events of the type ${interval.event}`); } } } // Limit daysAwayFromEnding if (!!interval.daysAwayFromEnding && (interval.daysAwayFromEnding < SUBSCRIPTION_EVENT_MAX_DAYS_BEFORE || interval.daysAwayFromEnding > SUBSCRIPTION_EVENT_MAX_DAYS_AFTER)) { throw new common_1.BadRequestException(`daysAwayFromEnding is not in allowed range of ${SUBSCRIPTION_EVENT_MAX_DAYS_BEFORE} to ${SUBSCRIPTION_EVENT_MAX_DAYS_AFTER}: ${interval.daysAwayFromEnding}`); } // check for special daysAwayFromEnding event constraints if (interval.event === client_1.SubscriptionEvent.INVOICE_CREATION) { if (!!interval.daysAwayFromEnding && interval.daysAwayFromEnding > 0) { throw new common_1.BadRequestException(`It's not possible to set event ${interval.event} to a date later as the subscription is renewed`); } } if (interval.event === client_1.SubscriptionEvent.DEACTIVATION_UNPAID) { if (!!interval.daysAwayFromEnding && interval.daysAwayFromEnding < 0) { throw new common_1.BadRequestException(`It's not possible to set event ${interval.event} to a date before as the subscription is renewed`); } } }); } }; exports.SubscriptionFlowService = SubscriptionFlowService = tslib_1.__decorate([ (0, common_1.Injectable)(), tslib_1.__metadata("design:paramtypes", [client_1.PrismaClient]) ], SubscriptionFlowService); //# sourceMappingURL=subscription-flow.service.js.map