Skip to content

Commit

Permalink
ORV2 2386 Fixing void permit issue (#1422)
Browse files Browse the repository at this point in the history
Co-authored-by: zgong-gov <[email protected]>
  • Loading branch information
gchauhan-aot and zgong-gov authored Jun 7, 2024
1 parent ad1a9e0 commit 43e264c
Show file tree
Hide file tree
Showing 13 changed files with 187 additions and 60 deletions.
1 change: 1 addition & 0 deletions frontend/src/features/permits/constants/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const PERMIT_TYPE_CHOOSE_FROM_OPTIONS = [

export const BASE_DAYS_IN_YEAR = 365;
export const COMMON_MIN_DURATION = 30;
export const TERM_DURATION_INTERVAL_DAYS = 30;

export const COMMON_DURATION_OPTIONS = [
{ value: COMMON_MIN_DURATION, label: "30 Days" },
Expand Down
9 changes: 8 additions & 1 deletion frontend/src/features/permits/constants/tros.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { tros } from "./tros.json";
import { PermitCommodity } from "../types/PermitCommodity";
import { COMMON_DURATION_OPTIONS, COMMON_MIN_DURATION } from "./constants";
import {
BASE_DAYS_IN_YEAR,
COMMON_DURATION_OPTIONS,
COMMON_MIN_DURATION,
TERM_DURATION_INTERVAL_DAYS,
} from "./constants";

export const TROS_INELIGIBLE_POWERUNITS = [...tros.ineligiblePowerUnitSubtypes];
export const TROS_INELIGIBLE_TRAILERS = [...tros.ineligibleTrailerSubtypes];
Expand All @@ -12,4 +17,6 @@ export const MANDATORY_TROS_COMMODITIES: PermitCommodity[] =
);

export const MIN_TROS_DURATION = COMMON_MIN_DURATION;
export const MAX_TROS_DURATION = BASE_DAYS_IN_YEAR;
export const TROS_DURATION_OPTIONS = [...COMMON_DURATION_OPTIONS];
export const TROS_DURATION_INTERVAL_DAYS = TERM_DURATION_INTERVAL_DAYS;
9 changes: 8 additions & 1 deletion frontend/src/features/permits/constants/trow.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import { trow } from "./trow.json";
import { PermitCommodity } from "../types/PermitCommodity";
import { COMMON_DURATION_OPTIONS, COMMON_MIN_DURATION } from "./constants";
import {
BASE_DAYS_IN_YEAR,
COMMON_DURATION_OPTIONS,
COMMON_MIN_DURATION,
TERM_DURATION_INTERVAL_DAYS,
} from "./constants";

export const TROW_INELIGIBLE_POWERUNITS = [...trow.ineligiblePowerUnitSubtypes];
export const TROW_INELIGIBLE_TRAILERS = [...trow.ineligibleTrailerSubtypes];
export const TROW_COMMODITIES: PermitCommodity[] = [...trow.commodities];
export const MANDATORY_TROW_COMMODITIES: PermitCommodity[] = [...TROW_COMMODITIES];
export const MIN_TROW_DURATION = COMMON_MIN_DURATION;
export const MAX_TROW_DURATION = BASE_DAYS_IN_YEAR;
export const TROW_DURATION_OPTIONS = [...COMMON_DURATION_OPTIONS];
export const TROW_DURATION_INTERVAL_DAYS = TERM_DURATION_INTERVAL_DAYS;
43 changes: 41 additions & 2 deletions frontend/src/features/permits/helpers/dateSelection.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
import { MIN_TROS_DURATION, TROS_DURATION_OPTIONS } from "../constants/tros";
import { MIN_TROW_DURATION, TROW_DURATION_OPTIONS } from "../constants/trow";
import { BASE_DAYS_IN_YEAR, TERM_DURATION_INTERVAL_DAYS } from "../constants/constants";
import { PERMIT_TYPES, PermitType } from "../types/PermitType";
import {
MAX_TROS_DURATION,
MIN_TROS_DURATION,
TROS_DURATION_INTERVAL_DAYS,
TROS_DURATION_OPTIONS,
} from "../constants/tros";

import {
MAX_TROW_DURATION,
MIN_TROW_DURATION,
TROW_DURATION_INTERVAL_DAYS,
TROW_DURATION_OPTIONS,
} from "../constants/trow";

/**
* Get list of selectable duration options for a given permit type.
Expand All @@ -23,3 +35,30 @@ export const minDurationForPermitType = (permitType: PermitType) => {
if (permitType === PERMIT_TYPES.TROW) return MIN_TROW_DURATION;
return 0;
};

/**
* Get the maximum allowable duration for a given permit type.
* @param permitType Permit type to get max duration for
* @returns Maxinum allowable duration for the permit type
*/
export const maxDurationForPermitType = (permitType: PermitType) => {
if (permitType === PERMIT_TYPES.TROS) return MAX_TROS_DURATION;
if (permitType === PERMIT_TYPES.TROW) return MAX_TROW_DURATION;
return BASE_DAYS_IN_YEAR;
};

/**
* Get the duration interval (in days) for a given permit type.
* @param permitType Permit type to get duration interval for
* @returns Number of days as duration interval for the permit type.
*/
export const getDurationIntervalDays = (permitType: PermitType) => {
switch (permitType) {
case PERMIT_TYPES.TROW:
return TROW_DURATION_INTERVAL_DAYS;
case PERMIT_TYPES.TROS:
return TROS_DURATION_INTERVAL_DAYS;
default:
return TERM_DURATION_INTERVAL_DAYS; // This needs to be updated once more permit types are added
}
};
33 changes: 25 additions & 8 deletions frontend/src/features/permits/helpers/feeSummary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { TRANSACTION_TYPES, TransactionType } from "../types/payment";
import { Permit } from "../types/permit";
import { isValidTransaction } from "./payment";
import { Nullable } from "../../../common/types/common";
import { PERMIT_STATES, getPermitState } from "./permitState";
import { PERMIT_STATES, daysLeftBeforeExpiry, getPermitState } from "./permitState";
import { PERMIT_TYPES, PermitType } from "../types/PermitType";

import { getDurationIntervalDays, maxDurationForPermitType } from "./dateSelection";
import {
applyWhenNotNullable,
getDefaultRequiredVal,
Expand All @@ -18,13 +18,26 @@ import {
* @returns Fee to be paid for the permit duration
*/
export const calculateFeeByDuration = (permitType: PermitType, duration: number) => {
const maxAllowableDuration = maxDurationForPermitType(permitType);

// Make sure that duration is between 0 and max allowable duration (for given permit type)
const safeDuration = duration < 0
? 0
: (duration > maxAllowableDuration) ? maxAllowableDuration : duration;

const intervalDays = getDurationIntervalDays(permitType);

const intervalPeriodsToPay = safeDuration > 360
? Math.ceil(360 / intervalDays) : Math.ceil(safeDuration / intervalDays);

if (permitType === PERMIT_TYPES.TROW) {
// Only for TROW
return duration > 360 ? 1200 : Math.floor(duration / 30) * 100;
// Only for TROW, $100 per interval (30 days)
return intervalPeriodsToPay * 100;
}
// Add more conditions for other permit types if needed
// 1 Year === 365 days, but the fee for one year is only $360
return duration > 360 ? 360 : duration;

// For TROS, $30 per interval (30 days)
return intervalPeriodsToPay * 30;
};

/**
Expand Down Expand Up @@ -115,12 +128,16 @@ export const isZeroAmount = (amount: number) => {
*/
export const calculateAmountForVoid = (
permit: Permit,
permitHistory: PermitHistory[],
) => {
const permitState = getPermitState(permit);
if (permitState === PERMIT_STATES.EXPIRED) {
return 0;
}

return calculateNetAmount(permitHistory);
const daysLeft = daysLeftBeforeExpiry(permit);
const intervalDays = getDurationIntervalDays(permit.permitType);
return calculateFeeByDuration(
permit.permitType,
Math.floor(daysLeft / intervalDays) * intervalDays,
);
};
3 changes: 1 addition & 2 deletions frontend/src/features/permits/helpers/permitState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@ export const daysLeftBeforeExpiry = (permit: Permit) => {
}

// Active permit (current datetime is between the start date and end date)
const tomorrow = dayjs(getStartOfDate(currDate)).add(1, "day");
return getDateDiffInDays(permitExpiryDate, tomorrow);
return getDateDiffInDays(permitExpiryDate, currDate);
};

/**
Expand Down
42 changes: 30 additions & 12 deletions frontend/src/features/permits/hooks/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,21 @@ import {
getPendingPermits,
} from "../apiManager/permitsAPI";

const QUERY_KEYS = {
PERMIT_DETAIL: (
permitId?: Nullable<string>,
companyId?: Nullable<string>,
) => ["permit", permitId, companyId],
AMEND_APPLICATION: (
originalPermitId?: Nullable<string>,
companyId?: Nullable<string>,
) => ["amendmentApplication", originalPermitId, companyId],
PERMIT_HISTORY: (
originalPermitId?: Nullable<string>,
companyId?: Nullable<string>,
) => ["permitHistory", originalPermitId, companyId],
};

/**
* A custom react query mutation hook that saves the application data to the backend API
* The hook checks for an existing application number to decide whether to send an update or create request
Expand Down Expand Up @@ -146,7 +161,7 @@ export const usePermitDetailsQuery = (
permitId?: Nullable<string>,
) => {
return useQuery({
queryKey: ["permit"],
queryKey: QUERY_KEYS.PERMIT_DETAIL(permitId, companyId),
queryFn: async () => {
const res = await getPermit(permitId, companyId);
return res ? deserializePermitResponse(res) : res;
Expand Down Expand Up @@ -262,7 +277,7 @@ export const usePermitHistoryQuery = (
companyId?: Nullable<string>,
) => {
return useQuery({
queryKey: ["permitHistory"],
queryKey: QUERY_KEYS.PERMIT_HISTORY(originalPermitId, companyId),
queryFn: () => getPermitHistory(originalPermitId, companyId),
enabled: Boolean(originalPermitId) && Boolean(companyId),
retry: false,
Expand All @@ -288,7 +303,7 @@ export const useIssuePermits = (companyIdParam?: Nullable<string>) => {
retry: false,
onSuccess: (issueResponseData) => {
queryClient.invalidateQueries({
queryKey: ["application", "permit"],
queryKey: ["application"],
});
setIssueResults(issueResponseData);
},
Expand All @@ -314,13 +329,13 @@ export const useAmendPermit = (companyIdParam?: Nullable<string>) => {
const amendResult = await amendPermit(data, companyIdParam);
if (amendResult.status === 200 || amendResult.status === 201) {
queryClient.invalidateQueries({
queryKey: ["permit"],
queryKey: QUERY_KEYS.PERMIT_DETAIL(data.permitId, companyIdParam),
});
queryClient.invalidateQueries({
queryKey: ["amendmentApplication"],
queryKey: QUERY_KEYS.AMEND_APPLICATION(data.originalPermitId, companyIdParam),
});
queryClient.invalidateQueries({
queryKey: ["permitHistory"],
queryKey: QUERY_KEYS.PERMIT_HISTORY(data.originalPermitId, companyIdParam),
});

return {
Expand Down Expand Up @@ -348,13 +363,16 @@ export const useModifyAmendmentApplication = () => {

if (amendResult.status === 200 || amendResult.status === 201) {
queryClient.invalidateQueries({
queryKey: ["permit"],
});
queryClient.invalidateQueries({
queryKey: ["amendmentApplication"],
queryKey: QUERY_KEYS.AMEND_APPLICATION(
data.application.originalPermitId,
data.companyId,
),
});
queryClient.invalidateQueries({
queryKey: ["permitHistory"],
queryKey: QUERY_KEYS.PERMIT_HISTORY(
data.application.originalPermitId,
data.companyId,
),
});

return {
Expand All @@ -380,7 +398,7 @@ export const useAmendmentApplicationQuery = (
companyId?: Nullable<string>,
) => {
return useQuery({
queryKey: ["amendmentApplication"],
queryKey: QUERY_KEYS.AMEND_APPLICATION(originalPermitId, companyId),
queryFn: async () => {
const res = await getCurrentAmendmentApplication(
originalPermitId,
Expand Down
12 changes: 9 additions & 3 deletions frontend/src/features/permits/pages/Void/FinishVoid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { useVoidPermit } from "./hooks/useVoidPermit";
import { isValidTransaction } from "../../helpers/payment";
import { Nullable } from "../../../../common/types/common";
import { hasPermitsActionFailed } from "../../helpers/permitState";
import { getDefaultRequiredVal } from "../../../../common/helpers/util";
import { applyWhenNotNullable, getDefaultRequiredVal } from "../../../../common/helpers/util";

export const FinishVoid = ({
permit,
Expand All @@ -26,7 +26,13 @@ export const FinishVoid = ({

const { email, additionalEmail, fax, reason } = voidPermitData;

const permitHistoryQuery = usePermitHistoryQuery(permit?.originalPermitId);
const permitHistoryQuery = usePermitHistoryQuery(
permit?.originalPermitId,
applyWhenNotNullable(
id => `${id}`,
permit?.companyId,
),
);

const permitHistory = getDefaultRequiredVal([], permitHistoryQuery.data);

Expand All @@ -38,7 +44,7 @@ export const FinishVoid = ({

const amountToRefund = !permit
? 0
: -1 * calculateAmountForVoid(permit, transactionHistory);
: -1 * calculateAmountForVoid(permit);

const { mutation: voidPermitMutation, voidResults } = useVoidPermit();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,11 @@ import { useVoidPermitForm } from "../hooks/useVoidPermitForm";
import { VoidPermitHeader } from "./VoidPermitHeader";
import { Permit } from "../../../types/permit";
import { RevokeDialog } from "./RevokeDialog";
import { usePermitHistoryQuery } from "../../../hooks/hooks";
import { calculateAmountForVoid } from "../../../helpers/feeSummary";
import { FeeSummary } from "../../../components/feeSummary/FeeSummary";
import { VoidPermitFormData } from "../types/VoidPermit";
import { useVoidPermit } from "../hooks/useVoidPermit";
import { mapToRevokeRequestData } from "../helpers/mapper";
import { isValidTransaction } from "../../../helpers/payment";
import { Nullable } from "../../../../../common/types/common";
import { hasPermitsActionFailed } from "../../../helpers/permitState";
import { getDefaultRequiredVal } from "../../../../../common/helpers/util";
Expand Down Expand Up @@ -46,14 +44,6 @@ export const VoidPermitForm = ({
const { formMethods, permitId, setVoidPermitData, next } =
useVoidPermitForm();

const permitHistoryQuery = usePermitHistoryQuery(permit?.originalPermitId);

const permitHistory = getDefaultRequiredVal([], permitHistoryQuery.data);

const validTransactionHistory = permitHistory.filter((history) =>
isValidTransaction(history.paymentMethodTypeCode, history.pgApproved),
);

const { mutation: revokePermitMutation, voidResults } = useVoidPermit();

useEffect(() => {
Expand All @@ -67,10 +57,7 @@ export const VoidPermitForm = ({
}
}, [voidResults]);

const amountToRefund =
permitHistoryQuery.isLoading || !permit
? 0
: -1 * calculateAmountForVoid(permit, validTransactionHistory);
const amountToRefund = !permit ? 0 : -1 * calculateAmountForVoid(permit);

const {
control,
Expand Down
4 changes: 2 additions & 2 deletions vehicles/src/common/constants/permit.constant.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
export const TROS_TERM = 30;
export const TROS_PRICE_PER_TERM = 30;
export const TROS_MIN_VALID_DURATION = TROS_TERM;
export const TROS_MIN_VALID_DURATION = 1;
export const TROS_MAX_VALID_DURATION = 366;
export const TROW_TERM = 30;
export const TROW_PRICE_PER_TERM = 100;
export const TROW_MIN_VALID_DURATION = TROS_TERM;
export const TROW_MIN_VALID_DURATION = 1;
export const TROW_MAX_VALID_DURATION = 366;
4 changes: 4 additions & 0 deletions vehicles/src/common/enum/pg-approved-status-type.enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export enum PgApprovesStatus {
DECLINED = 0,
APPROVED = 1,
}
Loading

0 comments on commit 43e264c

Please sign in to comment.