Skip to content
Snippets Groups Projects
Commit 569410c9 authored by Martin Mojžiš's avatar Martin Mojžiš
Browse files

feat: persistence, delete balance added

parent 991b99ed
No related branches found
No related tags found
No related merge requests found
Showing
with 121 additions and 122 deletions
......@@ -6,7 +6,7 @@ GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA bank_user TO "ACC_USER";
CREATE SCHEMA IF NOT EXISTS bank_account;
CREATE USER "ACC_ACCOUNT" WITH PASSWORD 'accountAccPasswd';
ALTER ROLE "ACC_ACCOUNT" SET SEARCH_PATH TO bank_account;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA bank_account TO "ACC_ACCOUNT";
GRANT ALL PRIVILEGES ON SCHEMA bank_account TO "ACC_ACCOUNT";
CREATE SCHEMA IF NOT EXISTS bank_transaction;
CREATE USER "ACC_TRANSACTION" WITH PASSWORD 'transactionAccPasswd';
......
......@@ -2,3 +2,25 @@ SET ROLE "ACC_ACCOUNT";
SET SEARCH_PATH TO bank_account;
-- CREATE TABLES
CREATE TABLE IF NOT EXISTS bal_transaction
(
amount NUMERIC(38, 2),
type SMALLINT,
date TIMESTAMP(6) WITH TIME ZONE,
id BIGINT PRIMARY KEY,
process_id UUID,
balance_id CHARACTER VARYING(255)
);
CREATE TABLE IF NOT EXISTS balance
(
amount NUMERIC(38, 2),
balance_id CHARACTER VARYING(255) PRIMARY KEY
);
CREATE SEQUENCE bal_transaction_seq START WITH 1 INCREMENT BY 50;
ALTER TABLE bal_transaction ADD CONSTRAINT CONSTRAINT_FF CHECK(TYPE BETWEEN 0 AND 4);
ALTER TABLE bal_transaction ADD CONSTRAINT CONSTRAINT_F CHECK(TYPE BETWEEN 0 AND 4);
ALTER TABLE bal_transaction ADD CONSTRAINT FKICJDGHKQ3OQKDCDC6KKUJD6O3 FOREIGN KEY(BALANCE_ID) REFERENCES balance(BALANCE_ID);
\ No newline at end of file
SET SEARCH_PATH TO bank_account;
-- INSERT starting data
\ No newline at end of file
-- INSERT starting data
INSERT INTO balance VALUES
(90.00, 'id1'),
(118.00, 'id2'),
(243.00, 'id3'),
(-243.00, 'id4');
INSERT INTO bal_transaction VALUES
(90.00, 1, TIMESTAMP WITH TIME ZONE '2024-04-15 14:11:00.288446+02', 1, UUID 'b775b79f-52a9-45c4-8ab3-bdb9f0f3d4ae', 'id1'),
(94.00, 2, TIMESTAMP WITH TIME ZONE '2024-04-15 14:11:42.919109+02', 2, UUID 'c91b6ef6-32ac-4160-bf7f-97979ca84606', 'id2'),
(24.00, 1, TIMESTAMP WITH TIME ZONE '2024-04-15 14:11:57.480291+02', 3, UUID '6a1fa40e-3ba8-46a8-b005-8bcd63ae44de', 'id2'),
(243.00, 3, TIMESTAMP WITH TIME ZONE '2024-04-15 14:12:14.949613+02', 4, UUID 'd9974137-7000-4f34-8c64-1d35b0534e31', 'id3'),
(-243.00, 3, TIMESTAMP WITH TIME ZONE '2024-04-15 14:12:23.109443+02', 5, UUID 'd9974137-7000-4f34-8c64-1d35b0534e31', 'id4');
\ No newline at end of file
stages:
- build
- test
image: maven:latest
......@@ -13,11 +14,14 @@ test-account-management:
test-account-query:
stage: test
image: docker
tags:
- shared-fi
script:
- 'docker-compose up -d'
- 'cd account-query'
- 'mvn clean install'
- 'docker-compose down'
test-infrastructure:
stage: test
......
FROM eclipse-temurin:21.0.2_13-jdk-alpine
WORKDIR /app
COPY target/*.jar /account-query.jar
EXPOSE 8081
ENTRYPOINT ["java", "-jar", "-Ddb.hostname=banking-db", "/account-query.jar"]
-- H2 2.2.224;
;
CREATE USER IF NOT EXISTS "ACCOUNT-QUERY-SERVICE" SALT '21f469e7ee641b1b' HASH '18dbefd38a85a488a92d7cc2e485ff9c47f29703294af67d9d907903a1551190' ADMIN;
CREATE SEQUENCE "PUBLIC"."TRANSACTION_SEQ" START WITH 1 RESTART WITH 101 INCREMENT BY 50;
CREATE MEMORY TABLE "PUBLIC"."BALANCE"(
"AMOUNT" NUMERIC(38, 2),
"BALANCE_ID" CHARACTER VARYING(255) NOT NULL
);
ALTER TABLE "PUBLIC"."BALANCE" ADD CONSTRAINT "PUBLIC"."CONSTRAINT_1" PRIMARY KEY("BALANCE_ID");
-- 4 +/- SELECT COUNT(*) FROM PUBLIC.BALANCE;
INSERT INTO "PUBLIC"."BALANCE" VALUES
(400.00, 'id1'),
(86.00, 'id2'),
(23.00, 'id3'),
(232.00, 'id4');
CREATE MEMORY TABLE "PUBLIC"."TRANSACTION"(
"AMOUNT" NUMERIC(38, 2),
"TYPE" SMALLINT,
"DATE" TIMESTAMP(6) WITH TIME ZONE,
"ID" BIGINT NOT NULL,
"PROCESS_ID" UUID,
"BALANCE_ID" CHARACTER VARYING(255)
);
ALTER TABLE "PUBLIC"."TRANSACTION" ADD CONSTRAINT "PUBLIC"."CONSTRAINT_FFF" PRIMARY KEY("ID");
-- 5 +/- SELECT COUNT(*) FROM PUBLIC.TRANSACTION;
INSERT INTO "PUBLIC"."TRANSACTION" VALUES
(433.00, 1, TIMESTAMP WITH TIME ZONE '2024-04-15 11:04:09.18155+02', 1, UUID '00000000-0000-0000-0000-000000000001', 'id1'),
(-33.00, 0, TIMESTAMP WITH TIME ZONE '2024-04-15 11:04:18.442307+02', 2, UUID '00000000-0000-0000-0000-000000000002', 'id1'),
(86.00, 2, TIMESTAMP WITH TIME ZONE '2024-04-15 11:04:32.518962+02', 3, UUID '00000000-0000-0000-0000-000000000003', 'id2'),
(23.00, 4, TIMESTAMP WITH TIME ZONE '2024-04-15 11:05:05.083367+02', 4, UUID '00000000-0000-0000-0000-000000000005', 'id3'),
(232.00, 1, TIMESTAMP WITH TIME ZONE '2024-04-15 11:05:18.375087+02', 5, UUID '00000000-0000-0000-0000-000000000006', 'id4');
ALTER TABLE "PUBLIC"."TRANSACTION" ADD CONSTRAINT "PUBLIC"."CONSTRAINT_FF" CHECK("TYPE" BETWEEN 0 AND 4) NOCHECK;
ALTER TABLE "PUBLIC"."TRANSACTION" ADD CONSTRAINT "PUBLIC"."CONSTRAINT_F" CHECK("TYPE" BETWEEN 0 AND 4) NOCHECK;
ALTER TABLE "PUBLIC"."TRANSACTION" ADD CONSTRAINT "PUBLIC"."FKICJDGHKQ3OQKDCDC6KKUJD6O3" FOREIGN KEY("BALANCE_ID") REFERENCES "PUBLIC"."BALANCE"("BALANCE_ID") NOCHECK;
......@@ -22,6 +22,7 @@
<spring.version>3.2.4</spring.version>
<org.mapstruct.version>1.5.5.Final</org.mapstruct.version>
<jdbc-postgres.version>42.7.3</jdbc-postgres.version>
</properties>
<build>
......@@ -116,10 +117,14 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- DB -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>${jdbc-postgres.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
......
......@@ -49,4 +49,10 @@ public class BalanceController implements CustomerServiceApi, SystemServiceApi {
balanceFacade.createNewBalance(id);
return new ResponseEntity<>(HttpStatus.CREATED);
}
@Override
public ResponseEntity<Void> deleteBalance(String id) {
balanceFacade.deleteBalance(id);
return new ResponseEntity<>(HttpStatus.OK);
}
}
......@@ -65,4 +65,7 @@ public class BalanceFacade {
return toReturn.stream().map(balanceMapper::mapTransactionIn).toList();
}
public void deleteBalance(String id) throws NotFoundAccountException {
balanceService.deleteBalance(id);
}
}
......@@ -95,4 +95,11 @@ public class BalanceServiceImpl implements BalanceService {
}
return result;
}
@Override
public void deleteBalance(String id) throws NotFoundAccountException {
Balance balance = findById(id);
transactionRepository.findByBalance(balance).forEach(a -> transactionRepository.delete(a));
balanceRepository.delete(balance);
}
}
......@@ -3,6 +3,7 @@ package cz.muni.pa165.banking.domain.balance.repository;
import cz.muni.pa165.banking.domain.balance.Balance;
import cz.muni.pa165.banking.domain.transaction.Transaction;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
......
......@@ -4,10 +4,14 @@ import cz.muni.pa165.banking.domain.balance.Balance;
import cz.muni.pa165.banking.domain.transaction.Transaction;
import cz.muni.pa165.banking.domain.transaction.TransactionType;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.math.BigDecimal;
import java.time.OffsetDateTime;
import java.util.Collection;
import java.util.Optional;
import java.util.UUID;
/**
......@@ -20,4 +24,7 @@ public interface TransactionRepository extends JpaRepository<Transaction, Long>
OffsetDateTime.now(), processId, balance);
this.save(tr);
}
@Query("SELECT u FROM Transaction u where u.balance = :balance")
Collection<Transaction> findByBalance(Balance balance);
}
......@@ -28,4 +28,6 @@ public interface BalanceService {
List<Transaction> getAllTransactions(OffsetDateTime from, OffsetDateTime from1, BigDecimal minAmount,
BigDecimal maxAmount, TransactionType transactionType);
void deleteBalance(String id) throws NotFoundAccountException;
}
......@@ -13,7 +13,7 @@ import java.util.UUID;
* @author Martin Mojzis
*/
@Entity
@Table(name = "transaction")
@Table(name = "bal_transaction")
public class Transaction {
@Id
......
server.port=8081
db.hostname=localhost
spring.application.name=Balance-Query
spring.jpa.open-in-view=false
spring.datasource.url=jdbc:h2:mem:account-query;MODE=PostgreSQL
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=account-query-service
spring.datasource.password=rnadompassword
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.datasource.url=jdbc:postgresql://${db.hostname}:5432/banking
spring.datasource.driverClassName=org.postgresql.Driver
spring.datasource.username=ACC_ACCOUNT
spring.datasource.password=accountAccPasswd
# showing SQL is generally good practice for running project locally to check whether there is not an issue with implementation of JPA methods.
spring.jpa.show-sql=true
spring.jackson.property-naming-strategy=SNAKE_CASE
......
......@@ -115,6 +115,18 @@ paths:
"201":
description: OK
/balance:
delete:
tags:
- SystemService
summary: deletes a balance
operationId: deleteBalance
parameters:
- { name: id, in: query, required: true, schema: { type: string }, description: "id of account" }
responses:
"200":
description: OK
/balance/add:
post:
tags:
......
......@@ -18,11 +18,11 @@ import org.springframework.test.web.servlet.MockMvc;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.time.OffsetDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.assertj.core.api.Assertions.assertThat;
......@@ -157,19 +157,20 @@ public class BalanceControllerIT {
@Test
void getAllTransactions_returnsAllTransactions() throws Exception {
// Arrange
mockMvc.perform(post("/balance/new?id=id"));
mockMvc.perform(post("/balance/add?id=id&amount=20&processId=5612b08f-27c2-42ca-9f23-0c9aff6ad877&type=WITHDRAW"));
mockMvc.perform(post("/balance/new?id=i"));
mockMvc.perform(post("/balance/add?id=i&amount=40&processId=5612b08f-27c2-42ca-9f23-0c9aff6ad874&type=WITHDRAW"));
mockMvc.perform(post("/balance/new?id=idddd"));
mockMvc.perform(post("/balance/add?id=idddd&amount=20&processId=5612b08f-27c2-42ca-9f23-0c9aff6ad847&type=WITHDRAW"));
mockMvc.perform(post("/balance/new?id=idd"));
mockMvc.perform(post("/balance/add?id=idd&amount=40&processId=5612b08f-27c2-42ca-9f23-0c9aff64d874&type=WITHDRAW"));
cz.muni.pa165.banking.account.query.dto.Transaction transaction = new Transaction();
transaction.setDate(OffsetDateTime.now());
transaction.setAmount(BigDecimal.valueOf(20));
transaction.setProcessId(UUID.fromString("5612b08f-27c2-42ca-9f23-0c9aff6ad877"));
transaction.setProcessId(UUID.fromString("5612b08f-27c2-42ca-9f23-0c9aff6ad847"));
transaction.setTransactionType(cz.muni.pa165.banking.account.query.dto.TransactionType.WITHDRAW);
cz.muni.pa165.banking.account.query.dto.Transaction transaction2 = new Transaction();
transaction2.setDate(OffsetDateTime.now());
transaction2.setAmount(BigDecimal.valueOf(40));
transaction2.setProcessId(UUID.fromString("5612b08f-27c2-42ca-9f23-0c9aff6ad874"));
transaction2.setProcessId(UUID.fromString("5612b08f-27c2-42ca-9f23-0c9aff64d874"));
transaction2.setTransactionType(cz.muni.pa165.banking.account.query.dto.TransactionType.WITHDRAW);
// Act
String id = "id";
......@@ -179,26 +180,30 @@ public class BalanceControllerIT {
.andReturn()
.getResponse()
.getContentAsString(StandardCharsets.UTF_8);
cz.muni.pa165.banking.account.query.dto.Transaction[] response = OBJECT_MAPPER.readValue(responseJson, cz.muni.pa165.banking.account.query.dto.Transaction[].class);
List<cz.muni.pa165.banking.account.query.dto.Transaction> response = Arrays.stream(OBJECT_MAPPER.readValue(responseJson, Transaction[].class)).toList();
mockMvc.perform(delete("/balance?id=idddd"));
mockMvc.perform(delete("/balance?id=idd"));
// Assert
assertThat(response[0].getAmount().byteValueExact()).isEqualTo(transaction2.getAmount().byteValueExact());
assertThat(response[0].getProcessId()).isEqualTo(transaction2.getProcessId());
assertThat(response[0].getTransactionType()).isEqualTo(transaction2.getTransactionType());
assertThat(response[1].getAmount().byteValueExact()).isEqualTo(transaction.getAmount().byteValueExact());
assertThat(response[1].getProcessId()).isEqualTo(transaction.getProcessId());
assertThat(response[1].getTransactionType()).isEqualTo(transaction.getTransactionType());
assertThat(response.stream().filter(a -> a.getProcessId().equals(transaction2.getProcessId())).findFirst().get()
.getAmount().byteValueExact()).isEqualTo(transaction2.getAmount().byteValueExact());
assertThat(response.stream().filter(a -> a.getProcessId().equals(transaction2.getProcessId())).findFirst().get()
.getTransactionType()).isEqualTo(transaction2.getTransactionType());
assertThat(response.stream().filter(a -> a.getProcessId().equals(transaction.getProcessId())).findFirst().get()
.getAmount().byteValueExact()).isEqualTo(transaction.getAmount().byteValueExact());
assertThat(response.stream().filter(a -> a.getProcessId().equals(transaction.getProcessId())).findFirst().get()
.getTransactionType()).isEqualTo(transaction.getTransactionType());
}
@Test
void getReport_personExists_returnsReport() throws Exception {
// Arrange
mockMvc.perform(post("/balance/new?id=iddd"));
mockMvc.perform(post("/balance/add?id=iddd&amount=20&processId=5612b08f-27c2-42ca-9f23-0c9aff6ad877&type=WITHDRAW"));
mockMvc.perform(post("/balance/add?id=iddd&amount=20&processId=5612b08f-27c2-42ca-9f26-0c9aff6ad877&type=WITHDRAW"));
cz.muni.pa165.banking.account.query.dto.Transaction transaction = new Transaction();
transaction.setDate(OffsetDateTime.now());
transaction.setAmount(BigDecimal.valueOf(20));
transaction.setProcessId(UUID.fromString("5612b08f-27c2-42ca-9f23-0c9aff6ad877"));
transaction.setProcessId(UUID.fromString("5612b08f-27c2-42ca-9f26-0c9aff6ad877"));
transaction.setTransactionType(cz.muni.pa165.banking.account.query.dto.TransactionType.WITHDRAW);
// Act
String id = "id";
......@@ -209,6 +214,7 @@ public class BalanceControllerIT {
.getResponse()
.getContentAsString(StandardCharsets.UTF_8);
cz.muni.pa165.banking.account.query.dto.TransactionsReport response = OBJECT_MAPPER.readValue(responseJson, cz.muni.pa165.banking.account.query.dto.TransactionsReport.class);
mockMvc.perform(delete("/balance?id=iddd"));
// Assert
assertThat(response.getWithdrawalAmount().getAmountIn().byteValueExact()).isEqualTo(BigDecimal.valueOf(20).byteValueExact());
......
package cz.muni.pa165.banking.application.repository;
import cz.muni.pa165.banking.domain.balance.Balance;
import cz.muni.pa165.banking.domain.balance.repository.BalancesRepository;
import jakarta.transaction.Transactional;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.math.BigDecimal;
import java.util.List;
import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
@ExtendWith(SpringExtension.class)
@Transactional
@DataJpaTest
class BalancesRepositoryTest {
@Autowired
BalancesRepository balancesRepository;
@BeforeEach
public void init(){
balancesRepository.addBalance("id1");
balancesRepository.addBalance("id2");
}
@Test
void findById_accountNotExists_returnsEmpty()
{
//Act
Optional<Balance> result = balancesRepository.findById("id3");
//Assert
assertThat(result).isEqualTo(Optional.empty());
}
@Test
void findById_accountExists_returnsBalance()
{
//Act
Optional<Balance> result = balancesRepository.findById("id2");
//Assert
assertThat(result).isNotNull();
assertThat(result.get().getAmount()).isEqualTo(BigDecimal.ZERO);
assertThat(result.get().getAccountId()).isEqualTo("id2");
}
@Test
void getAllIds_returnsAllIds(){
//Act
List<String> ids = balancesRepository.getAllIds();
//Assert
assertThat(ids).isNotNull();
assertThat(ids.size()).isEqualTo(2);
assertThat(ids.contains("id1")).isEqualTo(true);
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment