Skip to content

Commit

Permalink
refactored to use base abstract class and state bag
Browse files Browse the repository at this point in the history
  • Loading branch information
me-matt committed Oct 8, 2024
1 parent 69379f1 commit 7a40977
Show file tree
Hide file tree
Showing 15 changed files with 227 additions and 165 deletions.
17 changes: 11 additions & 6 deletions src/certificate/CertificatePayloadGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Service } from 'typedi';
import { ITestResult } from '../models';
import { ICertificatePayload } from '../models';
import { CERTIFICATE_DATA } from '../models/Enums';
import { CertificatePayloadStateBag } from './CertificatePayloadStateBag';
import { ICertificatePayloadCommand } from './ICertificatePayloadCommand';
import { AdrCertificateCommand } from './commands/AdrCertificateCommand';
import { DefectsCommand } from './commands/DefectsCommand';
Expand Down Expand Up @@ -61,27 +62,31 @@ export class CertificatePayloadGenerator implements ICertificatePayloadCommand {
type: CERTIFICATE_DATA,
isWelsh = false
): Promise<ICertificatePayload> {
this.initialise(type, isWelsh);
return this.generate(testResult);
this.initialise({
type,
isWelsh,
testResult,
});
return this.generate();
}

/**
* Initialises the certificate generation process.
* @param type The type of certificate to generate
* @param isWelsh True if a Welsh certificate should also be generated.
*/
public initialise(type: CERTIFICATE_DATA, isWelsh = false) {
this.commands.forEach((cmd) => cmd.initialise(type, isWelsh));
public initialise(state: CertificatePayloadStateBag) {
this.commands.forEach((cmd) => cmd.initialise(state));
}

/**
* Generates certificate data for a given test result and certificate type
* @param testResult the source test result for certificate generation
* @returns A generated certificate payload
*/
public async generate(testResult: ITestResult): Promise<ICertificatePayload> {
public async generate(): Promise<ICertificatePayload> {
// Map over all the commands and get their certificate data.
const results = await Promise.all(this.commands.map((cmd) => cmd.generate(testResult)));
const results = await Promise.all(this.commands.map((cmd) => cmd.generate()));

// Flatten all the certificate data into our result payload.
return Promise.resolve(merge({} as ICertificatePayload, ...results));
Expand Down
8 changes: 8 additions & 0 deletions src/certificate/CertificatePayloadStateBag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ITestResult } from '../models';
import { CERTIFICATE_DATA } from '../models/Enums';

export type CertificatePayloadStateBag = {
type: CERTIFICATE_DATA;
isWelsh: boolean;
testResult: ITestResult;
};
17 changes: 13 additions & 4 deletions src/certificate/ICertificatePayloadCommand.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
import { ICertificatePayload } from '../models';
import { ITestResult } from '../models';
import { CERTIFICATE_DATA } from '../models/Enums';
import { CertificatePayloadStateBag } from './CertificatePayloadStateBag';

export interface ICertificatePayloadCommand {
initialise(type: CERTIFICATE_DATA, isWelsh: boolean): void;
generate(testResult: ITestResult): Promise<ICertificatePayload>;
initialise(state: CertificatePayloadStateBag): void;
generate(): Promise<ICertificatePayload>;
}

export abstract class BasePayloadCommand implements ICertificatePayloadCommand {
protected state: CertificatePayloadStateBag = {} as CertificatePayloadStateBag;

initialise(state: CertificatePayloadStateBag) {
this.state = state;
}

abstract generate(): Promise<ICertificatePayload>;
}
21 changes: 9 additions & 12 deletions src/certificate/commands/AdrCertificateCommand.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,25 @@
import { Service } from 'typedi';
import { ITestResult } from '../../models';
import { ICertificatePayload } from '../../models';
import { CERTIFICATE_DATA } from '../../models/Enums';
import { TechRecordType } from '../../models/Types';
import { TechRecordService } from '../../tech-record/TechRecordService';
import { ICertificatePayloadCommand } from '../ICertificatePayloadCommand';
import { BasePayloadCommand } from '../ICertificatePayloadCommand';

@Service()
export class AdrCertificateCommand implements ICertificatePayloadCommand {
private type?: CERTIFICATE_DATA;

constructor(private techRecordService: TechRecordService) {}

private certificateIsAnAdr = (): boolean => this.type === CERTIFICATE_DATA.ADR_DATA;

public initialise(type: CERTIFICATE_DATA, isWelsh = false) {
this.type = type;
export class AdrCertificateCommand extends BasePayloadCommand {
constructor(private techRecordService: TechRecordService) {
super();
}

public async generate(testResult: ITestResult): Promise<ICertificatePayload> {
private certificateIsAnAdr = (): boolean => this.state.type === CERTIFICATE_DATA.ADR_DATA;

public async generate(): Promise<ICertificatePayload> {
if (!this.certificateIsAnAdr()) {
return {} as ICertificatePayload;
}

const { testResult } = this.state;

const adrDetails: TechRecordType<any> = await this.techRecordService.getAdrDetails(testResult);
const makeAndModel = await this.techRecordService.getVehicleMakeAndModel(testResult);

Expand Down
31 changes: 15 additions & 16 deletions src/certificate/commands/DefectsCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,29 @@ import { ITestType } from '../../models';
import { CERTIFICATE_DATA, TEST_RESULTS } from '../../models/Enums';
import { IDefectParent } from '../../models/IDefectParent';
import { IFlatDefect } from '../../models/IFlatDefect';
import { BasePayloadCommand } from '../ICertificatePayloadCommand';

@Service()
export class DefectsCommand {
protected type?: CERTIFICATE_DATA;

protected isWelsh = false;

export class DefectsCommand extends BasePayloadCommand {
constructor(
private defectService: DefectService,
private defectRepository: DefectRepository
) {}
) {
super();
}

private certificateIsAnPassOrFail = (): boolean =>
this.type === CERTIFICATE_DATA.PASS_DATA || this.type === CERTIFICATE_DATA.FAIL_DATA;
this.state.type === CERTIFICATE_DATA.PASS_DATA || this.state.type === CERTIFICATE_DATA.FAIL_DATA;

public initialise(type: CERTIFICATE_DATA, isWelsh = false) {
this.type = type;
this.isWelsh = isWelsh;
}

public async generate(testResult: ITestResult): Promise<ICertificatePayload> {
public async generate(): Promise<ICertificatePayload> {
if (!this.certificateIsAnPassOrFail()) {
return {} as ICertificatePayload;
}

const { testTypes } = testResult;
const {
testResult,
testResult: { testTypes },
} = this.state;

const result = {} as ICertificatePayload;

Expand All @@ -52,10 +49,12 @@ export class DefectsCommand {
}

private async getPayloadData(testResult: ITestResult, type: CERTIFICATE_DATA): Promise<any> {
const { isWelsh } = this.state;

let defectListFromApi: IDefectParent[] = [];
let flattenedDefects: IFlatDefect[] = [];

if (this.isWelsh) {
if (isWelsh) {
defectListFromApi = await this.defectRepository.getDefectTranslations();
flattenedDefects = this.defectService.flattenDefectsFromApi(defectListFromApi);
}
Expand All @@ -65,7 +64,7 @@ export class DefectsCommand {
type,
testResult.vehicleType,
flattenedDefects,
this.isWelsh
isWelsh
);
return defects;
}
Expand Down
22 changes: 10 additions & 12 deletions src/certificate/commands/IvaCertificateCommand.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,30 @@
import moment from 'moment';
import { Service } from 'typedi';
import { DefectService } from '../../defect/DefectService';
import { IRequiredStandard, ITestResult } from '../../models';
import { IRequiredStandard } from '../../models';
import { ICertificatePayload } from '../../models';
import { CERTIFICATE_DATA, IVA_30 } from '../../models/Enums';
import { TestResultService } from '../../test-result/TestResultService';
import { ICertificatePayloadCommand } from '../ICertificatePayloadCommand';
import { BasePayloadCommand } from '../ICertificatePayloadCommand';

@Service()
export class IvaCertificateCommand implements ICertificatePayloadCommand {
private type?: CERTIFICATE_DATA;

export class IvaCertificateCommand extends BasePayloadCommand {
constructor(
private defectService: DefectService,
private testResultService: TestResultService
) {}

private certificateIsAnIva = (): boolean => this.type === CERTIFICATE_DATA.IVA_DATA;

initialise(type: CERTIFICATE_DATA, isWelsh = false) {
this.type = type;
) {
super();
}

public async generate(testResult: ITestResult): Promise<ICertificatePayload> {
private certificateIsAnIva = (): boolean => this.state.type === CERTIFICATE_DATA.IVA_DATA;

public async generate(): Promise<ICertificatePayload> {
if (!this.certificateIsAnIva()) {
return {} as ICertificatePayload;
}

const { testResult } = this.state;

const ivaFailDetailsForDocGen = {
vin: testResult.vin,
serialNumber: testResult.vehicleType === 'trl' ? testResult.trailerId : testResult.vrm,
Expand Down
24 changes: 11 additions & 13 deletions src/certificate/commands/MakeAndModelCommand.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,35 @@
import { Service } from 'typedi';
import { ICertificatePayload } from '../../models';
import { ITestResult } from '../../models';
import { CERTIFICATE_DATA, TEST_RESULTS } from '../../models/Enums';
import { TechRecordService } from '../../tech-record/TechRecordService';
import { TestResultService } from '../../test-result/TestResultService';
import { TrailerRepository } from '../../trailer/TrailerRepository';
import { ICertificatePayloadCommand } from '../ICertificatePayloadCommand';
import { BasePayloadCommand } from '../ICertificatePayloadCommand';

@Service()
export class MakeAndModelCommand implements ICertificatePayloadCommand {
protected type?: CERTIFICATE_DATA;

export class MakeAndModelCommand extends BasePayloadCommand {
constructor(
private techRecordService: TechRecordService,
private trailerRepository: TrailerRepository,
private testResultService: TestResultService
) {}
) {
super();
}

private certificateIsAnPassOrFail = (): boolean =>
this.type === CERTIFICATE_DATA.PASS_DATA || this.type === CERTIFICATE_DATA.FAIL_DATA;

initialise(type: CERTIFICATE_DATA, isWelsh = false) {
this.type = type;
}
this.state.type === CERTIFICATE_DATA.PASS_DATA || this.state.type === CERTIFICATE_DATA.FAIL_DATA;

public async generate(testResult: ITestResult): Promise<ICertificatePayload> {
public async generate(): Promise<ICertificatePayload> {
const result = {} as ICertificatePayload;

if (!this.certificateIsAnPassOrFail()) {
return result;
}

const { testTypes, vehicleType } = testResult;
const {
testResult,
testResult: { testTypes, vehicleType },
} = this.state;

const makeAndModel = await this.techRecordService.getVehicleMakeAndModel(testResult);

Expand Down
21 changes: 9 additions & 12 deletions src/certificate/commands/MsvaCertificateCommand.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,26 @@
import moment from 'moment';
import { Service } from 'typedi';
import { DefectService } from '../../defect/DefectService';
import { ITestResult } from '../../models';
import { ICertificatePayload } from '../../models';
import { IRequiredStandard } from '../../models';
import { CERTIFICATE_DATA } from '../../models/Enums';
import { ICertificatePayloadCommand } from '../ICertificatePayloadCommand';
import { BasePayloadCommand } from '../ICertificatePayloadCommand';

@Service()
export class MsvaCertificateCommand implements ICertificatePayloadCommand {
private type?: CERTIFICATE_DATA;

constructor(private defectService: DefectService) {}

private certificateIsAnMsva = (): boolean => this.type === CERTIFICATE_DATA.MSVA_DATA;

initialise(type: CERTIFICATE_DATA, isWelsh = false) {
this.type = type;
export class MsvaCertificateCommand extends BasePayloadCommand {
constructor(private defectService: DefectService) {
super();
}

public async generate(testResult: ITestResult): Promise<ICertificatePayload> {
private certificateIsAnMsva = (): boolean => this.state.type === CERTIFICATE_DATA.MSVA_DATA;

public async generate(): Promise<ICertificatePayload> {
if (!this.certificateIsAnMsva()) {
return {} as ICertificatePayload;
}

const { testResult } = this.state;

const msvaFailDetailsForDocGen = {
vin: testResult.vin,
serialNumber: testResult.vrm,
Expand Down
25 changes: 12 additions & 13 deletions src/certificate/commands/OdometerHistoryCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,35 @@ import { ICertificatePayload } from '../../models';
import { ITestResult } from '../../models';
import { CERTIFICATE_DATA, TEST_RESULTS, VEHICLE_TYPES } from '../../models/Enums';
import { TestResultRepository } from '../../test-result/TestResultRepository';
import { ICertificatePayloadCommand } from '../ICertificatePayloadCommand';
import { BasePayloadCommand } from '../ICertificatePayloadCommand';

@Service()
export class OdometerHistoryCommand implements ICertificatePayloadCommand {
protected type?: CERTIFICATE_DATA;

constructor(private testResultRepository: TestResultRepository) {}
export class OdometerHistoryCommand extends BasePayloadCommand {
constructor(private testResultRepository: TestResultRepository) {
super();
}

private certificateIsAnPassOrFail = (): boolean =>
this.type === CERTIFICATE_DATA.PASS_DATA || this.type === CERTIFICATE_DATA.FAIL_DATA;
this.state.type === CERTIFICATE_DATA.PASS_DATA || this.state.type === CERTIFICATE_DATA.FAIL_DATA;

private vehicleIsTrailer = (testResult: ITestResult): boolean => testResult.vehicleType === VEHICLE_TYPES.TRL;

initialise(type: CERTIFICATE_DATA, isWelsh = false) {
this.type = type;
}

public async generate(testResult: ITestResult): Promise<ICertificatePayload> {
public async generate(): Promise<ICertificatePayload> {
const result = {} as ICertificatePayload;

if (!this.certificateIsAnPassOrFail()) {
return result;
}

const {
testResult,
testResult: { testTypes, systemNumber },
} = this.state;

if (this.vehicleIsTrailer(testResult)) {
return result;
}

const { testTypes, systemNumber } = testResult;

const odometerHistory = await this.testResultRepository.getOdometerHistory(systemNumber);

if (testTypes.testResult !== TEST_RESULTS.FAIL) {
Expand Down
19 changes: 8 additions & 11 deletions src/certificate/commands/PassOrFailCertificateCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,24 @@ import { Service } from 'typedi';
import { ITestResult } from '../../models';
import { ICertificatePayload } from '../../models';
import { CERTIFICATE_DATA, TEST_RESULTS, VEHICLE_TYPES } from '../../models/Enums';
import { ICertificatePayloadCommand } from '../ICertificatePayloadCommand';
import { BasePayloadCommand } from '../ICertificatePayloadCommand';

@Service()
export class PassOrFailCertificateCommand implements ICertificatePayloadCommand {
protected type?: CERTIFICATE_DATA;

export class PassOrFailCertificateCommand extends BasePayloadCommand {
private certificateIsAnPassOrFail = (): boolean =>
this.type === CERTIFICATE_DATA.PASS_DATA || this.type === CERTIFICATE_DATA.FAIL_DATA;

public initialise(type: CERTIFICATE_DATA, isWelsh = false) {
this.type = type;
}
this.state.type === CERTIFICATE_DATA.PASS_DATA || this.state.type === CERTIFICATE_DATA.FAIL_DATA;

public async generate(testResult: ITestResult): Promise<ICertificatePayload> {
public async generate(): Promise<ICertificatePayload> {
const result = {} as ICertificatePayload;

if (!this.certificateIsAnPassOrFail()) {
return result;
}

const { testTypes } = testResult;
const {
testResult,
testResult: { testTypes },
} = this.state;

const payload = await this.getPayloadData(testResult);

Expand Down
Loading

0 comments on commit 7a40977

Please sign in to comment.