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