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

fix(Payments): [#174552971] Notice number is wrong composed #2180

Merged
merged 3 commits into from
Sep 7, 2020
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
5 changes: 3 additions & 2 deletions ts/components/wallet/PaymentsHistoryList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import * as React from "react";
import { FlatList, ListRenderItemInfo, StyleSheet } from "react-native";
import I18n from "../../i18n";
import {
getIuv,
isPaymentDoneSuccessfully,
PaymentHistory,
PaymentsHistoryState
Expand All @@ -17,6 +16,7 @@ import customVariables from "../../theme/variables";
import { formatDateAsLocal } from "../../utils/dates";
import ItemSeparatorComponent from "../ItemSeparatorComponent";
import { EdgeBorderComponent } from "../screens/EdgeBorderComponent";
import { getIuv } from "../../utils/payment";
import PaymentHistoryItem from "./PaymentHistoryItem";

type Props = Readonly<{
Expand Down Expand Up @@ -45,7 +45,8 @@ const notAvailable = I18n.t("global.remoteStates.notAvailable");
export const getPaymentHistoryInfo = (
paymentHistory: PaymentHistory,
paymentCheckout: Option<boolean>
) => paymentCheckout.fold(
) =>
paymentCheckout.fold(
{
text11: I18n.t("payment.details.state.incomplete"),
text3: getIuv(paymentHistory.data),
Expand Down
6 changes: 3 additions & 3 deletions ts/sagas/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ import {
addWalletCreditCardFailure,
addWalletCreditCardRequest,
addWalletCreditCardSuccess,
addWalletNewCreditCardSuccess,
creditCardCheckout3dsRequest,
creditCardCheckout3dsSuccess,
deleteWalletRequest,
Expand Down Expand Up @@ -281,6 +282,8 @@ function* startOrResumeAddCreditCardSaga(
_ => _.idWallet === idWallet
);
if (maybeAddedWallet !== undefined) {
// dispatch the action: a new card has been added
yield put(addWalletNewCreditCardSuccess());
if (action.payload.setAsFavorite === true) {
yield put(setFavouriteWalletRequest(maybeAddedWallet.idWallet));
}
Expand All @@ -294,9 +297,6 @@ function* startOrResumeAddCreditCardSaga(
}
}
}

// TODO: set as favorite

break;
}
}
Expand Down
36 changes: 18 additions & 18 deletions ts/screens/wallet/PaymentHistoryDetailsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import {
import { SlidedContentComponent } from "../../components/wallet/SlidedContentComponent";
import I18n from "../../i18n";
import {
getCodiceAvviso,
isPaymentDoneSuccessfully,
PaymentHistory
} from "../../store/reducers/payments/history";
Expand All @@ -37,6 +36,7 @@ import { Transaction } from "../../types/pagopa";
import { formatDateAsLocal } from "../../utils/dates";
import { maybeInnerProperty } from "../../utils/options";
import {
getCodiceAvviso,
getErrorDescription,
getPaymentHistoryDetails,
getTransactionFee
Expand Down Expand Up @@ -191,21 +191,21 @@ class PaymentHistoryDetailsScreen extends React.Component<Props> {
);

private renderHelper = () => (
<View>
<Text alignCenter={true} style={styles.padded}>
{I18n.t("payment.details.info.help")}
</Text>
<View spacer={true} />
<ButtonDefaultOpacity
onPress={this.instabugLogAndOpenReport}
bordered={true}
block={true}
>
<IconFont name={"io-messaggi"} />
<Text>{I18n.t("payment.details.info.buttons.help")}</Text>
</ButtonDefaultOpacity>
</View>
);
<View>
<Text alignCenter={true} style={styles.padded}>
{I18n.t("payment.details.info.help")}
</Text>
<View spacer={true} />
<ButtonDefaultOpacity
onPress={this.instabugLogAndOpenReport}
bordered={true}
block={true}
>
<IconFont name={"io-messaggi"} />
<Text>{I18n.t("payment.details.info.buttons.help")}</Text>
</ButtonDefaultOpacity>
</View>
);

public render(): React.ReactNode {
const data = this.getData();
Expand Down Expand Up @@ -318,7 +318,7 @@ class PaymentHistoryDetailsScreen extends React.Component<Props> {
}

const mapStateToProps = (state: GlobalState) => ({
profile: profileSelector(state)
});
profile: profileSelector(state)
});

export default connect(mapStateToProps)(PaymentHistoryDetailsScreen);
7 changes: 7 additions & 0 deletions ts/store/actions/wallet/wallets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ export const addWalletCreditCardSuccess = createStandardAction(
"WALLET_ADD_CREDITCARD_SUCCESS"
)<WalletResponse>();

// this action describes when a new card is completed onboarded (add + pay + checkout)
// and available in wallets list
export const addWalletNewCreditCardSuccess = createStandardAction(
"WALLET_ADD_NEW_CREDITCARD_SUCCESS"
)();

export const addWalletCreditCardFailure = createStandardAction(
"WALLET_ADD_CREDITCARD_FAILURE"
)<"GENERIC_ERROR" | "ALREADY_EXISTS">();
Expand Down Expand Up @@ -134,6 +140,7 @@ export type WalletsActions =
| ActionType<typeof addWalletCreditCardRequest>
| ActionType<typeof addWalletCreditCardSuccess>
| ActionType<typeof addWalletCreditCardFailure>
| ActionType<typeof addWalletNewCreditCardSuccess>
| ActionType<typeof payCreditCardVerificationRequest>
| ActionType<typeof payCreditCardVerificationSuccess>
| ActionType<typeof payCreditCardVerificationFailure>
Expand Down
52 changes: 28 additions & 24 deletions ts/store/middlewares/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ import {
addWalletCreditCardFailure,
addWalletCreditCardInit,
addWalletCreditCardRequest,
addWalletNewCreditCardSuccess,
creditCardCheckout3dsRequest,
creditCardCheckout3dsSuccess,
deleteWalletFailure,
Expand Down Expand Up @@ -328,6 +329,7 @@ const trackAction = (mp: NonNullable<typeof mixpanel>) => (
case getType(fetchWalletsRequest):
case getType(addWalletCreditCardInit):
case getType(addWalletCreditCardRequest):
case getType(addWalletNewCreditCardSuccess):
case getType(payCreditCardVerificationRequest):
case getType(payCreditCardVerificationSuccess):
case getType(creditCardCheckout3dsRequest):
Expand Down Expand Up @@ -409,29 +411,31 @@ export const actionTracking = (_: MiddlewareAPI) => (next: Dispatch) => (
export function screenTracking(
store: MiddlewareAPI
): (_: Dispatch) => (__: Action) => Action {
return (next: Dispatch): ((_: Action) => Action) => (action: Action): Action => {
if (
action.type !== NavigationActions.NAVIGATE &&
action.type !== NavigationActions.BACK
) {
return next(action);
}
const currentScreen = getCurrentRouteName(store.getState().nav);
const result = next(action);
const nextScreen = getCurrentRouteName(store.getState().nav);
if (nextScreen !== currentScreen && mixpanel) {
if (nextScreen) {
setInstabugUserAttribute("activeScreen", nextScreen);
}
mixpanel
.track("SCREEN_CHANGE", {
SCREEN_NAME: nextScreen
})
.then(
() => 0,
() => 0
);
return (next: Dispatch): ((_: Action) => Action) => (
action: Action
): Action => {
if (
action.type !== NavigationActions.NAVIGATE &&
action.type !== NavigationActions.BACK
) {
return next(action);
}
const currentScreen = getCurrentRouteName(store.getState().nav);
const result = next(action);
const nextScreen = getCurrentRouteName(store.getState().nav);
if (nextScreen !== currentScreen && mixpanel) {
if (nextScreen) {
setInstabugUserAttribute("activeScreen", nextScreen);
}
return result;
};
mixpanel
.track("SCREEN_CHANGE", {
SCREEN_NAME: nextScreen
})
.then(
() => 0,
() => 0
);
}
return result;
};
}
31 changes: 0 additions & 31 deletions ts/store/reducers/payments/history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,35 +143,4 @@ export const isPaymentDoneSuccessfully = (
);
};

export const getIuv = (data: RptId): string => {
switch (data.paymentNoticeNumber.auxDigit) {
case "0":
case "3":
return data.paymentNoticeNumber.iuv13;
case "1":
return data.paymentNoticeNumber.iuv17;
case "2":
return data.paymentNoticeNumber.iuv15;
default:
return "";
}
};

// return the notice code from the given rptId
export const getCodiceAvviso = (rptId: RptId) => {
const pnn = rptId.paymentNoticeNumber;
switch (pnn.auxDigit) {
case "0":
return `${pnn.auxDigit}${pnn.applicationCode}${pnn.iuv13}${pnn.checkDigit}`;
case "1":
return `${pnn.auxDigit}${pnn.iuv17}`;
case "2":
return `${pnn.auxDigit}${pnn.iuv15}${pnn.checkDigit}`;
case "3":
return `${pnn.auxDigit}${pnn.iuv13}${pnn.checkDigit}${pnn.segregationCode}`;
default:
return "";
}
};

export default reducer;
60 changes: 57 additions & 3 deletions ts/utils/__tests__/payment.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { PaymentNoticeNumber } from "../../../definitions/backend/PaymentNoticeN
import { Transaction } from "../../types/pagopa";
import {
cleanTransactionDescription,
getCodiceAvviso,
getTransactionFee,
getTransactionIUV
} from "../payment";
Expand Down Expand Up @@ -86,7 +87,7 @@ describe("cleanTransactionDescription", () => {
],
[
"/RFS/0123456789012/666.98/TXT/ actual description/other text",
"actual description"
"actual description/other text"
],
[
"/RFB/000001234556859/143.00",
Expand All @@ -97,8 +98,8 @@ describe("cleanTransactionDescription", () => {
["/XYZ/TXT/some text", "some text"],
["/TXT/some text", "some text"],
["TXT/some text", "some text"],
["/TXT/some text/other text", "some text"],
["TXT/some text/other text", "some text"],
["/TXT/some text/other text", "some text/other text"],
["TXT/some text/other text", "some text/other text"],
["actual description", "actual description"]
].forEach(([dirty, cleaned]) => {
expect(cleanTransactionDescription(dirty)).toEqual(cleaned);
Expand Down Expand Up @@ -228,3 +229,56 @@ describe("getTransactionIUV", () => {
expect(getTransactionIUV(tuple.e1)).toEqual(tuple.e2);
});
});

describe("getCodiceAvviso", () => {
const organizationFiscalCode = "00000123456";
[
Tuple2<RptId, string>(
RptId.decode({
organizationFiscalCode,
paymentNoticeNumber: {
applicationCode: "02",
auxDigit: "0",
checkDigit: "78",
iuv13: "1600203993985"
}
}).value as RptId,
`002160020399398578`
),
Tuple2<RptId, string>(
RptId.decode({
organizationFiscalCode,
paymentNoticeNumber: {
auxDigit: "1",
iuv17: "16002039939851111"
}
}).value as RptId,
`116002039939851111`
),
Tuple2<RptId, string>(
RptId.decode({
organizationFiscalCode,
paymentNoticeNumber: {
checkDigit: "78",
auxDigit: "2",
iuv15: "160020399398511"
}
}).value as RptId,
`216002039939851178`
),
Tuple2<RptId, string>(
RptId.decode({
organizationFiscalCode,
paymentNoticeNumber: {
checkDigit: "78",
auxDigit: "3",
segregationCode: "55",
iuv13: "1600203993985"
}
}).value as RptId,
`355160020399398578`
)
].forEach(tuple => {
expect(getCodiceAvviso(tuple.e1)).toEqual(tuple.e2);
});
});
43 changes: 38 additions & 5 deletions ts/utils/payment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,7 @@ import { InitializedProfile } from "../../definitions/backend/InitializedProfile
import { PaymentAmount } from "../../definitions/backend/PaymentAmount";
import { PaymentNoticeNumber } from "../../definitions/backend/PaymentNoticeNumber";
import { DetailEnum } from "../../definitions/backend/PaymentProblemJson";
import {
getCodiceAvviso,
PaymentHistory
} from "../store/reducers/payments/history";
import { PaymentHistory } from "../store/reducers/payments/history";
import { Psp, Transaction, Wallet } from "../types/pagopa";
import { formatDateAsReminder } from "./dates";
import { getLocalePrimaryWithFallback } from "./locale";
Expand Down Expand Up @@ -128,7 +125,7 @@ export const cleanTransactionDescription = (description: string): string => {
const descriptionParts = description.split("TXT/");

return descriptionParts.length > 1
? descriptionParts[descriptionParts.length - 1].split("/")[0].trim()
? descriptionParts[descriptionParts.length - 1].trim()
: getTransactionIUV(description) // try to extract codice avviso from description
.chain(maybeNotNullyString)
.map(
Expand Down Expand Up @@ -237,3 +234,39 @@ export const orderPspByAmount = (pspList: ReadonlyArray<Psp>) =>
}
return 0;
});

export const getIuv = (data: RptId): string => {
switch (data.paymentNoticeNumber.auxDigit) {
case "0":
case "3":
return data.paymentNoticeNumber.iuv13;
case "1":
return data.paymentNoticeNumber.iuv17;
case "2":
return data.paymentNoticeNumber.iuv15;
}
};

// return the notice code from the given rptId
// see https://docs.italia.it/italia/pagopa/pagopa-codici-docs/it/stabile/_docs/Capitolo2.html#valore-0-del-componente-aux-digit
export const getCodiceAvviso = (rptId: RptId) => {
const pnn = rptId.paymentNoticeNumber;
switch (pnn.auxDigit) {
// 0<application code (2n)><IUV base (13n)><IUV check digit (2n)>
case "0":
return `${pnn.auxDigit}${pnn.applicationCode}${getIuv(rptId)}${
pnn.checkDigit
}`;
// 1<IUV base (17n)>
case "1":
return `${pnn.auxDigit}${getIuv(rptId)}`;
// 2<IUV base (15n)><IUV check digit (2n)>
case "2":
return `${pnn.auxDigit}${getIuv(rptId)}${pnn.checkDigit}`;
case "3":
// 3<codice segregazione (2n)><IUVbase (13n)><IUV check digit (2n)>
return `${pnn.auxDigit}${pnn.segregationCode}${getIuv(rptId)}${
pnn.checkDigit
}`;
}
};