Skip to content
This repository has been archived by the owner on May 6, 2022. It is now read-only.

Commit

Permalink
Merge pull request #70 from Tolfix/dev
Browse files Browse the repository at this point in the history
v1.9
  • Loading branch information
Tolfx authored Jan 22, 2022
2 parents 5449968 + cc6c02b commit 482cd22
Show file tree
Hide file tree
Showing 32 changed files with 1,660 additions and 142 deletions.
13 changes: 0 additions & 13 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -46,19 +46,6 @@ ENV STRIPE_SK_LIVE ""
ENV STRIPE_SK_PUBLIC ""
ENV STRIPE_WEBHOOK_SECRET ""

ENV COMPANY_NAME ""
ENV COMPANY_ADDRESS ""
ENV COMPANY_ZIP ""
ENV COMPANY_CITY ""
ENV COMPANY_COUNTRY ""
ENV COMPANY_PHONE ""
ENV COMPANY_EMAIL ""
ENV COMPANY_VAT ""
ENV COMPANY_CURRENCY "sek"
ENV COMPANY_LOGO_URL ""
ENV COMPANY_TAX_REGISTERED "false"
ENV COMPANY_WEBSITE ""

ENV PDF_TEMPLATE_URL ""

ENV PLUGINS "[]"
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cpg-api",
"version": "v1.8",
"version": "v1.9",
"description": "Central Payment Gateway",
"main": "./build/Main.js",
"dependencies": {
Expand Down
20 changes: 10 additions & 10 deletions src/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,61 +53,61 @@ export const Company_Address = async (): Promise<IConfigs["company"]["address"]>
if(!configs) throw new Error("No configs found");
return configs.company?.address ?? process.env.COMPANY_ADDRESS ?? "";
}
export const Company_Zip = async () =>
export const Company_Zip = async (): Promise<IConfigs["company"]["zip"]> =>
{
const configs = await ConfigModel.findOne();
if(!configs) throw new Error("No configs found");
return configs.company?.zip ?? process.env.COMPANY_ZIP ?? "";
}
export const Company_City = async () =>
export const Company_City = async (): Promise<IConfigs["company"]["city"]> =>
{
const configs = await ConfigModel.findOne();
if(!configs) throw new Error("No configs found");
return configs.company?.city ?? process.env.COMPANY_CITY ?? "";
}
export const Company_Country = async () =>
export const Company_Country = async (): Promise<IConfigs["company"]["country"]> =>
{
const configs = await ConfigModel.findOne();
if(!configs) throw new Error("No configs found");
return configs.company?.country ?? process.env.COMPANY_COUNTRY ?? "";
}
export const Company_Phone = async () =>
export const Company_Phone = async (): Promise<IConfigs["company"]["phone"]> =>
{
const configs = await ConfigModel.findOne();
if(!configs) throw new Error("No configs found");
return configs.company?.phone ?? process.env.COMPANY_PHONE ?? "";
}
export const Company_Email = async () =>
export const Company_Email = async (): Promise<IConfigs["company"]["email"]> =>
{
const configs = await ConfigModel.findOne();
if(!configs) throw new Error("No configs found");
return configs.company?.email ?? process.env.COMPANY_EMAIL ?? "";
}
export const Company_Vat = async () =>
export const Company_Vat = async (): Promise<IConfigs["company"]["vat"]> =>
{
const configs = await ConfigModel.findOne();
if(!configs) throw new Error("No configs found");
return configs.company?.vat ?? process.env.COMPANY_VAT ?? "";
}
export const Company_Currency = async () =>
export const Company_Currency = async (): Promise<IConfigs["company"]["currency"]> =>
{
const configs = await ConfigModel.findOne();
if(!configs) throw new Error("No configs found");
return configs.company?.currency ?? process.env.COMPANY_CURRENCY ?? "";
}
export const Company_Tax_Registered = async () =>
export const Company_Tax_Registered = async (): Promise<IConfigs["company"]["tax_registered"]> =>
{
const configs = await ConfigModel.findOne();
if(!configs) throw new Error("No configs found");
return configs.company?.tax_registered ?? (process.env.COMPANY_TAX_REGISTERED === "true" ? true : false);
}
export const Company_Logo_Url = async () =>
export const Company_Logo_Url = async (): Promise<IConfigs["company"]["logo_url"]> =>
{
const configs = await ConfigModel.findOne();
if(!configs) throw new Error("No configs found");
return configs.company?.logo_url ?? process.env.COMPANY_LOGO_URL ?? "";
}
export const Company_Website = async () =>
export const Company_Website = async (): Promise<IConfigs["company"]["website"]> =>
{
const configs = await ConfigModel.findOne();
if(!configs) throw new Error("No configs found");
Expand Down
65 changes: 63 additions & 2 deletions src/Cron/Invoices.cron.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Default_Language, d_Days } from "../Config";
import { sendInvoiceEmail, sendLateInvoiceEmail } from "../Lib/Invoices/SendEmail";
import { InvoiceNotifiedReport } from "../Email/Reports/InvoiceReport";
import GetText from "../Translation/GetText";
import { ChargeCustomer } from "../Payments/Stripe";

