Invoice should not be sent via Stripe but from e-Mobility, download invoice by e-Mobility ID, removed unused type
MODIFY
src/integration/billing/BillingIntegration.ts
src/integration/billing/BillingIntegration.ts
@@ -521,6 +521,14 @@ export default abstract class BillingIntegration<T extends BillingSetting> {
}
}
+ public async sendInvoiceToUser(invoice: BillingInvoice): Promise<BillingInvoice> {
+ // Save generated pdf
+ if (invoice.downloadable) {
+ // Send link to the user using our notification framework (link to the front-end + download)
+ }
+ return invoice;
+ }
+
private async checkAndGetBillingUser(user: User): Promise<BillingUser> {
const billingUser = await this.getUserByEmail(user.email);
if (!billingUser) {
@@ -607,7 +615,5 @@ export default abstract class BillingIntegration<T extends BillingSetting> {
async abstract createInvoice(user: BillingUser, invoiceItem: BillingInvoiceItem, idempotencyKey?: string | number): Promise<{ invoice: BillingInvoice; invoiceItem: BillingInvoiceItem }>;
- async abstract sendInvoiceToUser(invoice: BillingInvoice): Promise<BillingInvoice>;
-
async abstract downloadInvoiceDocument(invoice: BillingInvoice): Promise<BillingInvoiceDocument>;
}

MODIFY
src/integration/billing/stripe/StripeBillingIntegration.ts
src/integration/billing/stripe/StripeBillingIntegration.ts
@@ -387,56 +387,6 @@ export default class StripeBillingIntegration extends BillingIntegration<StripeB
}
}
- public async sendInvoiceToUser(invoice: BillingInvoice): Promise<BillingInvoice> {
- await this.checkConnection();
- // Send invoice to user
- try {
- const stripeInvoice = await this.stripe.invoices.sendInvoice(invoice.invoiceID);
- invoice.status = stripeInvoice.status as BillingInvoiceStatus;
- invoice.downloadUrl = stripeInvoice.invoice_pdf;
- invoice.id = await BillingStorage.saveInvoice(this.tenantID, invoice);
- } catch (error) {
- throw new BackendError({
- source: Constants.CENTRAL_SERVER,
- action: ServerAction.BILLING_SEND_INVOICE,
- module: MODULE_NAME, method: 'sendInvoiceToUser',
- message: 'Failed to send invoice',
- detailedMessages: { error: error.message, stack: error.stack }
- });
- }
- // Save generated pdf
- if (invoice.downloadUrl && invoice.downloadUrl !== '') {
- // Download PDF file
- const invoiceDocument = await this.downloadInvoiceDocument(invoice);
- // Save PDF file into database
- try {
- await BillingStorage.saveInvoiceDocument(this.tenantID, invoiceDocument);
- } catch (error) {
- throw new BackendError({
- source: Constants.CENTRAL_SERVER,
- action: ServerAction.BILLING_DOWNLOAD_INVOICE,
- module: MODULE_NAME, method: 'sendInvoiceToUser',
- message: 'Failed to save invoice PDF in database',
- detailedMessages: { error: error.message, stack: error.stack }
- });
- }
- // Update related invoice as downloadable
- invoice.downloadable = true;
- try {
- await BillingStorage.saveInvoice(this.tenantID, invoice);
- } catch (error) {
- throw new BackendError({
- source: Constants.CENTRAL_SERVER,
- action: ServerAction.BILLING_CREATE_INVOICE,
- module: MODULE_NAME, method: 'sendInvoiceToUser',
- message: 'Failed to save invoice in database',
- detailedMessages: { error: error.message, stack: error.stack }
- });
- }
- }
- return invoice;
- }
-
public async downloadInvoiceDocument(invoice: BillingInvoice): Promise<BillingInvoiceDocument> {
if (invoice.downloadUrl && invoice.downloadUrl !== '') {
// Get document

MODIFY
src/server/rest/service/BillingService.ts
src/server/rest/service/BillingService.ts
@@ -333,6 +333,9 @@ export default class BillingService {
}
public static async handleDownloadInvoice(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
+ // Check if component is active
+ UtilsService.assertComponentIsActiveFromToken(req.user, TenantComponents.BILLING,
+ Action.DOWNLOAD, Entity.BILLING, MODULE_NAME, 'handleDownloadInvoice');
if (!Authorizations.canDownloadInvoiceBilling(req.user)) {
throw new AppAuthError({
errorCode: HTTPAuthError.ERROR,
@@ -341,11 +344,7 @@ export default class BillingService {
module: MODULE_NAME, method: 'handleDownloadInvoice',
});
}
- // Check if component is active
- UtilsService.assertComponentIsActiveFromToken(req.user, TenantComponents.BILLING,
- Action.DOWNLOAD, Entity.BILLING, MODULE_NAME, 'handleDownloadInvoice');
- const tenant = await TenantStorage.getTenant(req.user.tenantID);
- const billingImpl = await BillingFactory.getBillingImpl(tenant.id);
+ const billingImpl = await BillingFactory.getBillingImpl(req.user.tenantID);
if (!billingImpl) {
throw new AppError({
source: Constants.CENTRAL_SERVER,
@@ -358,7 +357,10 @@ export default class BillingService {
}
const filteredRequest = BillingSecurity.filterDownloadInvoiceRequest(req.query);
// Get the Invoice
- const invoice = await BillingStorage.getInvoiceByBillingInvoiceID(req.user.tenantID, filteredRequest.invoiceID);
+ const invoice = await BillingStorage.getInvoice(req.user.tenantID, filteredRequest.ID);
+ UtilsService.assertObjectExists(action, invoice, `Invoice ID '${filteredRequest.ID}' does not exist`,
+ MODULE_NAME, 'handleDownloadInvoice', req.user);
+ // Check if belonging to the logged user
if (!Authorizations.isAdmin(req.user) && invoice.userID.toString() !== req.user.id) {
throw new AppAuthError({
errorCode: HTTPAuthError.ERROR,
@@ -367,15 +369,15 @@ export default class BillingService {
module: MODULE_NAME, method: 'handleDownloadInvoice',
});
}
-
- const invoicepdf = await BillingStorage.getInvoiceDocument(req.user.tenantID, invoice.id);
- UtilsService.assertObjectExists(action, invoicepdf, `Invoice '${filteredRequest.invoiceID}' does not exist`,
+ // Get the Invoice Document
+ const invoiceDocument = await BillingStorage.getInvoiceDocument(req.user.tenantID, invoice.id);
+ UtilsService.assertObjectExists(action, invoiceDocument, `Invoice Document ID '${filteredRequest.ID}' does not exist`,
MODULE_NAME, 'handleDownloadInvoice', req.user);
-
- if (invoicepdf && invoicepdf.content) {
- const base64RawData = invoicepdf.content.split(';base64,').pop();
- const filename = 'invoice_' + invoice.invoiceID + '.pdf';
- fs.writeFile(filename, base64RawData, { encoding: 'base64' }, (err) => {
+ // Send the Document
+ if (invoiceDocument && invoiceDocument.content) {
+ const base64RawData = invoiceDocument.content.split(`;${invoiceDocument.encoding},`).pop();
+ const filename = 'invoice_' + invoice.id + '.' + invoiceDocument.type;
+ fs.writeFile(filename, base64RawData, { encoding: invoiceDocument.encoding }, (err) => {
if (err) {
console.log(err);
throw err;

MODIFY
src/server/rest/service/security/BillingSecurity.ts
src/server/rest/service/security/BillingSecurity.ts
-import { BillingInvoice, BillingTax } from '../../../../types/Billing';
-import { HttpDownloadInvoiceRequest, HttpForceSynchronizeUserInvoicesRequest, HttpSynchronizeUserRequest } from '../../../../types/requests/HttpUserRequest';
-
+import sanitize from 'mongo-sanitize';
import Authorizations from '../../../../authorization/Authorizations';
+import { BillingInvoice, BillingTax } from '../../../../types/Billing';
import { DataResult } from '../../../../types/DataResult';
import { HttpBillingInvoiceRequest } from '../../../../types/requests/HttpBillingRequest';
+import HttpByIDRequest from '../../../../types/requests/HttpByIDRequest';
+import { HttpForceSynchronizeUserInvoicesRequest, HttpSynchronizeUserRequest } from '../../../../types/requests/HttpUserRequest';
import UserToken from '../../../../types/UserToken';
-import UtilsSecurity from './UtilsSecurity';
-import sanitize from 'mongo-sanitize';
import UserSecurity from './UserSecurity';
+import UtilsSecurity from './UtilsSecurity';
+
export default class BillingSecurity {
static filterTaxesResponse(taxes: BillingTax[], loggedUser: UserToken): BillingTax[] {
@@ -116,9 +117,9 @@ export default class BillingSecurity {
};
}
- static filterDownloadInvoiceRequest(request: any): HttpDownloadInvoiceRequest {
+ static filterDownloadInvoiceRequest(request: any): HttpByIDRequest {
return {
- invoiceID: sanitize(request.invoiceID)
+ ID: sanitize(request.ID)
};
}
}

MODIFY
src/types/requests/HttpUserRequest.ts
src/types/requests/HttpUserRequest.ts
@@ -14,10 +14,6 @@ export interface HttpForceSynchronizeUserInvoicesRequest {
userID?: string;
}
-export interface HttpDownloadInvoiceRequest {
- invoiceID?: string;
-}
-
export interface HttpUserMobileTokenRequest {
id: string;
mobileToken: string;

Invoice should not be sent via Stripe but from e-Mobility, download invoice by e-Mobility ID, removed unused type