@citrineos/data
Version:
The OCPP data module which includes all persistence layer implementation.
155 lines • 7.15 kB
JavaScript
// SPDX-FileCopyrightText: 2025 Contributors to the CitrineOS Project
//
// SPDX-License-Identifier: Apache-2.0
import { CrudRepository, OCPP2_0_1 } from '@citrineos/base';
import { SequelizeRepository } from './Base.js';
import { ChargingNeeds, ChargingProfile, ChargingSchedule, CompositeSchedule, Evse, EvseType, SalesTariff, Transaction, } from '../model/index.js';
import { Sequelize } from 'sequelize-typescript';
import { Logger } from 'tslog';
export class SequelizeChargingProfileRepository extends SequelizeRepository {
chargingNeeds;
chargingSchedule;
salesTariff;
transaction;
evse;
compositeSchedule;
constructor(config, logger, sequelizeInstance, chargingNeeds, chargingSchedule, salesTariff, transaction, evse, compositeSchedule) {
super(config, ChargingProfile.MODEL_NAME, logger, sequelizeInstance);
this.chargingNeeds = chargingNeeds
? chargingNeeds
: new SequelizeRepository(config, ChargingNeeds.MODEL_NAME, logger, sequelizeInstance);
this.chargingSchedule = chargingSchedule
? chargingSchedule
: new SequelizeRepository(config, ChargingSchedule.MODEL_NAME, logger, sequelizeInstance);
this.evse = evse
? evse
: new SequelizeRepository(config, EvseType.MODEL_NAME, logger, sequelizeInstance);
this.salesTariff = salesTariff
? salesTariff
: new SequelizeRepository(config, SalesTariff.MODEL_NAME, logger, sequelizeInstance);
this.transaction = transaction
? transaction
: new SequelizeRepository(config, Transaction.MODEL_NAME, logger, sequelizeInstance);
this.compositeSchedule = compositeSchedule
? compositeSchedule
: new SequelizeRepository(config, CompositeSchedule.MODEL_NAME, logger, sequelizeInstance);
}
async createOrUpdateChargingProfile(tenantId, chargingProfile, stationId, evseId, chargingLimitSource, isActive) {
let transactionDBId;
if (chargingProfile.transactionId) {
const activeTransaction = await Transaction.findOne({
where: {
stationId,
transactionId: chargingProfile.transactionId,
},
});
transactionDBId = activeTransaction?.id;
}
const [savedChargingProfile, profileCreated] = await this.readOrCreateByQuery(tenantId, {
where: {
tenantId: tenantId,
stationId: stationId,
id: chargingProfile.id,
},
defaults: {
...chargingProfile,
evseId: evseId,
transactionDatabaseId: transactionDBId,
chargingLimitSource: chargingLimitSource ?? OCPP2_0_1.ChargingLimitSourceEnumType.CSO,
isActive: isActive === undefined ? false : isActive,
},
});
if (!profileCreated) {
await this.updateByKey(tenantId, {
...chargingProfile,
chargingSchedule: chargingProfile.chargingSchedule.map((s) => ({ ...s })),
stationId: stationId,
transactionDatabaseId: transactionDBId,
evseId: evseId,
chargingLimitSource: chargingLimitSource ?? OCPP2_0_1.ChargingLimitSourceEnumType.CSO,
isActive: isActive === undefined ? false : isActive,
}, savedChargingProfile.databaseId.toString());
// delete existed charging schedules and sales tariff
const deletedChargingSchedules = await this.chargingSchedule.deleteAllByQuery(tenantId, {
where: {
chargingProfileDatabaseId: savedChargingProfile.databaseId,
},
});
for (const deletedSchedule of deletedChargingSchedules) {
await this.salesTariff.deleteAllByQuery(tenantId, {
where: {
chargingScheduleDatabaseId: deletedSchedule.databaseId,
},
});
}
}
for (const chargingSchedule of chargingProfile.chargingSchedule) {
const savedChargingSchedule = await this.chargingSchedule.create(tenantId, ChargingSchedule.build({
tenantId,
stationId,
chargingProfileDatabaseId: savedChargingProfile.databaseId,
...chargingSchedule,
}));
if (chargingSchedule.salesTariff) {
await this.salesTariff.create(tenantId, SalesTariff.build({
tenantId,
chargingScheduleDatabaseId: savedChargingSchedule.databaseId,
...chargingSchedule.salesTariff,
}));
}
}
return savedChargingProfile;
}
async createChargingNeeds(tenantId, chargingNeedsReq, stationId) {
const activeTransaction = await Transaction.findOne({
where: {
stationId,
isActive: true,
},
include: [{ model: Evse, where: { evseTypeId: chargingNeedsReq.evseId }, required: true }],
});
if (!activeTransaction) {
throw new Error(`No active transaction found on station ${stationId} evse ${chargingNeedsReq.evseId}`);
}
return await this.chargingNeeds.create(tenantId, ChargingNeeds.build({
tenantId,
...chargingNeedsReq.chargingNeeds,
evseId: activeTransaction.evseId,
transactionDatabaseId: activeTransaction.id,
maxScheduleTuples: chargingNeedsReq.maxScheduleTuples,
}));
}
async findChargingNeedsByEvseDBIdAndTransactionDBId(tenantId, evseDBId, transactionDataBaseId) {
const chargingNeedsArray = await this.chargingNeeds.readAllByQuery(tenantId, {
where: {
evseId: evseDBId,
transactionDatabaseId: transactionDataBaseId,
},
order: [['createdAt', 'DESC']],
});
return chargingNeedsArray.length > 0 ? chargingNeedsArray[0] : undefined;
}
async createCompositeSchedule(tenantId, compositeSchedule, stationId) {
return await this.compositeSchedule.create(tenantId, CompositeSchedule.build({
tenantId,
...compositeSchedule,
stationId,
}));
}
async getNextChargingScheduleId(tenantId, stationId) {
return await this.chargingSchedule.readNextValue(tenantId, 'id', { where: { stationId } });
}
async getNextChargingProfileId(tenantId, stationId) {
return await this.readNextValue(tenantId, 'id', { where: { stationId } });
}
async getNextStackLevel(tenantId, stationId, transactionDatabaseId, profilePurpose) {
return await this.readNextValue(tenantId, 'stackLevel', {
where: {
stationId,
transactionDatabaseId: transactionDatabaseId,
chargingProfilePurpose: profilePurpose,
},
}, 0);
}
}
//# sourceMappingURL=ChargingProfile.js.map