diff --git a/core/libraries/ifix-services-common/pom.xml b/core/libraries/ifix-services-common/pom.xml index 387b7a87..327c14df 100644 --- a/core/libraries/ifix-services-common/pom.xml +++ b/core/libraries/ifix-services-common/pom.xml @@ -1,73 +1,73 @@ - - - 4.0.0 - org.egov.services - ifix-services-common - ifix-services-common - 1.0.0-SNAPSHOT - Shared classes among services - - - UTF-8 - 1.8 - UTF-8 - - - - - repo.digit.org - eGov ERP Releases Repository - https://nexus-repo.digit.org/nexus/content/repositories/releases/ - - - repo.digit.org - eGov ERP Snapshots Repository - https://nexus-repo.digit.org/nexus/content/repositories/snapshots/ - - - - - - org.projectlombok - lombok - 1.16.12 - true - - - com.fasterxml.jackson.core - jackson-annotations - 2.8.7 - - - jakarta.validation - jakarta.validation-api - 2.0.2 - compile - - - - - - - maven-compiler-plugin - - 8 - 8 - - - - maven-source-plugin - - - attach-sources - - jar - - - - - - - + + + 4.0.0 + org.egov.services + ifix-services-common + ifix-services-common + 1.0.0-SNAPSHOT + Shared classes among services + + + UTF-8 + 1.8 + UTF-8 + + + + + repo.digit.org + eGov ERP Releases Repository + https://nexus-repo.digit.org/nexus/content/repositories/releases/ + + + repo.digit.org + eGov ERP Snapshots Repository + https://nexus-repo.digit.org/nexus/content/repositories/snapshots/ + + + + + + org.projectlombok + lombok + 1.16.12 + true + + + com.fasterxml.jackson.core + jackson-annotations + 2.8.7 + + + jakarta.validation + jakarta.validation-api + 2.0.2 + compile + + + + + + + maven-compiler-plugin + + 8 + 8 + + + + maven-source-plugin + + + attach-sources + + jar + + + + + + + diff --git a/domain-services/fiscal-event-post-processor/fiscal-event-post-processor-0.1.0.yaml b/domain-services/fiscal-event-post-processor/fiscal-event-post-processor-0.1.0.yaml new file mode 100644 index 00000000..6d4ef9e2 --- /dev/null +++ b/domain-services/fiscal-event-post-processor/fiscal-event-post-processor-0.1.0.yaml @@ -0,0 +1,762 @@ +--- +openapi: 3.0.0 +info: + title: fiscal-event-post-processor + version: 0.1.0 +servers: +- url: + description: SwaggerHub API Auto Mocking +paths: {} +components: + schemas: + Government: + type: object + properties: + id: + type: string + example: pb + name: + type: string + example: Punjab + Department: + type: object + properties: + id: + type: string + description: Unique system generated UUID + example: 5d664a9f-9367-458a-aa5f-07fb18b90adc + code: + type: string + description: Unique department code + example: DWSS + name: + type: string + description: Name of the department + example: Department of Water Supply & Sanitation + description: Department details + Expenditure: + type: object + properties: + id: + type: string + description: Unique system generated UUID + example: d334d99a-b5c1-426c-942b-f11b5b5454fe + code: + type: string + description: Unique Expenditure code + example: JJM + name: + type: string + description: Name of the Expenditure + example: Jal Jeevan Mission + type: + type: string + description: Type of the Expenditure + enum: + - Scheme + - Non-Scheme + description: Expenditure details + DepartmentEntityAttributes: + type: object + properties: + id: + maxLength: 64 + minLength: 1 + type: string + description: Unique system generated UUID + readOnly: true + code: + maxLength: 256 + minLength: 1 + type: string + description: Unique the department entity code + name: + maxLength: 256 + minLength: 1 + type: string + description: Captures the department entity name + hierarchyLevel: + maxLength: 256 + minLength: 1 + type: number + description: Capture the level of the given department entity + description: The list basic attributes of a department entity that are stored as part of the ancestry list + DepartmentEntity: + required: + - code + - hierarchyLevelId + - id + - name + type: object + properties: + id: + maxLength: 64 + minLength: 1 + type: string + description: Unique system generated UUID + readOnly: true + code: + maxLength: 256 + minLength: 1 + type: string + description: Unique the department entity code + name: + maxLength: 256 + minLength: 1 + type: string + description: Captures the department entity name + hierarchyLevel: + maxLength: 256 + minLength: 1 + type: number + description: Capture the level of the given department entity + ancestry: + type: array + items: + $ref: '#/components/schemas/DepartmentEntityAttributes' + description: This object captures the information for department entity + readOnly: true + Project: + type: object + properties: + id: + type: string + description: Unique system generated UUID + example: 6ab1b1d2-e224-46fa-b53b-ac83b3c7ce95 + code: + type: string + description: Unique Project code + example: PWT + name: + type: string + description: Name of the Project + example: Peepli Water Tank + description: Captures the Project attributes + ChartOfAccount: + type: object + properties: + id: + type: string + description: Unique system generated UUID + example: e9f940d4-69aa-4bbb-aa82-111b8948a6b6 + coaCode: + type: string + description: Chart of account concatinated string + example: 1234-123-123-12-12-12 + majorHead: + type: string + description: Major head code + example: "1234" + majorHeadName: + type: string + description: Major head name + majorHeadType: + type: string + description: Major head code type + example: Revenue + subMajorHead: + type: string + description: Sub-Major head code + example: "123" + subMajorHeadName: + type: string + description: Sub-Major head name + minorHead: + type: string + description: Minor head code + example: "123" + minorHeadName: + type: string + description: Minor head name + subHead: + type: string + description: Sub-Head code + example: "12" + subHeadName: + type: string + description: Sub-Head name + groupHead: + type: string + description: Group head code + example: "12" + groupHeadName: + type: string + description: Group head name + objectHead: + type: string + description: Object head code + example: "12" + objectHeadName: + type: string + description: Object head name + Amount: + required: + - amount + - coa + type: object + properties: + id: + type: string + description: System generated UUID + example: 51c9c03c-1607-4dd5-9e0e-93bbf860f6f7 + amount: + type: number + description: Transaction Amount + example: 10234.5 + coaId: + type: string + description: Id of Chart of Account from the iFix master data. + example: d1e87330-4de0-4d15-8d92-d40bfa9b3ca4 + fromBillingPeriod: + type: integer + description: Start date of the billing period for which transaction is applicable + format: int64 + example: 1622907239000 + toBillingPeriod: + type: integer + description: Start date of the billing period for which transaction is applicable + format: int64 + example: 1628177643000 + description: Capture the transaction amount and chart of account corresponding to the transaction amount + FiscalEvent: + required: + - amountDetails + - eventType + - referenceId + - tenantId + - transactionTime + type: object + properties: + version: + type: string + description: Version of the Data Model Definition + example: 1.0.0 + id: + type: string + description: System generated UUID. + example: fecbbf1d-d6e3-4f24-9935-02c33b9248e0 + tenantId: + type: string + description: Tenant Id + nullable: false + example: pb + projectId: + type: string + description: The unique reference id of the project under which the event is occurring + format: uuid + example: 090d1d25-8b88-46a3-b4c9-95b66483beb5 + eventType: + type: string + description: Captures the event type (eg- Sanction(B), Appropriation(B), Allocation(Fin-AD-BCO-DDO)(B), IntraTransfer (C), Inter Transfer (C), Demand(A), Receipt (C), Bill(A),Payment (C) + nullable: false + example: Appropriation + ingestionTime: + type: integer + description: when the event arrived in ifix + format: int64 + nullable: false + readOnly: true + example: 1628177497000 + eventTime: + type: integer + description: when the event occured at source system level + format: int64 + example: 1628177497000 + referenceId: + type: string + description: reference unique id(transaction id) of the caller system + example: 013e9c56-8207-4dac-9f4d-f1e20bd824e7 + parentEventId: + type: string + description: If this is a follow up event then it will refer to the parent event using this reference id. + nullable: true + example: 7d476bb0-bc9f-48e2-8ad4-5a4a36220779 + parentReferenceId: + type: string + description: If this is a follow up event then it will refer to the parent event in source system using this reference id. + nullable: true + example: 77f23efe-879d-407b-8f23-7b8dd5b2ecb1 + amountDetails: + type: array + items: + $ref: '#/components/schemas/Amount' + auditDetails: + $ref: '#/components/schemas/AuditDetails' + attributes: + type: object + description: This object captures the fiscal information of external systems. + FiscalEventRequest: + required: + - fiscalEvent + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + fiscalEvent: + $ref: '#/components/schemas/FiscalEvent' + description: Fiscal event request along with request metadata + AmountDetailsDeReferenced: + required: + - amount + - coa + type: object + properties: + id: + type: string + description: System generated UUID + example: 51c9c03c-1607-4dd5-9e0e-93bbf860f6f7 + amount: + type: number + description: Transaction Amount + example: 10234.5 + coa: + $ref: '#/components/schemas/ChartOfAccount' + fromBillingPeriod: + type: integer + description: Start date of the billing period for which transaction is applicable + format: int64 + example: 1622907239000 + toBillingPeriod: + type: integer + description: Start date of the billing period for which transaction is applicable + format: int64 + example: 1628177643000 + description: Capture the transaction amount and chart of account corresponding to the transaction amount + FiscalEventDeReferenced: + required: + - amountDetails + - eventType + - referenceId + - tenantId + - transactionTime + type: object + properties: + version: + type: string + description: Version of the Data Model Definition + example: 1.0.0 + id: + type: string + description: System generated UUID. + example: fecbbf1d-d6e3-4f24-9935-02c33b9248e0 + tenantId: + type: string + description: Tenant Id + nullable: false + example: pb + government: + $ref: '#/components/schemas/Government' + department: + $ref: '#/components/schemas/Department' + departmentEntity: + $ref: '#/components/schemas/DepartmentEntity' + expenditure: + $ref: '#/components/schemas/Expenditure' + project: + $ref: '#/components/schemas/Project' + eventType: + type: string + description: Captures the event type (eg- Sanction(B), Appropriation(B), Allocation(Fin-AD-BCO-DDO)(B), IntraTransfer (C), Inter Transfer (C), Demand(A), Receipt (C), Bill(A),Payment (C) + nullable: false + example: Appropriation + ingestionTime: + type: integer + description: when the event arrived in ifix + format: int64 + nullable: false + readOnly: true + example: 1628177497000 + eventTime: + type: integer + description: when the event occured at source system level + format: int64 + example: 1628177497000 + referenceId: + type: string + description: reference unique id(transaction id) of the caller system + example: 013e9c56-8207-4dac-9f4d-f1e20bd824e7 + parentEventId: + type: string + description: If this is a follow up event then it will refer to the parent event using this reference id. + nullable: true + example: 7d476bb0-bc9f-48e2-8ad4-5a4a36220779 + parentReferenceId: + type: string + description: If this is a follow up event then it will refer to the parent event in source system using this reference id. + nullable: true + example: 77f23efe-879d-407b-8f23-7b8dd5b2ecb1 + amountDetails: + type: array + items: + $ref: '#/components/schemas/AmountDetailsDeReferenced' + auditDetails: + $ref: '#/components/schemas/AuditDetails' + attributes: + type: object + description: It gets the whole master data objects based on the reference ids present in the incoming request + FiscalEventMongoDB: + $ref: '#/components/schemas/FiscalEventDeReferenced' + FiscalEventLineItemUnbundled: + type: object + properties: + version: + type: string + description: Version of the Data Model Definition + example: 1.0.0 + id: + type: string + description: System generated UUID of Line Item + example: 51c9c03c-1607-4dd5-9e0e-93bbf860f6f7 + eventId: + type: string + description: Fiscal Event Reference Id + example: fecbbf1d-d6e3-4f24-9935-02c33b9248e0 + tenantId: + type: string + description: Tenant Id + nullable: false + example: pb + government: + $ref: '#/components/schemas/Government' + department: + $ref: '#/components/schemas/Department' + Expenditure: + $ref: '#/components/schemas/Expenditure' + project: + $ref: '#/components/schemas/Project' + eventType: + type: string + description: Captures the event type (eg- Sanction(B), Appropriation(B), Allocation(Fin-AD-BCO-DDO)(B), IntraTransfer (C), Inter Transfer (C), Demand(A), Receipt (C), Bill(A),Payment (C) + nullable: false + example: Appropriation + eventTime: + type: integer + description: when the event occured at source system level + format: int64 + example: 1628177497000 + ingestionTime: + type: integer + description: when the event arrived in ifix + format: int64 + nullable: false + readOnly: true + example: 1628177497000 + referenceId: + type: string + description: reference unique id(transaction id) of the caller system + example: 013e9c56-8207-4dac-9f4d-f1e20bd824e7 + parentEventId: + type: string + description: If this is a follow up event then it will refer to the parent event using this reference id. + nullable: true + example: 7d476bb0-bc9f-48e2-8ad4-5a4a36220779 + parentReferenceId: + type: string + description: If this is a follow up event then it will refer to the parent event in source system using this reference id. + nullable: true + example: 77f23efe-879d-407b-8f23-7b8dd5b2ecb1 + amount: + type: number + description: Transaction Amount + example: 10234.5 + coa: + $ref: '#/components/schemas/ChartOfAccount' + fromBillingPeriod: + type: integer + description: Start date of the billing period for which transaction is applicable + format: int64 + example: 1622907239000 + toBillingPeriod: + type: integer + description: Start date of the billing period for which transaction is applicable + format: int64 + example: 1628177643000 + description: This is the unbundled line item into individual record from a given fiscal event. + FiscalEventLineItemFlattened: + type: object + properties: + version: + type: string + description: Version of the Data Model Definition + example: 1.0.0 + id: + type: string + description: System generated UUID of Line Item + example: 51c9c03c-1607-4dd5-9e0e-93bbf860f6f7 + eventId: + type: string + description: Fiscal Event Reference Id + example: fecbbf1d-d6e3-4f24-9935-02c33b9248e0 + tenantId: + type: string + description: Tenant Id + nullable: false + example: pb + government.id: + type: string + example: pb + government.name: + type: string + example: Punjab + department.id: + type: string + description: Unique system generated UUID + example: 5d664a9f-9367-458a-aa5f-07fb18b90adc + department.code: + type: string + description: Unique department code + example: DWSS + department.name: + type: string + description: Name of the department + example: Department of Water Supply & Sanitation + departmentEntity.id: + type: string + description: Unique system generated UUID + example: 054c8070-3135-47ce-a6ca-f425d2b57b02 + departmentEntity.code: + type: string + description: Unique department entity code + example: APS + departmentEntity.name: + type: string + description: Name of the department entity + example: Anandpur Sahib + departmentEntity.hierarchyLevel: + type: number + description: Hierarchy level of the department entity + example: 3 + departmentEntity.ancestry[0].id: + type: string + description: Unique system generated UUID + example: 99e988ee-3036-47e3-b907-d3273c18161f + departmentEntity.ancestry[0].code: + type: string + description: Unique department entity code + example: DWSS + departmentEntity.ancestry[0].name: + type: string + description: Name of the department entity + example: Department of Water Supply & Sanitation + departmentEntity.ancestry[0].hierarchyLevel: + type: number + description: Hierarchy level of the department entity + example: 0 + departmentEntity.ancestry[1].id: + type: string + description: Unique system generated UUID + example: 9d59e2bf-2892-4a27-977a-f3cfd7d2e024 + departmentEntity.ancestry[1].code: + type: string + description: Unique department entity code + example: South + departmentEntity.ancestry[1].name: + type: string + description: Name of the department entity + example: South Zone + departmentEntity.ancestry[1].hierarchyLevel: + type: number + description: Hierarchy level of the department entity + example: 1 + expenditure.id: + type: string + description: Unique system generated UUID + example: d334d99a-b5c1-426c-942b-f11b5b5454fe + expenditure.code: + type: string + description: Unique Expenditure code + example: JJM + expenditure.name: + type: string + description: Name of the Expenditure + example: Jal Jeevan Mission + expenditure.type: + type: string + description: Type of the Expenditure + enum: + - Scheme + - Non-Scheme + project.id: + type: string + description: Unique system generated UUID + example: 6ab1b1d2-e224-46fa-b53b-ac83b3c7ce95 + project.code: + type: string + description: Unique Project code + example: PWT + project.name: + type: string + description: Name of the Project + example: Peepli Water Tank + eventType: + type: string + description: Captures the event type (eg- Sanction(B), Appropriation(B), Allocation(Fin-AD-BCO-DDO)(B), IntraTransfer (C), Inter Transfer (C), Demand(A), Receipt (C), Bill(A),Payment (C) + nullable: false + example: Appropriation + eventTime: + type: integer + description: when the event occured at source system level + format: int64 + example: 1628177497000 + ingestionTime: + type: integer + description: when the event arrived in ifix + format: int64 + nullable: false + readOnly: true + example: 1628177497000 + referenceId: + type: string + description: reference unique id(transaction id) of the caller system + example: 013e9c56-8207-4dac-9f4d-f1e20bd824e7 + parentEventId: + type: string + description: If this is a follow up event then it will refer to the parent event using this reference id. + nullable: true + example: 7d476bb0-bc9f-48e2-8ad4-5a4a36220779 + parentReferenceId: + type: string + description: If this is a follow up event then it will refer to the parent event in source system using this reference id. + nullable: true + example: 77f23efe-879d-407b-8f23-7b8dd5b2ecb1 + amount: + type: number + description: Transaction Amount + example: 10234.5 + coa.id: + type: string + description: Unique system generated UUID + example: e9f940d4-69aa-4bbb-aa82-111b8948a6b6 + coa.coaCode: + type: string + description: Chart of account concatinated string + example: 1234-123-123-12-12-12 + coa.majorHead: + type: string + description: Major head code + example: "1234" + coa.majorHeadName: + type: string + description: Major head name + coa.majorHeadType: + type: string + description: Major head code type + example: Revenue + coa.subMajorHead: + type: string + description: Sub-Major head code + example: "123" + coa.subMajorHeadName: + type: string + description: Sub-Major head name + coa.minorHead: + type: string + description: Minor head code + example: "123" + coa.minorHeadName: + type: string + description: Minor head name + coa.subHead: + type: string + description: Sub-Head code + example: "12" + coa.subHeadName: + type: string + description: Sub-Head name + coa.groupHead: + type: string + description: Group head code + example: "12" + coa.groupHeadName: + type: string + description: Group head name + coa.objectHead: + type: string + description: Object head code + example: "12" + coa.objectHeadName: + type: string + description: Object head name + fromBillingPeriod: + type: integer + description: Start date of the billing period for which transaction is applicable + format: int64 + example: 1622907239000 + toBillingPeriod: + type: integer + description: Start date of the billing period for which transaction is applicable + format: int64 + example: 1628177643000 + description: This is the flattened structure of line item that will get persisted to Druid + FiscalEventDruid: + $ref: '#/components/schemas/FiscalEventLineItemFlattened' + AuditDetails: + type: object + properties: + createdBy: + type: string + description: UUID (preferred) or userid of the user that created the object + readOnly: true + lastModifiedBy: + type: string + description: UUID (preferred) or userid of the user that last modified the object + readOnly: true + createdTime: + type: integer + description: epoch of the time object is created + format: int64 + readOnly: true + lastModifiedTime: + type: integer + description: epoch of the time object is last modified + format: int64 + readOnly: true + description: Collection of audit related fields used by most models + readOnly: true + RequestHeader: + type: object + properties: + ts: + type: integer + description: time in epoch + format: int64 + nullable: false + version: + maxLength: 64 + minLength: 2 + type: string + description: The version of the API + nullable: false + msgId: + maxLength: 256 + type: string + description: Unique request message id from the caller + userInfo: + $ref: '#/components/schemas/UserInfo' + correlationId: + type: string + readOnly: true + signature: + type: string + description: Hash describing the current RequestHeader + description: RequestHeader should be used to carry meta information about the requests to the server as described in the fields below. All eGov APIs will use requestHeader as a part of the request body to carry this meta information. Some of this information will be returned back from the server as part of the ResponseHeader in the response body to ensure correlation. + UserInfo: + type: object + properties: + uuid: + type: string + description: System Generated User id of the authenticated user. + roles: + type: array + description: List of roles assigned to a user + items: + type: string + tenants: + type: array + description: List of tenants assigned to a user + items: + type: string + attributes: + type: object + description: Capture the user information + readOnly: true diff --git a/domain-services/fiscal-event-service/fiscal-event-service-0.1.0.yaml b/domain-services/fiscal-event-service/fiscal-event-service-0.1.0.yaml new file mode 100644 index 00000000..46bb760c --- /dev/null +++ b/domain-services/fiscal-event-service/fiscal-event-service-0.1.0.yaml @@ -0,0 +1,374 @@ +--- +openapi: 3.0.0 +info: + title: fiscal-event-service + version: 0.1.0 +servers: +- url: https:///fiscal-event-service + description: SwaggerHub API Auto Mocking +paths: + /fiscal/events/v1/_push: + post: + tags: + - Fiscal Events + summary: Create(publish) new fiscal event on iFix + description: Create the new fiscal event + requestBody: + description: Details for the new fiscal event + RequestHeader (meta data of the API). + content: + application/json: + schema: + $ref: '#/components/schemas/FiscalEventRequest' + required: true + responses: + "202": + description: Event published successfully + content: + '*/*': + schema: + $ref: '#/components/schemas/FiscalEventResponse' + "400": + description: Failed to process the request + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + /fiscal/events/v1/_search: + post: + tags: + - Fiscal Events + summary: Get the list fiscal events. + description: | + Based on the criteria get the list of events. + requestBody: + description: RequestHeader meta data. + content: + application/json: + schema: + $ref: '#/components/schemas/FiscalEventGetRequest' + required: true + responses: + "200": + description: Successful response + content: + '*/*': + schema: + $ref: '#/components/schemas/FiscalEventResponse' + "400": + description: Invalid input. + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' +components: + schemas: + FiscalEvent: + required: + - amountDetails + - eventType + - referenceId + - tenantId + - transactionTime + type: object + properties: + id: + maxLength: 64 + minLength: 1 + type: string + description: System generated UUID. + readOnly: true + example: fecbbf1d-d6e3-4f24-9935-02c33b9248e0 + tenantId: + maxLength: 256 + minLength: 2 + type: string + description: Tenant Id + nullable: false + example: pb + projectId: + type: string + description: The unique reference id of the project under which the event is occurring + format: uuid + example: 090d1d25-8b88-46a3-b4c9-95b66483beb5 + eventType: + maxLength: 64 + minLength: 1 + type: string + description: Captures the event type (eg- SANCTION(B), APPROPRIATION(B), ALLOCATION(FIN-AD-BCO-DDO)(B), INTRA_TRANSFER (C), INTER_TRANSFER (C), DEMAND(A), RECEIPT (C), BILL(A),PAYMENT (C) + nullable: false + example: Appropriation + eventTime: + type: integer + description: when the event occured at source system level + format: int64 + example: 1628177497000 + ingestionTime: + type: integer + description: when the event arrived in ifix + format: int64 + nullable: false + readOnly: true + example: 1628177497000 + referenceId: + maxLength: 64 + minLength: 1 + type: string + description: reference unique id(transaction id) of the caller system + example: 013e9c56-8207-4dac-9f4d-f1e20bd824e7 + parentEventId: + maxLength: 64 + minLength: 1 + type: string + description: If this is a follow up event then it will refer to the parent event using this reference id. + nullable: true + example: 7d476bb0-bc9f-48e2-8ad4-5a4a36220779 + parentReferenceId: + maxLength: 64 + minLength: 1 + type: string + description: If this is a follow up event then it will refer to the parent event in source system using this reference id. + nullable: true + example: 77f23efe-879d-407b-8f23-7b8dd5b2ecb1 + amountDetails: + type: array + items: + $ref: '#/components/schemas/Amount' + auditDetails: + $ref: '#/components/schemas/AuditDetails' + attributes: + type: object + description: This object captures the fiscal information of external systems. + Amount: + required: + - amount + - coa + type: object + properties: + id: + maxLength: 64 + minLength: 1 + type: string + description: System generated UUID + readOnly: true + example: 51c9c03c-1607-4dd5-9e0e-93bbf860f6f7 + amount: + type: number + description: Transaction Amount + example: 10234.5 + coaId: + maxLength: 64 + minLength: 1 + type: string + description: Id of Chart of Account from the iFix master data. + example: d1e87330-4de0-4d15-8d92-d40bfa9b3ca4 + fromBillingPeriod: + type: integer + description: Start date of the billing period for which transaction is applicable + format: int64 + example: 1622907239000 + toBillingPeriod: + type: integer + description: Start date of the billing period for which transaction is applicable + format: int64 + example: 1628177643000 + description: Capture the transaction amount and chart of account corresponding to the transaction amount + Criteria: + required: + - eventType + - tenantId + type: object + properties: + ids: + type: array + description: List of event ids + items: + maxItems: 100 + type: string + tenantId: + maxLength: 256 + minLength: 2 + type: string + description: Tenant Id + nullable: false + eventType: + maxLength: 64 + minLength: 1 + type: string + description: Captures the event type(eg- bill, receipt, expenditure) + nullable: false + fromEventTime: + type: integer + description: Search events b/w transaction time(Start date) + format: int64 + toEventTime: + type: integer + description: Search events b/w transaction time(End date) + format: int64 + referenceId: + type: array + items: + maxItems: 100 + type: string + description: The object contains all the search criteria of the fiscal events + FiscalEventRequest: + required: + - fiscalInfo + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + fiscalEvent: + $ref: '#/components/schemas/FiscalEvent' + description: Fiscal event request along with request metadata + FiscalEventGetRequest: + required: + - fiscalInfo + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + criteria: + $ref: '#/components/schemas/Criteria' + description: Fiscal event request along with request metadata + FiscalEventResponse: + properties: + responseHeader: + $ref: '#/components/schemas/ResponseHeader' + fiscalEvent: + type: array + items: + $ref: '#/components/schemas/FiscalEvent' + description: Contains the ResponseHeader and the enriched fiscal information + ErrorResponse: + required: + - ResponseHeader + type: object + properties: + ResponseHeader: + $ref: '#/components/schemas/ResponseHeader' + Errors: + minLength: 1 + type: array + description: Error response array to return multiple error for single request + items: + $ref: '#/components/schemas/Error' + description: All APIs will return ErrorRes in case of failure which will carry ResponseHeader as metadata and Error object as actual representation of error. + ResponseHeader: + type: object + properties: + ts: + type: integer + description: response time in epoch + format: int64 + correlationId: + maxLength: 256 + type: string + description: unique response message id (UUID) - will usually be the correlation id from the server + msgId: + maxLength: 256 + type: string + description: message id of the request + status: + type: string + description: status of request processing + enum: + - SUCCESS + - FAILED + signature: + type: string + description: Hash describing the current Request + version: + maxLength: 64 + minLength: 2 + type: string + description: The version of the API + nullable: false + description: ResponseHeader should be used to carry metadata information about the response from the server. apiId, ver and msgId in ResponseHeader should always correspond to the same values in respective request's RequestHeader. + readOnly: true + Error: + required: + - code + - description + - message + type: object + properties: + code: + type: string + description: Error Code will be service specific error label/code to identiffy the error. Example for error code would be User.NotFound to indicate User Not Found by User/Authentication service. All services must declare their possible Error Codes with brief description in the error response section of their API path. + message: + type: string + description: Human readable error message + description: + type: string + description: technical description of the error which can help developer to debug the error if error is unexpected. + description: Error object will be returned as a part of reponse body in conjunction with ResponseHeader as part of ErrorResponse whenever the request processing status in the ResponseHeader is FAILED. HTTP return in this scenario will usually be HTTP 400. + AuditDetails: + type: object + properties: + createdBy: + type: string + description: UUID (preferred) or userid of the user that created the object + readOnly: true + lastModifiedBy: + type: string + description: UUID (preferred) or userid of the user that last modified the object + readOnly: true + createdTime: + type: integer + description: epoch of the time object is created + format: int64 + readOnly: true + lastModifiedTime: + type: integer + description: epoch of the time object is last modified + format: int64 + readOnly: true + description: Collection of audit related fields used by most models + readOnly: true + RequestHeader: + type: object + properties: + ts: + type: integer + description: time in epoch + format: int64 + nullable: false + version: + maxLength: 64 + minLength: 2 + type: string + description: The version of the API + nullable: false + msgId: + maxLength: 256 + type: string + description: Unique request message id from the caller + userInfo: + $ref: '#/components/schemas/UserInfo' + correlationId: + type: string + readOnly: true + signature: + type: string + description: Hash describing the current RequestHeader + description: RequestHeader should be used to carry meta information about the requests to the server as described in the fields below. All eGov APIs will use requestHeader as a part of the request body to carry this meta information. Some of this information will be returned back from the server as part of the ResponseHeader in the response body to ensure correlation. + UserInfo: + type: object + properties: + uuid: + type: string + description: System Generated User id of the authenticated user. + roles: + type: array + description: List of roles assigned to a user + items: + type: string + tenants: + type: array + description: List of tenants assigned to a user + items: + type: string + attributes: + type: object + description: Capture the user information + readOnly: true diff --git a/domain-services/fiscal-event-service/src/main/resources/db/migration/V20210823115500__create_index b/domain-services/fiscal-event-service/src/main/resources/db/migration/V20210823115500__create_index new file mode 100644 index 00000000..384a6602 --- /dev/null +++ b/domain-services/fiscal-event-service/src/main/resources/db/migration/V20210823115500__create_index @@ -0,0 +1,4 @@ +db.fiscal_event.createIndexes( + [{"eventType":1},{"eventTime":1},{"tenantId":1},{"referenceId":1}] + ); +db.fiscalEvent.getIndexes(); diff --git a/domain-services/fiscal-event-service/src/main/resources/db/migration/V20210831021000__create_index b/domain-services/fiscal-event-service/src/main/resources/db/migration/V20210831021000__create_index new file mode 100644 index 00000000..b55031c8 --- /dev/null +++ b/domain-services/fiscal-event-service/src/main/resources/db/migration/V20210831021000__create_index @@ -0,0 +1,8 @@ +db.fiscal_event.createIndexes( + [ + {"ingestionTime": 1}, {"departmentEntity.id": 1} ,{"departmentEntity.hierarchyLevel": 1} , {"departmentEntity.code": 1} , {"departmentEntity.name": 1}, + {"departmentEntity.ancestry.id": 1}, {"departmentEntity.ancestry.code": 1}, {"departmentEntity.ancestry.name": 1}, {"departmentEntity.ancestry.hierarchyLevel": 1}, + {"expenditure.id": 1}, {"project.id": 1}, {"parentEventId": 1}, {"amountDetails.coa.id": 1} + ] + ); +db.fiscalEvent.getIndexes(); diff --git a/domain-services/fiscal-event-service/src/test/java/org/egov/TestConfiguration.java b/domain-services/fiscal-event-service/src/test/java/org/egov/TestConfiguration.java new file mode 100644 index 00000000..d13056a1 --- /dev/null +++ b/domain-services/fiscal-event-service/src/test/java/org/egov/TestConfiguration.java @@ -0,0 +1,16 @@ +package org.egov; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.core.KafkaTemplate; + +import static org.mockito.Mockito.mock; + +@Configuration +public class TestConfiguration { + @Bean + @SuppressWarnings("unchecked") + public KafkaTemplate kafkaTemplate() { + return mock(KafkaTemplate.class); + } +} \ No newline at end of file diff --git a/domain-services/ifix-department-entity-service/ifix-department-entity-service-0.1.0.yaml b/domain-services/ifix-department-entity-service/ifix-department-entity-service-0.1.0.yaml new file mode 100644 index 00000000..b700b4fd --- /dev/null +++ b/domain-services/ifix-department-entity-service/ifix-department-entity-service-0.1.0.yaml @@ -0,0 +1,467 @@ +--- +openapi: 3.0.0 +info: + title: ifix-department-entity-service + version: 0.1.0 +servers: +- url: https:///ifix-department-entity + description: SwaggerHub API Auto Mocking +paths: + /departmentEntity/v1/_create: + post: + tags: + - DepartmentEntity + summary: Create/Add new Department Entity on iFix for a tenant + description: Create/Add new Department Entity on iFix for a tenant + requestBody: + description: Details for the new Department Entity + RequestHeader (meta data of the API). + content: + application/json: + schema: + $ref: '#/components/schemas/DepartmentEntityRequest' + required: true + responses: + "202": + description: Request has been accepted for processing + content: + '*/*': + schema: + $ref: '#/components/schemas/DepartmentEntityResponse' + "400": + description: Failed to process the request + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + "500": + description: Internal server error + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + /departmentEntity/v1/_search: + post: + tags: + - DepartmentEntity + summary: Get Department Entity details. + description: | + Based on the criteria get the list of department entities. + requestBody: + description: RequestHeader meta data. + content: + application/json: + schema: + $ref: '#/components/schemas/DepartmentEntitySearchRequest' + required: true + responses: + "200": + description: Successful response + content: + '*/*': + schema: + $ref: '#/components/schemas/DepartmentEntityResponse' + "400": + description: Invalid input. + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + "500": + description: Internal server error + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + /departmentEntity/hierarchyLevel/v1/_create: + post: + tags: + - DepartmentHierarchyLevel + summary: Create/Add new DepartmentHierarchyLevel on iFix for a tenant + description: Create/Add new DepartmentHierarchyLevel on iFix for a tenant + requestBody: + description: Details for the new DepartmentHierarchyLevel + RequestHeader (meta data of the API). + content: + application/json: + schema: + $ref: '#/components/schemas/DepartmentHierarchyLevelRequest' + required: true + responses: + "202": + description: Request has been accepted for processing + content: + '*/*': + schema: + $ref: '#/components/schemas/DepartmentHierarchyLevelResponse' + "400": + description: Failed to process the request + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + "500": + description: Internal server error + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + /departmentEntity/hierarchyLevel/v1/_search: + post: + tags: + - DepartmentHierarchyLevel + summary: Get DepartmentHierarchyLevel. + description: | + Based on the criteria get the list of Department Hierarchy Levels. + requestBody: + description: RequestHeader meta data. + content: + application/json: + schema: + $ref: '#/components/schemas/DepartmentHierarchyLevelSearchRequest' + required: true + responses: + "200": + description: Successful response + content: + '*/*': + schema: + $ref: '#/components/schemas/DepartmentHierarchyLevelResponse' + "400": + description: Invalid input. + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + "500": + description: Internal server error + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' +components: + schemas: + DepartmentEntity: + required: + - children + - code + - hierarchyLevelId + - id + - name + - tenantId + type: object + properties: + id: + maxLength: 64 + minLength: 1 + type: string + description: Unique system generated UUID + readOnly: true + tenantId: + maxLength: 64 + minLength: 1 + type: string + description: Unique tenant identifier + departmentId: + type: string + description: Department id from department master + code: + maxLength: 256 + minLength: 1 + type: string + description: Unique the department entity code + name: + maxLength: 256 + minLength: 1 + type: string + description: Captures the department entity name + hierarchyLevel: + maxLength: 256 + minLength: 1 + type: number + description: Capture the level of the given department entity + children: + type: array + items: + type: string + description: Department Entity ids of the children + auditDetails: + $ref: '#/components/schemas/AuditDetails' + description: This object captures the information for department entity + DepartmentEntityRequest: + required: + - departmentEntity + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + departmentEntity: + $ref: '#/components/schemas/DepartmentEntity' + description: Department Entity request along with request metadata + DepartmentEntityResponse: + properties: + responseHeader: + $ref: '#/components/schemas/ResponseHeader' + departmentEntity: + type: array + items: + $ref: '#/components/schemas/DepartmentEntity' + description: Contains the ResponseHeader and the enriched Department Entity information + DepartmentEntitySearchRequest: + required: + - criteria + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + criteria: + $ref: '#/components/schemas/DepartmentEntitySearchCriteria' + description: Department Entity search request along with request metadata + DepartmentEntitySearchCriteria: + required: + - tenantId + type: object + properties: + Ids: + type: array + description: Department Entity Ids + items: + maxItems: 50 + type: string + tenantId: + type: string + description: Tenant Id + departmentId: + type: string + description: Department id from department master + code: + type: string + description: Unique the department entity code + name: + type: string + description: Captures the department entity name + level: + type: string + description: Capture the level of department entity + getAncestry: + type: boolean + description: If set to true, it will return all the department entity hierarchy details starting from the root to the specified department entity id. + description: The object contains all the search criteria of Department Entity + DepartmentHierarchyLevel: + required: + - departmentId + - id + - label + - tenantId + type: object + properties: + id: + type: string + description: Unique system generated UUID + readOnly: true + tenantId: + type: string + description: Unique tenant identifier + departmentId: + type: string + description: Department id from department master + label: + type: string + description: Unique department hierarchy level code + example: state, zone, city etc + parent: + type: string + description: Capture the department hierarchy level of the parent id (UUID). If it is the root level it will not have any parent. There can only be one root element for a given department. + nullable: true + level: + type: number + description: The level of current DepartmentHierarchyLevel will be set as 1 greater than it\'s parent\'s + readOnly: true + example: 2 + auditDetails: + $ref: '#/components/schemas/AuditDetails' + description: This object captures the information for level of the department hierarchy and it's alias + DepartmentHierarchyLevelRequest: + required: + - departmentHierarchyLevel + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + departmentHierarchyLevel: + $ref: '#/components/schemas/DepartmentHierarchyLevel' + description: Department Hierarchy Level request along with request metadata + DepartmentHierarchyLevelResponse: + properties: + responseHeader: + $ref: '#/components/schemas/ResponseHeader' + departmentHierarchyLevel: + type: array + items: + $ref: '#/components/schemas/DepartmentHierarchyLevel' + description: Contains the ResponseHeader and the enriched Department Hierarchy Level information + DepartmentHierarchyLevelSearchRequest: + required: + - criteria + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + criteria: + $ref: '#/components/schemas/DepartmentHierarchyLevelSearchCriteria' + description: Department Hierarchy Level search request along with request metadata + DepartmentHierarchyLevelSearchCriteria: + required: + - tenantId + type: object + properties: + Ids: + type: array + description: Department Hierarchy Level Ids + items: + maxItems: 50 + type: string + tenantId: + type: string + description: Tenant Id + departmentId: + type: string + description: Department id from department master + label: + type: string + description: Unique department hierarchy label like state, district, etc. + level: + type: number + description: The level of the department hierarchy level + description: The object contains all the search criteria of Department Hierarchy Level + ErrorResponse: + required: + - ResponseHeader + type: object + properties: + ResponseHeader: + $ref: '#/components/schemas/ResponseHeader' + Errors: + minLength: 1 + type: array + description: Error response array to return multiple error for single request + items: + $ref: '#/components/schemas/Error' + description: All APIs will return ErrorRes in case of failure which will carry ResponseHeader as metadata and Error object as actual representation of error. + ResponseHeader: + type: object + properties: + ts: + type: integer + description: response time in epoch + format: int64 + correlationId: + maxLength: 256 + type: string + description: unique response message id (UUID) - will usually be the correlation id from the server + msgId: + maxLength: 256 + type: string + description: message id of the request + status: + type: string + description: status of request processing + enum: + - SUCCESS + - FAILED + signature: + type: string + description: Hash describing the current Request + version: + maxLength: 64 + minLength: 2 + type: string + description: The version of the API + nullable: false + description: ResponseHeader should be used to carry metadata information about the response from the server. apiId, ver and msgId in ResponseHeader should always correspond to the same values in respective request's RequestHeader. + readOnly: true + Error: + required: + - code + - description + - message + type: object + properties: + code: + type: string + description: Error Code will be service specific error label/code to identiffy the error. Example for error code would be User.NotFound to indicate User Not Found by User/Authentication service. All services must declare their possible Error Codes with brief description in the error response section of their API path. + message: + type: string + description: Human readable error message + description: + type: string + description: technical description of the error which can help developer to debug the error if error is unexpected. + description: Error object will be returned as a part of reponse body in conjunction with ResponseHeader as part of ErrorResponse whenever the request processing status in the ResponseHeader is FAILED. HTTP return in this scenario will usually be HTTP 400. + AuditDetails: + type: object + properties: + createdBy: + type: string + description: UUID (preferred) or userid of the user that created the object + readOnly: true + lastModifiedBy: + type: string + description: UUID (preferred) or userid of the user that last modified the object + readOnly: true + createdTime: + type: integer + description: epoch of the time object is created + format: int64 + readOnly: true + lastModifiedTime: + type: integer + description: epoch of the time object is last modified + format: int64 + readOnly: true + description: Collection of audit related fields used by most models + readOnly: true + RequestHeader: + type: object + properties: + ts: + type: integer + description: time in epoch + format: int64 + nullable: false + version: + maxLength: 64 + minLength: 2 + type: string + description: The version of the API + nullable: false + msgId: + maxLength: 256 + type: string + description: Unique request message id from the caller + userInfo: + $ref: '#/components/schemas/UserInfo' + correlationId: + type: string + readOnly: true + signature: + type: string + description: Hash describing the current RequestHeader + description: RequestHeader should be used to carry meta information about the requests to the server as described in the fields below. All eGov APIs will use requestHeader as a part of the request body to carry this meta information. Some of this information will be returned back from the server as part of the ResponseHeader in the response body to ensure correlation. + UserInfo: + type: object + properties: + uuid: + type: string + description: System Generated User id of the authenticated user. + roles: + type: array + description: List of roles assigned to a user + items: + type: string + tenants: + type: array + description: List of tenants assigned to a user + items: + type: string + attributes: + type: object + description: Capture the user information + readOnly: true diff --git a/domain-services/ifix-department-entity-service/src/main/resources/db/migration/V20210824122400__create_index b/domain-services/ifix-department-entity-service/src/main/resources/db/migration/V20210824122400__create_index new file mode 100644 index 00000000..b40e3fc8 --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/resources/db/migration/V20210824122400__create_index @@ -0,0 +1,10 @@ +db.departmentHierarchyLevel.createIndexes( + [{"departmentId":1},{"label":1},{"tenantId":1},{"level":1}] + ); +db.departmentHierarchyLevel.getIndexes(); + +db.departmentEntity.createIndexes( + [{"departmentId":1},{"code":1},{"tenantId":1},{"level":1},{"name":1},{"children":1}] + ); +db.departmentEntity.getIndexes(); + diff --git a/domain-services/ifix-master-data-service/ifix-master-data-service-0.1.0.yaml b/domain-services/ifix-master-data-service/ifix-master-data-service-0.1.0.yaml new file mode 100644 index 00000000..a0fd8f7d --- /dev/null +++ b/domain-services/ifix-master-data-service/ifix-master-data-service-0.1.0.yaml @@ -0,0 +1,1083 @@ +--- +openapi: 3.0.0 +info: + title: ifix-master-data-service + description: iFIX-Master-Data + version: 0.1.0 +servers: +- url: https:///ifix-master-data-service + description: SwaggerHub API Auto Mocking +paths: + /government/v1/_create: + post: + tags: + - Government + summary: Create/Add new tenant on iFix + description: Create/Add the new tenant + requestBody: + description: Details for the new fiscal event + RequestHeader (meta data of the API). + content: + application/json: + schema: + $ref: '#/components/schemas/GovernmentRequest' + required: true + responses: + "202": + description: Request has been accepted for processing + content: + '*/*': + schema: + $ref: '#/components/schemas/GovernmentResponse' + "400": + description: Failed to process the request + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + "500": + description: Internal server error + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + /government/v1/_search: + post: + tags: + - Government + summary: Get the list fiscal events. + description: | + Based on the criteria get the list of events. + requestBody: + description: RequestHeader meta data. + content: + application/json: + schema: + $ref: '#/components/schemas/GovernmentSearchRequest' + required: true + responses: + "200": + description: Successful response + content: + '*/*': + schema: + $ref: '#/components/schemas/GovernmentResponse' + "400": + description: Invalid input. + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + "500": + description: Internal server error + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + /chartOfAccount/v1/_create: + post: + tags: + - COA + summary: Create/Add new COA on iFix for a tenant + description: Create/Add new COA on iFix for a tenant + requestBody: + description: Details for the new COA + RequestHeader (meta data of the API). + content: + application/json: + schema: + $ref: '#/components/schemas/COARequest' + required: true + responses: + "202": + description: Request has been accepted for processing + content: + '*/*': + schema: + $ref: '#/components/schemas/COAResponse' + "400": + description: Failed to process the request + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + "500": + description: Internal server error + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + /chartOfAccount/v1/_search: + post: + tags: + - COA + summary: Get the list COA. + description: | + Based on the criteria get the list of COA. + requestBody: + description: RequestHeader meta data. + content: + application/json: + schema: + $ref: '#/components/schemas/COASearchRequest' + required: true + responses: + "200": + description: Successful response + content: + '*/*': + schema: + $ref: '#/components/schemas/COAResponse' + "400": + description: Invalid input. + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + "500": + description: Internal server error + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + /department/v1/_create: + post: + tags: + - Department + summary: Create/Add new department on iFix for a tenant + description: Create/Add new department on iFix for a tenant + requestBody: + description: Details for the new department + RequestHeader (meta data of the API). + content: + application/json: + schema: + $ref: '#/components/schemas/DepartmentRequest' + required: true + responses: + "202": + description: Request has been accepted for processing + content: + '*/*': + schema: + $ref: '#/components/schemas/DepartmentResponse' + "400": + description: Failed to process the request + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + "500": + description: Internal server error + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + /department/v1/_search: + post: + tags: + - Department + summary: Get the list departments. + description: | + Based on the criteria get the list of departments. + requestBody: + description: Details for the department search criteria + RequestHeader (meta data of the API). + content: + application/json: + schema: + $ref: '#/components/schemas/DepartmentSearchRequest' + required: true + responses: + "200": + description: Successful response + content: + '*/*': + schema: + $ref: '#/components/schemas/DepartmentResponse' + "400": + description: Invalid input. + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + "500": + description: Internal server error + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + /expenditure/v1/_create: + post: + tags: + - Expenditure + summary: Create/Add new Expenditure on iFix for a tenant + description: Create/Add new Expenditure on iFix for a tenant + requestBody: + description: Details for the new Expenditure + RequestHeader (meta data of the API). + content: + application/json: + schema: + $ref: '#/components/schemas/ExpenditureRequest' + required: true + responses: + "202": + description: Request has been accepted for processing + content: + '*/*': + schema: + $ref: '#/components/schemas/ExpenditureResponse' + "400": + description: Failed to process the request + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + "500": + description: Internal server error + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + /expenditure/v1/_search: + post: + tags: + - Expenditure + summary: Get the list Expenditure. + description: | + Based on the criteria get the list of Expenditure. + requestBody: + description: Details for the Expenditure search criteria + RequestHeader (meta data of the API). + content: + application/json: + schema: + $ref: '#/components/schemas/ExpenditureSearchRequest' + required: true + responses: + "200": + description: Successful response + content: + '*/*': + schema: + $ref: '#/components/schemas/ExpenditureResponse' + "400": + description: Invalid input. + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + "500": + description: Internal server error + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + /project/v1/_create: + post: + tags: + - Project + summary: Create/Add new project on iFix for a tenant + description: Create/Add new project on iFix for a tenant + requestBody: + description: Details for the new Project + RequestHeader (meta data of the API). + content: + application/json: + schema: + $ref: '#/components/schemas/ProjectRequest' + required: true + responses: + "202": + description: Request has been accepted for processing + content: + '*/*': + schema: + $ref: '#/components/schemas/ProjectResponse' + "400": + description: Failed to process the request + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + "500": + description: Internal server error + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + /project/v1/_search: + post: + tags: + - Project + summary: Get the list Project. + description: | + Based on the criteria get the list of Project. + requestBody: + description: Details for the Project search criteria + RequestHeader (meta data of the API). + content: + application/json: + schema: + $ref: '#/components/schemas/ProjectSearchRequest' + required: true + responses: + "200": + description: Successful response + content: + '*/*': + schema: + $ref: '#/components/schemas/ProjectResponse' + "400": + description: Invalid input. + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + "500": + description: Internal server error + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' +components: + schemas: + Government: + required: + - id + - name + type: object + properties: + id: + maxLength: 64 + minLength: 1 + type: string + description: Unique tenant id(eg- pb) + name: + maxLength: 256 + minLength: 2 + type: string + description: name of the tenant + auditDetails: + $ref: '#/components/schemas/AuditDetails' + attributes: + type: object + description: This object captures the fiscal information of external systems. + ChartOfAccount: + required: + - groupHead + - majorHead + - minorHead + - objectHead + - subHead + - subMajorHead + type: object + properties: + id: + maxLength: 64 + minLength: 1 + type: string + description: Unique system generated UUID + readOnly: true + coaCode: + maxLength: 64 + minLength: 1 + type: string + description: Chart of account concatinated string + readOnly: true + tenantId: + maxLength: 64 + minLength: 1 + type: string + description: Unique tenant identifier + majorHead: + maxLength: 4 + minLength: 4 + type: string + description: Capture the major head code + nullable: false + majorHeadName: + maxLength: 64 + minLength: 2 + type: string + description: Capture the major head code name + nullable: false + majorHeadType: + maxLength: 32 + minLength: 2 + type: string + description: Capture the major head code type + example: Revenue + subMajorHead: + maxLength: 2 + minLength: 2 + type: string + description: Capture the sub major head code + subMajorHeadName: + maxLength: 64 + minLength: 2 + type: string + description: Capture the sub major head code name + minorHead: + maxLength: 3 + minLength: 3 + type: string + description: Capture the minor head code + minorHeadName: + maxLength: 64 + minLength: 2 + type: string + description: Capture the minor head code name + subHead: + maxLength: 2 + minLength: 2 + type: string + description: Capture the sub head code + subHeadName: + maxLength: 64 + minLength: 2 + type: string + description: Capture the sub head code name + groupHead: + maxLength: 2 + minLength: 2 + type: string + description: Capture the group head code + groupHeadName: + maxLength: 64 + minLength: 2 + type: string + description: Capture the group head code name + objectHead: + maxLength: 2 + minLength: 2 + type: string + description: Capture the object head code + objectHeadName: + maxLength: 64 + minLength: 2 + type: string + description: Capture the object head code name + auditDetails: + $ref: '#/components/schemas/AuditDetails' + description: Captures the COA data as map + Department: + required: + - code + - name + - tenantId + type: object + properties: + id: + maxLength: 64 + minLength: 1 + type: string + description: Unique system generated UUID + readOnly: true + tenantId: + maxLength: 64 + minLength: 1 + type: string + description: Unique tenant identifier + code: + maxLength: 64 + minLength: 1 + type: string + description: Capture unique department code + name: + maxLength: 256 + minLength: 2 + type: string + description: Capture the name of the department + isNodal: + type: boolean + description: If it is nodal department then the value will be true + default: false + parent: + maxLength: 64 + minLength: 1 + type: string + description: parent department id + auditDetails: + $ref: '#/components/schemas/AuditDetails' + description: Captures the department attributes + Expenditure: + required: + - code + - name + - tenantId + - type + type: object + properties: + id: + maxLength: 64 + minLength: 1 + type: string + description: Unique system generated UUID + readOnly: true + tenantId: + maxLength: 64 + minLength: 1 + type: string + description: Unique tenant identifier + code: + maxLength: 64 + minLength: 1 + type: string + description: Capture unique expenditure code + name: + maxLength: 256 + minLength: 2 + type: string + description: Capture the name of the expenditure + type: + type: string + description: Capture the type of the expenditure + enum: + - Scheme + - Non-Scheme + departmentId: + maxLength: 64 + minLength: 1 + type: string + description: Department id from department master + auditDetails: + $ref: '#/components/schemas/AuditDetails' + description: Captures the Expenditure attributes + DepartmentEntityAttributes: + type: object + properties: + id: + maxLength: 64 + minLength: 1 + type: string + description: Unique system generated UUID + readOnly: true + code: + maxLength: 256 + minLength: 1 + type: string + description: Unique the department entity code + name: + maxLength: 256 + minLength: 1 + type: string + description: Captures the department entity name + hierarchyLevel: + maxLength: 256 + minLength: 1 + type: number + description: Capture the level of the given department entity + description: The list basic attributes of a department entity that are stored as part of the ancestry list + DepartmentEntity: + required: + - code + - hierarchyLevelId + - id + - name + type: object + properties: + id: + maxLength: 64 + minLength: 1 + type: string + description: Unique system generated UUID + readOnly: true + code: + maxLength: 256 + minLength: 1 + type: string + description: Unique the department entity code + name: + maxLength: 256 + minLength: 1 + type: string + description: Captures the department entity name + hierarchyLevel: + maxLength: 256 + minLength: 1 + type: number + description: Capture the level of the given department entity + ancestry: + type: array + items: + $ref: '#/components/schemas/DepartmentEntityAttributes' + description: This object captures the information for department entity + readOnly: true + Project: + required: + - code + - name + - tenantId + type: object + properties: + id: + maxLength: 64 + minLength: 1 + type: string + description: Unique system generated UUID + readOnly: true + tenantId: + maxLength: 64 + minLength: 1 + type: string + description: Unique tenant identifier + code: + maxLength: 64 + minLength: 1 + type: string + description: Capture unique Project code + name: + maxLength: 256 + minLength: 2 + type: string + description: Capture the name of the project + expenditureId: + maxLength: 64 + minLength: 2 + type: string + description: Capture the expenditure id from expenditure master + departmentEntitytId: + maxLength: 64 + minLength: 2 + type: string + description: Capture the department entity id from department entity master + departmentEntity: + $ref: '#/components/schemas/DepartmentEntity' + locationIds: + type: array + description: Capture the location id from location master + items: + type: string + auditDetails: + $ref: '#/components/schemas/AuditDetails' + description: Captures the Project attributes + GovernmentRequest: + required: + - government + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + government: + $ref: '#/components/schemas/Government' + description: Tenant request along with request metadata + GovernmentResponse: + properties: + responseHeader: + $ref: '#/components/schemas/ResponseHeader' + government: + type: array + items: + $ref: '#/components/schemas/Government' + description: Contains the ResponseHeader and the enriched tenant information + GovernmentSearchRequest: + required: + - criteria + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + criteria: + $ref: '#/components/schemas/GovernmentSearchCriteria' + description: Tenant search request along with request metadata + GovernmentSearchCriteria: + type: object + properties: + Ids: + type: array + description: List of fund ids + items: + maxItems: 50 + type: string + description: The object contains all the search criteria of the tenant + COARequest: + required: + - coa + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + chartOfAccount: + $ref: '#/components/schemas/ChartOfAccount' + description: COA request along with request metadata + COAResponse: + properties: + responseHeader: + $ref: '#/components/schemas/ResponseHeader' + chartOfAccounts: + type: array + items: + $ref: '#/components/schemas/ChartOfAccount' + description: Contains the ResponseHeader and the enriched COA information + COASearchRequest: + required: + - criteria + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + criteria: + $ref: '#/components/schemas/COASearchCriteria' + description: COA search request along with request metadata. Defoult operator b/w multiple criteria is AND. + COASearchCriteria: + required: + - tenantId + type: object + properties: + Ids: + type: array + description: List of COA ids + items: + maxItems: 50 + type: string + tenantId: + maxLength: 64 + minLength: 2 + type: string + description: Tenant Id + coaCode: + maxLength: 64 + minLength: 1 + type: string + description: Chart of account concatinated string + majorHead: + maxLength: 4 + minLength: 4 + type: string + description: Search by major head + subMajorHead: + maxLength: 2 + minLength: 2 + type: string + description: Search by sub major head + minorHead: + maxLength: 3 + minLength: 3 + type: string + description: Search by minor head + subHead: + maxLength: 2 + minLength: 2 + type: string + description: Search by sub head + groupHead: + maxLength: 2 + minLength: 2 + type: string + description: Search by group head + objectHead: + maxLength: 2 + minLength: 2 + type: string + description: Search by object head + description: The object contains all the search criteria of the fund + DepartmentRequest: + required: + - department + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + department: + $ref: '#/components/schemas/Department' + description: Department request along with request metadata + DepartmentResponse: + properties: + responseHeader: + $ref: '#/components/schemas/ResponseHeader' + department: + type: array + items: + $ref: '#/components/schemas/Department' + description: Contains the ResponseHeader and the enriched Department information + DepartmentSearchRequest: + required: + - criteria + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + criteria: + $ref: '#/components/schemas/DepartmentSearchCriteria' + description: Department search request along with request metadata. Defoult operator b/w multiple criteria is AND. + DepartmentSearchCriteria: + required: + - tenantId + type: object + properties: + Ids: + type: array + description: List of Department ids + items: + maxItems: 50 + type: string + tenantId: + maxLength: 64 + minLength: 2 + type: string + description: Tenant Id + name: + maxLength: 256 + minLength: 2 + type: string + description: Search by department name + code: + maxLength: 64 + minLength: 2 + type: string + description: Search by department code + description: The object contains all the search criteria of the Department + ExpenditureRequest: + required: + - expenditure + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + expenditure: + $ref: '#/components/schemas/Expenditure' + description: Expenditure request along with request metadata + ExpenditureResponse: + properties: + responseHeader: + $ref: '#/components/schemas/ResponseHeader' + Expenditure: + type: array + items: + $ref: '#/components/schemas/Expenditure' + description: Contains the ResponseHeader and the enriched Expenditure information + ExpenditureSearchRequest: + required: + - criteria + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + criteria: + $ref: '#/components/schemas/ExpenditureSearchCriteria' + description: Expenditure search request along with request metadata. Defoult operator b/w multiple criteria is AND. + ExpenditureSearchCriteria: + required: + - tenantId + type: object + properties: + Ids: + type: array + description: List of Expenditure ids + items: + maxItems: 50 + type: string + tenantId: + maxLength: 64 + minLength: 2 + type: string + description: Tenant Id + name: + maxLength: 256 + minLength: 2 + type: string + description: Search by Expenditure name + code: + maxLength: 64 + minLength: 2 + type: string + description: Search by Expenditure code + description: The object contains all the search criteria of the Expenditure + ProjectRequest: + required: + - project + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + project: + $ref: '#/components/schemas/Project' + description: Project request along with request metadata + ProjectResponse: + properties: + responseHeader: + $ref: '#/components/schemas/ResponseHeader' + project: + type: array + items: + $ref: '#/components/schemas/Project' + description: Contains the ResponseHeader and the enriched Project information + ProjectSearchRequest: + required: + - criteria + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + criteria: + $ref: '#/components/schemas/ProjectSearchCriteria' + description: Project search request along with request metadata. Default operator b/w multiple criteria is AND + ProjectSearchCriteria: + required: + - tenantId + type: object + properties: + Ids: + type: array + description: List of Project ids + items: + maxItems: 50 + type: string + tenantId: + maxLength: 64 + minLength: 2 + type: string + description: Tenant Id + name: + maxLength: 256 + minLength: 2 + type: string + description: Search by Project name + code: + maxLength: 64 + minLength: 2 + type: string + description: Search by Project code + expenditureId: + maxLength: 64 + minLength: 2 + type: string + description: Capture the expenditure id from expenditure master + departmentId: + maxLength: 64 + minLength: 2 + type: string + description: Capture the department id from department master + locationId: + maxLength: 64 + minLength: 2 + type: string + description: Capture the location id from location master + description: The object contains all the search criteria of the Project + ErrorResponse: + required: + - ResponseHeader + type: object + properties: + ResponseHeader: + $ref: '#/components/schemas/ResponseHeader' + Errors: + minLength: 1 + type: array + description: Error response array to return multiple error for single request + items: + $ref: '#/components/schemas/Error' + description: All APIs will return ErrorRes in case of failure which will carry ResponseHeader as metadata and Error object as actual representation of error. + ResponseHeader: + type: object + properties: + ts: + type: integer + description: response time in epoch + format: int64 + correlationId: + maxLength: 256 + type: string + description: unique response message id (UUID) - will usually be the correlation id from the server + msgId: + maxLength: 256 + type: string + description: message id of the request + status: + type: string + description: status of request processing + enum: + - SUCCESS + - FAILED + signature: + type: string + description: Hash describing the current Request + version: + maxLength: 64 + minLength: 2 + type: string + description: The version of the API + nullable: false + description: ResponseHeader should be used to carry metadata information about the response from the server. apiId, ver and msgId in ResponseHeader should always correspond to the same values in respective request's RequestHeader. + readOnly: true + Error: + required: + - code + - description + - message + type: object + properties: + code: + type: string + description: Error Code will be service specific error label/code to identiffy the error. Example for error code would be User.NotFound to indicate User Not Found by User/Authentication service. All services must declare their possible Error Codes with brief description in the error response section of their API path. + message: + type: string + description: Human readable error message + description: + type: string + description: technical description of the error which can help developer to debug the error if error is unexpected. + description: Error object will be returned as a part of reponse body in conjunction with ResponseHeader as part of ErrorResponse whenever the request processing status in the ResponseHeader is FAILED. HTTP return in this scenario will usually be HTTP 400. + AuditDetails: + type: object + properties: + createdBy: + type: string + description: UUID (preferred) or userid of the user that created the object + readOnly: true + lastModifiedBy: + type: string + description: UUID (preferred) or userid of the user that last modified the object + readOnly: true + createdTime: + type: integer + description: epoch of the time object is created + format: int64 + readOnly: true + lastModifiedTime: + type: integer + description: epoch of the time object is last modified + format: int64 + readOnly: true + description: Collection of audit related fields used by most models + readOnly: true + RequestHeader: + type: object + properties: + ts: + type: integer + description: time in epoch + format: int64 + nullable: false + version: + maxLength: 64 + minLength: 2 + type: string + description: The version of the API + nullable: false + msgId: + maxLength: 256 + type: string + description: Unique request message id from the caller + userInfo: + $ref: '#/components/schemas/UserInfo' + correlationId: + type: string + readOnly: true + signature: + type: string + description: Hash describing the current RequestHeader + description: RequestHeader should be used to carry meta information about the requests to the server as described in the fields below. All eGov APIs will use requestHeader as a part of the request body to carry this meta information. Some of this information will be returned back from the server as part of the ResponseHeader in the response body to ensure correlation. + UserInfo: + type: object + properties: + uuid: + type: string + description: System Generated User id of the authenticated user. + roles: + type: array + description: List of roles assigned to a user + items: + type: string + tenants: + type: array + description: List of tenants assigned to a user + items: + type: string + attributes: + type: object + description: Capture the user information + readOnly: true diff --git a/domain-services/ifix-master-data-service/src/main/resources/db/migration/V20210811131300__create_index b/domain-services/ifix-master-data-service/src/main/resources/db/migration/V20210811131300__create_index new file mode 100644 index 00000000..c470f94e --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/resources/db/migration/V20210811131300__create_index @@ -0,0 +1,24 @@ +db.government.createIndexes( + [{"name":1}] + ); +db.government.getIndexes(); + +db.department.createIndexes( + [{"name":1},{"code":1},{"tenantId":1}] + ); +db.department.getIndexes(); + +db.chartOfAccount.createIndexes( + [{"coaCode":1},{"majorHead":1},{"tenantId":1},{"subMajorHead":1},{"minorHead":1},{"subHead":1},{"groupHead":1},{"objectHead":1}] + ); +db.chartOfAccount.getIndexes(); + +db.expenditure.createIndexes( + [{"name":1},{"code":1},{"tenantId":1}] +); +db.expenditure.getIndexes(); + +db.project.createIndexes( + [{"name":1},{"code":1},{"tenantId":1},{"expenditureId":1},{"departmentId":1}] +); +db.project.getIndexes(); \ No newline at end of file diff --git a/domain-services/ifix-master-data-service/src/test/java/org/egov/TestConfiguration.java b/domain-services/ifix-master-data-service/src/test/java/org/egov/TestConfiguration.java new file mode 100644 index 00000000..d13056a1 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/test/java/org/egov/TestConfiguration.java @@ -0,0 +1,16 @@ +package org.egov; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.core.KafkaTemplate; + +import static org.mockito.Mockito.mock; + +@Configuration +public class TestConfiguration { + @Bean + @SuppressWarnings("unchecked") + public KafkaTemplate kafkaTemplate() { + return mock(KafkaTemplate.class); + } +} \ No newline at end of file diff --git a/reference-dashboard/fiscal-event-aggregator/.gitignore b/reference-dashboard/fiscal-event-aggregator/.gitignore new file mode 100644 index 00000000..549e00a2 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/reference-dashboard/fiscal-event-aggregator/CHANGELOG.md b/reference-dashboard/fiscal-event-aggregator/CHANGELOG.md new file mode 100644 index 00000000..43928dc4 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/CHANGELOG.md @@ -0,0 +1,5 @@ +# Changelog +All notable changes to this module will be documented in this file. + +## 1.0.0 - 2021-09-24 +- Baseline version released diff --git a/reference-dashboard/fiscal-event-aggregator/LOCALSETUP.md b/reference-dashboard/fiscal-event-aggregator/LOCALSETUP.md new file mode 100644 index 00000000..e3dc6f21 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/LOCALSETUP.md @@ -0,0 +1,13 @@ +# Local Setup + +To setup the fiscal event aggregate in your local system, clone the [fiscal-event-aggregate](https://github.com/egovernments/iFix-Dev/tree/develop/reference-dashboard). + + +## Infra Dependency + +- [x] Postgres DB +- [x] Druid DB + +## Running Locally + +Run as standalone java program in your local system. diff --git a/reference-dashboard/fiscal-event-aggregator/README.md b/reference-dashboard/fiscal-event-aggregator/README.md new file mode 100644 index 00000000..158a5aff --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/README.md @@ -0,0 +1,23 @@ +# fiscal event aggregator + +Fiscal Event Aggregator is a java standalone application, which will be running as cron job to aggregate the fiscal event data from Druid data store to Postgres DB.It will pull all the fiscal event data as + +1. Group by of project id, coa id and event type And sum of amounts. +2. Pending collection(s) w.r.t distinct project id(s). +3. Pending payment(s) w.r.t distinct project id(s). + +Aggregate these all data and push it to postgres DB. + +# Running in Specific environment + +This service has been configured as cron job. Hence to run this service , first check in the specific environment that this service has been configured as cron job or not. To check run the below command + +```bash +kubectl get cronjobs +``` +If you want to run this program manually, use the below command + +```bash +kubectl create job --from=cronjob/fiscal-event-aggregator +``` +You can use custom name in place of "manual-job-name". \ No newline at end of file diff --git a/reference-dashboard/fiscal-event-aggregator/pom.xml b/reference-dashboard/fiscal-event-aggregator/pom.xml new file mode 100644 index 00000000..c36b66b9 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/pom.xml @@ -0,0 +1,75 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.5.4 + + + org.egov + fiscal-event-aggregator + 1.0.0-SNAPSHOT + fiscal-event-aggregator + Aggregate the fiscal event post processed data + + 1.8 + + + + org.springframework.boot + spring-boot-starter + + + org.flywaydb + flyway-core + + + org.postgresql + postgresql + runtime + + + org.springframework.boot + spring-boot-starter-jdbc + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + in.zapr.druid + druidry + 3.1 + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/FiscalEventAggregatorApplication.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/FiscalEventAggregatorApplication.java new file mode 100644 index 00000000..49757c7a --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/FiscalEventAggregatorApplication.java @@ -0,0 +1,15 @@ +package org.egov; + +import lombok.Data; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +@Data +public class FiscalEventAggregatorApplication { + + public static void main(String[] args) { + SpringApplication.run(FiscalEventAggregatorApplication.class, args); + } + +} diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/ConfigProperties.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/ConfigProperties.java new file mode 100644 index 00000000..580cfd96 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/ConfigProperties.java @@ -0,0 +1,29 @@ +package org.egov.ifix.aggregate.config; + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +@Data +public class ConfigProperties { + + @Value("${app.timezone}") + private String timeZone; + + @Value("${druid.host}") + private String druidHost; + + @Value("${druid.endPoint}") + private String druidEndPoint; + + @Value("${fiscal.event.datasource}") + private String fiscalEventDataSource; + + @Value("${druid.connect.protocol}") + private String druidConnectProtocol; + + @Value("${druid.connect.port}") + private String druidConnectPort; + +} diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/FiscalEventConfiguration.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/FiscalEventConfiguration.java new file mode 100644 index 00000000..e458d37d --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/FiscalEventConfiguration.java @@ -0,0 +1,50 @@ +package org.egov.ifix.aggregate.config; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import in.zapr.druid.druidry.client.DruidClient; +import in.zapr.druid.druidry.client.DruidConfiguration; +import in.zapr.druid.druidry.client.DruidJerseyClient; +import in.zapr.druid.druidry.client.DruidQueryProtocol; +import in.zapr.druid.druidry.client.exception.ConnectionException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.TimeZone; + + +@Configuration +@Slf4j +public class FiscalEventConfiguration { + + @Autowired + private ConfigProperties configProperties; + + @Bean + public ObjectMapper objectMapper() { + return new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) + .setTimeZone(TimeZone.getTimeZone(configProperties.getTimeZone())); + } + + @Bean + public DruidClient getDruidClient() { + DruidConfiguration config = DruidConfiguration + .builder() + .protocol(DruidQueryProtocol.valueOf(configProperties.getDruidConnectProtocol())) + .port(Integer.valueOf(configProperties.getDruidConnectPort())) + .host(configProperties.getDruidHost()) + .endpoint(configProperties.getDruidEndPoint()) + .build(); + + DruidClient client = new DruidJerseyClient(config); + try { + client.connect(); + log.debug("Druid Client connection: " + client); + } catch (ConnectionException e) { + log.error("Exception occurred while getting the druid client -{}", e.getStackTrace()); + } + return client; + } +} diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/model/FiscalEventAggregate.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/model/FiscalEventAggregate.java new file mode 100644 index 00000000..08651a96 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/model/FiscalEventAggregate.java @@ -0,0 +1,99 @@ +package org.egov.ifix.aggregate.model; + +import lombok.*; + +import java.math.BigDecimal; +import java.math.BigInteger; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +@ToString +@EqualsAndHashCode +public class FiscalEventAggregate { + private String ver; + private String tenantId; + private String government_id; + private String government_name; + private String type; + private BigDecimal sumAmount; + private String fiscalPeriod; + private BigInteger count; + private String department_id; + private String department_code; + private String department_name; + + private String departmentEntity_id; + private String departmentEntity_code; + private String departmentEntity_name; + private Integer departmentEntity_hierarchyLevel; + + private String departmentEntity_ancestry_0_id; + private String departmentEntity_ancestry_0_code; + private String departmentEntity_ancestry_0_name; + private Integer departmentEntity_ancestry_0_hierarchyLevel; + private String departmentEntity_ancestry_1_id; + private String departmentEntity_ancestry_1_code; + private String departmentEntity_ancestry_1_name; + private Integer departmentEntity_ancestry_1_hierarchyLevel; + private String departmentEntity_ancestry_2_id; + private String departmentEntity_ancestry_2_code; + private String departmentEntity_ancestry_2_name; + private Integer departmentEntity_ancestry_2_hierarchyLevel; + private String departmentEntity_ancestry_3_id; + private String departmentEntity_ancestry_3_code; + private String departmentEntity_ancestry_3_name; + private Integer departmentEntity_ancestry_3_hierarchyLevel; + private String departmentEntity_ancestry_4_id; + private String departmentEntity_ancestry_4_code; + private String departmentEntity_ancestry_4_name; + private Integer departmentEntity_ancestry_4_hierarchyLevel; + private String departmentEntity_ancestry_5_id; + private String departmentEntity_ancestry_5_code; + private String departmentEntity_ancestry_5_name; + private Integer departmentEntity_ancestry_5_hierarchyLevel; + private String departmentEntity_ancestry_6_id; + private String departmentEntity_ancestry_6_code; + private String departmentEntity_ancestry_6_name; + private Integer departmentEntity_ancestry_6_hierarchyLevel; + private String departmentEntity_ancestry_7_id; + private String departmentEntity_ancestry_7_code; + private String departmentEntity_ancestry_7_name; + private Integer departmentEntity_ancestry_7_hierarchyLevel; + private String departmentEntity_ancestry_8_id; + private String departmentEntity_ancestry_8_code; + private String departmentEntity_ancestry_8_name; + private Integer departmentEntity_ancestry_8_hierarchyLevel; + private String departmentEntity_ancestry_9_id; + private String departmentEntity_ancestry_9_code; + private String departmentEntity_ancestry_9_name; + private Integer departmentEntity_ancestry_9_hierarchyLevel; + private String departmentEntity_ancestry_10_id; + private String departmentEntity_ancestry_10_code; + private String departmentEntity_ancestry_10_name; + private Integer departmentEntity_ancestry_10_hierarchyLevel; + private String expenditure_id; + private String expenditure_code; + private String expenditure_name; + private String expenditure_type; + private String project_id; + private String project_code; + private String project_name; + private String coa_id; + private String coa_coaCode; + private String coa_majorHead; + private String coa_majorHeadName; + private String coa_majorHeadType; + private String coa_subMajorHead; + private String coa_subMajorHeadName; + private String coa_minorHead; + private String coa_minorHeadName; + private String coa_subHead; + private String coa_subHeadName; + private String coa_groupHead; + private String coa_groupHeadName; + private String coa_objectHead; + private String coa_objectHeadName; +} diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java new file mode 100644 index 00000000..9b2db516 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java @@ -0,0 +1,285 @@ +package org.egov.ifix.aggregate.processor; + + +import com.fasterxml.jackson.databind.JsonNode; +import in.zapr.druid.druidry.aggregator.CountAggregator; +import in.zapr.druid.druidry.aggregator.DoubleSumAggregator; +import in.zapr.druid.druidry.aggregator.DruidAggregator; +import in.zapr.druid.druidry.client.DruidClient; +import in.zapr.druid.druidry.client.exception.QueryException; +import in.zapr.druid.druidry.dataSource.TableDataSource; +import in.zapr.druid.druidry.dimension.DefaultDimension; +import in.zapr.druid.druidry.dimension.DruidDimension; +import in.zapr.druid.druidry.dimension.enums.OutputType; +import in.zapr.druid.druidry.filter.SelectorFilter; +import in.zapr.druid.druidry.granularity.Granularity; +import in.zapr.druid.druidry.granularity.PredefinedGranularity; +import in.zapr.druid.druidry.granularity.SimpleGranularity; +import in.zapr.druid.druidry.query.DruidQuery; +import in.zapr.druid.druidry.query.aggregation.DruidGroupByQuery; +import in.zapr.druid.druidry.query.config.Interval; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.ifix.aggregate.config.ConfigProperties; +import org.egov.ifix.aggregate.model.FiscalEventAggregate; +import org.egov.ifix.aggregate.util.FiscalEventAggregateConstants; +import org.egov.ifix.aggregate.util.FiscalEventAggregateUtil; +import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +@Component +@Slf4j +public class DruidDataQueryProcessor { + + @Autowired + private DruidClient druidClient; + + @Autowired + private ConfigProperties configProperties; + + @Autowired + private FiscalEventAggregateUtil aggregateUtil; + + /** + * Fetch the fiscal event data with total sum amount , count from druid date store + * based on the group of project id, coa id, event type + * @return + */ + public List fetchFiscalEventFromDruid() { + Map fiscalYearMap = aggregateUtil.getFiscalYear(); + List finalFiscalEventAggregates = new ArrayList<>(); + + for (String fyKey : fiscalYearMap.keySet()) { + int fiscalYear = fiscalYearMap.get(fyKey); + + DruidQuery groupByQuery = getDruidQueryForGroupbyProjectIdAndCoaIdAndEventType(fiscalYear); + DruidQuery distinctProjectQuery = getDruidQueryForProjectDetails(fiscalYear); + DruidQuery distinctCoaIdQuery = getDruidQueryForCoaDetails(fiscalYear); + DruidQuery demandEventTypeQuery = getDruidQueryForProjectIdAndSumAmountBy(FiscalEventAggregateConstants.EVENT_TYPE_DEMAND,fiscalYear); + DruidQuery receiptEventTypeQuery = getDruidQueryForProjectIdAndSumAmountBy(FiscalEventAggregateConstants.EVENT_TYPE_RECEIPT,fiscalYear); + DruidQuery billEventTypeQuery = getDruidQueryForProjectIdAndSumAmountBy(FiscalEventAggregateConstants.EVENT_TYPE_BILL,fiscalYear); + DruidQuery paymentEventTypeQuery = getDruidQueryForProjectIdAndSumAmountBy(FiscalEventAggregateConstants.EVENT_TYPE_PAYMENT,fiscalYear); + + List groupByResponses = null; + List distinctProjectResponses = null; + List distinctCoaIdResponses = null; + List demandEventTypeResponses = null; + List receiptEventTypeResponses = null; + List billEventTypeResponses = null; + List paymentEventTypeResponses = null; + try { + groupByResponses = druidClient.query(groupByQuery, Object.class); + log.info("Size of record returned from Group by query : {} for fiscal year : {}", groupByResponses.size(), fiscalYear); + distinctProjectResponses = druidClient.query(distinctProjectQuery, Object.class); + log.info("Size of record returned from distinct project id query : {} for fiscal year : {}", distinctProjectResponses.size(), fiscalYear); + distinctCoaIdResponses = druidClient.query(distinctCoaIdQuery, Object.class); + log.info("Size of record returned from distinct coa id query : {} for fiscal year : {}", distinctCoaIdResponses.size(), fiscalYear); + + demandEventTypeResponses = druidClient.query(demandEventTypeQuery, Object.class); + log.info("Size of record returned from demand event type query : {} for fiscal year : {}", demandEventTypeResponses.size(), fiscalYear); + receiptEventTypeResponses = druidClient.query(receiptEventTypeQuery, Object.class); + log.info("Size of record returned from receipt event type query : {} for fiscal year : {}", receiptEventTypeResponses.size(), fiscalYear); + + billEventTypeResponses = druidClient.query(billEventTypeQuery, Object.class); + log.info("Size of record returned from bill event type query : {} for fiscal year : {}", billEventTypeResponses.size(), fiscalYear); + paymentEventTypeResponses = druidClient.query(paymentEventTypeQuery, Object.class); + log.info("Size of record returned from payment event type query : {} for fiscal year : {}", paymentEventTypeResponses.size(), fiscalYear); + } catch (QueryException e) { + log.error("Exception occurred while querying the data from druid data store : {}", e.getDruidError()); + } + log.debug("Group by Response : {}", groupByResponses); + if (groupByResponses == null || groupByResponses.isEmpty()) { + log.info("There are no fiscal event data with group by of project id, event type and coa id for fiscal year : {}",fiscalYear); + continue; + } + + //Create a map of key as project id and event node details as value + Map projectNodeMap = aggregateUtil.getProjectDetailsMap(distinctProjectResponses); + //Create a map of key as coa id and event node details as value + Map coaNodeMap = aggregateUtil.getCOADetailsMap(distinctCoaIdResponses); + + //Create a map of key as project id and demand event node details as value + Map demandEventTypeNodeMap = aggregateUtil.getEventTypeMap(demandEventTypeResponses); + //Create a map of key as project id and receipt event node details as value + Map receiptEventTypeNodeMap = aggregateUtil.getEventTypeMap(receiptEventTypeResponses); + + //Create a map of key as project id and bill event node details as value + Map billEventTypeNodeMap = aggregateUtil.getEventTypeMap(billEventTypeResponses); + //Create a map of key as project id and payment event node details as value + Map paymentEventTypeNodeMap = aggregateUtil.getEventTypeMap(paymentEventTypeResponses); + + //Get the PENDING_COLLECTION aggregated fiscal event data + List pendingCollectionAggregatedList = aggregateUtil.getPendingCollectionFiscalEventAggregatedData(demandEventTypeNodeMap, receiptEventTypeNodeMap, projectNodeMap, + FiscalEventAggregateConstants.EVENT_TYPE_PENDING_COLLECTION,fiscalYear); + //Get the PENDING PAYMENT aggregated fiscal event data + List pendingPaymentAggregatedList = aggregateUtil.getPendingCollectionFiscalEventAggregatedData(billEventTypeNodeMap, paymentEventTypeNodeMap, projectNodeMap, + FiscalEventAggregateConstants.EVENT_TYPE_PENDING_PAYMENT, fiscalYear); + //Get the details by project id and coa id map key and create a List + List fiscalEventAggregates = aggregateUtil.getFiscalEventAggregateData(groupByResponses + , projectNodeMap, coaNodeMap,fiscalYear); + + finalFiscalEventAggregates.addAll(pendingCollectionAggregatedList); + finalFiscalEventAggregates.addAll(pendingPaymentAggregatedList); + finalFiscalEventAggregates.addAll(fiscalEventAggregates); + } + return finalFiscalEventAggregates; + } + + private DruidQuery getDruidQueryForProjectIdAndSumAmountBy(String eventType, int fiscalYear) { + TableDataSource dataSource = new TableDataSource(configProperties.getFiscalEventDataSource()); + + DateTime startTime = new DateTime(fiscalYear, 04, 1, 0, 0, 0, DateTimeZone.UTC); + DateTime endTime = new DateTime(fiscalYear + 1, 03, 31, 0, 0, 0, DateTimeZone.UTC); + Interval interval = new Interval(startTime, endTime); + + Granularity granularity = new SimpleGranularity(PredefinedGranularity.ALL); + + DruidDimension druidDimension = new DefaultDimension("project.id", "project.id", OutputType.STRING); + + SelectorFilter filter = new SelectorFilter("eventType", eventType); + + List aggregators = new ArrayList<>(); + aggregators.add(new DoubleSumAggregator("amount", "amount")); + + return (DruidGroupByQuery.builder() + .dataSource(dataSource) + .dimensions(Collections.singletonList(druidDimension)) + .granularity(granularity) + .filter(filter) + .aggregators(aggregators) + .intervals(Collections.singletonList(interval)) + .build()); + } + + + private DruidQuery getDruidQueryForCoaDetails(int fiscalYear) { + TableDataSource dataSource = new TableDataSource(configProperties.getFiscalEventDataSource()); + + DateTime startTime = new DateTime(fiscalYear, 04, 1, 0, 0, 0, DateTimeZone.UTC); + DateTime endTime = new DateTime(fiscalYear + 1, 03, 31, 0, 0, 0, DateTimeZone.UTC); + Interval interval = new Interval(startTime, endTime); + + Granularity granularity = new SimpleGranularity(PredefinedGranularity.ALL); + + List druidDimensions = new ArrayList<>(); + druidDimensions.add(new DefaultDimension("coa.id", "coa.id", OutputType.STRING)); + + druidDimensions.add(new DefaultDimension("coa.coaCode", "coa.coaCode", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("coa.groupHead", "coa.groupHead", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("coa.groupHeadName", "coa.groupHeadName", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("coa.majorHead", "coa.majorHead", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("coa.majorHeadName", "coa.majorHeadName", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("coa.minorHead", "coa.minorHead", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("coa.minorHeadName", "coa.minorHeadName", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("coa.objectHead", "coa.objectHead", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("coa.objectHeadName", "coa.objectHeadName", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("coa.subHead", "coa.subHead", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("coa.subHeadName", "coa.subHeadName", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("coa.subMajorHead", "coa.subMajorHead", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("coa.subMajorHeadName", "coa.subMajorHeadName", OutputType.STRING)); + +// List aggregators = new ArrayList<>(); +// aggregators.add(new DistinctCountAggregator("coa.id","coa.id")); + + return (DruidGroupByQuery.builder() + .dataSource(dataSource) + .dimensions(druidDimensions) + .granularity(granularity) + .filter(null) + //.aggregators(aggregators) + .intervals(Collections.singletonList(interval)) + .build()); + } + + + private DruidQuery getDruidQueryForProjectDetails(int fiscalYear) { + TableDataSource dataSource = new TableDataSource(configProperties.getFiscalEventDataSource()); + + DateTime startTime = new DateTime(fiscalYear, 04, 1, 0, 0, 0, DateTimeZone.UTC); + DateTime endTime = new DateTime(fiscalYear + 1, 03, 31, 0, 0, 0, DateTimeZone.UTC); + Interval interval = new Interval(startTime, endTime); + + Granularity granularity = new SimpleGranularity(PredefinedGranularity.ALL); + + List druidDimensions = new ArrayList<>(); + druidDimensions.add(new DefaultDimension("project.id", "project.id", OutputType.STRING)); + + druidDimensions.add(new DefaultDimension("department.code", "department.code", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("department.id", "department.id", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("department.name", "department.name", OutputType.STRING)); + + druidDimensions.add(new DefaultDimension("expenditure.code", "expenditure.code", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("expenditure.id", "expenditure.id", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("expenditure.name", "expenditure.name", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("expenditure.type", "expenditure.type", OutputType.STRING)); + + druidDimensions.add(new DefaultDimension("tenantId", "tenantId", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("government.id", "government.id", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("government.name", "government.name", OutputType.STRING)); + + druidDimensions.add(new DefaultDimension("departmentEntity.id", "departmentEntity.id", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("departmentEntity.code", "departmentEntity.code", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("departmentEntity.name", "departmentEntity.name", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("departmentEntity.hierarchyLevel", "departmentEntity.hierarchyLevel", OutputType.STRING)); + + druidDimensions.add(new DefaultDimension("project.code", "project.code", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("project.name", "project.name", OutputType.STRING)); + + int hierarchyLevel = FiscalEventAggregateConstants.DEFAULT_HIERARCHY_LEVEL; + + for (int i = 0; i <= hierarchyLevel; i++) { + druidDimensions.add(new DefaultDimension("departmentEntity.ancestry[" + i + "].code", "departmentEntity.ancestry[" + i + "].code", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("departmentEntity.ancestry[" + i + "].hierarchyLevel", "departmentEntity.ancestry[" + i + "].hierarchyLevel", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("departmentEntity.ancestry[" + i + "].id", "departmentEntity.ancestry[" + i + "].id", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("departmentEntity.ancestry[" + i + "].name", "departmentEntity.ancestry[" + i + "].name", OutputType.STRING)); + } + +// List aggregators = new ArrayList<>(); +// aggregators.add(new DistinctCountAggregator("project.id","project.id")); +// aggregators.add(new DoubleSumAggregator("amount", "amount")); + + return (DruidGroupByQuery.builder() + .dataSource(dataSource) + .dimensions(druidDimensions) + .granularity(granularity) + .filter(null) + //.aggregators(aggregators) + .intervals(Collections.singletonList(interval)) + .build()); + } + + private DruidGroupByQuery getDruidQueryForGroupbyProjectIdAndCoaIdAndEventType(int fiscalYear) { + TableDataSource dataSource = new TableDataSource(configProperties.getFiscalEventDataSource()); + + DateTime startTime = new DateTime(fiscalYear, 04, 1, 0, 0, 0, DateTimeZone.UTC); + DateTime endTime = new DateTime(fiscalYear + 1, 03, 31, 0, 0, 0, DateTimeZone.UTC); + Interval interval = new Interval(startTime, endTime); + + Granularity granularity = new SimpleGranularity(PredefinedGranularity.ALL); + + List druidDimensions = new ArrayList<>(); + druidDimensions.add(new DefaultDimension("project.id", "project.id", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("coa.id", "coa.id", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("eventType", "eventType", OutputType.STRING)); + + List aggregators = new ArrayList<>(); + aggregators.add(new CountAggregator("Count")); + aggregators.add(new DoubleSumAggregator("amount", "amount")); + + return (DruidGroupByQuery.builder() + .dataSource(dataSource) + .dimensions(druidDimensions) + .granularity(granularity) + .filter(null) + .aggregators(aggregators) + .intervals(Collections.singletonList(interval)) + .build()); + } +} diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/FiscalEventAggregateProcessor.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/FiscalEventAggregateProcessor.java new file mode 100644 index 00000000..de2387a4 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/FiscalEventAggregateProcessor.java @@ -0,0 +1,32 @@ +package org.egov.ifix.aggregate.processor; + +import lombok.extern.slf4j.Slf4j; +import org.egov.ifix.aggregate.model.FiscalEventAggregate; +import org.egov.ifix.aggregate.repository.FiscalEventAggregateRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Slf4j +@Component +public class FiscalEventAggregateProcessor implements ApplicationRunner { + + @Autowired + private DruidDataQueryProcessor druidDataQueryProcessor; + + @Autowired + private FiscalEventAggregateRepository aggregateRepository; + + @Override + public void run(ApplicationArguments args) throws Exception { + List fiscalEventAggregateList = druidDataQueryProcessor.fetchFiscalEventFromDruid(); + //pass the list for upsert + if (fiscalEventAggregateList != null && !fiscalEventAggregateList.isEmpty()) { + int[] upsertedRecord = aggregateRepository.upsert(fiscalEventAggregateList); + log.info("Record -> {} upserted successfully!", upsertedRecord != null ? upsertedRecord.length : 0); + } + } +} diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/FiscalEventAggregateRepository.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/FiscalEventAggregateRepository.java new file mode 100644 index 00000000..f816119e --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/FiscalEventAggregateRepository.java @@ -0,0 +1,27 @@ +package org.egov.ifix.aggregate.repository; + +import lombok.extern.slf4j.Slf4j; +import org.egov.ifix.aggregate.model.FiscalEventAggregate; +import org.egov.ifix.aggregate.repository.mapper.FiscalEventAggregateQuery; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.jdbc.core.namedparam.SqlParameterSource; +import org.springframework.jdbc.core.namedparam.SqlParameterSourceUtils; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +@Slf4j +public class FiscalEventAggregateRepository { + + @Autowired + private NamedParameterJdbcTemplate namedParameterJdbcTemplate; + + + public int[] upsert(List fiscalEventAggregates) { + SqlParameterSource[] batch = SqlParameterSourceUtils.createBatch(fiscalEventAggregates.toArray()); + return (namedParameterJdbcTemplate.batchUpdate(FiscalEventAggregateQuery.UPSERT_QUERY_FOR_FISCAL_EVENT_AGGREGATE, + batch)); + } +} diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/mapper/FiscalEventAggregateQuery.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/mapper/FiscalEventAggregateQuery.java new file mode 100644 index 00000000..2a360fe4 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/mapper/FiscalEventAggregateQuery.java @@ -0,0 +1,79 @@ +package org.egov.ifix.aggregate.repository.mapper; + + +import org.springframework.stereotype.Component; + +@Component +public class FiscalEventAggregateQuery { + + public static final String UPSERT_QUERY_FOR_FISCAL_EVENT_AGGREGATE = "INSERT INTO fiscal_event_aggregated" + + "(ver,tenantId,government_id,government_name,type,sumAmount,fiscalPeriod,count,department_id,department_code," + + "department_name,expenditure_id,expenditure_code,expenditure_name,expenditure_type,project_id,project_code,project_name,coa_id,coa_coaCode,coa_majorHead,coa_majorHeadName," + + "coa_majorHeadType,coa_subMajorHead,coa_subMajorHeadName,coa_minorHead,coa_minorHeadName,coa_subHead,coa_subHeadName," + + "coa_groupHead,coa_groupHeadName,coa_objectHead,coa_objectHeadName," + + "departmentEntity_ancestry_0_id,departmentEntity_ancestry_0_code,departmentEntity_ancestry_0_name,"+ + "departmentEntity_ancestry_0_hierarchyLevel,departmentEntity_ancestry_1_id,departmentEntity_ancestry_1_code,"+ + "departmentEntity_ancestry_1_name,departmentEntity_ancestry_1_hierarchyLevel,departmentEntity_ancestry_2_id," + + "departmentEntity_ancestry_2_code,departmentEntity_ancestry_2_name,departmentEntity_ancestry_2_hierarchyLevel," + + "departmentEntity_ancestry_3_id,departmentEntity_ancestry_3_code,departmentEntity_ancestry_3_name," + + "departmentEntity_ancestry_3_hierarchyLevel,departmentEntity_ancestry_4_id,departmentEntity_ancestry_4_code," + + "departmentEntity_ancestry_4_name,departmentEntity_ancestry_4_hierarchyLevel,departmentEntity_ancestry_5_id," + + "departmentEntity_ancestry_5_code,departmentEntity_ancestry_5_name,departmentEntity_ancestry_5_hierarchyLevel," + + "departmentEntity_ancestry_6_id,departmentEntity_ancestry_6_code,departmentEntity_ancestry_6_name," + + "departmentEntity_ancestry_6_hierarchyLevel,departmentEntity_ancestry_7_id,departmentEntity_ancestry_7_code," + + "departmentEntity_ancestry_7_name,departmentEntity_ancestry_7_hierarchyLevel,departmentEntity_ancestry_8_id," + + "departmentEntity_ancestry_8_code,departmentEntity_ancestry_8_name,departmentEntity_ancestry_8_hierarchyLevel," + + "departmentEntity_ancestry_9_id,departmentEntity_ancestry_9_code,departmentEntity_ancestry_9_name," + + "departmentEntity_ancestry_9_hierarchyLevel,departmentEntity_ancestry_10_id,departmentEntity_ancestry_10_code," + + "departmentEntity_ancestry_10_name,departmentEntity_ancestry_10_hierarchyLevel,departmentEntity_id,departmentEntity_code," + + "departmentEntity_name,departmentEntity_hierarchyLevel) " + + "VALUES" + + "(:ver,:tenantId,:government_id,:government_name,:type,:sumAmount,:fiscalPeriod,:count," + + ":department_id,:department_code,:department_name,:expenditure_id,:expenditure_code,:expenditure_name," + + ":expenditure_type,:project_id,:project_code,:project_name," + + ":coa_id,:coa_coaCode,:coa_majorHead,:coa_majorHeadName,:coa_majorHeadType,:coa_subMajorHead,:coa_subMajorHeadName," + + ":coa_minorHead,:coa_minorHeadName,:coa_subHead,:coa_subHeadName,:coa_groupHead,:coa_groupHeadName,:coa_objectHead," + + ":coa_objectHeadName,:departmentEntity_ancestry_0_id,:departmentEntity_ancestry_0_code,:departmentEntity_ancestry_0_name," + + ":departmentEntity_ancestry_0_hierarchyLevel,:departmentEntity_ancestry_1_id,:departmentEntity_ancestry_1_code," + + ":departmentEntity_ancestry_1_name,:departmentEntity_ancestry_1_hierarchyLevel,:departmentEntity_ancestry_2_id," + + ":departmentEntity_ancestry_2_code,:departmentEntity_ancestry_2_name,:departmentEntity_ancestry_2_hierarchyLevel," + + ":departmentEntity_ancestry_3_id,:departmentEntity_ancestry_3_code,:departmentEntity_ancestry_3_name," + + ":departmentEntity_ancestry_3_hierarchyLevel,:departmentEntity_ancestry_4_id,:departmentEntity_ancestry_4_code," + + ":departmentEntity_ancestry_4_name,:departmentEntity_ancestry_4_hierarchyLevel,:departmentEntity_ancestry_5_id," + + ":departmentEntity_ancestry_5_code,:departmentEntity_ancestry_5_name,:departmentEntity_ancestry_5_hierarchyLevel," + + ":departmentEntity_ancestry_6_id,:departmentEntity_ancestry_6_code,:departmentEntity_ancestry_6_name," + + ":departmentEntity_ancestry_6_hierarchyLevel,:departmentEntity_ancestry_7_id,:departmentEntity_ancestry_7_code," + + ":departmentEntity_ancestry_7_name,:departmentEntity_ancestry_7_hierarchyLevel,:departmentEntity_ancestry_8_id," + + ":departmentEntity_ancestry_8_code,:departmentEntity_ancestry_8_name,:departmentEntity_ancestry_8_hierarchyLevel," + + ":departmentEntity_ancestry_9_id,:departmentEntity_ancestry_9_code,:departmentEntity_ancestry_9_name," + + ":departmentEntity_ancestry_9_hierarchyLevel,:departmentEntity_ancestry_10_id,:departmentEntity_ancestry_10_code," + + ":departmentEntity_ancestry_10_name,:departmentEntity_ancestry_10_hierarchyLevel," + + ":departmentEntity_id,:departmentEntity_code,:departmentEntity_name,:departmentEntity_hierarchyLevel) " + + "ON CONFLICT(project_id,coa_id,type,fiscalPeriod) " + + "DO UPDATE " + + "SET " + + "ver=:ver,tenantId=:tenantId,government_id=:government_id,government_name=:government_name,sumAmount=:sumAmount,count=:count," + + "department_id=:department_id,department_code=:department_code,department_name=:department_name,departmentEntity_ancestry_0_id=:departmentEntity_ancestry_0_id," + + "expenditure_id=:expenditure_id,expenditure_code=:expenditure_code,expenditure_name=:expenditure_name,expenditure_type=:expenditure_type," + + "project_code=:project_code,project_name=:project_name," + + "coa_coaCode=:coa_coaCode,coa_majorHead=:coa_majorHead,coa_majorHeadName=:coa_majorHeadName,coa_majorHeadType=:coa_majorHeadType,coa_subMajorHead=:coa_subMajorHead," + + "coa_subMajorHeadName=:coa_subMajorHeadName,coa_minorHead=:coa_minorHead,coa_minorHeadName=:coa_minorHeadName,coa_subHead=:coa_subHead," + + "coa_subHeadName=:coa_subHeadName,coa_groupHead=:coa_groupHead,coa_groupHeadName=:coa_groupHeadName,coa_objectHead=:coa_objectHead,coa_objectHeadName=:coa_objectHeadName, " + + "departmentEntity_ancestry_0_code=:departmentEntity_ancestry_0_code," + + "departmentEntity_ancestry_0_name=:departmentEntity_ancestry_0_name,departmentEntity_ancestry_0_hierarchyLevel=:departmentEntity_ancestry_0_hierarchyLevel,departmentEntity_ancestry_1_id=:departmentEntity_ancestry_1_id," + + "departmentEntity_ancestry_1_code=:departmentEntity_ancestry_1_code,departmentEntity_ancestry_1_name=:departmentEntity_ancestry_1_name,departmentEntity_ancestry_1_hierarchyLevel=:departmentEntity_ancestry_1_hierarchyLevel," + + "departmentEntity_ancestry_2_id=:departmentEntity_ancestry_2_id,departmentEntity_ancestry_2_code=:departmentEntity_ancestry_2_code,departmentEntity_ancestry_2_name=:departmentEntity_ancestry_2_name," + + "departmentEntity_ancestry_2_hierarchyLevel=:departmentEntity_ancestry_2_hierarchyLevel,departmentEntity_ancestry_3_id=:departmentEntity_ancestry_3_id,departmentEntity_ancestry_3_code=:departmentEntity_ancestry_3_code," + + "departmentEntity_ancestry_3_name=:departmentEntity_ancestry_3_name,departmentEntity_ancestry_3_hierarchyLevel=:departmentEntity_ancestry_3_hierarchyLevel,departmentEntity_ancestry_4_id=:departmentEntity_ancestry_4_id," + + "departmentEntity_ancestry_4_code=:departmentEntity_ancestry_4_code,departmentEntity_ancestry_4_name=:departmentEntity_ancestry_4_name,departmentEntity_ancestry_4_hierarchyLevel=:departmentEntity_ancestry_4_hierarchyLevel," + + "departmentEntity_ancestry_5_id=:departmentEntity_ancestry_5_id,departmentEntity_ancestry_5_code=:departmentEntity_ancestry_5_code,departmentEntity_ancestry_5_name=:departmentEntity_ancestry_5_name," + + "departmentEntity_ancestry_5_hierarchyLevel=:departmentEntity_ancestry_5_hierarchyLevel,departmentEntity_ancestry_6_id=:departmentEntity_ancestry_6_id,departmentEntity_ancestry_6_code=:departmentEntity_ancestry_6_code," + + "departmentEntity_ancestry_6_name=:departmentEntity_ancestry_6_name,departmentEntity_ancestry_6_hierarchyLevel=:departmentEntity_ancestry_6_hierarchyLevel,departmentEntity_ancestry_7_id=:departmentEntity_ancestry_7_id," + + "departmentEntity_ancestry_7_code=:departmentEntity_ancestry_7_code,departmentEntity_ancestry_7_name=:departmentEntity_ancestry_7_name,departmentEntity_ancestry_7_hierarchyLevel=:departmentEntity_ancestry_7_hierarchyLevel," + + "departmentEntity_ancestry_8_id=:departmentEntity_ancestry_8_id,departmentEntity_ancestry_8_code=:departmentEntity_ancestry_8_code,departmentEntity_ancestry_8_name=:departmentEntity_ancestry_8_name," + + "departmentEntity_ancestry_8_hierarchyLevel=:departmentEntity_ancestry_8_hierarchyLevel,departmentEntity_ancestry_9_id=:departmentEntity_ancestry_9_id,departmentEntity_ancestry_9_code=:departmentEntity_ancestry_9_code," + + "departmentEntity_ancestry_9_name=:departmentEntity_ancestry_9_name,departmentEntity_ancestry_9_hierarchyLevel=:departmentEntity_ancestry_9_hierarchyLevel,departmentEntity_ancestry_10_id=:departmentEntity_ancestry_10_id," + + "departmentEntity_ancestry_10_code=:departmentEntity_ancestry_10_code,departmentEntity_ancestry_10_name=:departmentEntity_ancestry_10_name,departmentEntity_ancestry_10_hierarchyLevel=:departmentEntity_ancestry_10_hierarchyLevel," + + "departmentEntity_id=:departmentEntity_id,departmentEntity_code=:departmentEntity_code,departmentEntity_name=:departmentEntity_name,departmentEntity_hierarchyLevel=:departmentEntity_hierarchyLevel;"; + +} diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateConstants.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateConstants.java new file mode 100644 index 00000000..c05c6934 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateConstants.java @@ -0,0 +1,19 @@ +package org.egov.ifix.aggregate.util; + +public class FiscalEventAggregateConstants { + + private FiscalEventAggregateConstants(){} + + public static final String CURRENT_FISCAL_YEAR = "CURRENT_FISCAL_YEAR"; + public static final String PREVIOUS_FISCAL_YEAR = "PREVIOUS_FISCAL_YEAR"; + public static final int DEFAULT_HIERARCHY_LEVEL = 10; + public static final String VER = "1.0.0"; + + public static final String EVENT_TYPE_DEMAND= "Demand"; + public static final String EVENT_TYPE_RECEIPT= "Receipt"; + public static final String EVENT_TYPE_PAYMENT = "Payment"; + public static final String EVENT_TYPE_BILL= "Bill"; + + public static final String EVENT_TYPE_PENDING_COLLECTION = "Pending_Collection"; + public static final String EVENT_TYPE_PENDING_PAYMENT = "Pending_Payment"; +} diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateUtil.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateUtil.java new file mode 100644 index 00000000..f45928e8 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateUtil.java @@ -0,0 +1,399 @@ +package org.egov.ifix.aggregate.util; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.ifix.aggregate.config.ConfigProperties; +import org.egov.ifix.aggregate.model.FiscalEventAggregate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.Year; +import java.util.*; + +@Slf4j +@Component +public class FiscalEventAggregateUtil { + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private ConfigProperties configProperties; + + /** + * @param distinctProjectResponses + * @return + */ + public Map getProjectDetailsMap(List distinctProjectResponses) { + JsonNode responseJsonNode = objectMapper.convertValue(distinctProjectResponses, JsonNode.class); + Iterator nodeIterator = responseJsonNode.iterator(); + Map projectNodeMap = new HashMap<>(); + while (nodeIterator.hasNext()) { + JsonNode node = nodeIterator.next(); + if (node != null && !node.isEmpty() && node.get("event") != null) { + JsonNode eventNode = node.get("event"); + if (eventNode.get("project.id") != null) { + projectNodeMap.put(eventNode.get("project.id").asText(), eventNode); + } + } + } + return projectNodeMap; + } + + /** + * @param distinctCoaIdResponses + * @return + */ + public Map getCOADetailsMap(List distinctCoaIdResponses) { + JsonNode responseJsonNode = objectMapper.convertValue(distinctCoaIdResponses, JsonNode.class); + Iterator nodeIterator = responseJsonNode.iterator(); + Map coaNodeMap = new HashMap<>(); + while (nodeIterator.hasNext()) { + JsonNode node = nodeIterator.next(); + if (node != null && !node.isEmpty() && node.get("event") != null) { + JsonNode eventNode = node.get("event"); + if (eventNode.get("coa.id") != null) { + coaNodeMap.put(eventNode.get("coa.id").asText(), eventNode); + } + } + } + return coaNodeMap; + } + + /** + * @param groupByResponses + * @param projectNodeMap + * @param coaNodeMap + * @param fiscalYear + * @return + */ + public List getFiscalEventAggregateData(List groupByResponses, Map projectNodeMap, Map coaNodeMap, int fiscalYear) { + List fiscalEventAggregateList = new ArrayList<>(); + JsonNode responseJsonNode = objectMapper.convertValue(groupByResponses, JsonNode.class); + Iterator nodeIterator = responseJsonNode.iterator(); + while (nodeIterator.hasNext()) { + JsonNode node = nodeIterator.next(); + if (node != null && !node.isEmpty() && node.get("event") != null) { + JsonNode eventNode = node.get("event"); + FiscalEventAggregate eventAggregate = new FiscalEventAggregate(); + + BigDecimal amount = eventNode.get("amount") != null ? eventNode.get("amount").decimalValue() : null; + BigInteger count = eventNode.get("Count") != null ? eventNode.get("Count").bigIntegerValue() : null; + String projectId = eventNode.get("project.id") != null ? eventNode.get("project.id").asText() : null; + String coaId = eventNode.get("coa.id") != null ? eventNode.get("coa.id").asText() : null; + String eventType = eventNode.get("eventType") != null ? eventNode.get("eventType").asText() : null; + + eventAggregate.setProject_id(projectId); + eventAggregate.setSumAmount(amount); + eventAggregate.setCount(count); + eventAggregate.setCoa_id(coaId); + eventAggregate.setType(eventType); + + eventAggregate.setVer(FiscalEventAggregateConstants.VER); + String fiscalPeriod = createFiscalPeriodFrom(fiscalYear); + eventAggregate.setFiscalPeriod(fiscalPeriod); + //set the project details to fiscal event aggregate + setProjectDetailsToFiscalEventAggregate(projectNodeMap, eventAggregate, projectId); + + //set the coa details to fiscal event aggregate + setCoaDetailsToFiscalEventAggregate(coaNodeMap, eventAggregate, coaId); + + fiscalEventAggregateList.add(eventAggregate); + } + } + return fiscalEventAggregateList; + } + + private void setCoaDetailsToFiscalEventAggregate(Map coaNodeMap, FiscalEventAggregate eventAggregate, String coaId) { + if (coaNodeMap.containsKey(coaId)) { + JsonNode coaEventNode = coaNodeMap.get(coaId); + if (coaEventNode != null && !coaEventNode.isEmpty()) { + eventAggregate.setCoa_coaCode(coaEventNode.get("coa.coaCode") != null + ? coaEventNode.get("coa.coaCode").asText() : null); + eventAggregate.setCoa_groupHead(coaEventNode.get("coa.groupHead") != null + ? coaEventNode.get("coa.groupHead").asText() : null); + eventAggregate.setCoa_groupHeadName(coaEventNode.get("coa.groupHeadName") != null + ? coaEventNode.get("coa.groupHeadName").asText() : null); + eventAggregate.setCoa_majorHead(coaEventNode.get("coa.majorHead") != null + ? coaEventNode.get("coa.majorHead").asText() : null); + eventAggregate.setCoa_majorHeadName(coaEventNode.get("coa.majorHeadName") != null + ? coaEventNode.get("coa.majorHeadName").asText() : null); + + eventAggregate.setCoa_minorHead(coaEventNode.get("coa.minorHead") != null + ? coaEventNode.get("coa.minorHead").asText() : null); + eventAggregate.setCoa_minorHeadName(coaEventNode.get("coa.minorHeadName") != null + ? coaEventNode.get("coa.minorHeadName").asText() : null); + eventAggregate.setCoa_objectHead(coaEventNode.get("coa.objectHead") != null + ? coaEventNode.get("coa.objectHead").asText() : null); + eventAggregate.setCoa_objectHeadName(coaEventNode.get("coa.objectHeadName") != null + ? coaEventNode.get("coa.objectHeadName").asText() : null); + + eventAggregate.setCoa_subHead(coaEventNode.get("coa.subHead") != null + ? coaEventNode.get("coa.subHead").asText() : null); + eventAggregate.setCoa_subHeadName(coaEventNode.get("coa.subHeadName") != null + ? coaEventNode.get("coa.subHeadName").asText() : null); + eventAggregate.setCoa_subMajorHead(coaEventNode.get("coa.subMajorHead") != null + ? coaEventNode.get("coa.subMajorHead").asText() : null); + eventAggregate.setCoa_subMajorHeadName(coaEventNode.get("coa.subMajorHeadName") != null + ? coaEventNode.get("coa.subMajorHeadName").asText() : null); + + } + } + } + + private void setProjectDetailsToFiscalEventAggregate(Map projectNodeMap, FiscalEventAggregate eventAggregate, String projectId) { + if (projectNodeMap.containsKey(projectId)) { + JsonNode projectEventNode = projectNodeMap.get(projectId); + if (projectEventNode != null && !projectEventNode.isEmpty()) { + eventAggregate.setDepartment_code(projectEventNode.get("department.code") != null + ? projectEventNode.get("department.code").asText() : null); + eventAggregate.setDepartment_id(projectEventNode.get("department.id") != null + ? projectEventNode.get("department.id").asText() : null); + eventAggregate.setDepartment_name(projectEventNode.get("department.name") != null + ? projectEventNode.get("department.name").asText() : null); + + eventAggregate.setDepartmentEntity_code(projectEventNode.get("departmentEntity.code") != null + ? projectEventNode.get("departmentEntity.code").asText() : null); + eventAggregate.setDepartmentEntity_hierarchyLevel(projectEventNode.get("departmentEntity.hierarchyLevel") != null + ? projectEventNode.get("departmentEntity.hierarchyLevel").asInt() : null); + eventAggregate.setDepartmentEntity_id(projectEventNode.get("departmentEntity.id") != null + ? projectEventNode.get("departmentEntity.id").asText() : null); + eventAggregate.setDepartmentEntity_name(projectEventNode.get("departmentEntity.name") != null + ? projectEventNode.get("departmentEntity.name").asText() : null); + + eventAggregate.setDepartmentEntity_ancestry_0_code(projectEventNode.get("departmentEntity.ancestry[0].code") != null + ? projectEventNode.get("departmentEntity.ancestry[0].code").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_0_hierarchyLevel(projectEventNode.get("departmentEntity.ancestry[0].hierarchyLevel") != null + ? projectEventNode.get("departmentEntity.ancestry[0].hierarchyLevel").asInt() : null); + eventAggregate.setDepartmentEntity_ancestry_0_id(projectEventNode.get("departmentEntity.ancestry[0].id") != null + ? projectEventNode.get("departmentEntity.ancestry[0].id").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_0_name(projectEventNode.get("departmentEntity.ancestry[0].name") != null + ? projectEventNode.get("departmentEntity.ancestry[0].name").asText() : null); + + eventAggregate.setDepartmentEntity_ancestry_1_code(projectEventNode.get("departmentEntity.ancestry[1].code") != null + ? projectEventNode.get("departmentEntity.ancestry[1].code").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_1_hierarchyLevel(projectEventNode.get("departmentEntity.ancestry[1].hierarchyLevel") != null + ? projectEventNode.get("departmentEntity.ancestry[1].hierarchyLevel").asInt() : null); + eventAggregate.setDepartmentEntity_ancestry_1_id(projectEventNode.get("departmentEntity.ancestry[1].id") != null + ? projectEventNode.get("departmentEntity.ancestry[1].id").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_1_name(projectEventNode.get("departmentEntity.ancestry[1].name") != null + ? projectEventNode.get("departmentEntity.ancestry[1].name").asText() : null); + + eventAggregate.setDepartmentEntity_ancestry_2_code(projectEventNode.get("departmentEntity.ancestry[2].code") != null + ? projectEventNode.get("departmentEntity.ancestry[2].code").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_2_hierarchyLevel(projectEventNode.get("departmentEntity.ancestry[2].hierarchyLevel") != null + ? projectEventNode.get("departmentEntity.ancestry[2].hierarchyLevel").asInt() : null); + eventAggregate.setDepartmentEntity_ancestry_2_id(projectEventNode.get("departmentEntity.ancestry[2].id") != null + ? projectEventNode.get("departmentEntity.ancestry[2].id").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_2_name(projectEventNode.get("departmentEntity.ancestry[2].name") != null + ? projectEventNode.get("departmentEntity.ancestry[2].name").asText() : null); + + eventAggregate.setDepartmentEntity_ancestry_3_code(projectEventNode.get("departmentEntity.ancestry[3].code") != null + ? projectEventNode.get("departmentEntity.ancestry[3].code").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_3_hierarchyLevel(projectEventNode.get("departmentEntity.ancestry[3].hierarchyLevel") != null + ? projectEventNode.get("departmentEntity.ancestry[3].hierarchyLevel").asInt() : null); + eventAggregate.setDepartmentEntity_ancestry_3_id(projectEventNode.get("departmentEntity.ancestry[3].id") != null + ? projectEventNode.get("departmentEntity.ancestry[3].id").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_3_name(projectEventNode.get("departmentEntity.ancestry[3].name") != null + ? projectEventNode.get("departmentEntity.ancestry[3].name").asText() : null); + + eventAggregate.setDepartmentEntity_ancestry_4_code(projectEventNode.get("departmentEntity.ancestry[4].code") != null + ? projectEventNode.get("departmentEntity.ancestry[4].code").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_4_hierarchyLevel(projectEventNode.get("departmentEntity.ancestry[4].hierarchyLevel") != null + ? projectEventNode.get("departmentEntity.ancestry[4].hierarchyLevel").asInt() : null); + eventAggregate.setDepartmentEntity_ancestry_4_id(projectEventNode.get("departmentEntity.ancestry[4].id") != null + ? projectEventNode.get("departmentEntity.ancestry[4].id").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_4_name(projectEventNode.get("departmentEntity.ancestry[4].name") != null + ? projectEventNode.get("departmentEntity.ancestry[4].name").asText() : null); + + eventAggregate.setDepartmentEntity_ancestry_5_code(projectEventNode.get("departmentEntity.ancestry[5].code") != null + ? projectEventNode.get("departmentEntity.ancestry[5].code").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_5_hierarchyLevel(projectEventNode.get("departmentEntity.ancestry[5].hierarchyLevel") != null + ? projectEventNode.get("departmentEntity.ancestry[5].hierarchyLevel").asInt() : null); + eventAggregate.setDepartmentEntity_ancestry_5_id(projectEventNode.get("departmentEntity.ancestry[5].id") != null + ? projectEventNode.get("departmentEntity.ancestry[5].id").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_5_name(projectEventNode.get("departmentEntity.ancestry[5].name") != null + ? projectEventNode.get("departmentEntity.ancestry[5].name").asText() : null); + + eventAggregate.setDepartmentEntity_ancestry_6_code(projectEventNode.get("departmentEntity.ancestry[6].code") != null + ? projectEventNode.get("departmentEntity.ancestry[6].code").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_6_hierarchyLevel(projectEventNode.get("departmentEntity.ancestry[6].hierarchyLevel") != null + ? projectEventNode.get("departmentEntity.ancestry[6].hierarchyLevel").asInt() : null); + eventAggregate.setDepartmentEntity_ancestry_6_id(projectEventNode.get("departmentEntity.ancestry[6].id") != null + ? projectEventNode.get("departmentEntity.ancestry[6].id").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_6_name(projectEventNode.get("departmentEntity.ancestry[6].name") != null + ? projectEventNode.get("departmentEntity.ancestry[6].name").asText() : null); + + eventAggregate.setDepartmentEntity_ancestry_7_code(projectEventNode.get("departmentEntity.ancestry[7].code") != null + ? projectEventNode.get("departmentEntity.ancestry[7].code").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_7_hierarchyLevel(projectEventNode.get("departmentEntity.ancestry[7].hierarchyLevel") != null + ? projectEventNode.get("departmentEntity.ancestry[7].hierarchyLevel").asInt() : null); + eventAggregate.setDepartmentEntity_ancestry_7_id(projectEventNode.get("departmentEntity.ancestry[7].id") != null + ? projectEventNode.get("departmentEntity.ancestry[7].id").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_7_name(projectEventNode.get("departmentEntity.ancestry[7].name") != null + ? projectEventNode.get("departmentEntity.ancestry[7].name").asText() : null); + + eventAggregate.setDepartmentEntity_ancestry_8_code(projectEventNode.get("departmentEntity.ancestry[8].code") != null + ? projectEventNode.get("departmentEntity.ancestry[8].code").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_8_hierarchyLevel(projectEventNode.get("departmentEntity.ancestry[8].hierarchyLevel") != null + ? projectEventNode.get("departmentEntity.ancestry[8].hierarchyLevel").asInt() : null); + eventAggregate.setDepartmentEntity_ancestry_8_id(projectEventNode.get("departmentEntity.ancestry[8].id") != null + ? projectEventNode.get("departmentEntity.ancestry[8].id").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_8_name(projectEventNode.get("departmentEntity.ancestry[8].name") != null + ? projectEventNode.get("departmentEntity.ancestry[8].name").asText() : null); + + eventAggregate.setDepartmentEntity_ancestry_9_code(projectEventNode.get("departmentEntity.ancestry[9].code") != null + ? projectEventNode.get("departmentEntity.ancestry[9].code").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_9_hierarchyLevel(projectEventNode.get("departmentEntity.ancestry[9].hierarchyLevel") != null + ? projectEventNode.get("departmentEntity.ancestry[9].hierarchyLevel").asInt() : null); + eventAggregate.setDepartmentEntity_ancestry_9_id(projectEventNode.get("departmentEntity.ancestry[9].id") != null + ? projectEventNode.get("departmentEntity.ancestry[9].id").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_9_name(projectEventNode.get("departmentEntity.ancestry[9].name") != null + ? projectEventNode.get("departmentEntity.ancestry[9].name").asText() : null); + + eventAggregate.setDepartmentEntity_ancestry_10_code(projectEventNode.get("departmentEntity.ancestry[10].code") != null + ? projectEventNode.get("departmentEntity.ancestry[10].code").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_10_hierarchyLevel(projectEventNode.get("departmentEntity.ancestry[10].hierarchyLevel") != null + ? projectEventNode.get("departmentEntity.ancestry[10].hierarchyLevel").asInt() : null); + eventAggregate.setDepartmentEntity_ancestry_10_id(projectEventNode.get("departmentEntity.ancestry[10].id") != null + ? projectEventNode.get("departmentEntity.ancestry[10].id").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_10_name(projectEventNode.get("departmentEntity.ancestry[10].name") != null + ? projectEventNode.get("departmentEntity.ancestry[10].name").asText() : null); + + eventAggregate.setExpenditure_code(projectEventNode.get("expenditure.code") != null + ? projectEventNode.get("expenditure.code").asText() : null); + eventAggregate.setExpenditure_id(projectEventNode.get("expenditure.id") != null + ? projectEventNode.get("expenditure.id").asText() : null); + eventAggregate.setExpenditure_name(projectEventNode.get("expenditure.name") != null + ? projectEventNode.get("expenditure.name").asText() : null); + eventAggregate.setExpenditure_type(projectEventNode.get("expenditure.type") != null + ? projectEventNode.get("expenditure.type").asText() : null); + + eventAggregate.setGovernment_id(projectEventNode.get("government.id") != null + ? projectEventNode.get("government.id").asText() : null); + eventAggregate.setGovernment_name(projectEventNode.get("government.name") != null + ? projectEventNode.get("government.name").asText() : null); + + eventAggregate.setTenantId(projectEventNode.get("tenantId") != null + ? projectEventNode.get("tenantId").asText() : null); + + eventAggregate.setProject_code(projectEventNode.get("project.code") != null + ? projectEventNode.get("project.code").asText() : null); + eventAggregate.setProject_name(projectEventNode.get("project.name") != null + ? projectEventNode.get("project.name").asText() : null); + +// eventAggregate.setVer(projectEventNode.get("version") != null +// ? projectEventNode.get("version").asText() : null); + } + } + } + + public Map getEventTypeMap(List eventTypeResponses) { + if (eventTypeResponses == null || eventTypeResponses.isEmpty()) { + return Collections.emptyMap(); + } + JsonNode responseJsonNode = objectMapper.convertValue(eventTypeResponses, JsonNode.class); + Iterator nodeIterator = responseJsonNode.iterator(); + Map projectNodeMap = new HashMap<>(); + while (nodeIterator.hasNext()) { + JsonNode node = nodeIterator.next(); + if (node != null && !node.isEmpty() && node.get("event") != null) { + JsonNode eventNode = node.get("event"); + if (eventNode.get("project.id") != null) { + projectNodeMap.put(eventNode.get("project.id").asText(), eventNode); + } + } + } + return projectNodeMap; + } + + /** + * + * @param firstEventTypeNodeMap - will be demand or bill + * @param secondEventTypeNodeMap - will be receipt or payment + * @param projectNodeMap + * @param pendingEventType + * @param fiscalYear + * @return + */ + public List getPendingCollectionFiscalEventAggregatedData(Map firstEventTypeNodeMap, Map secondEventTypeNodeMap, Map projectNodeMap, String pendingEventType, int fiscalYear) { + List fiscalEventAggregateList = new ArrayList<>(); + + Map pendingAmountMap = new HashMap<>(); + //pending collection Amount + if (firstEventTypeNodeMap != null && !firstEventTypeNodeMap.isEmpty()) { + for (String dPid : firstEventTypeNodeMap.keySet()) { + boolean isAvail = false; + JsonNode demandJsonNode = firstEventTypeNodeMap.get(dPid); + BigDecimal dAmt = demandJsonNode.get("amount") != null ? demandJsonNode.get("amount").decimalValue() : BigDecimal.ZERO; + for (String rPid : secondEventTypeNodeMap.keySet()) { + if (dPid.equalsIgnoreCase(rPid)) { + isAvail = true; + JsonNode receiptJsonNode = secondEventTypeNodeMap.get(rPid); + BigDecimal rAmt = receiptJsonNode.get("amount") != null ? receiptJsonNode.get("amount").decimalValue() : BigDecimal.ZERO; + pendingAmountMap.put(dPid, (dAmt.subtract(rAmt))); + } + } + if (!isAvail) { + pendingAmountMap.put(dPid, dAmt); + } + } + } + //In case any receipt project id that has no demand type + if (!pendingAmountMap.isEmpty() && !secondEventTypeNodeMap.isEmpty()) { + for (String rPid : secondEventTypeNodeMap.keySet()) { + if (!pendingAmountMap.containsKey(rPid)) { + JsonNode receiptJsonNode = secondEventTypeNodeMap.get(rPid); + BigDecimal rAmt = receiptJsonNode.get("amount") != null ? receiptJsonNode.get("amount").decimalValue() : BigDecimal.ZERO; + pendingAmountMap.put(rPid, BigDecimal.ZERO.subtract(rAmt)); + } + } + } + + //Create a fiscal event aggregated data for pending collections + if(!pendingAmountMap.isEmpty()){ + for(String pid : pendingAmountMap.keySet()){ + FiscalEventAggregate pendingEventAggregate = new FiscalEventAggregate(); + + pendingEventAggregate.setVer(FiscalEventAggregateConstants.VER); + String fiscalPeriod = createFiscalPeriodFrom(fiscalYear); + pendingEventAggregate.setFiscalPeriod(fiscalPeriod); + pendingEventAggregate.setProject_id(pid); + pendingEventAggregate.setCount(null); + pendingEventAggregate.setSumAmount(pendingAmountMap.get(pid)); + pendingEventAggregate.setType(pendingEventType); + + //set the project details to fiscal event aggregate + setProjectDetailsToFiscalEventAggregate(projectNodeMap, pendingEventAggregate, pid); + + //Handle the unique update on conflict + pendingEventAggregate.setCoa_id(""); + fiscalEventAggregateList.add(pendingEventAggregate); + } + } + + return fiscalEventAggregateList; + } + + private String createFiscalPeriodFrom(int fiscalYear) { + String fiscalPeriodBuilder = String.valueOf(fiscalYear); + String endFiscalPeriodBuilder = String.valueOf(fiscalYear + 1); + return (fiscalPeriodBuilder.concat("-").concat(endFiscalPeriodBuilder.substring(2))); + } + + /** + * Calculate the fiscal year(s) based on system time. + * @return + */ + public Map getFiscalYear() { + Map fiscalYearMap = new HashMap<>(); + int currentYear = Year.now().getValue(); + fiscalYearMap.put(FiscalEventAggregateConstants.CURRENT_FISCAL_YEAR, currentYear); + fiscalYearMap.put(FiscalEventAggregateConstants.PREVIOUS_FISCAL_YEAR, (currentYear-1)); + return fiscalYearMap; + } +} diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties b/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties new file mode 100644 index 00000000..1c0bbe63 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties @@ -0,0 +1,19 @@ +app.timezone=UTC + +## Postgres config ## +spring.datasource.driver-class-name=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://localhost:5432/fiscal_event +spring.datasource.username=postgres +spring.datasource.password=root + +## Druid Config ## +druid.host=druid-dev.digit.org +druid.endPoint=druid/v2/ +fiscal.event.datasource=fiscal-event +druid.connect.protocol=HTTPS +druid.connect.port=443 + +##flyway config ## +spring.flyway.enabled=true +spring.flyway.table=fiscal_event_aggregator_schema +spring.flyway.baseline-on-migrate = true diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/main/V20210921173000__fiscal_event_aggregate.sql b/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/main/V20210921173000__fiscal_event_aggregate.sql new file mode 100644 index 00000000..205917f3 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/main/V20210921173000__fiscal_event_aggregate.sql @@ -0,0 +1,94 @@ +DROP TABLE IF EXISTS fiscal_event_aggregated; + +CREATE TABLE fiscal_event_aggregated( + ver TEXT, + id SERIAL, + + sumAmount DECIMAL, + count bigint, + fiscalPeriod TEXT, + + type TEXT, + + project_id TEXT, + + tenantId TEXT, + government_id TEXT, + government_name TEXT, + department_id TEXT, + department_code TEXT, + department_name TEXT, + departmentEntity_code TEXT, + departmentEntity_hierarchyLevel integer, + departmentEntity_id TEXT, + departmentEntity_name TEXT, + departmentEntity_ancestry_0_id TEXT, + departmentEntity_ancestry_0_code TEXT, + departmentEntity_ancestry_0_name TEXT, + departmentEntity_ancestry_0_hierarchyLevel integer, + departmentEntity_ancestry_1_id TEXT, + departmentEntity_ancestry_1_code TEXT, + departmentEntity_ancestry_1_name TEXT, + departmentEntity_ancestry_1_hierarchyLevel integer, + departmentEntity_ancestry_2_id TEXT, + departmentEntity_ancestry_2_code TEXT, + departmentEntity_ancestry_2_name TEXT, + departmentEntity_ancestry_2_hierarchyLevel integer, + departmentEntity_ancestry_3_id TEXT, + departmentEntity_ancestry_3_code TEXT, + departmentEntity_ancestry_3_name TEXT, + departmentEntity_ancestry_3_hierarchyLevel integer, + departmentEntity_ancestry_4_id TEXT, + departmentEntity_ancestry_4_code TEXT, + departmentEntity_ancestry_4_name TEXT, + departmentEntity_ancestry_4_hierarchyLevel integer, + departmentEntity_ancestry_5_id TEXT, + departmentEntity_ancestry_5_code TEXT, + departmentEntity_ancestry_5_name TEXT, + departmentEntity_ancestry_5_hierarchyLevel integer, + departmentEntity_ancestry_6_id TEXT, + departmentEntity_ancestry_6_code TEXT, + departmentEntity_ancestry_6_name TEXT, + departmentEntity_ancestry_6_hierarchyLevel integer, + departmentEntity_ancestry_7_id TEXT, + departmentEntity_ancestry_7_code TEXT, + departmentEntity_ancestry_7_name TEXT, + departmentEntity_ancestry_7_hierarchyLevel integer, + departmentEntity_ancestry_8_id TEXT, + departmentEntity_ancestry_8_code TEXT, + departmentEntity_ancestry_8_name TEXT, + departmentEntity_ancestry_8_hierarchyLevel integer, + departmentEntity_ancestry_9_id TEXT, + departmentEntity_ancestry_9_code TEXT, + departmentEntity_ancestry_9_name TEXT, + departmentEntity_ancestry_9_hierarchyLevel integer, + departmentEntity_ancestry_10_id TEXT, + departmentEntity_ancestry_10_code TEXT, + departmentEntity_ancestry_10_name TEXT, + departmentEntity_ancestry_10_hierarchyLevel integer, + expenditure_id TEXT, + expenditure_code TEXT, + expenditure_name TEXT, + expenditure_type TEXT, + project_code TEXT, + project_name TEXT, + + coa_id TEXT, + coa_coaCode TEXT, + coa_majorHead TEXT, + coa_majorHeadName TEXT, + coa_majorHeadType TEXT, + coa_subMajorHead TEXT, + coa_subMajorHeadName TEXT, + coa_minorHead TEXT, + coa_minorHeadName TEXT, + coa_subHead TEXT, + coa_subHeadName TEXT, + coa_groupHead TEXT, + coa_groupHeadName TEXT, + coa_objectHead TEXT, + coa_objectHeadName TEXT, + + unique(project_id,coa_id,fiscalPeriod,type), + PRIMARY KEY (id) +); diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/main/V20210922163000__fiscal_event_aggregate_index.sql b/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/main/V20210922163000__fiscal_event_aggregate_index.sql new file mode 100644 index 00000000..c8f97ebb --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/main/V20210922163000__fiscal_event_aggregate_index.sql @@ -0,0 +1,98 @@ +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_sumAmount ON fiscal_event_aggregated (sumAmount); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_count ON fiscal_event_aggregated (count); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_fiscalPeriod ON fiscal_event_aggregated (fiscalPeriod); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_type ON fiscal_event_aggregated (type); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_tenantId ON fiscal_event_aggregated (tenantId); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_government_id ON fiscal_event_aggregated (government_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_government_name ON fiscal_event_aggregated (government_name); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_department_id ON fiscal_event_aggregated (department_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_department_code ON fiscal_event_aggregated (department_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_department_name ON fiscal_event_aggregated (department_name); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_code ON fiscal_event_aggregated (departmentEntity_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_hierarchyLevel ON fiscal_event_aggregated (departmentEntity_hierarchyLevel); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_id ON fiscal_event_aggregated (departmentEntity_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_name ON fiscal_event_aggregated (departmentEntity_name); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_0_id ON fiscal_event_aggregated (departmentEntity_ancestry_0_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_0_code ON fiscal_event_aggregated (departmentEntity_ancestry_0_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_0_name ON fiscal_event_aggregated (departmentEntity_ancestry_0_name); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_0_hierarchyLevel ON fiscal_event_aggregated (departmentEntity_ancestry_0_hierarchyLevel); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_1_id ON fiscal_event_aggregated (departmentEntity_ancestry_1_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_1_code ON fiscal_event_aggregated (departmentEntity_ancestry_1_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_1_name ON fiscal_event_aggregated (departmentEntity_ancestry_1_name); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_1_hierarchyLevel ON fiscal_event_aggregated (departmentEntity_ancestry_1_hierarchyLevel); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_2_id ON fiscal_event_aggregated (departmentEntity_ancestry_2_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_2_code ON fiscal_event_aggregated (departmentEntity_ancestry_2_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_2_name ON fiscal_event_aggregated (departmentEntity_ancestry_2_name); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_2_hierarchyLevel ON fiscal_event_aggregated (departmentEntity_ancestry_2_hierarchyLevel); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_3_id ON fiscal_event_aggregated (departmentEntity_ancestry_3_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_3_code ON fiscal_event_aggregated (departmentEntity_ancestry_3_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_3_name ON fiscal_event_aggregated (departmentEntity_ancestry_3_name); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_3_hierarchyLevel ON fiscal_event_aggregated (departmentEntity_ancestry_3_hierarchyLevel); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_4_id ON fiscal_event_aggregated (departmentEntity_ancestry_4_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_4_code ON fiscal_event_aggregated (departmentEntity_ancestry_4_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_4_name ON fiscal_event_aggregated (departmentEntity_ancestry_4_name); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_4_hierarchyLevel ON fiscal_event_aggregated (departmentEntity_ancestry_4_hierarchyLevel); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_5_id ON fiscal_event_aggregated (departmentEntity_ancestry_5_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_5_code ON fiscal_event_aggregated (departmentEntity_ancestry_5_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_5_name ON fiscal_event_aggregated (departmentEntity_ancestry_5_name); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_5_hierarchyLevel ON fiscal_event_aggregated (departmentEntity_ancestry_5_hierarchyLevel); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_6_id ON fiscal_event_aggregated (departmentEntity_ancestry_6_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_6_code ON fiscal_event_aggregated (departmentEntity_ancestry_6_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_6_name ON fiscal_event_aggregated (departmentEntity_ancestry_6_name); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_6_hierarchyLevel ON fiscal_event_aggregated (departmentEntity_ancestry_6_hierarchyLevel); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_7_id ON fiscal_event_aggregated (departmentEntity_ancestry_7_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_7_code ON fiscal_event_aggregated (departmentEntity_ancestry_7_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_7_name ON fiscal_event_aggregated (departmentEntity_ancestry_7_name); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_7_hierarchyLevel ON fiscal_event_aggregated (departmentEntity_ancestry_7_hierarchyLevel); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_8_id ON fiscal_event_aggregated (departmentEntity_ancestry_8_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_8_code ON fiscal_event_aggregated (departmentEntity_ancestry_8_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_8_name ON fiscal_event_aggregated (departmentEntity_ancestry_8_name); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_8_hierarchyLevel ON fiscal_event_aggregated (departmentEntity_ancestry_8_hierarchyLevel); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_9_id ON fiscal_event_aggregated (departmentEntity_ancestry_9_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_9_code ON fiscal_event_aggregated (departmentEntity_ancestry_9_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_9_name ON fiscal_event_aggregated (departmentEntity_ancestry_9_name); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_9_hierarchyLevel ON fiscal_event_aggregated (departmentEntity_ancestry_9_hierarchyLevel); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_10_id ON fiscal_event_aggregated (departmentEntity_ancestry_10_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_10_code ON fiscal_event_aggregated (departmentEntity_ancestry_10_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_10_name ON fiscal_event_aggregated (departmentEntity_ancestry_10_name); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_10_hierarchyLevel ON fiscal_event_aggregated (departmentEntity_ancestry_10_hierarchyLevel); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_expenditure_id ON fiscal_event_aggregated (expenditure_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_expenditure_code ON fiscal_event_aggregated (expenditure_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_expenditure_name ON fiscal_event_aggregated (expenditure_name); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_expenditure_type ON fiscal_event_aggregated (expenditure_type); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_project_id ON fiscal_event_aggregated (project_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_project_code ON fiscal_event_aggregated (project_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_project_name ON fiscal_event_aggregated (project_name); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_id ON fiscal_event_aggregated (coa_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_coaCode ON fiscal_event_aggregated (coa_coaCode); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_majorHead ON fiscal_event_aggregated (coa_majorHead); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_majorHeadName ON fiscal_event_aggregated (coa_majorHeadName); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_majorHeadType ON fiscal_event_aggregated (coa_majorHeadType); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_subMajorHead ON fiscal_event_aggregated (coa_subMajorHead); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_subMajorHeadName ON fiscal_event_aggregated (coa_subMajorHeadName); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_minorHead ON fiscal_event_aggregated (coa_minorHead); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_minorHeadName ON fiscal_event_aggregated (coa_minorHeadName); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_subHead ON fiscal_event_aggregated (coa_subHead); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_subHeadName ON fiscal_event_aggregated (coa_subHeadName); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_groupHead ON fiscal_event_aggregated (coa_groupHead); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_groupHeadName ON fiscal_event_aggregated (coa_groupHeadName); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_objectHead ON fiscal_event_aggregated (coa_objectHead); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_objectHeadName ON fiscal_event_aggregated (coa_objectHeadName);