diff --git a/server/src/http/controllers/Subscription/Vouchers.ts b/server/src/http/controllers/Subscription/Licenses.ts similarity index 52% rename from server/src/http/controllers/Subscription/Vouchers.ts rename to server/src/http/controllers/Subscription/Licenses.ts index 41436f621..56cb1a15c 100644 --- a/server/src/http/controllers/Subscription/Vouchers.ts +++ b/server/src/http/controllers/Subscription/Licenses.ts @@ -1,17 +1,17 @@ import { Router, Request, Response } from 'express' import { check, oneOf, ValidationChain } from 'express-validator'; import { Service, Inject } from 'typedi'; -import { Voucher, Plan } from '@/system/models'; +import { License, Plan } from '@/system/models'; import BaseController from '@/http/controllers/BaseController'; -import VoucherService from '@/services/Payment/Voucher'; +import LicenseService from '@/services/Payment/License'; import validateMiddleware from '@/http/middleware/validateMiddleware'; import asyncMiddleware from '@/http/middleware/asyncMiddleware'; -import { IVouchersFilter } from '@/interfaces'; +import { ILicensesFilter } from '@/interfaces'; @Service() -export default class VouchersController extends BaseController { +export default class LicensesController extends BaseController { @Inject() - voucherService: VoucherService; + licenseService: LicenseService; /** * Router constructor. @@ -21,40 +21,40 @@ export default class VouchersController extends BaseController { router.post( '/generate', - this.generateVoucherSchema, + this.generateLicenseSchema, validateMiddleware, asyncMiddleware(this.validatePlanExistance.bind(this)), - asyncMiddleware(this.generateVoucher.bind(this)), + asyncMiddleware(this.generateLicense.bind(this)), ); router.post( - '/disable/:voucherId', + '/disable/:licenseId', validateMiddleware, - asyncMiddleware(this.validateVoucherExistance.bind(this)), - asyncMiddleware(this.validateNotDisabledVoucher.bind(this)), - asyncMiddleware(this.disableVoucher.bind(this)), + asyncMiddleware(this.validateLicenseExistance.bind(this)), + asyncMiddleware(this.validateNotDisabledLicense.bind(this)), + asyncMiddleware(this.disableLicense.bind(this)), ); router.post( '/send', - this.sendVoucherSchemaValidation, + this.sendLicenseSchemaValidation, validateMiddleware, - asyncMiddleware(this.sendVoucher.bind(this)), + asyncMiddleware(this.sendLicense.bind(this)), ); router.delete( - '/:voucherId', - asyncMiddleware(this.validateVoucherExistance.bind(this)), - asyncMiddleware(this.deleteVoucher.bind(this)), + '/:licenseId', + asyncMiddleware(this.validateLicenseExistance.bind(this)), + asyncMiddleware(this.deleteLicense.bind(this)), ); router.get( '/', - asyncMiddleware(this.listVouchers.bind(this)), + asyncMiddleware(this.listLicenses.bind(this)), ); return router; } /** - * Generate voucher validation schema. + * Generate license validation schema. */ - get generateVoucherSchema(): ValidationChain[] { + get generateLicenseSchema(): ValidationChain[] { return [ check('loop').exists().isNumeric().toInt(), check('period').exists().isNumeric().toInt(), @@ -66,22 +66,22 @@ export default class VouchersController extends BaseController { } /** - * Specific voucher validation schema. + * Specific license validation schema. */ - get specificVoucherSchema(): ValidationChain[] { + get specificLicenseSchema(): ValidationChain[] { return [ oneOf([ - check('voucher_id').exists().isNumeric().toInt(), + check('license_id').exists().isNumeric().toInt(), ], [ - check('voucher_code').exists().isNumeric().toInt(), + check('license_code').exists().isNumeric().toInt(), ]) ] } /** - * Send voucher validation schema. + * Send license validation schema. */ - get sendVoucherSchemaValidation(): ValidationChain[] { + get sendLicenseSchemaValidation(): ValidationChain[] { return [ check('period').exists().isNumeric(), check('period_interval').exists().trim().escape(), @@ -113,60 +113,60 @@ export default class VouchersController extends BaseController { } /** - * Valdiate the voucher existance on the storage. + * Valdiate the license existance on the storage. * @param {Request} req * @param {Response} res * @param {Function} */ - async validateVoucherExistance(req: Request, res: Response, next: Function) { + async validateLicenseExistance(req: Request, res: Response, next: Function) { const body = this.matchedBodyData(req); - const voucherId = body.voucherId || req.params.voucherId; - const foundVoucher = await Voucher.query().findById(voucherId); + const licenseId = body.licenseId || req.params.licenseId; + const foundLicense = await License.query().findById(licenseId); - if (!foundVoucher) { + if (!foundLicense) { return res.status(400).send({ - errors: [{ type: 'VOUCHER.NOT.FOUND', code: 200 }], + errors: [{ type: 'LICENSE.NOT.FOUND', code: 200 }], }); } next(); } /** - * Validates whether the voucher id is disabled. + * Validates whether the license id is disabled. * @param {Request} req * @param {Response} res * @param {Function} next */ - async validateNotDisabledVoucher(req: Request, res: Response, next: Function) { - const voucherId = req.params.voucherId || req.query.voucherId; - const foundVoucher = await Voucher.query().findById(voucherId); + async validateNotDisabledLicense(req: Request, res: Response, next: Function) { + const licenseId = req.params.licenseId || req.query.licenseId; + const foundLicense = await License.query().findById(licenseId); - if (foundVoucher.disabled) { + if (foundLicense.disabled) { return res.status(400).send({ - errors: [{ type: 'VOUCHER.ALREADY.DISABLED', code: 200 }], + errors: [{ type: 'LICENSE.ALREADY.DISABLED', code: 200 }], }); } next(); } /** - * Generate vouchers codes with given period in bulk. + * Generate licenses codes with given period in bulk. * @param {Request} req * @param {Response} res * @return {Response} */ - async generateVoucher(req: Request, res: Response, next: Function) { + async generateLicense(req: Request, res: Response, next: Function) { const { loop = 10, period, periodInterval, planId } = this.matchedBodyData(req); try { - await this.voucherService.generateVouchers( + await this.licenseService.generateLicenses( loop, period, periodInterval, planId, ); return res.status(200).send({ code: 100, - type: 'VOUCHERES.GENERATED.SUCCESSFULLY', - message: 'The vouchers have been generated successfully.' + type: 'LICENSEES.GENERATED.SUCCESSFULLY', + message: 'The licenses have been generated successfully.' }); } catch (error) { console.log(error); @@ -175,84 +175,84 @@ export default class VouchersController extends BaseController { } /** - * Disable the given voucher on the storage. + * Disable the given license on the storage. * @param {Request} req * @param {Response} res * @return {Response} */ - async disableVoucher(req: Request, res: Response) { - const { voucherId } = req.params; + async disableLicense(req: Request, res: Response) { + const { licenseId } = req.params; - await this.voucherService.disableVoucher(voucherId); + await this.licenseService.disableLicense(licenseId); - return res.status(200).send({ voucher_id: voucherId }); + return res.status(200).send({ license_id: licenseId }); } /** - * Deletes the given voucher code on the storage. + * Deletes the given license code on the storage. * @param {Request} req * @param {Response} res * @return {Response} */ - async deleteVoucher(req: Request, res: Response) { - const { voucherId } = req.params; + async deleteLicense(req: Request, res: Response) { + const { licenseId } = req.params; - await this.voucherService.deleteVoucher(voucherId); + await this.licenseService.deleteLicense(licenseId); - return res.status(200).send({ voucher_id: voucherId }); + return res.status(200).send({ license_id: licenseId }); } /** - * Send voucher code in the given period to the customer via email or phone number + * Send license code in the given period to the customer via email or phone number * @param {Request} req * @param {Response} res * @return {Response} */ - async sendVoucher(req: Request, res: Response) { + async sendLicense(req: Request, res: Response) { const { phoneNumber, email, period, periodInterval, planId } = this.matchedBodyData(req); - const voucher = await Voucher.query() - .modify('filterActiveVoucher') - .where('voucher_period', period) + const license = await License.query() + .modify('filterActiveLicense') + .where('license_period', period) .where('period_interval', periodInterval) .where('plan_id', planId) .first(); - if (!voucher) { + if (!license) { return res.status(400).send({ status: 110, - message: 'There is no vouchers availiable right now with the given period and plan.', - code: 'NO.AVALIABLE.VOUCHER.CODE', + message: 'There is no licenses availiable right now with the given period and plan.', + code: 'NO.AVALIABLE.LICENSE.CODE', }); } - await this.voucherService.sendVoucherToCustomer( - voucher.voucherCode, phoneNumber, email, + await this.licenseService.sendLicenseToCustomer( + license.licenseCode, phoneNumber, email, ); return res.status(200).send({ status: 100, - code: 'VOUCHER.CODE.SENT', - message: 'The voucher has been sent to the given customer.', + code: 'LICENSE.CODE.SENT', + message: 'The license has been sent to the given customer.', }); } /** - * Listing vouchers. + * Listing licenses. * @param {Request} req * @param {Response} res */ - async listVouchers(req: Request, res: Response) { - const filter: IVouchersFilter = { + async listLicenses(req: Request, res: Response) { + const filter: ILicensesFilter = { disabled: false, used: false, sent: false, active: false, ...req.query, }; - const vouchers = await Voucher.query() + const licenses = await License.query() .onBuild((builder) => { builder.modify('filter', filter); builder.orderBy('createdAt', 'ASC'); }); - return res.status(200).send({ vouchers }); + return res.status(200).send({ licenses }); } } \ No newline at end of file diff --git a/server/src/http/controllers/Subscription/PaymentViaVoucher.ts b/server/src/http/controllers/Subscription/PaymentViaLicense.ts similarity index 53% rename from server/src/http/controllers/Subscription/PaymentViaVoucher.ts rename to server/src/http/controllers/Subscription/PaymentViaLicense.ts index 4dc9d0734..767caaa56 100644 --- a/server/src/http/controllers/Subscription/PaymentViaVoucher.ts +++ b/server/src/http/controllers/Subscription/PaymentViaLicense.ts @@ -1,7 +1,7 @@ import { Inject, Service } from 'typedi'; import { Router, Request, Response } from 'express'; import { check, param, query, ValidationSchema } from 'express-validator'; -import { Voucher, Plan } from '@/system/models'; +import { License, Plan } from '@/system/models'; import validateMiddleware from '@/http/middleware/validateMiddleware'; import asyncMiddleware from '@/http/middleware/asyncMiddleware'; import PaymentMethodController from '@/http/controllers/Subscription/PaymentMethod'; @@ -10,7 +10,7 @@ import { } from '@/exceptions'; @Service() -export default class PaymentViaVoucherController extends PaymentMethodController { +export default class PaymentViaLicenseController extends PaymentMethodController { @Inject('logger') logger: any; @@ -22,88 +22,88 @@ export default class PaymentViaVoucherController extends PaymentMethodController router.post( '/payment', - this.paymentViaVoucherSchema, + this.paymentViaLicenseSchema, validateMiddleware, - asyncMiddleware(this.validateVoucherCodeExistance.bind(this)), + asyncMiddleware(this.validateLicenseCodeExistance.bind(this)), asyncMiddleware(this.validatePlanSlugExistance.bind(this)), - asyncMiddleware(this.validateVoucherAndPlan.bind(this)), - asyncMiddleware(this.paymentViaVoucher.bind(this)), + asyncMiddleware(this.validateLicenseAndPlan.bind(this)), + asyncMiddleware(this.paymentViaLicense.bind(this)), ); return router; } /** - * Payment via voucher validation schema. + * Payment via license validation schema. */ - get paymentViaVoucherSchema() { + get paymentViaLicenseSchema() { return [ check('plan_slug').exists().trim().escape(), - check('voucher_code').exists().trim().escape(), + check('license_code').exists().trim().escape(), ]; } /** - * Validate the given voucher code exists on the storage. + * Validate the given license code exists on the storage. * @async * @param {Request} req * @param {Response} res */ - async validateVoucherCodeExistance(req: Request, res: Response, next: Function) { - const { voucherCode } = this.matchedBodyData(req); - this.logger.info('[voucher_payment] trying to validate voucher code.', { voucherCode }); + async validateLicenseCodeExistance(req: Request, res: Response, next: Function) { + const { licenseCode } = this.matchedBodyData(req); + this.logger.info('[license_payment] trying to validate license code.', { licenseCode }); - const foundVoucher = await Voucher.query() - .modify('filterActiveVoucher') - .where('voucher_code', voucherCode) + const foundLicense = await License.query() + .modify('filterActiveLicense') + .where('license_code', licenseCode) .first(); - if (!foundVoucher) { + if (!foundLicense) { return res.status(400).send({ - errors: [{ type: 'VOUCHER.CODE.IS.INVALID', code: 120 }], + errors: [{ type: 'LICENSE.CODE.IS.INVALID', code: 120 }], }); } next(); } /** - * Validate the voucher period and plan period. + * Validate the license period and plan period. * @param {Request} req * @param {Response} res * @param {Function} next */ - async validateVoucherAndPlan(req: Request, res: Response, next: Function) { - const { planSlug, voucherCode } = this.matchedBodyData(req); - this.logger.info('[voucher_payment] trying to validate voucher with the plan.', { voucherCode }); + async validateLicenseAndPlan(req: Request, res: Response, next: Function) { + const { planSlug, licenseCode } = this.matchedBodyData(req); + this.logger.info('[license_payment] trying to validate license with the plan.', { licenseCode }); - const voucher = await Voucher.query().findOne('voucher_code', voucherCode); + const license = await License.query().findOne('license_code', licenseCode); const plan = await Plan.query().findOne('slug', planSlug); - if (voucher.planId !== plan.id) { + if (license.planId !== plan.id) { return res.status(400).send({ - errors: [{ type: 'VOUCHER.NOT.FOR.GIVEN.PLAN' }], + errors: [{ type: 'LICENSE.NOT.FOR.GIVEN.PLAN' }], }); } next(); } /** - * Handle the subscription payment via voucher code. + * Handle the subscription payment via license code. * @param {Request} req * @param {Response} res * @return {Response} */ - async paymentViaVoucher(req: Request, res: Response, next: Function) { - const { planSlug, voucherCode } = this.matchedBodyData(req); + async paymentViaLicense(req: Request, res: Response, next: Function) { + const { planSlug, licenseCode } = this.matchedBodyData(req); const { tenant } = req; try { await this.subscriptionService - .subscriptionViaVoucher(tenant.id, planSlug, voucherCode); + .subscriptionViaLicense(tenant.id, planSlug, licenseCode); return res.status(200).send({ type: 'success', code: 'PAYMENT.SUCCESSFULLY.MADE', - message: 'Payment via voucher has been made successfully.', + message: 'Payment via license has been made successfully.', }); } catch (exception) { const errorReasons = []; diff --git a/server/src/http/controllers/Subscription/index.ts b/server/src/http/controllers/Subscription/index.ts index 7e3b8941f..683eb39a4 100644 --- a/server/src/http/controllers/Subscription/index.ts +++ b/server/src/http/controllers/Subscription/index.ts @@ -3,7 +3,7 @@ import { Container, Service } from 'typedi'; import JWTAuth from '@/http/middleware/jwtAuth'; import TenancyMiddleware from '@/http/middleware/TenancyMiddleware'; import AttachCurrentTenantUser from '@/http/middleware/AttachCurrentTenantUser'; -import PaymentViaVoucherController from '@/http/controllers/Subscription/PaymentViaVoucher'; +import PaymentViaLicenseController from '@/http/controllers/Subscription/PaymentViaLicense'; @Service() export default class SubscriptionController { @@ -17,7 +17,7 @@ export default class SubscriptionController { router.use(AttachCurrentTenantUser); router.use(TenancyMiddleware); - router.use('/voucher', Container.get(PaymentViaVoucherController).router()); + router.use('/license', Container.get(PaymentViaLicenseController).router()); return router; } diff --git a/server/src/http/index.js b/server/src/http/index.js index c14d4f966..ea2c1a45f 100644 --- a/server/src/http/index.js +++ b/server/src/http/index.js @@ -35,7 +35,7 @@ import Media from '@/http/controllers/Media'; import Ping from '@/http/controllers/Ping'; import Agendash from '@/http/controllers/Agendash'; import Subscription from '@/http/controllers/Subscription'; -import VouchersController from '@/http/controllers/Subscription/Vouchers'; +import LicensesController from '@/http/controllers/Subscription/Licenses'; export default () => { const app = Router(); @@ -45,7 +45,7 @@ export default () => { app.use('/auth', Container.get(Authentication).router()); app.use('/invite', Container.get(InviteUsers).nonAuthRouter()); app.use('/organization', Container.get(Organization).router()); - app.use('/vouchers', Container.get(VouchersController).router()); + app.use('/licenses', Container.get(LicensesController).router()); app.use('/subscription', Container.get(Subscription).router()); app.use('/ping', Container.get(Ping).router()); diff --git a/server/src/interfaces/Voucher.ts b/server/src/interfaces/License.ts similarity index 57% rename from server/src/interfaces/Voucher.ts rename to server/src/interfaces/License.ts index eb5359361..b2d1e47b6 100644 --- a/server/src/interfaces/Voucher.ts +++ b/server/src/interfaces/License.ts @@ -1,15 +1,15 @@ -export interface IVoucher { +export interface ILicense { id?: number, - voucherCode: string, - voucherPeriod: number, + licenseCode: string, + licensePeriod: number, sent: boolean, disabled: boolean, used: boolean, }; -export interface IVouchersFilter { +export interface ILicensesFilter { active: boolean, disabld: boolean, used: boolean, diff --git a/server/src/interfaces/Payment.ts b/server/src/interfaces/Payment.ts index 5c0e04a8e..4d5317319 100644 --- a/server/src/interfaces/Payment.ts +++ b/server/src/interfaces/Payment.ts @@ -2,16 +2,16 @@ export interface IPaymentModel {} -export interface IVoucherPaymentModel extends IPaymentModel { - voucherCode: string; +export interface ILicensePaymentModel extends IPaymentModel { + licenseCode: string; } export interface IPaymentMethod { makePayment(paymentModel: IPaymentModel): Promise; } -export interface IVoucherPaymentMethod { - makePayment(paymentModel: IVoucherPaymentModel): Promise; +export interface ILicensePaymentMethod { + makePayment(paymentModel: ILicensePaymentModel): Promise; } export interface IPaymentContext { diff --git a/server/src/interfaces/index.ts b/server/src/interfaces/index.ts index c838b61f7..c8d7a9446 100644 --- a/server/src/interfaces/index.ts +++ b/server/src/interfaces/index.ts @@ -7,13 +7,13 @@ import { import { IInventoryCostMethod } from './InventoryCostMethod'; import { IItemEntry } from './ItemEntry'; import { IItem } from './Item'; -import { IVoucher, IVouchersFilter } from './Voucher'; +import { ILicense, ILicensesFilter } from './License'; import { IItemCategory, IItemCategoryOTD } from './ItemCategory'; import { IPaymentModel, - IVoucherPaymentModel, + ILicensePaymentModel, IPaymentMethod, - IVoucherPaymentMethod, + ILicensePaymentMethod, IPaymentContext, } from './Payment'; import { @@ -57,16 +57,16 @@ export { IInventoryCostMethod, IItemEntry, IItem, - IVoucher, - IVouchersFilter, + ILicense, + ILicensesFilter, IItemCategory, IItemCategoryOTD, IPaymentModel, IPaymentMethod, IPaymentContext, - IVoucherPaymentModel, - IVoucherPaymentMethod, + ILicensePaymentModel, + ILicensePaymentMethod, ISaleInvoice, ISaleInvoiceOTD, diff --git a/server/src/jobs/SendLicenseEmail.ts b/server/src/jobs/SendLicenseEmail.ts new file mode 100644 index 000000000..48cc9733a --- /dev/null +++ b/server/src/jobs/SendLicenseEmail.ts @@ -0,0 +1,22 @@ +import { Container } from 'typedi'; +import LicenseService from '@/services/Payment/License'; + +export default class SendLicenseViaEmailJob { + public async handler(job, done: Function): Promise { + const Logger = Container.get('logger'); + const licenseService = Container.get(LicenseService); + const { email, licenseCode } = job.attrs.data; + + Logger.debug(`Send license via email - started: ${job.attrs.data}`); + + try { + await licenseService.mailMessages.sendMailLicense(licenseCode, email); + Logger.debug(`Send license via email - completed: ${job.attrs.data}`); + done(); + } catch(e) { + console.log(e); + Logger.error(`Send license via email: ${job.attrs.data}, error: ${e}`); + done(e); + } + } +} diff --git a/server/src/jobs/SendLicensePhone.ts b/server/src/jobs/SendLicensePhone.ts new file mode 100644 index 000000000..2129b9c9b --- /dev/null +++ b/server/src/jobs/SendLicensePhone.ts @@ -0,0 +1,23 @@ +import { Container } from 'typedi'; +import LicenseService from '@/services/Payment/License'; + +export default class SendLicenseViaPhoneJob { + public async handler(job, done: Function): Promise { + const { phoneNumber, licenseCode } = job.attrs.data; + + const Logger = Container.get('logger'); + const licenseService = Container.get(LicenseService); + + Logger.debug(`Send license via phone number - started: ${job.attrs.data}`); + + try { + await licenseService.smsMessages.sendLicenseSMSMessage(phoneNumber, licenseCode); + Logger.debug(`Send license via phone number - completed: ${job.attrs.data}`); + done(); + } catch(e) { + console.log(e); + Logger.error(`Send license via phone number: ${job.attrs.data}, error: ${e}`); + done(e); + } + } +} diff --git a/server/src/jobs/SendVoucherEmail.ts b/server/src/jobs/SendVoucherEmail.ts deleted file mode 100644 index cb0fc2bcc..000000000 --- a/server/src/jobs/SendVoucherEmail.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Container } from 'typedi'; -import VoucherService from '@/services/Payment/Voucher'; - -export default class SendVoucherViaEmailJob { - public async handler(job, done: Function): Promise { - const Logger = Container.get('logger'); - const voucherService = Container.get(VoucherService); - const { email, voucherCode } = job.attrs.data; - - Logger.debug(`Send voucher via email - started: ${job.attrs.data}`); - - try { - await voucherService.mailMessages.sendMailVoucher(voucherCode, email); - Logger.debug(`Send voucher via email - completed: ${job.attrs.data}`); - done(); - } catch(e) { - console.log(e); - Logger.error(`Send voucher via email: ${job.attrs.data}, error: ${e}`); - done(e); - } - } -} diff --git a/server/src/jobs/SendVoucherPhone.ts b/server/src/jobs/SendVoucherPhone.ts deleted file mode 100644 index ec302c0ed..000000000 --- a/server/src/jobs/SendVoucherPhone.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Container } from 'typedi'; -import VoucherService from '@/services/Payment/Voucher'; - -export default class SendVoucherViaPhoneJob { - public async handler(job, done: Function): Promise { - const { phoneNumber, voucherCode } = job.attrs.data; - - const Logger = Container.get('logger'); - const voucherService = Container.get(VoucherService); - - Logger.debug(`Send voucher via phone number - started: ${job.attrs.data}`); - - try { - await voucherService.smsMessages.sendVoucherSMSMessage(phoneNumber, voucherCode); - Logger.debug(`Send voucher via phone number - completed: ${job.attrs.data}`); - done(); - } catch(e) { - console.log(e); - Logger.error(`Send voucher via phone number: ${job.attrs.data}, error: ${e}`); - done(e); - } - } -} diff --git a/server/src/loaders/jobs.ts b/server/src/loaders/jobs.ts index bae51a2d0..c5c5b543a 100644 --- a/server/src/loaders/jobs.ts +++ b/server/src/loaders/jobs.ts @@ -4,8 +4,8 @@ import WelcomeSMSJob from '@/jobs/WelcomeSMS'; import ResetPasswordMailJob from '@/jobs/ResetPasswordMail'; import ComputeItemCost from '@/jobs/ComputeItemCost'; import RewriteInvoicesJournalEntries from '@/jobs/writeInvoicesJEntries'; -import SendVoucherViaPhoneJob from '@/jobs/SendVoucherPhone'; -import SendVoucherViaEmailJob from '@/jobs/SendVoucherEmail'; +import SendLicenseViaPhoneJob from '@/jobs/SendLicensePhone'; +import SendLicenseViaEmailJob from '@/jobs/SendLicenseEmail'; import SendSMSNotificationSubscribeEnd from '@/jobs/SMSNotificationSubscribeEnd'; import SendSMSNotificationTrialEnd from '@/jobs/SMSNotificationTrialEnd'; import SendMailNotificationSubscribeEnd from '@/jobs/MailNotificationSubscribeEnd'; @@ -34,14 +34,14 @@ export default ({ agenda }: { agenda: Agenda }) => { new RewriteInvoicesJournalEntries(agenda).handler, ); agenda.define( - 'send-voucher-via-phone', + 'send-license-via-phone', { priority: 'high', concurrency: 1, }, - new SendVoucherViaPhoneJob().handler, + new SendLicenseViaPhoneJob().handler, ); agenda.define( - 'send-voucher-via-email', + 'send-license-via-email', { priority: 'high', concurrency: 1, }, - new SendVoucherViaEmailJob().handler, + new SendLicenseViaEmailJob().handler, ); agenda.define( 'send-sms-notification-subscribe-end', diff --git a/server/src/services/Payment/License.ts b/server/src/services/Payment/License.ts new file mode 100644 index 000000000..253e19223 --- /dev/null +++ b/server/src/services/Payment/License.ts @@ -0,0 +1,104 @@ +import { Service, Container, Inject } from 'typedi'; +import cryptoRandomString from 'crypto-random-string'; +import { times } from 'lodash'; +import { License } from "@/system/models"; +import { ILicense } from '@/interfaces'; +import LicenseMailMessages from '@/services/Payment/LicenseMailMessages'; +import LicenseSMSMessages from '@/services/Payment/LicenseSMSMessages'; + +@Service() +export default class LicenseService { + @Inject() + smsMessages: LicenseSMSMessages; + + @Inject() + mailMessages: LicenseMailMessages; + + /** + * Generates the license code in the given period. + * @param {number} licensePeriod + * @return {Promise} + */ + async generateLicense( + licensePeriod: number, + periodInterval: string = 'days', + planId: number, + ): ILicense { + let licenseCode: string; + let repeat: boolean = true; + + console.log(License); + + while(repeat) { + licenseCode = cryptoRandomString({ length: 10, type: 'numeric' }); + const foundLicenses = await License.query().where('license_code', licenseCode); + + if (foundLicenses.length === 0) { + repeat = false; + } + } + return License.query().insert({ + licenseCode, licensePeriod, periodInterval, planId, + }); + } + + + /** + * + * @param {number} loop + * @param {number} licensePeriod + * @param {string} periodInterval + * @param {number} planId + */ + async generateLicenses( + loop = 1, + licensePeriod: numner, + periodInterval: string = 'days', + planId: number, + ) { + const asyncOpers: Promise[] = []; + + times(loop, () => { + const generateOper = this.generateLicense(licensePeriod, periodInterval, planId); + asyncOpers.push(generateOper); + }); + return Promise.all(asyncOpers); + } + + /** + * Disables the given license id on the storage. + * @param {number} licenseId + * @return {Promise} + */ + async disableLicense(licenseId: number) { + return License.markLicenseAsDisabled(licenseId, 'id'); + } + + /** + * Deletes the given license id from the storage. + * @param licenseId + */ + async deleteLicense(licenseId: number) { + return License.query().where('id', licenseId).delete(); + } + + /** + * Sends license code to the given customer via SMS or mail message. + * @param {string} licenseCode - License code + * @param {string} phoneNumber - Phone number + * @param {string} email - Email address. + */ + async sendLicenseToCustomer(licenseCode: string, phoneNumber: string, email: string) { + const agenda = Container.get('agenda'); + + // Mark the license as used. + await License.markLicenseAsSent(licenseCode); + + if (email) { + await agenda.schedule('1 second', 'send-license-via-email', { licenseCode, email }); + } + if (phoneNumber) { + await agenda.schedule('1 second', 'send-license-via-phone', { licenseCode, phoneNumber }); + } + } +} \ No newline at end of file diff --git a/server/src/services/Payment/VoucherMailMessages.ts b/server/src/services/Payment/LicenseMailMessages.ts similarity index 68% rename from server/src/services/Payment/VoucherMailMessages.ts rename to server/src/services/Payment/LicenseMailMessages.ts index cd22d8e6b..a6e56e54f 100644 --- a/server/src/services/Payment/VoucherMailMessages.ts +++ b/server/src/services/Payment/LicenseMailMessages.ts @@ -5,22 +5,22 @@ import { Container } from 'typedi'; export default class SubscriptionMailMessages { /** - * Send voucher code to the given mail address. - * @param {string} voucherCode + * Send license code to the given mail address. + * @param {string} licenseCode * @param {email} email */ - public async sendMailVoucher(voucherCode: string, email: string) { + public async sendMailLicense(licenseCode: string, email: string) { const Logger = Container.get('logger'); const Mail = Container.get('mail'); - const filePath = path.join(global.rootPath, 'views/mail/VoucherReceive.html'); + const filePath = path.join(global.rootPath, 'views/mail/LicenseReceive.html'); const template = fs.readFileSync(filePath, 'utf8'); - const rendered = Mustache.render(template, { voucherCode }); + const rendered = Mustache.render(template, { licenseCode }); const mailOptions = { to: email, from: `${process.env.MAIL_FROM_NAME} ${process.env.MAIL_FROM_ADDRESS}`, - subject: 'Bigcapital Voucher', + subject: 'Bigcapital License', html: rendered, }; return new Promise((resolve, reject) => { diff --git a/server/src/services/Payment/LicensePaymentMethod.ts b/server/src/services/Payment/LicensePaymentMethod.ts new file mode 100644 index 000000000..170540ea0 --- /dev/null +++ b/server/src/services/Payment/LicensePaymentMethod.ts @@ -0,0 +1,14 @@ +import { License } from "@/system/models"; +import PaymentMethod from '@/services/Payment/PaymentMethod'; +import { IPaymentMethod, ILicensePaymentModel } from '@/interfaces'; + +export default class VocuherPaymentMethod extends PaymentMethod implements IPaymentMethod { + /** + * Payment subscription of organization via license code. + * @param {ILicensePaymentModel} + */ + async payment(licensePaymentModel: ILicensePaymentModel) { + // Mark the license code as used. + return License.markLicenseAsUsed(licensePaymentModel.licenseCode); + } +} \ No newline at end of file diff --git a/server/src/services/Payment/VoucherSMSMessages.ts b/server/src/services/Payment/LicenseSMSMessages.ts similarity index 56% rename from server/src/services/Payment/VoucherSMSMessages.ts rename to server/src/services/Payment/LicenseSMSMessages.ts index d35bf2250..207e6a9a8 100644 --- a/server/src/services/Payment/VoucherSMSMessages.ts +++ b/server/src/services/Payment/LicenseSMSMessages.ts @@ -6,12 +6,12 @@ export default class SubscriptionSMSMessages { smsClient: SMSClient; /** - * Sends voucher code to the given phone number via SMS message. + * Sends license code to the given phone number via SMS message. * @param {string} phoneNumber - * @param {string} voucherCode + * @param {string} licenseCode */ - public async sendVoucherSMSMessage(phoneNumber: string, voucherCode: string) { - const message: string = `Your voucher card number: ${voucherCode}.`; + public async sendLicenseSMSMessage(phoneNumber: string, licenseCode: string) { + const message: string = `Your license card number: ${licenseCode}.`; return this.smsClient.sendMessage(phoneNumber, message); } } \ No newline at end of file diff --git a/server/src/services/Payment/Voucher.ts b/server/src/services/Payment/Voucher.ts deleted file mode 100644 index a87597974..000000000 --- a/server/src/services/Payment/Voucher.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { Service, Container, Inject } from 'typedi'; -import cryptoRandomString from 'crypto-random-string'; -import { times } from 'lodash'; -import { Voucher } from "@/system/models"; -import { IVoucher } from '@/interfaces'; -import VoucherMailMessages from '@/services/Payment/VoucherMailMessages'; -import VoucherSMSMessages from '@/services/Payment/VoucherSMSMessages'; - -@Service() -export default class VoucherService { - @Inject() - smsMessages: VoucherSMSMessages; - - @Inject() - mailMessages: VoucherMailMessages; - - /** - * Generates the voucher code in the given period. - * @param {number} voucherPeriod - * @return {Promise} - */ - async generateVoucher( - voucherPeriod: number, - periodInterval: string = 'days', - planId: number, - ): IVoucher { - let voucherCode: string; - let repeat: boolean = true; - - console.log(Voucher); - - while(repeat) { - voucherCode = cryptoRandomString({ length: 10, type: 'numeric' }); - const foundVouchers = await Voucher.query().where('voucher_code', voucherCode); - - if (foundVouchers.length === 0) { - repeat = false; - } - } - return Voucher.query().insert({ - voucherCode, voucherPeriod, periodInterval, planId, - }); - } - - - /** - * - * @param {number} loop - * @param {number} voucherPeriod - * @param {string} periodInterval - * @param {number} planId - */ - async generateVouchers( - loop = 1, - voucherPeriod: numner, - periodInterval: string = 'days', - planId: number, - ) { - const asyncOpers: Promise[] = []; - - times(loop, () => { - const generateOper = this.generateVoucher(voucherPeriod, periodInterval, planId); - asyncOpers.push(generateOper); - }); - return Promise.all(asyncOpers); - } - - /** - * Disables the given voucher id on the storage. - * @param {number} voucherId - * @return {Promise} - */ - async disableVoucher(voucherId: number) { - return Voucher.markVoucherAsDisabled(voucherId, 'id'); - } - - /** - * Deletes the given voucher id from the storage. - * @param voucherId - */ - async deleteVoucher(voucherId: number) { - return Voucher.query().where('id', voucherId).delete(); - } - - /** - * Sends voucher code to the given customer via SMS or mail message. - * @param {string} voucherCode - Voucher code - * @param {string} phoneNumber - Phone number - * @param {string} email - Email address. - */ - async sendVoucherToCustomer(voucherCode: string, phoneNumber: string, email: string) { - const agenda = Container.get('agenda'); - - // Mark the voucher as used. - await Voucher.markVoucherAsSent(voucherCode); - - if (email) { - await agenda.schedule('1 second', 'send-voucher-via-email', { voucherCode, email }); - } - if (phoneNumber) { - await agenda.schedule('1 second', 'send-voucher-via-phone', { voucherCode, phoneNumber }); - } - } -} \ No newline at end of file diff --git a/server/src/services/Payment/VoucherPaymentMethod.ts b/server/src/services/Payment/VoucherPaymentMethod.ts deleted file mode 100644 index 15e878c99..000000000 --- a/server/src/services/Payment/VoucherPaymentMethod.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Voucher } from "@/system/models"; -import PaymentMethod from '@/services/Payment/PaymentMethod'; -import { IPaymentMethod, IVoucherPaymentModel } from '@/interfaces'; - -export default class VocuherPaymentMethod extends PaymentMethod implements IPaymentMethod { - /** - * Payment subscription of organization via voucher code. - * @param {IVoucherPaymentModel} - */ - async payment(voucherPaymentModel: IVoucherPaymentModel) { - // Mark the voucher code as used. - return Voucher.markVoucherAsUsed(voucherPaymentModel.voucherCode); - } -} \ No newline at end of file diff --git a/server/src/services/Subscription/SubscriptionService.ts b/server/src/services/Subscription/SubscriptionService.ts index 5a850ec8b..7b6b0a282 100644 --- a/server/src/services/Subscription/SubscriptionService.ts +++ b/server/src/services/Subscription/SubscriptionService.ts @@ -1,7 +1,7 @@ import { Service, Inject } from 'typedi'; -import { Plan, Tenant, Voucher } from '@/system/models'; +import { Plan, Tenant, License } from '@/system/models'; import Subscription from '@/services/Subscription/Subscription'; -import VocuherPaymentMethod from '@/services/Payment/VoucherPaymentMethod'; +import VocuherPaymentMethod from '@/services/Payment/LicensePaymentMethod'; import PaymentContext from '@/services/Payment'; import SubscriptionSMSMessages from '@/services/Subscription/SMSMessages'; import SubscriptionMailMessages from '@/services/Subscription/MailMessages'; @@ -15,30 +15,30 @@ export default class SubscriptionService { mailMessages: SubscriptionMailMessages; /** - * Handles the payment process via voucher code and than subscribe to + * Handles the payment process via license code and than subscribe to * the given tenant. * * @param {number} tenantId * @param {String} planSlug - * @param {string} voucherCode + * @param {string} licenseCode * * @return {Promise} */ - async subscriptionViaVoucher( + async subscriptionViaLicense( tenantId: number, planSlug: string, - voucherCode: string, + licenseCode: string, subscriptionSlug: string = 'main', ) { const plan = await Plan.query().findOne('slug', planSlug); const tenant = await Tenant.query().findById(tenantId); - const voucherModel = await Voucher.query().findOne('voucher_code', voucherCode); + const licenseModel = await License.query().findOne('license_code', licenseCode); - const paymentViaVoucher = new VocuherPaymentMethod(); - const paymentContext = new PaymentContext(paymentViaVoucher); + const paymentViaLicense = new VocuherPaymentMethod(); + const paymentContext = new PaymentContext(paymentViaLicense); const subscription = new Subscription(paymentContext); - return subscription.subscribe(tenant, plan, voucherModel, subscriptionSlug); + return subscription.subscribe(tenant, plan, licenseModel, subscriptionSlug); } } \ No newline at end of file diff --git a/server/src/system/migrations/20200527101812_create_subscriptions_licenses_table.js b/server/src/system/migrations/20200527101812_create_subscriptions_licenses_table.js deleted file mode 100644 index 3bad5f9a1..000000000 --- a/server/src/system/migrations/20200527101812_create_subscriptions_licenses_table.js +++ /dev/null @@ -1,14 +0,0 @@ - -exports.up = function(knex) { - return knex.schema.createTable('subscription_licenses', table => { - table.increments(); - table.string('key'); - table.integer('license_period'); - table.string('license_interval'); - table.boolean('used').defaultTo(false); - }); -}; - -exports.down = function(knex) { - return knex.schema.dropTableIfExists('subscription_licenses'); -}; diff --git a/server/src/system/migrations/20200823235339_create_subscription_vouchers_table.js b/server/src/system/migrations/20200823235339_create_subscription_licenses_table.js similarity index 67% rename from server/src/system/migrations/20200823235339_create_subscription_vouchers_table.js rename to server/src/system/migrations/20200823235339_create_subscription_licenses_table.js index 2c5f68afe..576abffca 100644 --- a/server/src/system/migrations/20200823235339_create_subscription_vouchers_table.js +++ b/server/src/system/migrations/20200823235339_create_subscription_licenses_table.js @@ -1,12 +1,12 @@ exports.up = function(knex) { - return knex.schema.createTable('subscription_vouchers', table => { + return knex.schema.createTable('subscription_licenses', table => { table.increments(); - table.string('voucher_code').unique(); + table.string('license_code').unique(); table.integer('plan_id').unsigned(); - table.integer('voucher_period').unsigned(); + table.integer('license_period').unsigned(); table.string('period_interval'); table.boolean('sent').defaultTo(false); @@ -22,5 +22,5 @@ exports.up = function(knex) { }; exports.down = function(knex) { - return knex.schema.dropTableIfExists('subscription_vouchers'); + return knex.schema.dropTableIfExists('subscription_licenses'); }; diff --git a/server/src/system/models/Subscriptions/Voucher.js b/server/src/system/models/Subscriptions/License.js similarity index 55% rename from server/src/system/models/Subscriptions/Voucher.js rename to server/src/system/models/Subscriptions/License.js index c0fa08173..d2492afe7 100644 --- a/server/src/system/models/Subscriptions/Voucher.js +++ b/server/src/system/models/Subscriptions/License.js @@ -1,14 +1,14 @@ import { Model, mixin } from 'objection'; import moment from 'moment'; import SystemModel from '@/system/models/SystemModel'; -import { IVouchersFilter } from '@/interfaces'; +import { ILicensesFilter } from '@/interfaces'; -export default class Voucher extends SystemModel { +export default class License extends SystemModel { /** * Table name. */ static get tableName() { - return 'subscription_vouchers'; + return 'subscription_licenses'; } /** @@ -23,34 +23,34 @@ export default class Voucher extends SystemModel { */ static get modifiers() { return { - // Filters active vouchers. - filterActiveVoucher(query) { + // Filters active licenses. + filterActiveLicense(query) { query.where('disabled', false); query.where('used', false); }, - // Find voucher by its code or id. + // Find license by its code or id. findByCodeOrId(query, id, code) { if (id) { query.where('id', id); } if (code) { - query.where('voucher_code', code); + query.where('license_code', code); } }, - // Filters vouchers list. - filter(builder, vouchersFilter) { - if (vouchersFilter.active) { - builder.modify('filterActiveVoucher') + // Filters licenses list. + filter(builder, licensesFilter) { + if (licensesFilter.active) { + builder.modify('filterActiveLicense') } - if (vouchersFilter.disabled) { + if (licensesFilter.disabled) { builder.where('disabled', true); } - if (vouchersFilter.used) { + if (licensesFilter.used) { builder.where('used', true); } - if (vouchersFilter.sent) { + if (licensesFilter.sent) { builder.where('sent', true); } } @@ -68,7 +68,7 @@ export default class Voucher extends SystemModel { relation: Model.BelongsToOneRelation, modelClass: Plan.default, join: { - from: 'subscription_vouchers.planId', + from: 'subscription_licenses.planId', to: 'subscriptions_plans.id', }, }, @@ -76,24 +76,24 @@ export default class Voucher extends SystemModel { } /** - * Deletes the given voucher code from the storage. - * @param {string} voucherCode + * Deletes the given license code from the storage. + * @param {string} licenseCode * @return {Promise} */ - static deleteVoucher(voucherCode, viaAttribute = 'voucher_code') { + static deleteLicense(licenseCode, viaAttribute = 'license_code') { return this.query() - .where(viaAttribute, voucherCode) + .where(viaAttribute, licenseCode) .delete(); } /** - * Marks the given voucher code as disabled on the storage. - * @param {string} voucherCode + * Marks the given license code as disabled on the storage. + * @param {string} licenseCode * @return {Promise} */ - static markVoucherAsDisabled(voucherCode, viaAttribute = 'voucher_code') { + static markLicenseAsDisabled(licenseCode, viaAttribute = 'license_code') { return this.query() - .where(viaAttribute, voucherCode) + .where(viaAttribute, licenseCode) .patch({ disabled: true, disabled_at: moment().toMySqlDateTime(), @@ -101,12 +101,12 @@ export default class Voucher extends SystemModel { } /** - * Marks the given voucher code as sent on the storage. - * @param {string} voucherCode + * Marks the given license code as sent on the storage. + * @param {string} licenseCode */ - static markVoucherAsSent(voucherCode, viaAttribute = 'voucher_code') { + static markLicenseAsSent(licenseCode, viaAttribute = 'license_code') { return this.query() - .where(viaAttribute, voucherCode) + .where(viaAttribute, licenseCode) .patch({ sent: true, sent_at: moment().toMySqlDateTime(), @@ -114,13 +114,13 @@ export default class Voucher extends SystemModel { } /** - * Marks the given voucher code as used on the storage. - * @param {string} voucherCode + * Marks the given license code as used on the storage. + * @param {string} licenseCode * @return {Promise} */ - static markVoucherAsUsed(voucherCode, viaAttribute = 'voucher_code') { + static markLicenseAsUsed(licenseCode, viaAttribute = 'license_code') { return this.query() - .where(viaAttribute, voucherCode) + .where(viaAttribute, licenseCode) .patch({ used: true, used_at: moment().toMySqlDateTime() @@ -134,7 +134,7 @@ export default class Voucher extends SystemModel { */ isEqualPlanPeriod(plan) { return (this.invoicePeriod === plan.invoiceInterval && - voucher.voucherPeriod === voucher.periodInterval); + license.licensePeriod === license.periodInterval); } } diff --git a/server/src/system/models/index.js b/server/src/system/models/index.js index f981035bf..2030ad3f3 100644 --- a/server/src/system/models/index.js +++ b/server/src/system/models/index.js @@ -2,7 +2,7 @@ import Plan from './Subscriptions/Plan'; import PlanFeature from './Subscriptions/PlanFeature'; import PlanSubscription from './Subscriptions/PlanSubscription'; -import Voucher from './Subscriptions/Voucher'; +import License from './Subscriptions/License'; import Tenant from './Tenant'; import SystemUser from './SystemUser'; import PasswordReset from './PasswordReset'; @@ -12,7 +12,7 @@ export { Plan, PlanFeature, PlanSubscription, - Voucher, + License, Tenant, SystemUser, PasswordReset, diff --git a/server/views/mail/VoucherReceive.html b/server/views/mail/LicenseReceive.html similarity index 99% rename from server/views/mail/VoucherReceive.html rename to server/views/mail/LicenseReceive.html index 0778505d5..9ef71c781 100644 --- a/server/views/mail/VoucherReceive.html +++ b/server/views/mail/LicenseReceive.html @@ -372,9 +372,9 @@

-

Voucher Code

+

License Code

-

Voucher {{ voucherCode }},

+

License {{ licenseCode }},

Click On The link blow to reset your password.