From acab23bea803ab265922bc87960c4efbf648e636 Mon Sep 17 00:00:00 2001 From: Tolfx Date: Sat, 12 Mar 2022 23:09:31 +0100 Subject: [PATCH 01/15] feat: :art: Added `PaymentsRouter` --- .../Routes/v3/Payments/Payments.config.ts | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/Server/Routes/v3/Payments/Payments.config.ts diff --git a/src/Server/Routes/v3/Payments/Payments.config.ts b/src/Server/Routes/v3/Payments/Payments.config.ts new file mode 100644 index 0000000..e336db8 --- /dev/null +++ b/src/Server/Routes/v3/Payments/Payments.config.ts @@ -0,0 +1,27 @@ +import { Application, Router } from "express"; +import { APISuccess } from "../../../../Lib/Response"; +import { A_CC_Payments, A_RecurringMethod } from "../../../../Types/PaymentMethod"; +import { A_PaymentTypes } from "../../../../Types/PaymentTypes"; + +export = class PaymentsRouter +{ + private server: Application; + private router = Router(); + + constructor(server: Application, version: string) + { + this.server = server; + this.server.use(`/${version}/payments`, this.router); + + this.router.get("/", (req, res) => + { + return APISuccess({ + payment_types: A_CC_Payments, + recurring_methods: A_RecurringMethod, + order_payment_types: A_PaymentTypes, + })(res); + }); + + } + +} \ No newline at end of file From e5a86ff126cb873772a3c3f100990a83b99d6d9e Mon Sep 17 00:00:00 2001 From: Tolfx Date: Sun, 13 Mar 2022 14:30:51 +0100 Subject: [PATCH 02/15] fix: :art: Updated exporting --- src/Server/Routes/v1/Admin/Admin.config.ts | 4 ++-- src/Server/Routes/v1/Contact/Contact.config.ts | 4 ++-- src/Server/Routes/v2/Categories/Categories.config.ts | 4 ++-- .../v2/ConfigurableOptions/ConfigurableOptions.config.ts | 4 ++-- src/Server/Routes/v2/Customers/Customers.config.ts | 4 ++-- src/Server/Routes/v2/Images/Images.config.ts | 4 ++-- src/Server/Routes/v2/Invoices/Invoices.config.ts | 4 ++-- src/Server/Routes/v2/Orders/Orders.config.ts | 4 ++-- src/Server/Routes/v2/Paypal/Paypal.config.ts | 4 ++-- src/Server/Routes/v2/Products/Products.config.ts | 4 ++-- src/Server/Routes/v2/PromotionsCodes/PromotionCode.config.ts | 4 ++-- src/Server/Routes/v2/Quotes/Quotes.config.ts | 4 ++-- src/Server/Routes/v2/Stripe/Stripe.config.ts | 4 ++-- src/Server/Routes/v2/Transactions/Transactions.config.ts | 4 ++-- src/Server/Routes/v3/Currencies/Currencies.config.ts | 4 ++-- src/Server/Routes/v3/Payments/Payments.config.ts | 4 ++-- 16 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/Server/Routes/v1/Admin/Admin.config.ts b/src/Server/Routes/v1/Admin/Admin.config.ts index 48f5ecf..9a0e6c9 100644 --- a/src/Server/Routes/v1/Admin/Admin.config.ts +++ b/src/Server/Routes/v1/Admin/Admin.config.ts @@ -3,8 +3,8 @@ import { JWT_Access_Token } from "../../../../Config"; import jwt from "jsonwebtoken"; import { APISuccess } from "../../../../Lib/Response"; import EnsureAdmin from "../../../../Middlewares/EnsureAdmin"; - -export = class AdminRouter +export = AdminRouter; +class AdminRouter { private server: Application; private router = Router(); diff --git a/src/Server/Routes/v1/Contact/Contact.config.ts b/src/Server/Routes/v1/Contact/Contact.config.ts index 8f39cd1..2f1e50c 100644 --- a/src/Server/Routes/v1/Contact/Contact.config.ts +++ b/src/Server/Routes/v1/Contact/Contact.config.ts @@ -2,8 +2,8 @@ import { Application, Router } from "express"; //@ts-ignore import { OSTicket } from 'ac-osticket' import { osticket_api_key, osticket_url } from "../../../../Config"; - -export = class ContactRouter +export = ContactRouter; +class ContactRouter { private server: Application; private router = Router(); diff --git a/src/Server/Routes/v2/Categories/Categories.config.ts b/src/Server/Routes/v2/Categories/Categories.config.ts index fa73429..c3b9102 100644 --- a/src/Server/Routes/v2/Categories/Categories.config.ts +++ b/src/Server/Routes/v2/Categories/Categories.config.ts @@ -1,8 +1,8 @@ import { Application, Router } from "express"; import EnsureAdmin from "../../../../Middlewares/EnsureAdmin"; import CategoryController from "./Categories.controller"; - -export = class CategoryRouter +export = CategoryRouter; +class CategoryRouter { private server: Application; private router = Router(); diff --git a/src/Server/Routes/v2/ConfigurableOptions/ConfigurableOptions.config.ts b/src/Server/Routes/v2/ConfigurableOptions/ConfigurableOptions.config.ts index 3014d37..4dadad6 100644 --- a/src/Server/Routes/v2/ConfigurableOptions/ConfigurableOptions.config.ts +++ b/src/Server/Routes/v2/ConfigurableOptions/ConfigurableOptions.config.ts @@ -1,8 +1,8 @@ import { Application, Router } from "express"; import EnsureAdmin from "../../../../Middlewares/EnsureAdmin"; import ConfigurableOptionsController from "./ConfigurableOptions.controller"; - -export = class ProductsRouter +export = ProductsRouter; +class ProductsRouter { private server: Application; private router = Router(); diff --git a/src/Server/Routes/v2/Customers/Customers.config.ts b/src/Server/Routes/v2/Customers/Customers.config.ts index 72a62c7..0e29d07 100644 --- a/src/Server/Routes/v2/Customers/Customers.config.ts +++ b/src/Server/Routes/v2/Customers/Customers.config.ts @@ -28,8 +28,8 @@ import { CacheImages } from "../../../../Cache/Image.cache"; import ImageModel from "../../../../Database/Models/Images.model"; import Jimp from 'jimp'; import QuotesModel from "../../../../Database/Models/Quotes.model"; - -export = class CustomerRouter +export = CustomerRouter; +class CustomerRouter { private server: Application; private router = Router(); diff --git a/src/Server/Routes/v2/Images/Images.config.ts b/src/Server/Routes/v2/Images/Images.config.ts index 503df9d..db15b5a 100644 --- a/src/Server/Routes/v2/Images/Images.config.ts +++ b/src/Server/Routes/v2/Images/Images.config.ts @@ -8,8 +8,8 @@ import { UploadedFile } from "express-fileupload"; import { idImages } from "../../../../Lib/Generator"; import ImageModel from "../../../../Database/Models/Images.model"; import AW from "../../../../Lib/AW"; - -export = class ImagesRouter +export = ImagesRouter; +class ImagesRouter { private server: Application; private router = Router(); diff --git a/src/Server/Routes/v2/Invoices/Invoices.config.ts b/src/Server/Routes/v2/Invoices/Invoices.config.ts index 42525af..af8a4a3 100644 --- a/src/Server/Routes/v2/Invoices/Invoices.config.ts +++ b/src/Server/Routes/v2/Invoices/Invoices.config.ts @@ -4,8 +4,8 @@ import createPDFInvoice from "../../../../Lib/Invoices/CreatePDFInvoice"; import EnsureAdmin from "../../../../Middlewares/EnsureAdmin"; import InvoiceController from "./Invoices.controller"; - -export = class InvoiceRouter +export = InvoiceRouter; +class InvoiceRouter { private server: Application; private router = Router(); diff --git a/src/Server/Routes/v2/Orders/Orders.config.ts b/src/Server/Routes/v2/Orders/Orders.config.ts index cce918f..e9e8871 100644 --- a/src/Server/Routes/v2/Orders/Orders.config.ts +++ b/src/Server/Routes/v2/Orders/Orders.config.ts @@ -70,8 +70,8 @@ async function createOrder(customer: ICustomer, products: Array<{ body: await NewOrderCreated(order, customer), }); } - -export = class OrderRoute +export = OrderRoute; +class OrderRoute { private server: Application; private router = Router(); diff --git a/src/Server/Routes/v2/Paypal/Paypal.config.ts b/src/Server/Routes/v2/Paypal/Paypal.config.ts index 5196393..c55b880 100644 --- a/src/Server/Routes/v2/Paypal/Paypal.config.ts +++ b/src/Server/Routes/v2/Paypal/Paypal.config.ts @@ -3,8 +3,8 @@ import { Company_Website } from "../../../../Config"; import InvoiceModel from "../../../../Database/Models/Invoices.model"; import { IInvoice } from "@interface/Invoice.interface"; import { createPaypalPaymentFromInvoice, retrievePaypalTransaction } from "../../../../Payments/Paypal"; - -export = class PaypalRouter +export = PaypalRouter; +class PaypalRouter { private server: Application; private router = Router(); diff --git a/src/Server/Routes/v2/Products/Products.config.ts b/src/Server/Routes/v2/Products/Products.config.ts index ab76e78..fb1a699 100644 --- a/src/Server/Routes/v2/Products/Products.config.ts +++ b/src/Server/Routes/v2/Products/Products.config.ts @@ -6,8 +6,8 @@ import AW from "../../../../Lib/AW"; import { APIError, APISuccess } from "../../../../Lib/Response"; import EnsureAdmin from "../../../../Middlewares/EnsureAdmin"; import ProductController from "./Products.controller"; - -export = class ProductsRouter +export = ProductsRouter; +class ProductsRouter { private server: Application; private router = Router(); diff --git a/src/Server/Routes/v2/PromotionsCodes/PromotionCode.config.ts b/src/Server/Routes/v2/PromotionsCodes/PromotionCode.config.ts index 50136b0..ec3a1a6 100644 --- a/src/Server/Routes/v2/PromotionsCodes/PromotionCode.config.ts +++ b/src/Server/Routes/v2/PromotionsCodes/PromotionCode.config.ts @@ -5,8 +5,8 @@ import Logger from "../../../../Lib/Logger"; import { APIError, APISuccess } from "../../../../Lib/Response"; import EnsureAdmin from "../../../../Middlewares/EnsureAdmin"; import PromotionCodeController from "./PromotionCode.controller"; - -export = class PromotionCodeRoute +export = PromotionCodeRoute; +class PromotionCodeRoute { private server: Application; private router = Router(); diff --git a/src/Server/Routes/v2/Quotes/Quotes.config.ts b/src/Server/Routes/v2/Quotes/Quotes.config.ts index 2ea4f45..f541ab7 100644 --- a/src/Server/Routes/v2/Quotes/Quotes.config.ts +++ b/src/Server/Routes/v2/Quotes/Quotes.config.ts @@ -11,8 +11,8 @@ import QuotesController from "./Quotes.controller"; import { sendInvoiceEmail } from "../../../../Lib/Invoices/SendEmail"; import { sendEmail } from "../../../../Email/Send"; import QuoteAcceptedTemplate from "../../../../Email/Templates/Quotes/Quote.accepted.template"; - -export = class QuotesRouter +export = QuotesRouter; +class QuotesRouter { private server: Application; private router = Router(); diff --git a/src/Server/Routes/v2/Stripe/Stripe.config.ts b/src/Server/Routes/v2/Stripe/Stripe.config.ts index 970da2f..cbc5af8 100644 --- a/src/Server/Routes/v2/Stripe/Stripe.config.ts +++ b/src/Server/Routes/v2/Stripe/Stripe.config.ts @@ -14,8 +14,8 @@ import stripeWebhookEvent from "../../../../Events/Stripe.event"; const stripe = new Stripe(DebugMode ? Stripe_SK_Test : Stripe_SK_Live, { apiVersion: "2020-08-27", }); - -export = class StripeRouter +export = StripeRouter; +class StripeRouter { private server: Application; private router = Router(); diff --git a/src/Server/Routes/v2/Transactions/Transactions.config.ts b/src/Server/Routes/v2/Transactions/Transactions.config.ts index 264eaf1..8adbef8 100644 --- a/src/Server/Routes/v2/Transactions/Transactions.config.ts +++ b/src/Server/Routes/v2/Transactions/Transactions.config.ts @@ -1,8 +1,8 @@ import { Application, Router } from "express"; import EnsureAdmin from "../../../../Middlewares/EnsureAdmin"; import TransactionsController from "./Transactions.controller"; - -export = class TransactionsRouter +export = TransactionsRouter; +class TransactionsRouter { private server: Application; private router = Router(); diff --git a/src/Server/Routes/v3/Currencies/Currencies.config.ts b/src/Server/Routes/v3/Currencies/Currencies.config.ts index 82c6787..95e8291 100644 --- a/src/Server/Routes/v3/Currencies/Currencies.config.ts +++ b/src/Server/Routes/v3/Currencies/Currencies.config.ts @@ -2,8 +2,8 @@ import { Application, Router } from "express"; import { APIError, APISuccess } from "../../../../Lib/Response"; import { PaypalCurrencies } from "../../../../Payments/Currencies/Paypal.currencies"; import { currencyCodes, GetCurrencySymbol, TPaymentCurrency } from '../../../../Lib/Currencies'; - -export = class CurrenciesRouter +export = CurrenciesRouter; +class CurrenciesRouter { private server: Application; private router = Router(); diff --git a/src/Server/Routes/v3/Payments/Payments.config.ts b/src/Server/Routes/v3/Payments/Payments.config.ts index e336db8..124ecf2 100644 --- a/src/Server/Routes/v3/Payments/Payments.config.ts +++ b/src/Server/Routes/v3/Payments/Payments.config.ts @@ -2,8 +2,8 @@ import { Application, Router } from "express"; import { APISuccess } from "../../../../Lib/Response"; import { A_CC_Payments, A_RecurringMethod } from "../../../../Types/PaymentMethod"; import { A_PaymentTypes } from "../../../../Types/PaymentTypes"; - -export = class PaymentsRouter +export = PaymentsRouter; +class PaymentsRouter { private server: Application; private router = Router(); From d3095204f32307e8b8196fec48bf4200a00f8ae1 Mon Sep 17 00:00:00 2001 From: Tolfx Date: Sun, 13 Mar 2022 19:48:43 +0100 Subject: [PATCH 03/15] feat: :package: Added exchange api package --- package.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/package.json b/package.json index 9bdfcd5..53c0a19 100644 --- a/package.json +++ b/package.json @@ -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", @@ -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", From defe934b1cffdcdbdd5777d2f636667283a9ed4f Mon Sep 17 00:00:00 2001 From: Tolfx Date: Sun, 13 Mar 2022 19:49:14 +0100 Subject: [PATCH 04/15] feat: :ambulance: Products now has `currency` --- src/Database/Models/Products.model.ts | 7 +++++++ src/Interfaces/Products.interface.ts | 2 ++ 2 files changed, 9 insertions(+) diff --git a/src/Database/Models/Products.model.ts b/src/Database/Models/Products.model.ts index 4e8e2c0..8660232 100644 --- a/src/Database/Models/Products.model.ts +++ b/src/Database/Models/Products.model.ts @@ -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 @@ -64,6 +65,12 @@ const ProductSchema = new Schema required: true, }, + currency: { + type: String, + enum: currencyCodes, + required: true, + }, + setup_fee: { type: Number, required: true, diff --git a/src/Interfaces/Products.interface.ts b/src/Interfaces/Products.interface.ts index 47e648a..3a711f9 100644 --- a/src/Interfaces/Products.interface.ts +++ b/src/Interfaces/Products.interface.ts @@ -1,3 +1,4 @@ +import { TPaymentCurrency } from "../Lib/Currencies"; import { TRecurringMethod } from "../Types/PaymentMethod"; import { TPaymentTypes } from "../Types/PaymentTypes"; import { ICategory } from "./Categories.interface"; @@ -30,6 +31,7 @@ export interface IProduct special: boolean; payment_type: Partial; price: number; + currency: TPaymentCurrency; setup_fee: number; image?: IImage["id"][]; tax_rate: number; From 16cfc6b04ece92c7e17f5aab255ada125aee30f7 Mon Sep 17 00:00:00 2001 From: Tolfx Date: Sun, 13 Mar 2022 19:49:50 +0100 Subject: [PATCH 05/15] fix: :art: Ensure currency is added to product --- .../Routes/v2/Products/Products.controller.ts | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/Server/Routes/v2/Products/Products.controller.ts b/src/Server/Routes/v2/Products/Products.controller.ts index c09463a..4c9ba98 100644 --- a/src/Server/Routes/v2/Products/Products.controller.ts +++ b/src/Server/Routes/v2/Products/Products.controller.ts @@ -5,11 +5,28 @@ import { IProduct } from "@interface/Products.interface"; import { idProduct } from "../../../../Lib/Generator"; import { APISuccess } from "../../../../Lib/Response"; import BaseModelAPI from "../../../../Models/BaseModelAPI"; +import { currencyCodes, TPaymentCurrency } from "../../../../Lib/Currencies"; +import { Company_Currency } from "../../../../Config"; const API = new BaseModelAPI(idProduct, ProductModel); -function insert(req: Request, res: Response) +async function insert(req: Request, res: Response) { + + if(!req.body.currency) + req.body.currency = (await Company_Currency()).toUpperCase(); + + // Check if our currency is valid + // req.body.currency = igh7183 + const validCurrency = (currency: string) => + { + currency = currency.toUpperCase(); + return currencyCodes.includes(currency as TPaymentCurrency); + } + + if(!validCurrency(req.body.currency)) + req.body.currency = (await Company_Currency()).toUpperCase(); + API.create(req.body) .then((result) => { From 608c8c6057ca5ef564dca4dad668a04e43e370c5 Mon Sep 17 00:00:00 2001 From: Tolfx Date: Sun, 13 Mar 2022 19:50:20 +0100 Subject: [PATCH 06/15] feat: :art: Possible to convert currencies between --- src/Lib/Currencies.ts | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/Lib/Currencies.ts b/src/Lib/Currencies.ts index 4da2e7a..2db1dfd 100644 --- a/src/Lib/Currencies.ts +++ b/src/Lib/Currencies.ts @@ -1,3 +1,4 @@ +import { exchangeRates } from "exchange-rates-api"; // Every currency's code is in ISO 4217 export type TPaymentCurrency = "AED" @@ -194,4 +195,29 @@ export function GetCurrencySymbol(code: TPaymentCurrency) maximumFractionDigits: 0 } ).replace(/\d/g, '').trim() -} \ No newline at end of file +} + +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); +}; \ No newline at end of file From 244256c689abc2ca715039c420757b9ed9fd486b Mon Sep 17 00:00:00 2001 From: Tolfx Date: Sun, 13 Mar 2022 19:50:51 +0100 Subject: [PATCH 07/15] fix: :ambulance: Fixed conversion on currencies --- src/Lib/Orders/newInvoice.ts | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/Lib/Orders/newInvoice.ts b/src/Lib/Orders/newInvoice.ts index 15cb1da..d590ca6 100644 --- a/src/Lib/Orders/newInvoice.ts +++ b/src/Lib/Orders/newInvoice.ts @@ -14,6 +14,8 @@ import { Document } from "mongoose"; import Logger from "../Logger"; import PromotionCodeModel from "../../Database/Models/PromotionsCode.model"; import { sanitizeMongoose } from "../Sanitize"; +import CustomerModel from "../../Database/Models/Customers/Customer.model"; +import { convertCurrency } from "../Currencies"; // Create a method that checks if the order next recycle is within 14 days export function isWithinNext14Days(date: Date | string): boolean @@ -35,12 +37,28 @@ export async function createInvoiceFromOrder(order: IOrder) { // Get our products - const Products = await getProductsByOrder(order); + let Products = await getProductsByOrder(order); const LBProducts = createMapProductsFromOrder(order); const Promotion_Code = await PromotionCodeModel.findOne({ id: sanitizeMongoose(order.promotion_code) }); - + // Get customer id const Customer_Id = order.customer_uid; + const customer = await CustomerModel.findOne({ $or: [ + { uid: Customer_Id }, + { id: Customer_Id }, + ] }); + if(!customer) + throw new Error(`Customer ${Customer_Id} not found`); + + // Change products price based on customers.currenc + Products = await Promise.all(Products.map(async product => + { + // Check if same currency + if(product.currency.toUpperCase() !== customer.currency.toUpperCase()) + // Convert to customer currency + product.price = await convertCurrency(product.price, product.currency, customer.currency); + return product; + })); const items = []; for await(let product of Products) @@ -72,6 +90,10 @@ export async function createInvoiceFromOrder(order: IOrder) const option = configurable_option.options[ option_index ]; + // Fix option.price to customer currency + if(product.currency.toUpperCase() !== customer.currency.toUpperCase()) + option.price = await convertCurrency(option.price, product.currency, customer.currency); + items.push({ amount: option.price ?? 0, notes: `+ ${product?.name} - ${configurable_option.name} ${option.name}`, @@ -103,8 +125,8 @@ export async function createInvoiceFromOrder(order: IOrder) status: order.order_status, tax_rate: Products?.reduce((acc, cur) => cur.tax_rate, 0), notes: "", - paid: false, currency: order.currency, + paid: false, notified: false, })).save(); From 1decc622a90f7c9abc0dd33ccbc2ad5654244a84 Mon Sep 17 00:00:00 2001 From: Tolfx Date: Sun, 13 Mar 2022 19:51:05 +0100 Subject: [PATCH 08/15] fix: :ambulance: Fixed conversion on orders --- src/Email/Templates/Orders/NewOrderCreated.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/Email/Templates/Orders/NewOrderCreated.ts b/src/Email/Templates/Orders/NewOrderCreated.ts index 91b26d2..0c6c023 100644 --- a/src/Email/Templates/Orders/NewOrderCreated.ts +++ b/src/Email/Templates/Orders/NewOrderCreated.ts @@ -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`
@@ -18,7 +19,7 @@ export default async (order: IOrder, customer: ICustomer) => await UseStyles(str Order number: ${order.id}

- ${await printOrderProductTable(order)} + ${await printOrderProductTable(order, customer)}

@@ -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 ?? []) @@ -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; @@ -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()}

