From 6a2bebb62c1678e20e7825e9e08174016f509da2 Mon Sep 17 00:00:00 2001
From: Azizbek Khushvakov <113523904+azizbekxm@users.noreply.github.com>
Date: Fri, 15 Nov 2024 16:16:41 +0500
Subject: [PATCH] [MODFISTO-500] - Implement endpoint to return all finance
data for FY (#432)
* [MODFISTO-500] - Implement endpoint to return all finance data for FY
* [MODFISTO-500] - Implement endpoint to return all finance data for FY
* Removed unnecessary tests from TestEntities
* Minor improvements
* added to StorageTestSuite
* remove drop part
* Update acq-model to master branch
---
descriptors/ModuleDescriptor-template.json | 19 +++++-
ramls/acq-models | 2 +-
ramls/finance-data.raml | 35 ++++++++++
.../org/folio/rest/impl/FinanceDataApi.java | 25 +++++++
.../db_scripts/all_finance_data_view.sql | 27 ++++++++
.../templates/db_scripts/schema.json | 5 ++
src/test/java/org/folio/StorageTestSuite.java | 4 ++
.../folio/rest/impl/FinanceDataApiTest.java | 68 +++++++++++++++++++
.../org/folio/rest/utils/TestEntities.java | 38 +++--------
9 files changed, 193 insertions(+), 30 deletions(-)
create mode 100644 ramls/finance-data.raml
create mode 100644 src/main/java/org/folio/rest/impl/FinanceDataApi.java
create mode 100644 src/main/resources/templates/db_scripts/all_finance_data_view.sql
create mode 100644 src/test/java/org/folio/rest/impl/FinanceDataApiTest.java
diff --git a/descriptors/ModuleDescriptor-template.json b/descriptors/ModuleDescriptor-template.json
index 72bbbe84..e2f8e4d3 100644
--- a/descriptors/ModuleDescriptor-template.json
+++ b/descriptors/ModuleDescriptor-template.json
@@ -462,6 +462,17 @@
}
]
},
+ {
+ "id": "finance-storage.finance-data",
+ "version": "1.0",
+ "handlers": [
+ {
+ "methods": ["GET"],
+ "pathPattern": "/finance-storage/finance-data",
+ "permissionsRequired": ["finance-storage.finance-data.collection.get"]
+ }
+ ]
+ },
{
"id" : "_tenant",
"version" : "2.0",
@@ -1005,6 +1016,11 @@
"finance-storage.fund-update-logs.item.delete"
]
},
+ {
+ "permissionName": "finance-storage.finance-data.collection.get",
+ "displayName": "all finance-data for fiscal year",
+ "description": "Get collection of finance data for particular fiscal year"
+ },
{
"permissionName" : "finance.module.all",
"displayName" : "All finance-module perms",
@@ -1019,7 +1035,8 @@
"finance-storage.ledgers.all",
"finance-storage.transactions.all",
"finance-storage.fund-types.all",
- "finance-storage.fund-update-logs.all"
+ "finance-storage.fund-update-logs.all",
+ "finance-storage.finance-data.collection.get"
]
}
],
diff --git a/ramls/acq-models b/ramls/acq-models
index 680fe63a..1652e69e 160000
--- a/ramls/acq-models
+++ b/ramls/acq-models
@@ -1 +1 @@
-Subproject commit 680fe63a34fc7b25d9d59013a2758de76cf82b56
+Subproject commit 1652e69e9e98499b805b698e59efd7d2a51d98b5
diff --git a/ramls/finance-data.raml b/ramls/finance-data.raml
new file mode 100644
index 00000000..bd605d0c
--- /dev/null
+++ b/ramls/finance-data.raml
@@ -0,0 +1,35 @@
+#%RAML 1.0
+title: "mod-finance-storage"
+baseUri: https://github.com/folio-org/mod-finance-storage
+version: v1
+
+documentation:
+ - title: mod-finance-storage (Funds)
+ content: CRUD APIs used to retrieve finance data for a fiscal year
+
+types:
+ errors: !include raml-util/schemas/errors.schema
+ fy-finance-data-collection: !include acq-models/mod-finance/schemas/fy_finance_data_collection.json
+ UUID:
+ type: string
+ pattern: ^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$
+
+traits:
+ pageable: !include raml-util/traits/pageable.raml
+ searchable: !include raml-util/traits/searchable.raml
+ validate: !include raml-util/traits/validation.raml
+
+resourceTypes:
+ collection-get: !include raml-util/rtypes/collection-get.raml
+
+/finance-storage/finance-data:
+ type:
+ collection-get:
+ exampleCollection: !include acq-models/mod-finance/examples/fy_finance_data_collection.sample
+ schemaCollection: fy-finance-data-collection
+ get:
+ description: Get finance data for a fiscal year
+ is: [
+ searchable: { description: "with valid searchable fields: for example fiscalYearId", example: "[\"fiscalYearId\", \"7a4c4d30-3b63-4102-8e2d-3ee5792d7d02\", \"=\"]" },
+ pageable
+ ]
diff --git a/src/main/java/org/folio/rest/impl/FinanceDataApi.java b/src/main/java/org/folio/rest/impl/FinanceDataApi.java
new file mode 100644
index 00000000..e0c9cd22
--- /dev/null
+++ b/src/main/java/org/folio/rest/impl/FinanceDataApi.java
@@ -0,0 +1,25 @@
+package org.folio.rest.impl;
+
+
+import javax.ws.rs.core.Response;
+import java.util.Map;
+
+import io.vertx.core.AsyncResult;
+import io.vertx.core.Context;
+import io.vertx.core.Handler;
+import org.folio.rest.jaxrs.model.FyFinanceData;
+import org.folio.rest.jaxrs.model.FyFinanceDataCollection;
+import org.folio.rest.jaxrs.resource.FinanceStorageFinanceData;
+import org.folio.rest.persist.PgUtil;
+
+public class FinanceDataApi implements FinanceStorageFinanceData {
+ private static final String FINANCE_DATA_VIEW = "finance_data_view";
+
+ @Override
+ public void getFinanceStorageFinanceData(String query, String totalRecords, int offset, int limit, Map okapiHeaders,
+ Handler> asyncResultHandler, Context vertxContext) {
+ PgUtil.get(FINANCE_DATA_VIEW, FyFinanceData.class, FyFinanceDataCollection.class, query, offset, limit,
+ okapiHeaders, vertxContext, GetFinanceStorageFinanceDataResponse.class, asyncResultHandler);
+ }
+
+}
diff --git a/src/main/resources/templates/db_scripts/all_finance_data_view.sql b/src/main/resources/templates/db_scripts/all_finance_data_view.sql
new file mode 100644
index 00000000..f40f7954
--- /dev/null
+++ b/src/main/resources/templates/db_scripts/all_finance_data_view.sql
@@ -0,0 +1,27 @@
+CREATE OR REPLACE VIEW ${myuniversity}_${mymodule}.finance_data_view AS
+SELECT
+ fiscal_year.id as id,
+ jsonb_build_object(
+ 'fiscalYearId', fiscal_year.id,
+ 'fiscalYearCode', fiscal_year.jsonb ->>'code',
+ 'fundId', fund.id,
+ 'fundCode', fund.jsonb ->>'code',
+ 'fundName', fund.jsonb ->>'name',
+ 'fundDescription', fund.jsonb ->>'description',
+ 'fundStatus', fund.jsonb ->>'fundStatus',
+ 'fundTags', fund.jsonb ->'tags' -> 'tagList',
+ 'budgetId', budget.id,
+ 'budgetName', budget.jsonb ->>'name',
+ 'budgetStatus', budget.jsonb ->>'budgetStatus',
+ 'budgetInitialAllocation', budget.jsonb ->>'initialAllocation',
+ 'budgetCurrentAllocation', budget.jsonb ->>'allocated',
+ 'budgetAllowableExpenditure', budget.jsonb ->>'allowableExpenditure',
+ 'budgetAllowableEncumbrance', budget.jsonb ->>'allowableEncumbrance'
+ ) as jsonb
+FROM ${myuniversity}_${mymodule}.fiscal_year
+LEFT OUTER JOIN ${myuniversity}_${mymodule}.ledger
+ ON ledger.fiscalyearoneid = fiscal_year.id
+LEFT OUTER JOIN ${myuniversity}_${mymodule}.fund
+ ON fund.ledgerid = ledger.id
+LEFT OUTER JOIN ${myuniversity}_${mymodule}.budget
+ ON fund.id = budget.fundid;
diff --git a/src/main/resources/templates/db_scripts/schema.json b/src/main/resources/templates/db_scripts/schema.json
index feeb2605..1e92f710 100644
--- a/src/main/resources/templates/db_scripts/schema.json
+++ b/src/main/resources/templates/db_scripts/schema.json
@@ -95,6 +95,11 @@
"run": "after",
"snippetPath": "migration/extract_credits_from_expenditures.sql",
"fromModuleVersion": "mod-finance-storage-8.7.0"
+ },
+ {
+ "run": "after",
+ "snippetPath": "all_finance_data_view.sql",
+ "fromModuleVersion": "mod-finance-storage-8.8.0"
}
],
"tables": [
diff --git a/src/test/java/org/folio/StorageTestSuite.java b/src/test/java/org/folio/StorageTestSuite.java
index 82cdd2c6..6df6d059 100644
--- a/src/test/java/org/folio/StorageTestSuite.java
+++ b/src/test/java/org/folio/StorageTestSuite.java
@@ -22,6 +22,7 @@
import org.folio.rest.core.RestClientTest;
import org.folio.rest.impl.BudgetTest;
import org.folio.rest.impl.EntitiesCrudTest;
+import org.folio.rest.impl.FinanceDataApiTest;
import org.folio.rest.impl.GroupBudgetTest;
import org.folio.rest.impl.GroupFundFYTest;
import org.folio.rest.impl.GroupTest;
@@ -216,4 +217,7 @@ class PaymentCreditTestNested extends PaymentCreditTest {}
@Nested
class PendingPaymentTestNested extends PendingPaymentTest {}
+
+ @Nested
+ class FinanceDataApiTestNested extends FinanceDataApiTest {}
}
diff --git a/src/test/java/org/folio/rest/impl/FinanceDataApiTest.java b/src/test/java/org/folio/rest/impl/FinanceDataApiTest.java
new file mode 100644
index 00000000..9491007f
--- /dev/null
+++ b/src/test/java/org/folio/rest/impl/FinanceDataApiTest.java
@@ -0,0 +1,68 @@
+package org.folio.rest.impl;
+
+import static org.folio.rest.RestVerticle.OKAPI_HEADER_TENANT;
+import static org.folio.rest.utils.TenantApiTestUtil.deleteTenant;
+import static org.folio.rest.utils.TenantApiTestUtil.prepareTenant;
+import static org.folio.rest.utils.TenantApiTestUtil.purge;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import io.restassured.http.Header;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.folio.rest.jaxrs.model.FyFinanceDataCollection;
+import org.folio.rest.jaxrs.model.TenantJob;
+import org.folio.rest.jaxrs.resource.FinanceStorageFinanceData;
+import org.folio.rest.persist.HelperUtils;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+
+public class FinanceDataApiTest extends TestBase {
+ private static final String TENANT_NAME = "fyfinancedata";
+ private static final Header TENANT_HEADER = new Header(OKAPI_HEADER_TENANT, TENANT_NAME);
+ private static final Logger logger = LogManager.getLogger();
+ private static final String FINANCE_DATA_ENDPOINT = HelperUtils.getEndpoint(FinanceStorageFinanceData.class);
+ private static TenantJob tenantJob;
+
+ @BeforeAll
+ public static void before() {
+ logger.info("Create a new tenant loading the sample data");
+ tenantJob = prepareTenant(TENANT_HEADER, true, true);
+ }
+
+ @AfterAll
+ public static void after() {
+ logger.info("Delete the created \"fyfinancedata\" tenant");
+ purge(TENANT_HEADER);
+ deleteTenant(tenantJob, TENANT_HEADER);
+ }
+
+ @Test
+ public void positive_testGetQuery() {
+ verifyCollectionQuantity(FINANCE_DATA_ENDPOINT + "?query=(fiscalYearId==7a4c4d30-3b63-4102-8e2d-3ee5792d7d02)", 21, TENANT_HEADER);
+ verifyCollectionQuantity(FINANCE_DATA_ENDPOINT + "?query=(fiscalYearId==9b1d00d1-1f3d-4f1c-8e4b-0f1e3b7b1b1b)", 0, TENANT_HEADER);
+ }
+
+ @Test
+ public void positive_testResponseOfGet() {
+ var response = getData(FINANCE_DATA_ENDPOINT + "?query=(fiscalYearId==7a4c4d30-3b63-4102-8e2d-3ee5792d7d02)", TENANT_HEADER);
+ var body = response.getBody().as(FyFinanceDataCollection.class);
+
+ var fyFinanceDataExample = body.getFyFinanceData().get(0);
+ assertEquals("7a4c4d30-3b63-4102-8e2d-3ee5792d7d02", fyFinanceDataExample.getFiscalYearId());
+ assertNotNull(fyFinanceDataExample.getFundId());
+ assertNotNull(fyFinanceDataExample.getFundCode());
+ assertNotNull(fyFinanceDataExample.getFundName());
+ assertNotNull(fyFinanceDataExample.getFundDescription());
+ assertNotNull(fyFinanceDataExample.getFundStatus());
+ assertNotNull(fyFinanceDataExample.getBudgetId());
+ assertNotNull(fyFinanceDataExample.getBudgetName());
+ assertNotNull(fyFinanceDataExample.getBudgetStatus());
+ assertNotNull(fyFinanceDataExample.getBudgetInitialAllocation());
+ assertNotNull(fyFinanceDataExample.getBudgetCurrentAllocation());
+ assertNotNull(fyFinanceDataExample.getBudgetAllowableExpenditure());
+ assertNotNull(fyFinanceDataExample.getBudgetAllowableEncumbrance());
+ }
+}
diff --git a/src/test/java/org/folio/rest/utils/TestEntities.java b/src/test/java/org/folio/rest/utils/TestEntities.java
index 0f180f16..f480cfd8 100644
--- a/src/test/java/org/folio/rest/utils/TestEntities.java
+++ b/src/test/java/org/folio/rest/utils/TestEntities.java
@@ -1,9 +1,11 @@
package org.folio.rest.utils;
+import lombok.Getter;
import org.folio.rest.jaxrs.model.*;
import org.folio.rest.jaxrs.resource.*;
import org.folio.rest.persist.HelperUtils;
+@Getter
public enum TestEntities {
//The Order is important because of the foreign key relationships
EXPENSE_CLASS(HelperUtils.getEndpoint(FinanceStorageExpenseClasses.class), ExpenseClass.class, "data/expense-classes-4.0.0/", "elec.json", "name", "Electronic", 2, true),
@@ -33,44 +35,24 @@ public enum TestEntities {
this.isOptLockingEnabled = isOptLockingEnabled;
}
- private int initialQuantity;
- private String endpoint;
- private String sampleFileName;
+ private final int initialQuantity;
+ private final String endpoint;
+ private final String sampleFileName;
private String sampleId;
- private String pathToSamples;
- private String updatedFieldName;
- private String updatedFieldValue;
- private Class> clazz;
- private boolean isOptLockingEnabled;
-
- public String getEndpoint() {
- return endpoint;
- }
+ private final String pathToSamples;
+ private final String updatedFieldName;
+ private final String updatedFieldValue;
+ private final Class> clazz;
+ private final boolean isOptLockingEnabled;
public String getEndpointWithId() {
return endpoint + "/{id}";
}
- public String getUpdatedFieldName() {
- return updatedFieldName;
- }
-
- public String getUpdatedFieldValue() {
- return updatedFieldValue;
- }
-
- public int getInitialQuantity() {
- return initialQuantity;
- }
-
public String getSampleFileName() {
return pathToSamples + sampleFileName;
}
- public Class> getClazz() {
- return clazz;
- }
-
public String getPathToSampleFile() {
return pathToSamples + sampleFileName;
}