diff --git a/descriptors/ModuleDescriptor-template.json b/descriptors/ModuleDescriptor-template.json index bd147774..5c7f25a8 100644 --- a/descriptors/ModuleDescriptor-template.json +++ b/descriptors/ModuleDescriptor-template.json @@ -23,13 +23,13 @@ "finance-storage.budgets.collection.get", "finance-storage.group-fund-fiscal-years.collection.get", "finance-storage.group-fund-fiscal-years.item.put", - "finance-storage.transactions.item.post", "finance-storage.fiscal-years.item.get", "finance-storage.fiscal-years.collection.get", "finance-storage.budget-expense-classes.collection.get", "finance-storage.budget-expense-classes.item.post", "finance-storage.funds.item.get", "finance-storage.ledgers.item.get", + "finance-storage.transactions.batch", "configuration.entries.collection.get" ] }, @@ -599,43 +599,15 @@ }, { "id": "finance.transactions", - "version": "5.1", + "version": "6.0", "handlers": [ { "methods": ["POST"], "pathPattern": "/finance/allocations", "permissionsRequired": ["finance.allocations.item.post"], "modulePermissions": [ - "finance-storage.transactions.item.post", - "finance-storage.funds.item.get" - ] - }, - { - "methods": ["POST"], - "pathPattern": "/finance/encumbrances", - "permissionsRequired": ["finance.encumbrances.item.post"], - "modulePermissions": [ - "finance-storage.transactions.item.post" - ] - }, - { - "methods": ["PUT"], - "pathPattern": "/finance/encumbrances/{id}", - "permissionsRequired": ["finance.encumbrances.item.put"], - "modulePermissions": [ - "finance-storage.transactions.item.put" - ] - }, - { - "methods": ["DELETE"], - "pathPattern": "/finance/encumbrances/{id}", - "permissionsRequired": ["finance.encumbrances.item.delete"], - "modulePermissions": [ - "finance-storage.transactions.item.get", - "finance-storage.transactions.item.put", - "finance-storage.transactions.item.delete", - "finance-storage.transactions.collection.get", - "finance-storage.order-transaction-summaries.item.put" + "finance-storage.funds.item.get", + "finance-storage.transactions.batch" ] }, { @@ -643,58 +615,8 @@ "pathPattern": "/finance/transfers", "permissionsRequired": ["finance.transfers.item.post"], "modulePermissions": [ - "finance-storage.transactions.item.post", - "finance-storage.funds.item.get" - ] - }, - { - "methods": ["POST"], - "pathPattern": "/finance/payments", - "permissionsRequired": ["finance.payments.item.post"], - "modulePermissions": [ - "finance-storage.transactions.item.post" - ] - }, - { - "methods": ["PUT"], - "pathPattern": "/finance/payments/{id}", - "permissionsRequired": ["finance.payments.item.put"], - "modulePermissions": [ - "finance-storage.transactions.item.put", - "finance-storage.transactions.item.get" - ] - }, - { - "methods": ["POST"], - "pathPattern": "/finance/pending-payments", - "permissionsRequired": ["finance.pending-payments.item.post"], - "modulePermissions": [ - "finance-storage.transactions.item.post" - ] - }, - { - "methods": ["PUT"], - "pathPattern": "/finance/pending-payments/{id}", - "permissionsRequired": ["finance.pending-payments.item.put"], - "modulePermissions": [ - "finance-storage.transactions.item.put" - ] - }, - { - "methods": ["POST"], - "pathPattern": "/finance/credits", - "permissionsRequired": ["finance.credits.item.post"], - "modulePermissions": [ - "finance-storage.transactions.item.post" - ] - }, - { - "methods": ["PUT"], - "pathPattern": "/finance/credits/{id}", - "permissionsRequired": ["finance.credits.item.put"], - "modulePermissions": [ - "finance-storage.transactions.item.put", - "finance-storage.transactions.item.get" + "finance-storage.funds.item.get", + "finance-storage.transactions.batch" ] }, { @@ -742,28 +664,6 @@ } ] }, - { - "id": "finance.order-transaction-summaries", - "version": "1.2", - "handlers": [ - { - "methods": ["POST"], - "pathPattern": "/finance/order-transaction-summaries", - "permissionsRequired": ["finance.order-transaction-summaries.item.post"], - "modulePermissions": [ - "finance-storage.order-transaction-summaries.item.post" - ] - }, - { - "methods": ["PUT"], - "pathPattern": "/finance/order-transaction-summaries/{id}", - "permissionsRequired": ["finance.order-transaction-summaries.item.put"], - "modulePermissions": [ - "finance-storage.order-transaction-summaries.item.put" - ] - } - ] - }, { "id": "finance.group-fiscal-year-summaries", "version": "1.3", @@ -780,28 +680,6 @@ } ] }, - { - "id": "finance.invoice-transaction-summaries", - "version": "2.1", - "handlers": [ - { - "methods": ["POST"], - "pathPattern": "/finance/invoice-transaction-summaries", - "permissionsRequired": ["finance.invoice-transaction-summaries.item.post"], - "modulePermissions": [ - "finance-storage.invoice-transaction-summaries.item.post" - ] - }, - { - "methods": ["PUT"], - "pathPattern": "/finance/invoice-transaction-summaries/{id}", - "permissionsRequired": ["finance.invoice-transaction-summaries.item.put"], - "modulePermissions": [ - "finance-storage.invoice-transaction-summaries.item.put" - ] - } - ] - }, { "id": "finance.exchange-rate", "version": "1.0", @@ -912,20 +790,12 @@ }, { "id": "finance-storage.transactions", - "version":"4.0" + "version":"4.1" }, { "id": "configuration", "version":"2.0" }, - { - "id": "finance-storage.order-transaction-summaries", - "version":"1.1" - }, - { - "id": "finance-storage.invoice-transaction-summaries", - "version":"2.1" - }, { "id": "finance-storage.ledger-rollovers", "version":"2.0" @@ -1328,56 +1198,11 @@ "displayName" : "Allocations - create a new transaction of type allocation", "description" : "Create a new allocation" }, - { - "permissionName" : "finance.encumbrances.item.post", - "displayName" : "Encumbrances - create a new transaction of type encumbrance", - "description" : "Create a new encumbrance" - }, - { - "permissionName" : "finance.encumbrances.item.put", - "displayName" : "Encumbrances - update transaction of type encumbrance", - "description" : "Update an encumbrance" - }, - { - "permissionName" : "finance.encumbrances.item.delete", - "displayName" : "Encumbrances - delete transaction of type encumbrance", - "description" : "Delete an encumbrance" - }, { "permissionName" : "finance.transfers.item.post", "displayName" : "Transfers - create a new transaction of type transfer", "description" : "Create a new transfer" }, - { - "permissionName" : "finance.payments.item.post", - "displayName" : "Payments - create a new transaction of type payment", - "description" : "Create a new payment" - }, - { - "permissionName" : "finance.payments.item.put", - "displayName" : "Payments - update a transaction of type payment", - "description" : "Update a payment" - }, - { - "permissionName" : "finance.pending-payments.item.post", - "displayName" : "Pending payments - create a new transaction of type pending payment", - "description" : "Create a new pending payment" - }, - { - "permissionName" : "finance.pending-payments.item.put", - "displayName" : "Pending payments - update a transaction of type pending payment", - "description" : "Update a pending payment" - }, - { - "permissionName" : "finance.credits.item.post", - "displayName" : "Credits - create a new transaction of type credit", - "description" : "Create a new credit" - }, - { - "permissionName" : "finance.credits.item.put", - "displayName" : "Credits - update a transaction of type credit", - "description" : "Update a credit" - }, { "permissionName": "finance.transactions.collection.get", "displayName": "Finances - Get finance transaction collection", @@ -1399,16 +1224,7 @@ "description" : "All permissions for the transaction APIs", "subPermissions" : [ "finance.allocations.item.post", - "finance.encumbrances.item.post", - "finance.encumbrances.item.put", - "finance.encumbrances.item.delete", "finance.transfers.item.post", - "finance.payments.item.post", - "finance.payments.item.put", - "finance.pending-payments.item.post", - "finance.pending-payments.item.put", - "finance.credits.item.post", - "finance.credits.item.put", "finance.transactions.collection.get", "finance.transactions.item.get", "finance.release-encumbrance.item.post", @@ -1431,31 +1247,6 @@ "displayName": "Finances - get group fiscal year summaries", "description": "Get group fiscal year summaries collection" }, - { - "permissionName" : "finance.order-transaction-summaries.item.post", - "displayName" : "Finances - Post Order transaction Summaries", - "description" : "Post Order Transaction Summary" - }, - { - "permissionName" : "finance.order-transaction-summaries.item.put", - "displayName" : "Finances - Put Order transaction Summaries", - "description" : "Put Order Transaction Summary" - }, - { - "permissionName" : "finance.order-transaction-summaries.item.get", - "displayName" : "Finances - Get Order transaction Summaries", - "description" : "Get Order Transaction Summary" - }, - { - "permissionName" : "finance.invoice-transaction-summaries.item.post", - "displayName" : "Finances - Post Invoice transaction Summaries", - "description" : "Post Invoice Transaction Summary" - }, - { - "permissionName" : "finance.invoice-transaction-summaries.item.put", - "displayName" : "Finances - Put Invoice transaction Summaries", - "description" : "Put Invoice Transaction Summary" - }, { "permissionName" : "finance.exchange-rate.item.get", "displayName" : "Finances - Exchange Rate", @@ -1486,10 +1277,6 @@ "finance.transactions.all", "finance.fund-codes-expense-classes.collection.get", "finance.group-fiscal-year-summaries.collection.get", - "finance.order-transaction-summaries.item.post", - "finance.order-transaction-summaries.item.put", - "finance.invoice-transaction-summaries.item.post", - "finance.invoice-transaction-summaries.item.put", "finance.exchange-rate.item.get", "finance.calculate-exchange.item.get", "finance.expense-classes.all", diff --git a/ramls/release-encumbrance.raml b/ramls/release-encumbrance.raml index 8d73b01c..a513817d 100644 --- a/ramls/release-encumbrance.raml +++ b/ramls/release-encumbrance.raml @@ -9,7 +9,7 @@ documentation: - title: Release encumbrance API content: | This documents the API calls that release any remaining money encumbered back to the budget's available pool. - It should only be used by the UI, and only to release a single encumbrance - batch-all-or-nothing should be used otherwise. + It should only be used by the UI, and only to release a single encumbrance - batch-all-or-nothing should be used otherwise. types: errors: !include raml-util/schemas/errors.schema @@ -28,10 +28,10 @@ traits: displayName: Finance release encumbrance description: | Finance release encumbrance APIs. - It should only be used by the UI, and only to release a single encumbrance - batch-all-or-nothing should be used otherwise. + It should only be used by the UI, and only to release a single encumbrance - batch-all-or-nothing should be used otherwise. post: is: [validate] - description: Release encumbrance (use only in UI for a single encumbrance - use batch-all-or-nothing otherwise) + description: Release encumbrance (use only in UI for a single encumbrance - use batch-all-or-nothing otherwise) responses: 204: description: "Encumbrance successfully released" diff --git a/ramls/transaction-summary.raml b/ramls/transaction-summary.raml deleted file mode 100644 index a41625be..00000000 --- a/ramls/transaction-summary.raml +++ /dev/null @@ -1,71 +0,0 @@ -#%RAML 1.0 - -title: Finance Transaction Summaries -version: v1.1 -protocols: [ HTTP, HTTPS ] -baseUri: https://github.com/folio-org/mod-finance - -documentation: - - title: Transaction Summaries API - content: This documents the API calls that can be made to create Transaction summaries for Orders and Invoices - -types: - order-transaction-summary: !include acq-models/mod-finance/schemas/order_transaction_summary.json - invoice-transaction-summary: !include acq-models/mod-finance/schemas/invoice_transaction_summary.json - errors: !include raml-util/schemas/errors.schema - - -traits: - validate: !include raml-util/traits/validation.raml - -resourceTypes: - post-with-201: !include rtypes/post-json-201.raml - put-json: !include rtypes/post-put-json.raml - -/finance/order-transaction-summaries: - displayName: Create a transaction allocation - description: Create a new order transaction summary - type: - post-with-201: - requestSchema: order-transaction-summary - responseSchema: order-transaction-summary - requestExample: !include acq-models/mod-finance/examples/order_transaction_summary.sample - responseExample: !include acq-models/mod-finance/examples/order_transaction_summary.sample - is: [validate] - post: - description: Create a new order transaction summary, for an order with number of transactions(encumbrances) - - /{id}: - displayName: Create a transaction summary - description: Create a new order transaction summary - type: - put-json: - schemaItem: order-transaction-summary - exampleItem: !include acq-models/mod-finance/examples/order_transaction_summary.sample - is: [validate] - put: - description: Updated order transaction summary, for an order with number of transactions(encumbrances) - - -/finance/invoice-transaction-summaries: - displayName: Create a transaction allocation - description: Create a new invoice transaction summary - type: - post-with-201: - requestSchema: invoice-transaction-summary - responseSchema: invoice-transaction-summary - requestExample: !include acq-models/mod-finance/examples/invoice_transaction_summary.sample - responseExample: !include acq-models/mod-finance/examples/invoice_transaction_summary.sample - is: [validate] - post: - description: Create a new invoice transaction summary, for an order with number of transactions(encumbrances) and number of payment credits - /{id}: - displayName: Update a transaction summary - description: Update a new invoice transaction summary - type: - put-json: - schemaItem: invoice-transaction-summary - exampleItem: !include acq-models/mod-finance/examples/invoice_transaction_summary.sample - is: [validate] - put: - description: Updated invoice transaction summary, for an invoice with number of pending payments and number of payment/credits diff --git a/ramls/transaction.raml b/ramls/transaction.raml index d1c53253..f2ae624f 100644 --- a/ramls/transaction.raml +++ b/ramls/transaction.raml @@ -1,7 +1,7 @@ #%RAML 1.0 title: "mod-finance" baseUri: https://github.com/folio-org/mod-finance -version: v1.1 +version: v6.0 documentation: - title: mod-finance (Transactions) @@ -23,14 +23,13 @@ traits: resourceTypes: post-with-201: !include rtypes/post-json-201.raml - put-json: !include rtypes/post-put-json.raml get-only: !include raml-util/rtypes/get-only-with-json-response.raml collection-item-get: !include raml-util/rtypes/item-collection-get-with-json-response.raml /finance: /allocations: displayName: Create a transaction allocation - description: Create an allocation; DEPRECATED - use batch-all-or-nothing instead + description: Create an allocation; DEPRECATED - use batch-all-or-nothing instead type: post-with-201: requestSchema: transaction @@ -39,11 +38,11 @@ resourceTypes: responseExample: !include acq-models/mod-finance/examples/transaction_allocation.sample is: [validate] post: - description: Create an allocation by transaction; DEPRECATED - use batch-all-or-nothing instead + description: Create an allocation by transaction; DEPRECATED - use batch-all-or-nothing instead /transfers: displayName: Create a transaction transfer - description: Create a transfer; DEPRECATED - use batch-all-or-nothing instead + description: Create a transfer; DEPRECATED - use batch-all-or-nothing instead type: post-with-201: requestSchema: transaction @@ -52,101 +51,7 @@ resourceTypes: responseExample: !include acq-models/mod-finance/examples/transaction_transfer.sample is: [validate] post: - description: Create a transfer by transaction; DEPRECATED - use batch-all-or-nothing instead - - /encumbrances: - displayName: Create a transaction encumbrance - description: Create a encumbrance; DEPRECATED - use batch-all-or-nothing instead - type: - post-with-201: - requestSchema: transaction - responseSchema: transaction - requestExample: !include acq-models/mod-finance/examples/transaction_encumbrance.sample - responseExample: !include acq-models/mod-finance/examples/transaction_encumbrance.sample - is: [validate] - post: - description: Create an encumbrance by transaction - /{id}: - displayName: Transaction instance - put: - description: Update a Transaction instance; DEPRECATED - use batch-all-or-nothing instead - body: - application/json: - type: transaction - delete: - is: [validate] - description: Delete an encumbrance with given transactionId; DEPRECATED - use batch-all-or-nothing instead - - /payments: - displayName: Create a transaction payment - description: Create a payment; DEPRECATED - use batch-all-or-nothing instead - type: - post-with-201: - requestSchema: transaction - responseSchema: transaction - requestExample: !include acq-models/mod-finance/examples/transaction_payment.sample - responseExample: !include acq-models/mod-finance/examples/transaction_payment.sample - is: [validate] - post: - description: Create a payment by transaction; DEPRECATED - use batch-all-or-nothing instead - /{id}: - displayName: Transaction payment - type: - put-json: - schemaItem: transaction - exampleItem: !include acq-models/mod-finance/examples/transaction_payment.sample - is: [validate] - put: - description: | - Update a payment transaction (only allowed to set invoiceCancelled to true); - DEPRECATED - use batch-all-or-nothing instead - - /pending-payments: - displayName: Create a transaction pending payment - description: Create a pending payment; DEPRECATED - use batch-all-or-nothing instead - type: - post-with-201: - requestSchema: transaction - responseSchema: transaction - requestExample: !include acq-models/mod-finance/examples/transaction_pending_payment.sample - responseExample: !include acq-models/mod-finance/examples/transaction_pending_payment.sample - is: [validate] - post: - description: Create a pending payment by transaction; DEPRECATED - use batch-all-or-nothing instead - - /{id}: - displayName: Transaction pending payment - type: - put-json: - schemaItem: transaction - exampleItem: !include acq-models/mod-finance/examples/transaction_pending_payment.sample - is: [validate] - put: - description: Update a pending payment by transaction; DEPRECATED - use batch-all-or-nothing instead - - /credits: - displayName: Create a transaction credit - description: Create a credit; DEPRECATED - use batch-all-or-nothing instead - type: - post-with-201: - requestSchema: transaction - responseSchema: transaction - requestExample: !include acq-models/mod-finance/examples/transaction_credit.sample - responseExample: !include acq-models/mod-finance/examples/transaction_credit.sample - is: [validate] - post: - description: Create a credit by transaction; DEPRECATED - use batch-all-or-nothing instead - /{id}: - displayName: Transaction credit - type: - put-json: - schemaItem: transaction - exampleItem: !include acq-models/mod-finance/examples/transaction_credit.sample - is: [validate] - put: - description: | - Update a credit transaction (only allowed to set invoiceCancelled to true); - DEPRECATED - use batch-all-or-nothing instead + description: Create a transfer by transaction; DEPRECATED - use batch-all-or-nothing instead /transactions: displayName: Transactions diff --git a/ramls/unrelease-encumbrance.raml b/ramls/unrelease-encumbrance.raml index 28de3cf7..d7f130c1 100644 --- a/ramls/unrelease-encumbrance.raml +++ b/ramls/unrelease-encumbrance.raml @@ -9,7 +9,7 @@ documentation: - title: Unrelease encumbrance API content: | This documents the API calls that unrelease any remaining money encumbered back to the budget's available pool. - It should only be used by the UI, and only to unrelease a single encumbrance - batch-all-or-nothing should be used otherwise + It should only be used by the UI, and only to unrelease a single encumbrance - batch-all-or-nothing should be used otherwise types: errors: !include raml-util/schemas/errors.schema @@ -28,10 +28,10 @@ traits: displayName: Finance unrelease encumbrance description: | Finance unrelease encumbrance APIs. - It should only be used by the UI, and only to release a single encumbrance - batch-all-or-nothing should be used otherwise. + It should only be used by the UI, and only to release a single encumbrance - batch-all-or-nothing should be used otherwise. post: is: [validate] - description: Unrelease encumbrance (use only in UI for a single encumbrance - use batch-all-or-nothing otherwise) + description: Unrelease encumbrance (use only in UI for a single encumbrance - use batch-all-or-nothing otherwise) responses: 204: description: "Encumbrance successfully unreleased" diff --git a/src/main/java/org/folio/config/ServicesConfiguration.java b/src/main/java/org/folio/config/ServicesConfiguration.java index 9c6c077d..4e24e012 100644 --- a/src/main/java/org/folio/config/ServicesConfiguration.java +++ b/src/main/java/org/folio/config/ServicesConfiguration.java @@ -1,7 +1,5 @@ package org.folio.config; -import java.util.Set; - import org.folio.rest.core.RestClient; import org.folio.services.ExpenseClassService; import org.folio.services.budget.BudgetExpenseClassService; @@ -10,6 +8,7 @@ import org.folio.services.budget.RecalculateBudgetService; import org.folio.services.budget.CreateBudgetService; import org.folio.services.configuration.ConfigurationEntriesService; +import org.folio.services.fiscalyear.FiscalYearApiService; import org.folio.services.fiscalyear.FiscalYearService; import org.folio.services.fund.FundCodeExpenseClassesService; import org.folio.services.fund.FundDetailsService; @@ -30,20 +29,8 @@ import org.folio.services.protection.AcqUnitMembershipsService; import org.folio.services.protection.AcqUnitsService; import org.folio.services.protection.ProtectionService; -import org.folio.services.transactions.AllocationService; -import org.folio.services.transactions.BaseTransactionService; -import org.folio.services.transactions.BatchTransactionService; -import org.folio.services.transactions.CommonTransactionService; -import org.folio.services.transactions.CreditService; -import org.folio.services.transactions.EncumbranceService; -import org.folio.services.transactions.PaymentService; -import org.folio.services.transactions.PendingPaymentService; -import org.folio.services.transactions.TransactionManagingService; -import org.folio.services.transactions.TransactionRestrictService; +import org.folio.services.transactions.TransactionApiService; import org.folio.services.transactions.TransactionService; -import org.folio.services.transactions.TransactionStrategyFactory; -import org.folio.services.transactions.TransactionTypeManagingStrategy; -import org.folio.services.transactions.TransferService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; @@ -61,19 +48,24 @@ ExpenseClassService expenseClassService(RestClient restClient) { } @Bean - BudgetExpenseClassService budgetExpenseClassService(RestClient restClient, CommonTransactionService transactionService) { + BudgetExpenseClassService budgetExpenseClassService(RestClient restClient, TransactionService transactionService) { return new BudgetExpenseClassService(restClient, transactionService); } @Bean - CommonTransactionService transactionService(RestClient restClient) { - return new CommonTransactionService(restClient); + TransactionApiService transactionApiService(TransactionService transactionService, FundService fundService) { + return new TransactionApiService(transactionService, fundService); + } + + @Bean + TransactionService transactionService(RestClient restClient, FiscalYearService fiscalYearService) { + return new TransactionService(restClient, fiscalYearService); } @Bean BudgetExpenseClassTotalsService budgetExpenseClassTotalsService(RestClient restClient, ExpenseClassService expenseClassService, - CommonTransactionService transactionService, + TransactionService transactionService, BudgetExpenseClassService budgetExpenseClassService) { return new BudgetExpenseClassTotalsService(restClient, expenseClassService, transactionService, budgetExpenseClassService); } @@ -97,8 +89,14 @@ BudgetService budgetService(RestClient restClient, } @Bean - FiscalYearService fiscalYearService(RestClient restClient, ConfigurationEntriesService configurationEntriesService, BudgetService budgetService, AcqUnitsService acqUnitsService){ - return new FiscalYearService(restClient, configurationEntriesService, budgetService, acqUnitsService); + FiscalYearApiService fiscalYearApiService(FiscalYearService fiscalYearService, ConfigurationEntriesService configurationEntriesService, + BudgetService budgetService, AcqUnitsService acqUnitsService){ + return new FiscalYearApiService(fiscalYearService, configurationEntriesService, budgetService, acqUnitsService); + } + + @Bean + FiscalYearService fiscalYearService(RestClient restClient){ + return new FiscalYearService(restClient); } @Bean @@ -133,8 +131,8 @@ LedgerRolloverBudgetsService ledgerRolloverBudgetsService(RestClient restClient) @Bean LedgerTotalsService ledgerTotalsService(FiscalYearService fiscalYearService, BudgetService budgetService, - BaseTransactionService baseTransactionService) { - return new LedgerTotalsService(fiscalYearService, budgetService, baseTransactionService); + TransactionService transactionService) { + return new LedgerTotalsService(fiscalYearService, budgetService, transactionService); } @Bean @@ -148,7 +146,7 @@ GroupService groupService(RestClient restClient, AcqUnitsService acquisitionUnit } @Bean - GroupExpenseClassTotalsService groupExpenseClassTotalsService(GroupFundFiscalYearService groupFundFiscalYearService, CommonTransactionService transactionService, ExpenseClassService expenseClassService) { + GroupExpenseClassTotalsService groupExpenseClassTotalsService(GroupFundFiscalYearService groupFundFiscalYearService, TransactionService transactionService, ExpenseClassService expenseClassService) { return new GroupExpenseClassTotalsService(groupFundFiscalYearService, transactionService, expenseClassService); } @@ -157,61 +155,6 @@ LedgerDetailsService ledgerDetailsService(FiscalYearService fiscalYearService, L return new LedgerDetailsService(fiscalYearService, ledgerService, configurationEntriesService); } - @Bean - TransactionService baseTransactionService(RestClient restClient) { - return new BaseTransactionService(restClient); - } - - @Bean - TransactionRestrictService transactionRestrictService(FundService fundService) { - return new TransactionRestrictService(fundService); - } - - @Bean - TransactionManagingService allocationService(BaseTransactionService transactionService, TransactionRestrictService transactionRestrictService) { - return new AllocationService(transactionService, transactionRestrictService); - } - - @Bean - TransactionManagingService creditService(BaseTransactionService transactionService) { - return new CreditService(transactionService); - } - - @Bean - TransactionManagingService paymentService(BaseTransactionService transactionService) { - return new PaymentService(transactionService); - } - - @Bean - TransactionManagingService encumbranceService(BaseTransactionService transactionService) { - return new EncumbranceService(transactionService); - } - - @Bean - TransactionManagingService transferService(BaseTransactionService transactionService, TransactionRestrictService transactionRestrictService) { - return new TransferService(transactionService, transactionRestrictService); - } - - @Bean - TransactionManagingService pendingPaymentService(BaseTransactionService transactionService) { - return new PendingPaymentService(transactionService); - } - - @Bean - TransactionService commonTransactionService(RestClient restClient) { - return new CommonTransactionService(restClient); - } - - @Bean - TransactionStrategyFactory transactionStrategyFactory(Set transactionTypeManagingStrategies) { - return new TransactionStrategyFactory(transactionTypeManagingStrategies); - } - - @Bean - public BatchTransactionService batchTransactionService(RestClient restClient, BaseTransactionService baseTransactionService) { - return new BatchTransactionService(restClient, baseTransactionService); - } - @Bean FundFiscalYearService fundFiscalYearService(LedgerDetailsService ledgerDetailsService, FundService fundService) { return new FundFiscalYearService(ledgerDetailsService, fundService); @@ -222,16 +165,16 @@ CreateBudgetService createBudgetService(RestClient restClient, GroupFundFiscalYearService groupFundFiscalYearService, FundFiscalYearService fundFiscalYearService, BudgetExpenseClassService budgetExpenseClassService, - CommonTransactionService transactionService, + TransactionService transactionService, FundDetailsService fundDetailsService) { return new CreateBudgetService(restClient, groupFundFiscalYearService, fundFiscalYearService, - budgetExpenseClassService, transactionService, fundDetailsService); + budgetExpenseClassService, transactionService, fundDetailsService); } @Bean GroupFiscalYearTotalsService groupFiscalYearTotalsService(RestClient restClient, GroupFundFiscalYearService groupFundFiscalYearService, - BaseTransactionService baseTransactionService) { - return new GroupFiscalYearTotalsService(restClient, groupFundFiscalYearService, baseTransactionService); + TransactionService transactionService) { + return new GroupFiscalYearTotalsService(restClient, groupFundFiscalYearService, transactionService); } @Bean @@ -255,8 +198,8 @@ public ProtectionService protectionService(AcqUnitsService acqUnitsService, AcqU } @Bean - public RecalculateBudgetService recalculateBudgetService(BudgetService budgetService, CommonTransactionService commonTransactionService) { - return new RecalculateBudgetService(budgetService, commonTransactionService); + public RecalculateBudgetService recalculateBudgetService(BudgetService budgetService, TransactionService transactionService) { + return new RecalculateBudgetService(budgetService, transactionService); } @Bean diff --git a/src/main/java/org/folio/rest/exception/HttpException.java b/src/main/java/org/folio/rest/exception/HttpException.java index 30b72cc4..1bdb9c62 100644 --- a/src/main/java/org/folio/rest/exception/HttpException.java +++ b/src/main/java/org/folio/rest/exception/HttpException.java @@ -9,7 +9,9 @@ import org.apache.commons.lang3.StringUtils; import org.folio.rest.jaxrs.model.Error; import org.folio.rest.jaxrs.model.Errors; +import org.folio.rest.jaxrs.model.Parameter; import org.folio.rest.util.ErrorCodes; +import org.folio.rest.util.HelperUtils; public class HttpException extends RuntimeException { @Serial @@ -35,13 +37,33 @@ public HttpException(int code, ErrorCodes errCodes) { this.code = code; } + public HttpException(int code, ErrorCodes errCodes, Throwable cause) { + super(errCodes.getDescription()); + Error error = new Error() + .withCode(errCodes.getCode()) + .withMessage(errCodes.getDescription()); + if (cause.getMessage() != null) { + Parameter causeParam = new Parameter() + .withKey("cause") + .withValue(cause.getMessage()); + error.setParameters(Collections.singletonList(causeParam)); + } + this.errors = new Errors() + .withErrors(Collections.singletonList(error)) + .withTotalRecords(1); + this.code = code; + } + public HttpException(int code, Error error) { + super(HelperUtils.errorAsString(error)); this.code = code; - this.errors = new Errors().withErrors(Collections.singletonList(error)) - .withTotalRecords(1); + this.errors = new Errors() + .withErrors(Collections.singletonList(error)) + .withTotalRecords(1); } public HttpException(int code, Errors errors) { + super(HelperUtils.errorsAsString(errors)); this.code = code; this.errors = errors; } diff --git a/src/main/java/org/folio/rest/helper/TransactionSummariesHelper.java b/src/main/java/org/folio/rest/helper/TransactionSummariesHelper.java deleted file mode 100644 index d8541e76..00000000 --- a/src/main/java/org/folio/rest/helper/TransactionSummariesHelper.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.folio.rest.helper; - -import static org.folio.rest.util.ResourcePathResolver.INVOICE_TRANSACTION_SUMMARIES; -import static org.folio.rest.util.ResourcePathResolver.ORDER_TRANSACTION_SUMMARIES; -import static org.folio.rest.util.ResourcePathResolver.resourceByIdPath; -import static org.folio.rest.util.ResourcePathResolver.resourcesPath; - -import java.util.Map; - -import org.folio.rest.core.RestClient; -import org.folio.rest.core.models.RequestContext; -import org.folio.rest.exception.HttpException; -import org.folio.rest.jaxrs.model.InvoiceTransactionSummary; -import org.folio.rest.jaxrs.model.OrderTransactionSummary; -import org.folio.rest.util.ErrorCodes; -import org.folio.spring.SpringContextUtil; -import org.springframework.beans.factory.annotation.Autowired; - -import io.vertx.core.Context; -import io.vertx.core.Future; -import io.vertx.core.Vertx; - -public class TransactionSummariesHelper extends AbstractHelper { - @Autowired - private RestClient restClient; - - public TransactionSummariesHelper(Map okapiHeaders, Context ctx) { - super(okapiHeaders, ctx); - SpringContextUtil.autowireDependencies(this, Vertx.currentContext()); - } - - public Future createOrderTransactionSummary(OrderTransactionSummary orderSummary, RequestContext requestContext) { - return Future.succeededFuture() - .map(v -> { - validateOrderTransactionCount(orderSummary.getNumTransactions()); - return null; - }) - .compose(ok -> restClient.post(resourcesPath(ORDER_TRANSACTION_SUMMARIES), orderSummary, OrderTransactionSummary.class, requestContext)) - .map(createdSummary -> orderSummary.withId(createdSummary.getId())); - } - - public Future createInvoiceTransactionSummary(InvoiceTransactionSummary invoiceSummary, RequestContext requestContext) { - return Future.succeededFuture() - .map(v -> { - validateInvoiceTransactionCount(invoiceSummary.getNumPaymentsCredits(), invoiceSummary.getNumPendingPayments()); - return null; - }) - .compose(ok -> restClient.post(resourcesPath(INVOICE_TRANSACTION_SUMMARIES), invoiceSummary, InvoiceTransactionSummary.class, requestContext)) - .map(createdSummary -> invoiceSummary.withId(createdSummary.getId())); - } - - /** - * There has to be atleast 1 transaction that needs to be updated upon invoice approval otherwise throw an exception - */ - private void validateOrderTransactionCount(Integer numTransactions) { - if (numTransactions <= 0) { - throw new HttpException(422, ErrorCodes.INVALID_ORDER_TRANSACTION_COUNT); - } - } - - /** - * There has to be atleast 1 payment/credits, otherwise no point in having an invoice. Also, it is possible that there are no - * encumbrances related to an invoice upon approval. If not, throw an exception - */ - private void validateInvoiceTransactionCount(Integer numPaymentsCredits, Integer numEncumbrances) { - if (numPaymentsCredits <= 0 || numEncumbrances < 0) { - throw new HttpException(422, ErrorCodes.INVALID_INVOICE_TRANSACTION_COUNT); - } - } - - public Future updateOrderTransactionSummary(OrderTransactionSummary orderSummary, RequestContext requestContext) { - return Future.succeededFuture() - .map(v -> { - validateOrderTransactionCount(orderSummary.getNumTransactions()); - return null; - }) - .compose(v -> restClient.put(resourceByIdPath(ORDER_TRANSACTION_SUMMARIES, orderSummary.getId()), orderSummary, requestContext)); - } - - public Future updateInvoiceTransactionSummary(InvoiceTransactionSummary invoiceSummary, RequestContext requestContext) { - return Future.succeededFuture() - .map(v-> { - validateInvoiceTransactionCount(invoiceSummary.getNumPaymentsCredits(), invoiceSummary.getNumPendingPayments()); - return null; - }) - .compose(ok -> restClient.put(resourceByIdPath(INVOICE_TRANSACTION_SUMMARIES, invoiceSummary.getId()), invoiceSummary, requestContext)); - } -} diff --git a/src/main/java/org/folio/rest/impl/EncumbranceApi.java b/src/main/java/org/folio/rest/impl/EncumbranceApi.java index e5af40a4..f88af942 100644 --- a/src/main/java/org/folio/rest/impl/EncumbranceApi.java +++ b/src/main/java/org/folio/rest/impl/EncumbranceApi.java @@ -10,7 +10,7 @@ import org.folio.rest.core.models.RequestContext; import org.folio.rest.jaxrs.resource.FinanceReleaseEncumbranceId; import org.folio.rest.jaxrs.resource.FinanceUnreleaseEncumbranceId; -import org.folio.services.transactions.BatchTransactionService; +import org.folio.services.transactions.TransactionApiService; import org.folio.spring.SpringContextUtil; import org.springframework.beans.factory.annotation.Autowired; @@ -22,7 +22,7 @@ public class EncumbranceApi extends BaseApi implements FinanceReleaseEncumbranceId, FinanceUnreleaseEncumbranceId { @Autowired - private BatchTransactionService batchTransactionService; + private TransactionApiService transactionApiService; public EncumbranceApi() { SpringContextUtil.autowireDependencies(this, Vertx.currentContext()); @@ -32,7 +32,7 @@ public EncumbranceApi() { @Validate public void postFinanceReleaseEncumbranceById(String id, Map okapiHeaders, Handler> asyncResultHandler, Context vertxContext) { - batchTransactionService.releaseEncumbrance(id, new RequestContext(vertxContext, okapiHeaders)) + transactionApiService.releaseEncumbrance(id, new RequestContext(vertxContext, okapiHeaders)) .onSuccess(v -> asyncResultHandler.handle(succeededFuture(buildNoContentResponse()))) .onFailure(fail -> handleErrorResponse(asyncResultHandler, fail)); } @@ -41,7 +41,7 @@ public void postFinanceReleaseEncumbranceById(String id, Map oka @Validate public void postFinanceUnreleaseEncumbranceById(String id, Map okapiHeaders, Handler> asyncResultHandler, Context vertxContext) { - batchTransactionService.unreleaseEncumbrance(id, new RequestContext(vertxContext, okapiHeaders)) + transactionApiService.unreleaseEncumbrance(id, new RequestContext(vertxContext, okapiHeaders)) .onSuccess(v -> asyncResultHandler.handle(succeededFuture(buildNoContentResponse()))) .onFailure(fail -> handleErrorResponse(asyncResultHandler, fail)); } diff --git a/src/main/java/org/folio/rest/impl/FiscalYearsApi.java b/src/main/java/org/folio/rest/impl/FiscalYearsApi.java index 86e0a40c..3a5e3b74 100644 --- a/src/main/java/org/folio/rest/impl/FiscalYearsApi.java +++ b/src/main/java/org/folio/rest/impl/FiscalYearsApi.java @@ -17,7 +17,7 @@ import org.folio.rest.exception.HttpException; import org.folio.rest.jaxrs.model.FiscalYear; import org.folio.rest.jaxrs.resource.FinanceFiscalYears; -import org.folio.services.fiscalyear.FiscalYearService; +import org.folio.services.fiscalyear.FiscalYearApiService; import org.folio.spring.SpringContextUtil; import org.springframework.beans.factory.annotation.Autowired; @@ -33,7 +33,7 @@ public class FiscalYearsApi extends BaseApi implements FinanceFiscalYears { private static final String FISCAL_YEAR_CODE_PATTERN = "^[a-zA-Z]+[0-9]{4}$"; @Autowired - private FiscalYearService fiscalYearService; + private FiscalYearApiService fiscalYearApiService; public FiscalYearsApi() { SpringContextUtil.autowireDependencies(this, Vertx.currentContext()); @@ -57,7 +57,7 @@ public void postFinanceFiscalYears(FiscalYear fiscalYear, Map he // series should always be calculated setFYearWithSeries(fiscalYear); - fiscalYearService.createFiscalYear(fiscalYear, new RequestContext(ctx, headers)) + fiscalYearApiService.createFiscalYear(fiscalYear, new RequestContext(ctx, headers)) .onSuccess(fy -> handler .handle(succeededFuture(buildResponseWithLocation(headers.get(OKAPI_URL), String.format(FISCAL_YEARS_LOCATION_PREFIX, fy.getId()), fy)))) .onFailure(fail -> handleErrorResponse(handler, fail)); @@ -72,7 +72,7 @@ private boolean isFiscalYearValid(FiscalYear fiscalYear) { public void getFinanceFiscalYears(String totalRecords, int offset, int limit, String query, Map headers, Handler> handler, Context ctx) { - fiscalYearService.getFiscalYearsWithAcqUnitsRestriction(query, offset, limit, new RequestContext(ctx, headers)) + fiscalYearApiService.getFiscalYearsWithAcqUnitsRestriction(query, offset, limit, new RequestContext(ctx, headers)) .onSuccess(fiscalYears -> handler.handle(succeededFuture(buildOkResponse(fiscalYears)))) .onFailure(fail -> handleErrorResponse(handler, fail)); } @@ -103,7 +103,7 @@ public void putFinanceFiscalYearsById(String id, FiscalYear fiscalYearRequest, M // series should always be calculated setFYearWithSeries(fiscalYearRequest); - fiscalYearService.updateFiscalYear(fiscalYearRequest, new RequestContext(ctx, headers)) + fiscalYearApiService.updateFiscalYear(fiscalYearRequest, new RequestContext(ctx, headers)) .onSuccess(fiscalYear -> handler.handle(succeededFuture(buildNoContentResponse()))) .onFailure(fail -> handleErrorResponse(handler, fail)); } @@ -113,7 +113,7 @@ public void putFinanceFiscalYearsById(String id, FiscalYear fiscalYearRequest, M public void getFinanceFiscalYearsById(String id, boolean withFinancialSummary, Map headers, Handler> handler, Context ctx) { - fiscalYearService.getFiscalYearById(id, withFinancialSummary, new RequestContext(ctx, headers)) + fiscalYearApiService.getFiscalYearById(id, withFinancialSummary, new RequestContext(ctx, headers)) .onSuccess(fiscalYear -> handler.handle(succeededFuture(buildOkResponse(fiscalYear)))) .onFailure(fail -> handleErrorResponse(handler, fail)); } @@ -122,7 +122,7 @@ public void getFinanceFiscalYearsById(String id, boolean withFinancialSummary, M @Override public void deleteFinanceFiscalYearsById(String id, Map headers, Handler> handler, Context ctx) { - fiscalYearService.deleteFiscalYear(id, new RequestContext(ctx, headers)) + fiscalYearApiService.deleteFiscalYear(id, new RequestContext(ctx, headers)) .onSuccess(fiscalYear -> handler.handle(succeededFuture(buildNoContentResponse()))) .onFailure(fail -> handleErrorResponse(handler, fail)); } diff --git a/src/main/java/org/folio/rest/impl/TransactionSummariesAPI.java b/src/main/java/org/folio/rest/impl/TransactionSummariesAPI.java deleted file mode 100644 index d541e453..00000000 --- a/src/main/java/org/folio/rest/impl/TransactionSummariesAPI.java +++ /dev/null @@ -1,93 +0,0 @@ -package org.folio.rest.impl; - -import static io.vertx.core.Future.succeededFuture; -import static org.apache.commons.lang3.StringUtils.isEmpty; -import static org.folio.rest.util.ErrorCodes.MISMATCH_BETWEEN_ID_IN_PATH_AND_BODY; -import static org.folio.rest.util.HelperUtils.getEndpoint; -import static org.folio.rest.util.HelperUtils.handleErrorResponse; - -import java.util.Map; - -import javax.ws.rs.core.Response; - -import org.folio.rest.annotations.Validate; -import org.folio.rest.core.models.RequestContext; -import org.folio.rest.helper.TransactionSummariesHelper; -import org.folio.rest.jaxrs.model.InvoiceTransactionSummary; -import org.folio.rest.jaxrs.model.OrderTransactionSummary; -import org.folio.rest.jaxrs.resource.FinanceInvoiceTransactionSummaries; -import org.folio.rest.jaxrs.resource.FinanceOrderTransactionSummaries; - -import io.vertx.core.AsyncResult; -import io.vertx.core.Context; -import io.vertx.core.Handler; - -public class TransactionSummariesAPI implements FinanceOrderTransactionSummaries, FinanceInvoiceTransactionSummaries { - - private static final String ORDER_TRANSACTION_SUMMARIES_LOCATION_PREFIX = getEndpoint(FinanceOrderTransactionSummaries.class) + "/%s"; - private static final String INVOICE_TRANSACTION_SUMMARIES_LOCATION_PREFIX = getEndpoint(FinanceInvoiceTransactionSummaries.class) + "/%s"; - - @Override - @Validate - public void postFinanceOrderTransactionSummaries(OrderTransactionSummary entity, Map okapiHeaders, - Handler> asyncResultHandler, Context vertxContext) { - TransactionSummariesHelper helper = new TransactionSummariesHelper(okapiHeaders, vertxContext); - helper.createOrderTransactionSummary(entity, new RequestContext(vertxContext, okapiHeaders)) - .onSuccess(orderTxSummary -> asyncResultHandler.handle(succeededFuture( - helper.buildResponseWithLocation(String.format(ORDER_TRANSACTION_SUMMARIES_LOCATION_PREFIX, orderTxSummary.getId()), orderTxSummary)))) - .onFailure(fail -> handleErrorResponse(asyncResultHandler, helper, fail)); - } - - @Override - @Validate - public void putFinanceOrderTransactionSummariesById(String id, OrderTransactionSummary entity, - Map okapiHeaders, Handler> asyncResultHandler, Context vertxContext) { - TransactionSummariesHelper helper = new TransactionSummariesHelper(okapiHeaders, vertxContext); - - // Set id if this is available only in path - if (isEmpty(entity.getId())) { - entity.setId(id); - } else if (!id.equals(entity.getId())) { - helper.addProcessingError(MISMATCH_BETWEEN_ID_IN_PATH_AND_BODY.toError()); - asyncResultHandler.handle(succeededFuture(helper.buildErrorResponse(422))); - return; - } - - helper.updateOrderTransactionSummary(entity, new RequestContext(vertxContext, okapiHeaders)) - .onSuccess(types -> asyncResultHandler.handle(succeededFuture(helper.buildNoContentResponse()))) - .onFailure(fail -> handleErrorResponse(asyncResultHandler, helper, fail)); - } - - @Override - @Validate - public void postFinanceInvoiceTransactionSummaries(InvoiceTransactionSummary entity, - Map okapiHeaders, Handler> asyncResultHandler, Context vertxContext) { - TransactionSummariesHelper helper = new TransactionSummariesHelper(okapiHeaders, vertxContext); - helper.createInvoiceTransactionSummary(entity, new RequestContext(vertxContext, okapiHeaders)) - .onSuccess(invoiceTxSummary -> asyncResultHandler.handle(succeededFuture(helper - .buildResponseWithLocation(String.format(INVOICE_TRANSACTION_SUMMARIES_LOCATION_PREFIX, invoiceTxSummary.getId()), invoiceTxSummary)))) - .onFailure(fail -> handleErrorResponse(asyncResultHandler, helper, fail)); - } - - @Override - @Validate - public void putFinanceInvoiceTransactionSummariesById(String id, InvoiceTransactionSummary entity, - Map okapiHeaders, Handler> asyncResultHandler, Context vertxContext) { - TransactionSummariesHelper helper = new TransactionSummariesHelper(okapiHeaders, vertxContext); - - // Set id if this is available only in path - if (isEmpty(entity.getId())) { - entity.setId(id); - } else if (!id.equals(entity.getId())) { - helper.addProcessingError(MISMATCH_BETWEEN_ID_IN_PATH_AND_BODY.toError()); - asyncResultHandler.handle(succeededFuture(helper.buildErrorResponse(422))); - return; - } - - helper.updateInvoiceTransactionSummary(entity, new RequestContext(vertxContext, okapiHeaders)) - .onSuccess(types -> asyncResultHandler.handle(succeededFuture(helper.buildNoContentResponse()))) - .onFailure(fail -> handleErrorResponse(asyncResultHandler, helper, fail)); - } - -} - diff --git a/src/main/java/org/folio/rest/impl/TransactionsApi.java b/src/main/java/org/folio/rest/impl/TransactionsApi.java index 6f562e6a..d7df4d22 100644 --- a/src/main/java/org/folio/rest/impl/TransactionsApi.java +++ b/src/main/java/org/folio/rest/impl/TransactionsApi.java @@ -1,8 +1,6 @@ package org.folio.rest.impl; import static io.vertx.core.Future.succeededFuture; -import static org.apache.commons.lang3.StringUtils.isEmpty; -import static org.folio.rest.util.ErrorCodes.MISMATCH_BETWEEN_ID_IN_PATH_AND_BODY; import static org.folio.rest.util.HelperUtils.OKAPI_URL; import static org.folio.rest.util.HelperUtils.getEndpoint; @@ -12,14 +10,10 @@ import org.folio.rest.annotations.Validate; import org.folio.rest.core.models.RequestContext; -import org.folio.rest.exception.HttpException; import org.folio.rest.jaxrs.model.Batch; import org.folio.rest.jaxrs.model.Transaction; -import org.folio.rest.jaxrs.model.Transaction.TransactionType; import org.folio.rest.jaxrs.resource.Finance; -import org.folio.services.transactions.BatchTransactionService; -import org.folio.services.transactions.TransactionService; -import org.folio.services.transactions.TransactionStrategyFactory; +import org.folio.services.transactions.TransactionApiService; import org.folio.spring.SpringContextUtil; import org.springframework.beans.factory.annotation.Autowired; @@ -33,11 +27,7 @@ public class TransactionsApi extends BaseApi implements Finance { private static final String TRANSACTIONS_LOCATION_PREFIX = getEndpoint(Finance.class) + "/%s"; @Autowired - private TransactionStrategyFactory transactionStrategyFactory; - @Autowired - private TransactionService transactionService; - @Autowired - private BatchTransactionService batchTransactionService; + private TransactionApiService transactionApiService; public TransactionsApi() { SpringContextUtil.autowireDependencies(this, Vertx.currentContext()); @@ -48,8 +38,9 @@ public TransactionsApi() { public void postFinanceAllocations(Transaction allocation, Map okapiHeaders, Handler> asyncResultHandler, Context vertxContext) { - transactionStrategyFactory.createTransaction(Transaction.TransactionType.ALLOCATION, allocation, new RequestContext(vertxContext, okapiHeaders)) - .onSuccess(type -> asyncResultHandler.handle(succeededFuture(buildResponseWithLocation(okapiHeaders.get(OKAPI_URL), String.format(TRANSACTIONS_LOCATION_PREFIX, type.getId()), type)))) + transactionApiService.createAllocation(allocation, new RequestContext(vertxContext, okapiHeaders)) + .onSuccess(tr -> asyncResultHandler.handle(succeededFuture(buildResponseWithLocation( + okapiHeaders.get(OKAPI_URL), String.format(TRANSACTIONS_LOCATION_PREFIX, tr.getId()), tr)))) .onFailure(fail -> handleErrorResponse(asyncResultHandler, fail)); } @@ -58,57 +49,18 @@ public void postFinanceAllocations(Transaction allocation, Map o public void postFinanceTransfers(Transaction transfer, Map okapiHeaders, Handler> asyncResultHandler, Context vertxContext) { - transactionStrategyFactory.createTransaction(Transaction.TransactionType.TRANSFER, transfer, new RequestContext(vertxContext, okapiHeaders)) - .onSuccess(type -> asyncResultHandler - .handle(succeededFuture(buildResponseWithLocation(okapiHeaders.get(OKAPI_URL), String.format(TRANSACTIONS_LOCATION_PREFIX, type.getId()), type)))) - .onFailure(fail -> handleErrorResponse(asyncResultHandler, fail)); - } - - @Validate - @Override - public void postFinanceEncumbrances(Transaction encumbrance, Map okapiHeaders, - Handler> asyncResultHandler, Context vertxContext) { - - transactionStrategyFactory.createTransaction(Transaction.TransactionType.ENCUMBRANCE, encumbrance, new RequestContext(vertxContext, okapiHeaders)) - .onSuccess(type -> asyncResultHandler - .handle(succeededFuture(buildResponseWithLocation(okapiHeaders.get(OKAPI_URL), String.format(TRANSACTIONS_LOCATION_PREFIX, type.getId()), type)))) + transactionApiService.createTransfer(transfer, new RequestContext(vertxContext, okapiHeaders)) + .onSuccess(tr -> asyncResultHandler.handle(succeededFuture(buildResponseWithLocation( + okapiHeaders.get(OKAPI_URL), String.format(TRANSACTIONS_LOCATION_PREFIX, tr.getId()), tr)))) .onFailure(fail -> handleErrorResponse(asyncResultHandler, fail)); } - @Validate - @Override - public void putFinanceEncumbrancesById(String id, Transaction encumbrance, Map okapiHeaders, - Handler> asyncResultHandler, Context vertxContext) { - if (isEmpty(encumbrance.getId())) { - encumbrance.setId(id); - } - if (id.equals(encumbrance.getId())) { - - transactionStrategyFactory.updateTransaction(Transaction.TransactionType.ENCUMBRANCE, encumbrance, new RequestContext(vertxContext, okapiHeaders)) - .onSuccess(types -> asyncResultHandler.handle(succeededFuture(buildNoContentResponse()))) - .onFailure(fail -> handleErrorResponse(asyncResultHandler, fail)); - } else { - asyncResultHandler.handle(succeededFuture(buildErrorResponse(new HttpException(422, MISMATCH_BETWEEN_ID_IN_PATH_AND_BODY)))); - } - } - - @Validate - @Override - public void deleteFinanceEncumbrancesById(String id, Map okapiHeaders, - Handler> asyncResultHandler, Context vertxContext) { - transactionService.retrieveTransactionById(id, new RequestContext(vertxContext, okapiHeaders)) - .compose(transaction -> transactionStrategyFactory.deleteTransaction(Transaction.TransactionType.ENCUMBRANCE, - transaction, new RequestContext(vertxContext, okapiHeaders))) - .onSuccess(types -> asyncResultHandler.handle(succeededFuture(buildNoContentResponse()))) - .onFailure(fail -> handleErrorResponse(asyncResultHandler, fail)); - } - @Validate @Override public void getFinanceTransactions(String query, String totalRecords, int offset, int limit, Map okapiHeaders, Handler> asyncResultHandler, Context vertxContext) { - transactionService.retrieveTransactions(query, offset, limit, new RequestContext(vertxContext, okapiHeaders)) + transactionApiService.getTransactionCollectionByQuery(query, offset, limit, new RequestContext(vertxContext, okapiHeaders)) .onSuccess(types -> asyncResultHandler.handle(succeededFuture(buildOkResponse(types)))) .onFailure(fail -> handleErrorResponse(asyncResultHandler, fail)); } @@ -118,94 +70,17 @@ public void getFinanceTransactions(String query, String totalRecords, int offset public void getFinanceTransactionsById(String id, Map okapiHeaders, Handler> asyncResultHandler, Context vertxContext) { - transactionService.retrieveTransactionById(id, new RequestContext(vertxContext, okapiHeaders)) + transactionApiService.getTransactionById(id, new RequestContext(vertxContext, okapiHeaders)) .onSuccess(type -> asyncResultHandler.handle(succeededFuture(buildOkResponse(type)))) .onFailure(fail -> handleErrorResponse(asyncResultHandler, fail)); } @Validate @Override - public void postFinancePayments(Transaction payment, Map okapiHeaders, - Handler> asyncResultHandler, Context vertxContext) { - - transactionStrategyFactory.createTransaction(Transaction.TransactionType.PAYMENT, payment, new RequestContext(vertxContext, okapiHeaders)) - .onSuccess(type -> asyncResultHandler - .handle(succeededFuture(buildResponseWithLocation(okapiHeaders.get(OKAPI_URL), String.format(TRANSACTIONS_LOCATION_PREFIX, type.getId()), type)))) - .onFailure(fail -> handleErrorResponse(asyncResultHandler, fail)); - } - - @Override - public void putFinancePaymentsById(String id, Transaction payment, - Map okapiHeaders, Handler> asyncResultHandler, Context vertxContext) { - if (isEmpty(payment.getId())) { - payment.setId(id); - } else if (!id.equals(payment.getId())) { - asyncResultHandler.handle(succeededFuture(buildErrorResponse(new HttpException(422, MISMATCH_BETWEEN_ID_IN_PATH_AND_BODY)))); - return; - } - transactionStrategyFactory.updateTransaction( - TransactionType.PAYMENT, payment, new RequestContext(vertxContext, okapiHeaders)) - .onSuccess(types -> asyncResultHandler.handle(succeededFuture(buildNoContentResponse()))) - .onFailure(fail -> handleErrorResponse(asyncResultHandler, fail)); - } - - @Validate - @Override - public void postFinancePendingPayments(Transaction pendingPayment, Map okapiHeaders, - Handler> asyncResultHandler, Context vertxContext) { - - transactionStrategyFactory.createTransaction(Transaction.TransactionType.PENDING_PAYMENT, pendingPayment, new RequestContext(vertxContext, okapiHeaders)) - .onSuccess(transaction -> asyncResultHandler - .handle(succeededFuture(buildResponseWithLocation(okapiHeaders.get(OKAPI_URL), String.format(TRANSACTIONS_LOCATION_PREFIX, transaction.getId()), transaction)))) - .onFailure(fail -> handleErrorResponse(asyncResultHandler, fail)); - } - - @Override - public void putFinancePendingPaymentsById(String id, Transaction pendingPayment, - Map okapiHeaders, Handler> asyncResultHandler, Context vertxContext) { - if (isEmpty(pendingPayment.getId())) { - pendingPayment.setId(id); - } else if (!id.equals(pendingPayment.getId())) { - asyncResultHandler.handle(succeededFuture(buildErrorResponse(new HttpException(422, MISMATCH_BETWEEN_ID_IN_PATH_AND_BODY)))); - return; - } - transactionStrategyFactory.updateTransaction( - TransactionType.PENDING_PAYMENT, pendingPayment, new RequestContext(vertxContext, okapiHeaders)) - .onSuccess(types -> asyncResultHandler.handle(succeededFuture(buildNoContentResponse()))) - .onFailure(fail -> handleErrorResponse(asyncResultHandler, fail)); - } - - @Validate - @Override - public void postFinanceCredits(Transaction credit, Map okapiHeaders, + public void postFinanceTransactionsBatchAllOrNothing(Batch batch, Map okapiHeaders, Handler> asyncResultHandler, Context vertxContext) { - transactionStrategyFactory.createTransaction(Transaction.TransactionType.CREDIT, credit, new RequestContext(vertxContext, okapiHeaders)) - .onSuccess(type -> asyncResultHandler - .handle(succeededFuture(buildResponseWithLocation(okapiHeaders.get(OKAPI_URL), String.format(TRANSACTIONS_LOCATION_PREFIX, type.getId()), type)))) - .onFailure(fail -> handleErrorResponse(asyncResultHandler, fail)); - } - - @Override - public void putFinanceCreditsById(String id, Transaction credit, - Map okapiHeaders, Handler> asyncResultHandler, Context vertxContext) { - if (isEmpty(credit.getId())) { - credit.setId(id); - } else if (!id.equals(credit.getId())) { - asyncResultHandler.handle(succeededFuture(buildErrorResponse(new HttpException(422, MISMATCH_BETWEEN_ID_IN_PATH_AND_BODY)))); - return; - } - transactionStrategyFactory.updateTransaction( - TransactionType.CREDIT, credit, new RequestContext(vertxContext, okapiHeaders)) - .onSuccess(types -> asyncResultHandler.handle(succeededFuture(buildNoContentResponse()))) - .onFailure(fail -> handleErrorResponse(asyncResultHandler, fail)); - } - - @Validate - @Override - public void postFinanceTransactionsBatchAllOrNothing(Batch batch, Map okapiHeaders, - Handler> asyncResultHandler, Context vertxContext) { - batchTransactionService.processBatch(batch, new RequestContext(vertxContext, okapiHeaders)) + transactionApiService.processBatch(batch, new RequestContext(vertxContext, okapiHeaders)) .onSuccess(types -> asyncResultHandler.handle(succeededFuture(buildNoContentResponse()))) .onFailure(fail -> handleErrorResponse(asyncResultHandler, fail)); } diff --git a/src/main/java/org/folio/rest/util/HelperUtils.java b/src/main/java/org/folio/rest/util/HelperUtils.java index 97826bf2..4fa8b751 100644 --- a/src/main/java/org/folio/rest/util/HelperUtils.java +++ b/src/main/java/org/folio/rest/util/HelperUtils.java @@ -5,7 +5,6 @@ import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; import static org.apache.commons.lang3.StringUtils.EMPTY; import static org.folio.rest.util.ErrorCodes.GENERIC_ERROR_CODE; -import static org.folio.rest.util.ErrorCodes.NEGATIVE_VALUE; import java.math.BigDecimal; import java.net.URLEncoder; @@ -38,7 +37,6 @@ import org.folio.rest.helper.AbstractHelper; import org.folio.rest.jaxrs.model.Error; import org.folio.rest.jaxrs.model.Errors; -import org.folio.rest.jaxrs.model.Parameter; import io.vertx.core.json.Json; import io.vertx.core.json.JsonObject; @@ -186,22 +184,6 @@ public static javax.ws.rs.core.Response.ResponseBuilder createResponseBuilder(in }; } - public static void validateAmount(double doubleAmount, String fieldName) { - BigDecimal amount = BigDecimal.valueOf(doubleAmount); - if (isNegative(amount)) { - Parameter parameter = new Parameter().withKey("field").withValue(fieldName); - throw new HttpException(422, NEGATIVE_VALUE.toError().withParameters(Collections.singletonList(parameter))); - } - } - - private static boolean isNegative(BigDecimal amount) { - return amount.compareTo(BigDecimal.ZERO) < 0; - } - - public static Future unsupportedOperationExceptionFuture() { - return Future.failedFuture(new UnsupportedOperationException()); - } - public static double calculateTotals(List budgets, ToDoubleFunction getDouble) { return budgets.stream() .map(budget -> BigDecimal.valueOf(getDouble.applyAsDouble(budget))) @@ -239,4 +221,32 @@ public static void removeInitialAllocationByFunds(List allocationTo } }); } + + public static String errorsAsString(Errors errors) { + if (errors == null) { + return GENERIC_ERROR_CODE.getDescription(); + } + List errorList = errors.getErrors(); + if (errorList.isEmpty()) { + return GENERIC_ERROR_CODE.getDescription(); + } + if (errorList.size() == 1) { + return errorAsString(errorList.get(0)); + } + return JsonObject.mapFrom(errorList).encode(); + } + + public static String errorAsString(Error error) { + if (error == null) { + return GENERIC_ERROR_CODE.getDescription(); + } + if (!error.getParameters().isEmpty()) { + return JsonObject.mapFrom(error).encode(); + } + if (error.getMessage() == null) { + return GENERIC_ERROR_CODE.getDescription(); + } + return error.getMessage(); + } + } diff --git a/src/main/java/org/folio/services/budget/BudgetExpenseClassService.java b/src/main/java/org/folio/services/budget/BudgetExpenseClassService.java index bc434a00..4bc9b194 100644 --- a/src/main/java/org/folio/services/budget/BudgetExpenseClassService.java +++ b/src/main/java/org/folio/services/budget/BudgetExpenseClassService.java @@ -34,7 +34,7 @@ import org.folio.rest.jaxrs.model.BudgetExpenseClassCollection; import org.folio.rest.jaxrs.model.SharedBudget; import org.folio.rest.jaxrs.model.StatusExpenseClass; -import org.folio.services.transactions.CommonTransactionService; +import org.folio.services.transactions.TransactionService; import io.vertx.core.Future; @@ -43,9 +43,9 @@ public class BudgetExpenseClassService { private static final Logger log = LogManager.getLogger(); private final RestClient restClient; - private final CommonTransactionService transactionService; + private final TransactionService transactionService; - public BudgetExpenseClassService(RestClient restClient, CommonTransactionService transactionService) { + public BudgetExpenseClassService(RestClient restClient, TransactionService transactionService) { this.restClient = restClient; this.transactionService = transactionService; } @@ -118,7 +118,7 @@ private Future deleteBudgetExpenseClasses(List deleteL private Future checkNoTransactionsAssigned(List deleteList, SharedBudget budget, RequestContext requestContext) { log.debug("checkNoTransactionsAssigned:: Checking there is no transaction assigned for budget: {} and deleteList with size: {}", budget.getId(), deleteList.size()); - return transactionService.retrieveTransactions(deleteList, budget, requestContext) + return transactionService.getBudgetTransactionsWithExpenseClasses(deleteList, budget, requestContext) .map(transactions -> { if (isNotEmpty(transactions)) { log.error("checkNoTransactionsAssigned:: There is assigned transaction for budget: '{}'", budget.getId()); diff --git a/src/main/java/org/folio/services/budget/BudgetExpenseClassTotalsService.java b/src/main/java/org/folio/services/budget/BudgetExpenseClassTotalsService.java index bf060c2f..51177ab9 100644 --- a/src/main/java/org/folio/services/budget/BudgetExpenseClassTotalsService.java +++ b/src/main/java/org/folio/services/budget/BudgetExpenseClassTotalsService.java @@ -28,7 +28,7 @@ import org.folio.rest.jaxrs.model.Transaction; import org.folio.rest.util.MoneyUtils; import org.folio.services.ExpenseClassService; -import org.folio.services.transactions.CommonTransactionService; +import org.folio.services.transactions.TransactionService; import io.vertx.core.Future; import org.javamoney.moneta.Money; @@ -37,12 +37,12 @@ public class BudgetExpenseClassTotalsService { private final RestClient restClient; private final ExpenseClassService expenseClassService; - private final CommonTransactionService transactionService; + private final TransactionService transactionService; private final BudgetExpenseClassService budgetExpenseClassService; public BudgetExpenseClassTotalsService(RestClient restClient, ExpenseClassService expenseClassService, - CommonTransactionService transactionService, + TransactionService transactionService, BudgetExpenseClassService budgetExpenseClassService) { this.restClient = restClient; this.expenseClassService = expenseClassService; @@ -53,7 +53,7 @@ public BudgetExpenseClassTotalsService(RestClient restClient, public Future getExpenseClassTotals(String budgetId, RequestContext requestContext) { return restClient.get(resourceByIdPath(BUDGETS_STORAGE, budgetId), Budget.class, requestContext) .compose(budget -> expenseClassService.getExpenseClassesByBudgetId(budgetId, requestContext) - .compose(expenseClasses -> transactionService.retrieveTransactions(budget, requestContext) + .compose(expenseClasses -> transactionService.getBudgetTransactions(budget, requestContext) .map(transactions -> buildBudgetExpenseClassesTotals(expenseClasses, transactions, budget)))) .compose(budgetExpenseClassTotalsCollection -> budgetExpenseClassService.getBudgetExpenseClasses(budgetId, requestContext) .map(budgetExpenseClasses -> updateExpenseClassStatus(budgetExpenseClassTotalsCollection, budgetExpenseClasses))); diff --git a/src/main/java/org/folio/services/budget/CreateBudgetService.java b/src/main/java/org/folio/services/budget/CreateBudgetService.java index 99121d37..967ed7c6 100644 --- a/src/main/java/org/folio/services/budget/CreateBudgetService.java +++ b/src/main/java/org/folio/services/budget/CreateBudgetService.java @@ -25,9 +25,9 @@ import org.folio.services.fund.FundDetailsService; import org.folio.services.fund.FundFiscalYearService; import org.folio.services.group.GroupFundFiscalYearService; -import org.folio.services.transactions.CommonTransactionService; import io.vertx.core.Future; +import org.folio.services.transactions.TransactionService; public class CreateBudgetService { @@ -37,14 +37,14 @@ public class CreateBudgetService { private final GroupFundFiscalYearService groupFundFiscalYearService; private final FundFiscalYearService fundFiscalYearService; private final BudgetExpenseClassService budgetExpenseClassService; - private final CommonTransactionService transactionService; + private final TransactionService transactionService; private final FundDetailsService fundDetailsService; public CreateBudgetService(RestClient restClient, GroupFundFiscalYearService groupFundFiscalYearService, FundFiscalYearService fundFiscalYearService, BudgetExpenseClassService budgetExpenseClassService, - CommonTransactionService transactionService, + TransactionService transactionService, FundDetailsService fundDetailsService) { this.restClient = restClient; this.groupFundFiscalYearService = groupFundFiscalYearService; @@ -95,10 +95,10 @@ private Future allocateToBudget(Budget createdBudget, RequestContext req if (createdBudget.getAllocated() > 0d) { log.info("allocateToBudget:: allocation for created budget '{}' is greater than zero, allocation transaction is being created", createdBudget.getId()); return transactionService.createAllocationTransaction(createdBudget, requestContext) - .map(transaction -> createdBudget) - .recover(e -> { - log.error("Failed to create allocation transaction for budget '{}': {}", createdBudget.getId(), e.getMessage(), e); - return Future.failedFuture(new HttpException(500, ErrorCodes.ALLOCATION_TRANSFER_FAILED)); + .map(v -> createdBudget) + .recover(t -> { + log.error("Failed to create allocation transaction for budget '{}': {}", createdBudget.getId(), t.getMessage(), t); + return Future.failedFuture(new HttpException(500, ErrorCodes.ALLOCATION_TRANSFER_FAILED, t)); }); } log.info("allocateToBudget:: Allocation for createdBudget '{}' is zero or less, no transaction needed", createdBudget.getId()); diff --git a/src/main/java/org/folio/services/budget/RecalculateBudgetService.java b/src/main/java/org/folio/services/budget/RecalculateBudgetService.java index 9e6ea82f..14253839 100644 --- a/src/main/java/org/folio/services/budget/RecalculateBudgetService.java +++ b/src/main/java/org/folio/services/budget/RecalculateBudgetService.java @@ -6,22 +6,22 @@ import org.folio.rest.jaxrs.model.SharedBudget; import org.folio.rest.jaxrs.model.Transaction; import org.folio.rest.util.BudgetUtils; -import org.folio.services.transactions.CommonTransactionService; +import org.folio.services.transactions.TransactionService; import java.util.List; public class RecalculateBudgetService { private final BudgetService budgetService; - private final CommonTransactionService transactionService; + private final TransactionService transactionService; - public RecalculateBudgetService(BudgetService budgetService, CommonTransactionService transactionService) { + public RecalculateBudgetService(BudgetService budgetService, TransactionService transactionService) { this.budgetService = budgetService; this.transactionService = transactionService; } public Future recalculateBudget(String budgetId, RequestContext requestContext) { return budgetService.getBudgetById(budgetId, requestContext) - .compose(budget -> transactionService.retrieveTransactions(BudgetUtils.convertToBudget(budget), requestContext) + .compose(budget -> transactionService.getBudgetTransactions(BudgetUtils.convertToBudget(budget), requestContext) .map(transactions -> recalculateBudgetBasedOnTransactions(budget, transactions))) .compose(budget -> budgetService.updateBudgetWithAmountFields(budget, requestContext)) .mapEmpty(); diff --git a/src/main/java/org/folio/services/fiscalyear/FiscalYearApiService.java b/src/main/java/org/folio/services/fiscalyear/FiscalYearApiService.java new file mode 100644 index 00000000..91eeae85 --- /dev/null +++ b/src/main/java/org/folio/services/fiscalyear/FiscalYearApiService.java @@ -0,0 +1,105 @@ +package org.folio.services.fiscalyear; + +import static io.vertx.core.Future.succeededFuture; +import static org.folio.rest.util.HelperUtils.combineCqlExpressions; + +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.folio.rest.core.models.RequestContext; +import org.folio.rest.jaxrs.model.Budget; +import org.folio.rest.jaxrs.model.FinancialSummary; +import org.folio.rest.jaxrs.model.FiscalYear; +import org.folio.rest.jaxrs.model.FiscalYearsCollection; +import org.folio.rest.util.HelperUtils; +import org.folio.services.budget.BudgetService; +import org.folio.services.configuration.ConfigurationEntriesService; +import org.folio.services.protection.AcqUnitsService; + +import io.vertx.core.Future; + +public class FiscalYearApiService { + + private static final Logger log = LogManager.getLogger(); + + private final FiscalYearService fiscalYearService; + private final ConfigurationEntriesService configurationEntriesService; + private final BudgetService budgetService; + private final AcqUnitsService acqUnitsService; + + /** + * This class is only used by FiscalYearApi + */ + public FiscalYearApiService(FiscalYearService fiscalYearService, ConfigurationEntriesService configurationEntriesService, + BudgetService budgetService, AcqUnitsService acqUnitsService) { + this.fiscalYearService = fiscalYearService; + this.configurationEntriesService = configurationEntriesService; + this.budgetService = budgetService; + this.acqUnitsService = acqUnitsService; + } + + public Future createFiscalYear(FiscalYear fiscalYear, RequestContext requestContext) { + log.debug("createFiscalYear:: Creating fiscal year: {}", fiscalYear.getId()); + return configurationEntriesService.getSystemCurrency(requestContext) + .compose(currency -> { + fiscalYear.setCurrency(currency); + return fiscalYearService.createFiscalYear(fiscalYear, requestContext); + }); + } + + public Future getFiscalYearsWithAcqUnitsRestriction(String query, int offset, int limit, + RequestContext requestContext) { + return acqUnitsService.buildAcqUnitsCqlClause(requestContext) + .map(clause -> StringUtils.isEmpty(query) ? clause : combineCqlExpressions("and", clause, query)) + .compose(effectiveQuery -> fiscalYearService.getFiscalYearsWithoutAcqUnitsRestriction(effectiveQuery, offset, + limit, requestContext)); + } + + public Future getFiscalYearById(String id, boolean withFinancialSummary, RequestContext requestContext) { + return fiscalYearService.getFiscalYearById(id, requestContext) + .compose(fiscalYear -> { + if (withFinancialSummary) { + return withFinancialSummary(fiscalYear, requestContext); + } + return succeededFuture(fiscalYear); + }); + } + + public Future updateFiscalYear(FiscalYear fiscalYear, RequestContext requestContext) { + return configurationEntriesService.getSystemCurrency(requestContext) + .compose(currency -> { + fiscalYear.setCurrency(currency); + return fiscalYearService.updateFiscalYear(fiscalYear, requestContext); + }); + } + + public Future deleteFiscalYear(String id, RequestContext requestContext) { + return fiscalYearService.deleteFiscalYear(id, requestContext); + } + + private Future withFinancialSummary(FiscalYear fiscalYear, RequestContext requestContext) { + String query = "fiscalYearId==" + fiscalYear.getId(); + return budgetService.getBudgets(query, 0, Integer.MAX_VALUE, requestContext) + .map(budgetsCollection -> populateFinancialSummary(fiscalYear, budgetsCollection.getBudgets())); + } + + private FiscalYear populateFinancialSummary(FiscalYear fiscalYear, List budgets) { + FinancialSummary financialSummary = new FinancialSummary() + .withAllocated(HelperUtils.calculateTotals(budgets, Budget::getAllocated)) + .withAvailable(HelperUtils.calculateTotals(budgets, Budget::getAvailable)) + .withUnavailable(HelperUtils.calculateTotals(budgets, Budget::getUnavailable)) + .withInitialAllocation(HelperUtils.calculateTotals(budgets, Budget::getInitialAllocation)) + .withAllocationTo(HelperUtils.calculateTotals(budgets, Budget::getAllocationTo)) + .withAllocationFrom(HelperUtils.calculateTotals(budgets, Budget::getAllocationFrom)) + .withAwaitingPayment(HelperUtils.calculateTotals(budgets, Budget::getAwaitingPayment)) + .withEncumbered(HelperUtils.calculateTotals(budgets, Budget::getEncumbered)) + .withExpenditures(HelperUtils.calculateTotals(budgets, Budget::getExpenditures)) + .withOverEncumbrance(HelperUtils.calculateTotals(budgets, Budget::getOverEncumbrance)) + .withOverExpended(HelperUtils.calculateTotals(budgets, Budget::getOverExpended)) + .withTotalFunding(HelperUtils.calculateTotals(budgets, Budget::getTotalFunding)) + .withCashBalance(HelperUtils.calculateTotals(budgets, Budget::getCashBalance)); + return fiscalYear.withFinancialSummary(financialSummary); + } +} diff --git a/src/main/java/org/folio/services/fiscalyear/FiscalYearService.java b/src/main/java/org/folio/services/fiscalyear/FiscalYearService.java index 8d63dda5..f7ebc593 100644 --- a/src/main/java/org/folio/services/fiscalyear/FiscalYearService.java +++ b/src/main/java/org/folio/services/fiscalyear/FiscalYearService.java @@ -1,30 +1,19 @@ package org.folio.services.fiscalyear; -import static io.vertx.core.Future.succeededFuture; import static org.folio.rest.util.ErrorCodes.FISCAL_YEARS_NOT_FOUND; -import static org.folio.rest.util.HelperUtils.combineCqlExpressions; import static org.folio.rest.util.ResourcePathResolver.FISCAL_YEARS_STORAGE; import static org.folio.rest.util.ResourcePathResolver.resourceByIdPath; import static org.folio.rest.util.ResourcePathResolver.resourcesPath; -import java.util.List; - import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.folio.rest.core.RestClient; import org.folio.rest.core.models.RequestContext; import org.folio.rest.core.models.RequestEntry; import org.folio.rest.exception.HttpException; -import org.folio.rest.jaxrs.model.Budget; -import org.folio.rest.jaxrs.model.FinancialSummary; import org.folio.rest.jaxrs.model.FiscalYear; import org.folio.rest.jaxrs.model.FiscalYearsCollection; -import org.folio.rest.util.HelperUtils; -import org.folio.services.budget.BudgetService; -import org.folio.services.configuration.ConfigurationEntriesService; -import org.folio.services.protection.AcqUnitsService; import io.vertx.core.Future; @@ -33,24 +22,13 @@ public class FiscalYearService { private static final Logger log = LogManager.getLogger(); private final RestClient restClient; - private final ConfigurationEntriesService configurationEntriesService; - private final BudgetService budgetService; - private final AcqUnitsService acqUnitsService; - public FiscalYearService(RestClient fiscalYearRestClient, ConfigurationEntriesService configurationEntriesService, BudgetService budgetService, AcqUnitsService acqUnitsService) { - this.restClient = fiscalYearRestClient; - this.configurationEntriesService = configurationEntriesService; - this.budgetService = budgetService; - this.acqUnitsService = acqUnitsService; + public FiscalYearService(RestClient restClient) { + this.restClient = restClient; } public Future createFiscalYear(FiscalYear fiscalYear, RequestContext requestContext) { - log.debug("createFiscalYear:: Creating fiscal year: {}", fiscalYear.getId()); - return configurationEntriesService.getSystemCurrency(requestContext) - .compose(currency -> { - fiscalYear.setCurrency(currency); - return restClient.post(resourcesPath(FISCAL_YEARS_STORAGE), fiscalYear, FiscalYear.class, requestContext); - }); + return restClient.post(resourcesPath(FISCAL_YEARS_STORAGE), fiscalYear, FiscalYear.class, requestContext); } public Future getFiscalYearsWithoutAcqUnitsRestriction(String query, int offset, int limit, RequestContext requestContext) { @@ -61,25 +39,8 @@ public Future getFiscalYearsWithoutAcqUnitsRestriction(St return restClient.get(requestEntry.buildEndpoint(), FiscalYearsCollection.class, requestContext); } - public Future getFiscalYearsWithAcqUnitsRestriction(String query, int offset, int limit, RequestContext requestContext) { - return acqUnitsService.buildAcqUnitsCqlClause(requestContext) - .map(clause -> StringUtils.isEmpty(query) ? clause : combineCqlExpressions("and", clause, query)) - .map(effectiveQuery -> new RequestEntry(resourcesPath(FISCAL_YEARS_STORAGE)) - .withOffset(offset) - .withLimit(limit) - .withQuery(effectiveQuery) - ) - .compose(requestEntry -> restClient.get(requestEntry.buildEndpoint(), FiscalYearsCollection.class, requestContext)); - } - - public Future getFiscalYearById(String id, boolean withFinancialSummary, RequestContext requestContext) { - return restClient.get(resourceByIdPath(FISCAL_YEARS_STORAGE, id), FiscalYear.class, requestContext) - .compose(fiscalYear -> { - if (withFinancialSummary) { - return withFinancialSummary(fiscalYear, requestContext); - } - return succeededFuture(fiscalYear); - }); + public Future getFiscalYearById(String id, RequestContext requestContext) { + return restClient.get(resourceByIdPath(FISCAL_YEARS_STORAGE, id), FiscalYear.class, requestContext); } public Future getFiscalYearByFiscalYearCode(String fiscalYearCode, RequestContext requestContext) { @@ -102,45 +63,12 @@ public String getFiscalYearByFiscalYearCode(String fiscalYearCode) { return String.format("code=%s", fiscalYearCode); } - public Future getFiscalYearById(String id, RequestContext requestContext) { - return getFiscalYearById(id, false, requestContext); - } - public Future updateFiscalYear(FiscalYear fiscalYear, RequestContext requestContext) { - return configurationEntriesService.getSystemCurrency(requestContext) - .compose(currency -> { - fiscalYear.setCurrency(currency); - return restClient.put(resourceByIdPath(FISCAL_YEARS_STORAGE, fiscalYear.getId()), fiscalYear, requestContext); - }); - + return restClient.put(resourceByIdPath(FISCAL_YEARS_STORAGE, fiscalYear.getId()), fiscalYear, requestContext); } public Future deleteFiscalYear(String id, RequestContext requestContext) { return restClient.delete(resourceByIdPath(FISCAL_YEARS_STORAGE, id), requestContext); } - - public Future withFinancialSummary(FiscalYear fiscalYear, RequestContext requestContext) { - String query = "fiscalYearId==" + fiscalYear.getId(); - return budgetService.getBudgets(query, 0, Integer.MAX_VALUE, requestContext) - .map(budgetsCollection -> populateFinancialSummary(fiscalYear, budgetsCollection.getBudgets())); - } - - private FiscalYear populateFinancialSummary(FiscalYear fiscalYear, List budgets) { - FinancialSummary financialSummary = new FinancialSummary() - .withAllocated(HelperUtils.calculateTotals(budgets, Budget::getAllocated)) - .withAvailable(HelperUtils.calculateTotals(budgets, Budget::getAvailable)) - .withUnavailable(HelperUtils.calculateTotals(budgets, Budget::getUnavailable)) - .withInitialAllocation(HelperUtils.calculateTotals(budgets, Budget::getInitialAllocation)) - .withAllocationTo(HelperUtils.calculateTotals(budgets, Budget::getAllocationTo)) - .withAllocationFrom(HelperUtils.calculateTotals(budgets, Budget::getAllocationFrom)) - .withAwaitingPayment(HelperUtils.calculateTotals(budgets, Budget::getAwaitingPayment)) - .withEncumbered(HelperUtils.calculateTotals(budgets, Budget::getEncumbered)) - .withExpenditures(HelperUtils.calculateTotals(budgets, Budget::getExpenditures)) - .withOverEncumbrance(HelperUtils.calculateTotals(budgets, Budget::getOverEncumbrance)) - .withOverExpended(HelperUtils.calculateTotals(budgets, Budget::getOverExpended)) - .withTotalFunding(HelperUtils.calculateTotals(budgets, Budget::getTotalFunding)) - .withCashBalance(HelperUtils.calculateTotals(budgets, Budget::getCashBalance)); - return fiscalYear.withFinancialSummary(financialSummary); - } } diff --git a/src/main/java/org/folio/services/fund/FundCodeExpenseClassesService.java b/src/main/java/org/folio/services/fund/FundCodeExpenseClassesService.java index df850028..e3fbc657 100644 --- a/src/main/java/org/folio/services/fund/FundCodeExpenseClassesService.java +++ b/src/main/java/org/folio/services/fund/FundCodeExpenseClassesService.java @@ -102,7 +102,7 @@ public Future getFundCodeVsExpenseClassesWithF .compose(fcecHolder -> getActiveBudgetsByFiscalYear(fcecHolder.getFiscalYear(), requestContext)) .map(fundCodeExpenseClassesHolder::withBudgetCollectionList) .map(holder -> holder.getBudgetCollection().getBudgets().stream().map(Budget::getFundId).distinct().collect(Collectors.toList())) - .compose(fundsId -> fundService.getFunds(fundsId, requestContext)) + .compose(fundsId -> fundService.getFundsByIds(fundsId, requestContext)) .map(fundCodeExpenseClassesHolder::withFundList) .map(fcecHolder -> fcecHolder.getFundList().stream().map(Fund::getLedgerId).collect(Collectors.toList())) .compose(ledgerIds -> ledgerService.getLedgers(ledgerIds, requestContext)) diff --git a/src/main/java/org/folio/services/fund/FundService.java b/src/main/java/org/folio/services/fund/FundService.java index b0153bc4..b62abf2c 100644 --- a/src/main/java/org/folio/services/fund/FundService.java +++ b/src/main/java/org/folio/services/fund/FundService.java @@ -12,7 +12,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.folio.rest.core.RestClient; @@ -64,23 +63,23 @@ public Future getFundsWithoutAcqUnitsRestriction(String query, return restClient.get(requestEntry.buildEndpoint(), FundsCollection.class, requestContext); } - public Future> getFunds(List fundIds, RequestContext requestContext) { + public Future> getFundsByIds(List fundIds, RequestContext requestContext) { return collectResultsOnSuccess( ofSubLists(new ArrayList<>(fundIds), MAX_IDS_FOR_GET_RQ) - .map(ids -> getFundsByIds(ids, requestContext)) - .collect(Collectors.toList())) + .map(ids -> getFundsByIdsChunk(ids, requestContext)) + .toList()) .map(lists -> lists.stream() .flatMap(Collection::stream) - .collect(Collectors.toList()) + .toList() ); } - public Future> getFundsByIds(List ids, RequestContext requestContext) { + private Future> getFundsByIdsChunk(List ids, RequestContext requestContext) { String query = HelperUtils.convertIdsToCqlQuery(ids); var requestEntry = new RequestEntry(resourcesPath(FUNDS_STORAGE)) .withQuery(query) .withOffset(0) - .withLimit(MAX_IDS_FOR_GET_RQ); + .withLimit(Integer.MAX_VALUE); return restClient.get(requestEntry.buildEndpoint(), FundsCollection.class, requestContext) .map(FundsCollection::getFunds); } diff --git a/src/main/java/org/folio/services/group/GroupExpenseClassTotalsService.java b/src/main/java/org/folio/services/group/GroupExpenseClassTotalsService.java index 37ab126a..f271b2c2 100644 --- a/src/main/java/org/folio/services/group/GroupExpenseClassTotalsService.java +++ b/src/main/java/org/folio/services/group/GroupExpenseClassTotalsService.java @@ -28,7 +28,7 @@ import org.folio.rest.util.MoneyUtils; import org.folio.services.ExpenseClassService; import org.folio.services.budget.RecalculatedBudgetBuilder; -import org.folio.services.transactions.CommonTransactionService; +import org.folio.services.transactions.TransactionService; import org.javamoney.moneta.Money; import org.javamoney.moneta.function.MonetaryFunctions; @@ -39,10 +39,10 @@ public class GroupExpenseClassTotalsService { private static final Logger log = LogManager.getLogger(); private final GroupFundFiscalYearService groupFundFiscalYearService; - private final CommonTransactionService transactionService; + private final TransactionService transactionService; private final ExpenseClassService expenseClassService; - public GroupExpenseClassTotalsService(GroupFundFiscalYearService groupFundFiscalYearService, CommonTransactionService transactionService, ExpenseClassService expenseClassService) { + public GroupExpenseClassTotalsService(GroupFundFiscalYearService groupFundFiscalYearService, TransactionService transactionService, ExpenseClassService expenseClassService) { this.groupFundFiscalYearService = groupFundFiscalYearService; this.transactionService = transactionService; this.expenseClassService = expenseClassService; @@ -67,7 +67,7 @@ private Future getGroupExpenseClassTotals(Lis private Future> getTransactions(List groupFundFiscalYears, String fiscalYearId, RequestContext requestContext) { List fundIds = groupFundFiscalYears.stream().map(GroupFundFiscalYear::getFundId).collect(Collectors.toList()); - return transactionService.retrieveTransactionsByFundIds(fundIds, fiscalYearId, requestContext); + return transactionService.getTransactionsByFundIds(fundIds, fiscalYearId, requestContext); } private Future> getExpenseClasses(List groupFundFiscalYears, RequestContext requestContext) { diff --git a/src/main/java/org/folio/services/group/GroupFiscalYearTotalsService.java b/src/main/java/org/folio/services/group/GroupFiscalYearTotalsService.java index ba71a273..dfa290f8 100644 --- a/src/main/java/org/folio/services/group/GroupFiscalYearTotalsService.java +++ b/src/main/java/org/folio/services/group/GroupFiscalYearTotalsService.java @@ -36,7 +36,7 @@ import org.folio.rest.jaxrs.model.Transaction; import org.folio.rest.jaxrs.model.Transaction.TransactionType; import org.folio.rest.util.HelperUtils; -import org.folio.services.transactions.BaseTransactionService; +import org.folio.services.transactions.TransactionService; import io.vertx.core.Future; @@ -46,13 +46,13 @@ public class GroupFiscalYearTotalsService { private final RestClient restClient; private final GroupFundFiscalYearService groupFundFiscalYearService; - private final BaseTransactionService baseTransactionService; + private final TransactionService transactionService; public GroupFiscalYearTotalsService(RestClient restClient, GroupFundFiscalYearService groupFundFiscalYearService, - BaseTransactionService baseTransactionService) { + TransactionService transactionService) { this.restClient = restClient; this.groupFundFiscalYearService = groupFundFiscalYearService; - this.baseTransactionService = baseTransactionService; + this.transactionService = transactionService; } public Future getGroupFiscalYearSummaries(String query, RequestContext requestContext) { @@ -83,7 +83,7 @@ public Future getGroupFiscalYearSummaries(Stri return buildHolderSkeletons(fundIdFiscalYearIdBudgetsMap, collection, groupFundFiscalYearsCollection); })) .compose(holders -> updateHoldersWithAllocations(holders, requestContext) - .map(holder -> { + .map(v -> { log.debug("getGroupFiscalYearSummaries:: Updating group summary with allocation fields for '{}' holder(s)", holders.size()); updateGroupSummaryWithAllocation(holders); return null; @@ -144,6 +144,7 @@ private GroupFiscalYearSummaryCollection convertHolders(List holders) { holders.forEach(holder -> { + holder.withToAllocations(new ArrayList<>(holder.getToAllocations())); removeInitialAllocationByFunds(holder.getToAllocations()); GroupFiscalYearSummary summary = holder.getGroupFiscalYearSummary(); summary.withAllocationTo(HelperUtils.calculateTotals(holder.getToAllocations(), Transaction::getAmount)) @@ -259,8 +260,8 @@ private Future updateHoldersWithTransfers(List updateHolderWithAllocations(RequestContext requestContext, GroupFiscalYearTransactionsHolder holder) { List groupFundIds = holder.getGroupFundIds(); String fiscalYearId = holder.getGroupFiscalYearSummary().getFiscalYearId(); - var fromAllocations = baseTransactionService.retrieveFromTransactions(groupFundIds, fiscalYearId, List.of(TransactionType.ALLOCATION), requestContext); - var toAllocations = baseTransactionService.retrieveToTransactions(groupFundIds, fiscalYearId, List.of(TransactionType.ALLOCATION), requestContext); + var fromAllocations = transactionService.getTransactionsFromFunds(groupFundIds, fiscalYearId, List.of(TransactionType.ALLOCATION), requestContext); + var toAllocations = transactionService.getTransactionsToFunds(groupFundIds, fiscalYearId, List.of(TransactionType.ALLOCATION), requestContext); return GenericCompositeFuture.join(List.of(fromAllocations, toAllocations)) .map(cf -> holder.withToAllocations(toAllocations.result()).withFromAllocations(fromAllocations.result())); @@ -271,8 +272,8 @@ private Future updateHolderWithTransfers(Requ String fiscalYearId = holder.getGroupFiscalYearSummary().getFiscalYearId(); List trTypes = List.of(TransactionType.TRANSFER, TransactionType.ROLLOVER_TRANSFER); - var fromTransfers = baseTransactionService.retrieveFromTransactions(groupFundIds, fiscalYearId, trTypes, requestContext); - var toTransfers = baseTransactionService.retrieveToTransactions(groupFundIds, fiscalYearId, trTypes, requestContext); + var fromTransfers = transactionService.getTransactionsFromFunds(groupFundIds, fiscalYearId, trTypes, requestContext); + var toTransfers = transactionService.getTransactionsToFunds(groupFundIds, fiscalYearId, trTypes, requestContext); return GenericCompositeFuture.join(List.of(fromTransfers, toTransfers)) .map(cf -> holder.withToTransfers(toTransfers.result()).withFromTransfers(fromTransfers.result())); } diff --git a/src/main/java/org/folio/services/ledger/LedgerTotalsService.java b/src/main/java/org/folio/services/ledger/LedgerTotalsService.java index 7eea1e00..210a930f 100644 --- a/src/main/java/org/folio/services/ledger/LedgerTotalsService.java +++ b/src/main/java/org/folio/services/ledger/LedgerTotalsService.java @@ -4,6 +4,7 @@ import static org.folio.rest.util.HelperUtils.removeInitialAllocationByFunds; import java.math.BigDecimal; +import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -24,9 +25,9 @@ import org.folio.rest.util.HelperUtils; import org.folio.services.budget.BudgetService; import org.folio.services.fiscalyear.FiscalYearService; -import org.folio.services.transactions.BaseTransactionService; import io.vertx.core.Future; +import org.folio.services.transactions.TransactionService; public class LedgerTotalsService { @@ -35,12 +36,12 @@ public class LedgerTotalsService { private final FiscalYearService fiscalYearService; private final BudgetService budgetService; - private final BaseTransactionService baseTransactionService; + private final TransactionService transactionService; - public LedgerTotalsService(FiscalYearService fiscalYearService, BudgetService budgetService, BaseTransactionService baseTransactionService) { + public LedgerTotalsService(FiscalYearService fiscalYearService, BudgetService budgetService, TransactionService transactionService) { this.fiscalYearService = fiscalYearService; this.budgetService = budgetService; - this.baseTransactionService = baseTransactionService; + this.transactionService = transactionService; } public Future populateLedgerTotals(Ledger ledger, String fiscalYearId, RequestContext requestContext) { @@ -77,18 +78,19 @@ public Future populateLedgerTotals(Ledger ledger, FiscalYear fiscalYear, } private void updateLedgerWithAllocation(LedgerFiscalYearTransactionsHolder holder) { - removeInitialAllocationByFunds(holder.getToAllocations()); - Ledger ledger = holder.getLedger(); - ledger.withAllocationTo(HelperUtils.calculateTotals(holder.getToAllocations(), Transaction::getAmount)) - .withAllocationFrom(HelperUtils.calculateTotals(holder.getFromAllocations(), Transaction::getAmount)); + holder.withToAllocations(new ArrayList<>(holder.getToAllocations())); + removeInitialAllocationByFunds(holder.getToAllocations()); + Ledger ledger = holder.getLedger(); + ledger.withAllocationTo(HelperUtils.calculateTotals(holder.getToAllocations(), Transaction::getAmount)) + .withAllocationFrom(HelperUtils.calculateTotals(holder.getFromAllocations(), Transaction::getAmount)); } private Future updateHolderWithAllocations(LedgerFiscalYearTransactionsHolder holder, RequestContext requestContext) { List ledgerFundIds = holder.getLedgerFundIds(); String fiscalYearId = holder.getFiscalYearId(); - var fromAllocations = baseTransactionService.retrieveFromTransactions(ledgerFundIds, fiscalYearId, List.of(TransactionType.ALLOCATION), requestContext); - var toAllocations = baseTransactionService.retrieveToTransactions(ledgerFundIds, fiscalYearId, List.of(TransactionType.ALLOCATION), requestContext); + var fromAllocations = transactionService.getTransactionsFromFunds(ledgerFundIds, fiscalYearId, List.of(TransactionType.ALLOCATION), requestContext); + var toAllocations = transactionService.getTransactionsToFunds(ledgerFundIds, fiscalYearId, List.of(TransactionType.ALLOCATION), requestContext); return GenericCompositeFuture.join(List.of(fromAllocations, toAllocations)) .map(cf -> holder.withToAllocations(toAllocations.result()).withFromAllocations(fromAllocations.result())); } @@ -98,8 +100,8 @@ private Future updateHolderWithTransfers(Led List ledgerFundIds = holder.getLedgerFundIds(); String fiscalYearId = holder.getFiscalYearId(); List trTypes = List.of(TransactionType.TRANSFER, TransactionType.ROLLOVER_TRANSFER); - var fromTransfer = baseTransactionService.retrieveFromTransactions(ledgerFundIds, fiscalYearId, trTypes, requestContext); - var toTransfer = baseTransactionService.retrieveToTransactions(ledgerFundIds, fiscalYearId, trTypes, requestContext); + var fromTransfer = transactionService.getTransactionsFromFunds(ledgerFundIds, fiscalYearId, trTypes, requestContext); + var toTransfer = transactionService.getTransactionsToFunds(ledgerFundIds, fiscalYearId, trTypes, requestContext); return GenericCompositeFuture.join(List.of(fromTransfer, toTransfer)) .map(f -> holder.withToTransfers(toTransfer.result()).withFromTransfers(fromTransfer.result())); diff --git a/src/main/java/org/folio/services/transactions/AllocationService.java b/src/main/java/org/folio/services/transactions/AllocationService.java deleted file mode 100644 index ce642782..00000000 --- a/src/main/java/org/folio/services/transactions/AllocationService.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.folio.services.transactions; - -import org.folio.rest.core.models.RequestContext; -import org.folio.rest.jaxrs.model.Transaction; -import org.folio.rest.util.HelperUtils; - -import io.vertx.core.Future; - -public class AllocationService implements TransactionTypeManagingStrategy { - - private final TransactionService transactionService; - private final TransactionRestrictService transactionRestrictService; - - public AllocationService(TransactionService transactionService, TransactionRestrictService transactionRestrictService) { - this.transactionService = transactionService; - this.transactionRestrictService = transactionRestrictService; - } - - @Override - public Future createTransaction(Transaction allocation, RequestContext requestContext) { - return Future.succeededFuture() - .map(v -> { - transactionService.validateTransactionType(allocation, Transaction.TransactionType.ALLOCATION); - return null; - }) - .compose(aVoid -> transactionRestrictService.checkAllocation(allocation, requestContext)) - .compose(v -> transactionService.createTransaction(allocation, requestContext)); - } - - @Override - public Future updateTransaction(Transaction transaction, RequestContext requestContext) { - return HelperUtils.unsupportedOperationExceptionFuture(); - } - - @Override - public Future deleteTransaction(Transaction encumbrance, RequestContext requestContext) { - return HelperUtils.unsupportedOperationExceptionFuture(); - } - - @Override - public Transaction.TransactionType getStrategyName() { - return Transaction.TransactionType.ALLOCATION; - } - -} diff --git a/src/main/java/org/folio/services/transactions/BaseTransactionService.java b/src/main/java/org/folio/services/transactions/BaseTransactionService.java deleted file mode 100644 index f3e088df..00000000 --- a/src/main/java/org/folio/services/transactions/BaseTransactionService.java +++ /dev/null @@ -1,134 +0,0 @@ -package org.folio.services.transactions; - -import static one.util.streamex.StreamEx.ofSubLists; -import static org.folio.rest.util.ErrorCodes.INVALID_TRANSACTION_TYPE; -import static org.folio.rest.util.HelperUtils.collectResultsOnSuccess; -import static org.folio.rest.util.HelperUtils.convertIdsToCqlQuery; -import static org.folio.rest.util.ResourcePathResolver.TRANSACTIONS; -import static org.folio.rest.util.ResourcePathResolver.resourceByIdPath; -import static org.folio.rest.util.ResourcePathResolver.resourcesPath; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.function.Function; -import java.util.stream.Collectors; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.folio.rest.core.RestClient; -import org.folio.rest.core.models.RequestContext; -import org.folio.rest.core.models.RequestEntry; -import org.folio.rest.exception.HttpException; -import org.folio.rest.jaxrs.model.Parameter; -import org.folio.rest.jaxrs.model.Transaction; -import org.folio.rest.jaxrs.model.TransactionCollection; - -import io.vertx.core.Future; - -public class BaseTransactionService implements TransactionService { - - private static final Logger log = LogManager.getLogger(); - private static final int MAX_FUND_PER_QUERY = 5; - private static final int MAX_TRANSACTIONS_PER_QUERY = 15; - private static final String ALLOCATION_TYPE_TRANSACTIONS_QUERY = "(fiscalYearId==%s AND %s) AND %s"; - private static final String AWAITING_PAYMENT_WITH_ENCUMBRANCE = "awaitingPayment.encumbranceId==%s"; - - final RestClient restClient; - - public BaseTransactionService(RestClient restClient) { - this.restClient = restClient; - } - - @Override - public Future retrieveTransactions(String query, int offset, int limit, RequestContext requestContext) { - var requestEntry = new RequestEntry(resourcesPath(TRANSACTIONS)) - .withOffset(offset) - .withLimit(limit) - .withQuery(query); - return restClient.get(requestEntry.buildEndpoint(), TransactionCollection.class, requestContext); - } - - @Override - public Future retrieveTransactionById(String id, RequestContext requestContext) { - return restClient.get(resourceByIdPath(TRANSACTIONS, id), Transaction.class, requestContext); - } - - public Future createTransaction(Transaction transaction, RequestContext requestContext) { - return restClient.post(resourcesPath(TRANSACTIONS), transaction, Transaction.class, requestContext); - } - - public Future updateTransaction(Transaction transaction, RequestContext requestContext) { - return restClient.put(resourceByIdPath(TRANSACTIONS, transaction.getId()), transaction, requestContext); - } - - public Future deleteTransaction(Transaction transaction, RequestContext requestContext) { - return restClient.delete(resourceByIdPath(TRANSACTIONS, transaction.getId()), requestContext); - } - - public void validateTransactionType(Transaction transaction, Transaction.TransactionType transactionType) { - if (transaction.getTransactionType() != transactionType) { - log.warn("validateTransactionType:: Transaction '{}' type mismatch. '{}' expected", transaction.getId(), transactionType); - Parameter parameter = new Parameter().withKey("expected").withValue(transactionType.name()); - throw new HttpException(422, INVALID_TRANSACTION_TYPE.toError().withParameters(Collections.singletonList(parameter))); - } - } - - public Future> retrieveFromTransactions(List fundIds, String fiscalYearId, - List trTypes, RequestContext requestContext) { - return collectResultsOnSuccess( - ofSubLists(new ArrayList<>(fundIds), MAX_FUND_PER_QUERY) - .map(ids -> retrieveAllocationTransactionsChunk(ids, fiscalYearId, trTypes, "fromFundId", requestContext) - .map(transactions -> filterFundIdsByAllocationDirection(fundIds, transactions, Transaction::getToFundId))) - .collect(Collectors.toList())).map(lists -> lists.stream().flatMap(Collection::stream).collect(Collectors.toList())); - } - - public Future> retrieveToTransactions(List fundIds, String fiscalYearId, - List trTypes, RequestContext requestContext) { - return collectResultsOnSuccess( - ofSubLists(new ArrayList<>(fundIds), MAX_FUND_PER_QUERY) - .map(ids -> retrieveAllocationTransactionsChunk(ids, fiscalYearId, trTypes, "toFundId", requestContext) - .map(transactions -> filterFundIdsByAllocationDirection(fundIds, transactions, Transaction::getFromFundId))) - .collect(Collectors.toList())).map(lists -> lists.stream().flatMap(Collection::stream).collect(Collectors.toList())); - } - - public Future> retrievePendingPaymentsByEncumbranceIds(List encumbranceIds, - RequestContext requestContext) { - return collectResultsOnSuccess( - ofSubLists(new ArrayList<>(encumbranceIds), MAX_TRANSACTIONS_PER_QUERY) - .map(ids -> retrievePendingPaymentsByEncumbranceIdsChunk(ids, requestContext)) - .toList()) - .map(lists -> lists.stream().flatMap(Collection::stream).toList()); - } - - public Future isConnectedToInvoice(String transactionId, RequestContext requestContext) { - // We want to know if the order with the given encumbrance is connected to an invoice. - // To avoid adding a dependency to mod-invoice, we check if there is a related awaitingPayment transaction - String query = String.format(AWAITING_PAYMENT_WITH_ENCUMBRANCE, transactionId); - return retrieveTransactions(query, 0, Integer.MAX_VALUE, requestContext) - .map(collection -> collection.getTotalRecords() > 0); - } - - private Future> retrieveAllocationTransactionsChunk(List fundIds, String fiscalYearId, - List trTypes, String allocationDirection, RequestContext requestContext) { - String fundQuery = convertIdsToCqlQuery(fundIds, allocationDirection, "==", " OR "); - List trTypeValues = trTypes.stream().map(Transaction.TransactionType::value).collect(Collectors.toList()); - String trTypeQuery = convertIdsToCqlQuery(trTypeValues, "transactionType", "==", " OR "); - String query = String.format(ALLOCATION_TYPE_TRANSACTIONS_QUERY, fiscalYearId, trTypeQuery, fundQuery); - return retrieveTransactions(query, 0, Integer.MAX_VALUE, requestContext).map(TransactionCollection::getTransactions); - } - - private List filterFundIdsByAllocationDirection(List fundIds, List transactions, Function allocationDirection) { - return transactions.stream() - .filter(transaction -> !fundIds.contains(allocationDirection.apply(transaction))) - .collect(Collectors.toList()); - } - - private Future> retrievePendingPaymentsByEncumbranceIdsChunk(List encumbranceIds, - RequestContext requestContext) { - String query = convertIdsToCqlQuery(encumbranceIds, "awaitingPayment.encumbranceId", "==", " OR "); - return retrieveTransactions(query, 0, Integer.MAX_VALUE, requestContext) - .map(TransactionCollection::getTransactions); - } -} diff --git a/src/main/java/org/folio/services/transactions/BatchTransactionService.java b/src/main/java/org/folio/services/transactions/BatchTransactionService.java deleted file mode 100644 index 6a9fb53b..00000000 --- a/src/main/java/org/folio/services/transactions/BatchTransactionService.java +++ /dev/null @@ -1,117 +0,0 @@ -package org.folio.services.transactions; - -import io.vertx.core.Future; -import io.vertx.core.json.JsonObject; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.folio.rest.core.RestClient; -import org.folio.rest.core.models.RequestContext; -import org.folio.rest.exception.HttpException; -import org.folio.rest.jaxrs.model.Batch; -import org.folio.rest.jaxrs.model.Encumbrance; -import org.folio.rest.jaxrs.model.Transaction; - -import java.util.List; -import java.util.Optional; - -import static io.vertx.core.Future.succeededFuture; -import static java.lang.Boolean.TRUE; -import static java.util.Collections.singletonList; -import static org.folio.rest.util.ErrorCodes.DELETE_CONNECTED_TO_INVOICE; -import static org.folio.rest.util.ResourcePathResolver.BATCH_TRANSACTIONS_STORAGE; -import static org.folio.rest.util.ResourcePathResolver.resourcesPath; - -public class BatchTransactionService { - private static final Logger logger = LogManager.getLogger(); - - private final RestClient restClient; - private final BaseTransactionService baseTransactionService; - - public BatchTransactionService(RestClient restClient, BaseTransactionService baseTransactionService) { - this.restClient = restClient; - this.baseTransactionService = baseTransactionService; - } - - public Future processBatch(Batch batch, RequestContext requestContext) { - return checkDeletions(batch, requestContext) - .compose(v -> restClient.postEmptyResponse(resourcesPath(BATCH_TRANSACTIONS_STORAGE), batch, requestContext)) - .onSuccess(v -> logger.info("Batch transaction successful")) - .onFailure(t -> logger.error("Batch transaction failed, batch={}", JsonObject.mapFrom(batch).encodePrettily(), t)); - } - - public Future releaseEncumbrance(String id, RequestContext requestContext) { - return baseTransactionService.retrieveTransactionById(id, requestContext) - .compose(transaction -> releaseEncumbrance(transaction, requestContext)) - .onSuccess(v -> logger.info("Release encumbrance successful, id={}", id)) - .onFailure(t -> logger.error("Release encumbrance failed, id={}", id, t)); - } - - public Future unreleaseEncumbrance(String id, RequestContext requestContext) { - return baseTransactionService.retrieveTransactionById(id, requestContext) - .compose(transaction -> unreleaseEncumbrance(transaction, requestContext)) - .onSuccess(v -> logger.info("Unrelease encumbrance successful, id={}", id)) - .onFailure(t -> logger.error("Unrelease encumbrance failed, id={}", id, t)); - } - - private Future releaseEncumbrance(Transaction transaction, RequestContext requestContext) { - baseTransactionService.validateTransactionType(transaction, Transaction.TransactionType.ENCUMBRANCE); - if (transaction.getEncumbrance().getStatus() == Encumbrance.Status.RELEASED) { - return succeededFuture(null); - } - transaction.getEncumbrance().setStatus(Encumbrance.Status.RELEASED); - return updateTransaction(transaction, requestContext); - } - - private Future unreleaseEncumbrance(Transaction transaction, RequestContext requestContext) { - baseTransactionService.validateTransactionType(transaction, Transaction.TransactionType.ENCUMBRANCE); - if (transaction.getEncumbrance().getStatus() != Encumbrance.Status.RELEASED) { - return succeededFuture(null); - } - transaction.getEncumbrance().setStatus(Encumbrance.Status.UNRELEASED); - return updateTransaction(transaction, requestContext); - } - - private Future updateTransaction(Transaction transaction, RequestContext requestContext) { - // This will need to change to use patch when it is available - see MODFIN-351 - Batch batch = new Batch() - .withTransactionsToUpdate(singletonList(transaction)); - return processBatch(batch, requestContext); - } - - /** - * Check transaction deletions are allowed. - * Usually it is not allowed to delete an encumbrance connected to an approved invoice. - * To avoid adding a dependency to mod-invoice, we check if there is a related awaitingPayment transaction. - * It is OK to delete an encumbrance connected to a *cancelled* invoice *if* the batch includes a change to the - * matching pending payment to remove the link to the encumbrance. - */ - private Future checkDeletions(Batch batch, RequestContext requestContext) { - List ids = batch.getIdsOfTransactionsToDelete(); - if (ids.isEmpty()) { - return succeededFuture(); - } - return baseTransactionService.retrievePendingPaymentsByEncumbranceIds(ids, requestContext) - .map(pendingPayments -> { - if (pendingPayments.isEmpty()) { - return null; - } - ids.forEach(id -> { - Optional existingPP = pendingPayments.stream() - .filter(pp -> id.equals(pp.getAwaitingPayment().getEncumbranceId())).findFirst(); - if (existingPP.isEmpty()) { - return; - } - if (TRUE.equals(existingPP.get().getInvoiceCancelled())) { - Optional matchingPPInBatch = batch.getTransactionsToUpdate().stream() - .filter(pp -> existingPP.get().getId().equals(pp.getId())).findFirst(); - if (matchingPPInBatch.isPresent() && matchingPPInBatch.get().getAwaitingPayment().getEncumbranceId() == null) { - return; - } - } - logger.warn("validateDeletion:: Tried to delete transactions but one is connected to an invoice, id={}", id); - throw new HttpException(422, DELETE_CONNECTED_TO_INVOICE.toError()); - }); - return null; - }); - } -} diff --git a/src/main/java/org/folio/services/transactions/CommonTransactionService.java b/src/main/java/org/folio/services/transactions/CommonTransactionService.java deleted file mode 100644 index aa651ee2..00000000 --- a/src/main/java/org/folio/services/transactions/CommonTransactionService.java +++ /dev/null @@ -1,79 +0,0 @@ -package org.folio.services.transactions; - -import static org.folio.rest.RestConstants.MAX_IDS_FOR_GET_RQ; -import static org.folio.rest.util.HelperUtils.collectResultsOnSuccess; -import static org.folio.rest.util.HelperUtils.convertIdsToCqlQuery; -import static org.folio.rest.util.ResourcePathResolver.FISCAL_YEARS_STORAGE; -import static org.folio.rest.util.ResourcePathResolver.resourceByIdPath; - -import java.util.Collection; -import java.util.List; -import java.util.stream.Collectors; - -import org.folio.rest.core.RestClient; -import org.folio.rest.core.models.RequestContext; -import org.folio.rest.jaxrs.model.Budget; -import org.folio.rest.jaxrs.model.BudgetExpenseClass; -import org.folio.rest.jaxrs.model.FiscalYear; -import org.folio.rest.jaxrs.model.SharedBudget; -import org.folio.rest.jaxrs.model.Transaction; -import org.folio.rest.jaxrs.model.TransactionCollection; - -import io.vertx.core.Future; -import one.util.streamex.StreamEx; - -public class CommonTransactionService extends BaseTransactionService { - - public CommonTransactionService(RestClient restClient) { - super(restClient); - } - - public Future> retrieveTransactions(Budget budget, RequestContext requestContext) { - String query = String.format("(fromFundId==%s OR toFundId==%s) AND fiscalYearId==%s", budget.getFundId(), budget.getFundId(), budget.getFiscalYearId()); - return retrieveTransactions(query, 0, Integer.MAX_VALUE, requestContext) - .map(TransactionCollection::getTransactions); - } - - public Future> retrieveTransactions(List budgetExpenseClasses, SharedBudget budget, RequestContext requestContext) { - List ids = budgetExpenseClasses.stream() - .map(BudgetExpenseClass::getExpenseClassId) - .collect(Collectors.toList()); - String query = String.format("(fromFundId==%s OR toFundId==%s) AND fiscalYearId==%s AND %s", budget.getFundId(), budget.getFundId(), budget.getFiscalYearId(), convertIdsToCqlQuery(ids, "expenseClassId", true)); - return retrieveTransactions(query, 0, Integer.MAX_VALUE, requestContext) - .map(TransactionCollection::getTransactions); - } - - public Future> retrieveTransactionsByFundIds(List fundIds, String fiscalYearId, RequestContext requestContext) { - List>> futures = StreamEx - .ofSubLists(fundIds, MAX_IDS_FOR_GET_RQ) - .map(ids -> retrieveTransactionsChunk(buildGetTransactionsQuery(fiscalYearId, ids), requestContext)) - .collect(Collectors.toList()); - - return collectResultsOnSuccess(futures) - .map(listList -> listList.stream() - .flatMap(Collection::stream) - .collect(Collectors.toList()) - ); - } - - private Future> retrieveTransactionsChunk(String query, RequestContext requestContext) { - return retrieveTransactions(query, 0, Integer.MAX_VALUE, requestContext) - .map(TransactionCollection::getTransactions); - } - - private String buildGetTransactionsQuery(String fiscalYearId, List fundIds) { - return String.format("fiscalYearId==%s AND (%s OR %s)", - fiscalYearId, - convertIdsToCqlQuery(fundIds, "fromFundId", true), - convertIdsToCqlQuery(fundIds, "toFundId", true)); - } - - public Future createAllocationTransaction(Budget budget, RequestContext requestContext) { - Transaction transaction = new Transaction().withAmount(budget.getAllocated()) - .withFiscalYearId(budget.getFiscalYearId()).withToFundId(budget.getFundId()) - .withTransactionType(Transaction.TransactionType.ALLOCATION).withSource(Transaction.Source.USER); - return restClient.get(resourceByIdPath(FISCAL_YEARS_STORAGE, budget.getFiscalYearId()), FiscalYear.class, requestContext) - .compose(fiscalYear -> createTransaction(transaction.withCurrency(fiscalYear.getCurrency()), requestContext)); - } - -} diff --git a/src/main/java/org/folio/services/transactions/CreditService.java b/src/main/java/org/folio/services/transactions/CreditService.java deleted file mode 100644 index 7822c3e8..00000000 --- a/src/main/java/org/folio/services/transactions/CreditService.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.folio.services.transactions; - -import static org.folio.rest.util.ErrorCodes.UPDATE_CREDIT_TO_CANCEL_INVOICE; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.folio.rest.core.models.RequestContext; -import org.folio.rest.exception.HttpException; -import org.folio.rest.jaxrs.model.Transaction; -import org.folio.rest.util.HelperUtils; - -import io.vertx.core.Future; - -public class CreditService implements TransactionTypeManagingStrategy { - - private static final Logger log = LogManager.getLogger(); - private final TransactionService transactionService; - - public CreditService(TransactionService transactionService) { - this.transactionService = transactionService; - } - - @Override - public Future createTransaction(Transaction credit, RequestContext requestContext) { - return Future.succeededFuture() - .map(v-> { - transactionService.validateTransactionType(credit, Transaction.TransactionType.CREDIT); - HelperUtils.validateAmount(credit.getAmount(), "amount"); - return null; - }) - .compose(aVoid -> transactionService.createTransaction(credit, requestContext)); - } - - @Override - public Future updateTransaction(Transaction credit, RequestContext requestContext) { - log.debug("updateTransaction:: Updating transaction '{}'", credit.getId()); - return Future.succeededFuture() - .map(v -> { - transactionService.validateTransactionType(credit, Transaction.TransactionType.CREDIT); - if (!Boolean.TRUE.equals(credit.getInvoiceCancelled())) { - log.warn("updateTransaction:: Credit '{}' invoice is not cancelled", credit.getId()); - throw new HttpException(422, UPDATE_CREDIT_TO_CANCEL_INVOICE.toError()); - } - return null; - }) - .compose(v -> transactionService.retrieveTransactionById(credit.getId(), requestContext)) - .map(existingTransaction -> { - if (Boolean.TRUE.equals(existingTransaction.getInvoiceCancelled())) { - log.warn("updateTransaction:: Existing transaction '{}' already has invoiceCancelled flag set to true", existingTransaction.getId()); - throw new HttpException(422, UPDATE_CREDIT_TO_CANCEL_INVOICE.toError()); - } - // compare new transaction with existing one: ignore invoiceCancelled and metadata changes - existingTransaction.setInvoiceCancelled(true); - existingTransaction.setMetadata(credit.getMetadata()); - if (!existingTransaction.equals(credit)) { - log.warn("updateTransaction:: Existing transaction '{}' is equal to credit '{}'", existingTransaction.getId(), credit.getId()); - throw new HttpException(422, UPDATE_CREDIT_TO_CANCEL_INVOICE.toError()); - } - return null; - }) - .compose(v -> transactionService.updateTransaction(credit, requestContext)); - } - - @Override - public Future deleteTransaction(Transaction encumbrance, RequestContext requestContext) { - return HelperUtils.unsupportedOperationExceptionFuture(); - } - - @Override - public Transaction.TransactionType getStrategyName() { - return Transaction.TransactionType.CREDIT; - } - -} diff --git a/src/main/java/org/folio/services/transactions/EncumbranceService.java b/src/main/java/org/folio/services/transactions/EncumbranceService.java deleted file mode 100644 index e7408274..00000000 --- a/src/main/java/org/folio/services/transactions/EncumbranceService.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.folio.services.transactions; - -import static org.folio.rest.util.ErrorCodes.DELETE_CONNECTED_TO_INVOICE; -import static org.folio.rest.util.ErrorCodes.TRANSACTION_NOT_RELEASED; - -import java.util.Collections; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.folio.rest.core.models.RequestContext; -import org.folio.rest.exception.HttpException; -import org.folio.rest.jaxrs.model.Encumbrance; -import org.folio.rest.jaxrs.model.Parameter; -import org.folio.rest.jaxrs.model.Transaction; - -import io.vertx.core.Future; - -public class EncumbranceService implements TransactionTypeManagingStrategy { - - private static final Logger log = LogManager.getLogger(); - private final TransactionService transactionService; - - public EncumbranceService(TransactionService transactionService) { - this.transactionService = transactionService; - } - - @Override - public Future createTransaction(Transaction encumbrance, RequestContext requestContext) { - return Future.succeededFuture() - .map(v -> { - transactionService.validateTransactionType(encumbrance, Transaction.TransactionType.ENCUMBRANCE); - return null; - }) - .compose(aVoid -> transactionService.createTransaction(encumbrance, requestContext)); - } - - @Override - public Future updateTransaction(Transaction encumbrance, RequestContext requestContext) { - return Future.succeededFuture() - .map(v -> { - transactionService.validateTransactionType(encumbrance, Transaction.TransactionType.ENCUMBRANCE); - return null; - }) - .compose(aVoid -> transactionService.updateTransaction(encumbrance, requestContext)); - } - - @Override - public Future deleteTransaction(Transaction encumbrance, RequestContext requestContext) { - return Future.succeededFuture() - .map(v -> { - transactionService.validateTransactionType(encumbrance, Transaction.TransactionType.ENCUMBRANCE); - return null; - }) - .compose(aVoid -> validateDeletion(encumbrance, requestContext)) - .compose(aVoid -> transactionService.deleteTransaction(encumbrance, requestContext)); - } - - @Override - public Transaction.TransactionType getStrategyName() { - return Transaction.TransactionType.ENCUMBRANCE; - } - - private Future validateDeletion(Transaction encumbrance, RequestContext requestContext) { - log.debug("validateDeletion:: Validation to delete encumbrance '{}'", encumbrance.getId()); - return Future.succeededFuture() - .map(v -> { - checkEncumbranceStatusNotReleased(encumbrance); - return null; - }) - .compose(v -> transactionService.isConnectedToInvoice(encumbrance.getId(), requestContext)) - .map(connected -> { - if (connected) { - log.warn("validateDeletion:: Tried to delete transaction {} but it is connected to an invoice.", encumbrance.getId()); - Parameter parameter = new Parameter().withKey("id").withValue(encumbrance.getId()); - throw new HttpException(422, DELETE_CONNECTED_TO_INVOICE.toError().withParameters(Collections.singletonList(parameter))); - } - return null; - }); - } - - private void checkEncumbranceStatusNotReleased(Transaction encumbrance) { - if (encumbrance.getEncumbrance().getStatus() != Encumbrance.Status.RELEASED) { - log.warn("checkEncumbranceStatusNotReleased:: Transaction {} should be released before deletion", encumbrance.getId()); - Parameter parameter = new Parameter().withKey("id").withValue(encumbrance.getId()); - throw new HttpException(400, TRANSACTION_NOT_RELEASED.toError().withParameters(Collections.singletonList(parameter))); - } - } -} diff --git a/src/main/java/org/folio/services/transactions/PaymentService.java b/src/main/java/org/folio/services/transactions/PaymentService.java deleted file mode 100644 index 09fd5919..00000000 --- a/src/main/java/org/folio/services/transactions/PaymentService.java +++ /dev/null @@ -1,73 +0,0 @@ -package org.folio.services.transactions; - -import static org.folio.rest.util.ErrorCodes.UPDATE_PAYMENT_TO_CANCEL_INVOICE; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.folio.rest.core.models.RequestContext; -import org.folio.rest.exception.HttpException; -import org.folio.rest.jaxrs.model.Transaction; -import org.folio.rest.util.HelperUtils; - -import io.vertx.core.Future; - -public class PaymentService implements TransactionTypeManagingStrategy { - private static final Logger log = LogManager.getLogger(); - private final TransactionService transactionService; - - public PaymentService(TransactionService transactionService) { - this.transactionService = transactionService; - } - - @Override - public Future createTransaction(Transaction payment, RequestContext requestContext) { - return Future.succeededFuture() - .map(v -> { - transactionService.validateTransactionType(payment, Transaction.TransactionType.PAYMENT); - HelperUtils.validateAmount(payment.getAmount(), "amount"); - return null; - }) - .compose(v -> transactionService.createTransaction(payment, requestContext)); - } - - @Override - public Future updateTransaction(Transaction payment, RequestContext requestContext) { - log.debug("updateTransaction:: Updating transaction for payment '{}'", payment.getId()); - return Future.succeededFuture() - .map(v -> { - transactionService.validateTransactionType(payment, Transaction.TransactionType.PAYMENT); - if (Boolean.FALSE.equals(payment.getInvoiceCancelled())) { - log.warn("updateTransaction:: payment '{}' invoice is not cancelled", payment.getId()); - throw new HttpException(422, UPDATE_PAYMENT_TO_CANCEL_INVOICE.toError()); - } - return null; - }) - .compose(v -> transactionService.retrieveTransactionById(payment.getId(), requestContext)) - .map(existingTransaction -> { - if (Boolean.TRUE.equals(existingTransaction.getInvoiceCancelled())) { - log.warn("updateTransaction:: Existing transaction '{}' already has invoiceCancelled flag set to true", existingTransaction.getId()); - throw new HttpException(422, UPDATE_PAYMENT_TO_CANCEL_INVOICE.toError()); - } - // compare new transaction with existing one: ignore invoiceCancelled and metadata changes - existingTransaction.setInvoiceCancelled(true); - existingTransaction.setMetadata(payment.getMetadata()); - if (!existingTransaction.equals(payment)) { - log.warn("updateTransaction:: Existing transaction '{}' is not equal to payment '{}'", existingTransaction.getId(), payment.getId()); - throw new HttpException(422, UPDATE_PAYMENT_TO_CANCEL_INVOICE.toError()); - } - return null; - }) - .compose(v -> transactionService.updateTransaction(payment, requestContext)); - } - - @Override - public Future deleteTransaction(Transaction encumbrance, RequestContext requestContext) { - return HelperUtils.unsupportedOperationExceptionFuture(); - } - - @Override - public Transaction.TransactionType getStrategyName() { - return Transaction.TransactionType.PAYMENT; - } - -} diff --git a/src/main/java/org/folio/services/transactions/PendingPaymentService.java b/src/main/java/org/folio/services/transactions/PendingPaymentService.java deleted file mode 100644 index 788e0c1e..00000000 --- a/src/main/java/org/folio/services/transactions/PendingPaymentService.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.folio.services.transactions; - -import org.folio.rest.core.models.RequestContext; -import org.folio.rest.jaxrs.model.Transaction; -import org.folio.rest.util.HelperUtils; - -import io.vertx.core.Future; - -public class PendingPaymentService implements TransactionTypeManagingStrategy { - - private final TransactionService transactionService; - - public PendingPaymentService(TransactionService transactionService) { - this.transactionService = transactionService; - } - - @Override - public Future createTransaction(Transaction pendingPayment, RequestContext requestContext) { - return Future.succeededFuture() - .map(v -> { - transactionService.validateTransactionType(pendingPayment, Transaction.TransactionType.PENDING_PAYMENT); - return null; - }) - .compose(aVoid -> transactionService.createTransaction(pendingPayment, requestContext)); - } - - @Override - public Future updateTransaction(Transaction pendingPayment, RequestContext requestContext) { - return Future.succeededFuture() - .map(v -> { - transactionService.validateTransactionType(pendingPayment, Transaction.TransactionType.PENDING_PAYMENT); - return null; - }) - .compose(aVoid -> transactionService.updateTransaction(pendingPayment, requestContext)); - } - - @Override - public Future deleteTransaction(Transaction encumbrance, RequestContext requestContext) { - return HelperUtils.unsupportedOperationExceptionFuture(); - } - - @Override - public Transaction.TransactionType getStrategyName() { - return Transaction.TransactionType.PENDING_PAYMENT; - } -} diff --git a/src/main/java/org/folio/services/transactions/TransactionApiService.java b/src/main/java/org/folio/services/transactions/TransactionApiService.java new file mode 100644 index 00000000..b331111a --- /dev/null +++ b/src/main/java/org/folio/services/transactions/TransactionApiService.java @@ -0,0 +1,246 @@ +package org.folio.services.transactions; + +import static io.vertx.core.Future.failedFuture; +import static io.vertx.core.Future.succeededFuture; +import static java.lang.Boolean.TRUE; +import static java.util.Collections.singletonList; +import static java.util.stream.Collectors.toMap; +import static one.util.streamex.StreamEx.ofSubLists; +import static org.folio.rest.jaxrs.model.Transaction.TransactionType.ALLOCATION; +import static org.folio.rest.jaxrs.model.Transaction.TransactionType.TRANSFER; +import static org.folio.rest.util.ErrorCodes.ALLOCATION_IDS_MISMATCH; +import static org.folio.rest.util.ErrorCodes.DELETE_CONNECTED_TO_INVOICE; +import static org.folio.rest.util.ErrorCodes.INVALID_TRANSACTION_TYPE; +import static org.folio.rest.util.ErrorCodes.MISSING_FUND_ID; +import static org.folio.rest.util.HelperUtils.collectResultsOnSuccess; +import static org.folio.rest.util.HelperUtils.convertIdsToCqlQuery; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; +import java.util.function.Function; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.folio.rest.core.models.RequestContext; +import org.folio.rest.exception.HttpException; +import org.folio.rest.jaxrs.model.Batch; +import org.folio.rest.jaxrs.model.Encumbrance; +import org.folio.rest.jaxrs.model.Fund; +import org.folio.rest.jaxrs.model.Parameter; +import org.folio.rest.jaxrs.model.Transaction; +import org.folio.rest.jaxrs.model.Transaction.TransactionType; +import org.folio.rest.jaxrs.model.TransactionCollection; + +import io.vertx.core.Future; +import org.folio.services.fund.FundService; + +/** + * This class is only used by the API handlers (TransactionsApi and EncumbranceApi). + * It does not directly use storage (using TransactionService for storage calls). + */ +public class TransactionApiService { + private static final Logger log = LogManager.getLogger(); + private static final int MAX_TRANSACTIONS_PER_QUERY = 15; + + private final TransactionService transactionService; + private final FundService fundService; + + public TransactionApiService(TransactionService transactionService, FundService fundService) { + this.transactionService = transactionService; + this.fundService = fundService; + } + + public Future getTransactionCollectionByQuery(String query, int offset, int limit, + RequestContext requestContext) { + return transactionService.getTransactionCollectionByQuery(query, offset, limit, requestContext); + } + + public Future getTransactionById(String id, RequestContext requestContext) { + return transactionService.getTransactionById(id, requestContext); + } + + public Future processBatch(Batch batch, RequestContext requestContext) { + return checkDeletions(batch, requestContext) + .compose(v -> checkFundAllocations(batch, requestContext)) + .compose(v -> transactionService.processBatch(batch, requestContext)); + } + + public Future createAllocation(Transaction allocation, RequestContext requestContext) { + try { + validateTransactionType(allocation, ALLOCATION); + } catch (Exception ex) { + return failedFuture(ex); + } + if (allocation.getId() == null) { + allocation.setId(UUID.randomUUID().toString()); + } + Batch batch = new Batch().withTransactionsToCreate(singletonList(allocation)); + return processBatch(batch, requestContext) + .map(v -> allocation) + .onSuccess(v -> log.info("Success creating allocation, id={}", allocation.getId())) + .onFailure(t -> log.error("Error creating allocation, id={}", allocation.getId(), t)); + } + + public Future createTransfer(Transaction transfer, RequestContext requestContext) { + try { + validateTransactionType(transfer, TRANSFER); + } catch (Exception ex) { + return failedFuture(ex); + } + if (transfer.getId() == null) { + transfer.setId(UUID.randomUUID().toString()); + } + Batch batch = new Batch().withTransactionsToCreate(singletonList(transfer)); + return processBatch(batch, requestContext) + .map(v -> transfer) + .onSuccess(v -> log.info("Success creating transfer, id={}", transfer.getId())) + .onFailure(t -> log.error("Error creating transfer, id={}", transfer.getId(), t)); + } + + public Future releaseEncumbrance(String id, RequestContext requestContext) { + return getTransactionById(id, requestContext) + .compose(transaction -> releaseEncumbrance(transaction, requestContext)) + .onSuccess(v -> log.info("Success releasing encumbrance, id={}", id)) + .onFailure(t -> log.error("Error releasing encumbrance, id={}", id, t)); + } + + public Future unreleaseEncumbrance(String id, RequestContext requestContext) { + return getTransactionById(id, requestContext) + .compose(transaction -> unreleaseEncumbrance(transaction, requestContext)) + .onSuccess(v -> log.info("Success unreleasing encumbrance, id={}", id)) + .onFailure(t -> log.error("Error unreleasing encumbrance, id={}", id, t)); + } + + + private void validateTransactionType(Transaction transaction, TransactionType transactionType) { + if (transaction.getTransactionType() != transactionType) { + log.warn("validateTransactionType:: Transaction '{}' type mismatch. '{}' expected", transaction.getId(), transactionType); + Parameter parameter = new Parameter().withKey("expected").withValue(transactionType.name()); + throw new HttpException(422, INVALID_TRANSACTION_TYPE.toError().withParameters(Collections.singletonList(parameter))); + } + } + + /** + * Check transaction deletions are allowed. + * Usually it is not allowed to delete an encumbrance connected to an approved invoice. + * To avoid adding a dependency to mod-invoice, we check if there is a related awaitingPayment transaction. + * It is OK to delete an encumbrance connected to a *cancelled* invoice *if* the batch includes a change to the + * matching pending payment to remove the link to the encumbrance. + */ + private Future checkDeletions(Batch batch, RequestContext requestContext) { + List ids = batch.getIdsOfTransactionsToDelete(); + if (ids.isEmpty()) { + return succeededFuture(); + } + return getPendingPaymentsByEncumbranceIds(ids, requestContext) + .map(pendingPayments -> { + if (pendingPayments.isEmpty()) { + return null; + } + ids.forEach(id -> { + Optional existingPP = pendingPayments.stream() + .filter(pp -> id.equals(pp.getAwaitingPayment().getEncumbranceId())).findFirst(); + if (existingPP.isEmpty()) { + return; + } + if (TRUE.equals(existingPP.get().getInvoiceCancelled())) { + Optional matchingPPInBatch = batch.getTransactionsToUpdate().stream() + .filter(pp -> existingPP.get().getId().equals(pp.getId())).findFirst(); + if (matchingPPInBatch.isPresent() && matchingPPInBatch.get().getAwaitingPayment().getEncumbranceId() == null) { + return; + } + } + log.warn("validateDeletion:: Tried to delete transactions but one is connected to an invoice, id={}", id); + throw new HttpException(422, DELETE_CONNECTED_TO_INVOICE.toError()); + }); + return null; + }); + } + + private Future> getPendingPaymentsByEncumbranceIds(List encumbranceIds, + RequestContext requestContext) { + return collectResultsOnSuccess(ofSubLists(new ArrayList<>(encumbranceIds), MAX_TRANSACTIONS_PER_QUERY) + .map(ids -> getPendingPaymentsByEncumbranceIdsChunk(ids, requestContext)) + .toList()) + .map(lists -> lists.stream().flatMap(Collection::stream).toList()); + } + + private Future> getPendingPaymentsByEncumbranceIdsChunk(List encumbranceIds, + RequestContext requestContext) { + String query = convertIdsToCqlQuery(encumbranceIds, "awaitingPayment.encumbranceId", "==", " OR "); + return transactionService.getAllTransactionsByQuery(query, requestContext); + } + + private Future checkFundAllocations(Batch batch, RequestContext requestContext) { + List transactionsToCheck = batch.getTransactionsToCreate().stream() + .filter(t -> (t.getTransactionType() == ALLOCATION && Objects.isNull(t.getFromFundId()) == Objects.isNull(t.getToFundId())) || + t.getTransactionType() == TRANSFER) + .toList(); + if (transactionsToCheck.isEmpty()) { + return succeededFuture(); + } + for (Transaction t : transactionsToCheck) { + if (!(Objects.nonNull(t.getFromFundId()) && Objects.nonNull(t.getToFundId()))) { + log.warn("checkFundsAllocatedIds:: fundId is missing for transaction: {}", t.getId()); + return failedFuture(new HttpException(422, MISSING_FUND_ID)); + } + } + List fundIds = transactionsToCheck.stream() + .map(t -> List.of(t.getFromFundId(), t.getToFundId())) + .flatMap(Collection::stream) + .filter(Objects::nonNull) + .distinct() + .toList(); + return fundService.getFundsByIds(fundIds, requestContext) + .map(funds -> { + Map fundMap = funds.stream().collect(toMap(Fund::getId, Function.identity())); + for (Transaction t : transactionsToCheck) { + if (!isAllocationAllowed(fundMap.get(t.getFromFundId()), fundMap.get(t.getToFundId()), t)) { + log.warn("checkFundsAllocatedIds:: Allocation ids mismatch for transaction: {}", t.getId()); + throw new HttpException(422, ALLOCATION_IDS_MISMATCH); + } + } + return null; + }) + .onSuccess(v -> log.debug("checkFundAllocations:: Funds checked successfully for transactions")) + .mapEmpty(); + } + + private boolean isAllocationAllowed(Fund fromFund, Fund toFund, Transaction transaction) { + return (fromFund.getAllocatedToIds().isEmpty() || fromFund.getAllocatedToIds().contains(transaction.getToFundId())) && + (toFund.getAllocatedFromIds().isEmpty() || toFund.getAllocatedFromIds().contains(transaction.getFromFundId())); + } + + private Future releaseEncumbrance(Transaction transaction, RequestContext requestContext) { + try { + validateTransactionType(transaction, TransactionType.ENCUMBRANCE); + } catch (Exception ex) { + return failedFuture(ex); + } + if (transaction.getEncumbrance().getStatus() == Encumbrance.Status.RELEASED) { + return succeededFuture(null); + } + transaction.getEncumbrance().setStatus(Encumbrance.Status.RELEASED); + return transactionService.updateTransaction(transaction, requestContext); + } + + private Future unreleaseEncumbrance(Transaction transaction, RequestContext requestContext) { + try { + validateTransactionType(transaction, TransactionType.ENCUMBRANCE); + } catch (Exception ex) { + return failedFuture(ex); + } + if (transaction.getEncumbrance().getStatus() != Encumbrance.Status.RELEASED) { + return succeededFuture(null); + } + transaction.getEncumbrance().setStatus(Encumbrance.Status.UNRELEASED); + return transactionService.updateTransaction(transaction, requestContext); + } + +} diff --git a/src/main/java/org/folio/services/transactions/TransactionManagingService.java b/src/main/java/org/folio/services/transactions/TransactionManagingService.java deleted file mode 100644 index d724d857..00000000 --- a/src/main/java/org/folio/services/transactions/TransactionManagingService.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.folio.services.transactions; - -import org.folio.rest.core.models.RequestContext; -import org.folio.rest.jaxrs.model.Transaction; - -import io.vertx.core.Future; - -public interface TransactionManagingService { - Future createTransaction(Transaction transaction, RequestContext requestContext); - Future updateTransaction(Transaction transaction, RequestContext requestContext); - Future deleteTransaction(Transaction transaction, RequestContext requestContext); -} diff --git a/src/main/java/org/folio/services/transactions/TransactionRestrictService.java b/src/main/java/org/folio/services/transactions/TransactionRestrictService.java deleted file mode 100644 index da736cdb..00000000 --- a/src/main/java/org/folio/services/transactions/TransactionRestrictService.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.folio.services.transactions; - -import static io.vertx.core.Future.failedFuture; -import static io.vertx.core.Future.succeededFuture; -import static org.folio.rest.util.ErrorCodes.ALLOCATION_IDS_MISMATCH; -import static org.folio.rest.util.ErrorCodes.MISSING_FUND_ID; - -import java.util.Objects; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.folio.rest.core.models.RequestContext; -import org.folio.rest.exception.HttpException; -import org.folio.rest.jaxrs.model.Fund; -import org.folio.rest.jaxrs.model.Transaction; -import org.folio.services.fund.FundService; - -import io.vertx.core.CompositeFuture; -import io.vertx.core.Future; - -public class TransactionRestrictService { - - private static final Logger log = LogManager.getLogger(); - private final FundService fundService; - - public TransactionRestrictService(FundService fundService) { - this.fundService = fundService; - } - - public Future checkAllocation(Transaction transaction, RequestContext requestContext) { - if (Objects.isNull(transaction.getFromFundId()) ^ Objects.isNull(transaction.getToFundId())) { - return succeededFuture(); - } else { - return checkFundsAllocatedIds(transaction, requestContext); - } - } - - public Future checkTransfer(Transaction transaction, RequestContext requestContext) { - return checkFundsAllocatedIds(transaction, requestContext); - } - - private Future checkFundsAllocatedIds(Transaction transaction, RequestContext requestContext) { - log.debug("checkFundsAllocatedIds:: Checking funds allocated ids for transaction '{}'", transaction.getId()); - if (Objects.nonNull(transaction.getFromFundId()) && Objects.nonNull(transaction.getToFundId())) { - var fromFund = fundService.getFundById(transaction.getFromFundId(), requestContext); - var toFund = fundService.getFundById(transaction.getToFundId(), requestContext); - return CompositeFuture.join(toFund, fromFund) - .map(cf -> isAllocationAllowed(fromFund.result(), toFund.result(), transaction)) - .compose(isAllocationAllowed -> { - if (Boolean.TRUE.equals(isAllocationAllowed)) { - log.info("checkFundsAllocatedIds: Allocation is allowed for transaction: {}", transaction.getId()); - return succeededFuture(); - } else { - log.warn("checkFundsAllocatedIds:: Allocation ids is mismatch in transaction: {}", transaction.getId()); - return failedFuture(new HttpException(422, ALLOCATION_IDS_MISMATCH)); - } - }); - } else { - log.warn("checkFundsAllocatedIds:: fundId is missing for transaction: {}", transaction.getId()); - return failedFuture(new HttpException(422, MISSING_FUND_ID)); - } -} - - private boolean isAllocationAllowed(Fund fromFund, Fund toFund, Transaction transaction) { - return (fromFund.getAllocatedToIds().isEmpty() || fromFund.getAllocatedToIds().contains(transaction.getToFundId())) && - (toFund.getAllocatedFromIds().isEmpty() || toFund.getAllocatedFromIds().contains(transaction.getFromFundId())); - } - -} diff --git a/src/main/java/org/folio/services/transactions/TransactionService.java b/src/main/java/org/folio/services/transactions/TransactionService.java index 2aeebfae..53dd0e33 100644 --- a/src/main/java/org/folio/services/transactions/TransactionService.java +++ b/src/main/java/org/folio/services/transactions/TransactionService.java @@ -1,15 +1,172 @@ package org.folio.services.transactions; +import static java.util.Collections.singletonList; +import static one.util.streamex.StreamEx.ofSubLists; +import static org.folio.rest.RestConstants.MAX_IDS_FOR_GET_RQ; +import static org.folio.rest.util.HelperUtils.collectResultsOnSuccess; +import static org.folio.rest.util.HelperUtils.convertIdsToCqlQuery; +import static org.folio.rest.util.ResourcePathResolver.BATCH_TRANSACTIONS_STORAGE; +import static org.folio.rest.util.ResourcePathResolver.TRANSACTIONS; +import static org.folio.rest.util.ResourcePathResolver.resourceByIdPath; +import static org.folio.rest.util.ResourcePathResolver.resourcesPath; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.UUID; +import java.util.function.Function; + +import io.vertx.core.json.JsonObject; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.folio.rest.core.RestClient; import org.folio.rest.core.models.RequestContext; +import org.folio.rest.core.models.RequestEntry; +import org.folio.rest.jaxrs.model.Batch; +import org.folio.rest.jaxrs.model.Budget; +import org.folio.rest.jaxrs.model.BudgetExpenseClass; +import org.folio.rest.jaxrs.model.SharedBudget; import org.folio.rest.jaxrs.model.Transaction; +import org.folio.rest.jaxrs.model.Transaction.TransactionType; import org.folio.rest.jaxrs.model.TransactionCollection; import io.vertx.core.Future; +import one.util.streamex.StreamEx; +import org.folio.services.fiscalyear.FiscalYearService; + +public class TransactionService { + private static final Logger log = LogManager.getLogger(); + private static final int MAX_FUND_PER_QUERY = 5; + + private final RestClient restClient; + private final FiscalYearService fiscalYearService; + + public TransactionService(RestClient restClient, FiscalYearService fiscalYearService) { + this.restClient = restClient; + this.fiscalYearService = fiscalYearService; + } + + public Future getTransactionCollectionByQuery(String query, int offset, int limit, + RequestContext requestContext) { + var requestEntry = new RequestEntry(resourcesPath(TRANSACTIONS)) + .withOffset(offset) + .withLimit(limit) + .withQuery(query); + return restClient.get(requestEntry.buildEndpoint(), TransactionCollection.class, requestContext); + } + + public Future> getAllTransactionsByQuery(String query, RequestContext requestContext) { + return getTransactionCollectionByQuery(query, 0, Integer.MAX_VALUE, requestContext) + .map(TransactionCollection::getTransactions); + } + + public Future getTransactionById(String id, RequestContext requestContext) { + return restClient.get(resourceByIdPath(TRANSACTIONS, id), Transaction.class, requestContext); + } + + public Future processBatch(Batch batch, RequestContext requestContext) { + return restClient.postEmptyResponse(resourcesPath(BATCH_TRANSACTIONS_STORAGE), batch, requestContext) + .onSuccess(v -> log.info("Batch transaction successful")) + .onFailure(t -> log.error("Batch transaction failed, batch={}", JsonObject.mapFrom(batch).encodePrettily(), t)); + } + + public Future updateTransaction(Transaction transaction, RequestContext requestContext) { + // This will need to change to use patch when it is available - see MODFIN-351 + Batch batch = new Batch().withTransactionsToUpdate(singletonList(transaction)); + return processBatch(batch, requestContext); + } + + public Future> getTransactionsFromFunds(List fundIds, String fiscalYearId, + List trTypes, RequestContext requestContext) { + return getTransactionsFromOrToFunds(fundIds, fiscalYearId, trTypes, "from", requestContext); + } + + public Future> getTransactionsToFunds(List fundIds, String fiscalYearId, + List trTypes, RequestContext requestContext) { + return getTransactionsFromOrToFunds(fundIds, fiscalYearId, trTypes, "to", requestContext); + } + + public Future> getBudgetTransactions(Budget budget, RequestContext requestContext) { + String query = String.format("(fromFundId==%s OR toFundId==%s) AND fiscalYearId==%s", budget.getFundId(), + budget.getFundId(), budget.getFiscalYearId()); + return getAllTransactionsByQuery(query, requestContext); + } + + public Future> getBudgetTransactionsWithExpenseClasses(List budgetExpenseClasses, + SharedBudget budget, RequestContext requestContext) { + List ids = budgetExpenseClasses.stream() + .map(BudgetExpenseClass::getExpenseClassId) + .toList(); + String query = String.format("(fromFundId==%s OR toFundId==%s) AND fiscalYearId==%s AND %s", budget.getFundId(), + budget.getFundId(), budget.getFiscalYearId(), convertIdsToCqlQuery(ids, "expenseClassId", true)); + return getAllTransactionsByQuery(query, requestContext); + } + + public Future> getTransactionsByFundIds(List fundIds, String fiscalYearId, + RequestContext requestContext) { + List>> futures = StreamEx + .ofSubLists(fundIds, MAX_IDS_FOR_GET_RQ) + .map(ids -> getAllTransactionsByQuery(buildGetTransactionsByFundIdsQuery(fiscalYearId, ids), requestContext)) + .toList(); + + return collectResultsOnSuccess(futures) + .map(listList -> listList.stream() + .flatMap(Collection::stream) + .toList() + ); + } + + public Future createTransaction(Transaction transaction, RequestContext requestContext) { + Batch batch = new Batch().withTransactionsToCreate(singletonList(transaction)); + return processBatch(batch, requestContext); + } + + public Future createAllocationTransaction(Budget budget, RequestContext requestContext) { + Transaction transaction = new Transaction() + .withTransactionType(Transaction.TransactionType.ALLOCATION) + .withId(UUID.randomUUID().toString()) + .withAmount(budget.getAllocated()) + .withFiscalYearId(budget.getFiscalYearId()) + .withToFundId(budget.getFundId()) + .withSource(Transaction.Source.USER); + return fiscalYearService.getFiscalYearById(budget.getFiscalYearId(), requestContext) + .compose(fiscalYear -> createTransaction(transaction.withCurrency(fiscalYear.getCurrency()), requestContext)); + } + + + private Future> getTransactionsFromOrToFunds(List fundIds, String fiscalYearId, + List trTypes, String direction, RequestContext requestContext) { + return collectResultsOnSuccess(ofSubLists(new ArrayList<>(fundIds), MAX_FUND_PER_QUERY) + .map(ids -> getTransactionsByFundChunk(ids, fiscalYearId, trTypes, direction, requestContext) + .map(transactions -> filterFundIdsByAllocationDirection(fundIds, transactions, direction))) + .toList()) + .map(lists -> lists.stream().flatMap(Collection::stream).toList()); + } + + private Future> getTransactionsByFundChunk(List fundIds, String fiscalYearId, + List trTypes, String direction, RequestContext requestContext) { + String fundIdField = "from".equals(direction) ? "fromFundId" : "toFundId"; + String fundQuery = convertIdsToCqlQuery(fundIds, fundIdField, "==", " OR "); + List trTypeValues = trTypes.stream().map(TransactionType::value).toList(); + String trTypeQuery = convertIdsToCqlQuery(trTypeValues, "transactionType", "==", " OR "); + String query = String.format("(fiscalYearId==%s AND %s) AND %s", fiscalYearId, trTypeQuery, fundQuery); + return getAllTransactionsByQuery(query, requestContext); + } + + private List filterFundIdsByAllocationDirection(List fundIds, List transactions, + String direction) { + // Note that here getToFundId() is used when direction is from (a negation is used afterward) + Function getFundId = "from".equals(direction) ? Transaction::getToFundId : Transaction::getFromFundId; + return transactions.stream() + .filter(transaction -> !fundIds.contains(getFundId.apply(transaction))) + .toList(); + } -public interface TransactionService extends TransactionManagingService { + private String buildGetTransactionsByFundIdsQuery(String fiscalYearId, List fundIds) { + return String.format("fiscalYearId==%s AND (%s OR %s)", + fiscalYearId, + convertIdsToCqlQuery(fundIds, "fromFundId", true), + convertIdsToCqlQuery(fundIds, "toFundId", true)); + } - Future retrieveTransactions(String query, int offset, int limit, RequestContext requestContext); - Future retrieveTransactionById(String id, RequestContext requestContext); - void validateTransactionType(Transaction transaction, Transaction.TransactionType transactionType); - Future isConnectedToInvoice(String transactionId, RequestContext requestContext); } diff --git a/src/main/java/org/folio/services/transactions/TransactionStrategyFactory.java b/src/main/java/org/folio/services/transactions/TransactionStrategyFactory.java deleted file mode 100644 index 1a7f4d5a..00000000 --- a/src/main/java/org/folio/services/transactions/TransactionStrategyFactory.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.folio.services.transactions; - -import java.util.EnumMap; -import java.util.Map; -import java.util.Set; - -import org.folio.rest.core.models.RequestContext; -import org.folio.rest.jaxrs.model.Transaction; - -import io.vertx.core.Future; - -public class TransactionStrategyFactory { - - private Map strategies; - - public TransactionStrategyFactory(Set strategySet) { - createStrategy(strategySet); - } - - public TransactionTypeManagingStrategy findStrategy(Transaction.TransactionType transactionType) { - return strategies.get(transactionType); - } - - private void createStrategy(Set strategySet) { - strategies = new EnumMap<>(Transaction.TransactionType.class); - strategySet.forEach( - strategy -> strategies.put(strategy.getStrategyName(), strategy)); - } - - public Future createTransaction(Transaction.TransactionType type, Transaction transaction, RequestContext requestContext) { - return findStrategy(type).createTransaction(transaction, requestContext); - } - - public Future updateTransaction(Transaction.TransactionType type, Transaction transaction, RequestContext requestContext) { - return findStrategy(type).updateTransaction(transaction, requestContext); - } - - public Future deleteTransaction(Transaction.TransactionType type, Transaction transaction, RequestContext requestContext) { - return findStrategy(type).deleteTransaction(transaction, requestContext); - } - -} diff --git a/src/main/java/org/folio/services/transactions/TransactionTypeManagingStrategy.java b/src/main/java/org/folio/services/transactions/TransactionTypeManagingStrategy.java deleted file mode 100644 index 92f9f902..00000000 --- a/src/main/java/org/folio/services/transactions/TransactionTypeManagingStrategy.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.folio.services.transactions; - -import org.folio.rest.jaxrs.model.Transaction; - -public interface TransactionTypeManagingStrategy extends TransactionManagingService { - Transaction.TransactionType getStrategyName(); -} diff --git a/src/main/java/org/folio/services/transactions/TransferService.java b/src/main/java/org/folio/services/transactions/TransferService.java deleted file mode 100644 index 9d172d96..00000000 --- a/src/main/java/org/folio/services/transactions/TransferService.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.folio.services.transactions; - -import org.folio.rest.core.models.RequestContext; -import org.folio.rest.jaxrs.model.Transaction; -import org.folio.rest.util.HelperUtils; - -import io.vertx.core.Future; - -public class TransferService implements TransactionTypeManagingStrategy { - - private final TransactionRestrictService transactionRestrictService; - private final TransactionService transactionService; - - public TransferService(BaseTransactionService transactionService, TransactionRestrictService transactionRestrictService) { - this.transactionService = transactionService; - this.transactionRestrictService = transactionRestrictService; - } - - @Override - public Future createTransaction(Transaction transfer, RequestContext requestContext) { - return Future.succeededFuture() - .map(v -> { - transactionService.validateTransactionType(transfer, Transaction.TransactionType.TRANSFER); - return null; - }) - .compose(v -> transactionRestrictService.checkTransfer(transfer, requestContext)) - .compose(v -> transactionService.createTransaction(transfer, requestContext)); - } - - @Override - public Future updateTransaction(Transaction transaction, RequestContext requestContext) { - return HelperUtils.unsupportedOperationExceptionFuture(); - } - - @Override - public Future deleteTransaction(Transaction encumbrance, RequestContext requestContext) { - return HelperUtils.unsupportedOperationExceptionFuture(); - } - - @Override - public Transaction.TransactionType getStrategyName() { - return Transaction.TransactionType.TRANSFER; - } -} diff --git a/src/test/java/org/folio/ApiTestSuite.java b/src/test/java/org/folio/ApiTestSuite.java index d21b9726..30a36f30 100644 --- a/src/test/java/org/folio/ApiTestSuite.java +++ b/src/test/java/org/folio/ApiTestSuite.java @@ -25,13 +25,14 @@ import org.folio.rest.impl.LedgersApiTest; import org.folio.rest.impl.TransactionApiTest; import org.folio.rest.util.HelperUtilsTest; -import org.folio.services.CommonTransactionServiceTest; +import org.folio.services.TransactionServiceTest; import org.folio.services.ExpenseClassServiceTest; import org.folio.services.budget.BudgetExpenseClassServiceTest; import org.folio.services.budget.BudgetExpenseClassTotalsServiceTest; import org.folio.services.budget.BudgetServiceTest; import org.folio.services.budget.CreateBudgetServiceTest; import org.folio.services.budget.RecalculateBudgetServiceTest; +import org.folio.services.fiscalyear.FiscalYearApiServiceTest; import org.folio.services.fiscalyear.FiscalYearServiceTest; import org.folio.services.fund.FundCodeExpenseClassesServiceTest; import org.folio.services.fund.FundDetailsServiceTest; @@ -50,7 +51,7 @@ import org.folio.services.protection.AcqUnitMembershipsServiceTest; import org.folio.services.protection.AcqUnitsServiceTest; import org.folio.services.protection.ProtectionServiceTest; -import org.folio.services.transactions.BatchTransactionServiceTest; +import org.folio.services.transactions.TransactionApiServiceTest; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Nested; @@ -142,7 +143,11 @@ class ExpenseClassServiceTestNested extends ExpenseClassServiceTest { } @Nested - class CommonTransactionServiceTestNested extends CommonTransactionServiceTest { + class TransactionServiceTestNested extends TransactionServiceTest { + } + + @Nested + class TransactionApiServiceTestNested extends TransactionApiServiceTest { } @Nested @@ -205,6 +210,10 @@ class CreateBudgetServiceTestNested extends CreateBudgetServiceTest { class FundServiceTestNested extends FundServiceTest { } + @Nested + class FiscalYearApiServiceTestNested extends FiscalYearApiServiceTest { + } + @Nested class FiscalYearServiceTestNested extends FiscalYearServiceTest { } @@ -235,7 +244,4 @@ class GroupServiceNested extends GroupServiceTest {} @Nested class RecalculateBudgetServiceTestNested extends RecalculateBudgetServiceTest {} - @Nested - class BatchTransactionServiceTestNested extends BatchTransactionServiceTest {} - } diff --git a/src/test/java/org/folio/rest/impl/EntitiesCrudBasicsTest.java b/src/test/java/org/folio/rest/impl/EntitiesCrudBasicsTest.java index bf321675..5409013f 100644 --- a/src/test/java/org/folio/rest/impl/EntitiesCrudBasicsTest.java +++ b/src/test/java/org/folio/rest/impl/EntitiesCrudBasicsTest.java @@ -8,7 +8,6 @@ import static javax.ws.rs.core.Response.Status.NO_CONTENT; import static javax.ws.rs.core.Response.Status.OK; import static org.folio.rest.util.HelperUtils.ID; -import static org.folio.rest.util.MockServer.addMockEntry; import static org.folio.rest.util.MockServer.getCollectionRecords; import static org.folio.rest.util.MockServer.getRecordById; import static org.folio.rest.util.TestConfig.clearServiceInteractions; @@ -25,22 +24,15 @@ import static org.folio.rest.util.TestEntities.FUND; import static org.folio.rest.util.TestEntities.GROUP; import static org.folio.rest.util.TestEntities.GROUP_FUND_FISCAL_YEAR; -import static org.folio.rest.util.TestEntities.INVOICE_TRANSACTION_SUMMARY; import static org.folio.rest.util.TestEntities.LEDGER; import static org.folio.rest.util.TestEntities.LEDGER_ROLLOVER; import static org.folio.rest.util.TestEntities.LEDGER_ROLLOVER_BUDGETS; import static org.folio.rest.util.TestEntities.LEDGER_ROLLOVER_ERRORS; import static org.folio.rest.util.TestEntities.LEDGER_ROLLOVER_LOGS; import static org.folio.rest.util.TestEntities.LEDGER_ROLLOVER_PROGRESS; -import static org.folio.rest.util.TestEntities.ORDER_TRANSACTION_SUMMARY; import static org.folio.rest.util.TestEntities.TRANSACTIONS; import static org.folio.rest.util.TestEntities.TRANSACTIONS_ALLOCATION; -import static org.folio.rest.util.TestEntities.TRANSACTIONS_CREDIT; -import static org.folio.rest.util.TestEntities.TRANSACTIONS_ENCUMBRANCE; -import static org.folio.rest.util.TestEntities.TRANSACTIONS_PAYMENT; -import static org.folio.rest.util.TestEntities.TRANSACTIONS_PENDING_PAYMENT; import static org.folio.rest.util.TestEntities.TRANSACTIONS_TRANSFER; -import static org.folio.rest.util.TestUtils.getMockData; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasSize; @@ -53,7 +45,6 @@ import java.util.Arrays; import java.util.List; import java.util.Optional; -import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; import java.util.regex.Matcher; @@ -96,9 +87,7 @@ public class EntitiesCrudBasicsTest { private static final Logger logger = LogManager.getLogger(EntitiesCrudBasicsTest.class); - private static final List transactionEntities = Arrays.asList(TRANSACTIONS_ALLOCATION, TRANSACTIONS_ENCUMBRANCE - , TRANSACTIONS_TRANSFER, TRANSACTIONS_PAYMENT, TRANSACTIONS_PENDING_PAYMENT - , TRANSACTIONS_CREDIT, ORDER_TRANSACTION_SUMMARY, INVOICE_TRANSACTION_SUMMARY); + private static final List transactionEntities = Arrays.asList(TRANSACTIONS_ALLOCATION, TRANSACTIONS_TRANSFER); private static boolean runningOnOwn; @@ -120,7 +109,7 @@ static Stream getTestEntities() { } /** - * Test entities except for TRANSACTIONS_ALLOCATION, TRANSACTIONS_TRANSFER, TRANSACTIONS_ENCUMBRANCE + * Test entities except for TRANSACTIONS_ALLOCATION, TRANSACTIONS_TRANSFER * * @return stream of test entities */ @@ -143,7 +132,10 @@ static Stream getTestEntitiesWithGetByIdEndpoint() { } static Stream getTestEntitiesWithPostEndpoint() { - return getTestEntities().filter(e -> !e.equals(TRANSACTIONS)); + return getTestEntities() + .filter(e -> !e.equals(TRANSACTIONS)) + .filter(e -> !e.equals(TRANSACTIONS_ALLOCATION)) + .filter(e -> !e.equals(TRANSACTIONS_TRANSFER)); } /** @@ -152,8 +144,8 @@ static Stream getTestEntitiesWithPostEndpoint() { * @return stream of test entities */ static Stream getTestEntitiesWithPutEndpoint() { - return Stream.concat(getTestEntitiesWithGetByIdEndpoint() - .filter(e -> !e.equals(TRANSACTIONS)), Stream.of(TRANSACTIONS_PENDING_PAYMENT)); + return getTestEntitiesWithGetByIdEndpoint() + .filter(e -> !e.equals(TRANSACTIONS)); } /** @@ -166,13 +158,12 @@ static Stream getTestEntitiesWithDeleteEndpoint() { } /** - * Test entities only for TRANSACTIONS_ALLOCATION, TRANSACTIONS_TRANSFER, TRANSACTIONS_ENCUMBRANCE + * Test entities only for TRANSACTIONS_ALLOCATION, TRANSACTIONS_TRANSFER * * @return stream of test entities */ static Stream getTestEntitiesForOnlyTransactionTypes() { - return transactionEntities.stream().filter(e -> !e.equals(ORDER_TRANSACTION_SUMMARY) - && !e.equals(INVOICE_TRANSACTION_SUMMARY)); + return transactionEntities.stream(); } @BeforeAll @@ -276,10 +267,6 @@ void testGetRecordByIdNotFound(TestEntities testEntity) { @MethodSource("getTestEntitiesWithPostEndpoint") void testPostRecord(TestEntities testEntity) throws IOException { logger.info("=== Test create {} record ===", testEntity.name()); - if (testEntity.equals(TRANSACTIONS_ALLOCATION) || testEntity.equals(TRANSACTIONS_TRANSFER)) { - addMockEntry(FUND.name(), new JsonObject(getMockData("mockdata/funds/HIST.json"))); - addMockEntry(FUND.name(), new JsonObject(getMockData("mockdata/funds/CANHIST.json"))); - } JsonObject record = testEntity.getMockObject(); RestTestUtils.verifyPostResponse(testEntity.getEndpoint(), record, APPLICATION_JSON, CREATED.getStatusCode()); @@ -308,10 +295,6 @@ record = JsonObject.mapFrom(t); @MethodSource("getTestEntitiesWithPostEndpoint") void testPostRecordServerError(TestEntities testEntity) throws IOException { logger.info("=== Test create {} record - Internal Server Error ===", testEntity.name()); - if (testEntity.equals(TRANSACTIONS_ALLOCATION) || testEntity.equals(TRANSACTIONS_TRANSFER)) { - addMockEntry(FUND.name(), new JsonObject(getMockData("mockdata/funds/HIST.json"))); - addMockEntry(FUND.name(), new JsonObject(getMockData("mockdata/funds/CANHIST.json"))); - } Headers headers = RestTestUtils.prepareHeaders(TestConfig.X_OKAPI_URL, ERROR_X_OKAPI_TENANT); JsonObject record = testEntity.getMockObject(); @@ -396,27 +379,6 @@ void testDeleteRecordNotFound(TestEntities testEntity) { .as(Errors.class); } - @ParameterizedTest - @EnumSource(value = TestEntities.class, names = {"ORDER_TRANSACTION_SUMMARY", "INVOICE_TRANSACTION_SUMMARY"}) - void testPostRecordMinimumValidation(TestEntities testEntity) { - logger.info("=== Test create {} record with less then minimum validation fails===", testEntity.name()); - - JsonObject record = testEntity.getMockObject(); - record.put(testEntity.getUpdatedFieldName(), testEntity.getUpdatedFieldValue()); - RestTestUtils.verifyPostResponse(testEntity.getEndpoint(), record, APPLICATION_JSON, 422); - } - - @ParameterizedTest - @EnumSource(value = TestEntities.class, names = {"ORDER_TRANSACTION_SUMMARY", "INVOICE_TRANSACTION_SUMMARY"}) - void testPutRecordMinimumValidation(TestEntities testEntity) { - logger.info("=== Test create {} record with less then minimum validation fails===", testEntity.name()); - - JsonObject record = testEntity.getMockObject(); - record.put(testEntity.getUpdatedFieldName(), 4); - RestTestUtils.verifyPut(testEntity.getEndpointWithId(UUID.randomUUID().toString()), record, "", 422); - RestTestUtils.verifyPut(testEntity.getEndpointWithDefaultId(), record, "", 204); - } - @ParameterizedTest @EnumSource(value = TestEntities.class, names = {"GROUP"}) void testPostGroupWhenJsonErrorComeFromStorage(TestEntities testEntity) { diff --git a/src/test/java/org/folio/rest/impl/TransactionApiTest.java b/src/test/java/org/folio/rest/impl/TransactionApiTest.java index 03640449..5fdfd169 100644 --- a/src/test/java/org/folio/rest/impl/TransactionApiTest.java +++ b/src/test/java/org/folio/rest/impl/TransactionApiTest.java @@ -2,12 +2,7 @@ import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static org.folio.rest.jaxrs.model.Transaction.TransactionType.ALLOCATION; -import static org.folio.rest.jaxrs.model.Transaction.TransactionType.CREDIT; -import static org.folio.rest.jaxrs.model.Transaction.TransactionType.ENCUMBRANCE; -import static org.folio.rest.jaxrs.model.Transaction.TransactionType.PAYMENT; import static org.folio.rest.jaxrs.model.Transaction.TransactionType.TRANSFER; -import static org.folio.rest.util.ErrorCodes.NEGATIVE_VALUE; -import static org.folio.rest.util.ErrorCodes.TRANSACTION_NOT_RELEASED; import static org.folio.rest.util.MockServer.addMockEntry; import static org.folio.rest.util.ResourcePathResolver.BATCH_TRANSACTIONS; import static org.folio.rest.util.ResourcePathResolver.resourcesPath; @@ -15,13 +10,8 @@ import static org.folio.rest.util.TestConfig.initSpringContext; import static org.folio.rest.util.TestConfig.isVerticleNotDeployed; import static org.folio.rest.util.TestEntities.FUND; -import static org.folio.rest.util.TestEntities.TRANSACTIONS; import static org.folio.rest.util.TestUtils.getMockData; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.hasSize; -import static org.junit.jupiter.api.Assertions.assertEquals; -import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -29,8 +19,6 @@ import org.apache.logging.log4j.Logger; import org.folio.ApiTestSuite; import org.folio.config.ApplicationConfig; -import org.folio.rest.jaxrs.model.Encumbrance; -import org.folio.rest.jaxrs.model.Errors; import org.folio.rest.jaxrs.model.Transaction; import org.folio.rest.util.RestTestUtils; import org.folio.rest.util.TestEntities; @@ -52,7 +40,6 @@ public class TransactionApiTest { private static final String LATHIST_ID = "e6d7e91a-4dbc-4a70-9b38-e000d2fbdc79"; private static final String ASIAHIST_ID = "55f48dc6-efa7-4cfe-bc7c-4786efe493e3"; - public static final String DELETE_TRANSACTION_ID = UUID.randomUUID().toString(); public static final String DELETE_CONNECTED_TRANSACTION_ID = "ac857ef5-4e21-4929-8b97-1a4ae06add16"; @BeforeAll @@ -76,28 +63,6 @@ static void afterAll() { } } - @Test - void shouldReturnResponseWithErrorWhenPostPaymentWithNegativeAmount() { - - Transaction transaction = TestEntities.TRANSACTIONS_PAYMENT.getMockObject().mapTo(Transaction.class); - transaction.setAmount(-1d); - Errors errors = RestTestUtils.verifyPostResponse(TestEntities.TRANSACTIONS_PAYMENT.getEndpoint(), JsonObject.mapFrom(transaction), APPLICATION_JSON, 422).as(Errors.class); - - assertThat(errors.getErrors(), hasSize(1)); - assertEquals(NEGATIVE_VALUE.toError().getCode(), errors.getErrors().get(0).getCode()); - } - - @Test - void shouldReturnResponseWithErrorWhenPostCreditWithNegativeAmount() { - - Transaction transaction = TestEntities.TRANSACTIONS_CREDIT.getMockObject().mapTo(Transaction.class); - transaction.setAmount(-1d); - Errors errors = RestTestUtils.verifyPostResponse(TestEntities.TRANSACTIONS_CREDIT.getEndpoint(), JsonObject.mapFrom(transaction), APPLICATION_JSON, 422).as(Errors.class); - - assertThat(errors.getErrors(), hasSize(1)); - assertEquals(NEGATIVE_VALUE.toError().getCode(), errors.getErrors().get(0).getCode()); - } - @Test void testTransferAndAllocationWithMatchingAllocatedIds() throws Exception { logger.info("=== Test transfer and allocation toFund.allocatedFromIds matches fromFund.allocatedToIds) - Success ==="); @@ -222,163 +187,6 @@ void testAllocationMissingBothFundIds() { RestTestUtils.verifyPostResponse(TestEntities.TRANSACTIONS_ALLOCATION.getEndpoint(), JsonObject.mapFrom(transaction), APPLICATION_JSON, 422); } - @Test - void testUpdateEncumbrance() { - logger.info("=== Test update encumbrance - Success ==="); - String id = UUID.randomUUID().toString(); - Transaction transaction = createTransaction(ENCUMBRANCE); - transaction.setId(id); - RestTestUtils.verifyPut(TestEntities.TRANSACTIONS_ENCUMBRANCE.getEndpointWithId(id), JsonObject.mapFrom(transaction), "", 204); - } - - @Test - void testUpdateEncumbranceIdsMismatch() { - logger.info("=== Test update encumbrance with ids mismatch - Unprocessable entity ==="); - String id = UUID.randomUUID().toString(); - Transaction transaction = createTransaction(ENCUMBRANCE); - transaction.setId(UUID.randomUUID().toString()); - RestTestUtils.verifyPut(TestEntities.TRANSACTIONS_ENCUMBRANCE.getEndpointWithId(id), JsonObject.mapFrom(transaction), APPLICATION_JSON, 422); - } - - @Test - void testUpdateNonEncumbranceTransaction() { - logger.info("=== Test update non-encumbrance transaction - Unprocessable entity ==="); - String id = UUID.randomUUID().toString(); - Transaction transaction = createTransaction(PAYMENT); - transaction.setId(id); - RestTestUtils.verifyPut(TestEntities.TRANSACTIONS_ENCUMBRANCE.getEndpointWithId(id), JsonObject.mapFrom(transaction), APPLICATION_JSON, 422); - } - - @Test - void testDeleteEncumbrance() { - logger.info("=== Test delete encumbrance - Success ==="); - String id = DELETE_TRANSACTION_ID; - Transaction transaction = createTransaction(ENCUMBRANCE) - .withEncumbrance(new Encumbrance().withStatus(Encumbrance.Status.RELEASED)); - transaction.setId(id); - addMockEntry(TRANSACTIONS.name(), JsonObject.mapFrom(transaction)); - RestTestUtils.verifyDeleteResponse(TestEntities.TRANSACTIONS_ENCUMBRANCE.getEndpointWithId(id), "", 204); - } - - @Test - void testDeleteEncumbranceConnectedToInvoice() { - logger.info("=== Test delete encumbrance connected to an invoice - Unprocessable entity ==="); - String id = DELETE_CONNECTED_TRANSACTION_ID; - Transaction transaction = createTransaction(ENCUMBRANCE) - .withEncumbrance(new Encumbrance().withStatus(Encumbrance.Status.RELEASED)); - transaction.setId(id); - addMockEntry(TRANSACTIONS.name(), JsonObject.mapFrom(transaction)); - RestTestUtils.verifyDeleteResponse(TestEntities.TRANSACTIONS_ENCUMBRANCE.getEndpointWithId(id), "", 422); - } - - @Test - void testDeleteUnreleasedEncumbrance() { - logger.info("=== Test delete unreleased encumbrance==="); - String id = DELETE_CONNECTED_TRANSACTION_ID; - Transaction transaction = createTransaction(ENCUMBRANCE) - .withEncumbrance(new Encumbrance().withStatus(Encumbrance.Status.UNRELEASED)); - transaction.setId(id); - addMockEntry(TRANSACTIONS.name(), JsonObject.mapFrom(transaction)); - Errors err = RestTestUtils.verifyDeleteResponse(TestEntities.TRANSACTIONS_ENCUMBRANCE.getEndpointWithId(id), "", 400) - .as(Errors.class); - - assertEquals(TRANSACTION_NOT_RELEASED.getCode(), err.getErrors().get(0).getCode()); - } - - @Test - void testUpdatePayment() { - logger.info("=== Test update payment - Success ==="); - Transaction transaction = TestEntities.TRANSACTIONS_PAYMENT.getMockObject().mapTo(Transaction.class); - transaction.setInvoiceCancelled(true); - RestTestUtils.verifyPut(TestEntities.TRANSACTIONS_PAYMENT.getEndpointWithId(transaction.getId()), - JsonObject.mapFrom(transaction), "", 204); - } - - @Test - void testUpdatePaymentWithoutId() { - logger.info("=== Test update payment without id - Success ==="); - Transaction transaction = TestEntities.TRANSACTIONS_PAYMENT.getMockObject().mapTo(Transaction.class); - String id = transaction.getId(); - transaction.setId(null); - transaction.setInvoiceCancelled(true); - RestTestUtils.verifyPut(TestEntities.TRANSACTIONS_PAYMENT.getEndpointWithId(id), - JsonObject.mapFrom(transaction), "", 204); - } - - @Test - void testUpdatePaymentIdsMismatch() { - logger.info("=== Test update payment with ids mismatch - Unprocessable entity ==="); - String id = UUID.randomUUID().toString(); - Transaction transaction = createTransaction(PAYMENT); - transaction.setId(UUID.randomUUID().toString()); - RestTestUtils.verifyPut(TestEntities.TRANSACTIONS_PAYMENT.getEndpointWithId(id), JsonObject.mapFrom(transaction), - APPLICATION_JSON, 422); - } - - @Test - void testUpdatePaymentWithAnotherChange() { - logger.info("=== Test update payment with another change - Unprocessable entity ==="); - Transaction transaction = TestEntities.TRANSACTIONS_PAYMENT.getMockObject().mapTo(Transaction.class); - transaction.setDescription("Test fail"); - RestTestUtils.verifyPut(TestEntities.TRANSACTIONS_PAYMENT.getEndpointWithId(transaction.getId()), - JsonObject.mapFrom(transaction), APPLICATION_JSON, 422); - } - - @Test - void testUpdatePaymentWithoutInvoiceCancelled() { - logger.info("=== Test update payment without invoiceCancelled - Unprocessable entity ==="); - Transaction transaction = TestEntities.TRANSACTIONS_PAYMENT.getMockObject().mapTo(Transaction.class); - RestTestUtils.verifyPut(TestEntities.TRANSACTIONS_PAYMENT.getEndpointWithId(transaction.getId()), - JsonObject.mapFrom(transaction), APPLICATION_JSON, 422); - } - - @Test - void testUpdateCredit() { - logger.info("=== Test update credit - Success ==="); - Transaction transaction = TestEntities.TRANSACTIONS_CREDIT.getMockObject().mapTo(Transaction.class); - transaction.setInvoiceCancelled(true); - RestTestUtils.verifyPut(TestEntities.TRANSACTIONS_CREDIT.getEndpointWithId(transaction.getId()), - JsonObject.mapFrom(transaction), "", 204); - } - - @Test - void testUpdateCreditWithoutId() { - logger.info("=== Test update credit without id - Success ==="); - Transaction transaction = TestEntities.TRANSACTIONS_CREDIT.getMockObject().mapTo(Transaction.class); - String id = transaction.getId(); - transaction.setId(null); - transaction.setInvoiceCancelled(true); - RestTestUtils.verifyPut(TestEntities.TRANSACTIONS_CREDIT.getEndpointWithId(id), - JsonObject.mapFrom(transaction), "", 204); - } - - @Test - void testUpdateCreditIdsMismatch() { - logger.info("=== Test update credit with ids mismatch - Unprocessable entity ==="); - String id = UUID.randomUUID().toString(); - Transaction transaction = createTransaction(CREDIT); - transaction.setId(UUID.randomUUID().toString()); - RestTestUtils.verifyPut(TestEntities.TRANSACTIONS_CREDIT.getEndpointWithId(id), JsonObject.mapFrom(transaction), - APPLICATION_JSON, 422); - } - - @Test - void testUpdateCreditWithAnotherChange() { - logger.info("=== Test update credit with another change - Unprocessable entity ==="); - Transaction transaction = TestEntities.TRANSACTIONS_CREDIT.getMockObject().mapTo(Transaction.class); - transaction.setDescription("Test fail"); - RestTestUtils.verifyPut(TestEntities.TRANSACTIONS_CREDIT.getEndpointWithId(transaction.getId()), - JsonObject.mapFrom(transaction), APPLICATION_JSON, 422); - } - - @Test - void testUpdateCreditWithoutInvoiceCancelled() { - logger.info("=== Test update credit without invoiceCancelled - Unprocessable entity ==="); - Transaction transaction = TestEntities.TRANSACTIONS_CREDIT.getMockObject().mapTo(Transaction.class); - RestTestUtils.verifyPut(TestEntities.TRANSACTIONS_CREDIT.getEndpointWithId(transaction.getId()), - JsonObject.mapFrom(transaction), APPLICATION_JSON, 422); - } - @Test void testTransactionBatch() throws Exception { String batchAsString = getMockData("mockdata/transactions/batch_with_patch.json"); diff --git a/src/test/java/org/folio/rest/util/MockServer.java b/src/test/java/org/folio/rest/util/MockServer.java index 32c6fc3a..93a436ed 100644 --- a/src/test/java/org/folio/rest/util/MockServer.java +++ b/src/test/java/org/folio/rest/util/MockServer.java @@ -14,7 +14,6 @@ import static org.folio.rest.impl.GroupFiscalYearSummariesTest.TO_ALLOCATION_FIRST_DIF_GROUP; import static org.folio.rest.impl.GroupFiscalYearSummariesTest.TO_ALLOCATION_SECOND_DIF_GROUP; import static org.folio.rest.impl.TransactionApiTest.DELETE_CONNECTED_TRANSACTION_ID; -import static org.folio.rest.impl.TransactionApiTest.DELETE_TRANSACTION_ID; import static org.folio.rest.util.ErrorCodes.TRANSACTION_IS_PRESENT_BUDGET_DELETE_ERROR; import static org.folio.rest.util.HelperUtils.ID; import static org.folio.rest.util.ResourcePathResolver.BUDGETS_STORAGE; @@ -25,9 +24,7 @@ import static org.folio.rest.util.ResourcePathResolver.FUND_TYPES; import static org.folio.rest.util.ResourcePathResolver.GROUPS; import static org.folio.rest.util.ResourcePathResolver.GROUP_FUND_FISCAL_YEARS; -import static org.folio.rest.util.ResourcePathResolver.INVOICE_TRANSACTION_SUMMARIES; import static org.folio.rest.util.ResourcePathResolver.LEDGERS_STORAGE; -import static org.folio.rest.util.ResourcePathResolver.ORDER_TRANSACTION_SUMMARIES; import static org.folio.rest.util.ResourcePathResolver.TRANSACTIONS; import static org.folio.rest.util.ResourcePathResolver.resourcesPath; import static org.folio.rest.util.TestConstants.BAD_QUERY; @@ -76,10 +73,8 @@ import org.folio.rest.jaxrs.model.GroupCollection; import org.folio.rest.jaxrs.model.GroupFundFiscalYear; import org.folio.rest.jaxrs.model.GroupFundFiscalYearCollection; -import org.folio.rest.jaxrs.model.InvoiceTransactionSummary; import org.folio.rest.jaxrs.model.Ledger; import org.folio.rest.jaxrs.model.LedgersCollection; -import org.folio.rest.jaxrs.model.OrderTransactionSummary; import org.folio.rest.jaxrs.model.Transaction; import org.folio.rest.jaxrs.model.TransactionCollection; @@ -186,12 +181,6 @@ private Router defineRoutes() { .handler(ctx -> handlePostEntry(ctx, Ledger.class, TestEntities.LEDGER.name())); router.route(HttpMethod.POST, resourcesPath(GROUPS)) .handler(ctx -> handlePostEntry(ctx, Group.class, TestEntities.GROUP.name())); - router.route(HttpMethod.POST, resourcesPath(TRANSACTIONS)) - .handler(ctx -> handleTransactionPostEntry(ctx, Transaction.class)); - router.route(HttpMethod.POST, resourcesPath(ResourcePathResolver.ORDER_TRANSACTION_SUMMARIES)) - .handler(ctx -> handlePostEntry(ctx, OrderTransactionSummary.class, TestEntities.ORDER_TRANSACTION_SUMMARY.name())); - router.route(HttpMethod.POST, resourcesPath(ResourcePathResolver.INVOICE_TRANSACTION_SUMMARIES)) - .handler(ctx -> handlePostEntry(ctx, InvoiceTransactionSummary.class, TestEntities.INVOICE_TRANSACTION_SUMMARY.name())); router.route(HttpMethod.POST, resourcesPath(ResourcePathResolver.EXPENSE_CLASSES_STORAGE_URL)) .handler(ctx -> handlePostEntry(ctx, ExpenseClass.class, TestEntities.EXPENSE_CLASSES.name())); router.route(HttpMethod.POST, resourcesPath(ResourcePathResolver.BATCH_TRANSACTIONS_STORAGE)) @@ -249,8 +238,6 @@ private Router defineRoutes() { .handler(ctx -> handleDeleteRequest(ctx, TestEntities.LEDGER.name())); router.route(HttpMethod.DELETE, resourceByIdPath(GROUPS)) .handler(ctx -> handleDeleteRequest(ctx, TestEntities.GROUP.name())); - router.route(HttpMethod.DELETE, resourceByIdPath(TRANSACTIONS)) - .handler(ctx -> handleDeleteRequest(ctx, TestEntities.TRANSACTIONS.name())); router.route(HttpMethod.DELETE, resourceByIdPath(EXPENSE_CLASSES_STORAGE_URL)) .handler(ctx -> handleDeleteRequest(ctx, TestEntities.EXPENSE_CLASSES.name())); @@ -268,12 +255,6 @@ private Router defineRoutes() { .handler(ctx -> handlePutGenericSubObj(ctx, TestEntities.GROUP.name())); router.route(HttpMethod.PUT, resourceByIdPath(GROUP_FUND_FISCAL_YEARS)) .handler(ctx -> handlePutGenericSubObj(ctx, TestEntities.GROUP_FUND_FISCAL_YEAR.name())); - router.route(HttpMethod.PUT, resourceByIdPath(TRANSACTIONS)) - .handler(ctx -> handleTransactionPutEntry(ctx, Transaction.class)); - router.route(HttpMethod.PUT, resourceByIdPath(ORDER_TRANSACTION_SUMMARIES)) - .handler(ctx -> handlePutGenericSubObj(ctx, TestEntities.ORDER_TRANSACTION_SUMMARY.name())); - router.route(HttpMethod.PUT, resourceByIdPath(INVOICE_TRANSACTION_SUMMARIES)) - .handler(ctx -> handlePutGenericSubObj(ctx, TestEntities.INVOICE_TRANSACTION_SUMMARY.name())); router.route(HttpMethod.PUT, resourceByIdPath(EXPENSE_CLASSES_STORAGE_URL)) .handler(ctx -> handlePutGenericSubObj(ctx, TestEntities.EXPENSE_CLASSES.name())); return router; @@ -294,8 +275,7 @@ private void handleGetTransactionsCollection(RoutingContext ctx, TestEntities te serverResponse(ctx,200, APPLICATION_JSON, emptyCollection.encodePrettily()); } else if (query.contains(FUND_ID_FIRST_SAME_GROUP) || query.contains(FUND_ID_SECOND_SAME_GROUP) || (query.contains(FUND_ID_SECOND_DIFFERENT_GROUP) && (query.matches(TRANSACTION_ALLOCATION_FROM_QUERY))) - || (query.contains(FUND_ID_FIRST_DIFFERENT_GROUP) && (query.matches(TRANSACTION_ALLOCATION_TO_QUERY))) - || query.contains(DELETE_TRANSACTION_ID)) { + || (query.contains(FUND_ID_FIRST_DIFFERENT_GROUP) && (query.matches(TRANSACTION_ALLOCATION_TO_QUERY)))) { JsonObject emptyCollection = new JsonObject().put(testEntity.getName(), new JsonArray()); emptyCollection.put(TOTAL_RECORDS, 0); serverResponse(ctx,200, APPLICATION_JSON, emptyCollection.encodePrettily()); @@ -669,74 +649,6 @@ private String resourceByIdPath(String field) { return resourcesPath(field) + ID_PATH_PARAM; } - private void handleTransactionPutEntry(RoutingContext ctx, Class tClass) { - logger.info("got: " + ctx.body().asString()); - - String tenant = ctx.request() - .getHeader(OKAPI_HEADER_TENANT); - if (ERROR_TENANT.equals(tenant)) { - serverResponse(ctx, 500, TEXT_PLAIN, INTERNAL_SERVER_ERROR.getReasonPhrase()); - } else { - JsonObject body = ctx.body().asJsonObject(); - if (body.getString(ID) == null) { - body.put(ID, UUID.randomUUID() - .toString()); - } - T entry = body.mapTo(tClass); - Transaction t = ctx.body().asJsonObject().mapTo(Transaction.class); - - if (ID_DOES_NOT_EXIST.equals(t.getId())) { - serverResponse(ctx, 404, APPLICATION_JSON, t.getId()); - return; - } else if (t.getId().equals(ID_FOR_INTERNAL_SERVER_ERROR)) { - serverResponse(ctx, 500, APPLICATION_JSON, INTERNAL_SERVER_ERROR.getReasonPhrase()); - return; - } - if (t.getTransactionType() == Transaction.TransactionType.PENDING_PAYMENT) { - addServerRqRsData(HttpMethod.PUT, TestEntities.TRANSACTIONS_PENDING_PAYMENT.name(), body); - } else { - addServerRqRsData(HttpMethod.PUT, TestEntities.TRANSACTIONS.name(), body); - } - - serverResponse(ctx, 201, APPLICATION_JSON, JsonObject.mapFrom(entry) - .encodePrettily()); - } - } - - private void handleTransactionPostEntry(RoutingContext ctx, Class tClass) { - logger.info("got: " + ctx.body().asString()); - - String tenant = ctx.request() - .getHeader(OKAPI_HEADER_TENANT); - if (ERROR_TENANT.equals(tenant)) { - serverResponse(ctx, 500, TEXT_PLAIN, INTERNAL_SERVER_ERROR.getReasonPhrase()); - } else { - JsonObject body = ctx.body().asJsonObject(); - if (body.getString(ID) == null) { - body.put(ID, UUID.randomUUID() - .toString()); - } - T entry = body.mapTo(tClass); - Transaction t = ctx.body().asJsonObject().mapTo(Transaction.class); - if (t.getTransactionType() == Transaction.TransactionType.ALLOCATION) { - addServerRqRsData(HttpMethod.POST, TestEntities.TRANSACTIONS_ALLOCATION.name(), body); - } else if (t.getTransactionType() == Transaction.TransactionType.TRANSFER) { - addServerRqRsData(HttpMethod.POST, TestEntities.TRANSACTIONS_TRANSFER.name(), body); - } else if (t.getTransactionType() == Transaction.TransactionType.ENCUMBRANCE) { - addServerRqRsData(HttpMethod.POST, TestEntities.TRANSACTIONS_ENCUMBRANCE.name(), body); - } else if (t.getTransactionType() == Transaction.TransactionType.PAYMENT) { - addServerRqRsData(HttpMethod.POST, TestEntities.TRANSACTIONS_PAYMENT.name(), body); - } else if (t.getTransactionType() == Transaction.TransactionType.PENDING_PAYMENT) { - addServerRqRsData(HttpMethod.POST, TestEntities.TRANSACTIONS_PENDING_PAYMENT.name(), body); - } else if (t.getTransactionType() == Transaction.TransactionType.CREDIT) { - addServerRqRsData(HttpMethod.POST, TestEntities.TRANSACTIONS_CREDIT.name(), body); - } - - serverResponse(ctx, 201, APPLICATION_JSON, JsonObject.mapFrom(entry) - .encodePrettily()); - } - } - private void handlePostEntry(RoutingContext ctx, Class tClass, String entryName) { logger.info("got: " + ctx.body().asString()); diff --git a/src/test/java/org/folio/rest/util/TestEntities.java b/src/test/java/org/folio/rest/util/TestEntities.java index 84a6c8f3..be16cfc1 100644 --- a/src/test/java/org/folio/rest/util/TestEntities.java +++ b/src/test/java/org/folio/rest/util/TestEntities.java @@ -13,14 +13,12 @@ import org.folio.rest.jaxrs.model.FundType; import org.folio.rest.jaxrs.model.Group; import org.folio.rest.jaxrs.model.GroupFundFiscalYear; -import org.folio.rest.jaxrs.model.InvoiceTransactionSummary; import org.folio.rest.jaxrs.model.Ledger; import org.folio.rest.jaxrs.model.LedgerFiscalYearRollover; import org.folio.rest.jaxrs.model.LedgerFiscalYearRolloverBudget; import org.folio.rest.jaxrs.model.LedgerFiscalYearRolloverError; import org.folio.rest.jaxrs.model.LedgerFiscalYearRolloverLog; import org.folio.rest.jaxrs.model.LedgerFiscalYearRolloverProgress; -import org.folio.rest.jaxrs.model.OrderTransactionSummary; import org.folio.rest.jaxrs.model.Transaction; import org.folio.rest.jaxrs.resource.Finance; import org.folio.rest.jaxrs.resource.FinanceBudgets; @@ -30,14 +28,12 @@ import org.folio.rest.jaxrs.resource.FinanceFunds; import org.folio.rest.jaxrs.resource.FinanceGroupFundFiscalYears; import org.folio.rest.jaxrs.resource.FinanceGroups; -import org.folio.rest.jaxrs.resource.FinanceInvoiceTransactionSummaries; import org.folio.rest.jaxrs.resource.FinanceLedgerRollovers; import org.folio.rest.jaxrs.resource.FinanceLedgerRolloversBudgets; import org.folio.rest.jaxrs.resource.FinanceLedgerRolloversErrors; import org.folio.rest.jaxrs.resource.FinanceLedgerRolloversLogs; import org.folio.rest.jaxrs.resource.FinanceLedgerRolloversProgress; import org.folio.rest.jaxrs.resource.FinanceLedgers; -import org.folio.rest.jaxrs.resource.FinanceOrderTransactionSummaries; import org.folio.rest.tools.parser.JsonPathParser; import io.vertx.core.json.JsonObject; @@ -53,12 +49,6 @@ public enum TestEntities { TRANSACTIONS("transactions", getEndpoint(Finance.class) + "/transactions", Transaction.class, "mockdata/transactions/transactions.json", "transactions[0]", "amount", 25, 3), TRANSACTIONS_ALLOCATION("Allocation", getEndpoint(Finance.class) + "/allocations", Transaction.class, "mockdata/transactions/allocations.json", "transactions[0]", "amount", 25, 1), TRANSACTIONS_TRANSFER("Transfer", getEndpoint(Finance.class) + "/transfers", Transaction.class, "mockdata/transactions/transfers.json", "transactions[0]", "amount", 25, 1), - TRANSACTIONS_ENCUMBRANCE("Encumbrance", getEndpoint(Finance.class) + "/encumbrances", Transaction.class, "mockdata/transactions/encumbrances.json", "transactions[0]", "amount", 25, 1), - TRANSACTIONS_PAYMENT("Payment", getEndpoint(Finance.class) + "/payments", Transaction.class, "mockdata/transactions/payments.json", "transactions[0]", "amount", 25, 1), - TRANSACTIONS_PENDING_PAYMENT("pendingPayment", getEndpoint(Finance.class) + "/pending-payments", Transaction.class, "mockdata/transactions/pending-payments.json", "transactions[0]", "amount", 25, 1), - TRANSACTIONS_CREDIT("Credit", getEndpoint(Finance.class) + "/credits", Transaction.class, "mockdata/transactions/credits.json", "transactions[0]", "amount", 25, 1), - ORDER_TRANSACTION_SUMMARY("orderTransactionSummary", getEndpoint(FinanceOrderTransactionSummaries.class), OrderTransactionSummary.class, "mockdata/transaction-summaries/order_transaction_summary.json", "", "numTransactions", 0, 1), - INVOICE_TRANSACTION_SUMMARY("invoiceTransactionSummary", getEndpoint(FinanceInvoiceTransactionSummaries.class), InvoiceTransactionSummary.class, "mockdata/transaction-summaries/invoice_transaction_summary.json", "", "numPaymentsCredits", -1, 1), EXPENSE_CLASSES("expenseClasses", getEndpoint(FinanceExpenseClasses.class), ExpenseClass.class, "mockdata/expense-classes/expense-classes.json", "expenseClasses[0]", "externalAccountNumberExt", 1, 1), LEDGER_ROLLOVER("ledgerRollover", getEndpoint(FinanceLedgerRollovers.class), LedgerFiscalYearRollover.class, "mockdata/ledger-rollovers/ledger-rollovers.json", "ledgerFiscalYearRollovers[0]", "toFiscalYearId", 1, 1), LEDGER_ROLLOVER_LOGS("ledgerRolloverLogs", getEndpoint(FinanceLedgerRolloversLogs.class), LedgerFiscalYearRolloverLog.class, "", "", "", 1, 1), diff --git a/src/test/java/org/folio/services/CommonTransactionServiceTest.java b/src/test/java/org/folio/services/TransactionServiceTest.java similarity index 71% rename from src/test/java/org/folio/services/CommonTransactionServiceTest.java rename to src/test/java/org/folio/services/TransactionServiceTest.java index 0687fb3c..f28b0e96 100644 --- a/src/test/java/org/folio/services/CommonTransactionServiceTest.java +++ b/src/test/java/org/folio/services/TransactionServiceTest.java @@ -1,8 +1,8 @@ package org.folio.services; import static io.vertx.core.Future.succeededFuture; +import static org.folio.rest.util.ResourcePathResolver.BATCH_TRANSACTIONS_STORAGE; import static org.folio.rest.util.ResourcePathResolver.FISCAL_YEARS_STORAGE; -import static org.folio.rest.util.ResourcePathResolver.TRANSACTIONS; import static org.folio.rest.util.ResourcePathResolver.resourceByIdPath; import static org.folio.rest.util.ResourcePathResolver.resourcesPath; import static org.folio.rest.util.TestUtils.assertQueryContains; @@ -12,7 +12,6 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.refEq; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -26,16 +25,20 @@ import org.folio.rest.core.RestClient; import org.folio.rest.core.models.RequestContext; +import org.folio.rest.jaxrs.model.Batch; import org.folio.rest.jaxrs.model.Budget; import org.folio.rest.jaxrs.model.BudgetExpenseClass; import org.folio.rest.jaxrs.model.FiscalYear; import org.folio.rest.jaxrs.model.SharedBudget; import org.folio.rest.jaxrs.model.Transaction; import org.folio.rest.jaxrs.model.TransactionCollection; -import org.folio.services.transactions.CommonTransactionService; +import org.folio.services.fiscalyear.FiscalYearService; +import org.folio.services.transactions.TransactionService; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -45,9 +48,10 @@ @ExtendWith(VertxExtension.class) -public class CommonTransactionServiceTest { +public class TransactionServiceTest { - private CommonTransactionService transactionService; + private TransactionService transactionService; + private AutoCloseable mockitoMocks; @Mock(name = "restClient") private RestClient restClient; @@ -57,8 +61,14 @@ public class CommonTransactionServiceTest { @BeforeEach public void initMocks() { - MockitoAnnotations.openMocks(this); - transactionService = new CommonTransactionService(restClient); + mockitoMocks = MockitoAnnotations.openMocks(this); + FiscalYearService fiscalYearService = new FiscalYearService(restClient); + transactionService = new TransactionService(restClient, fiscalYearService); + } + + @AfterEach + public void afterEach() throws Exception { + mockitoMocks.close(); } @Test @@ -73,7 +83,7 @@ void getTransactionsByBudgetId(VertxTestContext vertxTestContext) { when(restClient.get(anyString(), any(), eq(requestContext))) .thenReturn(succeededFuture(transactionCollection)); - Future> future = transactionService.retrieveTransactions(budget, requestContext); + Future> future = transactionService.getBudgetTransactions(budget, requestContext); vertxTestContext.assertComplete(future) .onComplete(result -> { @@ -107,7 +117,7 @@ void getTransactionsByExpenseClasses(VertxTestContext vertxTestContext) { when(restClient.get(anyString(), any(), eq(requestContext))) .thenReturn(succeededFuture(transactionCollection)); - Future> future = transactionService.retrieveTransactions(Arrays.asList(budgetExpenseClass1, budgetExpenseClass2), budget, requestContext); + Future> future = transactionService.getBudgetTransactionsWithExpenseClasses(Arrays.asList(budgetExpenseClass1, budgetExpenseClass2), budget, requestContext); vertxTestContext.assertComplete(future) .onComplete(result -> { @@ -135,26 +145,25 @@ void createAllocationTransaction(VertxTestContext vertxTestContext) { .withId(fiscalYearId) .withCurrency("BYN"); - Transaction transaction = new Transaction() - .withId(UUID.randomUUID().toString()) - .withToFundId(budget.getFundId()) - .withFiscalYearId(budget.getFiscalYearId()) - .withCurrency(fiscalYear.getCurrency()) - .withAmount(budget.getAllocated()) - .withTransactionType(Transaction.TransactionType.ALLOCATION) - .withSource(Transaction.Source.USER); - - when(restClient.post(eq(resourcesPath(TRANSACTIONS)), any(), eq(Transaction.class), eq(requestContext))) - .thenReturn(succeededFuture(transaction)); - when(restClient.get(eq(resourceByIdPath(FISCAL_YEARS_STORAGE, fiscalYear.getId())), any(), any())).thenReturn(succeededFuture(fiscalYear)); + when(restClient.postEmptyResponse(eq(resourcesPath(BATCH_TRANSACTIONS_STORAGE)), any(Batch.class), eq(requestContext))) + .thenReturn(Future.succeededFuture()); + when(restClient.get(eq(resourceByIdPath(FISCAL_YEARS_STORAGE, fiscalYear.getId())), any(), any())) + .thenReturn(succeededFuture(fiscalYear)); - Future future = transactionService.createAllocationTransaction(budget, requestContext); + Future future = transactionService.createAllocationTransaction(budget, requestContext); vertxTestContext.assertComplete(future) .onComplete(result -> { - verify(restClient).post(eq(resourcesPath(TRANSACTIONS)), refEq(transaction, "id"), eq(Transaction.class), eq(requestContext)); - assertEquals(transaction, result.result()); - assertEquals(result.result().getCurrency(), fiscalYear.getCurrency()); + ArgumentCaptor batchCaptor = ArgumentCaptor.forClass(Batch.class); + verify(restClient).postEmptyResponse(eq(resourcesPath(BATCH_TRANSACTIONS_STORAGE)), batchCaptor.capture(), eq(requestContext)); + Batch batch = batchCaptor.getValue(); + Transaction transaction = batch.getTransactionsToCreate().get(0); + assertEquals(budget.getFundId(), transaction.getToFundId()); + assertEquals(budget.getFiscalYearId(), transaction.getFiscalYearId()); + assertEquals(fiscalYear.getCurrency(), transaction.getCurrency()); + assertEquals(budget.getAllocated(), transaction.getAmount()); + assertEquals(budget.getAllocated(), transaction.getAmount()); + assertEquals(Transaction.Source.USER, transaction.getSource()); verify(restClient).get(resourceByIdPath(FISCAL_YEARS_STORAGE, fiscalYearId), FiscalYear.class, requestContext); vertxTestContext.completeNow(); @@ -178,9 +187,11 @@ void getTransactionsByFundIdsInChunks(VertxTestContext vertxTestContext) { .withTotalRecords(1); when(restClient.get(anyString(), eq(TransactionCollection.class), any())) - .thenReturn(succeededFuture(transactionCollection), succeededFuture(new TransactionCollection()), succeededFuture(new TransactionCollection())); + .thenReturn(succeededFuture(transactionCollection)) + .thenReturn(succeededFuture(new TransactionCollection())) + .thenReturn(succeededFuture(new TransactionCollection())); - Future> future = transactionService.retrieveTransactionsByFundIds(fundIds, fiscalYearId, requestContext); + Future> future = transactionService.getTransactionsByFundIds(fundIds, fiscalYearId, requestContext); vertxTestContext.assertComplete(future) .onComplete(result -> { diff --git a/src/test/java/org/folio/services/budget/BudgetExpenseClassServiceTest.java b/src/test/java/org/folio/services/budget/BudgetExpenseClassServiceTest.java index 03a8a888..761f9fae 100644 --- a/src/test/java/org/folio/services/budget/BudgetExpenseClassServiceTest.java +++ b/src/test/java/org/folio/services/budget/BudgetExpenseClassServiceTest.java @@ -43,7 +43,7 @@ import org.folio.rest.jaxrs.model.SharedBudget; import org.folio.rest.jaxrs.model.StatusExpenseClass; import org.folio.rest.jaxrs.model.Transaction; -import org.folio.services.transactions.CommonTransactionService; +import org.folio.services.transactions.TransactionService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -68,7 +68,7 @@ public class BudgetExpenseClassServiceTest { private RestClient restClient; @Mock - private CommonTransactionService transactionServiceMock; + private TransactionService transactionServiceMock; @Mock private RequestContext requestContextMock; @@ -191,7 +191,7 @@ void testUpdateBudgetExpenseClassesLinks_withoutStatusExpenseClasses_noTransacti .withBudgetExpenseClasses(Arrays.asList(budgetExpenseClass1, budgetExpenseClass2, budgetExpenseClass3)); when(restClient.get(anyString(), any(), any())).thenReturn(succeededFuture(budgetExpenseClassCollection)); - when(transactionServiceMock.retrieveTransactions(anyList(), any(), any())).thenReturn(succeededFuture(emptyList())); + when(transactionServiceMock.getBudgetTransactionsWithExpenseClasses(anyList(), any(), any())).thenReturn(succeededFuture(emptyList())); when(restClient.delete(anyString(), any())).thenReturn(succeededFuture(null)); when(requestContextMock.context()).thenReturn(Vertx.vertx().getOrCreateContext()); @@ -206,7 +206,7 @@ void testUpdateBudgetExpenseClassesLinks_withoutStatusExpenseClasses_noTransacti verify(restClient, never()).post(anyString(), any(), any(), any()); verify(restClient, never()).put(anyString(), any(), any()); ArgumentCaptor> listArgumentCaptor = ArgumentCaptor.forClass(List.class); - verify(transactionServiceMock).retrieveTransactions(listArgumentCaptor.capture(), eq(sharedBudget), eq(requestContextMock)); + verify(transactionServiceMock).getBudgetTransactionsWithExpenseClasses(listArgumentCaptor.capture(), eq(sharedBudget), eq(requestContextMock)); List budgetExpenseClasses = listArgumentCaptor.getValue(); assertThat(budgetExpenseClasses, containsInAnyOrder(budgetExpenseClass1, budgetExpenseClass2, budgetExpenseClass3)); @@ -227,7 +227,7 @@ void testUpdateBudgetExpenseClassesLinks_withoutStatusExpenseClasses_transaction .withBudgetExpenseClasses(Arrays.asList(budgetExpenseClass1, budgetExpenseClass2, budgetExpenseClass3)); when(restClient.get(anyString(), any(), any())).thenReturn(succeededFuture(budgetExpenseClassCollection)); - when(transactionServiceMock.retrieveTransactions(anyList(), any(), any())).thenReturn(succeededFuture(Collections.singletonList(new Transaction()))); + when(transactionServiceMock.getBudgetTransactionsWithExpenseClasses(anyList(), any(), any())).thenReturn(succeededFuture(Collections.singletonList(new Transaction()))); when(restClient.delete(anyString(), any())).thenReturn(succeededFuture(null)); when(requestContextMock.context()).thenReturn(Vertx.vertx().getOrCreateContext()); @@ -246,7 +246,7 @@ void testUpdateBudgetExpenseClassesLinks_withoutStatusExpenseClasses_transaction verify(restClient, never()).post(anyString(), any(), any(), any()); verify(restClient, never()).put(anyString(), any(), any()); ArgumentCaptor> listArgumentCaptor = ArgumentCaptor.forClass(List.class); - verify(transactionServiceMock).retrieveTransactions(listArgumentCaptor.capture(), eq(sharedBudget), eq(requestContextMock)); + verify(transactionServiceMock).getBudgetTransactionsWithExpenseClasses(listArgumentCaptor.capture(), eq(sharedBudget), eq(requestContextMock)); List budgetExpenseClasses = listArgumentCaptor.getValue(); assertThat(budgetExpenseClasses, containsInAnyOrder(budgetExpenseClass1, budgetExpenseClass2, budgetExpenseClass3)); @@ -283,7 +283,7 @@ void testUpdateBudgetExpenseClassesLinks_withSameStatusExpenseClassesAsExistingB verify(restClient).get(assertQueryContains(expectedQuery), eq(BudgetExpenseClassCollection.class), eq(requestContextMock)); verify(restClient, never()).post(anyString(), any(), any(), any()); verify(restClient, never()).put(anyString(), any(), any()); - verify(transactionServiceMock, never()).retrieveTransactions(any(), any(), any()); + verify(transactionServiceMock, never()).getBudgetTransactionsWithExpenseClasses(any(), any(), any()); verify(restClient, never()).delete(anyString(), any()); vertxTestContext.completeNow(); @@ -321,7 +321,7 @@ void testUpdateBudgetExpenseClassesLinks_withUpdatedStatusExpenseClasses_existin verify(restClient).get(assertQueryContains(expectedQuery), eq(BudgetExpenseClassCollection.class), eq(requestContextMock)); verify(restClient, never()).post(anyString(), any(), any(), any()); - verify(transactionServiceMock, never()).retrieveTransactions(any(), any(), any()); + verify(transactionServiceMock, never()).getBudgetTransactionsWithExpenseClasses(any(), any(), any()); verify(restClient, never()).delete(anyString(), any()); ArgumentCaptor idArgumentCaptor = ArgumentCaptor.forClass(String.class); @@ -368,7 +368,7 @@ void testUpdateBudgetExpenseClassesLinks_complexTestWithBudgetExpenseClassDeleti when(restClient.put(anyString(), any(), any())).thenReturn(succeededFuture(null)); when(restClient.post(anyString(), any(), any(), any())).thenReturn(succeededFuture(newBudgetExpenseClass)); when(restClient.delete(anyString(), any())).thenReturn(succeededFuture(null)); - when(transactionServiceMock.retrieveTransactions(anyList(), any(), any())).thenReturn(succeededFuture(emptyList())); + when(transactionServiceMock.getBudgetTransactionsWithExpenseClasses(anyList(), any(), any())).thenReturn(succeededFuture(emptyList())); when(requestContextMock.context()).thenReturn(Vertx.vertx().getOrCreateContext()); Future future = budgetExpenseClassService.updateBudgetExpenseClassesLinks(sharedBudget, requestContextMock); @@ -382,7 +382,7 @@ void testUpdateBudgetExpenseClassesLinks_complexTestWithBudgetExpenseClassDeleti List expectedToDeleteList = new ArrayList<>(); expectedToDeleteList.add(budgetExpenseClassToBeDeleted); - verify(transactionServiceMock).retrieveTransactions(eq(expectedToDeleteList), eq(sharedBudget), eq(requestContextMock)); + verify(transactionServiceMock).getBudgetTransactionsWithExpenseClasses(eq(expectedToDeleteList), eq(sharedBudget), eq(requestContextMock)); verify(restClient).delete(assertQueryContains(budgetExpenseClassToBeDeleted.getId()), eq(requestContextMock)); diff --git a/src/test/java/org/folio/services/budget/BudgetExpenseClassTotalsServiceTest.java b/src/test/java/org/folio/services/budget/BudgetExpenseClassTotalsServiceTest.java index 039912fb..a31a6aee 100644 --- a/src/test/java/org/folio/services/budget/BudgetExpenseClassTotalsServiceTest.java +++ b/src/test/java/org/folio/services/budget/BudgetExpenseClassTotalsServiceTest.java @@ -25,7 +25,7 @@ import org.folio.rest.jaxrs.model.ExpenseClass; import org.folio.rest.jaxrs.model.Transaction; import org.folio.services.ExpenseClassService; -import org.folio.services.transactions.CommonTransactionService; +import org.folio.services.transactions.TransactionService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -50,7 +50,7 @@ public class BudgetExpenseClassTotalsServiceTest { private ExpenseClassService expenseClassServiceMock; @Mock - private CommonTransactionService transactionServiceMock; + private TransactionService transactionServiceMock; @Mock private BudgetExpenseClassService budgetExpenseClassServiceMock; @@ -122,7 +122,7 @@ void getExpenseClassTotalsComplexPositiveTest(VertxTestContext vertxTestContext) when(restClient.get(anyString(), any(), any())).thenReturn(succeededFuture(budget)); when(expenseClassServiceMock.getExpenseClassesByBudgetId(anyString(), any())).thenReturn(succeededFuture(expenseClasses)); - when(transactionServiceMock.retrieveTransactions(any(), any())).thenReturn(succeededFuture(transactions)); + when(transactionServiceMock.getBudgetTransactions(any(), any())).thenReturn(succeededFuture(transactions)); when(budgetExpenseClassServiceMock.getBudgetExpenseClasses(anyString(), any())).thenReturn(succeededFuture(budgetExpenseClasses)); Future future = budgetExpenseClassTotalsService.getExpenseClassTotals(budget.getId(), requestContext); @@ -131,7 +131,7 @@ void getExpenseClassTotalsComplexPositiveTest(VertxTestContext vertxTestContext) var budgetExpenseClassTotalsCollection = result.result(); verify(restClient).get(assertQueryContains(budget.getId()), eq(Budget.class), eq(requestContext)); verify(expenseClassServiceMock).getExpenseClassesByBudgetId(eq(budget.getId()), eq(requestContext)); - verify(transactionServiceMock).retrieveTransactions(eq(budget), eq(requestContext)); + verify(transactionServiceMock).getBudgetTransactions(eq(budget), eq(requestContext)); verify(budgetExpenseClassServiceMock).getBudgetExpenseClasses(eq(budget.getId()), eq(requestContext)); assertEquals(2, budgetExpenseClassTotalsCollection.getTotalRecords()); @@ -174,7 +174,7 @@ void getExpenseClassTotalsWhenBudgetExpendedTotalIsZeroPercentageExpendedMustBeN when(restClient.get(anyString(), any(), any())).thenReturn(succeededFuture(budget)); when(expenseClassServiceMock.getExpenseClassesByBudgetId(anyString(), any())).thenReturn(succeededFuture(expenseClasses)); - when(transactionServiceMock.retrieveTransactions(any(), any())).thenReturn(succeededFuture(transactions)); + when(transactionServiceMock.getBudgetTransactions(any(), any())).thenReturn(succeededFuture(transactions)); when(budgetExpenseClassServiceMock.getBudgetExpenseClasses(anyString(), any())).thenReturn(succeededFuture(budgetExpenseClasses)); Future future = budgetExpenseClassTotalsService.getExpenseClassTotals(budget.getId(), requestContext); @@ -184,7 +184,7 @@ void getExpenseClassTotalsWhenBudgetExpendedTotalIsZeroPercentageExpendedMustBeN verify(restClient).get(assertQueryContains(budget.getId()), eq(Budget.class), eq(requestContext)); verify(expenseClassServiceMock).getExpenseClassesByBudgetId(assertQueryContains(budget.getId()), eq(requestContext)); - verify(transactionServiceMock).retrieveTransactions(eq(budget), eq(requestContext)); + verify(transactionServiceMock).getBudgetTransactions(eq(budget), eq(requestContext)); verify(budgetExpenseClassServiceMock).getBudgetExpenseClasses(assertQueryContains(budget.getId()), eq(requestContext)); @@ -213,7 +213,7 @@ void getExpenseClassTotalsWithoutLinkedExpenseClasses(VertxTestContext vertxTest when(restClient.get(anyString(), any(), any())).thenReturn(succeededFuture(budget)); when(expenseClassServiceMock.getExpenseClassesByBudgetId(anyString(), any())).thenReturn(succeededFuture(Collections.emptyList())); - when(transactionServiceMock.retrieveTransactions(any(), any())).thenReturn(succeededFuture(Collections.singletonList(credit))); + when(transactionServiceMock.getBudgetTransactions(any(), any())).thenReturn(succeededFuture(Collections.singletonList(credit))); when(budgetExpenseClassServiceMock.getBudgetExpenseClasses(anyString(), any())).thenReturn(succeededFuture(Collections.emptyList())); Future future = budgetExpenseClassTotalsService.getExpenseClassTotals(budget.getId(), requestContext); @@ -223,7 +223,7 @@ void getExpenseClassTotalsWithoutLinkedExpenseClasses(VertxTestContext vertxTest var budgetExpenseClassTotalsCollection = result.result(); verify(restClient).get(assertQueryContains(budget.getId()), eq(Budget.class), eq(requestContext)); verify(expenseClassServiceMock).getExpenseClassesByBudgetId(assertQueryContains(budget.getId()), eq(requestContext)); - verify(transactionServiceMock).retrieveTransactions(eq(budget), eq(requestContext)); + verify(transactionServiceMock).getBudgetTransactions(eq(budget), eq(requestContext)); verify(budgetExpenseClassServiceMock).getBudgetExpenseClasses(assertQueryContains(budget.getId()), eq(requestContext)); assertEquals(0, budgetExpenseClassTotalsCollection.getTotalRecords()); @@ -240,7 +240,7 @@ void getExpenseClassTotalsWithoutTransactions(VertxTestContext vertxTestContext) List budgetExpenseClasses = Collections.singletonList(budgetExpenseClass1); when(restClient.get(anyString(), any(), any())).thenReturn(succeededFuture(budget)); when(expenseClassServiceMock.getExpenseClassesByBudgetId(anyString(), any())).thenReturn(succeededFuture(expenseClasses)); - when(transactionServiceMock.retrieveTransactions(any(), any())).thenReturn(succeededFuture(Collections.emptyList())); + when(transactionServiceMock.getBudgetTransactions(any(), any())).thenReturn(succeededFuture(Collections.emptyList())); when(budgetExpenseClassServiceMock.getBudgetExpenseClasses(anyString(), any())).thenReturn(succeededFuture(budgetExpenseClasses)); var future = budgetExpenseClassTotalsService.getExpenseClassTotals(budget.getId(), requestContext); @@ -250,7 +250,7 @@ void getExpenseClassTotalsWithoutTransactions(VertxTestContext vertxTestContext) var budgetExpenseClassTotalsCollection = result.result(); verify(restClient).get(assertQueryContains(budget.getId()), eq(Budget.class), eq(requestContext)); verify(expenseClassServiceMock).getExpenseClassesByBudgetId(assertQueryContains(budget.getId()), eq(requestContext)); - verify(transactionServiceMock).retrieveTransactions(eq(budget), eq(requestContext)); + verify(transactionServiceMock).getBudgetTransactions(eq(budget), eq(requestContext)); verify(budgetExpenseClassServiceMock).getBudgetExpenseClasses(assertQueryContains(budget.getId()), eq(requestContext)); assertEquals(1, budgetExpenseClassTotalsCollection.getTotalRecords()); diff --git a/src/test/java/org/folio/services/budget/CreateBudgetServiceTest.java b/src/test/java/org/folio/services/budget/CreateBudgetServiceTest.java index b0d7a291..58b784ed 100644 --- a/src/test/java/org/folio/services/budget/CreateBudgetServiceTest.java +++ b/src/test/java/org/folio/services/budget/CreateBudgetServiceTest.java @@ -23,11 +23,11 @@ import org.folio.rest.jaxrs.model.FiscalYear; import org.folio.rest.jaxrs.model.SharedBudget; import org.folio.rest.jaxrs.model.StatusExpenseClass; -import org.folio.rest.jaxrs.model.Transaction; import org.folio.services.fund.FundDetailsService; import org.folio.services.fund.FundFiscalYearService; import org.folio.services.group.GroupFundFiscalYearService; -import org.folio.services.transactions.CommonTransactionService; +import org.folio.services.transactions.TransactionService; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -48,7 +48,7 @@ public class CreateBudgetServiceTest { @Mock private RestClient restClient; @Mock - private CommonTransactionService transactionMockService; + private TransactionService transactionMockService; @Mock private BudgetExpenseClassService budgetExpenseClassMockService; @Mock @@ -62,6 +62,7 @@ public class CreateBudgetServiceTest { @Mock private RequestContext requestContextMock; + private AutoCloseable mockitoMocks; private SharedBudget currSharedBudget; private Budget currBudget; private SharedBudget plannedSharedBudget; @@ -71,7 +72,7 @@ public class CreateBudgetServiceTest { @BeforeEach public void initMocks() { - MockitoAnnotations.openMocks(this); + mockitoMocks = MockitoAnnotations.openMocks(this); String currBudgetId = UUID.randomUUID().toString(); String currFiscalYearId = UUID.randomUUID().toString(); String fundId = UUID.randomUUID().toString(); @@ -88,6 +89,11 @@ public void initMocks() { plannedSharedBudget = new SharedBudget().withId(UUID.randomUUID().toString()).withFiscalYearId(plannedFiscalYear.getId()).withFundId(fundId); } + @AfterEach + public void afterEach() throws Exception { + mockitoMocks.close(); + } + @Test void testCurrentCreateBudgetWithAllocated(VertxTestContext vertxTestContext) { currSharedBudget.withAllocated(100.43); @@ -100,7 +106,7 @@ void testCurrentCreateBudgetWithAllocated(VertxTestContext vertxTestContext) { when(restClient.post(anyString(), any(), any(), any())).thenReturn(succeededFuture(budgetFromStorage)); when(groupFundFiscalYearMockService.updateBudgetIdForGroupFundFiscalYears(any(), any())).thenReturn(succeededFuture(null)); when(budgetExpenseClassMockService.createBudgetExpenseClasses(any(), any())).thenReturn(succeededFuture(null)); - when(transactionMockService.createAllocationTransaction(any(Budget.class), any())).thenReturn(succeededFuture(new Transaction())); + when(transactionMockService.createAllocationTransaction(any(Budget.class), any())).thenReturn(succeededFuture(null)); var future = createBudgetService.createBudget(currSharedBudget, requestContextMock); vertxTestContext.assertComplete(future) @@ -140,7 +146,7 @@ void testShouldCreatePlannedBudgetWithoutCurrExpenseClassesAndAllocatedIfCurrent when(budgetExpenseClassMockService.createBudgetExpenseClasses(any(), any())).thenReturn(succeededFuture(null)); when(budgetExpenseClassMockService.getBudgetExpenseClasses(currBudget.getId(), requestContextMock)).thenReturn(succeededFuture(currBudgetExpenseClasses)); - when(transactionMockService.createAllocationTransaction(any(Budget.class), any())).thenReturn(succeededFuture(new Transaction())); + when(transactionMockService.createAllocationTransaction(any(Budget.class), any())).thenReturn(succeededFuture(null)); when(fundDetailsMockService.retrieveCurrentBudget(plannedSharedBudget.getFundId(), null, true, requestContextMock)).thenReturn(succeededFuture(null)); var future = createBudgetService.createBudget(plannedSharedBudget, requestContextMock); @@ -183,7 +189,7 @@ void testShouldCreatePlannedBudgetWithoutCurrExpenseClassesAndAllocatedIfCurrent when(budgetExpenseClassMockService.createBudgetExpenseClasses(any(), any())).thenReturn(succeededFuture(null)); when(budgetExpenseClassMockService.getBudgetExpenseClasses(currBudget.getId(), requestContextMock)).thenReturn(succeededFuture(Collections.emptyList())); - when(transactionMockService.createAllocationTransaction(any(Budget.class), any())).thenReturn(succeededFuture(new Transaction())); + when(transactionMockService.createAllocationTransaction(any(Budget.class), any())).thenReturn(succeededFuture(null)); when(fundDetailsMockService.retrieveCurrentBudget(plannedSharedBudget.getFundId(), null, true, requestContextMock)).thenReturn(succeededFuture(currBudget)); Future future = createBudgetService.createBudget(plannedSharedBudget, requestContextMock); @@ -229,7 +235,7 @@ void testShouldCreatePlannedBudgetWithExpenseClassesProvidedFromUserAndAllocated when(budgetExpenseClassMockService.createBudgetExpenseClasses(any(), any())).thenReturn(succeededFuture(null)); when(budgetExpenseClassMockService.getBudgetExpenseClasses(currBudget.getId(), requestContextMock)).thenReturn(succeededFuture(currBudgetExpenseClasses)); - when(transactionMockService.createAllocationTransaction(any(Budget.class), any())).thenReturn(succeededFuture(new Transaction())); + when(transactionMockService.createAllocationTransaction(any(Budget.class), any())).thenReturn(succeededFuture(null)); when(fundDetailsMockService.retrieveCurrentBudget(plannedSharedBudget.getFundId(), null, true, requestContextMock)).thenReturn(succeededFuture(currBudget)); var future = createBudgetService.createBudget(plannedSharedBudget, requestContextMock); @@ -277,7 +283,7 @@ void testShouldCreatePlannedBudgetWithExpenseCurrExpenseClassesAndAllocatedIfCur when(budgetExpenseClassMockService.createBudgetExpenseClasses(any(), any())).thenReturn(succeededFuture(null)); when(budgetExpenseClassMockService.getBudgetExpenseClasses(currBudget.getId(), requestContextMock)).thenReturn(succeededFuture(currBudgetExpenseClasses)); - when(transactionMockService.createAllocationTransaction(any(Budget.class), any())).thenReturn(succeededFuture(new Transaction())); + when(transactionMockService.createAllocationTransaction(any(Budget.class), any())).thenReturn(succeededFuture(null)); when(fundDetailsMockService.retrieveCurrentBudget(plannedSharedBudget.getFundId(), null, true, requestContextMock)).thenReturn(succeededFuture(currBudget)); var future = createBudgetService.createBudget(plannedSharedBudget, requestContextMock); @@ -322,7 +328,7 @@ void testPlannedBudgetWithAllocated(VertxTestContext vertxTestContext) { when(budgetExpenseClassMockService.createBudgetExpenseClasses(any(), any())).thenReturn(succeededFuture(null)); when(budgetExpenseClassMockService.getBudgetExpenseClasses(currBudget.getId(), requestContextMock)).thenReturn(succeededFuture(currBudgetExpenseClasses)); - when(transactionMockService.createAllocationTransaction(any(Budget.class), any())).thenReturn(succeededFuture(new Transaction())); + when(transactionMockService.createAllocationTransaction(any(Budget.class), any())).thenReturn(succeededFuture(null)); when(fundDetailsMockService.retrieveCurrentBudget(plannedSharedBudget.getFundId(), null, true, requestContextMock)).thenReturn(succeededFuture(currBudget)); var future = createBudgetService.createBudget(plannedSharedBudget, requestContextMock); @@ -392,7 +398,7 @@ void testCreateBudgetWithAllocationCreationError(VertxTestContext vertxTestConte .withFiscalYearId(currSharedBudget.getFiscalYearId()) .withFundId(currSharedBudget.getFundId()); - Future errorFuture = Future.failedFuture(new Exception()); + Future errorFuture = Future.failedFuture(new Exception()); when(restClient.post(anyString(), any(), any(), any())).thenReturn(succeededFuture(budgetFromStorage)); when(transactionMockService.createAllocationTransaction(any(Budget.class), any())).thenReturn(errorFuture); diff --git a/src/test/java/org/folio/services/budget/RecalculateBudgetServiceTest.java b/src/test/java/org/folio/services/budget/RecalculateBudgetServiceTest.java index 6eabf0a7..6acd85ff 100644 --- a/src/test/java/org/folio/services/budget/RecalculateBudgetServiceTest.java +++ b/src/test/java/org/folio/services/budget/RecalculateBudgetServiceTest.java @@ -9,7 +9,7 @@ import org.folio.rest.jaxrs.model.SharedBudget; import org.folio.rest.jaxrs.model.Transaction; import org.folio.rest.util.BudgetUtils; -import org.folio.services.transactions.CommonTransactionService; +import org.folio.services.transactions.TransactionService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -44,7 +44,7 @@ public class RecalculateBudgetServiceTest { @Mock private RequestContext requestContext; @Mock - private CommonTransactionService transactionServiceMock; + private TransactionService transactionServiceMock; private Budget budget; @@ -86,13 +86,13 @@ void recalculateBudgetComplexPositiveTest(VertxTestContext vertxTestContext) { when(budgetServiceMock.getBudgetById(anyString(), any())).thenReturn(succeededFuture(BudgetUtils.convertToSharedBudget(budget))); when(budgetServiceMock.updateBudgetWithAmountFields(any(), any())).thenReturn(succeededFuture()); - when(transactionServiceMock.retrieveTransactions(any(), any())).thenReturn(succeededFuture(transactions)); + when(transactionServiceMock.getBudgetTransactions(any(), any())).thenReturn(succeededFuture(transactions)); Future future = recalculateBudgetService.recalculateBudget(budget.getId(), requestContext); vertxTestContext.assertComplete(future) .onSuccess(result -> { verify(budgetServiceMock).getBudgetById(eq(budget.getId()), eq(requestContext)); - verify(transactionServiceMock).retrieveTransactions(eq(budget), eq(requestContext)); + verify(transactionServiceMock).getBudgetTransactions(eq(budget), eq(requestContext)); verify(budgetServiceMock).updateBudgetWithAmountFields(budgetCaptor.capture(), eq(requestContext)); SharedBudget capturedBudget = budgetCaptor.getValue(); @@ -117,13 +117,13 @@ void recalculateBudgetWithoutTransactions(VertxTestContext vertxTestContext) { when(budgetServiceMock.getBudgetById(anyString(), any())).thenReturn(succeededFuture(BudgetUtils.convertToSharedBudget(budget))); when(budgetServiceMock.updateBudgetWithAmountFields(any(), any())).thenReturn(succeededFuture()); - when(transactionServiceMock.retrieveTransactions(any(), any())).thenReturn(succeededFuture(transactions)); + when(transactionServiceMock.getBudgetTransactions(any(), any())).thenReturn(succeededFuture(transactions)); Future future = recalculateBudgetService.recalculateBudget(budget.getId(), requestContext); vertxTestContext.assertComplete(future) .onSuccess(result -> { verify(budgetServiceMock).getBudgetById(eq(budget.getId()), eq(requestContext)); - verify(transactionServiceMock).retrieveTransactions(eq(budget), eq(requestContext)); + verify(transactionServiceMock).getBudgetTransactions(eq(budget), eq(requestContext)); verify(budgetServiceMock).updateBudgetWithAmountFields(budgetCaptor.capture(), eq(requestContext)); SharedBudget capturedBudget = budgetCaptor.getValue(); diff --git a/src/test/java/org/folio/services/fiscalyear/FiscalYearApiServiceTest.java b/src/test/java/org/folio/services/fiscalyear/FiscalYearApiServiceTest.java new file mode 100644 index 00000000..98ee109c --- /dev/null +++ b/src/test/java/org/folio/services/fiscalyear/FiscalYearApiServiceTest.java @@ -0,0 +1,210 @@ +package org.folio.services.fiscalyear; + +import static io.vertx.core.Future.succeededFuture; +import static org.folio.rest.util.ResourcePathResolver.FISCAL_YEARS_STORAGE; +import static org.folio.rest.util.ResourcePathResolver.resourceByIdPath; +import static org.folio.services.protection.AcqUnitConstants.NO_ACQ_UNIT_ASSIGNED_CQL; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +import org.apache.commons.lang3.StringUtils; +import org.folio.rest.core.RestClient; +import org.folio.rest.core.models.RequestContext; +import org.folio.rest.jaxrs.model.Budget; +import org.folio.rest.jaxrs.model.BudgetsCollection; +import org.folio.rest.jaxrs.model.FinancialSummary; +import org.folio.rest.jaxrs.model.FiscalYear; +import org.folio.rest.jaxrs.model.FiscalYearsCollection; +import org.folio.services.budget.BudgetService; +import org.folio.services.configuration.ConfigurationEntriesService; +import org.folio.services.protection.AcqUnitsService; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import io.vertx.junit5.VertxExtension; +import io.vertx.junit5.VertxTestContext; + +@ExtendWith(VertxExtension.class) +public class FiscalYearApiServiceTest { + private FiscalYearApiService fiscalYearApiService; + private AutoCloseable mockitoMocks; + + @Mock + private RestClient restClient; + @Mock + private BudgetService budgetService; + @Mock + private RequestContext requestContext; + @Mock + private ConfigurationEntriesService configurationEntriesService; + @Mock + private AcqUnitsService acqUnitsService; + + @BeforeEach + public void initMocks() { + mockitoMocks = MockitoAnnotations.openMocks(this); + FiscalYearService fiscalYearService = new FiscalYearService(restClient); + fiscalYearApiService = new FiscalYearApiService(fiscalYearService, configurationEntriesService, budgetService, acqUnitsService); + } + + @AfterEach + public void afterEach() throws Exception { + mockitoMocks.close(); + } + + @Test + void shouldRetrieveBudgetsAndSumBudgetsTotalsWhenWithFinancialSummaryTrue(VertxTestContext vertxTestContext) { + String fiscalYearId = UUID.randomUUID().toString(); + FiscalYear fiscalYear = new FiscalYear().withId(fiscalYearId); + + Budget budget1 = new Budget() + .withInitialAllocation(0.03) + .withAllocationTo(1.04) + .withAllocationFrom(0.01) + .withAllocated(1.06) + .withNetTransfers(1.03) + .withAwaitingPayment(0.11) + .withEncumbered(0.47) + .withExpenditures(0.03) + .withUnavailable(0.61) + .withAvailable(1.48) + .withTotalFunding(2.09) + .withCashBalance(2.06) + .withOverEncumbrance(0d) + .withOverExpended(0d); + + Budget budget2 = new Budget() + .withInitialAllocation(0.03) + .withAllocationTo(1.04) + .withAllocationFrom(0.01) + .withAllocated(1.06) + .withNetTransfers(0d) + .withAwaitingPayment(0.11) + .withEncumbered(0.47) + .withExpenditures(1.03) + .withUnavailable(1.61) + .withAvailable(0d) + .withTotalFunding(1.06) + .withCashBalance(0.03) + .withOverEncumbrance(0d) + .withOverExpended(0.55d); + + BudgetsCollection budgetCollection = new BudgetsCollection().withBudgets(Arrays.asList(budget1, budget2)); + + when(restClient.get(eq(resourceByIdPath(FISCAL_YEARS_STORAGE, fiscalYearId)), eq(FiscalYear.class), eq(requestContext))) + .thenReturn(succeededFuture(fiscalYear)); + when(budgetService.getBudgets(eq("fiscalYearId==" + fiscalYearId), anyInt(), anyInt(), eq(requestContext))).thenReturn(succeededFuture(budgetCollection)); + + var future = fiscalYearApiService.getFiscalYearById(fiscalYearId, true, requestContext); + + vertxTestContext.assertComplete(future) + .onComplete(result -> { + FinancialSummary summary = result.result().getFinancialSummary(); + assertNotNull(summary); + assertEquals(0.06, summary.getInitialAllocation()); + assertEquals(2.08, summary.getAllocationTo()); + assertEquals(0.02, summary.getAllocationFrom()); + assertEquals(2.12, summary.getAllocated()); + assertEquals(0.22, summary.getAwaitingPayment()); + assertEquals(0.94, summary.getEncumbered()); + assertEquals(1.06, summary.getExpenditures()); + assertEquals(2.22, summary.getUnavailable()); + assertEquals(1.48, summary.getAvailable()); + assertEquals(3.15, summary.getTotalFunding()); + assertEquals(2.09, summary.getCashBalance()); + assertEquals(0d, summary.getOverEncumbrance()); + assertEquals(0.55, summary.getOverExpended()); + vertxTestContext.completeNow(); + }); + } + + @Test + void shouldHasEmptyTotalsWhenNoBudgetsFound(VertxTestContext vertxTestContext) { + String fiscalYearId = UUID.randomUUID().toString(); + FiscalYear fiscalYear = new FiscalYear().withId(fiscalYearId); + BudgetsCollection budgetCollection = new BudgetsCollection(); + + when(restClient.get(eq(resourceByIdPath(FISCAL_YEARS_STORAGE, fiscalYearId)), eq(FiscalYear.class), eq(requestContext))) + .thenReturn(succeededFuture(fiscalYear)); + when(budgetService.getBudgets(eq("fiscalYearId==" + fiscalYearId), anyInt(), anyInt(), eq(requestContext))).thenReturn(succeededFuture(budgetCollection)); + + var future = fiscalYearApiService.getFiscalYearById(fiscalYearId, true, requestContext); + + vertxTestContext.assertComplete(future) + .onComplete(result -> { + FinancialSummary summary = result.result().getFinancialSummary(); + assertNotNull(summary); + assertEquals(0d, summary.getInitialAllocation()); + assertEquals(0d, summary.getAllocationTo()); + assertEquals(0d, summary.getAllocationFrom()); + assertEquals(0d, summary.getAllocated()); + assertEquals(0d, summary.getAwaitingPayment()); + assertEquals(0d, summary.getEncumbered()); + assertEquals(0d, summary.getExpenditures()); + assertEquals(0d, summary.getUnavailable()); + assertEquals(0d, summary.getAvailable()); + assertEquals(0d, summary.getTotalFunding()); + assertEquals(0d, summary.getCashBalance()); + assertEquals(0d, summary.getOverEncumbrance()); + assertEquals(0d, summary.getOverExpended()); + vertxTestContext.completeNow(); + }); + } + + @Test + void shouldNotRetrieveBudgetsAndSumBudgetsTotalsWhenWithFinancialSummaryFalse(VertxTestContext vertxTestContext) { + String fiscalYearId = UUID.randomUUID().toString(); + FiscalYear fiscalYear = new FiscalYear().withId(fiscalYearId); + + when(restClient.get(eq(resourceByIdPath(FISCAL_YEARS_STORAGE, fiscalYearId)), eq(FiscalYear.class), eq(requestContext))) + .thenReturn(succeededFuture(fiscalYear)); + + var future = fiscalYearApiService.getFiscalYearById(fiscalYearId, false, requestContext); + vertxTestContext.assertComplete(future) + .onComplete(result -> { + FinancialSummary summary = result.result().getFinancialSummary(); + assertNull(summary); + verify(budgetService, never()).getBudgets(any(), anyInt(), anyInt(), any()); + vertxTestContext.completeNow(); + }); + } + + @Test + void testShouldRetrieveFiscalYearsWithAcqUnits(VertxTestContext vertxTestContext) { + //Given + FiscalYear fiscalYear = new FiscalYear().withId(UUID.randomUUID().toString()).withCode("TST"); + FiscalYearsCollection fiscalYearsCollection = new FiscalYearsCollection().withFiscalYears(List.of(fiscalYear)).withTotalRecords(1); + doReturn(succeededFuture(NO_ACQ_UNIT_ASSIGNED_CQL)).when(acqUnitsService).buildAcqUnitsCqlClause(requestContext); + doReturn(succeededFuture(fiscalYearsCollection)) + .when(restClient).get(any(), eq(FiscalYearsCollection.class), eq(requestContext)); + //When + var future = fiscalYearApiService.getFiscalYearsWithAcqUnitsRestriction(StringUtils.EMPTY, 0,10, requestContext); + //Then + vertxTestContext.assertComplete(future) + .onComplete(result -> { + assertThat(fiscalYearsCollection, equalTo(result.result())); + verify(restClient).get(anyString(), eq(FiscalYearsCollection.class), eq(requestContext)); + vertxTestContext.completeNow(); + }); + } + +} diff --git a/src/test/java/org/folio/services/fiscalyear/FiscalYearServiceTest.java b/src/test/java/org/folio/services/fiscalyear/FiscalYearServiceTest.java index f8ac674d..d9053581 100644 --- a/src/test/java/org/folio/services/fiscalyear/FiscalYearServiceTest.java +++ b/src/test/java/org/folio/services/fiscalyear/FiscalYearServiceTest.java @@ -1,47 +1,32 @@ package org.folio.services.fiscalyear; import static io.vertx.core.Future.succeededFuture; -import static org.folio.rest.util.ResourcePathResolver.FISCAL_YEARS_STORAGE; -import static org.folio.rest.util.ResourcePathResolver.resourceByIdPath; import static org.folio.rest.util.TestUtils.assertQueryContains; -import static org.folio.services.protection.AcqUnitConstants.NO_ACQ_UNIT_ASSIGNED_CQL; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.UUID; -import org.apache.commons.lang3.StringUtils; import org.folio.rest.core.RestClient; import org.folio.rest.core.models.RequestContext; import org.folio.rest.exception.HttpException; -import org.folio.rest.jaxrs.model.Budget; -import org.folio.rest.jaxrs.model.BudgetsCollection; -import org.folio.rest.jaxrs.model.FinancialSummary; import org.folio.rest.jaxrs.model.FiscalYear; import org.folio.rest.jaxrs.model.FiscalYearsCollection; -import org.folio.services.budget.BudgetService; -import org.folio.services.protection.AcqUnitsService; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -51,182 +36,53 @@ @ExtendWith(VertxExtension.class) public class FiscalYearServiceTest { + private FiscalYearService fiscalYearService; + private AutoCloseable mockitoMocks; + + @Mock + private RestClient restClient; + @Mock + private RequestContext requestContext; + + @BeforeEach + public void initMocks() { + mockitoMocks = MockitoAnnotations.openMocks(this); + fiscalYearService = new FiscalYearService(restClient); + } - @InjectMocks - private FiscalYearService fiscalYearService; - - @Mock - private RestClient restClient; - - @Mock - private BudgetService budgetService; - - @Mock - private RequestContext requestContext; - - @Mock - private AcqUnitsService acqUnitsService; - - @BeforeEach - public void initMocks() { - MockitoAnnotations.openMocks(this); - } - - @Test - void shouldRetrieveBudgetsAndSumBudgetsTotalsWhenWithFinancialSummaryTrue(VertxTestContext vertxTestContext) { - - String fiscalYearId = UUID.randomUUID().toString(); - - FiscalYear fiscalYear = new FiscalYear().withId(fiscalYearId); - - Budget budget1 = new Budget() - .withInitialAllocation(0.03) - .withAllocationTo(1.04) - .withAllocationFrom(0.01) - .withAllocated(1.06) - .withNetTransfers(1.03) - .withAwaitingPayment(0.11) - .withEncumbered(0.47) - .withExpenditures(0.03) - .withUnavailable(0.61) - .withAvailable(1.48) - .withTotalFunding(2.09) - .withCashBalance(2.06) - .withOverEncumbrance(0d) - .withOverExpended(0d); - - Budget budget2 = new Budget() - .withInitialAllocation(0.03) - .withAllocationTo(1.04) - .withAllocationFrom(0.01) - .withAllocated(1.06) - .withNetTransfers(0d) - .withAwaitingPayment(0.11) - .withEncumbered(0.47) - .withExpenditures(1.03) - .withUnavailable(1.61) - .withAvailable(0d) - .withTotalFunding(1.06) - .withCashBalance(0.03) - .withOverEncumbrance(0d) - .withOverExpended(0.55d); - - BudgetsCollection budgetCollection = new BudgetsCollection().withBudgets(Arrays.asList(budget1, budget2)); - - when(restClient.get(eq(resourceByIdPath(FISCAL_YEARS_STORAGE, fiscalYearId)), eq(FiscalYear.class), eq(requestContext))) - .thenReturn(succeededFuture(fiscalYear)); - when(budgetService.getBudgets(eq("fiscalYearId==" + fiscalYearId), anyInt(), anyInt(), eq(requestContext))).thenReturn(succeededFuture(budgetCollection)); - - var future = fiscalYearService.getFiscalYearById(fiscalYearId, true, requestContext); - - vertxTestContext.assertComplete(future) - .onComplete(result -> { - FinancialSummary summary = result.result().getFinancialSummary(); - assertNotNull(summary); - assertEquals(0.06, summary.getInitialAllocation()); - assertEquals(2.08, summary.getAllocationTo()); - assertEquals(0.02, summary.getAllocationFrom()); - assertEquals(2.12, summary.getAllocated()); - assertEquals(0.22, summary.getAwaitingPayment()); - assertEquals(0.94, summary.getEncumbered()); - assertEquals(1.06, summary.getExpenditures()); - assertEquals(2.22, summary.getUnavailable()); - assertEquals(1.48, summary.getAvailable()); - assertEquals(3.15, summary.getTotalFunding()); - assertEquals(2.09, summary.getCashBalance()); - assertEquals(0d, summary.getOverEncumbrance()); - assertEquals(0.55, summary.getOverExpended()); - vertxTestContext.completeNow(); - }); - - } - - @Test - void shouldHasEmptyTotalsWhenNoBudgetsFound(VertxTestContext vertxTestContext) { - - String fiscalYearId = UUID.randomUUID().toString(); - - FiscalYear fiscalYear = new FiscalYear().withId(fiscalYearId); - - BudgetsCollection budgetCollection = new BudgetsCollection(); - - when(restClient.get(eq(resourceByIdPath(FISCAL_YEARS_STORAGE, fiscalYearId)), eq(FiscalYear.class), eq(requestContext))) - .thenReturn(succeededFuture(fiscalYear)); - when(budgetService.getBudgets(eq("fiscalYearId==" + fiscalYearId), anyInt(), anyInt(), eq(requestContext))).thenReturn(succeededFuture(budgetCollection)); - - var future = fiscalYearService.getFiscalYearById(fiscalYearId, true, requestContext); - - vertxTestContext.assertComplete(future) - .onComplete(result -> { - FinancialSummary summary = result.result().getFinancialSummary(); - assertNotNull(summary); - assertEquals(0d, summary.getInitialAllocation()); - assertEquals(0d, summary.getAllocationTo()); - assertEquals(0d, summary.getAllocationFrom()); - assertEquals(0d, summary.getAllocated()); - assertEquals(0d, summary.getAwaitingPayment()); - assertEquals(0d, summary.getEncumbered()); - assertEquals(0d, summary.getExpenditures()); - assertEquals(0d, summary.getUnavailable()); - assertEquals(0d, summary.getAvailable()); - assertEquals(0d, summary.getTotalFunding()); - assertEquals(0d, summary.getCashBalance()); - assertEquals(0d, summary.getOverEncumbrance()); - assertEquals(0d, summary.getOverExpended()); - vertxTestContext.completeNow(); - }); - } - - @Test - void shouldNotRetrieveBudgetsAndSumBudgetsTotalsWhenWithFinancialSummaryFalse(VertxTestContext vertxTestContext) { - - String fiscalYearId = UUID.randomUUID().toString(); - - FiscalYear fiscalYear = new FiscalYear().withId(fiscalYearId); - - when(restClient.get(eq(resourceByIdPath(FISCAL_YEARS_STORAGE, fiscalYearId)), eq(FiscalYear.class), eq(requestContext))) - .thenReturn(succeededFuture(fiscalYear)); - - var future = fiscalYearService.getFiscalYearById(fiscalYearId, false, requestContext); - vertxTestContext.assertComplete(future) - .onComplete(result -> { - FinancialSummary summary = result.result().getFinancialSummary(); - assertNull(summary); - verify(budgetService, never()).getBudgets(any(), anyInt(), anyInt(), any()); - vertxTestContext.completeNow(); - }); - } + @AfterEach + public void afterEach() throws Exception { + mockitoMocks.close(); + } - @Test - void testGetFiscalYearByFiscalYearCode(VertxTestContext vertxTestContext) { - FiscalYear fiscalYear = new FiscalYear() - .withCode("FUND CODE"); - String fiscalYearCode = "FiscalCode"; - String query = getFiscalYearByFiscalYearCode(fiscalYearCode); - List fiscalYearList = new ArrayList<>(); - fiscalYearList.add(fiscalYear); - FiscalYearsCollection fiscalYearsCollection = new FiscalYearsCollection(); - fiscalYearsCollection.setTotalRecords(10); - fiscalYearsCollection.setFiscalYears(fiscalYearList); - when(restClient.get(anyString(), eq(FiscalYearsCollection.class), eq(requestContext))) - .thenReturn(succeededFuture(fiscalYearsCollection)); + @Test + void testGetFiscalYearByFiscalYearCode(VertxTestContext vertxTestContext) { + FiscalYear fiscalYear = new FiscalYear() + .withCode("FUND CODE"); + String fiscalYearCode = "FiscalCode"; + List fiscalYearList = new ArrayList<>(); + fiscalYearList.add(fiscalYear); + FiscalYearsCollection fiscalYearsCollection = new FiscalYearsCollection(); + fiscalYearsCollection.setTotalRecords(10); + fiscalYearsCollection.setFiscalYears(fiscalYearList); + when(restClient.get(anyString(), eq(FiscalYearsCollection.class), eq(requestContext))) + .thenReturn(succeededFuture(fiscalYearsCollection)); - assertThat(fiscalYearsCollection.getFiscalYears(), is(not(empty()))); + assertThat(fiscalYearsCollection.getFiscalYears(), is(not(empty()))); - var future = fiscalYearService.getFiscalYearByFiscalYearCode(fiscalYearCode, requestContext); + var future = fiscalYearService.getFiscalYearByFiscalYearCode(fiscalYearCode, requestContext); - vertxTestContext.assertComplete(future) - .onSuccess(result -> { - assertEquals("FUND CODE", future.result().getCode()); + vertxTestContext.assertComplete(future) + .onSuccess(result -> { + assertEquals("FUND CODE", future.result().getCode()); - vertxTestContext.completeNow(); - }); - } + vertxTestContext.completeNow(); + }); + } @Test void testGetFiscalYearByFiscalYearCodeWithEmptyCollection(VertxTestContext vertxTestContext) { String fiscalYearCode = "FiscalCode"; - String query = getFiscalYearByFiscalYearCode(fiscalYearCode); FiscalYearsCollection fiscalYearsCollection = new FiscalYearsCollection(); when(restClient.get(anyString(), eq(FiscalYearsCollection.class), eq(requestContext))) .thenReturn(succeededFuture(fiscalYearsCollection)); @@ -241,25 +97,6 @@ void testGetFiscalYearByFiscalYearCodeWithEmptyCollection(VertxTestContext vertx } - @Test - void testShouldRetrieveFiscalYearsWithAcqUnits(VertxTestContext vertxTestContext) { - //Given - FiscalYear fiscalYear = new FiscalYear().withId(UUID.randomUUID().toString()).withCode("TST"); - FiscalYearsCollection fiscalYearsCollection = new FiscalYearsCollection().withFiscalYears(List.of(fiscalYear)).withTotalRecords(1); - doReturn(succeededFuture(NO_ACQ_UNIT_ASSIGNED_CQL)).when(acqUnitsService).buildAcqUnitsCqlClause(requestContext); - doReturn(succeededFuture(fiscalYearsCollection)) - .when(restClient).get(any(), eq(FiscalYearsCollection.class), eq(requestContext)); - //When - var future = fiscalYearService.getFiscalYearsWithAcqUnitsRestriction(StringUtils.EMPTY, 0,10, requestContext); - //Then - vertxTestContext.assertComplete(future) - .onComplete(result -> { - assertThat(fiscalYearsCollection, equalTo(result.result())); - verify(restClient).get(anyString(), eq(FiscalYearsCollection.class), eq(requestContext)); - vertxTestContext.completeNow(); - }); - } - @Test void testShouldRetrieveFiscalYearsWithoutAcqUnits(VertxTestContext vertxTestContext) { //Given @@ -276,11 +113,6 @@ void testShouldRetrieveFiscalYearsWithoutAcqUnits(VertxTestContext vertxTestCont verify(restClient).get(assertQueryContains("test_query"), eq(FiscalYearsCollection.class), eq(requestContext)); vertxTestContext.completeNow(); }); - } - public String getFiscalYearByFiscalYearCode(String fiscalYearCode) { - return String.format("code=%s", fiscalYearCode); - } - } diff --git a/src/test/java/org/folio/services/fund/FundCodeExpenseClassesServiceTest.java b/src/test/java/org/folio/services/fund/FundCodeExpenseClassesServiceTest.java index c45c5344..364b8fdd 100644 --- a/src/test/java/org/folio/services/fund/FundCodeExpenseClassesServiceTest.java +++ b/src/test/java/org/folio/services/fund/FundCodeExpenseClassesServiceTest.java @@ -172,7 +172,7 @@ public void shouldRetrieveCombinationFundCodeExpClassesWithFiscalYear(VertxTestC .withId(fundId2); List funds = Arrays.asList(fund1, fund2); - when(fundService.getFunds(any(), eq(requestContext))).thenReturn(succeededFuture(funds)); + when(fundService.getFundsByIds(any(), eq(requestContext))).thenReturn(succeededFuture(funds)); Ledger ledger1 = new Ledger() .withLedgerStatus(Ledger.LedgerStatus.ACTIVE) @@ -316,7 +316,7 @@ public void shouldRetrieveCombinationFundCodeExpClassesWithoutFiscalYear(VertxTe .withId(fundId2); List funds = Arrays.asList(fund1, fund2); - when(fundService.getFunds(any(), eq(requestContext))).thenReturn(succeededFuture(funds)); + when(fundService.getFundsByIds(any(), eq(requestContext))).thenReturn(succeededFuture(funds)); when(ledgerService.getLedgers(any(), eq(requestContext))).thenReturn(succeededFuture(ledgers)); diff --git a/src/test/java/org/folio/services/fund/FundServiceTest.java b/src/test/java/org/folio/services/fund/FundServiceTest.java index c240fa8e..5b4ba61e 100644 --- a/src/test/java/org/folio/services/fund/FundServiceTest.java +++ b/src/test/java/org/folio/services/fund/FundServiceTest.java @@ -255,7 +255,7 @@ void testGetFunds(VertxTestContext vertxTestContext) { fundsCollection.setFunds(fundsList); // When when(restClient.get(anyString(), eq(FundsCollection.class), any())).thenReturn(succeededFuture(fundsCollection)); - var future = fundService.getFunds(ids, requestContext); + var future = fundService.getFundsByIds(ids, requestContext); // Then vertxTestContext.assertComplete(future) .onComplete(result -> { diff --git a/src/test/java/org/folio/services/group/GroupExpenseClassTotalsServiceTest.java b/src/test/java/org/folio/services/group/GroupExpenseClassTotalsServiceTest.java index 138c2da8..ee08d704 100644 --- a/src/test/java/org/folio/services/group/GroupExpenseClassTotalsServiceTest.java +++ b/src/test/java/org/folio/services/group/GroupExpenseClassTotalsServiceTest.java @@ -26,7 +26,7 @@ import org.folio.rest.jaxrs.model.GroupFundFiscalYear; import org.folio.rest.jaxrs.model.Transaction; import org.folio.services.ExpenseClassService; -import org.folio.services.transactions.CommonTransactionService; +import org.folio.services.transactions.TransactionService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -49,7 +49,7 @@ public class GroupExpenseClassTotalsServiceTest { private GroupFundFiscalYearService groupFundFiscalYearServiceMock; @Mock - private CommonTransactionService transactionServiceMock; + private TransactionService transactionServiceMock; @Mock private ExpenseClassService expenseClassServiceMock; @@ -80,7 +80,7 @@ void getExpenseClassTotalsEmptyGroupFundFiscalYearResponse(VertxTestContext vert var groupExpenseClassTotalsCollection = result.result(); assertEquals(new GroupExpenseClassTotalsCollection().withTotalRecords(0), groupExpenseClassTotalsCollection); verify(groupFundFiscalYearServiceMock).getGroupFundFiscalYearsWithBudgetId(groupId, fiscalYearId, requestContext); - verify(transactionServiceMock, never()).retrieveTransactionsByFundIds(anyList(), anyString(), any()); + verify(transactionServiceMock, never()).getTransactionsByFundIds(anyList(), anyString(), any()); verify(expenseClassServiceMock, never()).getExpenseClassesByBudgetIds(anyList(), any()); vertxTestContext.completeNow(); @@ -106,7 +106,7 @@ void getExpenseClassTotalsEmptyExpenseClassesResponse(VertxTestContext vertxTest when(groupFundFiscalYearServiceMock.getGroupFundFiscalYearsWithBudgetId(anyString(), anyString(), any())) .thenReturn(succeededFuture(Collections.singletonList(groupFundFiscalYear))); - when(transactionServiceMock.retrieveTransactionsByFundIds(anyList(), anyString(), any())) + when(transactionServiceMock.getTransactionsByFundIds(anyList(), anyString(), any())) .thenReturn(succeededFuture(Collections.singletonList(transaction))); when(expenseClassServiceMock.getExpenseClassesByBudgetIds(anyList(), any())) .thenReturn(succeededFuture(Collections.emptyList())); @@ -117,7 +117,7 @@ void getExpenseClassTotalsEmptyExpenseClassesResponse(VertxTestContext vertxTest var groupExpenseClassTotalsCollection = result.result(); assertEquals(new GroupExpenseClassTotalsCollection().withTotalRecords(0), groupExpenseClassTotalsCollection); verify(groupFundFiscalYearServiceMock).getGroupFundFiscalYearsWithBudgetId(eq(groupId), eq(fiscalYearId), eq(requestContext)); - verify(transactionServiceMock).retrieveTransactionsByFundIds(eq(Collections.singletonList(groupFundFiscalYear.getFundId())), eq(fiscalYearId), eq(requestContext)); + verify(transactionServiceMock).getTransactionsByFundIds(eq(Collections.singletonList(groupFundFiscalYear.getFundId())), eq(fiscalYearId), eq(requestContext)); verify(expenseClassServiceMock).getExpenseClassesByBudgetIds(eq(Collections.singletonList(groupFundFiscalYear.getBudgetId())), eq(requestContext)); vertxTestContext.completeNow(); @@ -139,7 +139,7 @@ void getExpenseClassTotalsEmptyTransactionsResponse(VertxTestContext vertxTestCo when(groupFundFiscalYearServiceMock.getGroupFundFiscalYearsWithBudgetId(anyString(), anyString(), any())) .thenReturn(succeededFuture(Collections.singletonList(groupFundFiscalYear))); - when(transactionServiceMock.retrieveTransactionsByFundIds(anyList(), anyString(), any())) + when(transactionServiceMock.getTransactionsByFundIds(anyList(), anyString(), any())) .thenReturn(succeededFuture(Collections.emptyList())); when(expenseClassServiceMock.getExpenseClassesByBudgetIds(anyList(), any())) .thenReturn(succeededFuture(Collections.singletonList(expenseClass))); @@ -156,7 +156,7 @@ void getExpenseClassTotalsEmptyTransactionsResponse(VertxTestContext vertxTestCo assertEquals(0d, groupExpenseClassTotal.getPercentageExpended()); verify(groupFundFiscalYearServiceMock).getGroupFundFiscalYearsWithBudgetId(eq(groupId), eq(fiscalYearId), eq(requestContext)); - verify(transactionServiceMock).retrieveTransactionsByFundIds(eq(Collections.singletonList(groupFundFiscalYear.getFundId())), eq(fiscalYearId), eq(requestContext)); + verify(transactionServiceMock).getTransactionsByFundIds(eq(Collections.singletonList(groupFundFiscalYear.getFundId())), eq(fiscalYearId), eq(requestContext)); verify(expenseClassServiceMock).getExpenseClassesByBudgetIds(eq(Collections.singletonList(groupFundFiscalYear.getBudgetId())), eq(requestContext)); vertxTestContext.completeNow(); @@ -254,7 +254,7 @@ void getExpenseClassTotalsMultipleRecords(VertxTestContext vertxTestContext) { when(groupFundFiscalYearServiceMock.getGroupFundFiscalYearsWithBudgetId(anyString(), anyString(), any())) .thenReturn(succeededFuture(Arrays.asList(groupFundFiscalYear1, groupFundFiscalYear2))); - when(transactionServiceMock.retrieveTransactionsByFundIds(anyList(), anyString(), any())) + when(transactionServiceMock.getTransactionsByFundIds(anyList(), anyString(), any())) .thenReturn(succeededFuture(transactions)); when(expenseClassServiceMock.getExpenseClassesByBudgetIds(anyList(), any())) .thenReturn(succeededFuture(Arrays.asList(expenseClass1, expenseClass2))); @@ -287,7 +287,7 @@ void getExpenseClassTotalsMultipleRecords(VertxTestContext vertxTestContext) { List expectedFundIds = new ArrayList<>(); expectedFundIds.add(fundId1); expectedFundIds.add(fundId2); - verify(transactionServiceMock).retrieveTransactionsByFundIds(eq(expectedFundIds), eq(fiscalYearId), eq(requestContext)); + verify(transactionServiceMock).getTransactionsByFundIds(eq(expectedFundIds), eq(fiscalYearId), eq(requestContext)); List expectedBudgetIds = new ArrayList<>(); expectedBudgetIds.add(budgetId1); diff --git a/src/test/java/org/folio/services/ledger/LedgerTotalsServiceTest.java b/src/test/java/org/folio/services/ledger/LedgerTotalsServiceTest.java index 71fd0fc8..88cba8cb 100644 --- a/src/test/java/org/folio/services/ledger/LedgerTotalsServiceTest.java +++ b/src/test/java/org/folio/services/ledger/LedgerTotalsServiceTest.java @@ -39,7 +39,7 @@ import org.folio.rest.jaxrs.model.Transaction; import org.folio.services.budget.BudgetService; import org.folio.services.fiscalyear.FiscalYearService; -import org.folio.services.transactions.BaseTransactionService; +import org.folio.services.transactions.TransactionService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -65,7 +65,7 @@ public class LedgerTotalsServiceTest { private BudgetService budgetMockService; @Mock - private BaseTransactionService baseTransactionService; + private TransactionService transactionService; @Mock private RequestContext requestContextMock; @@ -146,17 +146,17 @@ void shouldCalculateFromRelatedBudgetsAndPopulateLedgerTotalsWhenCallPopulateLed when(fiscalYearService.getFiscalYearById(anyString(), any())).thenReturn(succeededFuture(fiscalYear)); when(budgetMockService.getBudgets(anyString(), anyInt(), anyInt(), any())).thenReturn(succeededFuture(budgetsCollection)); - when(baseTransactionService.retrieveToTransactions(anyList(), eq(fiscalYearId), argThat(list -> list.contains(ALLOCATION)), + when(transactionService.getTransactionsToFunds(anyList(), eq(fiscalYearId), argThat(list -> list.contains(ALLOCATION)), eq(requestContextMock))) .thenReturn(succeededFuture(allocToTrs)); - when(baseTransactionService.retrieveFromTransactions(anyList(), eq(fiscalYearId), argThat(list -> list.contains(ALLOCATION)), + when(transactionService.getTransactionsFromFunds(anyList(), eq(fiscalYearId), argThat(list -> list.contains(ALLOCATION)), eq(requestContextMock))) .thenReturn(succeededFuture(singletonList(allocFromTr))); List transfers = List.of(TRANSFER, ROLLOVER_TRANSFER); - when(baseTransactionService.retrieveToTransactions(anyList(), eq(fiscalYearId), argThat(list -> list.containsAll(transfers)), + when(transactionService.getTransactionsToFunds(anyList(), eq(fiscalYearId), argThat(list -> list.containsAll(transfers)), eq(requestContextMock))) .thenReturn(succeededFuture(List.of(tranToTr, tranToRollTr))); - when(baseTransactionService.retrieveFromTransactions(anyList(), eq(fiscalYearId), argThat(list -> list.containsAll(transfers)), + when(transactionService.getTransactionsFromFunds(anyList(), eq(fiscalYearId), argThat(list -> list.containsAll(transfers)), eq(requestContextMock))) .thenReturn(succeededFuture(List.of(tranFromTr, tranFromRollTr))); @@ -221,17 +221,17 @@ void shouldPopulateLedgerZeroTotalsIfNoBudgetsWhenCallPopulateLedgerTotals(Vertx when(budgetMockService.getBudgets(anyString(), anyInt(), anyInt(), any())).thenReturn(succeededFuture(budgetsCollection)); when(fiscalYearService.getFiscalYearById(anyString(), any())).thenReturn(succeededFuture(fiscalYear)); when(budgetMockService.getBudgets(anyString(), anyInt(), anyInt(), any())).thenReturn(succeededFuture(budgetsCollection)); - when(baseTransactionService.retrieveToTransactions(anyList(), eq(fiscalYearId), argThat(list -> list.contains(ALLOCATION)), + when(transactionService.getTransactionsToFunds(anyList(), eq(fiscalYearId), argThat(list -> list.contains(ALLOCATION)), eq(requestContextMock))) .thenReturn(succeededFuture(Collections.EMPTY_LIST)); - when(baseTransactionService.retrieveFromTransactions(anyList(), eq(fiscalYearId), argThat(list -> list.contains(ALLOCATION)), + when(transactionService.getTransactionsFromFunds(anyList(), eq(fiscalYearId), argThat(list -> list.contains(ALLOCATION)), eq(requestContextMock))) .thenReturn(succeededFuture(Collections.EMPTY_LIST)); List transfers = List.of(TRANSFER, ROLLOVER_TRANSFER); - when(baseTransactionService.retrieveToTransactions(anyList(), eq(fiscalYearId), argThat(list -> list.containsAll(transfers)), + when(transactionService.getTransactionsToFunds(anyList(), eq(fiscalYearId), argThat(list -> list.containsAll(transfers)), eq(requestContextMock))) .thenReturn(succeededFuture(Collections.EMPTY_LIST)); - when(baseTransactionService.retrieveFromTransactions(anyList(), eq(fiscalYearId), argThat(list -> list.containsAll(transfers)), + when(transactionService.getTransactionsFromFunds(anyList(), eq(fiscalYearId), argThat(list -> list.containsAll(transfers)), eq(requestContextMock))) .thenReturn(succeededFuture(Collections.EMPTY_LIST)); @@ -282,17 +282,17 @@ void shouldRetrieveBudgetsForEveryLedgerWhenCallPopulateLedgersTotals(VertxTestC when(budgetMockService.getBudgets(anyString(), anyInt(), anyInt(), any())).thenReturn(succeededFuture(budgetsCollection)); when(fiscalYearService.getFiscalYearById(anyString(), any())).thenReturn(succeededFuture(fiscalYear)); when(budgetMockService.getBudgets(anyString(), anyInt(), anyInt(), any())).thenReturn(succeededFuture(budgetsCollection)); - when(baseTransactionService.retrieveToTransactions(anyList(), eq(fiscalYearId), argThat(list -> list.contains(ALLOCATION)), + when(transactionService.getTransactionsToFunds(anyList(), eq(fiscalYearId), argThat(list -> list.contains(ALLOCATION)), eq(requestContextMock))) .thenReturn(succeededFuture(Collections.EMPTY_LIST)); - when(baseTransactionService.retrieveFromTransactions(anyList(), eq(fiscalYearId), argThat(list -> list.contains(ALLOCATION)), + when(transactionService.getTransactionsFromFunds(anyList(), eq(fiscalYearId), argThat(list -> list.contains(ALLOCATION)), eq(requestContextMock))) .thenReturn(succeededFuture(Collections.EMPTY_LIST)); List transfers = List.of(TRANSFER, ROLLOVER_TRANSFER); - when(baseTransactionService.retrieveToTransactions(anyList(), eq(fiscalYearId), argThat(list -> list.containsAll(transfers)), + when(transactionService.getTransactionsToFunds(anyList(), eq(fiscalYearId), argThat(list -> list.containsAll(transfers)), eq(requestContextMock))) .thenReturn(succeededFuture(Collections.EMPTY_LIST)); - when(baseTransactionService.retrieveFromTransactions(anyList(), eq(fiscalYearId), argThat(list -> list.containsAll(transfers)), + when(transactionService.getTransactionsFromFunds(anyList(), eq(fiscalYearId), argThat(list -> list.containsAll(transfers)), eq(requestContextMock))) .thenReturn(succeededFuture(Collections.EMPTY_LIST)); diff --git a/src/test/java/org/folio/services/transactions/BatchTransactionServiceTest.java b/src/test/java/org/folio/services/transactions/TransactionApiServiceTest.java similarity index 76% rename from src/test/java/org/folio/services/transactions/BatchTransactionServiceTest.java rename to src/test/java/org/folio/services/transactions/TransactionApiServiceTest.java index 2d640110..0d8c7fb5 100644 --- a/src/test/java/org/folio/services/transactions/BatchTransactionServiceTest.java +++ b/src/test/java/org/folio/services/transactions/TransactionApiServiceTest.java @@ -8,10 +8,15 @@ import org.folio.rest.core.models.RequestContext; import org.folio.rest.jaxrs.model.Batch; import org.folio.rest.jaxrs.model.TransactionCollection; +import org.folio.services.fiscalyear.FiscalYearService; +import org.folio.services.fund.FundService; +import org.folio.services.protection.AcqUnitsService; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.mockito.junit.jupiter.MockitoExtension; import java.net.URLEncoder; @@ -29,18 +34,30 @@ import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) -public class BatchTransactionServiceTest { +public class TransactionApiServiceTest { + private TransactionApiService transactionApiService; + private AutoCloseable mockitoMocks; + @Mock private RestClient restClient; @Mock private RequestContext requestContext; - - private BatchTransactionService batchTransactionService; + @Mock + private FiscalYearService fiscalYearService; + @Mock + private AcqUnitsService acqUnitsService; @BeforeEach void init() { - BaseTransactionService baseTransactionService = new BaseTransactionService(restClient); - batchTransactionService = new BatchTransactionService(restClient, baseTransactionService); + mockitoMocks = MockitoAnnotations.openMocks(this); + FundService fundService = new FundService(restClient, acqUnitsService); + TransactionService transactionService = new TransactionService(restClient, fiscalYearService); + transactionApiService = new TransactionApiService(transactionService, fundService); + } + + @AfterEach + public void afterEach() throws Exception { + mockitoMocks.close(); } @Test @@ -77,7 +94,7 @@ void testRemovingEncumbranceWithPendingPaymentUpdate() { when(restClient.postEmptyResponse(eq(resourcesPath(BATCH_TRANSACTIONS_STORAGE)), any(Batch.class), eq(requestContext))) .thenReturn(Future.succeededFuture()); - Future result = batchTransactionService.processBatch(batch, requestContext); + Future result = transactionApiService.processBatch(batch, requestContext); assertTrue(result.succeeded()); } } diff --git a/src/test/resources/mockdata/transaction-summaries/invoice_transaction_summary.json b/src/test/resources/mockdata/transaction-summaries/invoice_transaction_summary.json deleted file mode 100644 index dfdda428..00000000 --- a/src/test/resources/mockdata/transaction-summaries/invoice_transaction_summary.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id" : "252e326e-bbae-48ec-96a7-6c57e76555eb", - "numPendingPayments" : 1, - "numPaymentsCredits" : 1 -} diff --git a/src/test/resources/mockdata/transaction-summaries/order_transaction_summary.json b/src/test/resources/mockdata/transaction-summaries/order_transaction_summary.json deleted file mode 100644 index d2f6120d..00000000 --- a/src/test/resources/mockdata/transaction-summaries/order_transaction_summary.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "id": "0610be6d-0ddd-494b-b867-19f63d8b5d6d", - "numTransactions": 4 -} diff --git a/src/test/resources/mockdata/transactions/credits.json b/src/test/resources/mockdata/transactions/credits.json deleted file mode 100644 index 00778940..00000000 --- a/src/test/resources/mockdata/transactions/credits.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "transactions": [ - { - "id": "1d005509-ce25-4bd6-80d1-52fadf2dfc83", - "amount": 25.17, - "currency": "USD", - "description": "PO_Line: History of Incas", - "fiscalYearId": "684b5dc5-92f6-4db7-b996-b549d88f5e4e", - "fromFundId": "67cd0046-e4f1-4e4f-9024-adf0b0039d09", - "paymentEncumbranceId": "80c28fb4-c34e-48d6-b8c2-de6660c3e0aa", - "source": "Invoice", - "tags": { - "tagList": [ - "important" - ] - }, - "toFundId": "69640328-788e-43fc-9c3c-af39e243f3b7", - "transactionType": "Credit" - } - ], - "totalRecords": 1 -} diff --git a/src/test/resources/mockdata/transactions/payments.json b/src/test/resources/mockdata/transactions/payments.json deleted file mode 100644 index f59feb99..00000000 --- a/src/test/resources/mockdata/transactions/payments.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "transactions": [ - { - "id": "c21333a0-ddc7-4156-9feb-b0f8432fc64f", - "amount": 25.17, - "currency": "USD", - "description": "PO_Line: History of Incas", - "fiscalYearId": "684b5dc5-92f6-4db7-b996-b549d88f5e4e", - "fromFundId": "67cd0046-e4f1-4e4f-9024-adf0b0039d09", - "paymentEncumbranceId": "80c28fb4-c34e-48d6-b8c2-de6660c3e0aa", - "source": "Invoice", - "tags": { - "tagList": [ - "important" - ] - }, - "toFundId": "69640328-788e-43fc-9c3c-af39e243f3b7", - "transactionType": "Payment" - } - ], - "totalRecords": 1 -} diff --git a/src/test/resources/mockdata/transactions/pending-payments.json b/src/test/resources/mockdata/transactions/pending-payments.json deleted file mode 100644 index 80543bc9..00000000 --- a/src/test/resources/mockdata/transactions/pending-payments.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "transactions": [ - { - "id": "c5732efb-9536-4a49-a22e-1ec6ca8a7922", - "amount": 25, - "awaitingPayment": { - "encumbranceId": "12ac70a4-5c9d-112f-9acb-852adf67d7e1", - "releaseEncumbrance": "true" - }, - "currency": "USD", - "description": "PO_Line: History of Incas", - "fiscalYearId": "684b5dc5-92f6-4db7-b996-b549d88f5e4e", - "fromFundId": "7fbd5d84-62d1-44c6-9c45-6cb173998bbd", - "source": "Invoice", - "sourceInvoiceId": "5925e966-f242-4842-9d5e-b33a651bb390", - "sourceInvoiceLineId": "ee60ee78-f487-4940-adcf-fa0726989823", - "transactionType": "Pending payment" - } - ], - "totalRecords": 1 -}