mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
add invoice service
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
enum SmsStatus {
|
||||
Success = 'Success',
|
||||
Error = 'Error',
|
||||
LowBalance = 'Low Balance',
|
||||
LowBalance = 'Low Balance',
|
||||
}
|
||||
|
||||
export default SmsStatus;
|
||||
|
||||
@@ -497,6 +497,35 @@ export class BillingService {
|
||||
});
|
||||
}
|
||||
|
||||
public static async genrateInvoiceAndChargeCustomer(
|
||||
customerId: string,
|
||||
itemText: string,
|
||||
amountInUsd: number
|
||||
): Promise<void> {
|
||||
const invoice: Stripe.Invoice = await this.stripe.invoices.create({
|
||||
customer: customerId,
|
||||
auto_advance: true, // do not automatically charge.
|
||||
collection_method: 'charge_automatically',
|
||||
});
|
||||
|
||||
if (!invoice || !invoice.id) {
|
||||
throw new APIException('Invoice not generated.');
|
||||
}
|
||||
|
||||
await this.stripe.invoiceItems.create({
|
||||
invoice: invoice.id,
|
||||
amount: amountInUsd * 100,
|
||||
quantity: 1,
|
||||
description: itemText,
|
||||
currency: 'usd',
|
||||
customer: customerId,
|
||||
});
|
||||
|
||||
await this.stripe.invoices.finalizeInvoice(invoice.id!);
|
||||
|
||||
await this.stripe.invoices.pay(invoice.id);
|
||||
}
|
||||
|
||||
public static async payInvoice(
|
||||
customerId: string,
|
||||
invoiceId: string
|
||||
|
||||
@@ -12,12 +12,13 @@ import ObjectID from 'Common/Types/ObjectID';
|
||||
|
||||
export default class SmsService {
|
||||
public static async sendSms(
|
||||
to: Phone, message: string, options: {
|
||||
projectId?: ObjectID | undefined // project id for sms log
|
||||
from?: Phone, // from phone number
|
||||
to: Phone,
|
||||
message: string,
|
||||
options: {
|
||||
projectId?: ObjectID | undefined; // project id for sms log
|
||||
from?: Phone; // from phone number
|
||||
}
|
||||
): Promise<HTTPResponse<EmptyResponseData>> {
|
||||
|
||||
const body: JSONObject = {
|
||||
to: to.toString(),
|
||||
message,
|
||||
|
||||
@@ -35,8 +35,6 @@ const Detail: Function = (props: ComponentProps): ReactElement => {
|
||||
return <MarkdownViewer text={text} />;
|
||||
};
|
||||
|
||||
|
||||
|
||||
const getDropdownViewer: Function = (
|
||||
data: string,
|
||||
options: Array<DropdownOption>,
|
||||
@@ -76,7 +74,7 @@ const Detail: Function = (props: ComponentProps): ReactElement => {
|
||||
};
|
||||
|
||||
const getUSDCentsField: Function = (usdCents: number): ReactElement => {
|
||||
return <div>{usdCents/100} USD</div>;
|
||||
return <div>{usdCents / 100} USD</div>;
|
||||
};
|
||||
|
||||
const getField: Function = (field: Field, index: number): ReactElement => {
|
||||
@@ -288,5 +286,3 @@ const Detail: Function = (props: ComponentProps): ReactElement => {
|
||||
};
|
||||
|
||||
export default Detail;
|
||||
|
||||
|
||||
|
||||
@@ -18,10 +18,14 @@ router.post(
|
||||
async (req: ExpressRequest, res: ExpressResponse) => {
|
||||
const body: JSONObject = JSONFunctions.deserialize(req.body);
|
||||
|
||||
await SmsService.sendSms(body['to'] as Phone, body['message'] as string, {
|
||||
projectId: body['projectId'] as ObjectID,
|
||||
from: body['from'] as Phone,
|
||||
});
|
||||
await SmsService.sendSms(
|
||||
body['to'] as Phone,
|
||||
body['message'] as string,
|
||||
{
|
||||
projectId: body['projectId'] as ObjectID,
|
||||
from: body['from'] as Phone,
|
||||
}
|
||||
);
|
||||
|
||||
return Response.sendEmptyResponse(req, res);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,12 @@ export const InternalSmtpFromName: string =
|
||||
|
||||
export const TwilioAccountSid: string = process.env['TWILIO_ACCOUNT_SID'] || '';
|
||||
export const TwilioAuthToken: string = process.env['TWILIO_AUTH_TOKEN'] || '';
|
||||
export const TwilioPhoneNumber: string = process.env['TWILIO_PHONE_NUMBER'] || '';
|
||||
export const SMSDefaultCostInCents: number = process.env['SMS_DEFAULT_COST_IN_CENTS'] ? parseInt(process.env['SMS_DEFAULT_COST_IN_CENTS']) : 0;
|
||||
export const TwilioPhoneNumber: string =
|
||||
process.env['TWILIO_PHONE_NUMBER'] || '';
|
||||
export const SMSDefaultCostInCents: number = process.env[
|
||||
'SMS_DEFAULT_COST_IN_CENTS'
|
||||
]
|
||||
? parseInt(process.env['SMS_DEFAULT_COST_IN_CENTS'])
|
||||
: 0;
|
||||
|
||||
export const SendGridApiKey: string = process.env['SENDGRID_API_KEY'] || '';
|
||||
|
||||
@@ -10,6 +10,8 @@ import SmsLogService from "CommonServer/Services/SmsLogService"
|
||||
import ProjectService from "CommonServer/Services/ProjectService";
|
||||
import Project from "Model/Models/Project";
|
||||
import { MessageInstance } from "twilio/lib/rest/api/v2010/account/message";
|
||||
import BillingService from "CommonServer/Services/BillingService";
|
||||
import logger from "CommonServer/Utils/Logger";
|
||||
|
||||
export default class SmsService {
|
||||
public static async sendSms(to: Phone, message: string, options: {
|
||||
@@ -48,12 +50,16 @@ export default class SmsService {
|
||||
// make sure project has enough balance.
|
||||
|
||||
if (options.projectId && IsBillingEnabled) {
|
||||
|
||||
project = await ProjectService.findOneById({
|
||||
id: options.projectId,
|
||||
select: {
|
||||
smsOrCallCurrentBalanceInUSDCents: true,
|
||||
enableAutoRechargeSmsOrCallBalance: true,
|
||||
enableSmsNotifications: true
|
||||
enableSmsNotifications: true,
|
||||
autoRechargeSmsOrCallByBalanceInUSD: true,
|
||||
autoRechargeSmsOrCallWhenCurrentBalanceFallsInUSD: true,
|
||||
paymentProviderCustomerId: true
|
||||
},
|
||||
props: {
|
||||
isRoot: true
|
||||
@@ -63,7 +69,7 @@ export default class SmsService {
|
||||
if (!project) {
|
||||
smsLog.status = SmsStatus.Error;
|
||||
smsLog.statusMessage = `Project ${options.projectId.toString()} not found.`;
|
||||
await SmsLogService.create({
|
||||
await SmsLogService.create({
|
||||
data: smsLog,
|
||||
props: {
|
||||
isRoot: true
|
||||
@@ -73,7 +79,7 @@ export default class SmsService {
|
||||
|
||||
}
|
||||
|
||||
if(!project.enableSmsNotifications){
|
||||
if (!project.enableSmsNotifications) {
|
||||
smsLog.status = SmsStatus.Error;
|
||||
smsLog.statusMessage = `SMS notifications are not enabled for this project. Please enable SMS notifications in project settings.`;
|
||||
await SmsLogService.create({
|
||||
@@ -85,6 +91,39 @@ export default class SmsService {
|
||||
return;
|
||||
}
|
||||
|
||||
// check if auto recharge is enabled and current balance is low.
|
||||
|
||||
if (IsBillingEnabled && project && project.enableAutoRechargeSmsOrCallBalance && project.autoRechargeSmsOrCallByBalanceInUSD && project.autoRechargeSmsOrCallWhenCurrentBalanceFallsInUSD) {
|
||||
|
||||
if (project.smsOrCallCurrentBalanceInUSDCents && project.smsOrCallCurrentBalanceInUSDCents < project.autoRechargeSmsOrCallWhenCurrentBalanceFallsInUSD) {
|
||||
try {
|
||||
// recharge balance
|
||||
const updatedAmount: number = Math.floor(project.smsOrCallCurrentBalanceInUSDCents + (project.autoRechargeSmsOrCallByBalanceInUSD * 100));
|
||||
|
||||
// If the recharge is succcessful, then update the project balance.
|
||||
await BillingService.genrateInvoiceAndChargeCustomer(project.paymentProviderCustomerId!, "SMS or Call Balance Recharge", project.autoRechargeSmsOrCallByBalanceInUSD);
|
||||
|
||||
await ProjectService.updateOneById({
|
||||
data: {
|
||||
smsOrCallCurrentBalanceInUSDCents: updatedAmount
|
||||
},
|
||||
id: project.id!,
|
||||
props: {
|
||||
isRoot: true
|
||||
}
|
||||
});
|
||||
|
||||
project.smsOrCallCurrentBalanceInUSDCents = updatedAmount;
|
||||
|
||||
// TODO: Send an email on successful recharge.
|
||||
} catch (err) {
|
||||
// TODO: if the recharge fails, then send email to the user.
|
||||
logger.error(err);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (!project.smsOrCallCurrentBalanceInUSDCents) {
|
||||
smsLog.status = SmsStatus.LowBalance;
|
||||
smsLog.statusMessage = `Project ${options.projectId.toString()} does not have enough SMS balance.`;
|
||||
@@ -96,7 +135,7 @@ export default class SmsService {
|
||||
});
|
||||
return;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (project.smsOrCallCurrentBalanceInUSDCents < SMSDefaultCostInCents) {
|
||||
@@ -109,7 +148,6 @@ export default class SmsService {
|
||||
}
|
||||
});
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -153,6 +191,9 @@ export default class SmsService {
|
||||
isRoot: true
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user