added rest of emails
MODIFY
file.txt
file.txt
<mjml><mj-head>
- <mj-title>Session Finished</mj-title>
+ <mj-title>New Account Created</mj-title>
<mj-font name="Roboto" href="https://fonts.googleapis.com/css?family=Roboto:300,500"></mj-font>
<mj-attributes>
<mj-all font-family="Roboto, Helvetica, sans-serif"></mj-all>
</mj-section>
<mj-section>
<mj-column>
- <mj-text font-weight="500" font-size="20px">Session Finished</mj-text>
+ <mj-text font-weight="500" font-size="20px">New Account Created</mj-text>
</mj-column>
</mj-section>
,<mj-section padding-top="20px">
<mj-column>
<mj-text>
- <p>Hello ! User,</p>
- <p>Your session on the charging station charging box id, connector connector id has just finished.</p>
+ <p>Hello 0,</p>
+ <p>An account has just been created on your behalf in tenant name organisation.<br>Click on the link bellow to create your password.<br>You will have to log in at least once to this organisation to be able to charge your car.</p>
</mj-text>
</mj-column>
</mj-section>
-,<mj-section>
- <mj-column width="70%">
- <mj-table>
- <tr><th style="font-size:18px;font-weight:300">Consumption</th><td style="font-size:18px;font-weight:400;width:50%;text-align:center">total consumption kW.h</td></tr><tr><th style="font-size:18px;font-weight:300">Total Duration</th><td style="font-size:18px;font-weight:400;width:50%;text-align:center">undefined</td></tr><tr><th style="font-size:18px;font-weight:300">State of Charge</th><td style="font-size:18px;font-weight:400;width:50%;text-align:center">undefined %</td></tr>
- </mj-table>
- </mj-column>
-</mj-section>
,<mj-section>
<mj-column>
- <mj-button background-color="#8fd365" font-size="16px" href="undefined">
- View Session
+ <mj-button background-color="#8fd365" font-size="16px" href="some_url">
+ Create Your Password
</mj-button>
</mj-column>
</mj-section>

