Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[IOCOM-1914] Paid payment badge from message details #6610

Merged
merged 5 commits into from
Jan 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions ts/store/reducers/entities/__tests__/payments.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { Detail_v2Enum } from "../../../../../definitions/backend/PaymentProblemJson";
import { ServiceId } from "../../../../../definitions/backend/ServiceId";
import {
updatePaymentForMessage,
UpdatePaymentForMessageFailure
} from "../../../../features/messages/store/actions";
import { UIMessageId } from "../../../../features/messages/types";
import { isPaidPaymentFromDetailV2Enum } from "../../../../utils/payment";
import { paymentByRptIdReducer, PaymentByRptIdState } from "../payments";

describe("payments", () => {
describe("paymentByRptIdReducer", () => {
const rptId1 = "01234567890012345678912345610";
const rptId2 = "01234567890012345678912345620";
const initialState: PaymentByRptIdState = {
[rptId1]: {
kind: "COMPLETED",
transactionId: 15
},
[rptId2]: {
kind: "DUPLICATED"
}
};
const payload: UpdatePaymentForMessageFailure = {
details: Detail_v2Enum.PAA_PAGAMENTO_DUPLICATO,
messageId: "5a15aba4-7cd6-490b-b3fe-cf766f731a2f" as UIMessageId,
paymentId: "01234567890012345678912345630",
serviceId: "75c046cf-77a7-4d33-9c3f-578e00379b55" as ServiceId
};

Object.values(Detail_v2Enum)
.filter(detailV2Enum => !isPaidPaymentFromDetailV2Enum(detailV2Enum))
.forEach(detailV2Enum => {
it(`should return the input state if the failure details are '${detailV2Enum}'`, () => {
const outputState = paymentByRptIdReducer(
initialState,
updatePaymentForMessage.failure({
...payload,
details: detailV2Enum
})
);
expect(outputState).toBe(initialState);
});
});
it(`should return the input state if failure details are 'PAA_PAGAMENTO_DUPLICATO' but there is already a record in the state for the input payment`, () => {
const outputState = paymentByRptIdReducer(
initialState,
updatePaymentForMessage.failure({
...payload,
paymentId: rptId1,
details: Detail_v2Enum.PAA_PAGAMENTO_DUPLICATO
})
);
expect(outputState).toBe(initialState);
});
it(`should return the input state if failure details are 'PPT_PAGAMENTO_DUPLICATO' but there is already a record in the state for the input payment`, () => {
const outputState = paymentByRptIdReducer(
initialState,
updatePaymentForMessage.failure({
...payload,
paymentId: rptId1,
details: Detail_v2Enum.PPT_PAGAMENTO_DUPLICATO
})
);
expect(outputState).toBe(initialState);
});
it(`should return the updated state if failure details are 'PAA_PAGAMENTO_DUPLICATO' and there is no record for the input payment`, () => {
const outputState = paymentByRptIdReducer(
initialState,
updatePaymentForMessage.failure({
...payload,
details: Detail_v2Enum.PAA_PAGAMENTO_DUPLICATO
})
);
expect(outputState).toEqual({
...initialState,
[payload.paymentId]: { kind: "DUPLICATED" }
});
});
it(`should return the updated state if failure details are 'PPT_PAGAMENTO_DUPLICATO' and there is no record for the input payment`, () => {
const outputState = paymentByRptIdReducer(
initialState,
updatePaymentForMessage.failure({
...payload,
details: Detail_v2Enum.PPT_PAGAMENTO_DUPLICATO
})
);
expect(outputState).toEqual({
...initialState,
[payload.paymentId]: { kind: "DUPLICATED" }
});
});
});
});
38 changes: 38 additions & 0 deletions ts/store/reducers/entities/payments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ import { Action } from "../../actions/types";
import { paymentCompletedSuccess } from "../../../features/payments/checkout/store/actions/orchestration";
import { GlobalState } from "../types";
import { differentProfileLoggedIn } from "../../actions/crossSessions";
import {
updatePaymentForMessage,
UpdatePaymentForMessageFailure
} from "../../../features/messages/store/actions";
import { isPaidPaymentFromDetailV2Enum } from "../../../utils/payment";

export type PaidReason = Readonly<
| {
Expand Down Expand Up @@ -44,6 +49,14 @@ export const paymentByRptIdReducer = (
transactionId: undefined
}
};
// This action is dispatched by the payment status update saga that is triggered upon
// entering message details. Be aware that the status of a paid payment can never change,
// so there is no need to handle the removal of a no-more-paid payment from the state
case getType(updatePaymentForMessage.failure):
return paymentByRptIdStateFromUpdatePaymentForMessageFailure(
action.payload,
state
);
// clear state if the current profile is different from the previous one
case getType(differentProfileLoggedIn):
return INITIAL_STATE;
Expand All @@ -53,6 +66,31 @@ export const paymentByRptIdReducer = (
}
};

const paymentByRptIdStateFromUpdatePaymentForMessageFailure = (
payload: UpdatePaymentForMessageFailure,
state: PaymentByRptIdState
): PaymentByRptIdState => {
// Only paid payments are tracked from the reducer, ignore the others
const isPaidPayment = isPaidPaymentFromDetailV2Enum(payload.details);
if (!isPaidPayment) {
return state;
}
const rptId = payload.paymentId;
// Make sure not to overwrite any existing data (since it may
// have come from a payment flow, where data are more detailed)
const inMemoryPaymentData = state[rptId];
if (inMemoryPaymentData != null) {
return state;
}
// Paid payment was not tracked, add it to the reducer's state
return {
...state,
[rptId]: {
kind: "DUPLICATED"
}
};
};

// Selectors

export const paymentsByRptIdSelector = (
Expand Down
Loading