forked from Yara724/api
Merge pull request 'Removed some validations that were unneccesary for expert submit' (#290) from s.yahyaee/yara724-api:main into main
Reviewed-on: Yara724/api#290
This commit is contained in:
@@ -5,22 +5,18 @@ import {
|
|||||||
ValidatorConstraint,
|
ValidatorConstraint,
|
||||||
ValidatorConstraintInterface,
|
ValidatorConstraintInterface,
|
||||||
} from "class-validator";
|
} from "class-validator";
|
||||||
import { normalizeMoneyAmountString } from "src/utils/unicode-digits";
|
import { parseMoneyAmountToman } from "src/utils/unicode-digits";
|
||||||
|
|
||||||
@ValidatorConstraint({ name: "isMoneyAmountString", async: false })
|
@ValidatorConstraint({ name: "isMoneyAmountString", async: false })
|
||||||
export class IsMoneyAmountStringConstraint
|
export class IsMoneyAmountStringConstraint implements ValidatorConstraintInterface {
|
||||||
implements ValidatorConstraintInterface
|
|
||||||
{
|
|
||||||
validate(value: unknown): boolean {
|
validate(value: unknown): boolean {
|
||||||
if (value == null || value === "") return true;
|
if (value == null || value === "") return true;
|
||||||
if (typeof value !== "string") return false;
|
if (typeof value !== "string") return false;
|
||||||
const n = normalizeMoneyAmountString(value);
|
return parseMoneyAmountToman(value) !== null;
|
||||||
if (!n) return false;
|
|
||||||
return /^\d+(\.\d+)?$/.test(n);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultMessage(): string {
|
defaultMessage(): string {
|
||||||
return "Must be a non-negative amount (digits only, optional decimal).";
|
return "Must be a non-negative whole-Toman amount.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ describe("SubmitExpertReplyV2Dto", () => {
|
|||||||
expect(errors).not.toHaveLength(0);
|
expect(errors).not.toHaveLength(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("accepts a replacement part without a price", async () => {
|
it("rejects a replacement part without a price", async () => {
|
||||||
const dto = plainToInstance(SubmitExpertReplyV2Dto, {
|
const dto = plainToInstance(SubmitExpertReplyV2Dto, {
|
||||||
description: "Damage assessment",
|
description: "Damage assessment",
|
||||||
parts: [
|
parts: [
|
||||||
@@ -41,7 +41,7 @@ describe("SubmitExpertReplyV2Dto", () => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(await validate(dto)).toHaveLength(0);
|
expect(await validate(dto)).not.toHaveLength(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("accepts a repair part without daghi", async () => {
|
it("accepts a repair part without daghi", async () => {
|
||||||
@@ -61,4 +61,33 @@ describe("SubmitExpertReplyV2Dto", () => {
|
|||||||
|
|
||||||
expect(await validate(dto)).toHaveLength(0);
|
expect(await validate(dto)).toHaveLength(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("accepts the expert's repair and replacement pricing rules", async () => {
|
||||||
|
const dto = plainToInstance(SubmitExpertReplyV2Dto, {
|
||||||
|
description: "Damage assessment",
|
||||||
|
parts: [
|
||||||
|
{
|
||||||
|
partId: 11,
|
||||||
|
typeOfDamage: TypeOfDamage.Repair,
|
||||||
|
salary: "۵,۰۰۰",
|
||||||
|
totalPayment: "5000",
|
||||||
|
factorNeeded: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
partId: 23,
|
||||||
|
typeOfDamage: TypeOfDamage.Change,
|
||||||
|
price: "۵۰,۰۰۰",
|
||||||
|
salary: "۱۰۰,۰۰۰",
|
||||||
|
totalPayment: "150000",
|
||||||
|
factorNeeded: false,
|
||||||
|
daghi: {
|
||||||
|
option: DaghiOption.RECYCLED_PARTS_VALUE,
|
||||||
|
price: "۱۰۰,۵۰۰,۰۰۰",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(await validate(dto)).toHaveLength(0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
IsInt,
|
IsInt,
|
||||||
} from 'class-validator';
|
} from 'class-validator';
|
||||||
import { Type } from 'class-transformer';
|
import { Type } from 'class-transformer';
|
||||||
import { IsRepairLineAmountToman } from 'src/common/validators/repair-line-amount-toman.validator';
|
import { IsMoneyAmountString } from 'src/common/validators/money-amount-string.validator';
|
||||||
import { ClaimRequiredDocumentType } from 'src/Types&Enums/claim-request-management/required-document-type.enum';
|
import { ClaimRequiredDocumentType } from 'src/Types&Enums/claim-request-management/required-document-type.enum';
|
||||||
import { DamagedPartItem } from 'src/claim-request-management/dto/capture-requirements-v2.dto';
|
import { DamagedPartItem } from 'src/claim-request-management/dto/capture-requirements-v2.dto';
|
||||||
import { DaghiOption } from 'src/Types&Enums/claim-request-management/daghi-option.enum';
|
import { DaghiOption } from 'src/Types&Enums/claim-request-management/daghi-option.enum';
|
||||||
@@ -35,7 +35,7 @@ export class DaghiDetailsV2Dto {
|
|||||||
)
|
)
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
@IsRepairLineAmountToman()
|
@IsMoneyAmountString()
|
||||||
price?: string;
|
price?: string;
|
||||||
|
|
||||||
@ApiPropertyOptional({
|
@ApiPropertyOptional({
|
||||||
@@ -56,24 +56,24 @@ export class PartPricingV2Dto {
|
|||||||
|
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
enum: TypeOfDamage,
|
enum: TypeOfDamage,
|
||||||
description: "'repair' requires price; 'change' may omit it.",
|
description: "'change' requires price; 'repair' may omit it.",
|
||||||
})
|
})
|
||||||
@IsEnum(TypeOfDamage)
|
@IsEnum(TypeOfDamage)
|
||||||
typeOfDamage: TypeOfDamage;
|
typeOfDamage: TypeOfDamage;
|
||||||
|
|
||||||
@ApiPropertyOptional({
|
@ApiPropertyOptional({
|
||||||
example: "5000000",
|
example: "5000000",
|
||||||
description: "Required for repair lines; omitted for change lines. Use 0 if the full amount is in salary.",
|
description: "Required for change lines; omitted for repair lines. Use 0 if unused.",
|
||||||
})
|
})
|
||||||
@ValidateIf(
|
@ValidateIf(
|
||||||
(part: PartPricingV2Dto) =>
|
(part: PartPricingV2Dto) =>
|
||||||
part.typeOfDamage === TypeOfDamage.Repair ||
|
part.typeOfDamage === TypeOfDamage.Change ||
|
||||||
(part.price != null &&
|
(part.price != null &&
|
||||||
(typeof part.price !== 'string' || part.price.trim() !== '')),
|
(typeof part.price !== 'string' || part.price.trim() !== '')),
|
||||||
)
|
)
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
@IsRepairLineAmountToman({ allowZero: true })
|
@IsMoneyAmountString()
|
||||||
price: string;
|
price: string;
|
||||||
|
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
@@ -82,7 +82,7 @@ export class PartPricingV2Dto {
|
|||||||
})
|
})
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
@IsRepairLineAmountToman({ allowZero: true })
|
@IsMoneyAmountString()
|
||||||
salary: string;
|
salary: string;
|
||||||
|
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
@@ -91,7 +91,7 @@ export class PartPricingV2Dto {
|
|||||||
})
|
})
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
@IsRepairLineAmountToman({ allowZero: true })
|
@IsMoneyAmountString()
|
||||||
totalPayment: string;
|
totalPayment: string;
|
||||||
|
|
||||||
@ApiPropertyOptional({
|
@ApiPropertyOptional({
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ describe("getExpertReplyPricingValidationError", () => {
|
|||||||
).toBeNull();
|
).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("rejects a repair line without a price", () => {
|
it("accepts a repair line without a price", () => {
|
||||||
expect(
|
expect(
|
||||||
getExpertReplyPricingValidationError([
|
getExpertReplyPricingValidationError([
|
||||||
{
|
{
|
||||||
@@ -55,10 +55,9 @@ describe("getExpertReplyPricingValidationError", () => {
|
|||||||
typeOfDamage: TypeOfDamage.Repair,
|
typeOfDamage: TypeOfDamage.Repair,
|
||||||
salary: "0",
|
salary: "0",
|
||||||
totalPayment: "0",
|
totalPayment: "0",
|
||||||
daghi: { option: DaghiOption.NO_VALUE },
|
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
).toMatch(/price is also required/);
|
).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("rejects recycled-value daghi without its price", () => {
|
it("rejects recycled-value daghi without its price", () => {
|
||||||
@@ -67,6 +66,7 @@ describe("getExpertReplyPricingValidationError", () => {
|
|||||||
{
|
{
|
||||||
partId: 201,
|
partId: 201,
|
||||||
typeOfDamage: TypeOfDamage.Change,
|
typeOfDamage: TypeOfDamage.Change,
|
||||||
|
price: "0",
|
||||||
salary: "0",
|
salary: "0",
|
||||||
totalPayment: "0",
|
totalPayment: "0",
|
||||||
daghi: { option: DaghiOption.RECYCLED_PARTS_VALUE },
|
daghi: { option: DaghiOption.RECYCLED_PARTS_VALUE },
|
||||||
@@ -75,7 +75,7 @@ describe("getExpertReplyPricingValidationError", () => {
|
|||||||
).toMatch(/requires a valid daghi price/);
|
).toMatch(/requires a valid daghi price/);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("accepts a replacement line without a part price", () => {
|
it("rejects a replacement line without a part price", () => {
|
||||||
expect(
|
expect(
|
||||||
getExpertReplyPricingValidationError([
|
getExpertReplyPricingValidationError([
|
||||||
{
|
{
|
||||||
@@ -86,7 +86,7 @@ describe("getExpertReplyPricingValidationError", () => {
|
|||||||
daghi: { option: DaghiOption.NO_VALUE },
|
daghi: { option: DaghiOption.NO_VALUE },
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
).toBeNull();
|
).toMatch(/price is also required/);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("rejects an invalid price when a replacement line supplies one", () => {
|
it("rejects an invalid price when a replacement line supplies one", () => {
|
||||||
@@ -103,4 +103,22 @@ describe("getExpertReplyPricingValidationError", () => {
|
|||||||
]),
|
]),
|
||||||
).toMatch(/requires valid salary and totalPayment/);
|
).toMatch(/requires valid salary and totalPayment/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("accepts a recycled-parts daghi price above the repair-line cap", () => {
|
||||||
|
expect(
|
||||||
|
getExpertReplyPricingValidationError([
|
||||||
|
{
|
||||||
|
partId: 23,
|
||||||
|
typeOfDamage: TypeOfDamage.Change,
|
||||||
|
price: "۵۰,۰۰۰",
|
||||||
|
salary: "۱۰۰,۰۰۰",
|
||||||
|
totalPayment: "150000",
|
||||||
|
daghi: {
|
||||||
|
option: DaghiOption.RECYCLED_PARTS_VALUE,
|
||||||
|
price: "۱۰۰,۵۰۰,۰۰۰",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
).toBeNull();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { REPAIR_LINE_AMOUNT_TOMAN } from "src/constants/repair-amount-limits";
|
|
||||||
import { DaghiOption } from "src/Types&Enums/claim-request-management/daghi-option.enum";
|
import { DaghiOption } from "src/Types&Enums/claim-request-management/daghi-option.enum";
|
||||||
import { TypeOfDamage } from "src/Types&Enums/claim-request-management/type-of-damage.enum";
|
import { TypeOfDamage } from "src/Types&Enums/claim-request-management/type-of-damage.enum";
|
||||||
import { parseMoneyAmountToman } from "src/utils/unicode-digits";
|
import { parseMoneyAmountToman } from "src/utils/unicode-digits";
|
||||||
@@ -59,33 +58,22 @@ export function getExpertReplyPricingValidationError(
|
|||||||
part.price != null &&
|
part.price != null &&
|
||||||
(typeof part.price !== "string" || part.price.trim() !== "");
|
(typeof part.price !== "string" || part.price.trim() !== "");
|
||||||
|
|
||||||
const splitAmountIsValid = (amount: number | null) =>
|
const amountIsValid = (amount: number | null) => amount !== null;
|
||||||
amount !== null &&
|
const priceIsRequired = part.typeOfDamage === TypeOfDamage.Change;
|
||||||
(amount === 0 ||
|
const priceIsValid = !hasPrice || amountIsValid(price);
|
||||||
(amount >= REPAIR_LINE_AMOUNT_TOMAN.MIN &&
|
|
||||||
amount <= REPAIR_LINE_AMOUNT_TOMAN.MAX));
|
|
||||||
const totalIsValid =
|
|
||||||
totalPayment !== null &&
|
|
||||||
totalPayment >= 0 &&
|
|
||||||
totalPayment <= REPAIR_LINE_AMOUNT_TOMAN.MAX;
|
|
||||||
const priceIsRequired = part.typeOfDamage === TypeOfDamage.Repair;
|
|
||||||
const priceIsValid =
|
|
||||||
!hasPrice || (price !== null && splitAmountIsValid(price));
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!splitAmountIsValid(salary) ||
|
!amountIsValid(salary) ||
|
||||||
!totalIsValid ||
|
!amountIsValid(totalPayment) ||
|
||||||
(priceIsRequired && !splitAmountIsValid(price)) ||
|
(priceIsRequired && !amountIsValid(price)) ||
|
||||||
!priceIsValid
|
!priceIsValid
|
||||||
) {
|
) {
|
||||||
return `${label} requires valid salary and totalPayment; price is also required for '${TypeOfDamage.Repair}' damage. Price and salary may be 0; totalPayment may be 0.`;
|
return `${label} requires valid salary and totalPayment; price is also required for '${TypeOfDamage.Change}' damage. Price, salary, and totalPayment may be 0.`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
daghi?.option === DaghiOption.RECYCLED_PARTS_VALUE &&
|
daghi?.option === DaghiOption.RECYCLED_PARTS_VALUE &&
|
||||||
(daghiPrice === null ||
|
daghiPrice === null
|
||||||
daghiPrice < REPAIR_LINE_AMOUNT_TOMAN.MIN ||
|
|
||||||
daghiPrice > REPAIR_LINE_AMOUNT_TOMAN.MAX)
|
|
||||||
) {
|
) {
|
||||||
return `${label} requires a valid daghi price when option is '${DaghiOption.RECYCLED_PARTS_VALUE}'.`;
|
return `${label} requires a valid daghi price when option is '${DaghiOption.RECYCLED_PARTS_VALUE}'.`;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user