MODIFY
src/notification/email/EMailNotificationTask.ts
src/notification/email/EMailNotificationTask.ts
@@ -82,115 +82,148 @@ export default class EMailNotificationTask implements NotificationTask {
}
public async sendEndOfSignedSession(data: EndOfSignedSessionNotification, user: User, tenant: Tenant, severity: NotificationSeverity): Promise<void> {
- return this.prepareAndSendEmail('end-of-signed-session', data, user, tenant, severity);
+ return Promise.resolve();
+ // data.buttonUrl = data.evseDashboardURL;
+ // return this.prepareAndSendEmail('end-of-signed-session', data, user, tenant, severity);
}
public async sendChargingStationStatusError(data: ChargingStationStatusErrorNotification, user: User, tenant: Tenant, severity: NotificationSeverity): Promise<void> {
+ data.buttonUrl = data.evseDashboardChargingStationURL;
return this.prepareAndSendEmail('charging-station-status-error', data, user, tenant, severity);
}
public async sendChargingStationRegistered(data: ChargingStationRegisteredNotification, user: User, tenant: Tenant, severity: NotificationSeverity): Promise<void> {
+ data.buttonUrl = data.evseDashboardChargingStationURL;
return this.prepareAndSendEmail('charging-station-registered', data, user, tenant, severity);
}
public async sendUserAccountStatusChanged(data: UserAccountStatusChangedNotification, user: User, tenant: Tenant, severity: NotificationSeverity): Promise<void> {
+ data.buttonUrl = data.evseDashboardURL;
+ data.accountStatus = data.user.status === 'A' ? 'Actived' : 'Suspended';
return this.prepareAndSendEmail('user-account-status-changed', data, user, tenant, severity);
}
public async sendUnknownUserBadged(data: UnknownUserBadgedNotification, user: User, tenant: Tenant, severity: NotificationSeverity): Promise<void> {
+ data.buttonUrl = data.evseDashboardURL;
return this.prepareAndSendEmail('unknown-user-badged', data, user, tenant, severity);
}
public async sendSessionStarted(data: TransactionStartedNotification, user: User, tenant: Tenant, severity: NotificationSeverity): Promise<void> {
+ data.buttonUrl = data.evseDashboardChargingStationURL;
return this.prepareAndSendEmail('session-started', data, user, tenant, severity);
}
public async sendVerificationEmail(data: VerificationEmailNotification, user: User, tenant: Tenant, severity: NotificationSeverity): Promise<void> {
+ data.buttonUrl = data.evseDashboardVerifyEmailURL;
return this.prepareAndSendEmail('verification-email', data, user, tenant, severity);
}
public async sendVerificationEmailUserImport(data: VerificationEmailNotification, user: User, tenant: Tenant, severity: NotificationSeverity): Promise<void> {
+ data.buttonUrl = data.evseDashboardVerifyEmailURL;
return this.prepareAndSendEmail('verification-email-user-import', data, user, tenant, severity);
}
public async sendOCPIPatchChargingStationsStatusesError(data: OCPIPatchChargingStationsStatusesErrorNotification, user: User, tenant: Tenant, severity: NotificationSeverity): Promise<void> {
+ data.buttonUrl = data.evseDashboardURL;
return this.prepareAndSendEmail('ocpi-patch-status-error', data, user, tenant, severity);
}
public async sendOICPPatchChargingStationsStatusesError(data: OICPPatchChargingStationsStatusesErrorNotification, user: User, tenant: Tenant, severity: NotificationSeverity): Promise<void> {
+ data.buttonUrl = data.evseDashboardURL;
return this.prepareAndSendEmail('oicp-patch-status-error', data, user, tenant, severity);
}
public async sendOICPPatchChargingStationsError(data: OICPPatchChargingStationsErrorNotification, user: User, tenant: Tenant, severity: NotificationSeverity): Promise<void> {
+ data.buttonUrl = data.evseDashboardURL;
return this.prepareAndSendEmail('oicp-patch-evses-error', data, user, tenant, severity);
}
public async sendUserAccountInactivity(data: UserAccountInactivityNotification, user: User, tenant: Tenant, severity: NotificationSeverity): Promise<void> {
+ data.buttonUrl = data.evseDashboardURL;
return this.prepareAndSendEmail('user-account-inactivity', data, user, tenant, severity);
}
public async sendPreparingSessionNotStarted(data: PreparingSessionNotStartedNotification, user: User, tenant: Tenant, severity: NotificationSeverity): Promise<void> {
+ data.buttonUrl = data.evseDashboardChargingStationURL;
return this.prepareAndSendEmail('session-not-started', data, user, tenant, severity);
}
public async sendSessionNotStarted(data: SessionNotStartedNotification, user: User, tenant: Tenant, severity: NotificationSeverity): Promise<void> {
+ data.buttonUrl = data.evseDashboardChargingStationURL;
return this.prepareAndSendEmail('session-not-started-after-authorize', data, user, tenant, severity);
}
public async sendOfflineChargingStations(data: OfflineChargingStationNotification, user: User, tenant: Tenant, severity: NotificationSeverity): Promise<void> {
+ data.chargeBoxIDsNumber = data.chargeBoxIDs.length;
+ data.appUrl = data.evseDashboardURL;
return this.prepareAndSendEmail('offline-charging-station', data, user, tenant, severity);
}
public async sendBillingSynchronizationFailed(data: BillingUserSynchronizationFailedNotification, user: User, tenant: Tenant, severity: NotificationSeverity): Promise<void> {
+ data.buttonUrl = data.evseDashboardBillingURL;
return this.prepareAndSendEmail('billing-user-synchronization-failed', data, user, tenant, severity);
}
public async sendBillingInvoiceSynchronizationFailed(data: BillingInvoiceSynchronizationFailedNotification, user: User, tenant: Tenant, severity: NotificationSeverity): Promise<void> {
+ data.buttonUrl = data.evseDashboardBillingURL;
return this.prepareAndSendEmail('billing-invoice-synchronization-failed', data, user, tenant, severity);
}
public async sendBillingPeriodicOperationFailed(data: BillingInvoiceSynchronizationFailedNotification, user: User, tenant: Tenant, severity: NotificationSeverity): Promise<void> {
+ data.buttonUrl = data.evseDashboardBillingURL;
return this.prepareAndSendEmail('billing-periodic-operation-failed', data, user, tenant, severity);
}
public async sendBillingAccountCreationLink(data: BillingAccountCreationLinkNotification, user: User, tenant: Tenant, severity: NotificationSeverity): Promise<void> {
+ data.appUrl = data.onboardingLink;
return this.prepareAndSendEmail('billing-account-created', data, user, tenant, severity);
}
public async sendBillingAccountActivationNotification(data: BillingAccountActivationNotification, user: User, tenant: Tenant, severity: NotificationSeverity): Promise<void> {
+ data.buttonUrl = data.evseDashboardURL;
return this.prepareAndSendEmail('billing-account-activated', data, user, tenant, severity);
}
public async sendBillingNewInvoice(data: BillingNewInvoiceNotification, user: User, tenant: Tenant, severity: NotificationSeverity): Promise<void> {
- data.buttonUrl = data.evseDashboardInvoiceURL;
const optionalComponents = await EmailComponentManager.getComponent(EmailComponent.TABLE);
if (data.invoiceStatus === 'paid') {
+ data.buttonUrl = data.invoiceDownloadUrl;
return await this.prepareAndSendEmail('billing-new-invoice-paid', data, user, tenant, severity,false,optionalComponents);
}
+ data.buttonUrl = data.payInvoiceUrl;
return await this.prepareAndSendEmail('billing-new-invoice-unpaid', data, user, tenant, severity,false,optionalComponents);
}
public async sendCarCatalogSynchronizationFailed(data: CarCatalogSynchronizationFailedNotification, user: User, tenant: Tenant, severity: NotificationSeverity): Promise<void> {
+ data.buttonUrl = data.evseDashboardURL;
return this.prepareAndSendEmail('car-synchronization-failed', data, user, tenant, severity);
}
public async sendComputeAndApplyChargingProfilesFailed(data: ComputeAndApplyChargingProfilesFailedNotification, user: User, tenant: Tenant, severity: NotificationSeverity): Promise<void> {
+ data.buttonUrl = data.evseDashboardURL;
return this.prepareAndSendEmail('compute-and-apply-charging-profiles-failed', data, user, tenant, severity);
}
public async sendEndUserErrorNotification(data: EndUserErrorNotification, user: User, tenant: Tenant, severity: NotificationSeverity): Promise<void> {
+ data.buttonUrl = data.evseDashboardURL;
return this.prepareAndSendEmail('end-user-error-notification', data, user, tenant, severity);
}
public async sendAccountVerificationNotification(data: AccountVerificationNotification, user: User, tenant: Tenant, severity: NotificationSeverity): Promise<void> {
+ data.buttonUrl = data.evseDashboardURL;
+ data.accountStatus = data.userStatus === 'A' ? 'and Activated' : '';
+ data.accountStatus2 = data.userStatus === 'I' ? 'An Administrator will check and activate your account' : '';
return this.prepareAndSendEmail('account-verification-notification', data, user, tenant, severity);
}
public async sendAdminAccountVerificationNotification(data: AdminAccountVerificationNotification, user: User, tenant: Tenant, severity: NotificationSeverity): Promise<void> {
+ data.buttonUrl = data.evseUserToVerifyURL;
+ data.email = data.user.email;
return this.prepareAndSendEmail('admin-account-verification-notification', data, user, tenant, severity);
}
public async sendUserCreatePassword(data: UserCreatePassword, user: User, tenant: Tenant, severity: NotificationSeverity): Promise<void> {
+ data.buttonUrl = data.evseDashboardCreatePasswordURL;
return this.prepareAndSendEmail('user-create-password', data, user, tenant, severity);
}
@@ -325,7 +358,11 @@ export default class EMailNotificationTask implements NotificationTask {
});
}
context.appUrl = context.appUrl || 'https://open-e-mobility.io/';
- context.userFirstName = context.user.firstName || context.user.name;
+ if (context.user) {
+ context.userFirstName = context.user.firstName | context.user.name;
+ } else {
+ context.userFirstName = 'Admin';
+ }
context.tenantLogoURL = tenant.logo;
const i18nInstance = I18nManager.getInstanceForLocale(user.locale);
const template = (await mjmlBuilder.initialize())