export = function Cron_Invoices()
{
Expand Down Expand Up @@ -34,13 +35,21 @@ export = function Cron_Invoices()
return dates;
};

const getDatesAhead = (n: number) =>
{
const dates = [];
for (let i = 0; i < n; i++)
dates.push(dateFormat.format(dateFormat.addDays(new Date(), -i-1), "YYYY-MM-DD"))
return dates;
}

InvoiceModel.find({
"dates.due_date": {
$in: [...(getDates30DaysAhead())]
},
notified: false,
status: {
$not: /fraud|cancelled/g
$not: /fraud|cancelled|draft|refunded/g
}
}).then(async (invoices) =>
{
Expand All @@ -63,13 +72,65 @@ export = function Cron_Invoices()
InvoiceNotifiedReport(invoices);
});

// Trigger if a invoice has stripe_setup_intent enabled and is due in the next 2 weeks.
InvoiceModel.find({
"dates.due_date": {
$in: [...(getDatesAhead(14))]
},
status: {
$not: /fraud|cancelled|draft|refunded/g
},
paid: false,
extra: {
stripe_setup_intent: {
$exists: true
}
}
}).then(async (invoices) =>
{
Logger.info(`Found ${invoices.length} invoices to charge.`);
for await(const invoice of invoices)
{
// Get customer
const Customer = await CustomerModel.findOne({ id: invoice.customer_uid});
if(!Customer)
continue;

Logger.info(`Charging ${Customer.personal.email}`);

// Check if credit card
if(invoice.payment_method !== "credit_card")
continue;

// Check if customer got setup_intent enabled
if(!(Customer?.extra?.stripe_setup_intent))
continue;

// Assuming they have a card
// Try to create a payment intent and pay
try
{
await ChargeCustomer(invoice.id);
// assuming it worked, we can mark it as paid
invoice.status = "collections";
invoice.paid = true;
invoice.notified = true;
await invoice.save();
}
catch(e)
{
Logger.error(`Failed to charge customer ${Customer.id}`);
}
}
});

