44import lombok .RequiredArgsConstructor ;
55import lombok .extern .slf4j .Slf4j ;
66import lombok .val ;
7+ import org .cardanofoundation .lob .app .accounting_reporting_core .domain .core .TransactionProblem ;
78import org .cardanofoundation .lob .app .accounting_reporting_core .domain .core .TransactionType ;
89import org .cardanofoundation .lob .app .accounting_reporting_core .domain .core .ValidationStatus ;
910import org .cardanofoundation .lob .app .accounting_reporting_core .domain .entity .Rejection ;
1011import org .cardanofoundation .lob .app .accounting_reporting_core .domain .entity .TransactionEntity ;
12+ import org .cardanofoundation .lob .app .accounting_reporting_core .resource .requests .TransactionId ;
13+ import org .cardanofoundation .lob .app .accounting_reporting_core .resource .requests .TransactionsRequest ;
1114import org .cardanofoundation .lob .app .accounting_reporting_core .service .internal .LedgerService ;
15+ import org .springframework .dao .DataAccessException ;
1216import org .springframework .stereotype .Service ;
1317import org .springframework .transaction .annotation .Transactional ;
1418import org .zalando .problem .Problem ;
1519
20+ import java .util .ArrayList ;
1621import java .util .List ;
1722import java .util .Optional ;
1823import java .util .Set ;
1924import java .util .stream .Collectors ;
2025
21- import static org .cardanofoundation .lob .app .accounting_reporting_core .domain .core .ValidationStatus .FAILED ;
26+ import static org .cardanofoundation .lob .app .accounting_reporting_core .domain .core .TransactionStatus .FAIL ;
27+ import static org .springframework .transaction .annotation .Propagation .REQUIRES_NEW ;
2228
2329@ Service
2430@ Slf4j
@@ -30,119 +36,220 @@ public class TransactionRepositoryGateway {
3036 private final TransactionRepository transactionRepository ;
3137 private final LedgerService ledgerService ;
3238
33- @ Transactional
34- public Either <Problem , Boolean > approveTransaction (String transactionId ) {
39+ @ Transactional (propagation = REQUIRES_NEW )
40+ // TODO optimise performance because we have to load transaction from db each time and we don't save it in bulk
41+ private Either <TransactionProblem , TransactionEntity > approveTransaction (String transactionId ) {
3542 log .info ("Approving transaction: {}" , transactionId );
3643
3744 val txM = transactionRepository .findById (transactionId );
3845
3946 if (txM .isEmpty ()) {
40- return Either . left ( Problem .builder ()
47+ val problem = Problem .builder ()
4148 .withTitle ("TX_NOT_FOUND" )
4249 .withDetail (STR ."Transaction with id \{transactionId } not found" )
4350 .with ("transactionId" , transactionId )
44- .build ()
45- );
51+ .build ();
52+
53+ return Either .left (new TransactionProblem (transactionId , problem ));
4654 }
4755
4856 val tx = txM .orElseThrow ();
4957
50- if (tx .getAutomatedValidationStatus () == FAILED ) {
51- return Either . left ( Problem .builder ()
58+ if (tx .getStatus () == FAIL ) {
59+ val problem = Problem .builder ()
5260 .withTitle ("CANNOT_APPROVE_FAILED_TX" )
5361 .withDetail (STR ."Cannot approve a failed transaction, transactionId: \{transactionId }" )
5462 .with ("transactionId" , transactionId )
55- .build ()
56- );
63+ .build ();
64+
65+ return Either .left (new TransactionProblem (transactionId , problem ));
5766 }
5867
5968 tx .setTransactionApproved (true );
6069
6170 val savedTx = transactionRepository .save (tx );
62- val organisationId = savedTx .getOrganisation ().getId ();
6371
64- if (savedTx .getTransactionApproved ()) {
65- ledgerService .checkIfThereAreTransactionsToDispatch (organisationId , Set .of (savedTx ));
72+ return Either .right (savedTx );
73+ }
74+
75+ @ Transactional (propagation = REQUIRES_NEW )
76+ // TODO optimise performance because we have to load transaction from db each time and we don't save it in bulk
77+ private Either <TransactionProblem , TransactionEntity > approveTransactionsDispatch (String transactionId ) {
78+ log .info ("Approving transaction to dispatch: {}" , transactionId );
79+
80+ val txM = transactionRepository .findById (transactionId );
81+
82+ if (txM .isEmpty ()) {
83+ val problem = Problem .builder ()
84+ .withTitle ("TX_NOT_FOUND" )
85+ .withDetail (STR ."Transaction with id \{transactionId } not found" )
86+ .with ("transactionId" , transactionId )
87+ .build ();
6688
67- return Either .right ( savedTx . getTransactionApproved ( ));
89+ return Either .left ( new TransactionProblem ( transactionId , problem ));
6890 }
6991
70- return Either .right (false );
71- }
92+ val tx = txM .orElseThrow ();
7293
73- @ Transactional
74- public Set <String > approveTransactions (String organisationId , Set <String > transactionIds ) {
75- log .info ("Approving transactions: {}" , transactionIds );
94+ if (tx .getStatus () == FAIL ) {
95+ val problem = Problem .builder ()
96+ .withTitle ("CANNOT_APPROVE_FAILED_TX" )
97+ .withDetail (STR ."Cannot approve a failed transaction, transactionId: \{transactionId }" )
98+ .with ("transactionId" , transactionId )
99+ .build ();
76100
77- val transactions = transactionRepository .findAllById (transactionIds )
78- .stream ()
79- .filter (tx -> tx .getAutomatedValidationStatus () != FAILED )
80- .peek (tx -> tx .setTransactionApproved (true ))
81- .collect (Collectors .toSet ());
101+ return Either .left (new TransactionProblem (transactionId , problem ));
102+ }
82103
83- val savedTxs = transactionRepository .saveAll (transactions );
104+ if (!tx .getTransactionApproved ()) {
105+ val problem = Problem .builder ()
106+ .withTitle ("TX_NOT_APPROVED" )
107+ .withDetail (STR ."Cannot approve a transaction that has not been approved before, transactionId: \{transactionId }" )
108+ .with ("transactionId" , transactionId )
109+ .build ();
110+
111+ return Either .left (new TransactionProblem (transactionId , problem ));
112+ }
113+
114+ tx .setLedgerDispatchApproved (true );
84115
85- ledgerService . checkIfThereAreTransactionsToDispatch ( organisationId , Set . copyOf ( savedTxs ) );
116+ val savedTx = transactionRepository . save ( tx );
86117
87- return savedTxs . stream (). map ( TransactionEntity :: getId ). collect ( Collectors . toSet () );
118+ return Either . right ( savedTx );
88119 }
89120
90- @ Transactional
91- public Set <String > approveTransactionsDispatch (String organisationId , Set <String > transactionIds ) {
92- log .info ("Approving transactions dispatch: {}" , transactionIds );
121+ public List <Either <TransactionProblem , TransactionEntity >> approveTransactions (TransactionsRequest transactionsRequest ) {
122+ val organisationId = transactionsRequest .getOrganisationId ();
93123
94- val transactions = transactionRepository . findAllById ( transactionIds )
124+ val transactionIds = transactionsRequest . getTransactionIds ( )
95125 .stream ()
96- .filter (tx -> tx .getAutomatedValidationStatus () != FAILED )
97- .peek (tx -> tx .setLedgerDispatchApproved (true ))
126+ .map (TransactionId ::getId )
98127 .collect (Collectors .toSet ());
99128
100- val savedTxs = transactionRepository .saveAll (transactions );
129+ val transactionsApprovalResponseListE = new ArrayList <Either <TransactionProblem , TransactionEntity >>();
130+ for (val transactionId : transactionIds ) {
131+ try {
132+ val transactionEntities = approveTransaction (transactionId );
101133
102- ledgerService .checkIfThereAreTransactionsToDispatch (organisationId , Set .copyOf (savedTxs ));
134+ transactionsApprovalResponseListE .add (transactionEntities );
135+ } catch (DataAccessException dae ) {
136+ log .error ("Error approving transaction: {}" , transactionId , dae );
103137
104- return savedTxs .stream ().map (TransactionEntity ::getId ).collect (Collectors .toSet ());
105- }
138+ val problem = Problem .builder ()
139+ .withTitle ("DB_ERROR" )
140+ .withDetail (STR ."DB error approving transaction: \{transactionId }" )
141+ .with ("transactionId" , transactionId )
142+ .with ("error" , dae .getMessage ())
143+ .build ();
106144
107- @ Transactional
108- public Either < Problem , Boolean > approveTransactionDispatch ( String transactionId ) {
109- log . info ( "Approving transaction dispatch: {}" , transactionId );
145+ transactionsApprovalResponseListE . add ( Either . left ( new TransactionProblem ( transactionId , problem )));
146+ }
147+ }
110148
111- val txM = transactionRepository .findById (transactionId );
149+ val transactionSuccesses = transactionsApprovalResponseListE .stream ()
150+ .filter (Either ::isRight )
151+ .map (Either ::get )
152+ .collect (Collectors .toSet ());
112153
113- if (txM .isEmpty ()) {
114- return Either .left (Problem .builder ()
115- .withTitle ("TX_NOT_FOUND" )
116- .withDetail (STR ."Transaction with id \{transactionId } not found" )
117- .with ("transactionId" , transactionId )
118- .build ()
119- );
120- }
154+ ledgerService .checkIfThereAreTransactionsToDispatch (organisationId , transactionSuccesses );
121155
122- val tx = txM .orElseThrow ();
156+ return transactionsApprovalResponseListE ;
157+ }
123158
124- if (tx .getAutomatedValidationStatus () == FAILED ) {
125- return Either .left (Problem .builder ()
126- .withTitle ("CANNOT_APPROVE_FAILED_TX" )
127- .withDetail (STR ."Cannot approve dispatch for a failed transaction, transactionId: \{transactionId }" )
128- .with ("transactionId" , transactionId )
129- .build ()
130- );
131- }
159+ public List <Either <TransactionProblem , TransactionEntity >> approveTransactionsDispatch (TransactionsRequest transactionsRequest ) {
160+ val organisationId = transactionsRequest .getOrganisationId ();
132161
133- tx .setLedgerDispatchApproved (true );
162+ val transactionIds = transactionsRequest .getTransactionIds ()
163+ .stream ()
164+ .map (TransactionId ::getId )
165+ .collect (Collectors .toSet ());
134166
135- val savedTx = transactionRepository .save (tx );
167+ val transactionsApprovalResponseListE = new ArrayList <Either <TransactionProblem , TransactionEntity >>();
168+ for (val transactionId : transactionIds ) {
169+ try {
170+ val transactionEntities = approveTransactionsDispatch (transactionId );
136171
137- if (savedTx .getLedgerDispatchApproved ()) {
138- ledgerService .checkIfThereAreTransactionsToDispatch (savedTx .getOrganisation ().getId (), Set .of (savedTx ));
172+ transactionsApprovalResponseListE .add (transactionEntities );
173+ } catch (DataAccessException dae ) {
174+ log .error ("Error approving transaction publish: {}" , transactionId , dae );
139175
140- return Either .right (savedTx .getLedgerDispatchApproved ());
176+ val problem = Problem .builder ()
177+ .withTitle ("DB_ERROR" )
178+ .withDetail (STR ."DB error approving transaction publish:\{transactionId }" )
179+ .with ("transactionId" , transactionId )
180+ .with ("error" , dae .getMessage ())
181+ .build ();
182+
183+ transactionsApprovalResponseListE .add (Either .left (new TransactionProblem (transactionId , problem )));
184+ }
141185 }
142186
143- return Either .right (false );
187+ val transactionSuccesses = transactionsApprovalResponseListE .stream ()
188+ .filter (Either ::isRight )
189+ .map (Either ::get )
190+ .collect (Collectors .toSet ());
191+
192+ ledgerService .checkIfThereAreTransactionsToDispatch (organisationId , transactionSuccesses );
193+
194+ return transactionsApprovalResponseListE ;
144195 }
145196
197+ // @Transactional
198+ // public Set<String> approveTransactionsDispatch(String organisationId, Set<String> transactionIds) {
199+ // log.info("Approving transactions dispatch: {}", transactionIds);
200+ //
201+ // val transactions = transactionRepository.findAllById(transactionIds)
202+ // .stream()
203+ // .filter(tx -> tx.getAutomatedValidationStatus() != FAILED)
204+ // .peek(tx -> tx.setLedgerDispatchApproved(true))
205+ // .collect(Collectors.toSet());
206+ //
207+ // val savedTxs = transactionRepository.saveAll(transactions);
208+ //
209+ // ledgerService.checkIfThereAreTransactionsToDispatch(organisationId, Set.copyOf(savedTxs));
210+ //
211+ // return savedTxs.stream().map(TransactionEntity::getId).collect(Collectors.toSet());
212+ // }
213+
214+ // @Transactional
215+ // public Either<Problem, Boolean> approveTransactionDispatch(String transactionId) {
216+ // log.info("Approving transaction dispatch: {}", transactionId);
217+ //
218+ // val txM = transactionRepository.findById(transactionId);
219+ //
220+ // if (txM.isEmpty()) {
221+ // return Either.left(Problem.builder()
222+ // .withTitle("TX_NOT_FOUND")
223+ // .withDetail(STR."Transaction with id \{transactionId} not found")
224+ // .with("transactionId", transactionId)
225+ // .build()
226+ // );
227+ // }
228+ //
229+ // val tx = txM.orElseThrow();
230+ //
231+ // if (tx.getAutomatedValidationStatus() == FAILED) {
232+ // return Either.left(Problem.builder()
233+ // .withTitle("CANNOT_APPROVE_FAILED_TX")
234+ // .withDetail(STR."Cannot approve dispatch for a failed transaction, transactionId: \{transactionId}")
235+ // .with("transactionId", transactionId)
236+ // .build()
237+ // );
238+ // }
239+ //
240+ // tx.setLedgerDispatchApproved(true);
241+ //
242+ // val savedTx = transactionRepository.save(tx);
243+ //
244+ // if (savedTx.getLedgerDispatchApproved()) {
245+ // ledgerService.checkIfThereAreTransactionsToDispatch(savedTx.getOrganisation().getId(), Set.of(savedTx));
246+ //
247+ // return Either.right(savedTx.getLedgerDispatchApproved());
248+ // }
249+ //
250+ // return Either.right(false);
251+ // }
252+
146253 public Either <Problem , Boolean > changeTransactionComment (String txId , String userComment ) {
147254 val txM = transactionRepository .findById (txId );
148255
@@ -205,16 +312,15 @@ public Optional<TransactionEntity> findById(String transactionId) {
205312 }
206313
207314 public List <TransactionEntity > findByAllId (Set <String > transactionIds ) {
208-
209315 return transactionRepository .findAllById (transactionIds );
210316 }
211317
212- private static Set <String > transactionIds (Set <TransactionEntity > transactions ) {
213- return transactions
214- .stream ()
215- .map (TransactionEntity ::getId )
216- .collect (Collectors .toSet ());
217- }
318+ // private static Set<String> transactionIds(Set<TransactionEntity> transactions) {
319+ // return transactions
320+ // .stream()
321+ // .map(TransactionEntity::getId)
322+ // .collect(Collectors.toSet());
323+ // }
218324
219325 public List <TransactionEntity > findAllByStatus (String organisationId ,
220326 List <ValidationStatus > validationStatuses ,
@@ -225,4 +331,5 @@ public List<TransactionEntity> findAllByStatus(String organisationId,
225331 public List <TransactionEntity > listAll () {
226332 return transactionRepository .findAll ();
227333 }
334+
228335}
0 commit comments