MODIFY
src/notification/email/mjml-template/MjmlTemplate.ts
src/notification/email/mjml-template/MjmlTemplate.ts
@@ -24,7 +24,7 @@ export default class MjmlTemplate {
for (const selector of i18nSelectors) {
let value = i18nManager.translate(selector,context);
if (Array.isArray(value)) {
- value = value.join('</br>');
+ value = value.join('<br>');
}
this.replace(selector, value);
}

MODIFY
src/types/UserNotifications.ts
src/types/UserNotifications.ts
@@ -102,6 +102,10 @@ export interface BaseNotification {
appUrl?:string;
userFirstName?:string;
tableValues?:string[];
+ chargeBoxIDsNumber?:number;
+ accountStatus?:string;
+ accountStatus2?:string;
+ email?:string;
}
export interface EndOfChargeNotification extends BaseNotification {

MODIFY
test/api/EmailTest.ts
test/api/EmailTest.ts
-import { BillingAccountActivationNotification, BillingAccountCreationLinkNotification, BillingNewInvoiceNotification, ChargingStationRegisteredNotification, ChargingStationStatusErrorNotification, EndOfChargeNotification, EndOfSessionNotification, EndOfSignedSessionNotification, EndUserErrorNotification, NewRegisteredUserNotification, NotificationSeverity, OfflineChargingStationNotification, OptimalChargeReachedNotification, RequestPasswordNotification } from '../../src/types/UserNotifications';
+import { AccountVerificationNotification, AdminAccountVerificationNotification, BillingAccountActivationNotification, BillingAccountCreationLinkNotification, BillingInvoiceSynchronizationFailedNotification, BillingNewInvoiceNotification, BillingPeriodicOperationFailedNotification, BillingUserSynchronizationFailedNotification, CarCatalogSynchronizationFailedNotification, ChargingStationRegisteredNotification, ChargingStationStatusErrorNotification, ComputeAndApplyChargingProfilesFailedNotification, EndOfChargeNotification, EndOfSessionNotification, EndOfSignedSessionNotification, EndUserErrorNotification, NewRegisteredUserNotification, NotificationSeverity, OCPIPatchChargingStationsStatusesErrorNotification, OICPPatchChargingStationsErrorNotification, OICPPatchChargingStationsStatusesErrorNotification, OfflineChargingStationNotification, OptimalChargeReachedNotification, PreparingSessionNotStartedNotification, RequestPasswordNotification, SessionNotStartedNotification, TransactionStartedNotification, UnknownUserBadgedNotification, UserAccountInactivityNotification, UserAccountStatusChangedNotification, UserCreatePassword, VerificationEmailNotification } from '../../src/types/UserNotifications';
import ContextDefinition from './context/ContextDefinition';
import ContextProvider from './context/ContextProvider';
@@ -117,7 +117,7 @@ describe('Initialization', () => {
await emailNotificationTask.sendEndOfSession(data,user,tenant,severity);
});
- it('billing-new-invoice', async () => {
+ it('billing-new-invoice-paid', async () => {
data = {
evseDashboardURL: 'some_url',
evseDashboardInvoiceURL: 'some_url',
@@ -126,7 +126,21 @@ describe('Initialization', () => {
payInvoiceUrl: 'some_url',
invoiceNumber: '123123123',
invoiceAmount: '1200',
- invoiceStatus: 'active',
+ invoiceStatus: 'paid',
+ } as BillingNewInvoiceNotification;
+ await emailNotificationTask.sendBillingNewInvoice(data,user,tenant,severity);
+ });
+
+ it('billing-new-invoice-unpaid', async () => {
+ data = {
+ evseDashboardURL: 'some_url',
+ evseDashboardInvoiceURL: 'some_url',
+ user,
+ invoiceDownloadUrl: 'some_url',
+ payInvoiceUrl: 'https://open-e-mobility.io/',
+ invoiceNumber: '123123123',
+ invoiceAmount: '1200',
+ invoiceStatus: 'unpaid',
} as BillingNewInvoiceNotification;
await emailNotificationTask.sendBillingNewInvoice(data,user,tenant,severity);
});
@@ -164,7 +178,7 @@ describe('Initialization', () => {
await emailNotificationTask.sendOfflineChargingStations(data,user,tenant,severity);
});
- it('charging-station-charging-error', async () => {
+ it('charging-station-status-error', async () => {
data = {
chargeBoxID: 'some box id',
siteID: 'site id',
@@ -179,12 +193,232 @@ describe('Initialization', () => {
});
it('billing-account-created', async () => {
+ data = {
+ evseDashboardURL: 'some_url',
+ user,
+ } as BillingAccountCreationLinkNotification;
+ await emailNotificationTask.sendBillingAccountCreationLink(data,user,tenant,severity);
+ });
+
+ // it('end-of-signed-session', async () => {
+ // data = {
+ // user,
+ // alternateUser: user,
+ // transactionId: 10,
+ // chargeBoxID: 'charge box id',
+ // connectorId: 'connector id',
+ // tagId: 'tag id',
+ // startDate: 'start date',
+ // endDate: 'end date',
+ // meterStart: 'meter date',
+ // meterStop: 'meter stop',
+ // totalConsumption: 'total consumption',
+ // price:10,
+ // relativeCost: 10,
+ // startSignedData: 'start signed date',
+ // endSignedData: 'end signed date',
+ // evseDashboardURL: 'some_url',
+ // } as EndOfSignedSessionNotification;
+ // await emailNotificationTask.sendEndOfSignedSession(data,user,tenant,severity);
+ // });
+
+ it('user-account-status-changed', async () => {
+ data = {
+ user,
+ evseDashboardURL: 'some_url',
+ } as UserAccountStatusChangedNotification;
+ await emailNotificationTask.sendUserAccountStatusChanged(data,user,tenant,severity);
+ });
+
+ it('unknown-user-badged', async () => {
+ data = {
+ chargeBoxID: 'charge box id',
+ siteID: 'site id',
+ siteAreaID: 'site area id',
+ companyID: 'company id',
+ badgeID: 'badge id',
+ evseDashboardURL: 'some_url',
+ } as UnknownUserBadgedNotification;
+ await emailNotificationTask.sendUnknownUserBadged(data,user,tenant,severity);
+ });
+
+ it('session-started', async () => {
+ data = {
+ user,
+ transactionId: 14,
+ siteID: 'site id',
+ siteAreaID: 'site area id',
+ companyID: 'company id',
+ chargeBoxID: 'charge box id',
+ connectorId: 'connector id',
+ evseDashboardURL: 'some_url',
+ evseDashboardChargingStationURL: 'some_url',
+ } as TransactionStartedNotification;
+ await emailNotificationTask.sendSessionStarted(data,user,tenant,severity);
+ });
+
+ it('verification-email', async () => {
+ data = {
+ user,
+ tenantName: 'tenant name',
+ evseDashboardURL: 'some_url',
+ evseDashboardVerifyEmailURL: 'some_url',
+ } as VerificationEmailNotification;
+ await emailNotificationTask.sendVerificationEmail(data,user,tenant,severity);
+ });
+
+ it('verification-email-user-import', async () => {
+ data = {
+ user,
+ tenantName: 'tenant name',
+ evseDashboardURL: 'some_url',
+ evseDashboardVerifyEmailURL: 'some_url',
+ } as VerificationEmailNotification;
+ await emailNotificationTask.sendVerificationEmailUserImport(data,user,tenant,severity);
+ });
+
+ it('ocpi-patch-status-error', async () => {
+ data = {
+ evseDashboardURL: 'some_url',
+ location: 'location'
+ } as OCPIPatchChargingStationsStatusesErrorNotification;
+ await emailNotificationTask.sendOCPIPatchChargingStationsStatusesError(data,user,tenant,severity);
+ });
+
+ it('oicp-patch-status-error', async () => {
+ data = {
+ evseDashboardURL: 'some_url',
+ location: 'location',
+ } as OICPPatchChargingStationsStatusesErrorNotification;
+ await emailNotificationTask.sendOICPPatchChargingStationsStatusesError(data,user,tenant,severity);
+ });
+
+ it('oicp-patch-evses-error', async () => {
+ data = {
+ evseDashboardURL: 'some_url',
+ } as OICPPatchChargingStationsErrorNotification;
+ await emailNotificationTask.sendOICPPatchChargingStationsError(data,user,tenant,severity);
+ });
+
+ it('user-account-inactivity', async () => {
+ data = {
+ user,
+ lastLogin: 'last login',
+ evseDashboardURL: 'some_url',
+ } as UserAccountInactivityNotification;
+ await emailNotificationTask.sendUserAccountInactivity(data,user,tenant,severity);
+ });
+
+ it('session-not-started', async () => {
+ data = {
+ user,
+ chargeBoxID :'charge box id',
+ siteID: 'site id',
+ siteAreaID: 'site area id',
+ companyID: 'company id',
+ connectorId: 'connector id',
+ startedOn: 'started on',
+ evseDashboardURL: 'some_url',
+ evseDashboardChargingStationURL: 'some_url',
+ } as PreparingSessionNotStartedNotification;
+ await emailNotificationTask.sendPreparingSessionNotStarted(data,user,tenant,severity);
+ });
+
+ it('session-not-started-after-authorize', async () => {
+ data = {
+ chargeBoxID: 'charge box id',
+ siteID: 'site id',
+ siteAreaID: 'site area id',
+ companyID: 'company id',
+ user,
+ evseDashboardURL: 'some_url',
+ evseDashboardChargingStationURL: 'some_url',
+ } as SessionNotStartedNotification;
+ await emailNotificationTask.sendSessionNotStarted(data,user,tenant,severity);
+ });
+
+ it('billing-user-synchronization-failed', async () => {
+ data = {
+ nbrUsersInError: 123,
+ evseDashboardURL: 'some_url',
+ evseDashboardBillingURL: 'some_url',
+ } as BillingUserSynchronizationFailedNotification;
+ await emailNotificationTask.sendBillingInvoiceSynchronizationFailed(data,user,tenant,severity);
+ });
+
+ it('billing-invoice-synchronization-failed', async () => {
+ data = {
+ nbrInvoicesInError: 123,
+ evseDashboardURL: 'some_url',
+ evseDashboardBillingURL: 'some_url',
+ } as BillingInvoiceSynchronizationFailedNotification;
+ await emailNotificationTask.sendBillingInvoiceSynchronizationFailed(data,user,tenant,severity);
+ });
+
+ it('billing-periodic-operation-failed', async () => {
+ data = {
+ nbrInvoicesInError: 123,
+ evseDashboardURL: 'some_url',
+ evseDashboardBillingURL: 'some_url',
+ } as BillingPeriodicOperationFailedNotification;
+ await emailNotificationTask.sendBillingPeriodicOperationFailed(data,user,tenant,severity);
+ });
+
+ it('billing-account-activated', async () => {
data = {
evseDashboardURL: 'some_url',
user,
} as BillingAccountActivationNotification;
await emailNotificationTask.sendBillingAccountActivationNotification(data,user,tenant,severity);
});
+
+ it('car-synchronization-failed', async () => {
+ data = {
+ nbrCarsInError: 10,
+ evseDashboardURL: 'some_url',
+ } as CarCatalogSynchronizationFailedNotification;
+ await emailNotificationTask.sendCarCatalogSynchronizationFailed(data,user,tenant,severity);
+ });
+
+ it('compute-and-apply-charging-profiles-failed', async () => {
+ data = {
+ siteAreaName: 'site area name',
+ chargeBoxID: 'charge box id',
+ siteID: 'site id',
+ siteAreaID: 'site area id',
+ companyID: 'company id',
+ evseDashboardURL: 'some_url',
+ } as ComputeAndApplyChargingProfilesFailedNotification;
+ await emailNotificationTask.sendComputeAndApplyChargingProfilesFailed(data,user,tenant,severity);
+ });
+
+ it('account-verification-notification', async () => {
+ data = {
+ user,
+ userStatus: 'A',
+ evseDashboardURL: 'some_url',
+ } as AccountVerificationNotification;
+ await emailNotificationTask.sendAccountVerificationNotification(data,user,tenant,severity);
+ });
+
+ it('admin-account-verification-notification', async () => {
+ data = {
+ user,
+ evseDashboardURL: 'some_url',
+ evseUserToVerifyURL: 'some_url',
+ } as AdminAccountVerificationNotification;
+ await emailNotificationTask.sendAdminAccountVerificationNotification(data,user,tenant,severity);
+ });
+
+ it('user-create-password', async () => {
+ data = {
+ user,
+ tenantName: 'tenant name',
+ evseDashboardURL: 'some_url',
+ evseDashboardCreatePasswordURL: 'some_url',
+ } as UserCreatePassword;
+ await emailNotificationTask.sendUserCreatePassword(data,user,tenant,severity);
+ });
});
});

added rest of emails