From bf0df7aeeace34a50b046df28e66ed833aa83019 Mon Sep 17 00:00:00 2001 From: Beppe Catanese Date: Mon, 4 Dec 2023 21:33:57 +0100 Subject: [PATCH] Implement getTransactions --- react-app/src/dashboard/Payments.js | 112 +++++++++++++++++- .../adyen/controller/DashboardController.java | 15 +++ .../java/com/adyen/model/TransactionItem.java | 89 ++++++++++++++ .../service/ConfigurationAPIService.java | 57 +++++++++ .../com/adyen/util/TransactionHandler.java | 66 +++++++++++ 5 files changed, 335 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/adyen/model/TransactionItem.java create mode 100644 src/main/java/com/adyen/util/TransactionHandler.java diff --git a/react-app/src/dashboard/Payments.js b/react-app/src/dashboard/Payments.js index d3c4fc5..d51493b 100644 --- a/react-app/src/dashboard/Payments.js +++ b/react-app/src/dashboard/Payments.js @@ -1,17 +1,58 @@ -import * as React from 'react'; +import React, { useState, useEffect } from 'react'; +import axios from "axios"; + + import Box from '@mui/material/Box'; import Chip from '@mui/material/Chip'; import Toolbar from '@mui/material/Toolbar'; import Divider from '@mui/material/Divider'; -import { useParams } from "react-router-dom"; +import { useNavigate } from 'react-router-dom'; + +import Paper from '@mui/material/Paper'; +import Table from '@mui/material/Table'; +import TableBody from '@mui/material/TableBody'; +import TableCell from '@mui/material/TableCell'; +import TableContainer from '@mui/material/TableContainer'; +import TableHead from '@mui/material/TableHead'; +import TablePagination from '@mui/material/TablePagination'; +import TableRow from '@mui/material/TableRow'; import DashboardHeader from "./DashboardHeader.js"; import DashboardDrawer from "./DashboardDrawer.js"; export default function Products() { + const navigate = useNavigate() + + const [page, setPage] = useState(0); + const [rowsPerPage, setRowsPerPage] = useState(10); + const [rows, setRows] = useState([]); + + const handleChangePage = (event, newPage) => { + setPage(newPage); + }; + + const handleChangeRowsPerPage = (event) => { + setRowsPerPage(+event.target.value); + setPage(0); + }; + + useEffect(() => { + const fetchData = async () => { + try { + const response = await axios.post('/api/dashboard/getTransactions'); + setRows(response.data); + } catch (error) { + console.error('API request error:', error); + navigate('/'); + } + }; + + fetchData(); + }, []); + return ( @@ -30,11 +71,74 @@ export default function Products() { - +

+
+ + + + + + + {columns.map((column) => ( + + {column.label} + + ))} + + + + {rows + .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) + .map((row) => { + return ( + + {columns.map((column) => { + const value = row[column.id]; + return ( + + {column.format && typeof value === 'number' + ? column.format(value) + : value} + + ); + })} + + ); + })} + +
+
+ +
+ +
); -} \ No newline at end of file +} + +const columns = [ + { id: 'id', label: 'ID', minWidth: 100 }, + { id: 'status', label: 'Status', minWidth: 120 }, + { id: 'type', label: 'Type', minWidth: 120 }, + { id: 'created', label: 'Created', minWidth: 220 }, + { id: 'amount', label: 'Amount', minWidth: 150 }, + { id: 'pspReference', label: 'PSP Reference', minWidth: 200 }, +]; \ No newline at end of file diff --git a/src/main/java/com/adyen/controller/DashboardController.java b/src/main/java/com/adyen/controller/DashboardController.java index 3f128f8..0d99ec1 100644 --- a/src/main/java/com/adyen/controller/DashboardController.java +++ b/src/main/java/com/adyen/controller/DashboardController.java @@ -1,6 +1,7 @@ package com.adyen.controller; import com.adyen.model.OnboardingLinkProperties; +import com.adyen.model.TransactionItem; import com.adyen.model.User; import com.adyen.model.balanceplatform.AccountHolder; import com.adyen.model.legalentitymanagement.LegalEntity; @@ -15,6 +16,8 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import java.util.Arrays; +import java.util.List; import java.util.Optional; @RestController @@ -92,6 +95,18 @@ ResponseEntity getOnboardingLink(@RequestBody OnboardingLinkProperties o ); } + @PostMapping("/getTransactions") + ResponseEntity> getTransactions() { + + if (getUserIdOnSession() == null) { + log.warn("User is not logged in"); + return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); + } + + return new ResponseEntity<>( + getConfigurationAPIService().getTransactions(getUserIdOnSession()), HttpStatus.ACCEPTED); + } + public ConfigurationAPIService getConfigurationAPIService() { return configurationAPIService; } diff --git a/src/main/java/com/adyen/model/TransactionItem.java b/src/main/java/com/adyen/model/TransactionItem.java new file mode 100644 index 0000000..d0861e6 --- /dev/null +++ b/src/main/java/com/adyen/model/TransactionItem.java @@ -0,0 +1,89 @@ +package com.adyen.model; + +public class TransactionItem { + private String id; + private String status; + private String type; + private String created; + private String amount; + private String pspReference; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreated() { + return created; + } + + public void setCreated(String created) { + this.created = created; + } + + public String getAmount() { + return amount; + } + + public void setAmount(String amount) { + this.amount = amount; + } + + public String getPspReference() { + return pspReference; + } + + public void setPspReference(String pspReference) { + this.pspReference = pspReference; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public TransactionItem id(String id) { + this.id = id; + return this; + } + + public TransactionItem status(String status) { + this.status = status; + return this; + } + + public TransactionItem created(String created) { + this.created = created; + return this; + } + + public TransactionItem amount(String amount) { + this.amount = amount; + return this; + } + + public TransactionItem pspReference(String pspReference) { + this.pspReference = pspReference; + return this; + } + + public TransactionItem type(String type) { + this.type = type; + return this; + } + +} diff --git a/src/main/java/com/adyen/service/ConfigurationAPIService.java b/src/main/java/com/adyen/service/ConfigurationAPIService.java index d42b13e..3696b59 100644 --- a/src/main/java/com/adyen/service/ConfigurationAPIService.java +++ b/src/main/java/com/adyen/service/ConfigurationAPIService.java @@ -4,14 +4,22 @@ import com.adyen.config.ApplicationProperty; import com.adyen.enums.Environment; import com.adyen.model.AccountHolderStatus; +import com.adyen.model.TransactionItem; import com.adyen.model.balanceplatform.*; +import com.adyen.model.transfers.Transaction; +import com.adyen.model.transfers.TransactionSearchResponse; import com.adyen.service.balanceplatform.AccountHoldersApi; import com.adyen.service.balanceplatform.BalanceAccountsApi; +import com.adyen.service.transfers.TransactionsApi; +import com.adyen.util.TransactionHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.time.OffsetDateTime; +import java.time.temporal.ChronoUnit; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.UUID; @@ -32,6 +40,9 @@ public class ConfigurationAPIService { @Autowired private ApplicationProperty applicationProperty; + @Autowired + private TransactionHandler transactionHandler; + public Optional getAccountHolder(String accountHolderId) { Optional accountHolder = Optional.empty(); @@ -119,6 +130,40 @@ public BalanceAccount createBalanceAccount(String accountHolderId) { return balanceAccount; } + /** + * Get all transactions for the user (accountHolder) + * @param accountHolderId + * @return + */ + public List getTransactions(String accountHolderId) { + + List transactionItems = null; + + try { + + // in the last X days + OffsetDateTime createdSince = OffsetDateTime.now().minus(365, ChronoUnit.DAYS); + // until today + OffsetDateTime createdUntil = OffsetDateTime.now(); + // max number of transactions to fetch + Integer limit = 100; + + TransactionSearchResponse transactionSearchResponse = getTransactionsApi().getAllTransactions( + null, null, accountHolderId, null, + null, createdSince, createdUntil, limit, null); + + log.info(transactionSearchResponse.getData().toString()); + + transactionItems = getTransactionHandler().getTransactionItems(transactionSearchResponse.getData()); + } catch (Exception e) { + log.error(e.toString(), e); + throw new RuntimeException("Cannot create BalanceAccount: " + e.getMessage()); + } + + return transactionItems; + + } + // AccountHoldersApi handler private AccountHoldersApi getAccountHoldersApi() { return new AccountHoldersApi(getApiClient()); @@ -129,6 +174,11 @@ private BalanceAccountsApi getBalanceAccountsApi() { return new BalanceAccountsApi(getApiClient()); } + private TransactionsApi getTransactionsApi() { + return new TransactionsApi(getApiClient()); + } + + // create client to access the Configuration API private Client getApiClient() { if (apiClient == null) { @@ -149,4 +199,11 @@ public void setApplicationProperty(ApplicationProperty applicationProperty) { this.applicationProperty = applicationProperty; } + public TransactionHandler getTransactionHandler() { + return transactionHandler; + } + + public void setTransactionHandler(TransactionHandler transactionHandler) { + this.transactionHandler = transactionHandler; + } } diff --git a/src/main/java/com/adyen/util/TransactionHandler.java b/src/main/java/com/adyen/util/TransactionHandler.java new file mode 100644 index 0000000..ec51d01 --- /dev/null +++ b/src/main/java/com/adyen/util/TransactionHandler.java @@ -0,0 +1,66 @@ +package com.adyen.util; + +import com.adyen.model.TransactionItem; +import com.adyen.model.transfers.Amount; +import com.adyen.model.transfers.Transaction; +import org.springframework.stereotype.Service; + +import java.text.NumberFormat; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; + +/** + * Helper class to work with the Transaction class + */ +@Service +public class TransactionHandler { + + /** + * Create a list of TransactionItem from the given list of Transaction + * @param transactions + * @return + */ + public List getTransactionItems(List transactions) { + List transactionItems = new ArrayList<>(); + + for(Transaction transaction : transactions) { + transactionItems.add(getTransactionItem(transaction)); + } + + return transactionItems; + } + + /** + * Create a TransactionItem from the given Transaction + * @param transaction + * @return + */ + public TransactionItem getTransactionItem(Transaction transaction) { + return new TransactionItem() + .id(transaction.getId()) + .status(transaction.getStatus().getValue()) + .type(transaction.getAmount().getValue() > 0 ? "Incoming" : "Outgoing") + .created(formatDate(transaction.getCreationDate())) + .amount(formatAmount(transaction.getAmount())) + .pspReference(transaction.getEventId()); + } + + private String formatAmount(Amount amount) { + String ret = ""; + + if(amount != null) { + NumberFormat numberFormat = NumberFormat.getNumberInstance(); + String formattedAmount = numberFormat.format(amount.getValue()); + ret = amount.getCurrency() + " " + formattedAmount; + } + return ret; + } + + private String formatDate(OffsetDateTime offsetDateTime) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + return offsetDateTime.format(formatter); + } +}