Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d7d22382a5 | ||
|
|
7cdc25322e | ||
|
|
a4c3dbb6c4 | ||
|
|
dd8445de06 | ||
|
|
9345f2294c | ||
|
|
190cd92a85 | ||
|
|
81832b6bb7 | ||
|
|
0bd5296519 | ||
|
|
17e0dab435 | ||
|
|
67810bfaea |
@@ -0,0 +1,18 @@
|
|||||||
|
const https = require('https');
|
||||||
|
const agent = new https.Agent({ rejectUnauthorized: false });
|
||||||
|
|
||||||
|
fetch('https://localhost:8443/fineract-provider/api/v1/authentication?username=mifos&password=password&tenantIdentifier=default', {
|
||||||
|
method: 'POST',
|
||||||
|
agent: agent
|
||||||
|
}).then(res => res.json()).then(data => {
|
||||||
|
const token = data.base64EncodedAuthenticationKey;
|
||||||
|
return fetch('https://localhost:8443/fineract-provider/api/v1/clients/9/accounts?tenantIdentifier=default', {
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Basic ' + token,
|
||||||
|
'Fineract-Platform-TenantId': 'default'
|
||||||
|
},
|
||||||
|
agent: agent
|
||||||
|
});
|
||||||
|
}).then(res => res.json()).then(data => {
|
||||||
|
console.log(JSON.stringify(data, null, 2));
|
||||||
|
}).catch(console.error);
|
||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
package org.apache.fineract.portfolio.shareaccounts.api;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.ws.rs.Consumes;
|
||||||
|
import jakarta.ws.rs.GET;
|
||||||
|
import jakarta.ws.rs.Path;
|
||||||
|
import jakarta.ws.rs.Produces;
|
||||||
|
import jakarta.ws.rs.QueryParam;
|
||||||
|
import jakarta.ws.rs.core.MediaType;
|
||||||
|
import java.util.Collection;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||||
|
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountClientSummaryData;
|
||||||
|
import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountReadPlatformService;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Path("/v1/shareaccounts/summary")
|
||||||
|
@Component
|
||||||
|
@Tag(name = "Share Account Summary", description = "Provides a highly optimized summary of all share accounts linked with their respective clients.")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ShareAccountSummaryApiResource {
|
||||||
|
|
||||||
|
private final PlatformSecurityContext platformSecurityContext;
|
||||||
|
private final ShareAccountReadPlatformService shareAccountReadPlatformService;
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
|
@Produces({ MediaType.APPLICATION_JSON })
|
||||||
|
@Operation(summary = "List all share accounts with client details", description = "Retrieves all share accounts along with their associated client details in a single optimized query.\n\n"
|
||||||
|
+ "Example Requests:\n\n" + "shareaccounts/summary")
|
||||||
|
@ApiResponse(responseCode = "200", description = "OK")
|
||||||
|
public Collection<ShareAccountClientSummaryData> retrieveAllSummaries(@QueryParam("searchTerm") final String searchTerm) {
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
System.out.println("[TIMING] Start of retrieveAllSummaries (before auth)");
|
||||||
|
this.platformSecurityContext.authenticatedUser();
|
||||||
|
long afterAuth = System.currentTimeMillis();
|
||||||
|
System.out.println("[TIMING] Auth check: " + (afterAuth - start) + "ms");
|
||||||
|
Collection<ShareAccountClientSummaryData> result = this.shareAccountReadPlatformService.retrieveAllShareAccountClientSummaries(searchTerm);
|
||||||
|
long afterService = System.currentTimeMillis();
|
||||||
|
System.out.println("[TIMING] Service call total (including query): " + (afterService - afterAuth) + "ms");
|
||||||
|
System.out.println("[TIMING] Right before response returned: " + (System.currentTimeMillis() - start) + "ms total so far");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
package org.apache.fineract.portfolio.shareaccounts.data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||||
|
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountStatusEnumData;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class ShareAccountClientSummaryData implements Serializable {
|
||||||
|
|
||||||
|
private final Long id;
|
||||||
|
private final Long clientId;
|
||||||
|
private final String clientName;
|
||||||
|
private final Long officeId;
|
||||||
|
private final String officeName;
|
||||||
|
private final String accountNo;
|
||||||
|
private final Long productId;
|
||||||
|
private final String productName;
|
||||||
|
private final Long totalApprovedShares;
|
||||||
|
private final Long totalPendingForApprovalShares;
|
||||||
|
private final CurrencyData currency;
|
||||||
|
private final LocalDate activatedDate;
|
||||||
|
private final ShareAccountStatusEnumData status;
|
||||||
|
|
||||||
|
public ShareAccountClientSummaryData(final Long id, final Long clientId, final String clientName, final Long officeId, final String officeName, final String accountNo,
|
||||||
|
final Long productId, final String productName, final Long totalApprovedShares, final Long totalPendingForApprovalShares,
|
||||||
|
final CurrencyData currency, final LocalDate activatedDate, final ShareAccountStatusEnumData status) {
|
||||||
|
this.id = id;
|
||||||
|
this.clientId = clientId;
|
||||||
|
this.clientName = clientName;
|
||||||
|
this.officeId = officeId;
|
||||||
|
this.officeName = officeName;
|
||||||
|
this.accountNo = accountNo;
|
||||||
|
this.productId = productId;
|
||||||
|
this.productName = productName;
|
||||||
|
|
||||||
|
if (totalApprovedShares == null) {
|
||||||
|
this.totalApprovedShares = Long.valueOf(0);
|
||||||
|
} else {
|
||||||
|
this.totalApprovedShares = totalApprovedShares;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (totalPendingForApprovalShares == null) {
|
||||||
|
this.totalPendingForApprovalShares = Long.valueOf(0);
|
||||||
|
} else {
|
||||||
|
this.totalPendingForApprovalShares = totalPendingForApprovalShares;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.currency = currency;
|
||||||
|
this.activatedDate = activatedDate;
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
@@ -23,6 +23,7 @@ import java.util.Collection;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.apache.fineract.portfolio.accounts.service.AccountReadPlatformService;
|
import org.apache.fineract.portfolio.accounts.service.AccountReadPlatformService;
|
||||||
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountData;
|
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountData;
|
||||||
|
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountClientSummaryData;
|
||||||
|
|
||||||
public interface ShareAccountReadPlatformService extends AccountReadPlatformService {
|
public interface ShareAccountReadPlatformService extends AccountReadPlatformService {
|
||||||
|
|
||||||
@@ -38,5 +39,7 @@ public interface ShareAccountReadPlatformService extends AccountReadPlatformServ
|
|||||||
Collection<ShareAccountData> retrieveAllShareAccountDataForDividends(Long productId, boolean fetchInActiveAccounts,
|
Collection<ShareAccountData> retrieveAllShareAccountDataForDividends(Long productId, boolean fetchInActiveAccounts,
|
||||||
LocalDate startDate);
|
LocalDate startDate);
|
||||||
|
|
||||||
|
Collection<ShareAccountClientSummaryData> retrieveAllShareAccountClientSummaries(String searchTerm);
|
||||||
|
|
||||||
String retrieveAccountNumberByAccountId(Long accountId);
|
String retrieveAccountNumberByAccountId(Long accountId);
|
||||||
}
|
}
|
||||||
|
|||||||
+81
@@ -62,6 +62,7 @@ import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccountStatusType
|
|||||||
import org.apache.fineract.portfolio.shareproducts.data.ShareProductData;
|
import org.apache.fineract.portfolio.shareproducts.data.ShareProductData;
|
||||||
import org.apache.fineract.portfolio.shareproducts.data.ShareProductMarketPriceData;
|
import org.apache.fineract.portfolio.shareproducts.data.ShareProductMarketPriceData;
|
||||||
import org.apache.fineract.portfolio.shareproducts.service.ShareProductDropdownReadPlatformService;
|
import org.apache.fineract.portfolio.shareproducts.service.ShareProductDropdownReadPlatformService;
|
||||||
|
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountClientSummaryData;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.dao.EmptyResultDataAccessException;
|
import org.springframework.dao.EmptyResultDataAccessException;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
@@ -221,6 +222,29 @@ public class ShareAccountReadPlatformServiceImpl implements ShareAccountReadPlat
|
|||||||
}, mapper);
|
}, mapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<ShareAccountClientSummaryData> retrieveAllShareAccountClientSummaries(String searchTerm) {
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
System.out.println("[TIMING] Inside retrieveAllShareAccountClientSummaries, before query builder setup");
|
||||||
|
ShareAccountClientSummaryMapper mapper = new ShareAccountClientSummaryMapper();
|
||||||
|
StringBuilder queryBuilder = new StringBuilder("select ").append(mapper.schema());
|
||||||
|
List<Object> paramList = new ArrayList<>();
|
||||||
|
|
||||||
|
if (searchTerm != null && !searchTerm.trim().isEmpty()) {
|
||||||
|
queryBuilder.append(" where (c.display_name ILIKE ? OR sa.account_no ILIKE ?)");
|
||||||
|
String searchPattern = "%" + searchTerm + "%";
|
||||||
|
paramList.add(searchPattern);
|
||||||
|
paramList.add(searchPattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
long beforeQuery = System.currentTimeMillis();
|
||||||
|
System.out.println("[TIMING] Before actual SQL query call. Time since service start: " + (beforeQuery - start) + "ms");
|
||||||
|
Collection<ShareAccountClientSummaryData> result = this.jdbcTemplate.query(queryBuilder.toString(), mapper, paramList.toArray());
|
||||||
|
long afterQuery = System.currentTimeMillis();
|
||||||
|
System.out.println("[TIMING] Query execution (JdbcTemplate): " + (afterQuery - beforeQuery) + "ms");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public Collection<ShareAccountChargeData> convertChargesToShareAccountCharges(Collection<ChargeData> productCharges) {
|
public Collection<ShareAccountChargeData> convertChargesToShareAccountCharges(Collection<ChargeData> productCharges) {
|
||||||
final Collection<ShareAccountChargeData> savingsCharges = new ArrayList<>();
|
final Collection<ShareAccountChargeData> savingsCharges = new ArrayList<>();
|
||||||
for (final ChargeData chargeData : productCharges) {
|
for (final ChargeData chargeData : productCharges) {
|
||||||
@@ -495,6 +519,63 @@ public class ShareAccountReadPlatformServiceImpl implements ShareAccountReadPlat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final class ShareAccountClientSummaryMapper implements RowMapper<ShareAccountClientSummaryData> {
|
||||||
|
|
||||||
|
private final String schema;
|
||||||
|
|
||||||
|
ShareAccountClientSummaryMapper() {
|
||||||
|
StringBuilder buff = new StringBuilder().append("sa.id as id, c.id as clientId, c.display_name as clientName, ")
|
||||||
|
.append("sa.account_no as accountNo, p.id as productId, p.name as productName, ")
|
||||||
|
.append("sa.total_approved_shares as approvedShares, sa.total_pending_shares as pendingShares, ")
|
||||||
|
.append("sa.currency_code as currencyCode, sa.currency_digits as currencyDigits, sa.currency_multiplesof as inMultiplesOf, ")
|
||||||
|
.append("curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, ")
|
||||||
|
.append("curr.display_symbol as currencyDisplaySymbol, sa.activated_date as activatedDate, ")
|
||||||
|
.append("sa.status_enum as statusEnum, o.id as officeId, o.name as officeName ")
|
||||||
|
.append("from m_share_account sa ")
|
||||||
|
.append("inner join m_client c ON c.id = sa.client_id ")
|
||||||
|
.append("inner join m_office o ON o.id = c.office_id ")
|
||||||
|
.append("inner join m_share_product p on p.id = sa.product_id ")
|
||||||
|
.append("inner join m_currency curr on curr.code = sa.currency_code");
|
||||||
|
this.schema = buff.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ShareAccountClientSummaryData mapRow(ResultSet rs, @SuppressWarnings("unused") int rowNum) throws SQLException {
|
||||||
|
final Long id = rs.getLong("id");
|
||||||
|
final Long clientId = rs.getLong("clientId");
|
||||||
|
final String clientName = rs.getString("clientName");
|
||||||
|
final String accountNo = rs.getString("accountNo");
|
||||||
|
final Long productId = rs.getLong("productId");
|
||||||
|
final String productName = rs.getString("productName");
|
||||||
|
final Long totalApprovedShares = JdbcSupport.getLong(rs, "approvedShares");
|
||||||
|
final Long totalPendingForApprovalShares = JdbcSupport.getLong(rs, "pendingShares");
|
||||||
|
|
||||||
|
final String currencyCode = rs.getString("currencyCode");
|
||||||
|
final String currencyName = rs.getString("currencyName");
|
||||||
|
final String currencyNameCode = rs.getString("currencyNameCode");
|
||||||
|
final String currencyDisplaySymbol = rs.getString("currencyDisplaySymbol");
|
||||||
|
final Integer currencyDigits = JdbcSupport.getInteger(rs, "currencyDigits");
|
||||||
|
final Integer inMultiplesOf = JdbcSupport.getInteger(rs, "inMultiplesOf");
|
||||||
|
final CurrencyData currency = new CurrencyData(currencyCode, currencyName, currencyDigits, inMultiplesOf,
|
||||||
|
currencyDisplaySymbol, currencyNameCode);
|
||||||
|
|
||||||
|
final LocalDate activatedDate = JdbcSupport.getLocalDate(rs, "activatedDate");
|
||||||
|
|
||||||
|
final Integer statusEnum = rs.getInt("statusEnum");
|
||||||
|
final ShareAccountStatusEnumData status = SharesEnumerations.status(statusEnum);
|
||||||
|
|
||||||
|
final Long officeId = rs.getLong("officeId");
|
||||||
|
final String officeName = rs.getString("officeName");
|
||||||
|
|
||||||
|
return new ShareAccountClientSummaryData(id, clientId, clientName, officeId, officeName, accountNo, productId, productName,
|
||||||
|
totalApprovedShares, totalPendingForApprovalShares, currency, activatedDate, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String schema() {
|
||||||
|
return this.schema;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String retrieveAccountNumberByAccountId(Long accountId) {
|
public String retrieveAccountNumberByAccountId(Long accountId) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
+73
@@ -0,0 +1,73 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.welcomekit.api;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.ws.rs.Consumes;
|
||||||
|
import jakarta.ws.rs.GET;
|
||||||
|
import jakarta.ws.rs.POST;
|
||||||
|
import jakarta.ws.rs.Path;
|
||||||
|
import jakarta.ws.rs.PathParam;
|
||||||
|
import jakarta.ws.rs.Produces;
|
||||||
|
import jakarta.ws.rs.core.MediaType;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
|
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||||
|
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||||
|
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||||
|
import org.apache.fineract.portfolio.welcomekit.data.ClientWelcomeKitData;
|
||||||
|
import org.apache.fineract.portfolio.welcomekit.service.WelcomeKitReadPlatformService;
|
||||||
|
import org.apache.fineract.portfolio.welcomekit.service.WelcomeKitWritePlatformService;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Path("/v1/clients/{clientId}/welcomekit")
|
||||||
|
@Component
|
||||||
|
@Tag(name = "Welcome Kit Dispatch", description = "Manages the dispatching and tracking of welcome kits for clients.")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ClientWelcomeKitApiResource {
|
||||||
|
|
||||||
|
private static final String RESOURCE_NAME_FOR_PERMISSIONS = "WELCOMEKIT";
|
||||||
|
private final PlatformSecurityContext context;
|
||||||
|
private final WelcomeKitReadPlatformService readPlatformService;
|
||||||
|
private final WelcomeKitWritePlatformService writePlatformService;
|
||||||
|
private final FromJsonHelper fromJsonHelper;
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Produces({ MediaType.APPLICATION_JSON })
|
||||||
|
@Operation(summary = "List all welcome kits for a Client")
|
||||||
|
public ClientWelcomeKitData getClientWelcomeKits(@PathParam("clientId") @Parameter(description = "clientId") final Long clientId) {
|
||||||
|
this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
|
||||||
|
return this.readPlatformService.retrieveWelcomeKitsByClientId(clientId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
|
@Produces({ MediaType.APPLICATION_JSON })
|
||||||
|
@Operation(summary = "Create a new welcome kit dispatch")
|
||||||
|
public CommandProcessingResult dispatchWelcomeKit(@PathParam("clientId") @Parameter(description = "clientId") final Long clientId,
|
||||||
|
@Parameter(hidden = true) final String apiRequestBodyAsJson) {
|
||||||
|
this.context.authenticatedUser().validateHasPermissionTo("CREATE_" + RESOURCE_NAME_FOR_PERMISSIONS);
|
||||||
|
|
||||||
|
final JsonCommand command = JsonCommand.fromJsonElement(clientId, this.fromJsonHelper.parse(apiRequestBodyAsJson), this.fromJsonHelper);
|
||||||
|
|
||||||
|
return this.writePlatformService.dispatchWelcomeKit(clientId, command);
|
||||||
|
}
|
||||||
|
}
|
||||||
+67
@@ -0,0 +1,67 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.welcomekit.api;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.ws.rs.Consumes;
|
||||||
|
import jakarta.ws.rs.GET;
|
||||||
|
import jakarta.ws.rs.POST;
|
||||||
|
import jakarta.ws.rs.PUT;
|
||||||
|
import jakarta.ws.rs.Path;
|
||||||
|
import jakarta.ws.rs.PathParam;
|
||||||
|
import jakarta.ws.rs.Produces;
|
||||||
|
import jakarta.ws.rs.core.MediaType;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
|
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||||
|
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||||
|
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||||
|
import org.apache.fineract.portfolio.welcomekit.data.ClientWelcomeKitData;
|
||||||
|
import org.apache.fineract.portfolio.welcomekit.service.WelcomeKitReadPlatformService;
|
||||||
|
import org.apache.fineract.portfolio.welcomekit.service.WelcomeKitWritePlatformService;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Path("/v1/welcomekit")
|
||||||
|
@Component
|
||||||
|
@Tag(name = "Welcome Kit Dispatch", description = "Manages the dispatching and tracking of welcome kits for clients.")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class WelcomeKitApiResource {
|
||||||
|
|
||||||
|
private static final String RESOURCE_NAME_FOR_PERMISSIONS = "WELCOMEKIT";
|
||||||
|
private final PlatformSecurityContext context;
|
||||||
|
private final WelcomeKitWritePlatformService writePlatformService;
|
||||||
|
private final FromJsonHelper fromJsonHelper;
|
||||||
|
|
||||||
|
@PUT
|
||||||
|
@Path("{welcomeKitId}")
|
||||||
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
|
@Produces({ MediaType.APPLICATION_JSON })
|
||||||
|
@Operation(summary = "Update the status of an existing dispatch")
|
||||||
|
public CommandProcessingResult updateWelcomeKitStatus(
|
||||||
|
@PathParam("welcomeKitId") @Parameter(description = "welcomeKitId") final Long welcomeKitId,
|
||||||
|
@Parameter(hidden = true) final String apiRequestBodyAsJson) {
|
||||||
|
this.context.authenticatedUser().validateHasPermissionTo("UPDATE_" + RESOURCE_NAME_FOR_PERMISSIONS);
|
||||||
|
|
||||||
|
final JsonCommand command = JsonCommand.fromJsonElement(welcomeKitId, this.fromJsonHelper.parse(apiRequestBodyAsJson), this.fromJsonHelper);
|
||||||
|
|
||||||
|
return this.writePlatformService.updateWelcomeKitStatus(welcomeKitId, command);
|
||||||
|
}
|
||||||
|
}
|
||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.welcomekit.data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public class ClientWelcomeKitData implements Serializable {
|
||||||
|
|
||||||
|
private final String clientName;
|
||||||
|
private final boolean canDispatchNew;
|
||||||
|
private final List<WelcomeKitDispatchData> dispatches;
|
||||||
|
}
|
||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.welcomekit.data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public class WelcomeKitDispatchData implements Serializable {
|
||||||
|
|
||||||
|
private final Long id;
|
||||||
|
private final Long clientId;
|
||||||
|
private final String clientName;
|
||||||
|
private final String deliveryAddress;
|
||||||
|
private final String deliveryMode;
|
||||||
|
private final String deliveryModeOtherText;
|
||||||
|
private final String trackingId;
|
||||||
|
private final String status;
|
||||||
|
private final LocalDate dispatchedOnDate;
|
||||||
|
private final LocalDate deliveredOnDate;
|
||||||
|
}
|
||||||
+118
@@ -0,0 +1,118 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.welcomekit.domain;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.EntityListeners;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||||
|
import org.apache.fineract.portfolio.client.domain.Client;
|
||||||
|
import org.springframework.data.annotation.CreatedBy;
|
||||||
|
import org.springframework.data.annotation.CreatedDate;
|
||||||
|
import org.springframework.data.annotation.LastModifiedBy;
|
||||||
|
import org.springframework.data.annotation.LastModifiedDate;
|
||||||
|
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "m_welcome_kit_dispatch")
|
||||||
|
@EntityListeners(AuditingEntityListener.class)
|
||||||
|
public class WelcomeKitDispatch extends AbstractPersistableCustom<Long> {
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "client_id", nullable = false)
|
||||||
|
private Client client;
|
||||||
|
|
||||||
|
@Column(name = "delivery_address", length = 500, nullable = false)
|
||||||
|
private String deliveryAddress;
|
||||||
|
|
||||||
|
@Column(name = "delivery_mode", length = 50, nullable = false)
|
||||||
|
private String deliveryMode;
|
||||||
|
|
||||||
|
@Column(name = "delivery_mode_other_text", length = 255)
|
||||||
|
private String deliveryModeOtherText;
|
||||||
|
|
||||||
|
@Column(name = "tracking_id", length = 100, nullable = false, unique = true)
|
||||||
|
private String trackingId;
|
||||||
|
|
||||||
|
@Column(name = "status", length = 30, nullable = false)
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
@Column(name = "dispatched_on_date", nullable = false)
|
||||||
|
private LocalDate dispatchedOnDate;
|
||||||
|
|
||||||
|
@Column(name = "delivered_on_date")
|
||||||
|
private LocalDate deliveredOnDate;
|
||||||
|
|
||||||
|
@CreatedBy
|
||||||
|
@Column(name = "created_by", updatable = false)
|
||||||
|
private Long createdBy;
|
||||||
|
|
||||||
|
@CreatedDate
|
||||||
|
@Column(name = "created_date", updatable = false)
|
||||||
|
private LocalDateTime createdDate;
|
||||||
|
|
||||||
|
@LastModifiedBy
|
||||||
|
@Column(name = "last_modified_by")
|
||||||
|
private Long lastModifiedBy;
|
||||||
|
|
||||||
|
@LastModifiedDate
|
||||||
|
@Column(name = "last_modified_date")
|
||||||
|
private LocalDateTime lastModifiedDate;
|
||||||
|
|
||||||
|
protected WelcomeKitDispatch() {
|
||||||
|
// Default constructor for JPA
|
||||||
|
}
|
||||||
|
|
||||||
|
private WelcomeKitDispatch(final Client client, final String deliveryAddress, final String deliveryMode,
|
||||||
|
final String deliveryModeOtherText, final String trackingId, final String status,
|
||||||
|
final LocalDate dispatchedOnDate) {
|
||||||
|
this.client = client;
|
||||||
|
this.deliveryAddress = deliveryAddress;
|
||||||
|
this.deliveryMode = deliveryMode;
|
||||||
|
this.deliveryModeOtherText = deliveryModeOtherText;
|
||||||
|
this.trackingId = trackingId;
|
||||||
|
this.status = status;
|
||||||
|
this.dispatchedOnDate = dispatchedOnDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WelcomeKitDispatch createNew(final Client client, final String deliveryAddress, final String deliveryMode,
|
||||||
|
final String deliveryModeOtherText, final String trackingId, final LocalDate dispatchedOnDate) {
|
||||||
|
return new WelcomeKitDispatch(client, deliveryAddress, deliveryMode, deliveryModeOtherText, trackingId, "DISPATCHED", dispatchedOnDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Client getClient() {
|
||||||
|
return this.client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStatus() {
|
||||||
|
return this.status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateStatus(final String newStatus, final LocalDate deliveredOnDate) {
|
||||||
|
this.status = newStatus;
|
||||||
|
if ("DELIVERED".equals(newStatus)) {
|
||||||
|
this.deliveredOnDate = deliveredOnDate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.welcomekit.domain;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
|
||||||
|
public interface WelcomeKitDispatchRepository extends JpaRepository<WelcomeKitDispatch, Long>, JpaSpecificationExecutor<WelcomeKitDispatch> {
|
||||||
|
|
||||||
|
List<WelcomeKitDispatch> findByClientIdOrderByCreatedDateDesc(Long clientId);
|
||||||
|
}
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.welcomekit.service;
|
||||||
|
|
||||||
|
import org.apache.fineract.portfolio.welcomekit.data.ClientWelcomeKitData;
|
||||||
|
|
||||||
|
public interface WelcomeKitReadPlatformService {
|
||||||
|
|
||||||
|
ClientWelcomeKitData retrieveWelcomeKitsByClientId(Long clientId);
|
||||||
|
}
|
||||||
+103
@@ -0,0 +1,103 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.welcomekit.service;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
|
||||||
|
import org.apache.fineract.portfolio.welcomekit.data.ClientWelcomeKitData;
|
||||||
|
import org.apache.fineract.portfolio.welcomekit.data.WelcomeKitDispatchData;
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
import org.springframework.jdbc.core.RowMapper;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class WelcomeKitReadPlatformServiceImpl implements WelcomeKitReadPlatformService {
|
||||||
|
|
||||||
|
private final JdbcTemplate jdbcTemplate;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientWelcomeKitData retrieveWelcomeKitsByClientId(Long clientId) {
|
||||||
|
final WelcomeKitDispatchMapper rm = new WelcomeKitDispatchMapper();
|
||||||
|
final String sql = "SELECT " + rm.schema() + " WHERE w.client_id = ? ORDER BY w.created_date DESC";
|
||||||
|
|
||||||
|
List<WelcomeKitDispatchData> dispatches = this.jdbcTemplate.query(sql, rm, clientId);
|
||||||
|
|
||||||
|
String clientName = this.jdbcTemplate.queryForObject("SELECT display_name FROM m_client WHERE id = ?", String.class, clientId);
|
||||||
|
|
||||||
|
boolean canDispatchNew = true;
|
||||||
|
if (!dispatches.isEmpty()) {
|
||||||
|
WelcomeKitDispatchData latest = dispatches.get(0);
|
||||||
|
if ("RETURNED".equals(latest.getStatus())) {
|
||||||
|
canDispatchNew = true;
|
||||||
|
} else {
|
||||||
|
canDispatchNew = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ClientWelcomeKitData.builder()
|
||||||
|
.clientName(clientName)
|
||||||
|
.canDispatchNew(canDispatchNew)
|
||||||
|
.dispatches(dispatches)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class WelcomeKitDispatchMapper implements RowMapper<WelcomeKitDispatchData> {
|
||||||
|
|
||||||
|
public String schema() {
|
||||||
|
return " w.id as id, w.client_id as clientId, c.display_name as clientName, "
|
||||||
|
+ " w.delivery_address as deliveryAddress, w.delivery_mode as deliveryMode, "
|
||||||
|
+ " w.delivery_mode_other_text as deliveryModeOtherText, w.tracking_id as trackingId, "
|
||||||
|
+ " w.status as status, w.dispatched_on_date as dispatchedOnDate, w.delivered_on_date as deliveredOnDate "
|
||||||
|
+ " FROM m_welcome_kit_dispatch w "
|
||||||
|
+ " JOIN m_client c ON c.id = w.client_id ";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WelcomeKitDispatchData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||||
|
final Long id = rs.getLong("id");
|
||||||
|
final Long clientId = rs.getLong("clientId");
|
||||||
|
final String clientName = rs.getString("clientName");
|
||||||
|
final String deliveryAddress = rs.getString("deliveryAddress");
|
||||||
|
final String deliveryMode = rs.getString("deliveryMode");
|
||||||
|
final String deliveryModeOtherText = rs.getString("deliveryModeOtherText");
|
||||||
|
final String trackingId = rs.getString("trackingId");
|
||||||
|
final String status = rs.getString("status");
|
||||||
|
final LocalDate dispatchedOnDate = JdbcSupport.getLocalDate(rs, "dispatchedOnDate");
|
||||||
|
final LocalDate deliveredOnDate = JdbcSupport.getLocalDate(rs, "deliveredOnDate");
|
||||||
|
|
||||||
|
return WelcomeKitDispatchData.builder()
|
||||||
|
.id(id)
|
||||||
|
.clientId(clientId)
|
||||||
|
.clientName(clientName)
|
||||||
|
.deliveryAddress(deliveryAddress)
|
||||||
|
.deliveryMode(deliveryMode)
|
||||||
|
.deliveryModeOtherText(deliveryModeOtherText)
|
||||||
|
.trackingId(trackingId)
|
||||||
|
.status(status)
|
||||||
|
.dispatchedOnDate(dispatchedOnDate)
|
||||||
|
.deliveredOnDate(deliveredOnDate)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.welcomekit.service;
|
||||||
|
|
||||||
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
|
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||||
|
|
||||||
|
public interface WelcomeKitWritePlatformService {
|
||||||
|
|
||||||
|
CommandProcessingResult dispatchWelcomeKit(Long clientId, JsonCommand command);
|
||||||
|
|
||||||
|
CommandProcessingResult updateWelcomeKitStatus(Long welcomeKitId, JsonCommand command);
|
||||||
|
}
|
||||||
+112
@@ -0,0 +1,112 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.welcomekit.service;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.UUID;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
|
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||||
|
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||||
|
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||||
|
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||||
|
import org.apache.fineract.portfolio.client.domain.Client;
|
||||||
|
import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
|
||||||
|
import org.apache.fineract.portfolio.welcomekit.domain.WelcomeKitDispatch;
|
||||||
|
import org.apache.fineract.portfolio.welcomekit.domain.WelcomeKitDispatchRepository;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class WelcomeKitWritePlatformServiceImpl implements WelcomeKitWritePlatformService {
|
||||||
|
|
||||||
|
private final PlatformSecurityContext context;
|
||||||
|
private final ClientRepositoryWrapper clientRepository;
|
||||||
|
private final WelcomeKitDispatchRepository welcomeKitDispatchRepository;
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@Override
|
||||||
|
public CommandProcessingResult dispatchWelcomeKit(final Long clientId, final JsonCommand command) {
|
||||||
|
this.context.authenticatedUser();
|
||||||
|
|
||||||
|
final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId);
|
||||||
|
|
||||||
|
final String deliveryAddress = command.stringValueOfParameterNamed("deliveryAddress");
|
||||||
|
final String deliveryMode = command.stringValueOfParameterNamed("deliveryMode");
|
||||||
|
final String deliveryModeOtherText = command.stringValueOfParameterNamed("deliveryModeOtherText");
|
||||||
|
final LocalDate dispatchedOnDate = command.localDateValueOfParameterNamed("dispatchedOnDate");
|
||||||
|
|
||||||
|
if (deliveryAddress == null || deliveryAddress.trim().isEmpty()) {
|
||||||
|
throw new PlatformDataIntegrityException("error.msg.welcomekit.deliveryAddress.cannot.be.blank",
|
||||||
|
"Delivery address cannot be blank.");
|
||||||
|
}
|
||||||
|
if (deliveryMode == null || deliveryMode.trim().isEmpty()) {
|
||||||
|
throw new PlatformDataIntegrityException("error.msg.welcomekit.deliveryMode.cannot.be.blank",
|
||||||
|
"Delivery mode cannot be blank.");
|
||||||
|
}
|
||||||
|
if (dispatchedOnDate == null) {
|
||||||
|
throw new PlatformDataIntegrityException("error.msg.welcomekit.dispatchedOnDate.cannot.be.blank",
|
||||||
|
"Dispatched on date cannot be blank.");
|
||||||
|
}
|
||||||
|
|
||||||
|
final String trackingId = "WK-" + UUID.randomUUID().toString().substring(0, 8).toUpperCase();
|
||||||
|
|
||||||
|
final WelcomeKitDispatch newDispatch = WelcomeKitDispatch.createNew(client, deliveryAddress, deliveryMode, deliveryModeOtherText,
|
||||||
|
trackingId, dispatchedOnDate);
|
||||||
|
|
||||||
|
this.welcomeKitDispatchRepository.saveAndFlush(newDispatch);
|
||||||
|
|
||||||
|
return new CommandProcessingResultBuilder()
|
||||||
|
.withCommandId(command.commandId())
|
||||||
|
.withClientId(clientId)
|
||||||
|
.withEntityId(newDispatch.getId())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@Override
|
||||||
|
public CommandProcessingResult updateWelcomeKitStatus(final Long welcomeKitId, final JsonCommand command) {
|
||||||
|
this.context.authenticatedUser();
|
||||||
|
|
||||||
|
final WelcomeKitDispatch dispatch = this.welcomeKitDispatchRepository.findById(welcomeKitId).orElseThrow(
|
||||||
|
() -> new PlatformDataIntegrityException("error.msg.welcomekit.not.found", "Welcome kit not found."));
|
||||||
|
|
||||||
|
final String status = command.stringValueOfParameterNamed("status");
|
||||||
|
|
||||||
|
if (status == null || status.trim().isEmpty()) {
|
||||||
|
throw new PlatformDataIntegrityException("error.msg.welcomekit.status.cannot.be.blank", "Status cannot be blank.");
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalDate deliveredOnDate = null;
|
||||||
|
if ("DELIVERED".equals(status)) {
|
||||||
|
deliveredOnDate = LocalDate.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch.updateStatus(status, deliveredOnDate);
|
||||||
|
|
||||||
|
this.welcomeKitDispatchRepository.saveAndFlush(dispatch);
|
||||||
|
|
||||||
|
return new CommandProcessingResultBuilder()
|
||||||
|
.withCommandId(command.commandId())
|
||||||
|
.withClientId(dispatch.getClient().getId())
|
||||||
|
.withEntityId(dispatch.getId())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -46,7 +46,7 @@ fineract.security.oauth2.client.registrations.frontend-client.require-authorizat
|
|||||||
fineract.tenant.host=${FINERACT_DEFAULT_TENANTDB_HOSTNAME:localhost}
|
fineract.tenant.host=${FINERACT_DEFAULT_TENANTDB_HOSTNAME:localhost}
|
||||||
fineract.tenant.port=${FINERACT_DEFAULT_TENANTDB_PORT:5432}
|
fineract.tenant.port=${FINERACT_DEFAULT_TENANTDB_PORT:5432}
|
||||||
fineract.tenant.username=${FINERACT_DEFAULT_TENANTDB_UID:postgres}
|
fineract.tenant.username=${FINERACT_DEFAULT_TENANTDB_UID:postgres}
|
||||||
fineract.tenant.password=${FINERACT_DEFAULT_TENANTDB_PWD:Keshav@898966}
|
fineract.tenant.password=${FINERACT_DEFAULT_TENANTDB_PWD:313863}
|
||||||
fineract.tenant.parameters=${FINERACT_DEFAULT_TENANTDB_CONN_PARAMS:}
|
fineract.tenant.parameters=${FINERACT_DEFAULT_TENANTDB_CONN_PARAMS:}
|
||||||
fineract.tenant.timezone=${FINERACT_DEFAULT_TENANTDB_TIMEZONE:Asia/Kolkata}
|
fineract.tenant.timezone=${FINERACT_DEFAULT_TENANTDB_TIMEZONE:Asia/Kolkata}
|
||||||
fineract.tenant.identifier=${FINERACT_DEFAULT_TENANTDB_IDENTIFIER:default}
|
fineract.tenant.identifier=${FINERACT_DEFAULT_TENANTDB_IDENTIFIER:default}
|
||||||
@@ -407,7 +407,7 @@ server.tomcat.mbeanregistry.enabled=${FINERACT_SERVER_TOMCAT_MBEANREGISTRY_ENABL
|
|||||||
spring.datasource.hikari.driverClassName=${FINERACT_HIKARI_DRIVER_SOURCE_CLASS_NAME:org.postgresql.Driver}
|
spring.datasource.hikari.driverClassName=${FINERACT_HIKARI_DRIVER_SOURCE_CLASS_NAME:org.postgresql.Driver}
|
||||||
spring.datasource.hikari.jdbcUrl=${FINERACT_HIKARI_JDBC_URL:jdbc:postgresql://localhost:5432/fineract_tenants}
|
spring.datasource.hikari.jdbcUrl=${FINERACT_HIKARI_JDBC_URL:jdbc:postgresql://localhost:5432/fineract_tenants}
|
||||||
spring.datasource.hikari.username=${FINERACT_HIKARI_USERNAME:postgres}
|
spring.datasource.hikari.username=${FINERACT_HIKARI_USERNAME:postgres}
|
||||||
spring.datasource.hikari.password=${FINERACT_HIKARI_PASSWORD:Keshav@898966}
|
spring.datasource.hikari.password=${FINERACT_HIKARI_PASSWORD:313863}
|
||||||
spring.datasource.hikari.minimumIdle=${FINERACT_HIKARI_MINIMUM_IDLE:3}
|
spring.datasource.hikari.minimumIdle=${FINERACT_HIKARI_MINIMUM_IDLE:3}
|
||||||
spring.datasource.hikari.maximumPoolSize=${FINERACT_HIKARI_MAXIMUM_POOL_SIZE:10}
|
spring.datasource.hikari.maximumPoolSize=${FINERACT_HIKARI_MAXIMUM_POOL_SIZE:10}
|
||||||
spring.datasource.hikari.idleTimeout=${FINERACT_HIKARI_IDLE_TIMEOUT:60000}
|
spring.datasource.hikari.idleTimeout=${FINERACT_HIKARI_IDLE_TIMEOUT:60000}
|
||||||
|
|||||||
@@ -435,6 +435,7 @@
|
|||||||
<include file="parts/0412_activate_outward_clearing_batch_job.xml" relativeToChangelogFile="true"/>
|
<include file="parts/0412_activate_outward_clearing_batch_job.xml" relativeToChangelogFile="true"/>
|
||||||
<include file="parts/0413_inward_item_verify_signature_permission.xml" relativeToChangelogFile="true"/>
|
<include file="parts/0413_inward_item_verify_signature_permission.xml" relativeToChangelogFile="true"/>
|
||||||
<include file="parts/0414_inward_item_full_source_details.xml" relativeToChangelogFile="true"/>
|
<include file="parts/0414_inward_item_full_source_details.xml" relativeToChangelogFile="true"/>
|
||||||
|
<include file="parts/0415_welcome_kit_dispatch.xml" relativeToChangelogFile="true"/>
|
||||||
<include file="parts/0415_add_otp_delivery_method_and_first_login_gate_to_appuser.xml" relativeToChangelogFile="true"/>
|
<include file="parts/0415_add_otp_delivery_method_and_first_login_gate_to_appuser.xml" relativeToChangelogFile="true"/>
|
||||||
<include file="parts/0416_create_user_agreement_tables.xml" relativeToChangelogFile="true"/>
|
<include file="parts/0416_create_user_agreement_tables.xml" relativeToChangelogFile="true"/>
|
||||||
<include file="parts/0417_add_first_login_gate_config.xml" relativeToChangelogFile="true"/>
|
<include file="parts/0417_add_first_login_gate_config.xml" relativeToChangelogFile="true"/>
|
||||||
|
|||||||
+24
-16
@@ -23,24 +23,32 @@
|
|||||||
|
|
||||||
<!-- Dedicated liability GL account for the Sponsor DD Payable balance owed to SBI, as a child
|
<!-- Dedicated liability GL account for the Sponsor DD Payable balance owed to SBI, as a child
|
||||||
of the existing "OTHER LIABILITY" account (gl_code 9), matching the pattern already used
|
of the existing "OTHER LIABILITY" account (gl_code 9), matching the pattern already used
|
||||||
by "INTEREST PAYABLE" (gl_code 9.2). -->
|
by "INTEREST PAYABLE" (gl_code 9.2).
|
||||||
<changeSet author="fineract" id="0345-1-insert-sponsor-dd-payable-sbi-gl-account">
|
|
||||||
|
parent_id is resolved by gl_code (not hardcoded) — the "OTHER LIABILITY" row's numeric id
|
||||||
|
is an auto-increment value that depends on each tenant's own insert history, so a
|
||||||
|
hardcoded id (previously 22) only happened to match the `default` tenant and broke FK
|
||||||
|
inserts on any tenant whose chart of accounts was seeded differently (e.g. `saga`), which
|
||||||
|
aborted that tenant's whole Liquibase run — and with it, the entire application startup.
|
||||||
|
runOnChange lets this corrected version safely re-validate on tenants where the old,
|
||||||
|
already-recorded version succeeded: the "gl_code 9.3 doesn't exist yet" precondition below
|
||||||
|
is already false there, so it's skipped rather than re-inserted. -->
|
||||||
|
<changeSet author="fineract" id="0345-1-insert-sponsor-dd-payable-sbi-gl-account" runOnChange="true">
|
||||||
<preConditions onFail="MARK_RAN">
|
<preConditions onFail="MARK_RAN">
|
||||||
<not>
|
<and>
|
||||||
<sqlCheck expectedResult="1">select count(*) from acc_gl_account where gl_code = '9.3'</sqlCheck>
|
<not>
|
||||||
</not>
|
<sqlCheck expectedResult="1">select count(*) from acc_gl_account where gl_code = '9.3'</sqlCheck>
|
||||||
|
</not>
|
||||||
|
<sqlCheck expectedResult="1">select count(*) from acc_gl_account where gl_code = '9'</sqlCheck>
|
||||||
|
</and>
|
||||||
</preConditions>
|
</preConditions>
|
||||||
<insert tableName="acc_gl_account">
|
<sql>
|
||||||
<column name="name" value="Sponsor DD Payable - SBI"/>
|
INSERT INTO acc_gl_account (name, gl_code, parent_id, hierarchy, account_usage, classification_enum, disabled, manual_journal_entries_allowed, description)
|
||||||
<column name="gl_code" value="9.3"/>
|
SELECT 'Sponsor DD Payable - SBI', '9.3', parent.id, '.', 1, 2, FALSE, TRUE,
|
||||||
<column name="parent_id" valueNumeric="22"/>
|
'Liability owed to SBI for sponsor bank demand drafts issued on their behalf, pending clearing.'
|
||||||
<column name="hierarchy" value="."/>
|
FROM acc_gl_account parent
|
||||||
<column name="account_usage" valueNumeric="1"/>
|
WHERE parent.gl_code = '9';
|
||||||
<column name="classification_enum" valueNumeric="2"/>
|
</sql>
|
||||||
<column name="disabled" valueBoolean="false"/>
|
|
||||||
<column name="manual_journal_entries_allowed" valueBoolean="true"/>
|
|
||||||
<column name="description" value="Liability owed to SBI for sponsor bank demand drafts issued on their behalf, pending clearing."/>
|
|
||||||
</insert>
|
|
||||||
</changeSet>
|
</changeSet>
|
||||||
|
|
||||||
<!-- Fineract's GL hierarchy path embeds the row's own auto-generated id, so it can only be
|
<!-- Fineract's GL hierarchy path embeds the row's own auto-generated id, so it can only be
|
||||||
|
|||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
|
||||||
|
|
||||||
|
<changeSet id="0415_welcome_kit_dispatch" author="CBS" runOnChange="false">
|
||||||
|
<sql>
|
||||||
|
CREATE TABLE m_welcome_kit_dispatch (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
client_id BIGINT NOT NULL REFERENCES m_client(id),
|
||||||
|
delivery_address VARCHAR(500) NOT NULL,
|
||||||
|
delivery_mode VARCHAR(50) NOT NULL,
|
||||||
|
delivery_mode_other_text VARCHAR(255),
|
||||||
|
tracking_id VARCHAR(100) NOT NULL UNIQUE,
|
||||||
|
status VARCHAR(30) NOT NULL DEFAULT 'DISPATCHED',
|
||||||
|
dispatched_on_date DATE NOT NULL,
|
||||||
|
delivered_on_date DATE,
|
||||||
|
created_by BIGINT,
|
||||||
|
created_date TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||||
|
last_modified_by BIGINT,
|
||||||
|
last_modified_date TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker)
|
||||||
|
SELECT 'portfolio', 'READ_WELCOMEKIT', 'WELCOMEKIT', 'READ', false
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM m_permission WHERE code = 'READ_WELCOMEKIT');
|
||||||
|
|
||||||
|
INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker)
|
||||||
|
SELECT 'portfolio', 'CREATE_WELCOMEKIT', 'WELCOMEKIT', 'CREATE', false
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM m_permission WHERE code = 'CREATE_WELCOMEKIT');
|
||||||
|
|
||||||
|
INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker)
|
||||||
|
SELECT 'portfolio', 'UPDATE_WELCOMEKIT', 'WELCOMEKIT', 'UPDATE', false
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM m_permission WHERE code = 'UPDATE_WELCOMEKIT');
|
||||||
|
</sql>
|
||||||
|
</changeSet>
|
||||||
|
|
||||||
|
</databaseChangeLog>
|
||||||
+20
-13
@@ -32,6 +32,13 @@
|
|||||||
Threshold numbers marked "illustrative default" mirror the bank's own Rules Parameter
|
Threshold numbers marked "illustrative default" mirror the bank's own Rules Parameter
|
||||||
screens where a configured value was available (Rules 1, 6, 10, 11, 12, 13); others are
|
screens where a configured value was available (Rules 1, 6, 10, 11, 12, 13); others are
|
||||||
reasonable starting points meant to be tuned via the AML rule administration UI.
|
reasonable starting points meant to be tuned via the AML rule administration UI.
|
||||||
|
|
||||||
|
order_position is only unique WITHIN 0430's own 221-row insert - it collides with the
|
||||||
|
older, differently-numbered seed rows from 0428_add_client_risk_rules.xml (e.g. both
|
||||||
|
insert a row at order_position 10 and 30), which made every subquery below ambiguous
|
||||||
|
("more than one row returned") and aborted the whole tenant migration. aml_check_status
|
||||||
|
is populated only on 0430's rows (0428's predate that column and are NULL there), so
|
||||||
|
pairing it with order_position uniquely targets the intended 0430 row.
|
||||||
-->
|
-->
|
||||||
<changeSet author="fineract" id="0434-1">
|
<changeSet author="fineract" id="0434-1">
|
||||||
<preConditions onFail="MARK_RAN">
|
<preConditions onFail="MARK_RAN">
|
||||||
@@ -42,19 +49,19 @@
|
|||||||
VALUES
|
VALUES
|
||||||
('CTR_THRESHOLD_10L', 'Mandatory CTR reporting threshold - single cash transaction of INR 10,00,000 or more', 'ALL', 1000000, 'THRESHOLD', null, null, true),
|
('CTR_THRESHOLD_10L', 'Mandatory CTR reporting threshold - single cash transaction of INR 10,00,000 or more', 'ALL', 1000000, 'THRESHOLD', null, null, true),
|
||||||
('STRUCTURED_CTR_10L_MONTHLY', 'Connected cash transactions summing to INR 10,00,000 or more within a calendar month (CTR aggregation rule)', 'ALL', 1000000, 'STRUCTURING', 30, null, true),
|
('STRUCTURED_CTR_10L_MONTHLY', 'Connected cash transactions summing to INR 10,00,000 or more within a calendar month (CTR aggregation rule)', 'ALL', 1000000, 'STRUCTURING', 30, null, true),
|
||||||
('LARGE_CASH_TXN_25L', 'Large cash transaction', 'ALL', 2500000, 'THRESHOLD', null, (SELECT id FROM m_client_risk_rule WHERE order_position = 6), true),
|
('LARGE_CASH_TXN_25L', 'Large cash transaction', 'ALL', 2500000, 'THRESHOLD', null, (SELECT id FROM m_client_risk_rule WHERE order_position = 6 AND aml_check_status IS NOT NULL), true),
|
||||||
('STRUCTURING_BELOW_10L', 'Splitting of cash deposits just below INR 10,00,000 in multiple accounts in a month', 'SAVINGS', 1000000, 'STRUCTURING', 30, (SELECT id FROM m_client_risk_rule WHERE order_position = 28), true),
|
('STRUCTURING_BELOW_10L', 'Splitting of cash deposits just below INR 10,00,000 in multiple accounts in a month', 'SAVINGS', 1000000, 'STRUCTURING', 30, (SELECT id FROM m_client_risk_rule WHERE order_position = 28 AND aml_check_status IS NOT NULL), true),
|
||||||
('STRUCTURING_BELOW_50K', 'Splitting of cash deposits just below INR 50,000', 'SAVINGS', 50000, 'STRUCTURING', 30, (SELECT id FROM m_client_risk_rule WHERE order_position = 29), true),
|
('STRUCTURING_BELOW_50K', 'Splitting of cash deposits just below INR 50,000', 'SAVINGS', 50000, 'STRUCTURING', 30, (SELECT id FROM m_client_risk_rule WHERE order_position = 29 AND aml_check_status IS NOT NULL), true),
|
||||||
('FREQUENT_LOW_CASH_DEPOSIT', 'Frequent low cash deposits', 'SAVINGS', 50000, 'VELOCITY', 7, (SELECT id FROM m_client_risk_rule WHERE order_position = 30), true),
|
('FREQUENT_LOW_CASH_DEPOSIT', 'Frequent low cash deposits', 'SAVINGS', 50000, 'VELOCITY', 7, (SELECT id FROM m_client_risk_rule WHERE order_position = 30 AND aml_check_status IS NOT NULL), true),
|
||||||
('FREQUENT_LOW_CASH_WITHDRAWAL', 'Frequent low cash withdrawals', 'SAVINGS', 50000, 'VELOCITY', 7, (SELECT id FROM m_client_risk_rule WHERE order_position = 31), true),
|
('FREQUENT_LOW_CASH_WITHDRAWAL', 'Frequent low cash withdrawals', 'SAVINGS', 50000, 'VELOCITY', 7, (SELECT id FROM m_client_risk_rule WHERE order_position = 31 AND aml_check_status IS NOT NULL), true),
|
||||||
('FREQUENT_CASH_NEAR_10L', 'Frequent cash deposits just below INR 10,00,000', 'SAVINGS', 1000000, 'STRUCTURING', 30, (SELECT id FROM m_client_risk_rule WHERE order_position = 65), true),
|
('FREQUENT_CASH_NEAR_10L', 'Frequent cash deposits just below INR 10,00,000', 'SAVINGS', 1000000, 'STRUCTURING', 30, (SELECT id FROM m_client_risk_rule WHERE order_position = 65 AND aml_check_status IS NOT NULL), true),
|
||||||
('RTGS_HIGH_VALUE', 'Monitoring RTGS Transactions', 'TRANSFER', 2000000, 'THRESHOLD', null, (SELECT id FROM m_client_risk_rule WHERE order_position = 12), true),
|
('RTGS_HIGH_VALUE', 'Monitoring RTGS Transactions', 'TRANSFER', 2000000, 'THRESHOLD', null, (SELECT id FROM m_client_risk_rule WHERE order_position = 12 AND aml_check_status IS NOT NULL), true),
|
||||||
('JEWELLER_ACCOUNT_LARGE_TXN', 'Monitoring accounts of Jewellers', 'ALL', 2000000, 'THRESHOLD', null, (SELECT id FROM m_client_risk_rule WHERE order_position = 13), true),
|
('JEWELLER_ACCOUNT_LARGE_TXN', 'Monitoring accounts of Jewellers', 'ALL', 2000000, 'THRESHOLD', null, (SELECT id FROM m_client_risk_rule WHERE order_position = 13 AND aml_check_status IS NOT NULL), true),
|
||||||
('CHARITABLE_ORG_CASH_WITHDRAWAL', 'Substantial cash withdrawals in accounts of charitable organization', 'SAVINGS', 50000, 'THRESHOLD', null, (SELECT id FROM m_client_risk_rule WHERE order_position = 10), true),
|
('CHARITABLE_ORG_CASH_WITHDRAWAL', 'Substantial cash withdrawals in accounts of charitable organization', 'SAVINGS', 50000, 'THRESHOLD', null, (SELECT id FROM m_client_risk_rule WHERE order_position = 10 AND aml_check_status IS NOT NULL), true),
|
||||||
('PEP_ACCOUNT_MONITORING', 'Monitoring accounts of PEP (politically exposed person)', 'ALL', 50000, 'THRESHOLD', null, (SELECT id FROM m_client_risk_rule WHERE order_position = 11), true),
|
('PEP_ACCOUNT_MONITORING', 'Monitoring accounts of PEP (politically exposed person)', 'ALL', 50000, 'THRESHOLD', null, (SELECT id FROM m_client_risk_rule WHERE order_position = 11 AND aml_check_status IS NOT NULL), true),
|
||||||
('NEW_ACCOUNT_LARGE_TXN', 'New account Large transaction', 'ALL', 500000, 'THRESHOLD', 30, (SELECT id FROM m_client_risk_rule WHERE order_position = 14), true),
|
('NEW_ACCOUNT_LARGE_TXN', 'New account Large transaction', 'ALL', 500000, 'THRESHOLD', 30, (SELECT id FROM m_client_risk_rule WHERE order_position = 14 AND aml_check_status IS NOT NULL), true),
|
||||||
('RAPID_MOVEMENT_IN_ACCOUNTS', 'Rapid Movement in accounts (same-day credit followed by debit)', 'SAVINGS', null, 'VELOCITY', 1, (SELECT id FROM m_client_risk_rule WHERE order_position = 24), true),
|
('RAPID_MOVEMENT_IN_ACCOUNTS', 'Rapid Movement in accounts (same-day credit followed by debit)', 'SAVINGS', null, 'VELOCITY', 1, (SELECT id FROM m_client_risk_rule WHERE order_position = 24 AND aml_check_status IS NOT NULL), true),
|
||||||
('LOAN_REPAYMENT_IN_CASH', 'Repayment of loan in cash', 'LOAN', 200000, 'THRESHOLD', null, (SELECT id FROM m_client_risk_rule WHERE order_position = 73), true);
|
('LOAN_REPAYMENT_IN_CASH', 'Repayment of loan in cash', 'LOAN', 200000, 'THRESHOLD', null, (SELECT id FROM m_client_risk_rule WHERE order_position = 73 AND aml_check_status IS NOT NULL), true);
|
||||||
</sql>
|
</sql>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -16,10 +16,11 @@
|
|||||||
# specific language governing permissions and limitations
|
# specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
#
|
#
|
||||||
org.gradle.jvmargs=-Xmx6g --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.management/javax.management=ALL-UNNAMED --add-opens=java.naming/javax.naming=ALL-UNNAMED --add-opens=java.rmi/sun.rmi.transport=null
|
org.gradle.jvmargs=-Xmx8g -XX:MaxMetaspaceSize=1g --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.management/javax.management=ALL-UNNAMED --add-opens=java.naming/javax.naming=ALL-UNNAMED --add-opens=java.rmi/sun.rmi.transport=null
|
||||||
buildType=BUILD
|
buildType=BUILD
|
||||||
org.gradle.caching=true
|
org.gradle.caching=true
|
||||||
org.gradle.parallel=true
|
org.gradle.parallel=true
|
||||||
|
org.gradle.workers.max=2
|
||||||
org.gradle.daemon.idletimeout=10800000
|
org.gradle.daemon.idletimeout=10800000
|
||||||
# Temporarily disabled until we fix configuration cache compatibility
|
# Temporarily disabled until we fix configuration cache compatibility
|
||||||
#org.gradle.configuration-cache=true
|
#org.gradle.configuration-cache=true
|
||||||
|
|||||||
+2097
File diff suppressed because it is too large
Load Diff
+2115
File diff suppressed because it is too large
Load Diff
+2577
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,10 @@
|
|||||||
|
[33m17e0dab43[m Merge branch 'dev' of https://git.lincpay.tech/CBSNexora/cbsnexora-backend into dev
|
||||||
|
[33m67810bfae[m Add Welcome Kit Dispatch feature and Share Account summary API
|
||||||
|
[33m7c15fbb0c[m fix(documentmanagement): close leaked file handles causing Windows re-upload failures; add entity KYC document CodeValues
|
||||||
|
[33m6e3f195de[m Merge remote-tracking branch 'origin/uate' into uate
|
||||||
|
[33ma65d80125[m feat(clients): maker-checker for client creation and edits (backend)
|
||||||
|
[33mf45d5890e[m CTR/STR report and Risk Category auto mark on bases of person occupation and anual salary enter
|
||||||
|
[33m3c58bb231[m fix(clients): pwdCategoryOptions on edit template, minor-age threshold to 18, minor KYC identity-proof bypass
|
||||||
|
[33maabda18b6[m feat(clients): enforce Mother + Father/Caretaker family members on client activation
|
||||||
|
[33m0e5671b70[m Merge remote-tracking branch 'origin/uate' into uate
|
||||||
|
[33m67214ec0f[m fix(clients): stale signature bug, CKYC fixes, monthly turnover/annual income, senior citizen/PWD classification
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||||
|
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
|
||||||
|
|
||||||
|
$headers = @{
|
||||||
|
"fineract-platform-tenantid" = "default"
|
||||||
|
"Content-Type" = "application/json"
|
||||||
|
}
|
||||||
|
$body = '{"username":"mifos", "password":"password"}'
|
||||||
|
|
||||||
|
Write-Host "--- AUTHENTICATION ---"
|
||||||
|
$authResponse = Invoke-RestMethod -Method Post -Uri "https://localhost:8443/fineract-provider/api/v1/authentication?username=mifos&password=password" -Headers $headers
|
||||||
|
$authKey = $authResponse.base64EncodedAuthenticationKey
|
||||||
|
$headers.Add("Authorization", "Basic $authKey")
|
||||||
|
|
||||||
|
Write-Host "`n--- 1. GET /v1/clients/95/welcomekit ---"
|
||||||
|
$res1 = Invoke-RestMethod -Method Get -Uri "https://localhost:8443/fineract-provider/api/v1/clients/95/welcomekit" -Headers $headers
|
||||||
|
$res1 | ConvertTo-Json -Depth 10
|
||||||
|
|
||||||
|
Write-Host "`n--- 2. POST /v1/clients/95/welcomekit ---"
|
||||||
|
$postBody = @{
|
||||||
|
deliveryAddress = "123 Main St, Springfield"
|
||||||
|
deliveryMode = "POSTMAN"
|
||||||
|
dispatchedOnDate = "30 July 2026"
|
||||||
|
dateFormat = "dd MMMM yyyy"
|
||||||
|
locale = "en"
|
||||||
|
} | ConvertTo-Json
|
||||||
|
Write-Host "Request Body: $postBody"
|
||||||
|
$res2 = Invoke-RestMethod -Method Post -Uri "https://localhost:8443/fineract-provider/api/v1/clients/95/welcomekit" -Headers $headers -Body $postBody
|
||||||
|
$res2 | ConvertTo-Json -Depth 10
|
||||||
|
$welcomeKitId = $res2.resourceId
|
||||||
|
|
||||||
|
Write-Host "`n--- 3. GET /v1/clients/95/welcomekit (after POST) ---"
|
||||||
|
$res3 = Invoke-RestMethod -Method Get -Uri "https://localhost:8443/fineract-provider/api/v1/clients/95/welcomekit" -Headers $headers
|
||||||
|
$res3 | ConvertTo-Json -Depth 10
|
||||||
|
|
||||||
|
Write-Host "`n--- 4. PUT /v1/welcomekit/$welcomeKitId ---"
|
||||||
|
$putBody = @{
|
||||||
|
status = "DELIVERED"
|
||||||
|
} | ConvertTo-Json
|
||||||
|
Write-Host "Request Body: $putBody"
|
||||||
|
$res4 = Invoke-RestMethod -Method Put -Uri "https://localhost:8443/fineract-provider/api/v1/welcomekit/$welcomeKitId" -Headers $headers -Body $putBody
|
||||||
|
$res4 | ConvertTo-Json -Depth 10
|
||||||
|
|
||||||
|
Write-Host "`n--- 5. GET /v1/clients/95/welcomekit (after PUT) ---"
|
||||||
|
$res5 = Invoke-RestMethod -Method Get -Uri "https://localhost:8443/fineract-provider/api/v1/clients/95/welcomekit" -Headers $headers
|
||||||
|
$res5 | ConvertTo-Json -Depth 10
|
||||||
Reference in New Issue
Block a user