InvoiceModel.find({
"dates.due_date": {
$in: [...(getDates30DaysAgo())]
},
paid: false,
status: {
$not: /fraud|cancelled/g
$not: /fraud|cancelled|draft|refunded/g
}
}).then(async (invoices) =>
{
Expand Down
30 changes: 30 additions & 0 deletions src/Database/GraphQL/Schemas/Subscription.schemas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { resolverAdminAccess } from "../ResolverAccess";
import { composeWithMongoose } from "graphql-compose-mongoose";
import SubscriptionModel from "../../Models/Subscriptions.model";

export const SubscriptionGraphQL = composeWithMongoose(SubscriptionModel);
export const startsWith = "Subscription";
export const SubscriptionQuery = {
...resolverAdminAccess({
subscriptionById: SubscriptionGraphQL.getResolver("findById"),
subscriptionByIds: SubscriptionGraphQL.getResolver("findByIds"),
subscriptionOne: SubscriptionGraphQL.getResolver("findOne"),
subscriptionMany: SubscriptionGraphQL.getResolver("findMany"),
subscriptionCount: SubscriptionGraphQL.getResolver("count"),
subscriptionConnection: SubscriptionGraphQL.getResolver("connection"),
subscriptionPagination: SubscriptionGraphQL.getResolver("pagination"),
})
}

export const SubscriptionMutation = {
...resolverAdminAccess({
subscriptionCreateOne: SubscriptionGraphQL.getResolver("createOne"),
subscriptionCreateMany: SubscriptionGraphQL.getResolver("createMany"),
subscriptionUpdateById: SubscriptionGraphQL.getResolver("updateById"),
subscriptionUpdateOne: SubscriptionGraphQL.getResolver("updateOne"),
subscriptionUpdateMany: SubscriptionGraphQL.getResolver("updateMany"),
subscriptionRemoveById: SubscriptionGraphQL.getResolver("removeById"),
subscriptionRemoveOne: SubscriptionGraphQL.getResolver("removeOne"),
subscriptionRemoveMany: SubscriptionGraphQL.getResolver("removeMany"),
})
};
1 change: 1 addition & 0 deletions src/Database/Models/Customers/Customer.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ const CustomerSchema = new Schema
extra: {
type: Object,
required: false,
default: {},
}

}
Expand Down
2 changes: 1 addition & 1 deletion src/Database/Models/Orders.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const OrderSchema = new Schema
type: [
{
product_id: Number,
configurable_options_ids: {
configurable_options: {
type: [
{
id: Number,
Expand Down
102 changes: 102 additions & 0 deletions src/Database/Models/Subscriptions.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import mongoose, { Document, model, Schema } from "mongoose";
import increment from "mongoose-auto-increment";
import { MongoDB_URI } from "../../Config";
import { A_InvoiceStatus } from "../../Interfaces/Invoice.interface";
import { IQuotes } from "../../Interfaces/Quotes.interface";
import { ISubscription } from "../../Interfaces/Subscriptions.interface";
import Logger from "../../Lib/Logger";
import GetText from "../../Translation/GetText";
import { A_CC_Payments, A_RecurringMethod } from "../../Types/PaymentMethod";

const SubscriptionSchema = new Schema
(
{

id: Number,

uid: {
type: String,
required: false,
description: GetText().txt_Uid_Description,
},

customer_uid: {
type: String,
required: true,
},

products: {
type: [
{
product_id: Number,
configurable_options_ids: {
type: [
{
id: Number,
option_index: Number,
},
],
required: false
},
quantity: Number,
}
],
required: true,
},

promotion_codes: {
type: [Number],
default: []
},

renewing_method: {
type: String,
enum: [...A_RecurringMethod],
required: true,
},

payment_method: {
type: String,
enum: ["credit_card", "paypal"],
default: "credit_card",
},

status: {
type: String,
enum: [...A_InvoiceStatus],
default: "active",
},

start_date: {
type: String,
required: true,
},

transactions: {
type: [Number],
default: [],
}

}
);

// Log when creation
SubscriptionSchema.post('save', function(doc: IQuotes & Document)
{
Logger.db(GetText().database.txt_Model_Created(doc.modelName, doc.uid));
// Logger.db(`Created Quotes ${doc.id}`);
});

const connection = mongoose.createConnection(MongoDB_URI);
increment.initialize(connection);

SubscriptionSchema.plugin(increment.plugin, {
model: 'subscription',
field: 'id',
startAt: 0,
incrementBy: 1
});

const SubscriptionModel = model<ISubscription & Document>("subscription", SubscriptionSchema);

export default SubscriptionModel;
19 changes: 19 additions & 0 deletions src/Email/Templates/CSS/GetTableStyle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export default `
width: 100%;
border-collapse: collapse;
thead th,
tfoot th,
thead th,
tfoot th {
border-bottom: 1px solid #999;
text-align: left;
margin: 0;
padding: 7px 5px;
}
tbody tr td,
tbody tr td {
margin: 0;
padding: 7px 5px;
border-top: 1px solid #E6E6E6;
}
`
Loading

0 comments on commit 482cd22

Please sign in to comment.