${CPG_Customer_Panel_Domain ? ` From 32c5da72e958dfa4a8c1414b690afa54aa9858e8 Mon Sep 17 00:00:00 2001 From: Tolfx Date: Sun, 13 Mar 2022 19:51:34 +0100 Subject: [PATCH 09/15] fix: :ambulance: Fixed templates on currencies --- .../Templates/Invoices/Invoice.template.ts | 4 ++-- .../Templates/Invoices/LateInvoice.Template.ts | 4 ++-- .../Templates/Methods/InvoiceItems.print.ts | 2 +- .../Templates/Methods/OrderProducts.print.ts | 18 ++++++++++++++---- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/Email/Templates/Invoices/Invoice.template.ts b/src/Email/Templates/Invoices/Invoice.template.ts index 36262e2..8d04843 100644 --- a/src/Email/Templates/Invoices/Invoice.template.ts +++ b/src/Email/Templates/Invoices/Invoice.template.ts @@ -25,7 +25,7 @@ export default async (invoice: IInvoice & IInvoiceMethods, customer: ICustomer) Tax due: ${invoice.tax_rate}%

- Amount due: ${invoice.getTotalAmount({ tax: false, currency: true, symbol: true })} + Amount due: ${invoice.getTotalAmount({ tax: false, currency: false, symbol: false }).toFixed(2)} ${(invoice.currency)}

Due date: ${invoice.dates.due_date} @@ -69,7 +69,7 @@ export default async (invoice: IInvoice & IInvoiceMethods, customer: ICustomer) Total: - ${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}%)

diff --git a/src/Email/Templates/Invoices/LateInvoice.Template.ts b/src/Email/Templates/Invoices/LateInvoice.Template.ts index e37764f..ff91c54 100644 --- a/src/Email/Templates/Invoices/LateInvoice.Template.ts +++ b/src/Email/Templates/Invoices/LateInvoice.Template.ts @@ -25,7 +25,7 @@ export default async (invoice: IInvoice & IInvoiceMethods, customer: ICustomer) Tax due: ${invoice.tax_rate}%

- Amount due: ${invoice.getTotalAmount({ tax: false, currency: true, symbol: true })} + Amount due: ${invoice.getTotalAmount({ tax: false, currency: false, symbol: false }).toFixed(2)} ${(invoice.currency)}

Due date: ${invoice.dates.due_date} @@ -69,7 +69,7 @@ export default async (invoice: IInvoice & IInvoiceMethods, customer: ICustomer) Total: - ${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}%)

diff --git a/src/Email/Templates/Methods/InvoiceItems.print.ts b/src/Email/Templates/Methods/InvoiceItems.print.ts index 39a77ba..554d8c6 100644 --- a/src/Email/Templates/Methods/InvoiceItems.print.ts +++ b/src/Email/Templates/Methods/InvoiceItems.print.ts @@ -18,7 +18,7 @@ export default async function printInvoiceItemsTable(invoice: IInvoice) ${item.notes} ${item.quantity} - ${item.amount} ${GetCurrencySymbol(invoice.currency)} + ${item.amount.toFixed(2)} ${GetCurrencySymbol(invoice.currency)} `))).join('')} diff --git a/src/Email/Templates/Methods/OrderProducts.print.ts b/src/Email/Templates/Methods/OrderProducts.print.ts index 7b1a59f..09e2fa4 100644 --- a/src/Email/Templates/Methods/OrderProducts.print.ts +++ b/src/Email/Templates/Methods/OrderProducts.print.ts @@ -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 ` @@ -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 ?? []) { @@ -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` - + `; if(p_c.length > 0) @@ -49,7 +59,7 @@ export default async function printOrderProductTable(order: IOrder) - + ` } } From 6bd3d4140df932528759d108fb1009d16b270b6e Mon Sep 17 00:00:00 2001 From: Tolfx Date: Sun, 13 Mar 2022 19:51:50 +0100 Subject: [PATCH 10/15] fix: :ambulance: Fixed fixed numbers --- src/Lib/Invoices/CreatePDFInvoice.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Lib/Invoices/CreatePDFInvoice.ts b/src/Lib/Invoices/CreatePDFInvoice.ts index b8f7dc4..fc6f622 100644 --- a/src/Lib/Invoices/CreatePDFInvoice.ts +++ b/src/Lib/Invoices/CreatePDFInvoice.ts @@ -133,7 +133,7 @@ export default function createPDFInvoice(invoice: IInvoice): Promise "quantity": item.quantity, "description": item.notes, "tax-rate": invoice.tax_rate, - "price": item.amount + "price": item.amount.toFixed(2) } }), "bottomNotice": ` From 67d5ba8c97015d24030c4893480b3fab4500cbfc Mon Sep 17 00:00:00 2001 From: Tolfx Date: Sun, 13 Mar 2022 19:53:06 +0100 Subject: [PATCH 11/15] refactor: Removed unused imports --- src/Database/Postgres/Models/Customer/Customer.model.ts | 3 ++- src/Interfaces/Customer.interface.ts | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Database/Postgres/Models/Customer/Customer.model.ts b/src/Database/Postgres/Models/Customer/Customer.model.ts index d1f58f6..bfe72e0 100644 --- a/src/Database/Postgres/Models/Customer/Customer.model.ts +++ b/src/Database/Postgres/Models/Customer/Customer.model.ts @@ -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> implements ICustomer { @@ -27,7 +28,7 @@ export class CustomerModel extends Model> i }; declare password: string; declare profile_picture: IImage["id"] | null; - declare currency: string | ICustomer["currency"]; + declare currency: TPaymentCurrency; declare extra: { [key: string]: any; }; diff --git a/src/Interfaces/Customer.interface.ts b/src/Interfaces/Customer.interface.ts index dc66902..bbcc920 100644 --- a/src/Interfaces/Customer.interface.ts +++ b/src/Interfaces/Customer.interface.ts @@ -1,5 +1,4 @@ import { TPaymentCurrency } from "../Lib/Currencies"; -import { ICompanyConfig } from "./Admin/Configs.interface"; import { IImage } from "./Images.interface"; /** @@ -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; }; From 64b5ec82bea2df3f7b24eb4ee0e359205fd15bd2 Mon Sep 17 00:00:00 2001 From: Tolfx Date: Sun, 13 Mar 2022 19:53:19 +0100 Subject: [PATCH 12/15] refactor: Small changes --- src/Server/Routes/v2/Customers/Customers.controller.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Server/Routes/v2/Customers/Customers.controller.ts b/src/Server/Routes/v2/Customers/Customers.controller.ts index 9438837..d482658 100644 --- a/src/Server/Routes/v2/Customers/Customers.controller.ts +++ b/src/Server/Routes/v2/Customers/Customers.controller.ts @@ -35,9 +35,7 @@ function insert(req: Request, res: Response) return APIError(`Email ${email} already exists`, 409)(res); if(!req.body.currency) - { req.body.currency = await Company_Currency(); - } // Check if our currency is valid // req.body.currency = igh7183 @@ -45,8 +43,6 @@ function insert(req: Request, res: Response) { currency = currency.toUpperCase(); return currencyCodes.includes(currency as TPaymentCurrency); - - } if(!validCurrency(req.body.currency)) From 30efa1f5cb7aa14b398583becd2d52dc710b18c2 Mon Sep 17 00:00:00 2001 From: Tolfx Date: Sun, 13 Mar 2022 19:53:31 +0100 Subject: [PATCH 13/15] feat: :art: Added `TaxesRouter` --- src/Server/Routes/v3/Taxes/Taxes.config.ts | 37 ++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/Server/Routes/v3/Taxes/Taxes.config.ts diff --git a/src/Server/Routes/v3/Taxes/Taxes.config.ts b/src/Server/Routes/v3/Taxes/Taxes.config.ts new file mode 100644 index 0000000..d6e0f48 --- /dev/null +++ b/src/Server/Routes/v3/Taxes/Taxes.config.ts @@ -0,0 +1,37 @@ +import { Application, Router } from "express"; +import TransactionsModel from "../../../../Database/Models/Transactions.model"; +import { APISuccess } from "../../../../Lib/Response"; +import EnsureAdmin from "../../../../Middlewares/EnsureAdmin"; + +export = TaxesRouter; +class TaxesRouter +{ + private server: Application; + private router = Router(); + + constructor(server: Application, version: string) + { + this.server = server; + this.server.use(`/${version}/taxes`, this.router); + + this.router.get("/declaration/:start_date/:end_date", EnsureAdmin(), async (req, res) => + { + const start_date = req.params.start_date; + const end_date = req.params.end_date; + + // Get all transactions for the given date range + const transactions = await TransactionsModel.find({ + date: { + $gte: start_date, + $lte: end_date, + }, + }); + + return APISuccess({ + transactions, + })(res); + }); + + } + +} \ No newline at end of file From cb6f0e747217455667d9070f475e1fdb46bebbdd Mon Sep 17 00:00:00 2001 From: Tolfx Date: Sun, 13 Mar 2022 19:56:50 +0100 Subject: [PATCH 14/15] refactor: :label: v2.9 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 53c0a19..d659317 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cpg-api", - "version": "v2.8", + "version": "v2.9", "description": "Central Payment Gateway", "main": "./build/Main.js", "dependencies": { From 86bef8d811fdf82c0e53d746722a94032441565a Mon Sep 17 00:00:00 2001 From: Tolfx Date: Sun, 13 Mar 2022 20:00:32 +0100 Subject: [PATCH 15/15] fix: :ambulance: Ensure customer & product has currency --- src/Cache/reCache.ts | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/Cache/reCache.ts b/src/Cache/reCache.ts index caa058c..001fa94 100644 --- a/src/Cache/reCache.ts +++ b/src/Cache/reCache.ts @@ -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 @@ -51,17 +53,21 @@ 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); } @@ -69,9 +75,6 @@ export async function reCache_Customers() }); } -/** - * @deprecated - */ export async function reCache_Product() { Logger.info(`Starting caching on products..`); @@ -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); } @@ -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();
${p?.name} ${product.quantity}${p?.price} ${GetCurrencySymbol(order.currency)}${p?.price.toFixed(2)} ${GetCurrencySymbol(order.currency)}
+ ${p?.name} - ${c?.name} 1${c?.price} ${GetCurrencySymbol(order.currency)}${c?.price.toFixed(2)} ${GetCurrencySymbol(order.currency)}