szenarien

This commit is contained in:
Bastian Wagner
2026-07-21 09:07:11 +02:00
parent bf830f825d
commit bbe60752cd
6 changed files with 210 additions and 43 deletions

View File

@@ -281,27 +281,38 @@ export class FurnitureService {
await this.access.require(projectId, userId, 'edit');
await this.owned(this.furniture.requirements, projectId, requirementId);
await this.validateOptionLinks(projectId, dto.budgetCategoryId);
const totalPrice = this.total(dto);
const saved = await this.furniture.options.save(
this.furniture.options.create({
...this.optionValues(dto),
return this.dataSource.transaction(async (manager) => {
const options = manager.getRepository(FurnitureOptionEntity);
const saved = await options.save(
options.create({
...this.optionValues(dto),
projectId,
requirementId,
totalPrice: this.total(dto),
currentlySelected: false,
createdByUserId: userId,
}),
);
await manager
.getRepository(FurnitureRequirementEntity)
.update(
{ id: requirementId, projectId },
{ status: FurnitureRequirementStatus.HasOptions },
);
await this.refreshAutomaticScenarios(projectId, manager);
await this.activity(
projectId,
requirementId,
totalPrice,
currentlySelected: false,
createdByUserId: userId,
}),
);
await this.furniture.requirements.update(
{ id: requirementId, projectId },
{ status: FurnitureRequirementStatus.HasOptions },
);
await this.activity(projectId, userId, 'furniture.option-created', {
requirementId,
optionId: saved.id,
name: saved.name,
userId,
'furniture.option-created',
{
requirementId,
optionId: saved.id,
name: saved.name,
},
manager,
);
return saved;
});
return saved;
}
async updateOption(
projectId: string,
@@ -725,12 +736,27 @@ export class FurnitureService {
}
async deleteScenario(projectId: string, id: string, userId: string) {
await this.access.require(projectId, userId, 'edit');
const scenario = await this.owned(this.furniture.scenarios, projectId, id);
if (scenario.isDefault)
this.conflict(
'Das Standardszenario kann nicht archiviert werden. Legen Sie zuerst ein anderes Standardszenario fest.',
await this.owned(this.furniture.scenarios, projectId, id);
await this.dataSource.transaction(async (manager) => {
const scenarios = manager.getRepository(FurnitureScenarioEntity);
const scenario = await scenarios.findOneByOrFail({ id, projectId });
await scenarios.softDelete({ id, projectId });
if (scenario.isDefault) {
const replacement = await scenarios.findOne({
where: { projectId, deletedAt: IsNull() },
order: { createdAt: 'ASC' },
});
if (replacement)
await scenarios.update({ id: replacement.id }, { isDefault: true });
}
await this.activity(
projectId,
userId,
'furniture.scenario-deleted',
{ scenarioId: id },
manager,
);
await this.furniture.scenarios.softDelete({ id, projectId });
});
}
async updateSelections(
projectId: string,
@@ -1134,6 +1160,35 @@ export class FurnitureService {
}
await selectionRepo.save(selections);
}
private async refreshAutomaticScenarios(
projectId: string,
manager: EntityManager,
) {
const scenarios = await manager
.getRepository(FurnitureScenarioEntity)
.find({
where: { projectId, deletedAt: IsNull() },
});
const selectionRepo = manager.getRepository(
FurnitureScenarioSelectionEntity,
);
for (const scenario of scenarios) {
if (
![
FurnitureScenarioType.Budget,
FurnitureScenarioType.Preferred,
FurnitureScenarioType.Premium,
FurnitureScenarioType.Existing,
].includes(scenario.type)
)
continue;
await selectionRepo.delete({ projectId, scenarioId: scenario.id });
await this.autoSelections(projectId, scenario.id, scenario.type, manager);
scenario.version += 1;
await manager.getRepository(FurnitureScenarioEntity).save(scenario);
}
}
private optionValues(dto: CreateFurnitureOptionDto) {
const text = (value?: string) => value?.trim() || null;
const decimal = (value?: number | null) =>