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 #98 from Tolfix/dev
Browse files Browse the repository at this point in the history
v2.9
  • Loading branch information
Tolfx authored Mar 13, 2022
2 parents 64a31a6 + 86bef8d commit 412d0c3
Show file tree
Hide file tree
Showing 33 changed files with 231 additions and 65 deletions.
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cpg-api",
"version": "v2.8",
"version": "v2.9",
"description": "Central Payment Gateway",
"main": "./build/Main.js",
"dependencies": {
Expand All @@ -26,6 +26,7 @@
"date-and-time": "^1.0.1",
"dotenv": "^10.0.0",
"easyinvoice": "^2.0.8",
"exchange-rates-api": "^1.1.0",
"express": "^4.17.1",
"express-fileupload": "^1.2.1",
"express-rate-limit": "^6.2.0",
Expand Down Expand Up @@ -75,6 +76,7 @@
"devDependencies": {
"@types/cors": "^2.8.12",
"@types/cron": "^1.7.3",
"@types/exchange-rates-api": "^1.0.0",
"@types/express": "^4.17.13",
"@types/express-fileupload": "^1.1.7",
"@types/express-session": "^1.17.4",
Expand Down
28 changes: 19 additions & 9 deletions src/Cache/reCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import ConfigModel from "../Database/Models/Configs.model";
import { CacheConfig } from "./Configs.cache";
import InvoiceModel from "../Database/Models/Invoices.model";
import { CacheInvoice } from "./Invoices.cache";
import { Company_Currency } from "../Config";
import { TPaymentCurrency } from "../Lib/Currencies";

/**
* @deprecated
Expand Down Expand Up @@ -51,27 +53,28 @@ export async function reCache_Admin()
});
}

/**
* @deprecated
*/
export async function reCache_Customers()
{
Logger.info(`Starting caching on customers..`);
return new Promise(async (resolve) =>
{
const customer = await CustomerModel.find();
for (const c of customer)
for await(const c of customer)
{
// Check if customer has currency
if(!c.currency)
{
const companyCurrency = await Company_Currency();
c.currency = companyCurrency.toLocaleUpperCase() as TPaymentCurrency;
await c.save();
}
Logger.cache(`Caching customer ${c.uid}`);
CacheCustomer.set(c.uid, c);
}
return resolve(true);
});
}

/**
* @deprecated
*/
export async function reCache_Product()
{
Logger.info(`Starting caching on products..`);
Expand All @@ -80,6 +83,13 @@ export async function reCache_Product()
const product = await ProductModel.find();
for (const c of product)
{
// Check if product has currency
if(!c.currency)
{
const companyCurrency = await Company_Currency();
c.currency = companyCurrency.toLocaleUpperCase() as TPaymentCurrency;
await c.save();
}
Logger.cache(`Caching product ${c.uid}`);
CacheProduct.set(c.uid, c);
}
Expand Down Expand Up @@ -201,8 +211,8 @@ export async function reCache()
await reCache_Configs();
// await reCache_Categories();
await reCache_Admin();
// await reCache_Customers();
// await reCache_Product();
await reCache_Customers();
await reCache_Product();
// await reCache_Transactions();
// await reCache_Orders();
await reCache_Images();
Expand Down
7 changes: 7 additions & 0 deletions src/Database/Models/Products.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Logger from "../../Lib/Logger";
import GetText from "../../Translation/GetText";
import { A_RecurringMethod } from "../../Types/PaymentMethod";
import { A_PaymentTypes } from "../../Types/PaymentTypes";
import { currencyCodes } from "../../Lib/Currencies";


const ProductSchema = new Schema
Expand Down Expand Up @@ -64,6 +65,12 @@ const ProductSchema = new Schema
required: true,
},

currency: {
type: String,
enum: currencyCodes,
required: true,
},

setup_fee: {
type: Number,
required: true,
Expand Down
3 changes: 2 additions & 1 deletion src/Database/Postgres/Models/Customer/Customer.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Sequelize, {
import { Billing, ICustomer, Personal } from "@interface/Customer.interface";
import { IImage } from "@interface/Images.interface";
import { postgres } from "../../../Postgres";
import { TPaymentCurrency } from "../../../../Lib/Currencies";

export class CustomerModel extends Model<ICustomer, Optional<ICustomer, "id">> implements ICustomer
{
Expand All @@ -27,7 +28,7 @@ export class CustomerModel extends Model<ICustomer, Optional<ICustomer, "id">> i
};
declare password: string;
declare profile_picture: IImage["id"] | null;
declare currency: string | ICustomer["currency"];
declare currency: TPaymentCurrency;
declare extra: {
[key: string]: any;
};
Expand Down
4 changes: 2 additions & 2 deletions src/Email/Templates/Invoices/Invoice.template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default async (invoice: IInvoice & IInvoiceMethods, customer: ICustomer)
<strong>Tax due:</strong> ${invoice.tax_rate}%
</p>
<p>
<strong>Amount due:</strong> ${invoice.getTotalAmount({ tax: false, currency: true, symbol: true })}
<strong>Amount due:</strong> ${invoice.getTotalAmount({ tax: false, currency: false, symbol: false }).toFixed(2)} ${(invoice.currency)}
</p>
<p>
<strong>Due date:</strong> ${invoice.dates.due_date}
Expand Down Expand Up @@ -69,7 +69,7 @@ export default async (invoice: IInvoice & IInvoiceMethods, customer: ICustomer)
<strong>
Total:
</strong>
${invoice.getTotalAmount({ tax: true, currency: true, symbol: true })} (${invoice.tax_rate}%)
${invoice.getTotalAmount({ tax: true, currency: false, symbol: false }).toFixed(2)} ${invoice.currency} (${invoice.tax_rate}%)
</p>
<p>
<strong>
Expand Down
4 changes: 2 additions & 2 deletions src/Email/Templates/Invoices/LateInvoice.Template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default async (invoice: IInvoice & IInvoiceMethods, customer: ICustomer)
<strong>Tax due:</strong> ${invoice.tax_rate}%
</p>
<p>
<strong>Amount due:</strong> ${invoice.getTotalAmount({ tax: false, currency: true, symbol: true })}
<strong>Amount due:</strong> ${invoice.getTotalAmount({ tax: false, currency: false, symbol: false }).toFixed(2)} ${(invoice.currency)}
</p>
<p>
<strong>Due date:</strong> ${invoice.dates.due_date}
Expand Down Expand Up @@ -69,7 +69,7 @@ export default async (invoice: IInvoice & IInvoiceMethods, customer: ICustomer)
<strong>
Total:
</strong>
${invoice.getTotalAmount({ tax: true, currency: true, symbol: true })} (${invoice.tax_rate}%)
${invoice.getTotalAmount({ tax: true, currency: false, symbol: false }).toFixed(2)} ${invoice.currency} (${invoice.tax_rate}%)
</p>
<p>
<strong>
Expand Down
2 changes: 1 addition & 1 deletion src/Email/Templates/Methods/InvoiceItems.print.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default async function printInvoiceItemsTable(invoice: IInvoice)
<tr>
<td>${item.notes}</td>
<td>${item.quantity}</td>
<td>${item.amount} ${GetCurrencySymbol(invoice.currency)}</td>
<td>${item.amount.toFixed(2)} ${GetCurrencySymbol(invoice.currency)}</td>
</tr>
`))).join('')}
</tbody>
Expand Down
18 changes: 14 additions & 4 deletions src/Email/Templates/Methods/OrderProducts.print.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import { IOrder } from "@interface/Orders.interface";
import { stripIndents } from "common-tags";
import ConfigurableOptionsModel from "../../../Database/Models/ConfigurableOptions.model";
import getProductById from "../../../Lib/Products/getProductById";
import { GetCurrencySymbol } from "../../../Lib/Currencies";
import { convertCurrency, GetCurrencySymbol } from "../../../Lib/Currencies";
import GetTableStyle from "../CSS/GetTableStyle";
import { ICustomer } from "@interface/Customer.interface";

export default async function printOrderProductTable(order: IOrder)
export default async function printOrderProductTable(order: IOrder, customer: ICustomer)
{
return `
<table style="${GetTableStyle}">
Expand All @@ -20,6 +21,10 @@ export default async function printOrderProductTable(order: IOrder)
${(await Promise.all(order.products.map(async (product) =>
{
const p = await getProductById(product.product_id);
if(!p) return 0;
if(p?.currency.toUpperCase() !== customer.currency.toUpperCase())
p.price = await convertCurrency(p?.price, p?.currency, order.currency);
const p_c = [];
for await(const conf of product?.configurable_options ?? [])
{
Expand All @@ -28,17 +33,22 @@ export default async function printOrderProductTable(order: IOrder)
});
if(c)
{
if(p?.currency.toUpperCase() !== customer.currency.toUpperCase())
// Convert to customer currency
c.options[conf.option_index].price = await convertCurrency(c.options[conf.option_index].price, p?.currency, customer.currency);
p_c.push({
price: c.options[conf.option_index].price,
name: c.options[conf.option_index].name,
});
}
}
let result = stripIndents`
<tr>
<td>${p?.name}</td>
<td>${product.quantity}</td>
<td>${p?.price} ${GetCurrencySymbol(order.currency)}</td>
<td>${p?.price.toFixed(2)} ${GetCurrencySymbol(order.currency)}</td>
</tr>`;
if(p_c.length > 0)
Expand All @@ -49,7 +59,7 @@ export default async function printOrderProductTable(order: IOrder)
<tr>
<td>+ ${p?.name} - ${c?.name}</td>
<td>1</td>
<td>${c?.price} ${GetCurrencySymbol(order.currency)}</td>
<td>${c?.price.toFixed(2)} ${GetCurrencySymbol(order.currency)}</td>
</tr>`
}
}
Expand Down
16 changes: 13 additions & 3 deletions src/Email/Templates/Orders/NewOrderCreated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import getFullName from "../../../Lib/Customers/getFullName";
import getProductById from "../../../Lib/Products/getProductById";
import UseStyles from "../General/UseStyles";
import printOrderProductTable from "../Methods/OrderProducts.print";
import { convertCurrency } from "../../../Lib/Currencies";

export default async (order: IOrder, customer: ICustomer) => await UseStyles(stripIndents`
<div>
Expand All @@ -18,7 +19,7 @@ export default async (order: IOrder, customer: ICustomer) => await UseStyles(str
<strong>Order number:</strong> ${order.id}
</p>
${await printOrderProductTable(order)}
${await printOrderProductTable(order, customer)}
<p>
<strong>
Expand All @@ -27,6 +28,10 @@ export default async (order: IOrder, customer: ICustomer) => await UseStyles(str
${(await Promise.all(order.products.map(async (product) =>
{
const p = await getProductById(product.product_id as any);
if(!p) return 0;
if(p?.currency.toUpperCase() !== customer.currency.toUpperCase())
p.price = await convertCurrency(p?.price, p?.currency, order.currency);
// check if configurable options are added
const p_c = [];
for await(const conf of product?.configurable_options ?? [])
Expand All @@ -35,10 +40,15 @@ export default async (order: IOrder, customer: ICustomer) => await UseStyles(str
id: conf.id,
});
if(c)
{
// Check if same currency
if(p?.currency.toUpperCase() !== customer.currency.toUpperCase())
// Convert to customer currency
c.options[conf.option_index].price = await convertCurrency(c.options[conf.option_index].price, p?.currency, customer.currency);
p_c.push(c.options[conf.option_index].price);
}
}
if (!p)
return 0;
Expand All @@ -47,7 +57,7 @@ export default async (order: IOrder, customer: ICustomer) => await UseStyles(str
total += p_c.reduce((a, b) => a + b);
return total;
}))).reduce((acc, cur) => acc + cur, 0)} ${(order.currency).toLocaleUpperCase()}
}))).reduce((acc, cur) => acc + cur, 0).toFixed(2)} ${(order.currency).toLocaleUpperCase()}
</p>
${CPG_Customer_Panel_Domain ? `
Expand Down
3 changes: 1 addition & 2 deletions src/Interfaces/Customer.interface.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { TPaymentCurrency } from "../Lib/Currencies";
import { ICompanyConfig } from "./Admin/Configs.interface";
import { IImage } from "./Images.interface";

/**
Expand Down Expand Up @@ -28,7 +27,7 @@ export interface ICustomer
password: string;
createdAt: Date;
profile_picture: IImage["id"] | null;
currency: TPaymentCurrency | ICompanyConfig["currency"];
currency: TPaymentCurrency;
extra: {
[key: string]: any;
};
Expand Down
2 changes: 2 additions & 0 deletions src/Interfaces/Products.interface.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { TPaymentCurrency } from "../Lib/Currencies";
import { TRecurringMethod } from "../Types/PaymentMethod";
import { TPaymentTypes } from "../Types/PaymentTypes";
import { ICategory } from "./Categories.interface";
Expand Down Expand Up @@ -30,6 +31,7 @@ export interface IProduct
special: boolean;
payment_type: Partial<TPaymentTypes>;
price: number;
currency: TPaymentCurrency;
setup_fee: number;
image?: IImage["id"][];
tax_rate: number;
Expand Down
28 changes: 27 additions & 1 deletion src/Lib/Currencies.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { exchangeRates } from "exchange-rates-api";
// Every currency's code is in ISO 4217
export type TPaymentCurrency =
"AED"
Expand Down Expand Up @@ -194,4 +195,29 @@ export function GetCurrencySymbol(code: TPaymentCurrency)
maximumFractionDigits: 0
}
).replace(/\d/g, '').trim()
}
}

export const convertCurrency = async (
amount: number,
fromCurrency: TPaymentCurrency,
toCurrency: TPaymentCurrency,
date = 'latest'
) =>
{
const instance = exchangeRates();
// @ts-ignore
instance.setApiBaseUrl('https://api.exchangerate.host');

if (date === 'latest')
instance.latest();
else
// @ts-ignore
instance.at(date);

return instance
.base(fromCurrency)
.symbols(toCurrency)
.fetch()
// @ts-ignore
.then((rate) => rate * amount);
};
2 changes: 1 addition & 1 deletion src/Lib/Invoices/CreatePDFInvoice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ export default function createPDFInvoice(invoice: IInvoice): Promise<string>
"quantity": item.quantity,
"description": item.notes,
"tax-rate": invoice.tax_rate,
"price": item.amount
"price": item.amount.toFixed(2)
}
}),
"bottomNotice": `
Expand Down
Loading

0 comments on commit 412d0c3

Please sign in to comment.