diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/job/DefaultJob.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/job/DefaultJob.java index 347f3fca3a0..bbace62d8f4 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/job/DefaultJob.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/job/DefaultJob.java @@ -29,7 +29,8 @@ public enum DefaultJob implements Job { ADD_ACCRUAL_TRANSACTIONS_FOR_LOANS_WITH_INCOME_POSTED_AS_TRANSACTIONS( "Add Accrual Transactions For Loans With Income Posted As Transactions", "LA_AATR"), // RECALCULATE_INTEREST_FOR_LOANS("Recalculate Interest For Loans", "LA_RINT"), // - WORKING_CAPITAL_LOAN_COB("Working Capital Loan COB", "WC_COB"); // + WORKING_CAPITAL_LOAN_COB("Working Capital Loan COB", "WC_COB"), // + JOURNAL_ENTRY_AGGREGATION("Journal Entry Aggregation", "JRNL_AGG"); // private final String customName; private final String shortName; diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/assetexternalization/AssetExternalizationStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/assetexternalization/AssetExternalizationStepDef.java index ce72cb67c0b..6e71342a62a 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/assetexternalization/AssetExternalizationStepDef.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/assetexternalization/AssetExternalizationStepDef.java @@ -110,16 +110,15 @@ public void createAssetExternalizationRequestByLoanIdUserGeneratedExtId(DataTabl } @When("Admin makes asset externalization request by Loan ID with unique ownerExternalId, system-generated transferExternalId and the following data:") - public void createAssetExternalizationRequestByLoanIdSystemGeneratedExtId(DataTable table) throws IOException { + public void createAssetExternalizationRequestByLoanIdSystemGeneratedExtId(DataTable table) { createAssetExternalizationRequestByLoanId(table, null); } - private void createAssetExternalizationRequestByLoanId(DataTable table, String transferExternalId) throws IOException { + private void createAssetExternalizationRequestByLoanId(DataTable table, String transferExternalId) { createAssetExternalizationRequestByLoanId(table, transferExternalId, true); } - private void createAssetExternalizationRequestByLoanId(DataTable table, String transferExternalId, boolean regenerateOwner) - throws IOException { + private void createAssetExternalizationRequestByLoanId(DataTable table, String transferExternalId, boolean regenerateOwner) { List> data = table.asLists(); List transferData = data.get(1); @@ -286,7 +285,7 @@ private void logAssetExternalizationResponseDetails(long loanId, String ownerExt } @Then("Fetching Asset externalization details by loan id gives numberOfElements: {int} with correct ownerExternalId and the following data:") - public void checkAssetExternalizationDetailsByLoanId(int numberOfElements, DataTable table) throws IOException { + public void checkAssetExternalizationDetailsByLoanId(int numberOfElements, DataTable table) { PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.getLoanId(); @@ -296,7 +295,7 @@ public void checkAssetExternalizationDetailsByLoanId(int numberOfElements, DataT } @Then("Fetching Asset externalization details by loan external id gives numberOfElements: {int} with correct ownerExternalId and the following data:") - public void checkAssetExternalizationDetailsByLoanExternalId(int numberOfElements, DataTable table) throws IOException { + public void checkAssetExternalizationDetailsByLoanExternalId(int numberOfElements, DataTable table) { PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); String loanExternalId = loanResponse.getResourceExternalId(); @@ -305,7 +304,7 @@ public void checkAssetExternalizationDetailsByLoanExternalId(int numberOfElement } @Then("Fetching Asset externalization details by transfer external id gives numberOfElements: {int} with correct ownerExternalId and the following data:") - public void checkAssetExternalizationDetailsByTransferExternalId(int numberOfElements, DataTable table) throws IOException { + public void checkAssetExternalizationDetailsByTransferExternalId(int numberOfElements, DataTable table) { String transferExternalId = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_SALES_TRANSFER_EXTERNAL_ID_FROM_RESPONSE); PageExternalTransferData response = externalAssetOwnersApi().getTransfers(Map.of("transferExternalId", transferExternalId), diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/SchedulerStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/SchedulerStepDef.java index 5b19f9ac15c..d1af7270354 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/SchedulerStepDef.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/SchedulerStepDef.java @@ -42,6 +42,12 @@ public class SchedulerStepDef extends AbstractStepDef { @Autowired private FineractFeignClient fineractClient; + @And("Admin runs the {string} job") + public void runPeriodicAccrualTransaction(String jobName) { + DefaultJob job = DefaultJob.valueOf(jobName); + jobService.executeAndWait(job); + } + @And("Admin runs the Add Accrual Transactions job") public void runAccrualTransaction() { jobService.executeAndWait(DefaultJob.ADD_ACCRUAL_TRANSACTIONS); diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/reporting/ReportingStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/reporting/ReportingStepDef.java index c86c94ff9d1..0825e41c4e2 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/reporting/ReportingStepDef.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/reporting/ReportingStepDef.java @@ -60,17 +60,34 @@ public void transactionSummaryReportWithAssetOwnerColumnNonEmpty(final String da verifyColumnNullability("Transaction Summary Report with Asset Owner", dateStr, columnName, false); } + @Then("Transaction Summary Report with Asset Owner for date {string} has originatorId, asset owner externalId and the following data:") + public void transactionSummaryReportWithAssetOwnerHasDataWithOwnerExternalIdAndOriginatorId(final String dateStr, + final DataTable dataTable) { + verifyReportDataWithOwnerExternalIdAndOriginatorId("Transaction Summary Report with Asset Owner", dateStr, dataTable); + } + @Then("Transaction Summary Report with Asset Owner for date {string} column {string} has empty value for all rows") public void transactionSummaryReportWithAssetOwnerColumnEmpty(final String dateStr, final String columnName) { verifyColumnNullability("Transaction Summary Report with Asset Owner", dateStr, columnName, true); } + @Then("Trial Balance Summary Report with Asset Owner for date {string} has originatorId, asset owner externalId and the following data:") + public void trialBalanceSummaryReportWithAssetOwnerHasDataWithOwnerExternalIdAndOriginatorId(final String dateStr, + final DataTable dataTable) { + verifyBalanceReportDataWithOwnerExternalIdAndOriginatorId("Trial Balance Summary Report with Asset Owner", dateStr, dataTable); + } + private void verifyReportData(final String reportName, final String dateStr, final DataTable dataTable) { final RunReportsResponse response = executeReport(reportName, dateStr); final List> expected = dataTable.asLists(); final List headers = expected.getFirst(); + verifyReportData(reportName, response, expected, headers); + } + + private List> verifyReportDataHeaders(final String reportName, final RunReportsResponse response, + final List> expected, List headers) { assertThat(response.getColumnHeaders()).isNotNull(); final int[] colIdx = headers.stream().mapToInt(h -> findColumnIndex(response.getColumnHeaders(), h)).toArray(); @@ -86,11 +103,34 @@ private void verifyReportData(final String reportName, final String dateStr, fin assertThat(actual).as("Report '%s' row count mismatch.\nActual rows:\n%s", reportName, formatRows(actual)) .hasSize(expected.size() - 1); + return actual; + } + + private void verifyReportDataRows(final String reportName, List> actual, final List> expected, + List headers) { + for (int i = 1; i < expected.size(); i++) { + final List expRow = expected.get(i).stream().map(v -> v == null ? "" : v).toList(); + final List actRow = actual.get(i - 1); + for (int j = 0; j < headers.size(); j++) { + if (expRow.get(j).isEmpty()) { + continue; + } + if (!valuesMatch(expRow.get(j), actRow.get(j))) { + fail("Report '%s', row %d, column '%s': expected='%s', actual='%s'\nAll actual rows:\n%s", reportName, i, + headers.get(j), expRow.get(j), actRow.get(j), formatRows(actual)); + } + } + } + } + + private void verifyReportDataRowsWithEmptyValues(final String reportName, List> actual, final List> expected, + List headers) { for (int i = 1; i < expected.size(); i++) { final List expRow = expected.get(i).stream().map(v -> v == null ? "" : v).toList(); final List actRow = actual.get(i - 1); for (int j = 0; j < headers.size(); j++) { if (expRow.get(j).isEmpty()) { + assertThat(actRow.get(j).isEmpty() || actRow.get(j).equals("null")).isTrue(); continue; } if (!valuesMatch(expRow.get(j), actRow.get(j))) { @@ -101,6 +141,114 @@ private void verifyReportData(final String reportName, final String dateStr, fin } } + private void verifyBalanceReportData(final String reportName, List> actual, final List> expected, + List headers) { + for (int i = 1; i < expected.size(); i++) { + final List expRow = expected.get(i).stream().map(v -> v == null ? "" : v).toList(); + String expectedDescription = expRow.get(3); + String expectedAssetOwnerId = expRow.get(4); + final List actRow = actual.stream() + .filter(actualRow -> actualRow.contains(expectedDescription) && actualRow.contains(expectedAssetOwnerId)).findFirst() + .orElseThrow(() -> new RuntimeException(String.format("No such row is found in %s report!", reportName))); + for (int j = 0; j < headers.size(); j++) { + if (expRow.get(j).isEmpty()) { + assertThat(actRow.get(j).isEmpty() || actRow.get(j).equals("null")).isTrue(); + continue; + } + if (!valuesMatch(expRow.get(j), actRow.get(j))) { + fail("Report '%s', row %d, column '%s': expected='%s', actual='%s'\nAll actual rows:\n%s", reportName, i, + headers.get(j), expRow.get(j), actRow.get(j), formatRows(actual)); + } + } + } + } + + private void verifyReportDataWithEmptyValues(final String reportName, final RunReportsResponse response, + final List> expected, List headers) { + final List> actual = verifyReportDataHeaders(reportName, response, expected, headers); + verifyReportDataRowsWithEmptyValues(reportName, actual, expected, headers); + } + + private void verifyReportData(final String reportName, final RunReportsResponse response, final List> expected, + List headers) { + final List> actual = verifyReportDataHeaders(reportName, response, expected, headers); + verifyReportDataRows(reportName, actual, expected, headers); + } + + private void verifyBalanceReportData(final String reportName, final RunReportsResponse response, final List> expected, + List headers) { + final List> actual = verifyReportDataHeaders(reportName, response, expected, headers); + verifyBalanceReportData(reportName, actual, expected, headers); + } + + private void verifyReportDataWithOwnerExternalIdAndOriginatorId(final String reportName, final String dateStr, + final DataTable dataTable) { + String originatorExternalId = testContext().get(TestContextKey.ORIGINATOR_EXTERNAL_ID); + String ownerExternalId = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_OWNER_EXTERNAL_ID); + String previousOwnerExternalId = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_PREVIOUS_OWNER_EXTERNAL_ID); + + final RunReportsResponse response = executeReport(reportName, dateStr); + + final List> expected = dataTable.asLists(); + final List headers = expected.getFirst(); + + expected.stream().skip(1).forEach(expectedRow -> { + if (expectedRow.contains("previous_owner_external_id")) { + int index = expectedRow.indexOf("previous_owner_external_id"); + if (index != -1) { + expectedRow.set(index, previousOwnerExternalId); + } + } + if (expectedRow.contains("owner_external_id")) { + int index = expectedRow.indexOf("owner_external_id"); + if (index != -1) { + expectedRow.set(index, ownerExternalId); + } + } + + if (expectedRow.contains("originator_external_id")) { + int index = expectedRow.indexOf("originator_external_id"); + if (index != -1) { + expectedRow.set(index, originatorExternalId); + } + } + }); + verifyReportDataWithEmptyValues(reportName, response, expected, headers); + } + + private void verifyBalanceReportDataWithOwnerExternalIdAndOriginatorId(final String reportName, final String dateStr, + final DataTable dataTable) { + String originatorExternalId = testContext().get(TestContextKey.ORIGINATOR_EXTERNAL_ID); + String ownerExternalId = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_OWNER_EXTERNAL_ID); + String previousOwnerExternalId = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_PREVIOUS_OWNER_EXTERNAL_ID); + + final RunReportsResponse response = executeReport(reportName, dateStr); + + final List> expected = dataTable.asLists(); + expected.stream().skip(1).forEach(expectedRow -> { + if (expectedRow.contains("previous_owner_external_id")) { + int index = expectedRow.indexOf("previous_owner_external_id"); + if (index != -1) { + expectedRow.set(index, previousOwnerExternalId); + } + } else if (expectedRow.contains("owner_external_id")) { + int index = expectedRow.indexOf("owner_external_id"); + if (index != -1) { + expectedRow.set(index, ownerExternalId); + } + } + if (expectedRow.contains("originator_external_id")) { + int index = expectedRow.indexOf("originator_external_id"); + if (index != -1) { + expectedRow.set(index, originatorExternalId); + } + } + }); + final List headers = expected.getFirst(); + + verifyBalanceReportData(reportName, response, expected, headers); + } + private void verifyColumnNullability(final String reportName, final String dateStr, final String columnName, final boolean expectEmpty) { final RunReportsResponse response = executeReport(reportName, dateStr); diff --git a/fineract-e2e-tests-runner/src/test/resources/features/AssetExternalization-Part2.feature b/fineract-e2e-tests-runner/src/test/resources/features/AssetExternalization-Part2.feature index 127f1c491e4..855b65fbfa8 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/AssetExternalization-Part2.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/AssetExternalization-Part2.feature @@ -15,7 +15,6 @@ Feature: Asset Externalization - Part2 @TestRailId:C3801 @AssetExternalizationJournalEntry Scenario: Verify manual journal entry with External Asset Owner empty value if asset-externalization is enabled for existing loan - UC3 Given Global configuration "asset-externalization-of-non-active-loans" is enabled - When Admin sets the business date to "1 June 2025" When Admin creates a client with random data When Admin creates a new default Loan with date: "1 June 2025" @@ -29,7 +28,6 @@ Feature: Asset Externalization - Part2 Then Fetching Asset externalization details by loan id gives numberOfElements: 1 with correct ownerExternalId and the following data: | settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type | | 2025-06-01 | 1 | PENDING | 2025-06-01 | 9999-12-31 | SALE | - When Admin sets the business date to "27 June 2025" Then Admin creates manual Journal entry with "99" amount and "27 June 2025" date and unique External Asset Owner Then Verify manual Journal entry with External Asset Owner "true" and with the following Journal entries: @@ -37,7 +35,6 @@ Feature: Asset Externalization - Part2 | ASSET | 112601 | Loans Receivable | 99.0 | | true | | LIABILITY | 145023 | Suspense/Clearing account | | 99.0 | true | Given Global configuration "asset-externalization-of-non-active-loans" is enabled - When Loan Pay-off is made on "26 June 2025" Then Loan's all installments have obligations met @@ -96,6 +93,8 @@ Feature: Asset Externalization - Part2 | 2023-06-14 | 1 | ACTIVE | 2023-06-15 | 9999-12-31 | SALE | Then LoanOwnershipTransferBusinessEvent with transfer type: "SALE" and transfer asset owner based on intermediarySale is created When Admin set external asset owner loan product attribute "SETTLEMENT_MODEL" value "DEFAULT_SETTLEMENT" for loan product "LP1_DUE_DATE" + When Loan Pay-off is made on "15 June 2023" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3992 Scenario: Verify asset externalization previous owner for intermediarySale transfer with following SALES and BUYBACK requests - UC2 @@ -141,7 +140,6 @@ Feature: Asset Externalization - Part2 | 2023-06-14 | 1 | PENDING | 2023-06-14 | 2023-06-14 | SALE | | 2023-06-14 | 1 | ACTIVE | 2023-06-15 | 9999-12-31 | SALE | Then LoanOwnershipTransferBusinessEvent with transfer type: "SALE" and transfer asset owner based on intermediarySale is created - When Admin makes asset externalization request by Loan ID with unique ownerExternalId, system-generated transferExternalId and the following data: | Transaction type | settlementDate | purchasePriceRatio | | buyback | 2023-06-16 | | @@ -163,6 +161,8 @@ Feature: Asset Externalization - Part2 | 2023-06-16 | 1 | BUYBACK | 2023-06-15 | 2023-06-16 | BUYBACK | Then LoanOwnershipTransferBusinessEvent with transfer type: "BUYBACK" and transfer asset owner is created When Admin set external asset owner loan product attribute "SETTLEMENT_MODEL" value "DEFAULT_SETTLEMENT" for loan product "LP1_DUE_DATE" + When Loan Pay-off is made on "15 June 2023" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C3993 Scenario: Verify asset externalization previous owner for intermediarySale transfer with following BUYBACK requests - UC3 @@ -207,6 +207,8 @@ Feature: Asset Externalization - Part2 | 2023-06-14 | 1 | BUYBACK_INTERMEDIATE | 2023-06-14 | 2023-06-14 | BUYBACK | Then LoanOwnershipTransferBusinessEvent with transfer type: "BUYBACK" and transfer asset owner based on intermediarySale is created When Admin set external asset owner loan product attribute "SETTLEMENT_MODEL" value "DEFAULT_SETTLEMENT" for loan product "LP1_DUE_DATE" + When Loan Pay-off is made on "15 June 2023" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C4640 Scenario: Verify creation of new external asset owner and it presence in the list @@ -342,6 +344,8 @@ Feature: Asset Externalization - Part2 | ASSET | 112601 | Loans Receivable | DEBIT | 1000.00 | | ASSET | 112601 | Loans Receivable | CREDIT | 200.00 | | LIABILITY | 145023 | Suspense/Clearing account | DEBIT | 200.00 | + When Loan Pay-off is made on "26 May 2023" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C72363 Scenario: Verify owner-to-owner repayment accounting goes to old owner while PENDING transfer not yet settled @@ -372,6 +376,8 @@ Feature: Asset Externalization - Part2 | sale | 2023-06-14 | 1 | Then Asset externalization response has the correct Loan ID, transferExternalId When Customer makes "REPAYMENT" transaction with "AUTOPAY" payment type on "25 May 2023" with 200 EUR transaction amount and system-generated Idempotency key and check previous external owner + When Loan Pay-off is made on "25 May 2023" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C72364 Scenario: Verify chained owner-to-owner transfers complete successfully @@ -423,6 +429,8 @@ Feature: Asset Externalization - Part2 | ASSET | 112601 | Loans Receivable | DEBIT | 1000.00 | | ASSET | 112601 | Loans Receivable | CREDIT | 300.00 | | LIABILITY | 145023 | Suspense/Clearing account | DEBIT | 300.00 | + When Loan Pay-off is made on "29 May 2023" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C72365 Scenario: Verify cancel of PENDING owner-to-owner transfer before COB preserves original owner @@ -454,6 +462,8 @@ Feature: Asset Externalization - Part2 | settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type | | 2023-05-30 | 1 | CANCELLED | 2023-05-25 | 2023-05-25 | SALE | When Customer makes "REPAYMENT" transaction with "AUTOPAY" payment type on "25 May 2023" with 200 EUR transaction amount and system-generated Idempotency key and check previous external owner + When Loan Pay-off is made on "25 May 2023" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C72366 Scenario: Verify buyback is blocked while PENDING owner-to-owner transfer exists @@ -483,3 +493,5 @@ Feature: Asset Externalization - Part2 Then Asset externalization transaction with the following data results a 403 error and "BUYBACK_ALREADY_IN_PROGRESS_CANNOT_BE_BOUGHT" error message | Transaction type | settlementDate | purchasePriceRatio | | buyback | 2023-06-01 | | + When Loan Pay-off is made on "25 May 2023" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met diff --git a/fineract-e2e-tests-runner/src/test/resources/features/LoanOrigination.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanOrigination.feature index 2ed2cf4f66f..6e2dc6c0ccf 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanOrigination.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanOrigination.feature @@ -13,6 +13,9 @@ Feature: Loan Origination And Admin successfully approves the loan on "1 January 2025" with "1000" amount and expected disbursement date on "1 January 2025" When Admin successfully disburse the loan on "1 January 2025" with "1000" EUR transaction amount Then Loan details with association "originators" has the originator attached + When Admin creates a new loan originator with external ID and name "Waiver Reversal Originator" + When Admin creates a new default Loan with date: "1 January 2025" + When Admin attaches the originator to the loan @TestRailId:C4650 Scenario: Verify loan originator inline attachment with auto-creation during loan application @@ -25,6 +28,8 @@ Feature: Loan Origination When Admin successfully disburse the loan on "1 January 2025" with "1000" EUR transaction amount Then Loan details with association "originators" has the originator attached Given Global configuration "enable-originator-creation-during-loan-application" is disabled + When Loan Pay-off is made on "01 January 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C4651 Scenario: Verify loan originator details in external business event after loan approval @@ -35,6 +40,8 @@ Feature: Loan Origination When Admin attaches the originator to the loan When Admin approves the loan on "1 January 2025" with "1000" amount and expected disbursement date on "1 January 2025" Then LoanApprovedBusinessEvent is created with originator details + Then Admin can successfully undone the loan approval + Then Loan status will be "SUBMITTED_AND_PENDING_APPROVAL" @TestRailId:C4652 Scenario: Verify loan originator detachment from loan before approval @@ -46,6 +53,8 @@ Feature: Loan Origination Then Loan details with association "originators" has the originator attached When Admin detaches the originator from the loan Then Loan details with association "originators" has no originator attached + And Admin successfully rejects the loan on "01 January 2025" + Then Loan status will be "REJECTED" @TestRailId:C4653 Scenario: Verify that inactive originator cannot be attached to loan @@ -54,6 +63,8 @@ Feature: Loan Origination When Admin creates a new loan originator with external ID, name "Inactive Originator" and status "PENDING" When Admin creates a new default Loan with date: "1 January 2025" Then Attaching the originator to the loan should fail + And Admin successfully rejects the loan on "01 January 2025" + Then Loan status will be "REJECTED" @TestRailId:C4654 Scenario: Verify loan originator creation with all fields and persistence in loan details @@ -64,6 +75,8 @@ Feature: Loan Origination When Admin creates a new default Loan with date: "1 January 2025" When Admin attaches the originator to the loan Then Loan details with association "originators" has the originator with all fields attached + And Admin successfully rejects the loan on "01 January 2025" + Then Loan status will be "REJECTED" @TestRailId:C4655 Scenario: Verify that originator cannot be attached to approved loan @@ -73,6 +86,8 @@ Feature: Loan Origination When Admin creates a new default Loan with date: "1 January 2025" And Admin successfully approves the loan on "1 January 2025" with "1000" amount and expected disbursement date on "1 January 2025" Then Attaching the originator to the loan should fail with status 403 + Then Admin can successfully undone the loan approval + Then Loan status will be "SUBMITTED_AND_PENDING_APPROVAL" @TestRailId:C4656 Scenario: Verify that originator cannot be detached from approved loan @@ -83,6 +98,8 @@ Feature: Loan Origination When Admin attaches the originator to the loan And Admin successfully approves the loan on "1 January 2025" with "1000" amount and expected disbursement date on "1 January 2025" Then Detaching the originator from the loan should fail with status 403 + Then Admin can successfully undone the loan approval + Then Loan status will be "SUBMITTED_AND_PENDING_APPROVAL" @TestRailId:C4657 Scenario: Verify that same originator cannot be attached to loan twice @@ -92,6 +109,8 @@ Feature: Loan Origination When Admin creates a new default Loan with date: "1 January 2025" When Admin attaches the originator to the loan Then Attaching the originator to the loan should fail with status 403 + And Admin successfully rejects the loan on "01 January 2025" + Then Loan status will be "REJECTED" @TestRailId:C4658 Scenario: Verify that non-attached originator cannot be detached from loan @@ -100,6 +119,8 @@ Feature: Loan Origination When Admin creates a new loan originator with external ID and name "Not Attached Originator" When Admin creates a new default Loan with date: "1 January 2025" Then Detaching the originator from the loan should fail with status 404 + And Admin successfully rejects the loan on "01 January 2025" + Then Loan status will be "REJECTED" @TestRailId:C4659 Scenario: Verify that originator cannot be attached to non-existent loan @@ -112,6 +133,8 @@ Feature: Loan Origination When Admin creates a client with random data When Admin creates a new default Loan with date: "1 January 2025" Then Attaching non-existent originator to the loan should fail with status 404 + And Admin successfully rejects the loan on "01 January 2025" + Then Loan status will be "REJECTED" @TestRailId:C4661 Scenario: Verify loan originator creation without name succeeds with default handling @@ -126,6 +149,8 @@ Feature: Loan Origination When Admin creates new user with "ORIGINATOR_NO_ATTACH" username, "ORIGINATOR_NO_ATTACH_ROLE" role name and given permissions: | READ_LOAN | Then Created user without ATTACH_LOAN_ORIGINATOR permission fails to attach originator to the loan + And Admin successfully rejects the loan on "01 January 2025" + Then Loan status will be "REJECTED" @TestRailId:C4663 Scenario: Verify that user without DETACH_LOAN_ORIGINATOR permission cannot detach originator @@ -137,6 +162,8 @@ Feature: Loan Origination When Admin creates new user with "ORIGINATOR_NO_DETACH" username, "ORIGINATOR_NO_DETACH_ROLE" role name and given permissions: | READ_LOAN | Then Created user without DETACH_LOAN_ORIGINATOR permission fails to detach originator from the loan + And Admin successfully rejects the loan on "01 January 2025" + Then Loan status will be "REJECTED" @TestRailId:C4664 Scenario: Verify loan originator persistence through full loan lifecycle with repayments @@ -157,6 +184,8 @@ Feature: Loan Origination When Admin sets the business date to "1 March 2025" And Customer makes "AUTOPAY" repayment on "1 March 2025" with 340 EUR transaction amount Then Loan details with association "originators" has the originator with all fields attached + When Loan Pay-off is made on "01 March 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C4665 Scenario: Verify multiple originators on a loan with add, update, and detach operations @@ -173,6 +202,8 @@ Feature: Loan Origination When Admin detaches the originator from the loan Then Loan details with association "originators" has 1 originator attached And Loan details with association "originators" has the second originator attached + And Admin successfully rejects the loan on "01 January 2025" + Then Loan status will be "REJECTED" @TestRailId:C4666 Scenario: Verify loan originator persistence through undo approval @@ -186,6 +217,8 @@ Feature: Loan Origination Then Loan details with association "originators" has the originator attached Then Admin can successfully undone the loan approval Then Loan details with association "originators" has the originator attached + And Admin successfully rejects the loan on "01 January 2025" + Then Loan status will be "REJECTED" @TestRailId:C4667 Scenario: Verify loan originator persistence through undo disbursal @@ -199,6 +232,8 @@ Feature: Loan Origination Then Loan details with association "originators" has the originator attached When Admin successfully undo disbursal Then Loan details with association "originators" has the originator attached + Then Admin can successfully undone the loan approval + Then Loan status will be "SUBMITTED_AND_PENDING_APPROVAL" @TestRailId:C4668 Scenario: Verify loan originator persistence through loan charge-off @@ -212,6 +247,8 @@ Feature: Loan Origination Then Loan details with association "originators" has the originator attached And Admin does charge-off the loan on "1 January 2025" Then Loan details with association "originators" has the originator attached + When Loan Pay-off is made on "01 January 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C4669 Scenario: Verify that originator cannot be attached or detached from disbursed loan @@ -225,6 +262,8 @@ Feature: Loan Origination When Admin successfully disburse the loan on "1 January 2025" with "1000" EUR transaction amount Then Attaching the second originator to the loan should fail with status 403 And Detaching the originator from the loan should fail with status 403 + When Loan Pay-off is made on "01 January 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C4670 Scenario: Verify loan originator read operations with retrieve by external ID, list all, and template @@ -256,6 +295,8 @@ Feature: Loan Origination When Admin creates a new default Loan with date: "1 January 2025" When Admin attaches the originator to the loan Then Deleting the originator should fail with status 403 + And Admin successfully rejects the loan on "01 January 2025" + Then Loan status will be "REJECTED" @TestRailId:C4673 Scenario: Verify loan originator CRUD permission checks with create, update, and delete denied without permissions @@ -282,6 +323,8 @@ Feature: Loan Origination And Customer makes "AUTOPAY" repayment on "1 January 2025" with 500 EUR transaction amount When Customer makes a repayment undo on "1 January 2025" without event check Then LoanAdjustTransactionBusinessEvent is created with originator details in "transactionToAdjust" + When Loan Pay-off is made on "01 January 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C74522 Scenario: Verify that originator details are present in LoanAccrualTransactionCreatedBusinessEvent after COB runs @@ -296,6 +339,8 @@ Feature: Loan Origination When Admin sets the business date to "2 January 2025" When Admin runs inline COB job for Loan Then LoanAccrualTransactionCreatedBusinessEvent is created with originator details on "01 January 2025" + When Loan Pay-off is made on "02 January 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C74523 Scenario: Verify that originator details are present in LoanAdjustTransactionBusinessEvent after charge waiver reversal @@ -310,6 +355,8 @@ Feature: Loan Origination And Admin waives due date charge When Customer reverses the waiver transaction on "1 January 2025" Then LoanAdjustTransactionBusinessEvent is created with originator details in "transactionToAdjust" + When Loan Pay-off is made on "01 January 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C74524 Scenario: Verify that no originator details are present in LoanAdjustTransactionBusinessEvent when loan has no originator attached @@ -334,6 +381,8 @@ Feature: Loan Origination And Customer makes "AUTOPAY" repayment on "1 January 2025" with 500 EUR transaction amount When Customer adjusts the repayment on "1 January 2025" to 300 EUR without event check Then LoanAdjustTransactionBusinessEvent is created with originator details in "newTransactionDetail" + When Loan Pay-off is made on "01 January 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C78846 Scenario: Verify that LoanAccountDelinquencyRangeDataV1 and LoanRepaymentDueDataV1 has the correct data for Originators - UC1: no originator attached @@ -350,6 +399,8 @@ Feature: Loan Origination When Admin sets the business date to "10 April 2025" When Admin runs inline COB job for Loan Then LoanAccountDelinquencyRangeDataV1 has the same data for Originators as in loanDetails + When Loan Pay-off is made on "10 April 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C78847 Scenario: Verify that LoanAccountDelinquencyRangeDataV1 and LoanRepaymentDueDataV1 has the correct data for Originators - UC2: originator attached @@ -369,6 +420,8 @@ Feature: Loan Origination When Admin sets the business date to "01 April 2025" When Admin runs inline COB job for Loan Then LoanAccountDelinquencyRangeDataV1 has the same data for Originators as in loanDetails + When Loan Pay-off is made on "01 April 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C78848 Scenario: Verify that LoanAccountDelinquencyRangeDataV1 and LoanRepaymentDueDataV1 has the correct data for Originators - UC3: originator attached, fully customized loan @@ -389,7 +442,10 @@ Feature: Loan Origination When Admin sets the business date to "10 April 2025" When Admin runs inline COB job for Loan Then LoanAccountDelinquencyRangeDataV1 has the same data for Originators as in loanDetails + When Loan Pay-off is made on "10 April 2025" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C85196 Scenario: Verify that originator details are present in LoanRepaymentDueBusinessEvent after inline COB runs When Admin sets the business date to "01 January 2023" When Admin creates a client with random data @@ -401,7 +457,10 @@ Feature: Loan Origination When Admin sets the business date to "02 January 2023" When Admin runs inline COB job for Loan Then LoanRepaymentDueBusinessEvent is created with originator details + When Loan Pay-off is made on "02 January 2023" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C85197 Scenario: Verify no originator details in LoanRepaymentDueBusinessEvent when loan has no originator attached When Admin sets the business date to "01 January 2023" When Admin creates a client with random data @@ -411,7 +470,10 @@ Feature: Loan Origination When Admin sets the business date to "02 January 2023" When Admin runs inline COB job for Loan Then LoanRepaymentDueBusinessEvent is created without originator details + When Loan Pay-off is made on "02 January 2023" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C85198 Scenario: Verify multiple originator details in LoanRepaymentDueBusinessEvent after inline COB runs When Admin sets the business date to "01 January 2023" When Admin creates a client with random data @@ -425,7 +487,10 @@ Feature: Loan Origination When Admin sets the business date to "02 January 2023" When Admin runs inline COB job for Loan Then LoanRepaymentDueBusinessEvent is created with 2 originator details + When Loan Pay-off is made on "02 January 2023" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C85199 Scenario: Verify that originator details are present in LoanDelinquencyRangeChangeEvent when loan becomes delinquent When Admin sets the business date to "01 January 2023" When Admin creates a client with random data @@ -437,7 +502,10 @@ Feature: Loan Origination When Admin sets the business date to "07 January 2023" When Admin runs inline COB job for Loan Then LoanDelinquencyRangeChangeEvent is created with originator details + When Loan Pay-off is made on "07 January 2023" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C85200 Scenario: Verify no originator details in LoanDelinquencyRangeChangeEvent when loan has no originator attached When Admin sets the business date to "01 January 2023" When Admin creates a client with random data @@ -447,7 +515,10 @@ Feature: Loan Origination When Admin sets the business date to "07 January 2023" When Admin runs inline COB job for Loan Then LoanDelinquencyRangeChangeEvent is created without originator details + When Loan Pay-off is made on "07 January 2023" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + @TestRailId:C85201 Scenario: Verify multiple originator details in LoanDelinquencyRangeChangeEvent when loan becomes delinquent When Admin sets the business date to "01 January 2023" When Admin creates a client with random data @@ -461,5 +532,7 @@ Feature: Loan Origination When Admin sets the business date to "07 January 2023" When Admin runs inline COB job for Loan Then LoanDelinquencyRangeChangeEvent is created with 2 originator details + When Loan Pay-off is made on "07 January 2023" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met diff --git a/fineract-e2e-tests-runner/src/test/resources/features/Reporting.feature b/fineract-e2e-tests-runner/src/test/resources/features/Reporting.feature index b944c7e3adc..7fe46cc4609 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/Reporting.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/Reporting.feature @@ -276,6 +276,7 @@ Feature: Reporting | 2026-02-03 | LP2_PROGRESSIVE_ADVANCED_PAYMENT_ALLOCATION_BUYDOWN_FEES | Buy Down Fee Amortization | | | 0 | Principal | | 0.0 | | 2026-02-03 | LP2_PROGRESSIVE_ADVANCED_PAYMENT_ALLOCATION_BUYDOWN_FEES | Buy Down Fee Amortization | | | 0 | Unallocated Credit (UNC) | | 0.0 | + @TestRailId:C85202 Scenario: Verify Transaction Summary Report with Asset Owner contain correct originator_external_ids column When Admin sets the business date to "01 January 2025" And Admin creates a new office @@ -450,3 +451,276 @@ Feature: Reporting | 2026-01-04 | LP2_PROGRESSIVE_ADVANCED_PAYMENT_ALLOCATION_CAPITALIZED_INCOME | Capitalized Income Amortization | | | 0 | Penalty | | 0.0 | | 2026-01-04 | LP2_PROGRESSIVE_ADVANCED_PAYMENT_ALLOCATION_CAPITALIZED_INCOME | Capitalized Income Amortization | | | 0 | Principal | | 0.0 | | 2026-01-04 | LP2_PROGRESSIVE_ADVANCED_PAYMENT_ALLOCATION_CAPITALIZED_INCOME | Capitalized Income Amortization | | | 0 | Unallocated Credit (UNC) | | 0.0 | + + @TestRailId:C85203 + Scenario: Verify Verify Transaction Summary Report with Asset Owner with previous owner for intermediarySale transfer with following SALES request and originatorId - UC1 + When Admin set external asset owner loan product attribute "SETTLEMENT_MODEL" value "DELAYED_SETTLEMENT" for loan product "LP1_DUE_DATE" + When Admin sets the business date to "1 May 2023" + And Admin creates a new office + And Admin creates a client with random data in the last created office + When Admin creates a new loan originator with external ID and name "Asset Owner with intermediarySale transfer and SALES request" + When Admin creates a fully customized loan with the following data: + | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | + | LP1_DUE_DATE | 01 May 2023 | 1000 | 0 | DECLINING_BALANCE | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 1 | MONTHS | 1 | MONTHS | 1 | 0 | 0 | 0 | PENALTIES_FEES_INTEREST_PRINCIPAL_ORDER | + When Admin attaches the originator to the loan + And Admin successfully approves the loan on "1 May 2023" with "1000" amount and expected disbursement date on "1 May 2023" + When Admin successfully disburse the loan on "1 May 2023" with "1000" EUR transaction amount + Then Loan status will be "ACTIVE" + When Admin makes asset externalization request by Loan ID with unique ownerExternalId, system-generated transferExternalId and the following data: + | Transaction type | settlementDate | purchasePriceRatio | + | intermediarySale | 2023-05-21 | 1 | + Then Asset externalization response has the correct Loan ID, transferExternalId + Then Fetching Asset externalization details by loan id gives numberOfElements: 1 with correct ownerExternalId and the following data: + | settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type | + | 2023-05-21 | 1 | PENDING_INTERMEDIATE | 2023-05-01 | 9999-12-31 | INTERMEDIARYSALE | + When Admin sets the business date to "22 May 2023" + When Admin runs inline COB job for Loan + Then Fetching Asset externalization details by loan id gives numberOfElements: 2 with correct ownerExternalId and the following data: + | settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type | + | 2023-05-21 | 1 | PENDING_INTERMEDIATE | 2023-05-01 | 2023-05-21 | INTERMEDIARYSALE | + | 2023-05-21 | 1 | ACTIVE_INTERMEDIATE | 2023-05-22 | 9999-12-31 | INTERMEDIARYSALE | + Then LoanOwnershipTransferBusinessEvent with transfer type: "INTERMEDIARYSALE" and transfer asset owner is created + When Admin sets the business date to "14 June 2023" + When Admin makes asset externalization request by Loan ID with unique ownerExternalId, system-generated transferExternalId and the following data: + | Transaction type | settlementDate | purchasePriceRatio | + | sale | 2023-06-14 | 1 | + Then Fetching Asset externalization details by loan id gives numberOfElements: 3 with correct ownerExternalId and the following data: + | settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type | + | 2023-05-21 | 1 | PENDING_INTERMEDIATE | 2023-05-01 | 2023-05-21 | INTERMEDIARYSALE | + | 2023-05-21 | 1 | ACTIVE_INTERMEDIATE | 2023-05-22 | 9999-12-31 | INTERMEDIARYSALE | + | 2023-06-14 | 1 | PENDING | 2023-06-14 | 9999-12-31 | SALE | + When Admin sets the business date to "15 June 2023" + When Admin runs inline COB job for Loan + Then Fetching Asset externalization details by loan id gives numberOfElements: 4 with correct ownerExternalId and the following data: + | settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type | + | 2023-05-21 | 1 | PENDING_INTERMEDIATE | 2023-05-01 | 2023-05-21 | INTERMEDIARYSALE | + | 2023-05-21 | 1 | ACTIVE_INTERMEDIATE | 2023-05-22 | 2023-06-14 | INTERMEDIARYSALE | + | 2023-06-14 | 1 | PENDING | 2023-06-14 | 2023-06-14 | SALE | + | 2023-06-14 | 1 | ACTIVE | 2023-06-15 | 9999-12-31 | SALE | + Then LoanOwnershipTransferBusinessEvent with transfer type: "SALE" and transfer asset owner based on intermediarySale is created + When Admin set external asset owner loan product attribute "SETTLEMENT_MODEL" value "DEFAULT_SETTLEMENT" for loan product "LP1_DUE_DATE" +# --- run Journal Entry Aggregation job ---- # + And Admin runs the "JOURNAL_ENTRY_AGGREGATION" job +# --- run Transaction Summary Report with Asset Owner report --- # + Then Transaction Summary Report with Asset Owner for date "01 May 2023" has originatorId, asset owner externalId and the following data: + | TransactionDate | Product | TransactionType_Name | PaymentType_Name | chargetype | Reversed | Allocation_Type | Chargeoff_ReasonCode | Transaction_Amount | asset_owner_id | from_asset_owner_id | originator_external_ids | + | 2023-05-01 | LP1_DUE_DATE | Disbursement | AUTOPAY | | 0 | Fees | | 0.0 | | | originator_external_id | + | 2023-05-01 | LP1_DUE_DATE | Disbursement | AUTOPAY | | 0 | Interest | | 0.0 | | | originator_external_id | + | 2023-05-01 | LP1_DUE_DATE | Disbursement | AUTOPAY | | 0 | Penalty | | 0.0 | | | originator_external_id | + | 2023-05-01 | LP1_DUE_DATE | Disbursement | AUTOPAY | | 0 | Principal | | 1000.0 | | | originator_external_id | + | 2023-05-01 | LP1_DUE_DATE | Disbursement | AUTOPAY | | 0 | Unallocated Credit (UNC) | | 0.0 | | | originator_external_id | + Then Transaction Summary Report with Asset Owner for date "14 June 2023" has originatorId, asset owner externalId and the following data: + | TransactionDate | Product | TransactionType_Name | PaymentType_Name | chargetype | Reversed | Allocation_Type | Chargeoff_ReasonCode | Transaction_Amount | asset_owner_id | from_asset_owner_id | originator_external_ids | + | 2023-06-14 | LP1_DUE_DATE | Asset Transfer | | | 0 | Principal | | 1000.0 | owner_external_id | previous_owner_external_id | originator_external_id | + + @TestRailId:C85204 + Scenario: Verify Trial Balance Summary Report with Asset Owner with previous owner for intermediarySale transfer with following SALES and BUYBACK requests and originatorId - UC2 + When Admin set external asset owner loan product attribute "SETTLEMENT_MODEL" value "DELAYED_SETTLEMENT" for loan product "LP1_DUE_DATE" + When Admin sets the business date to "1 May 2023" + And Admin creates a new office + And Admin creates a client with random data in the last created office + When Admin creates a new loan originator with external ID and name "Asset Owner with intermediarySale transfer and SALES and BUYBACK request" + When Admin creates a fully customized loan with the following data: + | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | + | LP1_DUE_DATE | 01 May 2023 | 1000 | 0 | DECLINING_BALANCE | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 1 | MONTHS | 1 | MONTHS | 1 | 0 | 0 | 0 | PENALTIES_FEES_INTEREST_PRINCIPAL_ORDER | + When Admin attaches the originator to the loan + And Admin successfully approves the loan on "1 May 2023" with "1000" amount and expected disbursement date on "1 May 2023" + When Admin successfully disburse the loan on "1 May 2023" with "1000" EUR transaction amount + Then Loan status will be "ACTIVE" + When Admin makes asset externalization request by Loan ID with unique ownerExternalId, system-generated transferExternalId and the following data: + | Transaction type | settlementDate | purchasePriceRatio | + | intermediarySale | 2023-05-21 | 1 | + Then Asset externalization response has the correct Loan ID, transferExternalId + Then Fetching Asset externalization details by loan id gives numberOfElements: 1 with correct ownerExternalId and the following data: + | settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type | + | 2023-05-21 | 1 | PENDING_INTERMEDIATE | 2023-05-01 | 9999-12-31 | INTERMEDIARYSALE | + When Admin sets the business date to "22 May 2023" + When Admin runs inline COB job for Loan + Then Fetching Asset externalization details by loan id gives numberOfElements: 2 with correct ownerExternalId and the following data: + | settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type | + | 2023-05-21 | 1 | PENDING_INTERMEDIATE | 2023-05-01 | 2023-05-21 | INTERMEDIARYSALE | + | 2023-05-21 | 1 | ACTIVE_INTERMEDIATE | 2023-05-22 | 9999-12-31 | INTERMEDIARYSALE | + Then LoanOwnershipTransferBusinessEvent with transfer type: "INTERMEDIARYSALE" and transfer asset owner is created + When Admin sets the business date to "14 June 2023" + When Admin makes asset externalization request by Loan ID with unique ownerExternalId, system-generated transferExternalId and the following data: + | Transaction type | settlementDate | purchasePriceRatio | + | sale | 2023-06-14 | 1 | + Then Fetching Asset externalization details by loan id gives numberOfElements: 3 with correct ownerExternalId and the following data: + | settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type | + | 2023-05-21 | 1 | PENDING_INTERMEDIATE | 2023-05-01 | 2023-05-21 | INTERMEDIARYSALE | + | 2023-05-21 | 1 | ACTIVE_INTERMEDIATE | 2023-05-22 | 9999-12-31 | INTERMEDIARYSALE | + | 2023-06-14 | 1 | PENDING | 2023-06-14 | 9999-12-31 | SALE | + When Admin sets the business date to "15 June 2023" + When Admin runs inline COB job for Loan + Then Fetching Asset externalization details by loan id gives numberOfElements: 4 with correct ownerExternalId and the following data: + | settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type | + | 2023-05-21 | 1 | PENDING_INTERMEDIATE | 2023-05-01 | 2023-05-21 | INTERMEDIARYSALE | + | 2023-05-21 | 1 | ACTIVE_INTERMEDIATE | 2023-05-22 | 2023-06-14 | INTERMEDIARYSALE | + | 2023-06-14 | 1 | PENDING | 2023-06-14 | 2023-06-14 | SALE | + | 2023-06-14 | 1 | ACTIVE | 2023-06-15 | 9999-12-31 | SALE | + Then LoanOwnershipTransferBusinessEvent with transfer type: "SALE" and transfer asset owner based on intermediarySale is created + When Admin makes asset externalization request by Loan ID with unique ownerExternalId, system-generated transferExternalId and the following data: + | Transaction type | settlementDate | purchasePriceRatio | + | buyback | 2023-06-16 | | + Then Fetching Asset externalization details by loan id gives numberOfElements: 5 with correct ownerExternalId and the following data: + | settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type | + | 2023-05-21 | 1 | PENDING_INTERMEDIATE | 2023-05-01 | 2023-05-21 | INTERMEDIARYSALE | + | 2023-05-21 | 1 | ACTIVE_INTERMEDIATE | 2023-05-22 | 2023-06-14 | INTERMEDIARYSALE | + | 2023-06-14 | 1 | PENDING | 2023-06-14 | 2023-06-14 | SALE | + | 2023-06-14 | 1 | ACTIVE | 2023-06-15 | 9999-12-31 | SALE | + | 2023-06-16 | 1 | BUYBACK | 2023-06-15 | 9999-12-31 | BUYBACK | + When Admin sets the business date to "17 June 2023" + When Admin runs inline COB job for Loan + Then Fetching Asset externalization details by loan id gives numberOfElements: 5 with correct ownerExternalId and the following data: + | settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type | + | 2023-05-21 | 1 | PENDING_INTERMEDIATE | 2023-05-01 | 2023-05-21 | INTERMEDIARYSALE | + | 2023-05-21 | 1 | ACTIVE_INTERMEDIATE | 2023-05-22 | 2023-06-14 | INTERMEDIARYSALE | + | 2023-06-14 | 1 | PENDING | 2023-06-14 | 2023-06-14 | SALE | + | 2023-06-14 | 1 | ACTIVE | 2023-06-15 | 2023-06-16 | SALE | + | 2023-06-16 | 1 | BUYBACK | 2023-06-15 | 2023-06-16 | BUYBACK | + Then LoanOwnershipTransferBusinessEvent with transfer type: "BUYBACK" and transfer asset owner is created + When Admin set external asset owner loan product attribute "SETTLEMENT_MODEL" value "DEFAULT_SETTLEMENT" for loan product "LP1_DUE_DATE" +# --- run Journal Entry Aggregation job ---- # + And Admin runs the "JOURNAL_ENTRY_AGGREGATION" job +# --- run Trial Balance Summary Report with Asset Owner report --- # + Then Trial Balance Summary Report with Asset Owner for date "01 May 2023" has originatorId, asset owner externalId and the following data: + | PostingDate | Product | glAcct | Description | AssetOwner | BeginningBalance | DebitMovement | CreditMovement | EndingBalance | originator_external_ids | + | 2023-05-01 | LP1_DUE_DATE | 112601 | Loans Receivable | self | 0.0 | 1000.0 | 0.0 | 1000.0 | originator_external_id | + | 2023-05-01 | LP1_DUE_DATE | 145023 | Suspense/Clearing account | self | 0.0 | 0.0 | -1000.0 | -1000.0 | originator_external_id | + Then Trial Balance Summary Report with Asset Owner for date "14 June 2023" has originatorId, asset owner externalId and the following data: + | PostingDate | Product | glAcct | Description | AssetOwner | BeginningBalance | DebitMovement | CreditMovement | EndingBalance | originator_external_ids | + | 2023-06-14 | LP1_DUE_DATE | 112601 | Loans Receivable | owner_external_id | 0.0 | 1000.0 | 0.0 | 1000.0 | originator_external_id | + | 2023-06-14 | LP1_DUE_DATE | 112601 | Loans Receivable | previous_owner_external_id | 1000.0 | 0.0 | -1000.0 | 0.0 | originator_external_id | + | 2023-06-14 | LP1_DUE_DATE | 145023 | Suspense/Clearing account | self | -1000.0 | 0.0 | 0.0 | -1000.0 | originator_external_id | + | 2023-06-14 | LP1_DUE_DATE | 146000 | Asset transfer | self | 0.0 | 1000.0 | -1000.0 | 0.0 | originator_external_id | + Then Trial Balance Summary Report with Asset Owner for date "15 June 2023" has originatorId, asset owner externalId and the following data: + | PostingDate | Product | glAcct | Description | AssetOwner | BeginningBalance | DebitMovement | CreditMovement | EndingBalance | originator_external_ids | + | 2023-06-15 | LP1_DUE_DATE | 112601 | Loans Receivable | owner_external_id | 1000.0 | 0.0 | 0.0 | 1000.0 | originator_external_id | + | 2023-06-15 | LP1_DUE_DATE | 145023 | Suspense/Clearing account | self | -1000.0 | 0.0 | 0.0 | -1000.0 | originator_external_id | + + @TestRailId:C85205 + Scenario: Verify Transaction Summary Report with Asset Owner with previous owner for intermediarySale transfer with following BUYBACK requests and no originatorId - UC3 + When Admin set external asset owner loan product attribute "SETTLEMENT_MODEL" value "DELAYED_SETTLEMENT" for loan product "LP1_DUE_DATE" + When Admin sets the business date to "1 May 2023" + And Admin creates a new office + And Admin creates a client with random data in the last created office + When Admin creates a fully customized loan with the following data: + | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | + | LP1_DUE_DATE | 01 May 2023 | 1000 | 0 | DECLINING_BALANCE | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 1 | MONTHS | 1 | MONTHS | 1 | 0 | 0 | 0 | PENALTIES_FEES_INTEREST_PRINCIPAL_ORDER | + And Admin successfully approves the loan on "1 May 2023" with "1000" amount and expected disbursement date on "1 May 2023" + When Admin successfully disburse the loan on "1 May 2023" with "1000" EUR transaction amount + Then Loan status will be "ACTIVE" + When Admin makes asset externalization request by Loan ID with unique ownerExternalId, system-generated transferExternalId and the following data: + | Transaction type | settlementDate | purchasePriceRatio | + | intermediarySale | 2023-05-21 | 1 | + Then Asset externalization response has the correct Loan ID, transferExternalId + Then Fetching Asset externalization details by loan id gives numberOfElements: 1 with correct ownerExternalId and the following data: + | settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type | + | 2023-05-21 | 1 | PENDING_INTERMEDIATE | 2023-05-01 | 9999-12-31 | INTERMEDIARYSALE | + When Admin sets the business date to "22 May 2023" + When Admin runs inline COB job for Loan + Then Fetching Asset externalization details by loan id gives numberOfElements: 2 with correct ownerExternalId and the following data: + | settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type | + | 2023-05-21 | 1 | PENDING_INTERMEDIATE | 2023-05-01 | 2023-05-21 | INTERMEDIARYSALE | + | 2023-05-21 | 1 | ACTIVE_INTERMEDIATE | 2023-05-22 | 9999-12-31 | INTERMEDIARYSALE | + Then LoanOwnershipTransferBusinessEvent with transfer type: "INTERMEDIARYSALE" and transfer asset owner is created + When Admin sets the business date to "14 June 2023" + When Admin makes asset externalization request by Loan ID with unique ownerExternalId, system-generated transferExternalId and the following data: + | Transaction type | settlementDate | purchasePriceRatio | + | buyback | 2023-06-14 | | + Then Fetching Asset externalization details by loan id gives numberOfElements: 3 with correct ownerExternalId and the following data: + | settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type | + | 2023-05-21 | 1 | PENDING_INTERMEDIATE | 2023-05-01 | 2023-05-21 | INTERMEDIARYSALE | + | 2023-05-21 | 1 | ACTIVE_INTERMEDIATE | 2023-05-22 | 9999-12-31 | INTERMEDIARYSALE | + | 2023-06-14 | 1 | BUYBACK_INTERMEDIATE | 2023-06-14 | 9999-12-31 | BUYBACK | + When Admin sets the business date to "15 June 2023" + When Admin runs inline COB job for Loan + Then Fetching Asset externalization details by loan id gives numberOfElements: 3 with correct ownerExternalId and the following data: + | settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type | + | 2023-05-21 | 1 | PENDING_INTERMEDIATE | 2023-05-01 | 2023-05-21 | INTERMEDIARYSALE | + | 2023-05-21 | 1 | ACTIVE_INTERMEDIATE | 2023-05-22 | 2023-06-14 | INTERMEDIARYSALE | + | 2023-06-14 | 1 | BUYBACK_INTERMEDIATE | 2023-06-14 | 2023-06-14 | BUYBACK | + Then LoanOwnershipTransferBusinessEvent with transfer type: "BUYBACK" and transfer asset owner based on intermediarySale is created + When Admin set external asset owner loan product attribute "SETTLEMENT_MODEL" value "DEFAULT_SETTLEMENT" for loan product "LP1_DUE_DATE" +# --- run Journal Entry Aggregation job ---- # + And Admin runs the "JOURNAL_ENTRY_AGGREGATION" job +# --- run Transaction Summary Report with Asset Owner report --- # + Then Transaction Summary Report with Asset Owner for date "01 May 2023" has originatorId, asset owner externalId and the following data: + | TransactionDate | Product | TransactionType_Name | PaymentType_Name | chargetype | Reversed | Allocation_Type | Chargeoff_ReasonCode | Transaction_Amount | asset_owner_id | from_asset_owner_id | originator_external_ids | + | 2023-05-01 | LP1_DUE_DATE | Disbursement | AUTOPAY | | 0 | Fees | | 0.0 | | | | + | 2023-05-01 | LP1_DUE_DATE | Disbursement | AUTOPAY | | 0 | Interest | | 0.0 | | | | + | 2023-05-01 | LP1_DUE_DATE | Disbursement | AUTOPAY | | 0 | Penalty | | 0.0 | | | | + | 2023-05-01 | LP1_DUE_DATE | Disbursement | AUTOPAY | | 0 | Principal | | 1000.0 | | | | + | 2023-05-01 | LP1_DUE_DATE | Disbursement | AUTOPAY | | 0 | Unallocated Credit (UNC) | | 0.0 | | | | + Then Transaction Summary Report with Asset Owner for date "14 June 2023" has originatorId, asset owner externalId and the following data: + | TransactionDate | Product | TransactionType_Name | PaymentType_Name | chargetype | Reversed | Allocation_Type | Chargeoff_ReasonCode | Transaction_Amount | asset_owner_id | from_asset_owner_id | originator_external_ids | + | 2023-06-14 | LP1_DUE_DATE | Asset Buyback | | | 0 | Principal | | -1000.0 | | owner_external_id | | + + @TestRailId:C85206 + Scenario: Verify Trial Balance Summary Report with Asset Owner with owner-to-owner transfer completes via COB and next repayment accounting goes to new owner and no originatorId - UC4 + When Admin sets the business date to "1 May 2023" + And Admin creates a new office + And Admin creates a client with random data in the last created office + When Admin creates a new default Loan with date: "1 May 2023" + And Admin successfully approves the loan on "1 May 2023" with "1000" amount and expected disbursement date on "1 May 2023" + When Admin successfully disburse the loan on "1 May 2023" with "1000" EUR transaction amount + Then Loan status will be "ACTIVE" + When Admin makes asset externalization request by Loan ID with unique ownerExternalId, system-generated transferExternalId and the following data: + | Transaction type | settlementDate | purchasePriceRatio | + | sale | 2023-05-21 | 1 | + Then Asset externalization response has the correct Loan ID, transferExternalId + When Admin sets the business date to "22 May 2023" + When Admin runs inline COB job for Loan + Then LoanOwnershipTransferBusinessEvent is created + Then LoanAccountSnapshotBusinessEvent is created + Then Fetching Asset externalization details by loan id gives numberOfElements: 2 with correct ownerExternalId and the following data: + | settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type | + | 2023-05-21 | 1 | PENDING | 2023-05-01 | 2023-05-21 | SALE | + | 2023-05-21 | 1 | ACTIVE | 2023-05-22 | 9999-12-31 | SALE | + When Admin sets the business date to "25 May 2023" + When Admin makes asset externalization request by Loan ID with unique ownerExternalId, system-generated transferExternalId and the following data: + | Transaction type | settlementDate | purchasePriceRatio | + | sale | 2023-05-25 | 1 | + Then Asset externalization response has the correct Loan ID, transferExternalId + When Admin sets the business date to "26 May 2023" + When Admin runs inline COB job for Loan + Then LoanOwnershipTransferBusinessEvent is created + Then LoanAccountSnapshotBusinessEvent is created + Then The latest asset externalization transaction with "ACTIVE" status has the following TRANSFER Journal entries: + | glAccountType | glAccountCode | glAccountName | entryType | amount | + | ASSET | 112601 | Loans Receivable | CREDIT | 1000.00 | + | ASSET | 146000 | Asset transfer | DEBIT | 1000.00 | + | ASSET | 112601 | Loans Receivable | DEBIT | 1000.00 | + | ASSET | 146000 | Asset transfer | CREDIT | 1000.00 | + Then The asset external owner has the following OWNER Journal entries: + | glAccountType | glAccountCode | glAccountName | entryType | amount | + | ASSET | 112601 | Loans Receivable | DEBIT | 1000.00 | + When Customer makes "REPAYMENT" transaction with "AUTOPAY" payment type on "26 May 2023" with 200 EUR transaction amount and system-generated Idempotency key and check external owner + Then The asset external owner has the following OWNER Journal entries: + | glAccountType | glAccountCode | glAccountName | entryType | amount | + | ASSET | 112601 | Loans Receivable | DEBIT | 1000.00 | + | ASSET | 112601 | Loans Receivable | CREDIT | 200.00 | + | LIABILITY | 145023 | Suspense/Clearing account | DEBIT | 200.00 | +# --- run Journal Entry Aggregation job ---- # + And Admin runs the "JOURNAL_ENTRY_AGGREGATION" job +# --- run Transaction Summary Report with Asset Owner report --- # + Then Trial Balance Summary Report with Asset Owner for date "01 May 2023" has originatorId, asset owner externalId and the following data: + | PostingDate | Product | glAcct | Description | AssetOwner | BeginningBalance | DebitMovement | CreditMovement | EndingBalance | originator_external_ids | + | 2023-05-01 | LP1 | 112601 | Loans Receivable | self | 0.0 | 1000.0 | 0.0 | 1000.0 | | + | 2023-05-01 | LP1 | 145023 | Suspense/Clearing account | self | 0.0 | 0.0 | -1000.0 | -1000.0 | | + Then Trial Balance Summary Report with Asset Owner for date "22 May 2023" has originatorId, asset owner externalId and the following data: + | PostingDate | Product | glAcct | Description | AssetOwner | BeginningBalance | DebitMovement | CreditMovement | EndingBalance | originator_external_ids | + | 2023-05-22 | LP1 | 112601 | Loans Receivable | previous_owner_external_id | 1000.0 | 0.0 | 0.0 | 1000.0 | | + | 2023-05-22 | LP1 | 145023 | Suspense/Clearing account | self | -1000.0 | 0.0 | 0.0 | -1000.0 | | + Then Trial Balance Summary Report with Asset Owner for date "25 May 2023" has originatorId, asset owner externalId and the following data: + | PostingDate | Product | glAcct | Description | AssetOwner | BeginningBalance | DebitMovement | CreditMovement | EndingBalance | originator_external_ids | + | 2023-05-25 | LP1 | 112601 | Loans Receivable | owner_external_id | 0.0 | 1000.0 | 0.0 | 1000.0 | | + | 2023-05-25 | LP1 | 112601 | Loans Receivable | previous_owner_external_id | 1000.0 | 0.0 | -1000.0 | 0.0 | | + | 2023-05-25 | LP1 | 145023 | Suspense/Clearing account | self | -1000.0 | 0.0 | 0.0 | -1000.0 | | + | 2023-05-25 | LP1 | 146000 | Asset transfer | self | 0.0 | 1000.0 | -1000.0 | 0.0 | | + Then Trial Balance Summary Report with Asset Owner for date "26 May 2023" has originatorId, asset owner externalId and the following data: + | PostingDate | Product | glAcct | Description | AssetOwner | BeginningBalance | DebitMovement | CreditMovement | EndingBalance | originator_external_ids | + | 2023-05-26 | LP1 | 112601 | Loans Receivable | owner_external_id | 1000.0 | 0.0 | -200.0 | 800.0 | | + | 2023-05-26 | LP1 | 145023 | Suspense/Clearing account | self | -1000.0 | 0.0 | 0.0 | -1000.0 | | + | 2023-05-26 | LP1 | 145023 | Suspense/Clearing account | owner_external_id | 0.0 | 200.0 | 0.0 | 200.0 | | + diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/JournalEntryAggregationJobConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/JournalEntryAggregationJobConfiguration.java index b664c9fb6c7..fbb61af0ec8 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/JournalEntryAggregationJobConfiguration.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/JournalEntryAggregationJobConfiguration.java @@ -22,6 +22,7 @@ import static org.apache.fineract.infrastructure.jobs.service.aggregationjob.JournalEntryAggregationJobConstant.JOB_TRACKING_STEP_NAME; import org.apache.fineract.infrastructure.core.config.FineractProperties; +import org.apache.fineract.infrastructure.core.service.database.DatabaseTypeResolver; import org.apache.fineract.infrastructure.core.service.migration.TenantDataSourceFactory; import org.apache.fineract.infrastructure.jobs.service.JobName; import org.apache.fineract.infrastructure.jobs.service.aggregationjob.data.JournalEntryAggregationSummaryData; @@ -59,6 +60,8 @@ public class JournalEntryAggregationJobConfiguration { private JournalEntryAggregationTrackingTasklet journalEntryAggregationTrackingTasklet; @Autowired private TenantDataSourceFactory tenantDataSourceFactory; + @Autowired + private DatabaseTypeResolver databaseTypeResolver; @Bean public Step journalEntryAggregationSummaryStep() { @@ -70,7 +73,7 @@ public Step journalEntryAggregationSummaryStep() { @Bean public JournalEntryAggregationJobReader journalEntryAggregationJobReader() { - return new JournalEntryAggregationJobReader(tenantDataSourceFactory); + return new JournalEntryAggregationJobReader(tenantDataSourceFactory, databaseTypeResolver); } @Bean diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/JournalEntryAggregationJobReader.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/JournalEntryAggregationJobReader.java index 3b6d18e976e..ef395997c00 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/JournalEntryAggregationJobReader.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/JournalEntryAggregationJobReader.java @@ -24,6 +24,7 @@ import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant; import org.apache.fineract.infrastructure.core.domain.JdbcSupport; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; +import org.apache.fineract.infrastructure.core.service.database.DatabaseTypeResolver; import org.apache.fineract.infrastructure.core.service.migration.TenantDataSourceFactory; import org.apache.fineract.infrastructure.jobs.service.aggregationjob.data.JournalEntryAggregationSummaryData; import org.springframework.batch.core.StepExecution; @@ -37,10 +38,12 @@ @StepScope public class JournalEntryAggregationJobReader extends JdbcCursorItemReader { + private final DatabaseTypeResolver databaseTypeResolver; private LocalDate aggregatedOnDateFrom; private LocalDate aggregatedOnDateTo; - public JournalEntryAggregationJobReader(TenantDataSourceFactory tenantDataSourceFactory) { + public JournalEntryAggregationJobReader(TenantDataSourceFactory tenantDataSourceFactory, DatabaseTypeResolver databaseTypeResolver) { + this.databaseTypeResolver = databaseTypeResolver; FineractPlatformTenant tenant = ThreadLocalContextUtil.getTenant(); setDataSource(tenantDataSourceFactory.create(tenant)); setSql(buildAggregationQuery()); @@ -71,6 +74,7 @@ private JournalEntryAggregationSummaryData mapRow(ResultSet rs, int rowNum) thro .submittedOnDate(ThreadLocalContextUtil.getBusinessDate()) // .aggregatedOnDate(JdbcSupport.getLocalDate(rs, "aggregatedOnDate")) // .externalOwnerId(JdbcSupport.getLong(rs, "externalOwner")) // + .originatorExternalIds(rs.getString("originatorExternalIds")) // .debitAmount(rs.getBigDecimal("debitAmount")) // .creditAmount(rs.getBigDecimal("creditAmount")) // .manualEntry(false) // @@ -78,76 +82,96 @@ private JournalEntryAggregationSummaryData mapRow(ResultSet rs, int rowNum) thro } private String buildAggregationQuery() { + String aggregateFunction = databaseTypeResolver.isMySQL() + ? "GROUP_CONCAT(DISTINCT mlo.external_id ORDER BY mlo.external_id SEPARATOR ', ')" + : "STRING_AGG(DISTINCT mlo.external_id, ', ' ORDER BY mlo.external_id)"; return """ SELECT - COALESCE( - loan_product.id, - savings_product.id, - prov_product.id, - share_product.id - ) AS productId, - acc_gl_account.id AS glAccountId, - acc_gl_journal_entry.entity_type_enum AS entityTypeEnum, - acc_gl_journal_entry.office_id AS officeId, - aw.owner_id AS externalOwner, - SUM(CASE WHEN acc_gl_journal_entry.type_enum = 2 THEN amount ELSE 0 END) AS debitAmount, - SUM(CASE WHEN acc_gl_journal_entry.type_enum = 1 THEN amount ELSE 0 END) AS creditAmount, - acc_gl_journal_entry.submitted_on_date AS aggregatedOnDate, - acc_gl_journal_entry.currency_code AS currencyCode - FROM acc_gl_account - JOIN acc_gl_journal_entry - ON acc_gl_account.id = acc_gl_journal_entry.account_id - - -- entity_type_enum = 1 → LOAN - LEFT JOIN m_loan loan - ON loan.id = acc_gl_journal_entry.entity_id - AND acc_gl_journal_entry.entity_type_enum = 1 - LEFT JOIN m_product_loan loan_product - ON loan_product.id = loan.product_id - AND acc_gl_journal_entry.entity_type_enum = 1 - - -- entity_type_enum = 2 → SAVING - LEFT JOIN m_savings_account savings - ON savings.id = acc_gl_journal_entry.entity_id - AND acc_gl_journal_entry.entity_type_enum = 2 - LEFT JOIN m_savings_product savings_product - ON savings_product.id = savings.product_id - AND acc_gl_journal_entry.entity_type_enum = 2 - - -- entity_type_enum = 3 → PROVISIONING - LEFT JOIN m_provisioning_history prov - ON prov.id = acc_gl_journal_entry.entity_id - AND acc_gl_journal_entry.entity_type_enum = 3 - LEFT JOIN m_loanproduct_provisioning_entry prov_entry - ON prov_entry.history_id = prov.id - AND acc_gl_journal_entry.entity_type_enum = 3 - LEFT JOIN m_product_loan prov_product - ON prov_product.id = prov_entry.product_id - AND acc_gl_journal_entry.entity_type_enum = 3 - - -- entity_type_enum = 4 → SHARED - LEFT JOIN m_share_account share - ON share.id = acc_gl_journal_entry.entity_id - AND acc_gl_journal_entry.entity_type_enum = 4 - LEFT JOIN m_share_product share_product - ON share_product.id = share.product_id - AND acc_gl_journal_entry.entity_type_enum = 4 - - -- external owner - LEFT JOIN m_external_asset_owner_journal_entry_mapping aw - ON aw.journal_entry_id = acc_gl_journal_entry.id - - WHERE acc_gl_journal_entry.submitted_on_date > ? - AND acc_gl_journal_entry.submitted_on_date <= ? - - GROUP BY - productId, - glAccountId, - externalOwner, - aggregatedOnDate, - currencyCode, - entityTypeEnum, - officeId + je.productId, + je.glAccountId, + je.entityTypeEnum, + je.officeId, + je.externalOwner, + je.originatorExternalIds, + SUM(CASE WHEN je.type_enum = 2 THEN je.amount ELSE 0 END) AS debitAmount, + SUM(CASE WHEN je.type_enum = 1 THEN je.amount ELSE 0 END) AS creditAmount, + je.aggregatedOnDate, + je.currencyCode + FROM ( + SELECT + COALESCE( + loan_product.id, + savings_product.id, + prov_product.id, + share_product.id + ) AS productId, + acc_gl_account.id AS glAccountId, + acc_gl_journal_entry.entity_type_enum AS entityTypeEnum, + acc_gl_journal_entry.office_id AS officeId, + aw.owner_id AS externalOwner, + COALESCE((SELECT \s""" + aggregateFunction + """ + FROM m_loan_originator_mapping mlom + JOIN m_loan_originator mlo ON mlo.id = mlom.originator_id + WHERE mlom.loan_id = loan.id), '') AS originatorExternalIds, + acc_gl_journal_entry.type_enum, + acc_gl_journal_entry.amount, + acc_gl_journal_entry.submitted_on_date AS aggregatedOnDate, + acc_gl_journal_entry.currency_code AS currencyCode + FROM acc_gl_account + JOIN acc_gl_journal_entry + ON acc_gl_account.id = acc_gl_journal_entry.account_id + + -- entity_type_enum = 1 → LOAN + LEFT JOIN m_loan loan + ON loan.id = acc_gl_journal_entry.entity_id + AND acc_gl_journal_entry.entity_type_enum = 1 + LEFT JOIN m_product_loan loan_product + ON loan_product.id = loan.product_id + AND acc_gl_journal_entry.entity_type_enum = 1 + + -- entity_type_enum = 2 → SAVING + LEFT JOIN m_savings_account savings + ON savings.id = acc_gl_journal_entry.entity_id + AND acc_gl_journal_entry.entity_type_enum = 2 + LEFT JOIN m_savings_product savings_product + ON savings_product.id = savings.product_id + AND acc_gl_journal_entry.entity_type_enum = 2 + + -- entity_type_enum = 3 → PROVISIONING + LEFT JOIN m_provisioning_history prov + ON prov.id = acc_gl_journal_entry.entity_id + AND acc_gl_journal_entry.entity_type_enum = 3 + LEFT JOIN m_loanproduct_provisioning_entry prov_entry + ON prov_entry.history_id = prov.id + AND acc_gl_journal_entry.entity_type_enum = 3 + LEFT JOIN m_product_loan prov_product + ON prov_product.id = prov_entry.product_id + AND acc_gl_journal_entry.entity_type_enum = 3 + + -- entity_type_enum = 4 → SHARED + LEFT JOIN m_share_account share + ON share.id = acc_gl_journal_entry.entity_id + AND acc_gl_journal_entry.entity_type_enum = 4 + LEFT JOIN m_share_product share_product + ON share_product.id = share.product_id + AND acc_gl_journal_entry.entity_type_enum = 4 + + -- external owner + LEFT JOIN m_external_asset_owner_journal_entry_mapping aw + ON aw.journal_entry_id = acc_gl_journal_entry.id + + WHERE acc_gl_journal_entry.submitted_on_date > ? + AND acc_gl_journal_entry.submitted_on_date <= ? + ) je + GROUP BY + je.productId, + je.glAccountId, + je.externalOwner, + je.originatorExternalIds, + je.aggregatedOnDate, + je.currencyCode, + je.entityTypeEnum, + je.officeId """; } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/data/JournalEntryAggregationSummaryData.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/data/JournalEntryAggregationSummaryData.java index c81845734b6..0e6c8f2ba0d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/data/JournalEntryAggregationSummaryData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/data/JournalEntryAggregationSummaryData.java @@ -36,6 +36,7 @@ public class JournalEntryAggregationSummaryData { private LocalDate submittedOnDate; private LocalDate aggregatedOnDate; private Long externalOwnerId; + private String originatorExternalIds; private BigDecimal debitAmount; private BigDecimal creditAmount; private Boolean manualEntry; diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/domain/JournalEntrySummary.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/domain/JournalEntrySummary.java index 4927a8b22dc..56419971163 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/domain/JournalEntrySummary.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/domain/JournalEntrySummary.java @@ -54,6 +54,9 @@ public class JournalEntrySummary extends AbstractAuditableWithUTCDateTimeCustom< @Column(name = "external_owner_id", nullable = false) private Long externalOwnerId; + @Column(name = "originator_external_ids") + private String originatorExternalIds; + @Column(name = "debit_amount") private BigDecimal debitAmount; diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/services/JournalEntryAggregationWriterServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/services/JournalEntryAggregationWriterServiceImpl.java index c078c29590e..aacd30dea1b 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/services/JournalEntryAggregationWriterServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/services/JournalEntryAggregationWriterServiceImpl.java @@ -27,7 +27,6 @@ import org.apache.fineract.infrastructure.jobs.service.aggregationjob.domain.JournalEntryAggregationTrackingRepository; import org.apache.fineract.infrastructure.jobs.service.aggregationjob.domain.JournalEntrySummary; import org.apache.fineract.infrastructure.jobs.service.aggregationjob.domain.JournalEntrySummaryRepository; -import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.stereotype.Component; @Component @@ -37,7 +36,6 @@ public class JournalEntryAggregationWriterServiceImpl implements JournalEntryAgg private JournalEntrySummaryRepository journalSummaryRepository; private JournalEntryAggregationTrackingRepository journalEntryAggregationTrackingRepository; - private NamedParameterJdbcTemplate namedParameterJdbcTemplate; @Override public void insertJournalEntrySummaryBatch(final List journalEntrySummaries) { @@ -82,6 +80,7 @@ private JournalEntrySummary convertToJournalEntrySummary(final JournalEntryAggre entrySummary.setDebitAmount(summaryDTO.getDebitAmount()); entrySummary.setCreditAmount(summaryDTO.getCreditAmount()); entrySummary.setExternalOwnerId(summaryDTO.getExternalOwnerId()); + entrySummary.setOriginatorExternalIds(summaryDTO.getOriginatorExternalIds()); entrySummary.setAggregatedOnDate(summaryDTO.getAggregatedOnDate()); entrySummary.setJobExecutionId(summaryDTO.getJobExecutionId()); return entrySummary; diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml index 339750468cd..8e136d43ff9 100644 --- a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml +++ b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml @@ -255,4 +255,6 @@ + + diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0237_trial_balance_summary_report_update_originator_inline_join.xml b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0237_trial_balance_summary_report_update_originator_inline_join.xml new file mode 100644 index 00000000000..72740bdd56f --- /dev/null +++ b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0237_trial_balance_summary_report_update_originator_inline_join.xml @@ -0,0 +1,446 @@ + + + + + + + (SELECT latest FROM aggregated_date) + ) + AND acc_gl_journal_entry.submitted_on_date < '${endDate}' + AND (acc_gl_journal_entry.office_id = ${officeId}) + GROUP BY productname, glcode, glname, assetowner, originator_external_ids), + merged_historical_data AS (SELECT COALESCE(s.productname, p.productname) AS productname, + COALESCE(s.glcode, p.glcode) AS glcode, + COALESCE(s.glname, p.glname) AS glname, + COALESCE(s.assetowner, p.assetowner, 0) AS assetowner, + COALESCE(s.debitamount, 0) + COALESCE(p.debitamount, 0) AS debitamount, + COALESCE(s.creditamount, 0) + COALESCE(p.creditamount, 0) AS creditamount, + COALESCE(p.originator_external_ids, s.originator_external_ids, '') AS originator_external_ids + FROM summary_snapshot_baseline_data s + LEFT JOIN post_snapshot_delta_data p + ON s.glcode = p.glcode + AND s.productname = p.productname + AND s.assetowner = p.assetowner + AND s.originator_external_ids = p.originator_external_ids + + UNION ALL + + SELECT p.productname AS productname, + p.glcode AS glcode, + p.glname AS glname, + COALESCE(p.assetowner, 0) AS assetowner, + COALESCE(p.debitamount, 0) AS debitamount, + COALESCE(p.creditamount, 0) AS creditamount, + COALESCE(p.originator_external_ids, '') AS originator_external_ids + FROM post_snapshot_delta_data p + LEFT JOIN summary_snapshot_baseline_data s + ON s.glcode = p.glcode + AND s.productname = p.productname + AND s.assetowner = p.assetowner + AND s.originator_external_ids = p.originator_external_ids + WHERE s.glcode IS NULL), + current_cob_data AS (SELECT lp.name AS productname, + account_id, + acc_gl_account.gl_code AS glcode, + acc_gl_account.name AS glname, + CASE WHEN aw.owner_id IS NULL THEN 0 ELSE aw.owner_id END AS assetowner, + SUM(CASE WHEN acc_gl_journal_entry.type_enum = 2 THEN amount ELSE 0 END) AS debitamount, + SUM(CASE WHEN acc_gl_journal_entry.type_enum = 1 THEN amount ELSE 0 END) AS creditamount, + COALESCE((SELECT GROUP_CONCAT(DISTINCT mlo.external_id ORDER BY mlo.external_id SEPARATOR ', ') + FROM m_loan_originator_mapping mlom + JOIN m_loan_originator mlo ON mlo.id = mlom.originator_id + WHERE mlom.loan_id = m.id), '') AS originator_external_ids + FROM acc_gl_journal_entry + JOIN acc_gl_account ON acc_gl_account.id = acc_gl_journal_entry.account_id + JOIN m_loan m ON m.id = acc_gl_journal_entry.entity_id + JOIN m_product_loan lp ON lp.id = m.product_id + LEFT JOIN m_external_asset_owner_journal_entry_mapping aw + ON aw.journal_entry_id = acc_gl_journal_entry.id + WHERE acc_gl_journal_entry.entity_type_enum = 1 + AND acc_gl_journal_entry.manual_entry = FALSE + AND acc_gl_journal_entry.submitted_on_date = '${endDate}' + AND (acc_gl_journal_entry.office_id = ${officeId}) + GROUP BY productname, account_id, glcode, glname, assetowner, originator_external_ids) + +SELECT * +FROM (SELECT * + FROM retained_earning + WHERE glacct = (SELECT gl_code FROM acc_gl_account WHERE name = 'Retained Earnings Prior Year') + + UNION + + SELECT txnreport.postingdate, + txnreport.product, + txnreport.glacct, + txnreport.description, + txnreport.assetowner, + (COALESCE(txnreport.beginningbalance, 0) + COALESCE(summary.beginningbalance, 0)) AS beginningbalance, + txnreport.debitmovement AS debitmovement, + txnreport.creditmovement AS creditmovement, + (COALESCE(txnreport.endingbalance, 0) + COALESCE(summary.beginningbalance, 0)) AS endingbalance, + txnreport.originator_external_ids AS originator_external_ids + FROM (SELECT * + FROM (SELECT DISTINCT '${endDate}' AS postingdate, + loan.pname AS product, + loan.gl_code AS glacct, + loan.glname AS description, + COALESCE((SELECT external_id FROM m_external_asset_owner WHERE id = loan.assetowner), + 'self') AS assetowner, + loan.openingbalance AS beginningbalance, + (loan.debitamount * 1) AS debitmovement, + (loan.creditamount * -1) AS creditmovement, + (loan.openingbalance + loan.debitamount - loan.creditamount) AS endingbalance, + loan.originator_external_ids AS originator_external_ids + FROM (SELECT DISTINCT g.pname AS pname, + g.gl_code AS gl_code, + g.glname AS glname, + COALESCE(mh.assetowner, c.assetowner, 0) AS assetowner, + COALESCE(mh.debitamount, 0) - COALESCE(mh.creditamount, 0) AS openingbalance, + COALESCE(c.debitamount, 0) AS debitamount, + COALESCE(c.creditamount, 0) AS creditamount, + COALESCE(mh.originator_external_ids, c.originator_external_ids) AS originator_external_ids + FROM (SELECT DISTINCT ag.gl_code, ag.id, pl.NAME AS pname, ag.NAME AS glname + FROM acc_gl_account ag + JOIN acc_product_mapping am ON am.gl_account_id = ag.id AND am.product_type = 1 + JOIN m_product_loan pl ON pl.id = am.product_id) g + LEFT JOIN merged_historical_data mh + ON g.gl_code = mh.glcode + AND mh.productname = g.pname + LEFT JOIN current_cob_data c + ON g.gl_code = c.glcode + AND c.productname = g.pname + AND mh.assetowner = c.assetowner + AND mh.originator_external_ids = c.originator_external_ids + + UNION ALL + + SELECT DISTINCT c.productname AS pname, + c.glcode AS gl_code, + c.glname AS glname, + COALESCE(c.assetowner, 0) AS assetowner, + 0 AS openingbalance, + COALESCE(c.debitamount, 0) AS debitamount, + COALESCE(c.creditamount, 0) AS creditamount, + COALESCE(matched.originator_external_ids, c.originator_external_ids) AS originator_external_ids + FROM current_cob_data c + LEFT JOIN (SELECT g3.gl_code, g3.pname, mh.assetowner, mh.originator_external_ids + FROM (SELECT DISTINCT ag.gl_code, pl.NAME AS pname + FROM acc_gl_account ag + JOIN acc_product_mapping am + ON am.gl_account_id = ag.id AND am.product_type = 1 + JOIN m_product_loan pl ON pl.id = am.product_id) g3 + LEFT JOIN merged_historical_data mh + ON g3.gl_code = mh.glcode + AND mh.productname = g3.pname) matched + ON matched.gl_code = c.glcode + AND matched.pname = c.productname + AND matched.assetowner = c.assetowner + AND matched.originator_external_ids = c.originator_external_ids + WHERE matched.gl_code IS NULL) loan) a) AS txnreport + LEFT JOIN retained_earning summary + ON txnreport.glacct = summary.glacct + AND txnreport.assetowner = summary.assetowner + AND summary.product = txnreport.product + AND summary.originator_external_ids = txnreport.originator_external_ids) report +WHERE report.endingbalance != 0 + OR report.debitmovement != 0 + OR report.creditmovement != 0 +ORDER BY glacct + ]]> + + report_name='Trial Balance Summary Report with Asset Owner' + + + + + (SELECT latest FROM aggregated_date) + ) + AND acc_gl_journal_entry.submitted_on_date < '${endDate}' + AND (acc_gl_journal_entry.office_id = ${officeId}) + GROUP BY productname, glcode, glname, assetowner, originator_external_ids), + merged_historical_data AS (SELECT COALESCE(s.productname, p.productname) AS productname, + COALESCE(s.glcode, p.glcode) AS glcode, + COALESCE(s.glname, p.glname) AS glname, + COALESCE(s.assetowner, p.assetowner, 0) AS assetowner, + COALESCE(s.debitamount, 0) + COALESCE(p.debitamount, 0) AS debitamount, + COALESCE(s.creditamount, 0) + COALESCE(p.creditamount, 0) AS creditamount, + COALESCE(p.originator_external_ids, s.originator_external_ids, '') AS originator_external_ids + FROM summary_snapshot_baseline_data s + LEFT JOIN post_snapshot_delta_data p + ON s.glcode = p.glcode + AND s.productname = p.productname + AND s.assetowner = p.assetowner + AND s.originator_external_ids = p.originator_external_ids + + UNION ALL + + SELECT p.productname AS productname, + p.glcode AS glcode, + p.glname AS glname, + COALESCE(p.assetowner, 0) AS assetowner, + COALESCE(p.debitamount, 0) AS debitamount, + COALESCE(p.creditamount, 0) AS creditamount, + COALESCE(p.originator_external_ids, '') AS originator_external_ids + FROM post_snapshot_delta_data p + LEFT JOIN summary_snapshot_baseline_data s + ON s.glcode = p.glcode + AND s.productname = p.productname + AND s.assetowner = p.assetowner + AND s.originator_external_ids = p.originator_external_ids + WHERE s.glcode IS NULL), + current_cob_data AS (SELECT lp.name AS productname, + account_id, + acc_gl_account.gl_code AS glcode, + acc_gl_account.name AS glname, + CASE WHEN aw.owner_id IS NULL THEN 0 ELSE aw.owner_id END AS assetowner, + SUM(CASE WHEN acc_gl_journal_entry.type_enum = 2 THEN amount ELSE 0 END) AS debitamount, + SUM(CASE WHEN acc_gl_journal_entry.type_enum = 1 THEN amount ELSE 0 END) AS creditamount, + COALESCE((SELECT STRING_AGG(DISTINCT mlo.external_id, ', ' ORDER BY mlo.external_id) + FROM m_loan_originator_mapping mlom + JOIN m_loan_originator mlo ON mlo.id = mlom.originator_id + WHERE mlom.loan_id = m.id), '') AS originator_external_ids + FROM acc_gl_journal_entry + JOIN acc_gl_account ON acc_gl_account.id = acc_gl_journal_entry.account_id + JOIN m_loan m ON m.id = acc_gl_journal_entry.entity_id + JOIN m_product_loan lp ON lp.id = m.product_id + LEFT JOIN m_external_asset_owner_journal_entry_mapping aw + ON aw.journal_entry_id = acc_gl_journal_entry.id + WHERE acc_gl_journal_entry.entity_type_enum = 1 + AND acc_gl_journal_entry.manual_entry = FALSE + AND acc_gl_journal_entry.submitted_on_date = '${endDate}' + AND (acc_gl_journal_entry.office_id = ${officeId}) + GROUP BY productname, account_id, glcode, glname, assetowner, originator_external_ids) + +SELECT * +FROM (SELECT * + FROM retained_earning + WHERE glacct = (SELECT gl_code FROM acc_gl_account WHERE name = 'Retained Earnings Prior Year') + + UNION + + SELECT txnreport.postingdate, + txnreport.product, + txnreport.glacct, + txnreport.description, + txnreport.assetowner, + (COALESCE(txnreport.beginningbalance, 0) + COALESCE(summary.beginningbalance, 0)) AS beginningbalance, + txnreport.debitmovement AS debitmovement, + txnreport.creditmovement AS creditmovement, + (COALESCE(txnreport.endingbalance, 0) + COALESCE(summary.beginningbalance, 0)) AS endingbalance, + txnreport.originator_external_ids AS originator_external_ids + FROM (SELECT * + FROM (SELECT DISTINCT '${endDate}' AS postingdate, + loan.pname AS product, + loan.gl_code AS glacct, + loan.glname AS description, + COALESCE((SELECT external_id FROM m_external_asset_owner WHERE id = loan.assetowner), + 'self') AS assetowner, + loan.openingbalance AS beginningbalance, + (loan.debitamount * 1) AS debitmovement, + (loan.creditamount * -1) AS creditmovement, + (loan.openingbalance + loan.debitamount - loan.creditamount) AS endingbalance, + loan.originator_external_ids AS originator_external_ids + FROM (SELECT DISTINCT g.pname AS pname, + g.gl_code AS gl_code, + g.glname AS glname, + COALESCE(mh.assetowner, c.assetowner, 0) AS assetowner, + COALESCE(mh.debitamount, 0) - COALESCE(mh.creditamount, 0) AS openingbalance, + COALESCE(c.debitamount, 0) AS debitamount, + COALESCE(c.creditamount, 0) AS creditamount, + COALESCE(mh.originator_external_ids, c.originator_external_ids) AS originator_external_ids + FROM (SELECT DISTINCT ag.gl_code, ag.id, pl.NAME AS pname, ag.NAME AS glname + FROM acc_gl_account ag + JOIN acc_product_mapping am ON am.gl_account_id = ag.id AND am.product_type = 1 + JOIN m_product_loan pl ON pl.id = am.product_id) g + LEFT JOIN merged_historical_data mh + ON g.gl_code = mh.glcode + AND mh.productname = g.pname + LEFT JOIN current_cob_data c + ON g.gl_code = c.glcode + AND c.productname = g.pname + AND mh.assetowner = c.assetowner + AND mh.originator_external_ids = c.originator_external_ids + + UNION ALL + + SELECT DISTINCT c.productname AS pname, + c.glcode AS gl_code, + c.glname AS glname, + COALESCE(c.assetowner, 0) AS assetowner, + 0 AS openingbalance, + COALESCE(c.debitamount, 0) AS debitamount, + COALESCE(c.creditamount, 0) AS creditamount, + COALESCE(matched.originator_external_ids, c.originator_external_ids) AS originator_external_ids + FROM current_cob_data c + LEFT JOIN (SELECT g3.gl_code, g3.pname, mh.assetowner, mh.originator_external_ids + FROM (SELECT DISTINCT ag.gl_code, pl.NAME AS pname + FROM acc_gl_account ag + JOIN acc_product_mapping am + ON am.gl_account_id = ag.id AND am.product_type = 1 + JOIN m_product_loan pl ON pl.id = am.product_id) g3 + LEFT JOIN merged_historical_data mh + ON g3.gl_code = mh.glcode + AND mh.productname = g3.pname) matched + ON matched.gl_code = c.glcode + AND matched.pname = c.productname + AND matched.assetowner = c.assetowner + AND matched.originator_external_ids = c.originator_external_ids + WHERE matched.gl_code IS NULL) loan) a) AS txnreport + LEFT JOIN retained_earning summary + ON txnreport.glacct = summary.glacct + AND txnreport.assetowner = summary.assetowner + AND summary.product = txnreport.product + AND summary.originator_external_ids = txnreport.originator_external_ids) report +WHERE report.endingbalance != 0 + OR report.debitmovement != 0 + OR report.creditmovement != 0 +ORDER BY glacct + ]]> + + report_name='Trial Balance Summary Report with Asset Owner' + + + diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0238_transaction_summary_report_update_originator_inline_join.xml b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0238_transaction_summary_report_update_originator_inline_join.xml new file mode 100644 index 00000000000..fdbb525b591 --- /dev/null +++ b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0238_transaction_summary_report_update_originator_inline_join.xml @@ -0,0 +1,3285 @@ + + + + + + = '${endDate}' + WHERE t.submitted_on_date = '${endDate}' + AND t.transaction_type_enum not in (10, 26, 32, 34, 36, 39, 42, 43) + AND (t.office_id = ${officeId})), + slt_charge_adj AS (SELECT '${endDate}' AS transactiondate, + t.id, + l.name, + t.transaction_type_enum, + d.payment_type_id, + t.overpayment_portion_derived, + t.principal_portion_derived, + t.interest_portion_derived, + t.fee_charges_portion_derived, + t.penalty_charges_portion_derived, + t.amount, + e.status, + e.settlement_date, + e.owner_id, + m.charged_off_on_date, + t.transaction_date, + m.charge_off_reason_cv_id, + (SELECT STRING_AGG(DISTINCT mlo.external_id, ', ' ORDER BY mlo.external_id) FROM m_loan_originator_mapping mlom JOIN m_loan_originator mlo ON mlo.id = mlom.originator_id WHERE mlom.loan_id = t.loan_id) AS originator_external_ids + FROM m_loan_transaction t + JOIN m_loan m ON m.id = t.loan_id + JOIN m_product_loan l ON l.id = m.product_id + LEFT JOIN m_payment_detail d ON d.id = t.payment_detail_id + LEFT JOIN m_external_asset_owner_transfer e + ON e.loan_id = t.loan_id AND e.settlement_date < '${endDate}' AND + e.effective_date_to >= '${endDate}' + WHERE t.submitted_on_date = '${endDate}' + AND t.transaction_type_enum = 26 + AND (t.office_id = ${officeId})), + rlt_except_charge_adj_and_accrual AS (SELECT '${endDate}' AS transactiondate, + t.id, + l.name, + t.transaction_type_enum, + d.payment_type_id, + CASE + WHEN d.payment_type_id IS NULL AND t.classification_cv_id IS NOT NULL + THEN (SELECT code_value FROM m_code_value WHERE id = t.classification_cv_id) + ELSE NULL END AS classification_name, + t.overpayment_portion_derived, + t.principal_portion_derived, + t.interest_portion_derived, + t.fee_charges_portion_derived, + t.penalty_charges_portion_derived, + t.amount, + e.status, + e.settlement_date, + e.owner_id, + m.charged_off_on_date, + t.transaction_date, + m.charge_off_reason_cv_id, + (SELECT STRING_AGG(DISTINCT mlo.external_id, ', ' ORDER BY mlo.external_id) FROM m_loan_originator_mapping mlom JOIN m_loan_originator mlo ON mlo.id = mlom.originator_id WHERE mlom.loan_id = t.loan_id) AS originator_external_ids + FROM m_loan_transaction t + JOIN m_loan m ON m.id = t.loan_id + JOIN m_product_loan l ON l.id = m.product_id + LEFT JOIN m_payment_detail d ON d.id = t.payment_detail_id + LEFT JOIN m_external_asset_owner_transfer e + ON e.loan_id = t.loan_id AND + e.settlement_date < '${endDate}' AND + e.effective_date_to >= '${endDate}' + WHERE t.reversed_on_date = '${endDate}' + AND t.transaction_type_enum not in (10, 26, 32, 34, 36, 39, 42, 43) + AND (t.office_id = ${officeId})), + rlt_charge_adj AS (SELECT '${endDate}' AS transactiondate, + t.id, + l.name, + t.transaction_type_enum, + d.payment_type_id, + t.overpayment_portion_derived, + t.principal_portion_derived, + t.interest_portion_derived, + t.fee_charges_portion_derived, + t.penalty_charges_portion_derived, + t.amount, + e.status, + e.settlement_date, + e.owner_id, + m.charged_off_on_date, + t.transaction_date, + m.charge_off_reason_cv_id, + (SELECT STRING_AGG(DISTINCT mlo.external_id, ', ' ORDER BY mlo.external_id) FROM m_loan_originator_mapping mlom JOIN m_loan_originator mlo ON mlo.id = mlom.originator_id WHERE mlom.loan_id = t.loan_id) AS originator_external_ids + FROM m_loan_transaction t + JOIN m_loan m ON m.id = t.loan_id + JOIN m_product_loan l ON l.id = m.product_id + LEFT JOIN m_payment_detail d ON d.id = t.payment_detail_id + LEFT JOIN m_external_asset_owner_transfer e + ON e.loan_id = t.loan_id AND e.settlement_date < '${endDate}' AND + e.effective_date_to >= '${endDate}' + WHERE t.reversed_on_date = '${endDate}' + AND t.transaction_type_enum = 26 + AND (t.office_id = ${officeId})), + slt_cap_income_amortization AS (SELECT '${endDate}' AS transactiondate, + t.id, + l.name, + t.transaction_type_enum, + d.payment_type_id, + CASE + WHEN d.payment_type_id IS NULL AND bt.classification_cv_id IS NOT NULL + THEN (SELECT code_value FROM m_code_value WHERE id = bt.classification_cv_id) + ELSE NULL END AS classification_name, + CASE + WHEN t.overpayment_portion_derived IS NOT NULL + THEN map.amount + ELSE NULL END AS overpayment_portion_derived, + CASE + WHEN t.principal_portion_derived IS NOT NULL + THEN map.amount + ELSE NULL END AS principal_portion_derived, + CASE + WHEN t.interest_portion_derived IS NOT NULL + THEN map.amount + ELSE NULL END AS interest_portion_derived, + CASE + WHEN t.fee_charges_portion_derived IS NOT NULL + THEN map.amount + ELSE NULL END AS fee_charges_portion_derived, + CASE + WHEN t.penalty_charges_portion_derived IS NOT NULL + THEN map.amount + ELSE NULL END AS penalty_charges_portion_derived, + map.amount, + e.status, + e.settlement_date, + e.owner_id, + m.charged_off_on_date, + t.transaction_date, + m.charge_off_reason_cv_id, + (SELECT STRING_AGG(DISTINCT mlo.external_id, ', ' ORDER BY mlo.external_id) FROM m_loan_originator_mapping mlom JOIN m_loan_originator mlo ON mlo.id = mlom.originator_id WHERE mlom.loan_id = t.loan_id) AS originator_external_ids + FROM m_loan_transaction t + JOIN m_loan m ON m.id = t.loan_id + JOIN m_product_loan l ON l.id = m.product_id + LEFT JOIN m_payment_detail d ON d.id = t.payment_detail_id + JOIN m_loan_amortization_allocation_mapping map + ON map.amortization_loan_transaction_id = t.id + JOIN m_loan_transaction bt ON bt.id = map.base_loan_transaction_id + LEFT JOIN m_external_asset_owner_transfer e ON e.loan_id = t.loan_id AND + e.settlement_date < + '${endDate}' AND + e.effective_date_to >= + '${endDate}' + WHERE t.submitted_on_date = '${endDate}' + AND t.is_reversed = false + AND t.transaction_type_enum IN (36, 39, 42, 43) + AND (t.office_id = ${officeId})), + rlt_cap_income_amortization AS (SELECT '${endDate}' AS transactiondate, + t.id, + l.name, + t.transaction_type_enum, + d.payment_type_id, + CASE + WHEN d.payment_type_id IS NULL AND bt.classification_cv_id IS NOT NULL + THEN (SELECT code_value FROM m_code_value WHERE id = bt.classification_cv_id) + ELSE NULL END AS classification_name, + CASE + WHEN t.overpayment_portion_derived IS NOT NULL + THEN map.amount + ELSE NULL END AS overpayment_portion_derived, + CASE + WHEN t.principal_portion_derived IS NOT NULL + THEN map.amount + ELSE NULL END AS principal_portion_derived, + CASE + WHEN t.interest_portion_derived IS NOT NULL + THEN map.amount + ELSE NULL END AS interest_portion_derived, + CASE + WHEN t.fee_charges_portion_derived IS NOT NULL + THEN map.amount + ELSE NULL END AS fee_charges_portion_derived, + CASE + WHEN t.penalty_charges_portion_derived IS NOT NULL + THEN map.amount + ELSE NULL END AS penalty_charges_portion_derived, + map.amount, + e.status, + e.settlement_date, + e.owner_id, + m.charged_off_on_date, + t.transaction_date, + m.charge_off_reason_cv_id, + (SELECT STRING_AGG(DISTINCT mlo.external_id, ', ' ORDER BY mlo.external_id) FROM m_loan_originator_mapping mlom JOIN m_loan_originator mlo ON mlo.id = mlom.originator_id WHERE mlom.loan_id = t.loan_id) AS originator_external_ids + FROM m_loan_transaction t + JOIN m_loan m ON m.id = t.loan_id + JOIN m_product_loan l ON l.id = m.product_id + LEFT JOIN m_payment_detail d ON d.id = t.payment_detail_id + JOIN m_loan_amortization_allocation_mapping map + ON map.amortization_loan_transaction_id = t.id + JOIN m_loan_transaction bt ON bt.id = map.base_loan_transaction_id + LEFT JOIN m_external_asset_owner_transfer e ON e.loan_id = t.loan_id AND + e.settlement_date < + '${endDate}' AND + e.effective_date_to >= + '${endDate}' + WHERE t.reversed_on_date = '${endDate}' + AND t.is_reversed = true + AND t.transaction_type_enum IN (36, 39, 42, 43) + AND (t.office_id = ${officeId})), + active_external_asset_owner_transfers AS (SELECT '${endDate}' AS transactiondate, + t.id, + p.name, + t.owner_id, + t.previous_owner_id, + dt.principal_outstanding_derived, + dt.interest_outstanding_derived, + dt.fee_charges_outstanding_derived, + dt.penalty_charges_outstanding_derived, + dt.total_overpaid_derived, + l.charged_off_on_date, + t.settlement_date, + l.charge_off_reason_cv_id, + (SELECT STRING_AGG(DISTINCT mlo.external_id, ', ' ORDER BY mlo.external_id) FROM m_loan_originator_mapping mlom JOIN m_loan_originator mlo ON mlo.id = mlom.originator_id WHERE mlom.loan_id = t.loan_id) AS originator_external_ids + FROM m_external_asset_owner_transfer t + JOIN m_loan l ON l.id = t.loan_id + JOIN m_client c ON c.id = l.client_id + JOIN m_product_loan p ON p.id = l.product_id + JOIN m_external_asset_owner_transfer_details dt + ON dt.asset_owner_transfer_id = t.id + WHERE t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') + AND c.office_id = ${officeId} + AND t.settlement_date = '${endDate}'), + buyback_external_asset_owner_transfers AS (SELECT '${endDate}' AS transactiondate, + t.id, + p.name, + dt.principal_outstanding_derived, + dt.interest_outstanding_derived, + dt.fee_charges_outstanding_derived, + dt.penalty_charges_outstanding_derived, + dt.total_overpaid_derived, + l.charged_off_on_date, + t.settlement_date, + l.charge_off_reason_cv_id, + t.owner_id, + (SELECT STRING_AGG(DISTINCT mlo.external_id, ', ' ORDER BY mlo.external_id) FROM m_loan_originator_mapping mlom JOIN m_loan_originator mlo ON mlo.id = mlom.originator_id WHERE mlom.loan_id = t.loan_id) AS originator_external_ids + FROM m_external_asset_owner_transfer t + JOIN m_loan l ON l.id = t.loan_id + JOIN m_client c ON c.id = l.client_id + JOIN m_product_loan p ON p.id = l.product_id + JOIN m_external_asset_owner_transfer_details dt + ON dt.asset_owner_transfer_id = t.id + WHERE t.status in ('BUYBACK', 'BUYBACK_INTERMEDIATE') + AND c.office_id = ${officeId} + AND t.settlement_date = '${endDate}') +SELECT '${endDate}' AS TransactionDate, + a.product AS Product, + CASE + WHEN a.transaction_type = 9999 THEN 'Asset Transfer' + WHEN a.transaction_type = 99999 THEN 'Asset Buyback' + ELSE (SELECT enum_message_property + FROM r_enum_value + WHERE enum_name = 'transaction_type_enum' + AND enum_id = a.transaction_type) END AS TransactionType_Name, + COALESCE((SELECT value FROM m_payment_type WHERE id = a.payment_type_id), + a.classification_name) AS PaymentType_Name, + a.chargetype AS chargetype, + a.reversal_indicator AS Reversed, + a.Allocation_Type AS Allocation_Type, + (SELECT code_value FROM m_code_value WHERE id = a.charge_off_reason_id) AS Chargeoff_ReasonCode, + CASE + WHEN a.transaction_type = 9999 THEN sum(a.amount) * + 1 + WHEN a.transaction_type = 99999 THEN sum(a.amount) * - 1 + WHEN a.transaction_type IN (2, 23, 21, 22, 24, 4, 5, 8, 6, 27, 9, 26, 28, 31, 33, 34, 37, 39, 41, 43) AND + a.reversal_indicator = false THEN sum(a.amount) * -1 + WHEN a.transaction_type IN (2, 23, 21, 22, 24, 4, 5, 8, 6, 27, 9, 26, 28, 31, 33, 34, 37, 39, 41, 43) AND + a.reversal_indicator = true THEN sum(a.amount) * + 1 + WHEN a.transaction_type IN (1, 10, 25, 20, 35, 36, 40, 42) AND a.reversal_indicator = false THEN sum(a.amount) * + 1 + WHEN a.transaction_type IN (1, 10, 25, 20, 35, 36, 40, 42) AND a.reversal_indicator = true + THEN sum(a.amount) * -1 END AS Transaction_Amount, + (SELECT external_id + FROM m_external_asset_owner + WHERE id = a.asset_owner_id) AS Asset_owner_id, + (SELECT external_id + FROM m_external_asset_owner + WHERE id = a.from_asset_owner_id) AS From_asset_owner_id, + a.originator_external_ids +FROM (SELECT t.transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Principal' AS Allocation_Type, + CASE + WHEN t.transaction_type_enum in (1) THEN (CASE + WHEN t.amount is null THEN 0 + WHEN t.overpayment_portion_derived is null THEN t.amount + WHEN t.overpayment_portion_derived is not null + THEN t.amount - t.overpayment_portion_derived + ELSE t.amount END) + ELSE (CASE + WHEN t.principal_portion_derived is null THEN 0 + ELSE t.principal_portion_derived end) END amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM slt_except_charge_adj_and_accrual AS t + UNION ALL + SELECT t.transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Interest' AS Allocation_Type, + CASE WHEN t.interest_portion_derived is null THEN 0 ELSE t.interest_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM slt_except_charge_adj_and_accrual AS t + UNION ALL + SELECT t.transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Fees' AS Allocation_Type, + CASE WHEN t.fee_charges_portion_derived is null THEN 0 ELSE t.fee_charges_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM slt_except_charge_adj_and_accrual AS t + UNION ALL + SELECT t.transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Penalty' AS Allocation_Type, + CASE + WHEN t.penalty_charges_portion_derived is null THEN 0 + ELSE t.penalty_charges_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM slt_except_charge_adj_and_accrual AS t + UNION ALL + SELECT t.transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Unallocated Credit (UNC)' AS Allocation_Type, + CASE WHEN t.overpayment_portion_derived is null THEN 0 ELSE t.overpayment_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM slt_except_charge_adj_and_accrual AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Fees' AS Allocation_Type, + CASE WHEN t.fee_charges_portion_derived is null THEN 0 ELSE t.fee_charges_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.transaction_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM slt_cap_income_amortization AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Penalty' AS Allocation_Type, + CASE + WHEN t.penalty_charges_portion_derived is null THEN 0 + ELSE t.penalty_charges_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.transaction_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM slt_cap_income_amortization AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Interest' AS Allocation_Type, + CASE WHEN t.interest_portion_derived is null THEN 0 ELSE t.interest_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.transaction_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM slt_cap_income_amortization AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Principal' AS Allocation_Type, + CASE WHEN t.principal_portion_derived is null THEN 0 ELSE t.principal_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.transaction_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM slt_cap_income_amortization AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Unallocated Credit (UNC)' AS Allocation_Type, + CASE WHEN t.overpayment_portion_derived is null THEN 0 ELSE t.overpayment_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.transaction_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM slt_cap_income_amortization AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Fees' AS Allocation_Type, + CASE WHEN t.fee_charges_portion_derived is null THEN 0 ELSE t.fee_charges_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.transaction_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_cap_income_amortization AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Penalty' AS Allocation_Type, + CASE + WHEN t.penalty_charges_portion_derived is null THEN 0 + ELSE t.penalty_charges_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.transaction_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_cap_income_amortization AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Interest' AS Allocation_Type, + CASE WHEN t.interest_portion_derived is null THEN 0 ELSE t.interest_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.transaction_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_cap_income_amortization AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Principal' AS Allocation_Type, + CASE WHEN t.principal_portion_derived is null THEN 0 ELSE t.principal_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.transaction_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_cap_income_amortization AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Unallocated Credit (UNC)' AS Allocation_Type, + CASE WHEN t.overpayment_portion_derived is null THEN 0 ELSE t.overpayment_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.transaction_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_cap_income_amortization AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + l.name AS product, + t.transaction_type_enum AS transaction_type, + null AS payment_type_id, + null AS classification_name, + mc.name AS chargetype, + false AS reversal_indicator, + 'Fees' AS Allocation_Type, + CASE WHEN pd.amount is null THEN 0 ELSE pd.amount END AS amount, + CASE + WHEN e.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND e.settlement_date < '${endDate}' + THEN e.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (m.charged_off_on_date <= t.transaction_date) + THEN m.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + (SELECT STRING_AGG(DISTINCT mlo.external_id, ', ' ORDER BY mlo.external_id) FROM m_loan_originator_mapping mlom JOIN m_loan_originator mlo ON mlo.id = mlom.originator_id WHERE mlom.loan_id = t.loan_id) AS originator_external_ids + FROM m_loan_transaction t + JOIN m_loan m ON m.id = t.loan_id + JOIN m_product_loan l ON l.id = m.product_id + JOIN m_loan_charge_paid_by pd ON pd.loan_transaction_id = t.id + JOIN m_loan_charge c ON c.id = pd.loan_charge_id + JOIN m_charge mc ON mc.id = c.charge_id AND mc.is_penalty = false + LEFT JOIN m_external_asset_owner_transfer e + ON e.loan_id = t.loan_id AND e.settlement_date < '${endDate}' AND + e.effective_date_to >= '${endDate}' + WHERE t.submitted_on_date = '${endDate}' + AND t.transaction_type_enum = 10 + AND t.is_reversed = false + AND (t.office_id = ${officeId}) + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + l.name AS product, + t.transaction_type_enum AS transaction_type, + null AS payment_type_id, + null AS classification_name, + mc.name AS chargetype, + false AS reversal_indicator, + 'Penalty' AS Allocation_Type, + CASE WHEN pd.amount is null THEN 0 ELSE pd.amount END AS amount, + CASE + WHEN e.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND e.settlement_date < '${endDate}' + THEN e.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (m.charged_off_on_date <= t.transaction_date) + THEN m.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + (SELECT STRING_AGG(DISTINCT mlo.external_id, ', ' ORDER BY mlo.external_id) FROM m_loan_originator_mapping mlom JOIN m_loan_originator mlo ON mlo.id = mlom.originator_id WHERE mlom.loan_id = t.loan_id) AS originator_external_ids + FROM m_loan_transaction t + JOIN m_loan m ON m.id = t.loan_id + JOIN m_product_loan l ON l.id = m.product_id + JOIN m_loan_charge_paid_by pd ON pd.loan_transaction_id = t.id + JOIN m_loan_charge c ON c.id = pd.loan_charge_id + JOIN m_charge mc ON mc.id = c.charge_id AND mc.is_penalty = true + LEFT JOIN m_external_asset_owner_transfer e + ON e.loan_id = t.loan_id AND e.settlement_date < '${endDate}' AND + e.effective_date_to >= '${endDate}' + WHERE t.submitted_on_date = '${endDate}' + AND t.transaction_type_enum = 10 + AND t.is_reversed = false + AND (t.office_id = ${officeId}) + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + l.name AS product, + t.transaction_type_enum AS transaction_type, + null AS payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Interest' AS Allocation_Type, + CASE WHEN t.interest_portion_derived is null THEN 0 ELSE t.interest_portion_derived END AS amount, + CASE + WHEN e.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND e.settlement_date < '${endDate}' + THEN e.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (m.charged_off_on_date <= t.transaction_date) + THEN m.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + (SELECT STRING_AGG(DISTINCT mlo.external_id, ', ' ORDER BY mlo.external_id) FROM m_loan_originator_mapping mlom JOIN m_loan_originator mlo ON mlo.id = mlom.originator_id WHERE mlom.loan_id = t.loan_id) AS originator_external_ids + FROM m_loan_transaction t + JOIN m_loan m ON m.id = t.loan_id + JOIN m_product_loan l ON l.id = m.product_id + LEFT JOIN m_external_asset_owner_transfer e + ON e.loan_id = t.loan_id AND e.settlement_date < '${endDate}' AND + e.effective_date_to >= '${endDate}' + WHERE t.submitted_on_date = '${endDate}' + AND t.transaction_type_enum in (10, 34) + AND t.is_reversed = false + AND (t.office_id = ${officeId}) + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Fees' AS Allocation_Type, + CASE WHEN t.fee_charges_portion_derived is null THEN 0 ELSE t.fee_charges_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM slt_charge_adj AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Penalty' AS Allocation_Type, + CASE + WHEN t.penalty_charges_portion_derived is null THEN 0 + ELSE t.penalty_charges_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM slt_charge_adj AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Interest' AS Allocation_Type, + CASE WHEN t.interest_portion_derived is null THEN 0 ELSE t.interest_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM slt_charge_adj AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Principal' AS Allocation_Type, + CASE WHEN t.principal_portion_derived is null THEN 0 ELSE t.principal_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM slt_charge_adj AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Unallocated Credit (UNC)' AS Allocation_Type, + CASE WHEN t.overpayment_portion_derived is null THEN 0 ELSE t.overpayment_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM slt_charge_adj AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + true AS reversal_indicator, + 'Principal' AS Allocation_Type, + CASE + WHEN t.transaction_type_enum in (1) THEN (CASE + WHEN t.amount is null THEN 0 + WHEN t.overpayment_portion_derived is null THEN t.amount + WHEN t.overpayment_portion_derived is not null + THEN t.amount - t.overpayment_portion_derived + ELSE t.amount END) + ELSE (CASE + WHEN t.principal_portion_derived is null THEN 0 + ELSE t.principal_portion_derived end) END amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_except_charge_adj_and_accrual AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + true AS reversal_indicator, + 'Interest' AS Allocation_Type, + CASE WHEN t.interest_portion_derived is null THEN 0 ELSE t.interest_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_except_charge_adj_and_accrual AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + true AS reversal_indicator, + 'Fees' AS Allocation_Type, + CASE WHEN t.fee_charges_portion_derived is null THEN 0 ELSE t.fee_charges_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_except_charge_adj_and_accrual AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + true AS reversal_indicator, + 'Penalty' AS Allocation_Type, + CASE + WHEN t.penalty_charges_portion_derived is null THEN 0 + ELSE t.penalty_charges_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_except_charge_adj_and_accrual AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + true AS reversal_indicator, + 'Unallocated Credit (UNC)' AS Allocation_Type, + CASE WHEN t.overpayment_portion_derived is null THEN 0 ELSE t.overpayment_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_except_charge_adj_and_accrual AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + l.name AS product, + t.transaction_type_enum AS transaction_type, + null AS payment_type_id, + null AS classification_name, + mc.name AS chargetype, + true AS reversal_indicator, + 'Fees' AS Allocation_Type, + CASE WHEN pd.amount is null THEN 0 ELSE pd.amount END AS amount, + CASE + WHEN e.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND e.settlement_date < '${endDate}' + THEN e.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (m.charged_off_on_date <= t.transaction_date) + THEN m.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + (SELECT STRING_AGG(DISTINCT mlo.external_id, ', ' ORDER BY mlo.external_id) FROM m_loan_originator_mapping mlom JOIN m_loan_originator mlo ON mlo.id = mlom.originator_id WHERE mlom.loan_id = t.loan_id) AS originator_external_ids + FROM m_loan_transaction t + JOIN m_loan m ON m.id = t.loan_id + JOIN m_product_loan l ON l.id = m.product_id + JOIN m_loan_charge_paid_by pd ON pd.loan_transaction_id = t.id + JOIN m_loan_charge c ON c.id = pd.loan_charge_id + JOIN m_charge mc ON mc.id = c.charge_id AND mc.is_penalty = false + LEFT JOIN m_external_asset_owner_transfer e + ON e.loan_id = t.loan_id AND e.settlement_date < '${endDate}' AND + e.effective_date_to >= '${endDate}' + WHERE t.reversed_on_date = '${endDate}' + AND t.transaction_type_enum = 10 + AND t.is_reversed = true + AND (t.office_id = ${officeId}) + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + l.name AS product, + t.transaction_type_enum AS transaction_type, + null AS payment_type_id, + null AS classification_name, + mc.name AS chargetype, + true AS reversal_indicator, + 'Penalty' AS Allocation_Type, + CASE WHEN pd.amount is null THEN 0 ELSE pd.amount END AS amount, + CASE + WHEN e.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND e.settlement_date < '${endDate}' + THEN e.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (m.charged_off_on_date <= t.transaction_date) + THEN m.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + (SELECT STRING_AGG(DISTINCT mlo.external_id, ', ' ORDER BY mlo.external_id) FROM m_loan_originator_mapping mlom JOIN m_loan_originator mlo ON mlo.id = mlom.originator_id WHERE mlom.loan_id = t.loan_id) AS originator_external_ids + FROM m_loan_transaction t + JOIN m_loan m ON m.id = t.loan_id + JOIN m_product_loan l ON l.id = m.product_id + JOIN m_loan_charge_paid_by pd ON pd.loan_transaction_id = t.id + JOIN m_loan_charge c ON c.id = pd.loan_charge_id + JOIN m_charge mc ON mc.id = c.charge_id AND mc.is_penalty = true + LEFT JOIN m_external_asset_owner_transfer e + ON e.loan_id = t.loan_id AND e.settlement_date < '${endDate}' AND + e.effective_date_to >= '${endDate}' + WHERE t.reversed_on_date = '${endDate}' + AND t.transaction_type_enum = 10 + AND t.is_reversed = true + AND (t.office_id = ${officeId}) + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + l.name AS product, + t.transaction_type_enum AS transaction_type, + null AS payment_type_id, + null AS classification_name, + '' AS chargetype, + true AS reversal_indicator, + 'Interest' AS Allocation_Type, + CASE WHEN t.interest_portion_derived is null THEN 0 ELSE t.interest_portion_derived END AS amount, + CASE + WHEN e.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND e.settlement_date < '${endDate}' + THEN e.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (m.charged_off_on_date <= t.transaction_date) + THEN m.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + (SELECT STRING_AGG(DISTINCT mlo.external_id, ', ' ORDER BY mlo.external_id) FROM m_loan_originator_mapping mlom JOIN m_loan_originator mlo ON mlo.id = mlom.originator_id WHERE mlom.loan_id = t.loan_id) AS originator_external_ids + FROM m_loan_transaction t + JOIN m_loan m ON m.id = t.loan_id + JOIN m_product_loan l ON l.id = m.product_id + LEFT JOIN m_external_asset_owner_transfer e + ON e.loan_id = t.loan_id AND e.settlement_date < '${endDate}' AND + e.effective_date_to >= '${endDate}' + WHERE t.reversed_on_date = '${endDate}' + AND t.transaction_type_enum = 10 + AND t.is_reversed = true + AND (t.office_id = ${officeId}) + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + null AS classification_name, + '' AS chargetype, + true AS reversal_indicator, + 'Fees' AS Allocation_Type, + CASE WHEN t.fee_charges_portion_derived is null THEN 0 ELSE t.fee_charges_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_charge_adj AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + null AS classification_name, + '' AS chargetype, + true AS reversal_indicator, + 'Penalty' AS Allocation_Type, + CASE + WHEN t.penalty_charges_portion_derived is null THEN 0 + ELSE t.penalty_charges_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_charge_adj AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + null AS classification_name, + '' AS chargetype, + true AS reversal_indicator, + 'Interest' AS Allocation_Type, + CASE WHEN t.interest_portion_derived is null THEN 0 ELSE t.interest_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_charge_adj AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + null AS classification_name, + '' AS chargetype, + true AS reversal_indicator, + 'Principal' AS Allocation_Type, + CASE WHEN t.principal_portion_derived is null THEN 0 ELSE t.principal_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_charge_adj AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + null AS classification_name, + '' AS chargetype, + true AS reversal_indicator, + 'Unallocated Credit (UNC)' AS Allocation_Type, + CASE WHEN t.overpayment_portion_derived is null THEN 0 ELSE t.overpayment_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null::bigint AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_charge_adj AS t + UNION ALL + SELECT t.transactiondate, + t.id, + t.name AS product, + 9999 AS transaction_type, + null AS payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Principal' AS Allocation_type, + t.principal_outstanding_derived AS amount, + t.owner_id AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.settlement_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + t.previous_owner_id AS from_asset_owner_id, + t.originator_external_ids + FROM active_external_asset_owner_transfers AS t + WHERE t.principal_outstanding_derived > 0 + UNION ALL + SELECT t.transactiondate, + t.id, + t.name AS product, + 9999 AS transaction_type, + null AS payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Interest' AS Allocation_type, + t.interest_outstanding_derived AS amount, + t.owner_id AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.settlement_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + t.previous_owner_id AS from_asset_owner_id, + t.originator_external_ids + FROM active_external_asset_owner_transfers AS t + WHERE t.interest_outstanding_derived > 0 + UNION ALL + SELECT t.transactiondate, + t.id, + t.name AS product, + 9999 AS transaction_type, + null AS payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Fees' AS Allocation_type, + t.fee_charges_outstanding_derived AS amount, + t.owner_id AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.settlement_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + t.previous_owner_id AS from_asset_owner_id, + t.originator_external_ids + FROM active_external_asset_owner_transfers AS t + WHERE t.fee_charges_outstanding_derived > 0 + UNION ALL + SELECT t.transactiondate, + t.id, + t.name AS product, + 9999 AS transaction_type, + null AS payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Penalty' AS Allocation_type, + t.penalty_charges_outstanding_derived AS amount, + t.owner_id AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.settlement_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + t.previous_owner_id AS from_asset_owner_id, + t.originator_external_ids + FROM active_external_asset_owner_transfers AS t + WHERE t.penalty_charges_outstanding_derived > 0 + UNION ALL + SELECT t.transactiondate, + t.id, + t.name AS product, + 9999 AS transaction_type, + null AS payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Unallocated Credit (UNC)' AS Allocation_type, + t.total_overpaid_derived AS amount, + t.owner_id AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.settlement_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + t.previous_owner_id AS from_asset_owner_id, + t.originator_external_ids + FROM active_external_asset_owner_transfers AS t + WHERE t.total_overpaid_derived > 0 + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + 99999 AS transaction_type, + null AS payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Principal' AS Allocation_type, + t.principal_outstanding_derived AS amount, + null AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.settlement_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + t.owner_id AS from_asset_owner_id, + t.originator_external_ids + FROM buyback_external_asset_owner_transfers AS t + WHERE t.principal_outstanding_derived > 0 + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + 99999 AS transaction_type, + null AS payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Interest' AS Allocation_type, + t.interest_outstanding_derived AS amount, + null AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.settlement_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + t.owner_id AS from_asset_owner_id, + t.originator_external_ids + FROM buyback_external_asset_owner_transfers AS t + WHERE t.interest_outstanding_derived > 0 + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + 99999 AS transaction_type, + null AS payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Fees' AS Allocation_type, + t.fee_charges_outstanding_derived AS amount, + null AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.settlement_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + t.owner_id AS from_asset_owner_id, + t.originator_external_ids + FROM buyback_external_asset_owner_transfers AS t + WHERE t.fee_charges_outstanding_derived > 0 + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + 99999 AS transaction_type, + null AS payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Penalty' AS Allocation_type, + t.penalty_charges_outstanding_derived AS amount, + null AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.settlement_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + t.owner_id AS from_asset_owner_id, + t.originator_external_ids + FROM buyback_external_asset_owner_transfers AS t + WHERE t.penalty_charges_outstanding_derived > 0 + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + 99999 AS transaction_type, + null AS payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Unallocated Credit (UNC)' AS Allocation_type, + t.total_overpaid_derived * -1 AS amount, + null AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.settlement_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + t.owner_id AS from_asset_owner_id, + t.originator_external_ids + FROM buyback_external_asset_owner_transfers AS t + WHERE t.total_overpaid_derived > 0) a +GROUP BY a.transactiondate, a.product, a.transaction_type, a.payment_type_id, a.classification_name, a.chargetype, + a.reversal_indicator, a.Allocation_Type, a.asset_owner_id, a.charge_off_reason_id, a.from_asset_owner_id, + a.originator_external_ids +ORDER BY 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 + + ]]> + + report_name='Transaction Summary Report with Asset Owner' + + + + + = '${endDate}' + WHERE t.submitted_on_date = '${endDate}' + AND t.transaction_type_enum not in (10, 26, 32, 34, 36, 39, 42, 43) + AND (t.office_id = ${officeId})), + slt_charge_adj AS (SELECT '${endDate}' AS transactiondate, + t.id, + l.name, + t.transaction_type_enum, + d.payment_type_id, + t.overpayment_portion_derived, + t.principal_portion_derived, + t.interest_portion_derived, + t.fee_charges_portion_derived, + t.penalty_charges_portion_derived, + t.amount, + e.status, + e.settlement_date, + e.owner_id, + m.charged_off_on_date, + t.transaction_date, + m.charge_off_reason_cv_id, + (SELECT GROUP_CONCAT(DISTINCT mlo.external_id ORDER BY mlo.external_id SEPARATOR ', ') FROM m_loan_originator_mapping mlom JOIN m_loan_originator mlo ON mlo.id = mlom.originator_id WHERE mlom.loan_id = t.loan_id) AS originator_external_ids + FROM m_loan_transaction t + JOIN m_loan m ON m.id = t.loan_id + JOIN m_product_loan l ON l.id = m.product_id + LEFT JOIN m_payment_detail d ON d.id = t.payment_detail_id + LEFT JOIN m_external_asset_owner_transfer e + ON e.loan_id = t.loan_id AND e.settlement_date < '${endDate}' AND + e.effective_date_to >= '${endDate}' + WHERE t.submitted_on_date = '${endDate}' + AND t.transaction_type_enum = 26 + AND (t.office_id = ${officeId})), + rlt_except_charge_adj_and_accrual AS (SELECT '${endDate}' AS transactiondate, + t.id, + l.name, + t.transaction_type_enum, + d.payment_type_id, + CASE + WHEN d.payment_type_id IS NULL AND t.classification_cv_id IS NOT NULL + THEN (SELECT code_value FROM m_code_value WHERE id = t.classification_cv_id) + ELSE NULL END AS classification_name, + t.overpayment_portion_derived, + t.principal_portion_derived, + t.interest_portion_derived, + t.fee_charges_portion_derived, + t.penalty_charges_portion_derived, + t.amount, + e.status, + e.settlement_date, + e.owner_id, + m.charged_off_on_date, + t.transaction_date, + m.charge_off_reason_cv_id, + (SELECT GROUP_CONCAT(DISTINCT mlo.external_id ORDER BY mlo.external_id SEPARATOR ', ') FROM m_loan_originator_mapping mlom JOIN m_loan_originator mlo ON mlo.id = mlom.originator_id WHERE mlom.loan_id = t.loan_id) AS originator_external_ids + FROM m_loan_transaction t + JOIN m_loan m ON m.id = t.loan_id + JOIN m_product_loan l ON l.id = m.product_id + LEFT JOIN m_payment_detail d ON d.id = t.payment_detail_id + LEFT JOIN m_external_asset_owner_transfer e + ON e.loan_id = t.loan_id AND + e.settlement_date < '${endDate}' AND + e.effective_date_to >= '${endDate}' + WHERE t.reversed_on_date = '${endDate}' + AND t.transaction_type_enum not in (10, 26, 32, 34, 36, 39, 42, 43) + AND (t.office_id = ${officeId})), + rlt_charge_adj AS (SELECT '${endDate}' AS transactiondate, + t.id, + l.name, + t.transaction_type_enum, + d.payment_type_id, + t.overpayment_portion_derived, + t.principal_portion_derived, + t.interest_portion_derived, + t.fee_charges_portion_derived, + t.penalty_charges_portion_derived, + t.amount, + e.status, + e.settlement_date, + e.owner_id, + m.charged_off_on_date, + t.transaction_date, + m.charge_off_reason_cv_id, + (SELECT GROUP_CONCAT(DISTINCT mlo.external_id ORDER BY mlo.external_id SEPARATOR ', ') FROM m_loan_originator_mapping mlom JOIN m_loan_originator mlo ON mlo.id = mlom.originator_id WHERE mlom.loan_id = t.loan_id) AS originator_external_ids + FROM m_loan_transaction t + JOIN m_loan m ON m.id = t.loan_id + JOIN m_product_loan l ON l.id = m.product_id + LEFT JOIN m_payment_detail d ON d.id = t.payment_detail_id + LEFT JOIN m_external_asset_owner_transfer e + ON e.loan_id = t.loan_id AND e.settlement_date < '${endDate}' AND + e.effective_date_to >= '${endDate}' + WHERE t.reversed_on_date = '${endDate}' + AND t.transaction_type_enum = 26 + AND (t.office_id = ${officeId})), + slt_cap_income_amortization AS (SELECT '${endDate}' AS transactiondate, + t.id, + l.name, + t.transaction_type_enum, + d.payment_type_id, + CASE + WHEN d.payment_type_id IS NULL AND bt.classification_cv_id IS NOT NULL + THEN (SELECT code_value FROM m_code_value WHERE id = bt.classification_cv_id) + ELSE NULL END AS classification_name, + CASE + WHEN t.overpayment_portion_derived IS NOT NULL + THEN map.amount + ELSE NULL END AS overpayment_portion_derived, + CASE + WHEN t.principal_portion_derived IS NOT NULL + THEN map.amount + ELSE NULL END AS principal_portion_derived, + CASE + WHEN t.interest_portion_derived IS NOT NULL + THEN map.amount + ELSE NULL END AS interest_portion_derived, + CASE + WHEN t.fee_charges_portion_derived IS NOT NULL + THEN map.amount + ELSE NULL END AS fee_charges_portion_derived, + CASE + WHEN t.penalty_charges_portion_derived IS NOT NULL + THEN map.amount + ELSE NULL END AS penalty_charges_portion_derived, + map.amount, + e.status, + e.settlement_date, + e.owner_id, + m.charged_off_on_date, + t.transaction_date, + m.charge_off_reason_cv_id, + (SELECT GROUP_CONCAT(DISTINCT mlo.external_id ORDER BY mlo.external_id SEPARATOR ', ') FROM m_loan_originator_mapping mlom JOIN m_loan_originator mlo ON mlo.id = mlom.originator_id WHERE mlom.loan_id = t.loan_id) AS originator_external_ids + FROM m_loan_transaction t + JOIN m_loan m ON m.id = t.loan_id + JOIN m_product_loan l ON l.id = m.product_id + LEFT JOIN m_payment_detail d ON d.id = t.payment_detail_id + JOIN m_loan_amortization_allocation_mapping map + ON map.amortization_loan_transaction_id = t.id + JOIN m_loan_transaction bt ON bt.id = map.base_loan_transaction_id + LEFT JOIN m_external_asset_owner_transfer e ON e.loan_id = t.loan_id AND + e.settlement_date < + '${endDate}' AND + e.effective_date_to >= + '${endDate}' + WHERE t.submitted_on_date = '${endDate}' + AND t.is_reversed = false + AND t.transaction_type_enum IN (36, 39, 42, 43) + AND (t.office_id = ${officeId})), + rlt_cap_income_amortization AS (SELECT '${endDate}' AS transactiondate, + t.id, + l.name, + t.transaction_type_enum, + d.payment_type_id, + CASE + WHEN d.payment_type_id IS NULL AND bt.classification_cv_id IS NOT NULL + THEN (SELECT code_value FROM m_code_value WHERE id = bt.classification_cv_id) + ELSE NULL END AS classification_name, + CASE + WHEN t.overpayment_portion_derived IS NOT NULL + THEN map.amount + ELSE NULL END AS overpayment_portion_derived, + CASE + WHEN t.principal_portion_derived IS NOT NULL + THEN map.amount + ELSE NULL END AS principal_portion_derived, + CASE + WHEN t.interest_portion_derived IS NOT NULL + THEN map.amount + ELSE NULL END AS interest_portion_derived, + CASE + WHEN t.fee_charges_portion_derived IS NOT NULL + THEN map.amount + ELSE NULL END AS fee_charges_portion_derived, + CASE + WHEN t.penalty_charges_portion_derived IS NOT NULL + THEN map.amount + ELSE NULL END AS penalty_charges_portion_derived, + map.amount, + e.status, + e.settlement_date, + e.owner_id, + m.charged_off_on_date, + t.transaction_date, + m.charge_off_reason_cv_id, + (SELECT GROUP_CONCAT(DISTINCT mlo.external_id ORDER BY mlo.external_id SEPARATOR ', ') FROM m_loan_originator_mapping mlom JOIN m_loan_originator mlo ON mlo.id = mlom.originator_id WHERE mlom.loan_id = t.loan_id) AS originator_external_ids + FROM m_loan_transaction t + JOIN m_loan m ON m.id = t.loan_id + JOIN m_product_loan l ON l.id = m.product_id + LEFT JOIN m_payment_detail d ON d.id = t.payment_detail_id + JOIN m_loan_amortization_allocation_mapping map + ON map.amortization_loan_transaction_id = t.id + JOIN m_loan_transaction bt ON bt.id = map.base_loan_transaction_id + LEFT JOIN m_external_asset_owner_transfer e ON e.loan_id = t.loan_id AND + e.settlement_date < + '${endDate}' AND + e.effective_date_to >= + '${endDate}' + WHERE t.reversed_on_date = '${endDate}' + AND t.is_reversed = true + AND t.transaction_type_enum IN (36, 39, 42, 43) + AND (t.office_id = ${officeId})), + active_external_asset_owner_transfers AS (SELECT '${endDate}' AS transactiondate, + t.id, + p.name, + t.owner_id, + t.previous_owner_id, + dt.principal_outstanding_derived, + dt.interest_outstanding_derived, + dt.fee_charges_outstanding_derived, + dt.penalty_charges_outstanding_derived, + dt.total_overpaid_derived, + l.charged_off_on_date, + t.settlement_date, + l.charge_off_reason_cv_id, + (SELECT GROUP_CONCAT(DISTINCT mlo.external_id ORDER BY mlo.external_id SEPARATOR ', ') FROM m_loan_originator_mapping mlom JOIN m_loan_originator mlo ON mlo.id = mlom.originator_id WHERE mlom.loan_id = t.loan_id) AS originator_external_ids + FROM m_external_asset_owner_transfer t + JOIN m_loan l ON l.id = t.loan_id + JOIN m_client c ON c.id = l.client_id + JOIN m_product_loan p ON p.id = l.product_id + JOIN m_external_asset_owner_transfer_details dt + ON dt.asset_owner_transfer_id = t.id + WHERE t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') + AND c.office_id = ${officeId} + AND t.settlement_date = '${endDate}'), + buyback_external_asset_owner_transfers AS (SELECT '${endDate}' AS transactiondate, + t.id, + p.name, + dt.principal_outstanding_derived, + dt.interest_outstanding_derived, + dt.fee_charges_outstanding_derived, + dt.penalty_charges_outstanding_derived, + dt.total_overpaid_derived, + l.charged_off_on_date, + t.settlement_date, + l.charge_off_reason_cv_id, + t.owner_id, + (SELECT GROUP_CONCAT(DISTINCT mlo.external_id ORDER BY mlo.external_id SEPARATOR ', ') FROM m_loan_originator_mapping mlom JOIN m_loan_originator mlo ON mlo.id = mlom.originator_id WHERE mlom.loan_id = t.loan_id) AS originator_external_ids + FROM m_external_asset_owner_transfer t + JOIN m_loan l ON l.id = t.loan_id + JOIN m_client c ON c.id = l.client_id + JOIN m_product_loan p ON p.id = l.product_id + JOIN m_external_asset_owner_transfer_details dt + ON dt.asset_owner_transfer_id = t.id + WHERE t.status in ('BUYBACK', 'BUYBACK_INTERMEDIATE') + AND c.office_id = ${officeId} + AND t.settlement_date = '${endDate}') +SELECT '${endDate}' AS TransactionDate, + a.product AS Product, + CASE + WHEN a.transaction_type = 9999 THEN 'Asset Transfer' + WHEN a.transaction_type = 99999 THEN 'Asset Buyback' + ELSE (SELECT enum_message_property + FROM r_enum_value + WHERE enum_name = 'transaction_type_enum' + AND enum_id = a.transaction_type) END AS TransactionType_Name, + COALESCE((SELECT value FROM m_payment_type WHERE id = a.payment_type_id), + a.classification_name) AS PaymentType_Name, + a.chargetype AS chargetype, + a.reversal_indicator AS Reversed, + a.Allocation_Type AS Allocation_Type, + (SELECT code_value FROM m_code_value WHERE id = a.charge_off_reason_id) AS Chargeoff_ReasonCode, + CASE + WHEN a.transaction_type = 9999 THEN sum(a.amount) * + 1 + WHEN a.transaction_type = 99999 THEN sum(a.amount) * - 1 + WHEN a.transaction_type IN (2, 23, 21, 22, 24, 4, 5, 8, 6, 27, 9, 26, 28, 31, 33, 34, 37, 39, 41, 43) AND + a.reversal_indicator = false THEN sum(a.amount) * -1 + WHEN a.transaction_type IN (2, 23, 21, 22, 24, 4, 5, 8, 6, 27, 9, 26, 28, 31, 33, 34, 37, 39, 41, 43) AND + a.reversal_indicator = true THEN sum(a.amount) * + 1 + WHEN a.transaction_type IN (1, 10, 25, 20, 35, 36, 40, 42) AND a.reversal_indicator = false THEN sum(a.amount) * + 1 + WHEN a.transaction_type IN (1, 10, 25, 20, 35, 36, 40, 42) AND a.reversal_indicator = true + THEN sum(a.amount) * -1 END AS Transaction_Amount, + (SELECT external_id + FROM m_external_asset_owner + WHERE id = a.asset_owner_id) AS Asset_owner_id, + (SELECT external_id + FROM m_external_asset_owner + WHERE id = a.from_asset_owner_id) AS From_asset_owner_id, + a.originator_external_ids AS Originator_External_Ids +FROM (SELECT t.transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Principal' AS Allocation_Type, + CASE + WHEN t.transaction_type_enum in (1) THEN (CASE + WHEN t.amount is null THEN 0 + WHEN t.overpayment_portion_derived is null THEN t.amount + WHEN t.overpayment_portion_derived is not null + THEN t.amount - t.overpayment_portion_derived + ELSE t.amount END) + ELSE (CASE + WHEN t.principal_portion_derived is null THEN 0 + ELSE t.principal_portion_derived end) END amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM slt_except_charge_adj_and_accrual AS t + UNION ALL + SELECT t.transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Interest' AS Allocation_Type, + CASE WHEN t.interest_portion_derived is null THEN 0 ELSE t.interest_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM slt_except_charge_adj_and_accrual AS t + UNION ALL + SELECT t.transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Fees' AS Allocation_Type, + CASE WHEN t.fee_charges_portion_derived is null THEN 0 ELSE t.fee_charges_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM slt_except_charge_adj_and_accrual AS t + UNION ALL + SELECT t.transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Penalty' AS Allocation_Type, + CASE + WHEN t.penalty_charges_portion_derived is null THEN 0 + ELSE t.penalty_charges_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM slt_except_charge_adj_and_accrual AS t + UNION ALL + SELECT t.transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Unallocated Credit (UNC)' AS Allocation_Type, + CASE WHEN t.overpayment_portion_derived is null THEN 0 ELSE t.overpayment_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM slt_except_charge_adj_and_accrual AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Fees' AS Allocation_Type, + CASE WHEN t.fee_charges_portion_derived is null THEN 0 ELSE t.fee_charges_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.transaction_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM slt_cap_income_amortization AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Penalty' AS Allocation_Type, + CASE + WHEN t.penalty_charges_portion_derived is null THEN 0 + ELSE t.penalty_charges_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.transaction_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM slt_cap_income_amortization AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Interest' AS Allocation_Type, + CASE WHEN t.interest_portion_derived is null THEN 0 ELSE t.interest_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.transaction_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM slt_cap_income_amortization AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Principal' AS Allocation_Type, + CASE WHEN t.principal_portion_derived is null THEN 0 ELSE t.principal_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.transaction_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM slt_cap_income_amortization AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Unallocated Credit (UNC)' AS Allocation_Type, + CASE WHEN t.overpayment_portion_derived is null THEN 0 ELSE t.overpayment_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.transaction_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM slt_cap_income_amortization AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Fees' AS Allocation_Type, + CASE WHEN t.fee_charges_portion_derived is null THEN 0 ELSE t.fee_charges_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.transaction_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_cap_income_amortization AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Penalty' AS Allocation_Type, + CASE + WHEN t.penalty_charges_portion_derived is null THEN 0 + ELSE t.penalty_charges_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.transaction_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_cap_income_amortization AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Interest' AS Allocation_Type, + CASE WHEN t.interest_portion_derived is null THEN 0 ELSE t.interest_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.transaction_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_cap_income_amortization AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Principal' AS Allocation_Type, + CASE WHEN t.principal_portion_derived is null THEN 0 ELSE t.principal_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.transaction_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_cap_income_amortization AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Unallocated Credit (UNC)' AS Allocation_Type, + CASE WHEN t.overpayment_portion_derived is null THEN 0 ELSE t.overpayment_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.transaction_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_cap_income_amortization AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + l.name AS product, + t.transaction_type_enum AS transaction_type, + null AS payment_type_id, + null AS classification_name, + mc.name AS chargetype, + false AS reversal_indicator, + 'Fees' AS Allocation_Type, + CASE WHEN pd.amount is null THEN 0 ELSE pd.amount END AS amount, + CASE + WHEN e.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND e.settlement_date < '${endDate}' + THEN e.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (m.charged_off_on_date <= t.transaction_date) + THEN m.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + (SELECT GROUP_CONCAT(DISTINCT mlo.external_id ORDER BY mlo.external_id SEPARATOR ', ') FROM m_loan_originator_mapping mlom JOIN m_loan_originator mlo ON mlo.id = mlom.originator_id WHERE mlom.loan_id = t.loan_id) AS originator_external_ids + FROM m_loan_transaction t + JOIN m_loan m ON m.id = t.loan_id + JOIN m_product_loan l ON l.id = m.product_id + JOIN m_loan_charge_paid_by pd ON pd.loan_transaction_id = t.id + JOIN m_loan_charge c ON c.id = pd.loan_charge_id + JOIN m_charge mc ON mc.id = c.charge_id AND mc.is_penalty = false + LEFT JOIN m_external_asset_owner_transfer e + ON e.loan_id = t.loan_id AND e.settlement_date < '${endDate}' AND + e.effective_date_to >= '${endDate}' + WHERE t.submitted_on_date = '${endDate}' + AND t.transaction_type_enum = 10 + AND t.is_reversed = false + AND (t.office_id = ${officeId}) + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + l.name AS product, + t.transaction_type_enum AS transaction_type, + null AS payment_type_id, + null AS classification_name, + mc.name AS chargetype, + false AS reversal_indicator, + 'Penalty' AS Allocation_Type, + CASE WHEN pd.amount is null THEN 0 ELSE pd.amount END AS amount, + CASE + WHEN e.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND e.settlement_date < '${endDate}' + THEN e.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (m.charged_off_on_date <= t.transaction_date) + THEN m.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + (SELECT GROUP_CONCAT(DISTINCT mlo.external_id ORDER BY mlo.external_id SEPARATOR ', ') FROM m_loan_originator_mapping mlom JOIN m_loan_originator mlo ON mlo.id = mlom.originator_id WHERE mlom.loan_id = t.loan_id) AS originator_external_ids + FROM m_loan_transaction t + JOIN m_loan m ON m.id = t.loan_id + JOIN m_product_loan l ON l.id = m.product_id + JOIN m_loan_charge_paid_by pd ON pd.loan_transaction_id = t.id + JOIN m_loan_charge c ON c.id = pd.loan_charge_id + JOIN m_charge mc ON mc.id = c.charge_id AND mc.is_penalty = true + LEFT JOIN m_external_asset_owner_transfer e + ON e.loan_id = t.loan_id AND e.settlement_date < '${endDate}' AND + e.effective_date_to >= '${endDate}' + WHERE t.submitted_on_date = '${endDate}' + AND t.transaction_type_enum = 10 + AND t.is_reversed = false + AND (t.office_id = ${officeId}) + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + l.name AS product, + t.transaction_type_enum AS transaction_type, + null AS payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Interest' AS Allocation_Type, + CASE WHEN t.interest_portion_derived is null THEN 0 ELSE t.interest_portion_derived END AS amount, + CASE + WHEN e.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND e.settlement_date < '${endDate}' + THEN e.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (m.charged_off_on_date <= t.transaction_date) + THEN m.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + (SELECT GROUP_CONCAT(DISTINCT mlo.external_id ORDER BY mlo.external_id SEPARATOR ', ') FROM m_loan_originator_mapping mlom JOIN m_loan_originator mlo ON mlo.id = mlom.originator_id WHERE mlom.loan_id = t.loan_id) AS originator_external_ids + FROM m_loan_transaction t + JOIN m_loan m ON m.id = t.loan_id + JOIN m_product_loan l ON l.id = m.product_id + LEFT JOIN m_external_asset_owner_transfer e + ON e.loan_id = t.loan_id AND e.settlement_date < '${endDate}' AND + e.effective_date_to >= '${endDate}' + WHERE t.submitted_on_date = '${endDate}' + AND t.transaction_type_enum in (10, 34) + AND t.is_reversed = false + AND (t.office_id = ${officeId}) + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Fees' AS Allocation_Type, + CASE WHEN t.fee_charges_portion_derived is null THEN 0 ELSE t.fee_charges_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM slt_charge_adj AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Penalty' AS Allocation_Type, + CASE + WHEN t.penalty_charges_portion_derived is null THEN 0 + ELSE t.penalty_charges_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM slt_charge_adj AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Interest' AS Allocation_Type, + CASE WHEN t.interest_portion_derived is null THEN 0 ELSE t.interest_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM slt_charge_adj AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Principal' AS Allocation_Type, + CASE WHEN t.principal_portion_derived is null THEN 0 ELSE t.principal_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM slt_charge_adj AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Unallocated Credit (UNC)' AS Allocation_Type, + CASE WHEN t.overpayment_portion_derived is null THEN 0 ELSE t.overpayment_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM slt_charge_adj AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + true AS reversal_indicator, + 'Principal' AS Allocation_Type, + CASE + WHEN t.transaction_type_enum in (1) THEN (CASE + WHEN t.amount is null THEN 0 + WHEN t.overpayment_portion_derived is null THEN t.amount + WHEN t.overpayment_portion_derived is not null + THEN t.amount - t.overpayment_portion_derived + ELSE t.amount END) + ELSE (CASE + WHEN t.principal_portion_derived is null THEN 0 + ELSE t.principal_portion_derived end) END amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_except_charge_adj_and_accrual AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + true AS reversal_indicator, + 'Interest' AS Allocation_Type, + CASE WHEN t.interest_portion_derived is null THEN 0 ELSE t.interest_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_except_charge_adj_and_accrual AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + true AS reversal_indicator, + 'Fees' AS Allocation_Type, + CASE WHEN t.fee_charges_portion_derived is null THEN 0 ELSE t.fee_charges_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_except_charge_adj_and_accrual AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + true AS reversal_indicator, + 'Penalty' AS Allocation_Type, + CASE + WHEN t.penalty_charges_portion_derived is null THEN 0 + ELSE t.penalty_charges_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_except_charge_adj_and_accrual AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + t.classification_name, + '' AS chargetype, + true AS reversal_indicator, + 'Unallocated Credit (UNC)' AS Allocation_Type, + CASE WHEN t.overpayment_portion_derived is null THEN 0 ELSE t.overpayment_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_except_charge_adj_and_accrual AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + l.name AS product, + t.transaction_type_enum AS transaction_type, + null AS payment_type_id, + null AS classification_name, + mc.name AS chargetype, + true AS reversal_indicator, + 'Fees' AS Allocation_Type, + CASE WHEN pd.amount is null THEN 0 ELSE pd.amount END AS amount, + CASE + WHEN e.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND e.settlement_date < '${endDate}' + THEN e.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (m.charged_off_on_date <= t.transaction_date) + THEN m.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + (SELECT GROUP_CONCAT(DISTINCT mlo.external_id ORDER BY mlo.external_id SEPARATOR ', ') FROM m_loan_originator_mapping mlom JOIN m_loan_originator mlo ON mlo.id = mlom.originator_id WHERE mlom.loan_id = t.loan_id) AS originator_external_ids + FROM m_loan_transaction t + JOIN m_loan m ON m.id = t.loan_id + JOIN m_product_loan l ON l.id = m.product_id + JOIN m_loan_charge_paid_by pd ON pd.loan_transaction_id = t.id + JOIN m_loan_charge c ON c.id = pd.loan_charge_id + JOIN m_charge mc ON mc.id = c.charge_id AND mc.is_penalty = false + LEFT JOIN m_external_asset_owner_transfer e + ON e.loan_id = t.loan_id AND e.settlement_date < '${endDate}' AND + e.effective_date_to >= '${endDate}' + WHERE t.reversed_on_date = '${endDate}' + AND t.transaction_type_enum = 10 + AND t.is_reversed = true + AND (t.office_id = ${officeId}) + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + l.name AS product, + t.transaction_type_enum AS transaction_type, + null AS payment_type_id, + null AS classification_name, + mc.name AS chargetype, + true AS reversal_indicator, + 'Penalty' AS Allocation_Type, + CASE WHEN pd.amount is null THEN 0 ELSE pd.amount END AS amount, + CASE + WHEN e.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND e.settlement_date < '${endDate}' + THEN e.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (m.charged_off_on_date <= t.transaction_date) + THEN m.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + (SELECT GROUP_CONCAT(DISTINCT mlo.external_id ORDER BY mlo.external_id SEPARATOR ', ') FROM m_loan_originator_mapping mlom JOIN m_loan_originator mlo ON mlo.id = mlom.originator_id WHERE mlom.loan_id = t.loan_id) AS originator_external_ids + FROM m_loan_transaction t + JOIN m_loan m ON m.id = t.loan_id + JOIN m_product_loan l ON l.id = m.product_id + JOIN m_loan_charge_paid_by pd ON pd.loan_transaction_id = t.id + JOIN m_loan_charge c ON c.id = pd.loan_charge_id + JOIN m_charge mc ON mc.id = c.charge_id AND mc.is_penalty = true + LEFT JOIN m_external_asset_owner_transfer e + ON e.loan_id = t.loan_id AND e.settlement_date < '${endDate}' AND + e.effective_date_to >= '${endDate}' + WHERE t.reversed_on_date = '${endDate}' + AND t.transaction_type_enum = 10 + AND t.is_reversed = true + AND (t.office_id = ${officeId}) + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + l.name AS product, + t.transaction_type_enum AS transaction_type, + null AS payment_type_id, + null AS classification_name, + '' AS chargetype, + true AS reversal_indicator, + 'Interest' AS Allocation_Type, + CASE WHEN t.interest_portion_derived is null THEN 0 ELSE t.interest_portion_derived END AS amount, + CASE + WHEN e.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND e.settlement_date < '${endDate}' + THEN e.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (m.charged_off_on_date <= t.transaction_date) + THEN m.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + (SELECT GROUP_CONCAT(DISTINCT mlo.external_id ORDER BY mlo.external_id SEPARATOR ', ') FROM m_loan_originator_mapping mlom JOIN m_loan_originator mlo ON mlo.id = mlom.originator_id WHERE mlom.loan_id = t.loan_id) AS originator_external_ids + FROM m_loan_transaction t + JOIN m_loan m ON m.id = t.loan_id + JOIN m_product_loan l ON l.id = m.product_id + LEFT JOIN m_external_asset_owner_transfer e + ON e.loan_id = t.loan_id AND e.settlement_date < '${endDate}' AND + e.effective_date_to >= '${endDate}' + WHERE t.reversed_on_date = '${endDate}' + AND t.transaction_type_enum = 10 + AND t.is_reversed = true + AND (t.office_id = ${officeId}) + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + null AS classification_name, + '' AS chargetype, + true AS reversal_indicator, + 'Fees' AS Allocation_Type, + CASE WHEN t.fee_charges_portion_derived is null THEN 0 ELSE t.fee_charges_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_charge_adj AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + null AS classification_name, + '' AS chargetype, + true AS reversal_indicator, + 'Penalty' AS Allocation_Type, + CASE + WHEN t.penalty_charges_portion_derived is null THEN 0 + ELSE t.penalty_charges_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_charge_adj AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + null AS classification_name, + '' AS chargetype, + true AS reversal_indicator, + 'Interest' AS Allocation_Type, + CASE WHEN t.interest_portion_derived is null THEN 0 ELSE t.interest_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_charge_adj AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + null AS classification_name, + '' AS chargetype, + true AS reversal_indicator, + 'Principal' AS Allocation_Type, + CASE WHEN t.principal_portion_derived is null THEN 0 ELSE t.principal_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_charge_adj AS t + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + t.transaction_type_enum AS transaction_type, + t.payment_type_id, + null AS classification_name, + '' AS chargetype, + true AS reversal_indicator, + 'Unallocated Credit (UNC)' AS Allocation_Type, + CASE WHEN t.overpayment_portion_derived is null THEN 0 ELSE t.overpayment_portion_derived END AS amount, + CASE + WHEN t.status in ('ACTIVE', 'ACTIVE_INTERMEDIATE') AND t.settlement_date < '${endDate}' + THEN t.owner_id END AS asset_owner_id, + CASE + WHEN t.transaction_type_enum = 27 OR (t.charged_off_on_date <= t.transaction_date) + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + null AS from_asset_owner_id, + t.originator_external_ids + FROM rlt_charge_adj AS t + UNION ALL + SELECT t.transactiondate, + t.id, + t.name AS product, + 9999 AS transaction_type, + null AS payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Principal' AS Allocation_type, + t.principal_outstanding_derived AS amount, + t.owner_id AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.settlement_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + t.previous_owner_id AS from_asset_owner_id, + t.originator_external_ids + FROM active_external_asset_owner_transfers AS t + WHERE t.principal_outstanding_derived > 0 + UNION ALL + SELECT t.transactiondate, + t.id, + t.name AS product, + 9999 AS transaction_type, + null AS payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Interest' AS Allocation_type, + t.interest_outstanding_derived AS amount, + t.owner_id AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.settlement_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + t.previous_owner_id AS from_asset_owner_id, + t.originator_external_ids + FROM active_external_asset_owner_transfers AS t + WHERE t.interest_outstanding_derived > 0 + UNION ALL + SELECT t.transactiondate, + t.id, + t.name AS product, + 9999 AS transaction_type, + null AS payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Fees' AS Allocation_type, + t.fee_charges_outstanding_derived AS amount, + t.owner_id AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.settlement_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + t.previous_owner_id AS from_asset_owner_id, + t.originator_external_ids + FROM active_external_asset_owner_transfers AS t + WHERE t.fee_charges_outstanding_derived > 0 + UNION ALL + SELECT t.transactiondate, + t.id, + t.name AS product, + 9999 AS transaction_type, + null AS payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Penalty' AS Allocation_type, + t.penalty_charges_outstanding_derived AS amount, + t.owner_id AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.settlement_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + t.previous_owner_id AS from_asset_owner_id, + t.originator_external_ids + FROM active_external_asset_owner_transfers AS t + WHERE t.penalty_charges_outstanding_derived > 0 + UNION ALL + SELECT t.transactiondate, + t.id, + t.name AS product, + 9999 AS transaction_type, + null AS payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Unallocated Credit (UNC)' AS Allocation_type, + t.total_overpaid_derived AS amount, + t.owner_id AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.settlement_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + t.previous_owner_id AS from_asset_owner_id, + t.originator_external_ids + FROM active_external_asset_owner_transfers AS t + WHERE t.total_overpaid_derived > 0 + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + 99999 AS transaction_type, + null AS payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Principal' AS Allocation_type, + t.principal_outstanding_derived AS amount, + null AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.settlement_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + t.owner_id AS from_asset_owner_id, + t.originator_external_ids + FROM buyback_external_asset_owner_transfers AS t + WHERE t.principal_outstanding_derived > 0 + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + 99999 AS transaction_type, + null AS payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Interest' AS Allocation_type, + t.interest_outstanding_derived AS amount, + null AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.settlement_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + t.owner_id AS from_asset_owner_id, + t.originator_external_ids + FROM buyback_external_asset_owner_transfers AS t + WHERE t.interest_outstanding_derived > 0 + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + 99999 AS transaction_type, + null AS payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Fees' AS Allocation_type, + t.fee_charges_outstanding_derived AS amount, + null AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.settlement_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + t.owner_id AS from_asset_owner_id, + t.originator_external_ids + FROM buyback_external_asset_owner_transfers AS t + WHERE t.fee_charges_outstanding_derived > 0 + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + 99999 AS transaction_type, + null AS payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Penalty' AS Allocation_type, + t.penalty_charges_outstanding_derived AS amount, + null AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.settlement_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + t.owner_id AS from_asset_owner_id, + t.originator_external_ids + FROM buyback_external_asset_owner_transfers AS t + WHERE t.penalty_charges_outstanding_derived > 0 + UNION ALL + SELECT '${endDate}' AS transactiondate, + t.id, + t.name AS product, + 99999 AS transaction_type, + null AS payment_type_id, + null AS classification_name, + '' AS chargetype, + false AS reversal_indicator, + 'Unallocated Credit (UNC)' AS Allocation_type, + t.total_overpaid_derived * -1 AS amount, + null AS asset_owner_id, + CASE + WHEN t.charged_off_on_date <= t.settlement_date + THEN t.charge_off_reason_cv_id END AS charge_off_reason_id, + t.owner_id AS from_asset_owner_id, + t.originator_external_ids + FROM buyback_external_asset_owner_transfers AS t + WHERE t.total_overpaid_derived > 0) a +GROUP BY a.transactiondate, a.product, a.transaction_type, a.payment_type_id, a.classification_name, a.chargetype, + a.reversal_indicator, a.Allocation_Type, a.asset_owner_id, a.charge_off_reason_id, a.from_asset_owner_id, + a.originator_external_ids +ORDER BY 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 + ]]> + + report_name='Transaction Summary Report with Asset Owner' + + + + + + + + report_name='Transaction Summary Report' + + + diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/JournalEntryAggregationJobConfigurationTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/JournalEntryAggregationJobConfigurationTest.java index bc8311df0a2..edae43fdce7 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/JournalEntryAggregationJobConfigurationTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/JournalEntryAggregationJobConfigurationTest.java @@ -22,6 +22,7 @@ import static org.mockito.BDDMockito.given; import org.apache.fineract.infrastructure.core.config.FineractProperties; +import org.apache.fineract.infrastructure.core.service.database.DatabaseTypeResolver; import org.apache.fineract.infrastructure.core.service.migration.TenantDataSourceFactory; import org.apache.fineract.infrastructure.jobs.service.aggregationjob.listener.JournalEntryAggregationJobListener; import org.apache.fineract.infrastructure.jobs.service.aggregationjob.tasklet.JournalEntryAggregationTrackingTasklet; @@ -63,6 +64,9 @@ class JournalEntryAggregationJobConfigurationTest { @Mock private TenantDataSourceFactory tenantDataSourceFactory; + @Mock + private DatabaseTypeResolver databaseTypeResolver; + @Mock private FineractProperties fineractProperties; diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/JournalEntryAggregationJobReaderTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/JournalEntryAggregationJobReaderTest.java index 44ae7de1645..696badbfa10 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/JournalEntryAggregationJobReaderTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/JournalEntryAggregationJobReaderTest.java @@ -36,6 +36,7 @@ import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant; import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; +import org.apache.fineract.infrastructure.core.service.database.DatabaseTypeResolver; import org.apache.fineract.infrastructure.core.service.migration.TenantDataSourceFactory; import org.apache.fineract.infrastructure.jobs.service.aggregationjob.data.JournalEntryAggregationSummaryData; import org.junit.jupiter.api.AfterEach; @@ -60,6 +61,8 @@ public class JournalEntryAggregationJobReaderTest { @Mock private ExecutionContext executionContext; @Mock + private DatabaseTypeResolver databaseTypeResolver; + @Mock private HikariDataSource dataSource; @Mock private ResultSet resultSet; @@ -89,7 +92,7 @@ public void testRowMapping() throws Exception { setupResultSetMocks(); // Act - reader = new JournalEntryAggregationJobReader(tenantDataSourceFactory); + reader = new JournalEntryAggregationJobReader(tenantDataSourceFactory, databaseTypeResolver); JournalEntryAggregationSummaryData result = invokeMapRowMethod(resultSet, 1); // Assert @@ -101,6 +104,7 @@ public void testRowMapping() throws Exception { assertEquals("USD", result.getCurrencyCode(), "Currency code should match"); assertEquals(LocalDate.of(2023, 6, 15), result.getAggregatedOnDate(), "Aggregated date should match"); assertEquals(Long.valueOf(500L), result.getExternalOwnerId(), "Asset owner should match"); + assertEquals("originator1, originator2", result.getOriginatorExternalIds(), "Originator external IDs should match"); assertEquals(new BigDecimal("1000.00"), result.getDebitAmount(), "Debit amount should match"); assertEquals(Boolean.FALSE, result.getManualEntry(), "Manual entry should be false"); assertEquals(ThreadLocalContextUtil.getBusinessDate(), result.getSubmittedOnDate(), "Submitted on date should match business date"); @@ -112,11 +116,13 @@ public void testRowMappingWithNullAssetOwner() throws Exception { setupResultSetMocksWithNullOwner(); // Act - reader = new JournalEntryAggregationJobReader(tenantDataSourceFactory); + reader = new JournalEntryAggregationJobReader(tenantDataSourceFactory, databaseTypeResolver); JournalEntryAggregationSummaryData result = invokeMapRowMethod(resultSet, 1); // Assert assertEquals(Long.valueOf(0L), result.getExternalOwnerId(), "Asset owner should be 0 when null in resultset"); + assertEquals("", result.getOriginatorExternalIds(), + "Originator external IDs should default to empty string when null in resultset"); } private void setupResultSetMocks() throws SQLException { @@ -126,6 +132,7 @@ private void setupResultSetMocks() throws SQLException { when(resultSet.getDate("aggregatedOnDate")).thenReturn(Date.valueOf(LocalDate.of(2023,6,15))); when(resultSet.findColumn("externalOwner")).thenReturn(5); when(resultSet.getLong(5)).thenReturn(500L); + when(resultSet.getString("originatorExternalIds")).thenReturn("originator1, originator2"); when(resultSet.getLong("officeId")).thenReturn(1L); when(resultSet.getLong("entityTypeEnum")).thenReturn(1L); when(resultSet.getBigDecimal("debitAmount")).thenReturn(new BigDecimal("1000.00")); @@ -137,6 +144,7 @@ private void setupResultSetMocksWithNullOwner() throws SQLException { when(resultSet.getLong("productId")).thenReturn(100L); when(resultSet.getString("currencyCode")).thenReturn("USD"); when(resultSet.getDate("aggregatedOnDate")).thenReturn(Date.valueOf(LocalDate.of(2023,6,15))); + when(resultSet.getString("originatorExternalIds")).thenReturn(""); when(resultSet.getLong("officeId")).thenReturn(1L); when(resultSet.getLong("entityTypeEnum")).thenReturn(1L); when(resultSet.getBigDecimal("debitAmount")).thenReturn(new BigDecimal("1000.00")); diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/services/JournalEntryAggregationWriterServiceImplTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/services/JournalEntryAggregationWriterServiceImplTest.java index 5c046c0fbba..e1e9f3816ce 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/services/JournalEntryAggregationWriterServiceImplTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/jobs/service/aggregationjob/services/JournalEntryAggregationWriterServiceImplTest.java @@ -132,6 +132,7 @@ public void testInsertJournalEntrySummaryBatchWithAmounts() { when(summaryData.getAggregatedOnDate()).thenReturn(LocalDate.now(Clock.systemUTC())); when(summaryData.getDebitAmount()).thenReturn(debitAmount); when(summaryData.getCreditAmount()).thenReturn(creditAmount); + when(summaryData.getOriginatorExternalIds()).thenReturn("originator1, originator2"); when(summaryData.getJobExecutionId()).thenReturn(123L); List summariesList = List.of(summaryData); @@ -145,9 +146,11 @@ public void testInsertJournalEntrySummaryBatchWithAmounts() { return false; } JournalEntrySummary entity = (JournalEntrySummary) ((List) entities).getFirst(); - return entity.getDebitAmount().compareTo(debitAmount) == 0 && entity.getCreditAmount().compareTo(creditAmount) == 0; + return entity.getDebitAmount().compareTo(debitAmount) == 0 && entity.getCreditAmount().compareTo(creditAmount) == 0 + && "originator1, originator2".equals(entity.getOriginatorExternalIds()); })); verify(summaryData, times(1)).getDebitAmount(); verify(summaryData, times(1)).getCreditAmount(); + verify(summaryData, times(1)).getOriginatorExternalIds(); } }