mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-18 13:50:31 +00:00
feat: Payment system with voucher cards.
feat: Design with inversion dependency injection architecture. feat: Prettier http middleware. feat: Re-write items categories with preferred accounts.
This commit is contained in:
6
server/src/services/Payment/PaymentMethod.ts
Normal file
6
server/src/services/Payment/PaymentMethod.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import moment from 'moment';
|
||||
import { IPaymentModel } from '@/interfaces';
|
||||
|
||||
export default class PaymentMethod implements IPaymentModel {
|
||||
|
||||
}
|
||||
78
server/src/services/Payment/Voucher.ts
Normal file
78
server/src/services/Payment/Voucher.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { Service, Container, Inject } from 'typedi';
|
||||
import cryptoRandomString from 'crypto-random-string';
|
||||
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<IVoucher>}
|
||||
*/
|
||||
async generateVoucher(
|
||||
voucherPeriod: number,
|
||||
periodInterval: string = 'days',
|
||||
planId: number,
|
||||
): IVoucher {
|
||||
let voucherCode: string;
|
||||
let repeat: boolean = true;
|
||||
|
||||
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,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
36
server/src/services/Payment/VoucherMailMessages.ts
Normal file
36
server/src/services/Payment/VoucherMailMessages.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import Mustache from 'mustache';
|
||||
import { Container } from 'typedi';
|
||||
import mail from '@/services/mail';
|
||||
|
||||
export default class SubscriptionMailMessages {
|
||||
/**
|
||||
* Send voucher code to the given mail address.
|
||||
* @param {string} voucherCode
|
||||
* @param {email} email
|
||||
*/
|
||||
public async sendMailVoucher(voucherCode: string, email: string) {
|
||||
const logger = Container.get('logger');
|
||||
|
||||
const filePath = path.join(global.rootPath, 'views/mail/VoucherReceive.html');
|
||||
const template = fs.readFileSync(filePath, 'utf8');
|
||||
const rendered = Mustache.render(template, { voucherCode });
|
||||
|
||||
const mailOptions = {
|
||||
to: email,
|
||||
from: `${process.env.MAIL_FROM_NAME} ${process.env.MAIL_FROM_ADDRESS}`,
|
||||
subject: 'Bigcapital Voucher',
|
||||
html: rendered,
|
||||
};
|
||||
return new Promise((resolve, reject) => {
|
||||
mail.sendMail(mailOptions, (error) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
14
server/src/services/Payment/VoucherPaymentMethod.ts
Normal file
14
server/src/services/Payment/VoucherPaymentMethod.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
17
server/src/services/Payment/VoucherSMSMessages.ts
Normal file
17
server/src/services/Payment/VoucherSMSMessages.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Container, Inject } from 'typedi';
|
||||
import SMSClient from '@/services/SMSClient';
|
||||
|
||||
export default class SubscriptionSMSMessages {
|
||||
@Inject('SMSClient')
|
||||
smsClient: SMSClient;
|
||||
|
||||
/**
|
||||
* Sends voucher code to the given phone number via SMS message.
|
||||
* @param {string} phoneNumber
|
||||
* @param {string} voucherCode
|
||||
*/
|
||||
public async sendVoucherSMSMessage(phoneNumber: string, voucherCode: string) {
|
||||
const message: string = `Your voucher card number: ${voucherCode}.`;
|
||||
return this.smsClient.sendMessage(phoneNumber, message);
|
||||
}
|
||||
}
|
||||
21
server/src/services/Payment/index.ts
Normal file
21
server/src/services/Payment/index.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { IPaymentMethod, IPaymentContext } from "@/interfaces";
|
||||
|
||||
export default class PaymentContext<PaymentModel> implements IPaymentContext{
|
||||
paymentMethod: IPaymentMethod;
|
||||
|
||||
/**
|
||||
* Constructor method.
|
||||
* @param {IPaymentMethod} paymentMethod
|
||||
*/
|
||||
constructor(paymentMethod: IPaymentMethod) {
|
||||
this.paymentMethod = paymentMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {<PaymentModel>} paymentModel
|
||||
*/
|
||||
makePayment(paymentModel: PaymentModel) {
|
||||
this.paymentMethod.makePayment(paymentModel);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user