// src/infrastructure/repositories/SequelizeRequisitionRepository.js
const RequisitionRepository = require('../../domain/requisitionManagement/repositories/RequisitionRepository');
const Requisition = require('../../domain/requisitionManagement/entities/Requisition');
const RequisitionItem = require('../../domain/requisitionManagement/entities/RequisitionItem');
const RequisitionApprover = require('../../domain/requisitionManagement/entities/RequisitionApprover');
class SequelizeRequisitionRepository extends RequisitionRepository {
constructor(models, eventBus) {
super();
this.requisitionModel = models.requisitionModel;
this.requisitionItemModel = models.requisitionItemListModel;
this.requisitionApproverModel = models.requisitionApproverModel;
this.eventBus = eventBus;
}
async findById(id) {
const requisitionData = await this.requisitionModel.findByPk(id, {
include: [
{
model: this.requisitionItemModel,
as: 'requisitionItemLists',
},
{
model: this.requisitionApproverModel,
as: 'requisitionApprovers',
},
],
});
if (!requisitionData) {
return null;
}
return this._toDomain(requisitionData);
}
async save(requisition) {
const transaction = await this.requisitionModel.sequelize.transaction();
try {
const requisitionData = this._toPersistence(requisition);
let savedRequisition;
if (requisition.id) {
// Update existing requisition
await this.requisitionModel.update(
requisitionData,
{
where: { id: requisition.id },
transaction,
}
);
// Update items
for (const item of requisition.items) {
if (item.id) {
await this.requisitionItemModel.update(
this._itemToPersistence(item),
{
where: { id: item.id },
transaction,
}
);
} else {
const savedItem = await this.requisitionItemModel.create(
{
...this._itemToPersistence(item),
requisitionId: requisition.id,
},
{ transaction }
);
item.id = savedItem.id;
}
}
// Update approvers
for (const approver of requisition.approvers) {
if (approver.id) {
await this.requisitionApproverModel.update(
this._approverToPersistence(approver),
{
where: { id: approver.id },
transaction,
}
);
} else {
const savedApprover = await this.requisitionApproverModel.create(
{
...this._approverToPersistence(approver),
requisitionId: requisition.id,
},
{ transaction }
);
approver.id = savedApprover.id;
}
}
savedRequisition = await this.requisitionModel.findByPk(
requisition.id,
{
include: [
{
model: this.requisitionItemModel,
as: 'requisitionItemLists',
},
{
model: this.requisitionApproverModel,
as: 'requisitionApprovers',
},
],
transaction,
}
);
} else {
// Create new requisition
savedRequisition = await this.requisitionModel.create(
requisitionData,
{ transaction }
);
requisition.id = savedRequisition.id;
// Create items
for (const item of requisition.items) {
const savedItem = await this.requisitionItemModel.create(
{
...this._itemToPersistence(item),
requisitionId: requisition.id,
},
{ transaction }
);
item.id = savedItem.id;
}
// Create approvers
for (const approver of requisition.approvers) {
const savedApprover = await this.requisitionApproverModel.create(
{
...this._approverToPersistence(approver),
requisitionId: requisition.id,
},
{ transaction }
);
approver.id = savedApprover.id;
}
savedRequisition = await this.requisitionModel.findByPk(
requisition.id,
{
include: [
{
model: this.requisitionItemModel,
as: 'requisitionItemLists',
},
{
model: this.requisitionApproverModel,
as: 'requisitionApprovers',
},
],
transaction,
}
);
}
await transaction.commit();
return this._toDomain(savedRequisition);
} catch (error) {
await transaction.rollback();
throw error;
}
}
// Private methods to map between domain and persistence
_toDomain(data) {
const items = data.requisitionItemLists?.map(item =>
new RequisitionItem({
id: item.id,
itemId: item.itemId,
quantity: item.quantity,
unit: item.unit,
description: item.description,
})
) || [];
const approvers = data.requisitionApprovers?.map(approver =>
new RequisitionApprover({
id: approver.id,
userId: approver.userId,
status: approver.status,
level: approver.level,
})
) || [];
return Requisition.reconstitute({
id: data.id,
rsNumber: data.rsNumber,
rsLetter: data.rsLetter,
companyCode: data.companyCode,
createdBy: data.createdBy,
companyId: data.companyId,
departmentId: data.departmentId,
projectId: data.projectId,
dateRequired: data.dateRequired,
deliveryAddress: data.deliveryAddress,
purpose: data.purpose,
status: data.status,
type: data.type,
items,
approvers,
});
}
_toPersistence(domain) {
return {
id: domain.id,
rsNumber: domain.rsNumber,
rsLetter: domain.rsLetter,
companyCode: domain.companyCode,
createdBy: domain.createdBy,
companyId: domain.companyId,
departmentId: domain.departmentId,
projectId: domain.projectId,
dateRequired: domain.dateRequired,
deliveryAddress: domain.deliveryAddress,
purpose: domain.purpose,
status: domain.status.value,
type: domain.type,
};
}
_itemToPersistence(item) {
return {
id: item.id,
itemId: item.itemId,
quantity: item.quantity,
unit: item.unit,
description: item.description,
};
}
_approverToPersistence(approver) {
return {
id: approver.id,
userId: approver.userId,
status: approver.status,
level: approver.level,
};
}
}
module.exports = SequelizeRequisitionRepository;