diff --git a/package.json b/package.json index 4d221e06..58b08a5b 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "api_trial_system": "https://raw.githubusercontent.com/pagopa/io-backend/v14.3.0-RELEASE/api_trial_system.yaml", "api_pagopa_walletv3": "https://raw.githubusercontent.com/pagopa/pagopa-infra/v1.202.0/src/domains/pay-wallet-app/api/io-payment-wallet/v1/_openapi.json.tpl", "api_pagopa_ecommerce": "https://raw.githubusercontent.com/pagopa/pagopa-infra/v1.202.0/src/domains/ecommerce-app/api/ecommerce-io/v2/_openapi.json.tpl", - "api_pagopa_biz_events": "https://raw.githubusercontent.com/pagopa/pagopa-biz-events-service/0.1.37/openapi/openapi_io_patch.json", + "api_pagopa_biz_events": "https://raw.githubusercontent.com/pagopa/pagopa-biz-events-service/0.1.57/openapi/openapi_io_patch_lap.json", "api_pagopa_platform": "https://raw.githubusercontent.com/pagopa/pagopa-infra/v1.64.0/src/domains/shared-app/api/session-wallet/v1/_openapi.json.tpl", "api_services": "https://raw.githubusercontent.com/pagopa/io-backend/master/api_services_app_backend.yaml", "author": "Matteo Boschi", diff --git a/src/features/payments/persistence/notices.ts b/src/features/payments/persistence/notices.ts new file mode 100644 index 00000000..3f085470 --- /dev/null +++ b/src/features/payments/persistence/notices.ts @@ -0,0 +1,119 @@ +import { faker } from "@faker-js/faker"; +import { pipe } from "fp-ts/lib/function"; +import * as O from "fp-ts/lib/Option"; +import { NoticeListItem } from "../../../../generated/definitions/pagopa/transactions/NoticeListItem"; +import { NoticeDetailResponse } from "../../../../generated/definitions/pagopa/transactions/NoticeDetailResponse"; +import { TransactionInfo } from "../../../../generated/definitions/pagopa/ecommerce/TransactionInfo"; +import { generateRandomInfoNotice } from "../utils/transactions"; +import { ioDevServerConfig } from "../../../config"; + +const mockedTaxCodes = ["1199250158", "13756881002", "262700362", "31500945"]; + +type EventId = NoticeListItem["eventId"]; + +const userNotices = new Map(); +const notices = new Map(); + +const getUserNotices = () => + Array.from(userNotices.size > 0 ? userNotices.values() : []); + +const getNoticeDetails = (eventId: EventId) => + pipe( + notices, + O.fromNullable, + O.chain(notices => O.fromNullable(notices.get(eventId))) + ); + +const addUserNotice = (transaction: NoticeListItem) => { + userNotices.set(transaction.eventId, transaction); +}; + +const removeUserNotice = (eventId: EventId) => { + userNotices.delete(eventId); + removeNoticeDetails(eventId); +}; + +const addNoticeDetails = (eventId: EventId, notice: NoticeDetailResponse) => { + notices.set(eventId, notice); +}; + +const removeNoticeDetails = (eventId: EventId) => { + notices.delete(eventId); +}; + +const generateUserNotice = ( + eventId: EventId, + idx: number, + additionalTransactionInfo: Partial = {} +) => { + const payeeTaxCode = + mockedTaxCodes[ + faker.datatype.number({ min: 0, max: mockedTaxCodes.length - 1 }) + ]; + const randomNotice: NoticeListItem = { + eventId, + payeeName: faker.company.name(), + payeeTaxCode, + isDebtor: false, + isPayer: true, + amount: additionalTransactionInfo.payments?.[0]?.amount.toString() || "", + noticeDate: new Date( + new Date().setDate(new Date().getDate() - 2 * idx) + ).toISOString(), + isCart: false + }; + + const cartList = Array.from( + { length: faker.datatype.number({ min: 1, max: 2 }) }, + () => ({ + subject: faker.lorem.sentence(faker.datatype.number({ min: 2, max: 4 })), + amount: faker.finance.amount(1, 1000), + payee: { + name: randomNotice.payeeName, + taxCode: randomNotice.payeeTaxCode + }, + debtor: { + name: faker.name.fullName(), + taxCode: faker.random.alphaNumeric(16).toUpperCase() + }, + refNumberType: "IBAN", + refNumberValue: faker.datatype + .number({ min: 100000000000, max: 999999999999 }) + .toString() + }) + ); + const updatedNotice = { + ...randomNotice, + isCart: cartList.length > 1, + amount: cartList + .reduce((acc, item) => acc + Number(item.amount), 0) + .toString() + }; + addUserNotice(updatedNotice); + + const randomNoticeDetails: NoticeDetailResponse = { + infoNotice: generateRandomInfoNotice(cartList), + carts: cartList + }; + addNoticeDetails(eventId, randomNoticeDetails); + return randomNotice; +}; + +const generateUserNoticeData = () => { + for (const i of Array( + ioDevServerConfig.features.payments.numberOfTransactions + ).keys()) { + generateUserNotice(faker.datatype.uuid(), i); + } +}; + +// At server startup +generateUserNoticeData(); + +export default { + addUserNotice, + getUserNotices, + getNoticeDetails, + generateUserNotice, + removeUserNotice +}; diff --git a/src/features/payments/persistence/transactions.ts b/src/features/payments/persistence/transactions.ts deleted file mode 100644 index d6f39a2d..00000000 --- a/src/features/payments/persistence/transactions.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { faker } from "@faker-js/faker"; -import { pipe } from "fp-ts/lib/function"; -import * as O from "fp-ts/lib/Option"; -import { TransactionListItem } from "../../../../generated/definitions/pagopa/transactions/TransactionListItem"; -import { TransactionDetailResponse } from "../../../../generated/definitions/pagopa/transactions/TransactionDetailResponse"; -import { TransactionInfo } from "../../../../generated/definitions/pagopa/ecommerce/TransactionInfo"; -import { generateRandomInfoTransaction } from "../utils/transactions"; -import { ioDevServerConfig } from "../../../config"; - -const mockedTaxCodes = ["1199250158", "13756881002", "262700362", "31500945"]; - -type TransactionId = TransactionListItem["transactionId"]; - -const userTransactions = new Map(); -const transactions = new Map(); - -const getUserTransactions = () => - Array.from(userTransactions.size > 0 ? userTransactions.values() : []); - -const getTransactionDetails = (transactionId: TransactionId) => - pipe( - transactions, - O.fromNullable, - O.chain(transactions => O.fromNullable(transactions.get(transactionId))) - ); - -const addUserTransaction = (transaction: TransactionListItem) => { - userTransactions.set(transaction.transactionId, transaction); -}; - -const removeUserTransaction = (transactionId: TransactionId) => { - userTransactions.delete(transactionId); - removeTransactionDetails(transactionId); -}; - -const addTransactionDetails = ( - transactionId: TransactionId, - transaction: TransactionDetailResponse -) => { - transactions.set(transactionId, transaction); -}; - -const removeTransactionDetails = (transactionId: TransactionId) => { - transactions.delete(transactionId); -}; - -const generateUserTransaction = ( - transactionId: TransactionId, - idx: number, - additionalTransactionInfo: Partial = {} -) => { - const payeeTaxCode = - mockedTaxCodes[ - faker.datatype.number({ min: 0, max: mockedTaxCodes.length - 1 }) - ]; - const randomTransaction: TransactionListItem = { - transactionId, - payeeName: faker.company.name(), - payeeTaxCode, - amount: additionalTransactionInfo.payments?.[0]?.amount.toString(), - transactionDate: new Date( - new Date().setDate(new Date().getDate() - 2 * idx) - ).toISOString(), - isCart: false - }; - - const cartList = Array.from( - { length: faker.datatype.number({ min: 1, max: 2 }) }, - () => ({ - subject: faker.lorem.sentence(faker.datatype.number({ min: 2, max: 4 })), - amount: faker.finance.amount(1, 1000), - payee: { - name: randomTransaction.payeeName, - taxCode: randomTransaction.payeeTaxCode - }, - debtor: { - name: faker.name.fullName(), - taxCode: faker.random.alphaNumeric(16).toUpperCase() - }, - refNumberType: "IBAN", - refNumberValue: faker.datatype - .number({ min: 100000000000, max: 999999999999 }) - .toString() - }) - ); - // eslint-disable-next-line functional/immutable-data - randomTransaction.isCart = cartList.length > 1; - // eslint-disable-next-line functional/immutable-data - randomTransaction.amount = cartList - .reduce((acc, item) => acc + Number(item.amount), 0) - .toString(); - addUserTransaction(randomTransaction); - - const randomTransactionDetails: TransactionDetailResponse = { - infoTransaction: generateRandomInfoTransaction(cartList), - carts: cartList - }; - addTransactionDetails(transactionId, randomTransactionDetails); - return randomTransaction; -}; - -const generateUserTransactionData = () => { - for ( - // eslint-disable-next-line functional/no-let - let i = 0; - i < ioDevServerConfig.features.payments.numberOfTransactions; - i = i + 1 - ) { - generateUserTransaction(faker.datatype.uuid(), i); - } -}; - -// At server startup -generateUserTransactionData(); - -export default { - addUserTransaction, - getUserTransactions, - getTransactionDetails, - generateUserTransaction, - removeUserTransaction -}; diff --git a/src/features/payments/routers/index.ts b/src/features/payments/routers/index.ts index 35e032e9..fabc2ba4 100644 --- a/src/features/payments/routers/index.ts +++ b/src/features/payments/routers/index.ts @@ -1,6 +1,6 @@ import "./payment"; import "./wallets"; -import "./transactions"; +import "./notices"; import "./platform"; export { walletRouter } from "./router"; diff --git a/src/features/payments/routers/transactions.ts b/src/features/payments/routers/notices.ts similarity index 54% rename from src/features/payments/routers/transactions.ts rename to src/features/payments/routers/notices.ts index 83e69786..02ad348a 100644 --- a/src/features/payments/routers/transactions.ts +++ b/src/features/payments/routers/notices.ts @@ -1,32 +1,28 @@ import * as O from "fp-ts/lib/Option"; import { pipe } from "fp-ts/lib/function"; -import TransactionsDB from "../persistence/transactions"; +import NoticesDB from "../persistence/notices"; import { sendFileFromRootPath } from "../../../utils/file"; -import { TransactionListWrapResponse } from "../../../../generated/definitions/pagopa/transactions/TransactionListWrapResponse"; -import { addTransactionHandler } from "./router"; +import { NoticeListWrapResponse } from "../../../../generated/definitions/pagopa/transactions/NoticeListWrapResponse"; +import { addNoticesHandler } from "./router"; const CONTINUATION_TOKEN_HEADER = "x-continuation-token"; +const DEFAULT_SIZE = 10; -addTransactionHandler("get", "/transactions", (req, res) => { - const size = req.query.size ? Number(req.query.size) : 10; - const offset = - req.headers[CONTINUATION_TOKEN_HEADER] !== undefined && - req.headers[CONTINUATION_TOKEN_HEADER] !== "undefined" - ? Number(req.headers[CONTINUATION_TOKEN_HEADER]) - : 0; - const response: TransactionListWrapResponse = { - transactions: TransactionsDB.getUserTransactions().slice( - offset, - offset + size - ) +addNoticesHandler("get", "/paids", (req, res) => { + const size = req.query.size ? Number(req.query.size) : DEFAULT_SIZE; + const offset = isNaN(Number(req.headers[CONTINUATION_TOKEN_HEADER])) + ? 0 + : Number(req.headers[CONTINUATION_TOKEN_HEADER]); + const response: NoticeListWrapResponse = { + notices: NoticesDB.getUserNotices().slice(offset, offset + size) }; const continuationToken = - TransactionsDB.getUserTransactions().length > offset + size + NoticesDB.getUserNotices().length > offset + size ? (offset + size).toString() : undefined; pipe( - response.transactions, + response.notices, O.fromNullable, O.chain(O.fromPredicate(transactions => transactions.length > 0)), O.fold( @@ -46,14 +42,14 @@ addTransactionHandler("get", "/transactions", (req, res) => { ); }); -addTransactionHandler("get", "/transactions/:transactionId", (req, res) => { +addNoticesHandler("get", "/paids/:eventId", (req, res) => { pipe( - req.params.transactionId, + req.params.eventId, O.fromNullable, O.fold( () => res.sendStatus(400), - transactionId => { - const transaction = TransactionsDB.getTransactionDetails(transactionId); + eventId => { + const transaction = NoticesDB.getNoticeDetails(eventId); return pipe( transaction, O.fold( @@ -66,14 +62,14 @@ addTransactionHandler("get", "/transactions/:transactionId", (req, res) => { ); }); -addTransactionHandler("get", "/transactions/:transactionId/pdf", (req, res) => { +addNoticesHandler("get", "/paids/:eventId/pdf", (req, res) => { pipe( - req.params.transactionId, + req.params.eventId, O.fromNullable, O.fold( () => res.sendStatus(400), - transactionId => { - const transaction = TransactionsDB.getTransactionDetails(transactionId); + eventId => { + const transaction = NoticesDB.getNoticeDetails(eventId); return pipe( transaction, O.fold( diff --git a/src/features/payments/routers/payment.ts b/src/features/payments/routers/payment.ts index 8d22fa3e..ec849fee 100644 --- a/src/features/payments/routers/payment.ts +++ b/src/features/payments/routers/payment.ts @@ -20,7 +20,7 @@ import { getTransactionInfoPayload } from "../payloads/transactions"; import WalletDB from "../persistence/userWallet"; -import TransactionsDB from "../persistence/transactions"; +import NoticesDB from "../persistence/notices"; import { WalletPaymentFailure, getStatusCodeForWalletFailure @@ -210,7 +210,7 @@ addPaymentHandler("post", "/mock-transaction", (req, res) => O.fold( () => res.sendStatus(404), () => { - TransactionsDB.generateUserTransaction(transactionId, 0); + NoticesDB.generateUserNotice(transactionId, 0); return res.status(200).json({ status: "ok" }); } ) diff --git a/src/features/payments/routers/router.ts b/src/features/payments/routers/router.ts index 470954b9..8165975f 100644 --- a/src/features/payments/routers/router.ts +++ b/src/features/payments/routers/router.ts @@ -5,7 +5,7 @@ export const walletRouter = Router(); export const PAYMENT_WALLET_PREFIX = "/io-payment-wallet/v1"; export const ECOMMERCE_PREFIX = "/ecommerce/io/v2"; -export const TRANSACTIONS_PREFIX = "/bizevents/tx-service-jwt/v1"; +export const NOTICES_PREFIX = "/bizevents/notices-service-jwt/v1"; export const PLATFORM_PREFIX = "/session-wallet/v1"; export const addPaymentWalletPrefix = (path: string) => @@ -14,8 +14,7 @@ export const addPaymentWalletPrefix = (path: string) => export const addECommercePrefix = (path: string) => `${ECOMMERCE_PREFIX}${path}`; -export const addTransactionPrefix = (path: string) => - `${TRANSACTIONS_PREFIX}${path}`; +export const addNoticesPrefix = (path: string) => `${NOTICES_PREFIX}${path}`; export const addPlatformPrefix = (path: string) => `${PLATFORM_PREFIX}${path}`; @@ -32,12 +31,11 @@ export const addPaymentHandler = ( handleRequest: (request: Request, response: Response) => void ) => addHandler(walletRouter, method, addECommercePrefix(path), handleRequest); -export const addTransactionHandler = ( +export const addNoticesHandler = ( method: SupportedMethod, path: string, handleRequest: (request: Request, response: Response) => void -) => - addHandler(walletRouter, method, addTransactionPrefix(path), handleRequest); +) => addHandler(walletRouter, method, addNoticesPrefix(path), handleRequest); export const addPlatformHandler = ( method: SupportedMethod, diff --git a/src/features/payments/utils/transactions.ts b/src/features/payments/utils/transactions.ts index 9f916a85..c9608592 100644 --- a/src/features/payments/utils/transactions.ts +++ b/src/features/payments/utils/transactions.ts @@ -1,10 +1,10 @@ import { faker } from "@faker-js/faker"; import { ulid } from "ulid"; import { - InfoTransactionView, + InfoNotice, OriginEnum, PaymentMethodEnum -} from "../../../../generated/definitions/pagopa/transactions/InfoTransactionView"; +} from "../../../../generated/definitions/pagopa/transactions/InfoNotice"; import { CartItem } from "../../../../generated/definitions/pagopa/transactions/CartItem"; export const PAYMENT_METHODS_TRANSACTIONS_MOCK = [ @@ -40,18 +40,18 @@ export const PAYMENT_METHODS_TRANSACTIONS_MOCK = [ } ]; -export const generateRandomInfoTransaction = ( +export const generateRandomInfoNotice = ( cartList: CartItem[], - transactionId?: string -): InfoTransactionView => { + eventId?: string +): InfoNotice => { const randomPaymentMethod = faker.helpers.arrayElement( PAYMENT_METHODS_TRANSACTIONS_MOCK ); return { - transactionId: transactionId ?? ulid(), + eventId: eventId ?? ulid(), authCode: faker.random.alphaNumeric(6), rrn: faker.random.numeric(12), - transactionDate: new Date().toISOString(), + noticeDate: new Date().toISOString(), pspName: "Intesa Sanpaolo", walletInfo: { accountHolder: faker.name.fullName(),