Skip to content

Commit c67493f

Browse files
committed
add ConvertComputation use case and update plan creation logic
1 parent 6a08d4b commit c67493f

9 files changed

Lines changed: 143 additions & 5 deletions

File tree

src/adapters/controllers/PlanController.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
EditLongitudinalProfileParameters,
2424
EditLongitudinalProfileParametersRequest,
2525
} from '@use-cases/plan/EditLongitudinalProfileParameters';
26+
import { ConvertComputation, ConvertComputationRequest } from '@use-cases/plan/ConvertComputation';
2627

2728
export class PlanController {
2829
constructor(
@@ -41,6 +42,7 @@ export class PlanController {
4142
private readonly editTopoBoundaryUseCase: EditTopoBoundary,
4243
private readonly editTopoSettingUseCase: EditTopoSetting,
4344
private readonly editLongitudinalProfileParametersUseCase: EditLongitudinalProfileParameters,
45+
private readonly convertComputationUseCase: ConvertComputation,
4446
) {}
4547

4648
async createPlan(
@@ -319,13 +321,18 @@ export class PlanController {
319321
req: HttpRequest<undefined, { project_id: string }, undefined, Record<string, string>, AuthenticateResponse>,
320322
): Promise<HttpResponse<Plan[] | Error>> {
321323
try {
322-
const repoOptions: RepoOptions = parseQuery(req.query!, ['type'], ['created_at', 'updated_at']);
324+
const repoOptions: RepoOptions = parseQuery(
325+
req.query!,
326+
['type', 'bool-computation_only'],
327+
['created_at', 'updated_at'],
328+
);
323329
repoOptions.filter = repoOptions.filter ?? {};
324330
repoOptions.filter['user'] = req.user!.id;
325331
repoOptions.projection = {
326332
id: 1,
327333
name: 1,
328334
type: 1,
335+
computation_only: 1,
329336
created_at: 1,
330337
updated_at: 1,
331338
};
@@ -474,4 +481,27 @@ export class PlanController {
474481
return handleError(e);
475482
}
476483
}
484+
485+
async convertComputation(
486+
req: HttpRequest<ConvertComputationRequest, { plan_id: string }, undefined, undefined, AuthenticateResponse>,
487+
): Promise<HttpResponse<void | Error>> {
488+
try {
489+
const error = PlanValidator.validateConvertComputation(req.body);
490+
if (error) {
491+
return badRequest(error);
492+
}
493+
494+
await this.convertComputationUseCase.execute({
495+
...req.body!,
496+
plan_id: req.params!.plan_id,
497+
options: {
498+
filter: { user: req.user!.id },
499+
},
500+
});
501+
502+
return noContent();
503+
} catch (e) {
504+
return handleError(e);
505+
}
506+
}
477507
}

src/adapters/validators/PlanValidator.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ export class PlanValidator {
66
const rules = {
77
project: 'required|string',
88
name: 'required|string',
9-
type: `required|in:${Object.values(PlanType)}`,
9+
computation_only: `required|boolean`,
10+
// type: `required_if:computation_only,false|in:${Object.values(PlanType)}`,
11+
type: [{ required_if: ['computation_only', false] }],
1012
};
1113

1214
try {
@@ -277,4 +279,18 @@ export class PlanValidator {
277279

278280
return null;
279281
}
282+
283+
static validateConvertComputation(data: any): Error | null {
284+
const rules = {
285+
type: `required|in:${Object.values(PlanType)}`,
286+
};
287+
288+
try {
289+
validator.validate(data, rules);
290+
} catch (e) {
291+
return new Error((e as Error).message);
292+
}
293+
294+
return null;
295+
}
280296
}

src/domain/entities/Plan.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ export interface PlanProps {
121121
footer_size: number;
122122
longitudinal_profile_parameters?: LongitudinalProfileParameters;
123123
dxf_version?: string; // e.g., R12, R2000
124+
computation_only: boolean;
124125
}
125126

126127
export class Plan {
@@ -172,6 +173,7 @@ export class Plan {
172173
public readonly footer_size: number;
173174
public readonly longitudinal_profile_parameters?: LongitudinalProfileParameters;
174175
public readonly dxf_version?: string; // e.g., R12, R2000
176+
public readonly computation_only: boolean;
175177

176178
constructor(props: PlanProps) {
177179
this.id = props.id;
@@ -209,5 +211,6 @@ export class Plan {
209211
this.footer_size = props.footer_size; // Default to 0.5 if not provided
210212
this.longitudinal_profile_parameters = props.longitudinal_profile_parameters;
211213
this.dxf_version = props.dxf_version; // Default to R12 if not provided
214+
this.computation_only = props.computation_only;
212215
}
213216
}

src/infrastructure/mongodb/models/Plan.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ const PlanSchema: Schema<PlanDocument> = new Schema<PlanDocument>(
185185
type: {
186186
type: String,
187187
enum: Object.values(PlanType),
188-
default: PlanType.CADASTRAL,
188+
// default: PlanType.CADASTRAL,
189189
},
190190
font: {
191191
type: String,
@@ -297,6 +297,10 @@ const PlanSchema: Schema<PlanDocument> = new Schema<PlanDocument>(
297297
type: String,
298298
default: 'R2000',
299299
},
300+
computation_only: {
301+
type: Boolean,
302+
default: false,
303+
},
300304
deleted: {
301305
type: Boolean,
302306
select: false,

src/main/config/container.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ import { EditTopoBoundary } from '@use-cases/plan/EditTopoBoundary';
5454
import { EditTopoSetting } from '@use-cases/plan/EditTopoSetting';
5555
import { GoogleAuth } from '@use-cases/auth/GoogleAuth';
5656
import { EditLongitudinalProfileParameters } from '@use-cases/plan/EditLongitudinalProfileParameters';
57+
import { ConvertComputation } from '@use-cases/plan/ConvertComputation';
5758

5859
export class Container {
5960
private instances = new Map<string, any>();
@@ -294,6 +295,12 @@ export function setupContainer(): Container {
294295
container.resolve<PlanRepositoryInterface>('PlanRepo'),
295296
);
296297
});
298+
container.register('ConvertComputationUseCase', () => {
299+
return new ConvertComputation(
300+
container.resolve<Logger>('Logger'),
301+
container.resolve<PlanRepositoryInterface>('PlanRepo'),
302+
);
303+
});
297304

298305
// Register Controllers
299306
container.register('AuthController', () => {
@@ -356,6 +363,7 @@ export function setupContainer(): Container {
356363
container.resolve('EditTopoBoundaryUseCase'),
357364
container.resolve('EditTopoSettingUseCase'),
358365
container.resolve('EditLongitudinalProfileParametersUseCase'),
366+
container.resolve('ConvertComputationUseCase'),
359367
);
360368
});
361369

src/main/routes/plan-routes.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,10 @@ export default (logger: Logger, authController: AuthController, planController:
4242
);
4343
router.get('/generate/:plan_id', expressRouteAdapter(planController.generatePlan.bind(planController)));
4444

45+
router.put(
46+
'/computation/convert/:plan_id',
47+
expressRouteAdapter(planController.convertComputation.bind(planController)),
48+
);
49+
4550
return router;
4651
};
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { Logger, RepoOptions } from '@domain/types/Common';
2+
import { LongitudinalProfileParameters, PlanType, TopographicSetting } from '@domain/entities/Plan';
3+
import { PlanRepositoryInterface } from '@domain/interfaces/repositories/PlanRepositoryInterface';
4+
import NotFoundError from '@domain/errors/NotFoundError';
5+
import BadRequestError from '@domain/errors/BadRequestError';
6+
7+
export interface ConvertComputationRequest {
8+
plan_id: string;
9+
type: PlanType;
10+
options?: RepoOptions;
11+
}
12+
13+
export class ConvertComputation {
14+
constructor(
15+
private readonly logger: Logger,
16+
private readonly planRepo: PlanRepositoryInterface,
17+
) {}
18+
19+
async execute(data: ConvertComputationRequest): Promise<void> {
20+
this.logger.debug('Convert Computation execute');
21+
22+
// get plan
23+
const plan = await this.planRepo.getPlanById(data.plan_id, data.options);
24+
if (!plan) {
25+
throw new NotFoundError('Plan not found');
26+
}
27+
28+
let topographicSetting: TopographicSetting | undefined = undefined;
29+
let longitudinalProfileParameters: LongitudinalProfileParameters | undefined = undefined;
30+
31+
if (data.type === PlanType.TOPOGRAPHIC) {
32+
topographicSetting = {
33+
show_spot_heights: true,
34+
point_label_scale: 0.2,
35+
show_contours: true,
36+
contour_interval: 0.1,
37+
major_contour: 0.5,
38+
minimum_distance: 0.1,
39+
show_contours_labels: true,
40+
contour_label_scale: 0.5,
41+
show_boundary: true,
42+
boundary_label_scale: 0.2,
43+
tin: false,
44+
grid: true,
45+
show_mesh: false,
46+
};
47+
}
48+
49+
if (data.type === PlanType.ROUTE) {
50+
longitudinalProfileParameters = {
51+
horizontal_scale: 1.0,
52+
vertical_scale: 10,
53+
profile_origin: [0.0, 0.0],
54+
station_interval: 10,
55+
elevation_interval: 1.0,
56+
starting_chainage: 0.0,
57+
};
58+
}
59+
60+
if (!plan.computation_only) {
61+
throw new BadRequestError('Only Computations can be converted to a plan');
62+
}
63+
64+
await this.planRepo.editPlan(plan.id, {
65+
computation_only: false,
66+
type: data.type,
67+
longitudinal_profile_parameters: longitudinalProfileParameters,
68+
topographic_setting: topographicSetting,
69+
});
70+
}
71+
}

src/use-cases/plan/CreatePlan.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { PlanRepositoryInterface } from '@domain/interfaces/repositories/PlanRep
55
import NotFoundError from '@domain/errors/NotFoundError';
66

77
export interface CreatePlanRequest {
8-
plan: Pick<PlanProps, 'name' | 'type' | 'project'>;
8+
plan: Pick<PlanProps, 'name' | 'type' | 'project' | 'computation_only'>;
99
options?: RepoOptions;
1010
}
1111

@@ -17,7 +17,7 @@ export class CreatePlan {
1717
) {}
1818

1919
async execute(data: CreatePlanRequest): Promise<Plan> {
20-
this.logger.debug('Create Project execute');
20+
this.logger.debug('Create Plan execute');
2121

2222
// get project
2323
const project = await this.projectRepo.getProjectById(data.plan.project as string, data.options);
@@ -46,6 +46,7 @@ export class CreatePlan {
4646
title: 'Untitled Plan',
4747
footers: [],
4848
footer_size: 0.5,
49+
computation_only: data.plan.computation_only,
4950
};
5051

5152
if (planData.type === PlanType.TOPOGRAPHIC) {

src/use-cases/plan/ImportComputation.ts

Whitespace-only changes.

0 commit comments

Comments
 (0)