table changes on Maker-Checker workflow for Products, with approval-based updates and product locking to prevent concurrent edits
This commit is contained in:
+1
-1
@@ -3573,7 +3573,7 @@ public class CommandWrapperBuilder {
|
||||
this.actionName = "ACTIVATE";
|
||||
this.entityName = "CURRENTACCOUNT";
|
||||
this.savingsId = accountId;
|
||||
this.entityId = null;
|
||||
this.entityId = accountId;
|
||||
this.href = "/currentaccounts/" + accountId + "?command=activate";
|
||||
return this;
|
||||
}
|
||||
|
||||
+1
-1
@@ -224,7 +224,7 @@ public final class DepositsApiConstants {
|
||||
* Deposit Product Parameters
|
||||
*/
|
||||
private static final Set<String> DEPOSIT_PRODUCT_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName,
|
||||
monthDayFormatParamName, nameParamName, shortNameParamName, descriptionParamName, currencyCodeParamName,
|
||||
dateFormatParamName, monthDayFormatParamName, nameParamName, shortNameParamName, descriptionParamName, currencyCodeParamName,
|
||||
digitsAfterDecimalParamName, inMultiplesOfParamName, nominalAnnualInterestRateParamName, interestCompoundingPeriodTypeParamName,
|
||||
interestPostingPeriodTypeParamName, interestCalculationTypeParamName, interestCalculationDaysInYearTypeParamName,
|
||||
lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName, accountingRuleParamName, chargesParamName,
|
||||
|
||||
+52
-30
@@ -51,6 +51,14 @@ import org.apache.fineract.portfolio.tax.data.TaxGroupData;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEdit;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditSubmittedFieldRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditChargeRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditGlMappingRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditFacilityLimitRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditFieldMapper;
|
||||
import java.util.Set;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class CurrentProductReadPlatformServiceImpl implements CurrentProductReadPlatformService {
|
||||
@@ -60,6 +68,11 @@ public class CurrentProductReadPlatformServiceImpl implements CurrentProductRead
|
||||
private final CurrentProductFacilityConfigRepository facilityConfigRepository;
|
||||
private final CurrentProductFacilityLimitRepository facilityLimitRepository;
|
||||
private final CurrentProductDepositLimitKycRepository depositLimitKycRepository;
|
||||
private final ProductPendingEditRepository productPendingEditRepository;
|
||||
private final ProductPendingEditSubmittedFieldRepository pendingEditSubmittedFieldRepository;
|
||||
private final ProductPendingEditChargeRepository pendingEditChargeRepository;
|
||||
private final ProductPendingEditGlMappingRepository pendingEditGlMappingRepository;
|
||||
private final ProductPendingEditFacilityLimitRepository pendingEditFacilityLimitRepository;
|
||||
|
||||
private final CurrentProductMapper currentProductRowMapper = new CurrentProductMapper();
|
||||
private final CurrentProductLookupMapper currentProductLookupsRowMapper = new CurrentProductLookupMapper();
|
||||
@@ -150,41 +163,50 @@ public class CurrentProductReadPlatformServiceImpl implements CurrentProductRead
|
||||
}
|
||||
|
||||
private static final String PENDING_EDIT_SCHEMA = "spt.id as tempId, spt.product_id as savingsProductId, "
|
||||
+ "cp.name as savingsProductName, spt.maker_id as makerId, maker.username as makerUsername, "
|
||||
+ "spt.checker_id as checkerId, checker.username as checkerUsername, spt.created_on as createdOn, "
|
||||
+ "spt.checked_on as checkedOn, spt.status as status, spt.reject_reason as rejectReason, "
|
||||
+ "spt.proposed_payload_json as proposedPayloadJson "
|
||||
+ "from m_savings_product_temp spt "
|
||||
+ "cp.name as savingsProductName, spt.createdby_id as makerId, maker.username as makerUsername, "
|
||||
+ "spt.lastmodifiedby_id as checkerId, checker.username as checkerUsername, spt.created_date as createdOn, "
|
||||
+ "spt.lastmodified_date as checkedOn, spt.status as status, spt.reject_reason as rejectReason "
|
||||
+ "from m_saving_product_temp spt "
|
||||
+ "join m_current_product cp on cp.id = spt.product_id "
|
||||
+ "join m_appuser maker on maker.id = spt.maker_id "
|
||||
+ "left join m_appuser checker on checker.id = spt.checker_id "
|
||||
+ "join m_appuser maker on maker.id = spt.createdby_id "
|
||||
+ "left join m_appuser checker on checker.id = spt.lastmodifiedby_id "
|
||||
+ "where spt.product_type = 'CURRENT' ";
|
||||
|
||||
private static final RowMapper<SavingsProductTempData> PENDING_EDIT_MAPPER = (rs, rowNum) -> {
|
||||
final SavingsProductTempData data = new SavingsProductTempData();
|
||||
data.setId(rs.getLong("tempId"));
|
||||
data.setSavingsProductId(rs.getLong("savingsProductId"));
|
||||
data.setSavingsProductName(rs.getString("savingsProductName"));
|
||||
data.setMakerId(rs.getLong("makerId"));
|
||||
data.setMakerUsername(rs.getString("makerUsername"));
|
||||
data.setCheckerId(JdbcSupport.getLong(rs, "checkerId"));
|
||||
data.setCheckerUsername(rs.getString("checkerUsername"));
|
||||
data.setCreatedOn(rs.getTimestamp("createdOn") == null ? null : rs.getTimestamp("createdOn").toLocalDateTime());
|
||||
data.setCheckedOn(rs.getTimestamp("checkedOn") == null ? null : rs.getTimestamp("checkedOn").toLocalDateTime());
|
||||
data.setStatus(rs.getString("status"));
|
||||
data.setRejectReason(rs.getString("rejectReason"));
|
||||
final String proposedPayloadJson = rs.getString("proposedPayloadJson");
|
||||
if (proposedPayloadJson != null) {
|
||||
data.setProposedChanges(GSON.fromJson(proposedPayloadJson, new TypeToken<Map<String, Object>>() {}.getType()));
|
||||
}
|
||||
return data;
|
||||
};
|
||||
private RowMapper<SavingsProductTempData> getPendingEditRowMapper() {
|
||||
return (rs, rowNum) -> {
|
||||
final SavingsProductTempData data = new SavingsProductTempData();
|
||||
data.setId(rs.getLong("tempId"));
|
||||
data.setSavingsProductId(rs.getLong("savingsProductId"));
|
||||
data.setSavingsProductName(rs.getString("savingsProductName"));
|
||||
data.setMakerId(rs.getLong("makerId"));
|
||||
data.setMakerUsername(rs.getString("makerUsername"));
|
||||
data.setCheckerId(JdbcSupport.getLong(rs, "checkerId"));
|
||||
data.setCheckerUsername(rs.getString("checkerUsername"));
|
||||
data.setCreatedOn(rs.getTimestamp("createdOn") == null ? null : rs.getTimestamp("createdOn").toLocalDateTime());
|
||||
data.setCheckedOn(rs.getTimestamp("checkedOn") == null ? null : rs.getTimestamp("checkedOn").toLocalDateTime());
|
||||
data.setStatus(rs.getString("status"));
|
||||
data.setRejectReason(rs.getString("rejectReason"));
|
||||
|
||||
final Long tempId = data.getId();
|
||||
final java.util.Optional<ProductPendingEdit> opt = this.productPendingEditRepository.findById(tempId);
|
||||
if (opt.isPresent()) {
|
||||
final ProductPendingEdit pendingEdit = opt.get();
|
||||
final Set<String> submittedFields = new java.util.HashSet<>(
|
||||
this.pendingEditSubmittedFieldRepository.findFieldNamesByPendingEditId(pendingEdit.getId()));
|
||||
final Map<String, Object> proposedChanges = ProductPendingEditFieldMapper.reconstructProposedChangesMap(
|
||||
pendingEdit, submittedFields, this.pendingEditChargeRepository, this.pendingEditGlMappingRepository,
|
||||
this.pendingEditFacilityLimitRepository, GSON);
|
||||
data.setProposedChanges(proposedChanges);
|
||||
}
|
||||
return data;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SavingsProductTempData> retrieveAllPendingEdits() {
|
||||
this.context.authenticatedUser();
|
||||
final String sql = "select " + PENDING_EDIT_SCHEMA + "and spt.status = 'PENDING' order by spt.created_on desc";
|
||||
return this.jdbcTemplate.query(sql, PENDING_EDIT_MAPPER);
|
||||
final String sql = "select " + PENDING_EDIT_SCHEMA + "and spt.status = 'PENDING' order by spt.created_date desc";
|
||||
return this.jdbcTemplate.query(sql, getPendingEditRowMapper());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -192,7 +214,7 @@ public class CurrentProductReadPlatformServiceImpl implements CurrentProductRead
|
||||
this.context.authenticatedUser();
|
||||
final String sql = "select " + PENDING_EDIT_SCHEMA + "and spt.status = 'PENDING' and spt.product_id = ?";
|
||||
try {
|
||||
return this.jdbcTemplate.queryForObject(sql, PENDING_EDIT_MAPPER, new Object[] { productId }); // NOSONAR
|
||||
return this.jdbcTemplate.queryForObject(sql, getPendingEditRowMapper(), new Object[] { productId }); // NOSONAR
|
||||
} catch (final EmptyResultDataAccessException e) {
|
||||
throw new CurrentProductNoPendingEditException(productId);
|
||||
}
|
||||
@@ -249,7 +271,7 @@ public class CurrentProductReadPlatformServiceImpl implements CurrentProductRead
|
||||
sqlBuilder.append("cp.balance_swap_option as balanceSwapOption, cp.msme as msme, cp.auto_debit_facility as autoDebitFacility, ");
|
||||
sqlBuilder.append("cp.avg_balance_calc_period as avgBalanceCalcPeriod, cp.valid_for_period as validForPeriod, ");
|
||||
sqlBuilder.append("cp.od_account_closed_zero_balance_in_day_closing as odAccountClosedZeroBalanceInDayClosing, ");
|
||||
sqlBuilder.append("exists(select 1 from m_savings_product_temp spt where spt.product_id = cp.id "
|
||||
sqlBuilder.append("exists(select 1 from m_saving_product_temp spt where spt.product_id = cp.id "
|
||||
+ "and spt.product_type = 'CURRENT' and spt.status = 'PENDING') as isPendingApproval ");
|
||||
|
||||
sqlBuilder.append("from m_current_product cp ");
|
||||
|
||||
+117
-4
@@ -63,6 +63,16 @@ import org.apache.fineract.portfolio.savings.DepositAccountType;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEdit;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditRepository;
|
||||
import org.apache.fineract.portfolio.savings.exception.SavingsProductNotFoundException;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditSubmittedField;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditSubmittedFieldRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditCharge;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditChargeRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditFacilityLimit;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditFacilityLimitRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditGlMapping;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditGlMappingRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditFieldMapper;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.apache.fineract.portfolio.tax.domain.TaxGroup;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
@@ -72,6 +82,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
@RequiredArgsConstructor
|
||||
public class CurrentProductWritePlatformServiceJpaRepositoryImpl implements CurrentProductWritePlatformService {
|
||||
|
||||
private static final com.google.gson.Gson GSON = new com.google.gson.Gson();
|
||||
private final PlatformSecurityContext context;
|
||||
private final CurrentProductRepository currentProductRepository;
|
||||
private final CurrentProductDataValidator fromApiJsonDataValidator;
|
||||
@@ -81,6 +92,10 @@ public class CurrentProductWritePlatformServiceJpaRepositoryImpl implements Curr
|
||||
private final CurrentProductFacilityLimitRepository facilityLimitRepository;
|
||||
private final CurrentProductDepositLimitKycRepository depositLimitKycRepository;
|
||||
private final ProductPendingEditRepository productPendingEditRepository;
|
||||
private final ProductPendingEditSubmittedFieldRepository pendingEditSubmittedFieldRepository;
|
||||
private final ProductPendingEditChargeRepository pendingEditChargeRepository;
|
||||
private final ProductPendingEditFacilityLimitRepository pendingEditFacilityLimitRepository;
|
||||
private final ProductPendingEditGlMappingRepository pendingEditGlMappingRepository;
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
private final CommandSourceRepository commandSourceRepository;
|
||||
|
||||
@@ -281,7 +296,28 @@ public class CurrentProductWritePlatformServiceJpaRepositoryImpl implements Curr
|
||||
|
||||
this.fromApiJsonDataValidator.validateForUpdate(command.json(), product);
|
||||
|
||||
final ProductPendingEdit pendingEdit = new ProductPendingEdit(ProductPendingEdit.TYPE_CURRENT, productId, maker, command.json());
|
||||
final ProductPendingEdit pendingEdit = new ProductPendingEdit(ProductPendingEdit.TYPE_CURRENT, productId, maker);
|
||||
|
||||
final java.util.Set<String> submitted = ProductPendingEditFieldMapper.populateCoreFields(command, pendingEdit.getCoreFields());
|
||||
final java.util.Set<String> currentOnlySubmitted = ProductPendingEditFieldMapper.populateCurrentOnlyFields(command, pendingEdit.getCurrentOnlyFields());
|
||||
final boolean facilityConfigSubmitted = ProductPendingEditFieldMapper.populateFacilityConfig(command, pendingEdit.getFacilityConfigFields());
|
||||
final boolean depositLimitKycSubmitted = ProductPendingEditFieldMapper.populateDepositLimitKyc(command, pendingEdit.getDepositLimitKycFields());
|
||||
final boolean glMappingSubmitted = ProductPendingEditFieldMapper.populateGlAccountMapping(command, pendingEdit.getGlAccountMappingFields());
|
||||
|
||||
if (!currentOnlySubmitted.isEmpty()) {
|
||||
submitted.add("avgBalanceCalcPeriod");
|
||||
submitted.add("validForPeriod");
|
||||
submitted.add("odAccountClosedZeroBalanceInDayClosing");
|
||||
}
|
||||
if (facilityConfigSubmitted) {
|
||||
submitted.add("accountFacilityConfig");
|
||||
}
|
||||
if (depositLimitKycSubmitted) {
|
||||
submitted.add("depositLimitKyc");
|
||||
}
|
||||
if (glMappingSubmitted) {
|
||||
submitted.add("glAccountMapping");
|
||||
}
|
||||
|
||||
final CommandSource auditEntry = CommandSource.builder() //
|
||||
.actionName("UPDATE") //
|
||||
@@ -300,6 +336,30 @@ public class CurrentProductWritePlatformServiceJpaRepositoryImpl implements Curr
|
||||
|
||||
this.productPendingEditRepository.saveAndFlush(pendingEdit);
|
||||
|
||||
for (final String fieldName : submitted) {
|
||||
this.pendingEditSubmittedFieldRepository.save(new ProductPendingEditSubmittedField(pendingEdit, fieldName));
|
||||
}
|
||||
|
||||
final List<Long> chargeIds = ProductPendingEditFieldMapper.extractChargeIds(command);
|
||||
if (chargeIds != null) {
|
||||
this.pendingEditSubmittedFieldRepository.save(new ProductPendingEditSubmittedField(pendingEdit, "charges"));
|
||||
for (final Long chargeId : chargeIds) {
|
||||
this.pendingEditChargeRepository.save(new ProductPendingEditCharge(pendingEdit, chargeId));
|
||||
}
|
||||
}
|
||||
|
||||
final List<ProductPendingEditFacilityLimit> facilityLimits = ProductPendingEditFieldMapper.extractFacilityLimits(command, pendingEdit);
|
||||
if (facilityLimits != null) {
|
||||
this.pendingEditSubmittedFieldRepository.save(new ProductPendingEditSubmittedField(pendingEdit, "accountFacilityLimits"));
|
||||
this.pendingEditFacilityLimitRepository.saveAll(facilityLimits);
|
||||
}
|
||||
|
||||
final List<ProductPendingEditGlMapping> glMappings = ProductPendingEditFieldMapper.extractGlArrayMappings(command, pendingEdit);
|
||||
if (glMappings != null) {
|
||||
this.pendingEditSubmittedFieldRepository.save(new ProductPendingEditSubmittedField(pendingEdit, "glArrayMappings"));
|
||||
this.pendingEditGlMappingRepository.saveAll(glMappings);
|
||||
}
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(product.getId()) //
|
||||
.build();
|
||||
@@ -318,8 +378,33 @@ public class CurrentProductWritePlatformServiceJpaRepositoryImpl implements Curr
|
||||
throw new CurrentProductSelfApprovalNotAllowedException(productId);
|
||||
}
|
||||
|
||||
final JsonCommand replayedCommand = JsonCommand.fromJsonElement(productId,
|
||||
this.fromApiJsonHelper.parse(pendingEdit.getProposedPayloadJson()), this.fromApiJsonHelper);
|
||||
final Set<String> submittedFields = new java.util.HashSet<>(
|
||||
this.pendingEditSubmittedFieldRepository.findFieldNamesByPendingEditId(pendingEdit.getId()));
|
||||
final JsonObject root = new JsonObject();
|
||||
root.addProperty("locale", "en");
|
||||
root.addProperty("dateFormat", "yyyy-MM-dd");
|
||||
ProductPendingEditFieldMapper.writeCoreFieldsToJson(root, pendingEdit.getCoreFields(), submittedFields);
|
||||
ProductPendingEditFieldMapper.writeCurrentOnlyFieldsToJson(root, pendingEdit.getCurrentOnlyFields(), submittedFields);
|
||||
ProductPendingEditFieldMapper.writeFacilityConfigToJson(root, pendingEdit.getFacilityConfigFields(),
|
||||
submittedFields.contains("accountFacilityConfig"));
|
||||
ProductPendingEditFieldMapper.writeDepositLimitKycToJson(root, pendingEdit.getDepositLimitKycFields(),
|
||||
submittedFields.contains("depositLimitKyc"));
|
||||
if (submittedFields.contains("glAccountMapping")) {
|
||||
ProductPendingEditFieldMapper.writeGlAccountMappingToJson(root, pendingEdit.getGlAccountMappingFields());
|
||||
}
|
||||
if (submittedFields.contains("charges")) {
|
||||
ProductPendingEditFieldMapper.writeChargesToJson(root,
|
||||
this.pendingEditChargeRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
if (submittedFields.contains("accountFacilityLimits")) {
|
||||
ProductPendingEditFieldMapper.writeFacilityLimitsToJson(root,
|
||||
this.pendingEditFacilityLimitRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
if (submittedFields.contains("glArrayMappings")) {
|
||||
ProductPendingEditFieldMapper.writeGlArrayMappingsToJson(root,
|
||||
this.pendingEditGlMappingRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
final JsonCommand replayedCommand = JsonCommand.fromJsonElement(productId, root, this.fromApiJsonHelper);
|
||||
final CommandProcessingResult result = update(productId, replayedCommand);
|
||||
|
||||
pendingEdit.markApproved(checker);
|
||||
@@ -340,12 +425,40 @@ public class CurrentProductWritePlatformServiceJpaRepositoryImpl implements Curr
|
||||
return existing.get();
|
||||
}
|
||||
}
|
||||
final Set<String> submittedFields = new java.util.HashSet<>(
|
||||
this.pendingEditSubmittedFieldRepository.findFieldNamesByPendingEditId(pendingEdit.getId()));
|
||||
final JsonObject root = new JsonObject();
|
||||
root.addProperty("locale", "en");
|
||||
root.addProperty("dateFormat", "yyyy-MM-dd");
|
||||
ProductPendingEditFieldMapper.writeCoreFieldsToJson(root, pendingEdit.getCoreFields(), submittedFields);
|
||||
ProductPendingEditFieldMapper.writeCurrentOnlyFieldsToJson(root, pendingEdit.getCurrentOnlyFields(), submittedFields);
|
||||
ProductPendingEditFieldMapper.writeFacilityConfigToJson(root, pendingEdit.getFacilityConfigFields(),
|
||||
submittedFields.contains("accountFacilityConfig"));
|
||||
ProductPendingEditFieldMapper.writeDepositLimitKycToJson(root, pendingEdit.getDepositLimitKycFields(),
|
||||
submittedFields.contains("depositLimitKyc"));
|
||||
if (submittedFields.contains("glAccountMapping")) {
|
||||
ProductPendingEditFieldMapper.writeGlAccountMappingToJson(root, pendingEdit.getGlAccountMappingFields());
|
||||
}
|
||||
if (submittedFields.contains("charges")) {
|
||||
ProductPendingEditFieldMapper.writeChargesToJson(root,
|
||||
this.pendingEditChargeRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
if (submittedFields.contains("accountFacilityLimits")) {
|
||||
ProductPendingEditFieldMapper.writeFacilityLimitsToJson(root,
|
||||
this.pendingEditFacilityLimitRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
if (submittedFields.contains("glArrayMappings")) {
|
||||
ProductPendingEditFieldMapper.writeGlArrayMappingsToJson(root,
|
||||
this.pendingEditGlMappingRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
final String commandJson = GSON.toJson(root);
|
||||
|
||||
final CommandSource auditEntry = CommandSource.builder() //
|
||||
.actionName("UPDATE") //
|
||||
.entityName("CURRENTPRODUCT") //
|
||||
.resourceGetUrl("/currentproducts/" + productId) //
|
||||
.resourceId(productId) //
|
||||
.commandAsJson(pendingEdit.getProposedPayloadJson()) //
|
||||
.commandAsJson(commandJson) //
|
||||
.maker(pendingEdit.getMaker()) //
|
||||
.madeOnDate(DateUtils.getAuditOffsetDateTime()) //
|
||||
.status(CommandProcessingResultType.AWAITING_APPROVAL.getValue()) //
|
||||
|
||||
+21
-4
@@ -23,6 +23,10 @@ import org.apache.fineract.commands.domain.CommandSourceRepository;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditSubmittedFieldRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditChargeRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditFacilityLimitRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditGlMappingRepository;
|
||||
import org.apache.fineract.portfolio.currentproduct.data.CurrentProductDataValidator;
|
||||
import org.apache.fineract.portfolio.currentproduct.domain.CurrentProductAssembler;
|
||||
import org.apache.fineract.portfolio.currentproduct.domain.CurrentProductDepositLimitKycRepository;
|
||||
@@ -46,9 +50,17 @@ public class CurrentProductConfiguration {
|
||||
public CurrentProductReadPlatformService currentProductReadPlatformService(PlatformSecurityContext context,
|
||||
JdbcTemplate jdbcTemplate, CurrentProductFacilityConfigRepository currentFacilityConfigRepository,
|
||||
CurrentProductFacilityLimitRepository currentFacilityLimitRepository,
|
||||
CurrentProductDepositLimitKycRepository currentDepositLimitKycRepository) {
|
||||
CurrentProductDepositLimitKycRepository currentDepositLimitKycRepository,
|
||||
ProductPendingEditRepository productPendingEditRepository,
|
||||
ProductPendingEditSubmittedFieldRepository pendingEditSubmittedFieldRepository,
|
||||
ProductPendingEditChargeRepository pendingEditChargeRepository,
|
||||
ProductPendingEditGlMappingRepository pendingEditGlMappingRepository,
|
||||
ProductPendingEditFacilityLimitRepository pendingEditFacilityLimitRepository) {
|
||||
return new CurrentProductReadPlatformServiceImpl(context, jdbcTemplate, currentFacilityConfigRepository,
|
||||
currentFacilityLimitRepository, currentDepositLimitKycRepository);
|
||||
currentFacilityLimitRepository, currentDepositLimitKycRepository,
|
||||
productPendingEditRepository, pendingEditSubmittedFieldRepository,
|
||||
pendingEditChargeRepository, pendingEditGlMappingRepository,
|
||||
pendingEditFacilityLimitRepository);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -61,11 +73,16 @@ public class CurrentProductConfiguration {
|
||||
CurrentProductFacilityLimitRepository currentFacilityLimitRepository,
|
||||
CurrentProductDepositLimitKycRepository currentDepositLimitKycRepository,
|
||||
ProductPendingEditRepository productPendingEditRepository,
|
||||
ProductPendingEditSubmittedFieldRepository pendingEditSubmittedFieldRepository,
|
||||
ProductPendingEditChargeRepository pendingEditChargeRepository,
|
||||
ProductPendingEditFacilityLimitRepository pendingEditFacilityLimitRepository,
|
||||
ProductPendingEditGlMappingRepository pendingEditGlMappingRepository,
|
||||
FromJsonHelper fromApiJsonHelper,
|
||||
CommandSourceRepository commandSourceRepository) {
|
||||
return new CurrentProductWritePlatformServiceJpaRepositoryImpl(context, currentProductRepository, currentProductDataValidator,
|
||||
currentProductAssembler, accountMappingWritePlatformService, currentFacilityConfigRepository,
|
||||
currentFacilityLimitRepository, currentDepositLimitKycRepository, productPendingEditRepository, fromApiJsonHelper,
|
||||
commandSourceRepository);
|
||||
currentFacilityLimitRepository, currentDepositLimitKycRepository, productPendingEditRepository,
|
||||
pendingEditSubmittedFieldRepository, pendingEditChargeRepository, pendingEditFacilityLimitRepository,
|
||||
pendingEditGlMappingRepository, fromApiJsonHelper, commandSourceRepository);
|
||||
}
|
||||
}
|
||||
|
||||
+50
-30
@@ -44,6 +44,13 @@ import org.apache.fineract.portfolio.tax.data.TaxGroupData;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEdit;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditSubmittedFieldRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditChargeRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditGlMappingRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditFieldMapper;
|
||||
import java.util.Set;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class DepositProductReadPlatformServiceImpl implements DepositProductReadPlatformService {
|
||||
@@ -54,6 +61,10 @@ public class DepositProductReadPlatformServiceImpl implements DepositProductRead
|
||||
private final PlatformSecurityContext context;
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
private final InterestRateChartReadPlatformService chartReadPlatformService;
|
||||
private final ProductPendingEditRepository productPendingEditRepository;
|
||||
private final ProductPendingEditSubmittedFieldRepository pendingEditSubmittedFieldRepository;
|
||||
private final ProductPendingEditChargeRepository pendingEditChargeRepository;
|
||||
private final ProductPendingEditGlMappingRepository pendingEditGlMappingRepository;
|
||||
|
||||
@Override
|
||||
public Collection<DepositProductData> retrieveAll(final DepositAccountType depositAccountType) {
|
||||
@@ -135,41 +146,50 @@ public class DepositProductReadPlatformServiceImpl implements DepositProductRead
|
||||
return depositAccountType.isFixedDeposit() ? "FD" : "RD";
|
||||
}
|
||||
|
||||
private static final RowMapper<SavingsProductTempData> PENDING_EDIT_MAPPER = (rs, rowNum) -> {
|
||||
final SavingsProductTempData data = new SavingsProductTempData();
|
||||
data.setId(rs.getLong("tempId"));
|
||||
data.setSavingsProductId(rs.getLong("savingsProductId"));
|
||||
data.setSavingsProductName(rs.getString("savingsProductName"));
|
||||
data.setMakerId(rs.getLong("makerId"));
|
||||
data.setMakerUsername(rs.getString("makerUsername"));
|
||||
data.setCheckerId(JdbcSupport.getLong(rs, "checkerId"));
|
||||
data.setCheckerUsername(rs.getString("checkerUsername"));
|
||||
data.setCreatedOn(rs.getTimestamp("createdOn") == null ? null : rs.getTimestamp("createdOn").toLocalDateTime());
|
||||
data.setCheckedOn(rs.getTimestamp("checkedOn") == null ? null : rs.getTimestamp("checkedOn").toLocalDateTime());
|
||||
data.setStatus(rs.getString("status"));
|
||||
data.setRejectReason(rs.getString("rejectReason"));
|
||||
final String proposedPayloadJson = rs.getString("proposedPayloadJson");
|
||||
if (proposedPayloadJson != null) {
|
||||
data.setProposedChanges(GSON.fromJson(proposedPayloadJson, new TypeToken<Map<String, Object>>() {}.getType()));
|
||||
}
|
||||
return data;
|
||||
};
|
||||
private RowMapper<SavingsProductTempData> getPendingEditRowMapper() {
|
||||
return (rs, rowNum) -> {
|
||||
final SavingsProductTempData data = new SavingsProductTempData();
|
||||
data.setId(rs.getLong("tempId"));
|
||||
data.setSavingsProductId(rs.getLong("savingsProductId"));
|
||||
data.setSavingsProductName(rs.getString("savingsProductName"));
|
||||
data.setMakerId(rs.getLong("makerId"));
|
||||
data.setMakerUsername(rs.getString("makerUsername"));
|
||||
data.setCheckerId(JdbcSupport.getLong(rs, "checkerId"));
|
||||
data.setCheckerUsername(rs.getString("checkerUsername"));
|
||||
data.setCreatedOn(rs.getTimestamp("createdOn") == null ? null : rs.getTimestamp("createdOn").toLocalDateTime());
|
||||
data.setCheckedOn(rs.getTimestamp("checkedOn") == null ? null : rs.getTimestamp("checkedOn").toLocalDateTime());
|
||||
data.setStatus(rs.getString("status"));
|
||||
data.setRejectReason(rs.getString("rejectReason"));
|
||||
|
||||
final Long tempId = data.getId();
|
||||
final java.util.Optional<ProductPendingEdit> opt = this.productPendingEditRepository.findById(tempId);
|
||||
if (opt.isPresent()) {
|
||||
final ProductPendingEdit pendingEdit = opt.get();
|
||||
final Set<String> submittedFields = new java.util.HashSet<>(
|
||||
this.pendingEditSubmittedFieldRepository.findFieldNamesByPendingEditId(pendingEdit.getId()));
|
||||
final Map<String, Object> proposedChanges = ProductPendingEditFieldMapper.reconstructProposedChangesMap(
|
||||
pendingEdit, submittedFields, this.pendingEditChargeRepository, this.pendingEditGlMappingRepository, null, GSON);
|
||||
data.setProposedChanges(proposedChanges);
|
||||
}
|
||||
return data;
|
||||
};
|
||||
}
|
||||
|
||||
private static String pendingEditSchema(final String productType) {
|
||||
return "spt.id as tempId, spt.product_id as savingsProductId, " + "sp.name as savingsProductName, spt.maker_id as makerId, "
|
||||
+ "maker.username as makerUsername, spt.checker_id as checkerId, checker.username as checkerUsername, "
|
||||
+ "spt.created_on as createdOn, spt.checked_on as checkedOn, spt.status as status, "
|
||||
+ "spt.reject_reason as rejectReason, spt.proposed_payload_json as proposedPayloadJson "
|
||||
+ "from m_savings_product_temp spt " + "join m_savings_product sp on sp.id = spt.product_id "
|
||||
+ "join m_appuser maker on maker.id = spt.maker_id " + "left join m_appuser checker on checker.id = spt.checker_id "
|
||||
return "spt.id as tempId, spt.product_id as savingsProductId, " + "sp.name as savingsProductName, spt.createdby_id as makerId, "
|
||||
+ "maker.username as makerUsername, spt.lastmodifiedby_id as checkerId, checker.username as checkerUsername, "
|
||||
+ "spt.created_date as createdOn, spt.lastmodified_date as checkedOn, spt.status as status, "
|
||||
+ "spt.reject_reason as rejectReason "
|
||||
+ "from m_saving_product_temp spt " + "join m_savings_product sp on sp.id = spt.product_id "
|
||||
+ "join m_appuser maker on maker.id = spt.createdby_id " + "left join m_appuser checker on checker.id = spt.lastmodifiedby_id "
|
||||
+ "where spt.product_type = '" + productType + "' ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SavingsProductTempData> retrieveAllPendingEdits(final DepositAccountType depositAccountType) {
|
||||
final String sql = "select " + pendingEditSchema(productPendingType(depositAccountType))
|
||||
+ "and spt.status = 'PENDING' order by spt.created_on desc";
|
||||
return this.jdbcTemplate.query(sql, PENDING_EDIT_MAPPER);
|
||||
+ "and spt.status = 'PENDING' order by spt.created_date desc";
|
||||
return this.jdbcTemplate.query(sql, getPendingEditRowMapper());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -177,7 +197,7 @@ public class DepositProductReadPlatformServiceImpl implements DepositProductRead
|
||||
final String sql = "select " + pendingEditSchema(productPendingType(depositAccountType))
|
||||
+ "and spt.status = 'PENDING' and spt.product_id = ?";
|
||||
try {
|
||||
return this.jdbcTemplate.queryForObject(sql, PENDING_EDIT_MAPPER, new Object[] { productId }); // NOSONAR
|
||||
return this.jdbcTemplate.queryForObject(sql, getPendingEditRowMapper(), new Object[] { productId }); // NOSONAR
|
||||
} catch (final EmptyResultDataAccessException e) {
|
||||
throw new SavingsProductNoPendingEditException(productId);
|
||||
}
|
||||
@@ -315,7 +335,7 @@ public class DepositProductReadPlatformServiceImpl implements DepositProductRead
|
||||
sqlBuilder.append("sp.deceased_settlement as deceasedSettlement, ");
|
||||
sqlBuilder.append("sp.allow_debit_txn_after_due_date as allowDebitTxnAfterDueDate, ");
|
||||
sqlBuilder.append("sp.withdrawal_fee_for_transfer as withdrawalFeeForTransfers, ");
|
||||
sqlBuilder.append("exists(select 1 from m_savings_product_temp spt where spt.product_id = sp.id "
|
||||
sqlBuilder.append("exists(select 1 from m_saving_product_temp spt where spt.product_id = sp.id "
|
||||
+ "and spt.product_type = 'FD' and spt.status = 'PENDING') as isPendingApproval ");
|
||||
sqlBuilder.append("from m_savings_product sp ");
|
||||
sqlBuilder.append("left join m_deposit_product_term_and_preclosure dptp on sp.id=dptp.savings_product_id ");
|
||||
@@ -455,7 +475,7 @@ public class DepositProductReadPlatformServiceImpl implements DepositProductRead
|
||||
sqlBuilder.append("sp.deceased_settlement as deceasedSettlement, ");
|
||||
sqlBuilder.append("sp.allow_debit_txn_after_due_date as allowDebitTxnAfterDueDate, ");
|
||||
sqlBuilder.append("sp.withdrawal_fee_for_transfer as withdrawalFeeForTransfers, ");
|
||||
sqlBuilder.append("exists(select 1 from m_savings_product_temp spt where spt.product_id = sp.id "
|
||||
sqlBuilder.append("exists(select 1 from m_saving_product_temp spt where spt.product_id = sp.id "
|
||||
+ "and spt.product_type = 'RD' and spt.status = 'PENDING') as isPendingApproval ");
|
||||
sqlBuilder.append("from m_savings_product sp ");
|
||||
sqlBuilder.append("left join m_deposit_product_term_and_preclosure dptp on sp.id=dptp.savings_product_id ");
|
||||
|
||||
+90
-6
@@ -55,6 +55,14 @@ import org.apache.fineract.portfolio.savings.domain.FixedDepositProduct;
|
||||
import org.apache.fineract.portfolio.savings.domain.FixedDepositProductRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEdit;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditSubmittedField;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditSubmittedFieldRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditCharge;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditChargeRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditGlMapping;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditGlMappingRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditFieldMapper;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.apache.fineract.portfolio.savings.exception.FixedDepositProductNotFoundException;
|
||||
import org.apache.fineract.portfolio.savings.exception.SavingsProductEditPendingApprovalException;
|
||||
import org.apache.fineract.portfolio.savings.exception.SavingsProductNoPendingEditException;
|
||||
@@ -68,6 +76,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
@RequiredArgsConstructor
|
||||
public class FixedDepositProductWritePlatformServiceJpaRepositoryImpl implements FixedDepositProductWritePlatformService {
|
||||
|
||||
private static final com.google.gson.Gson GSON = new com.google.gson.Gson();
|
||||
private final PlatformSecurityContext context;
|
||||
private final FixedDepositProductRepository fixedDepositProductRepository;
|
||||
private final DepositProductDataValidator fromApiJsonDataValidator;
|
||||
@@ -75,6 +84,9 @@ public class FixedDepositProductWritePlatformServiceJpaRepositoryImpl implements
|
||||
private final ProductToGLAccountMappingWritePlatformService accountMappingWritePlatformService;
|
||||
private final InterestRateChartAssembler chartAssembler;
|
||||
private final ProductPendingEditRepository productPendingEditRepository;
|
||||
private final ProductPendingEditSubmittedFieldRepository pendingEditSubmittedFieldRepository;
|
||||
private final ProductPendingEditChargeRepository pendingEditChargeRepository;
|
||||
private final ProductPendingEditGlMappingRepository pendingEditGlMappingRepository;
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
private final CommandSourceRepository commandSourceRepository;
|
||||
|
||||
@@ -108,10 +120,16 @@ public class FixedDepositProductWritePlatformServiceJpaRepositoryImpl implements
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult update(final Long productId, final JsonCommand command) {
|
||||
return updateInternal(productId, command, true);
|
||||
}
|
||||
|
||||
private CommandProcessingResult updateInternal(final Long productId, final JsonCommand command, final boolean validate) {
|
||||
|
||||
try {
|
||||
this.context.authenticatedUser();
|
||||
this.fromApiJsonDataValidator.validateForFixedDepositUpdate(command.json());
|
||||
if (validate) {
|
||||
this.fromApiJsonDataValidator.validateForFixedDepositUpdate(command.json());
|
||||
}
|
||||
|
||||
final FixedDepositProduct product = this.fixedDepositProductRepository.findById(productId)
|
||||
.orElseThrow(() -> new FixedDepositProductNotFoundException(productId));
|
||||
@@ -180,7 +198,18 @@ public class FixedDepositProductWritePlatformServiceJpaRepositoryImpl implements
|
||||
|
||||
this.fromApiJsonDataValidator.validateForFixedDepositUpdate(command.json());
|
||||
|
||||
final ProductPendingEdit pendingEdit = new ProductPendingEdit(ProductPendingEdit.TYPE_FD, productId, maker, command.json());
|
||||
final ProductPendingEdit pendingEdit = new ProductPendingEdit(ProductPendingEdit.TYPE_FD, productId, maker);
|
||||
|
||||
final java.util.Set<String> submitted = ProductPendingEditFieldMapper.populateCoreFields(command, pendingEdit.getCoreFields());
|
||||
final java.util.Set<String> fdSubmitted = ProductPendingEditFieldMapper.populateFixedDepositFields(command, pendingEdit.getFixedDepositFields());
|
||||
final boolean glMappingSubmitted = ProductPendingEditFieldMapper.populateGlAccountMapping(command, pendingEdit.getGlAccountMappingFields());
|
||||
|
||||
if (!fdSubmitted.isEmpty()) {
|
||||
submitted.addAll(fdSubmitted);
|
||||
}
|
||||
if (glMappingSubmitted) {
|
||||
submitted.add("glAccountMapping");
|
||||
}
|
||||
|
||||
final CommandSource auditEntry = CommandSource.builder() //
|
||||
.actionName("UPDATE") //
|
||||
@@ -199,6 +228,24 @@ public class FixedDepositProductWritePlatformServiceJpaRepositoryImpl implements
|
||||
|
||||
this.productPendingEditRepository.saveAndFlush(pendingEdit);
|
||||
|
||||
for (final String fieldName : submitted) {
|
||||
this.pendingEditSubmittedFieldRepository.save(new ProductPendingEditSubmittedField(pendingEdit, fieldName));
|
||||
}
|
||||
|
||||
final List<Long> chargeIds = ProductPendingEditFieldMapper.extractChargeIds(command);
|
||||
if (chargeIds != null) {
|
||||
this.pendingEditSubmittedFieldRepository.save(new ProductPendingEditSubmittedField(pendingEdit, "charges"));
|
||||
for (final Long chargeId : chargeIds) {
|
||||
this.pendingEditChargeRepository.save(new ProductPendingEditCharge(pendingEdit, chargeId));
|
||||
}
|
||||
}
|
||||
|
||||
final List<ProductPendingEditGlMapping> glMappings = ProductPendingEditFieldMapper.extractGlArrayMappings(command, pendingEdit);
|
||||
if (glMappings != null) {
|
||||
this.pendingEditSubmittedFieldRepository.save(new ProductPendingEditSubmittedField(pendingEdit, "glArrayMappings"));
|
||||
this.pendingEditGlMappingRepository.saveAll(glMappings);
|
||||
}
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(product.getId()) //
|
||||
.build();
|
||||
@@ -217,9 +264,26 @@ public class FixedDepositProductWritePlatformServiceJpaRepositoryImpl implements
|
||||
throw new SavingsProductSelfApprovalNotAllowedException(productId);
|
||||
}
|
||||
|
||||
final JsonCommand replayedCommand = JsonCommand.fromJsonElement(productId,
|
||||
this.fromApiJsonHelper.parse(pendingEdit.getProposedPayloadJson()), this.fromApiJsonHelper);
|
||||
final CommandProcessingResult result = update(productId, replayedCommand);
|
||||
final Set<String> submittedFields = new java.util.HashSet<>(
|
||||
this.pendingEditSubmittedFieldRepository.findFieldNamesByPendingEditId(pendingEdit.getId()));
|
||||
final JsonObject root = new JsonObject();
|
||||
root.addProperty("locale", "en");
|
||||
root.addProperty("dateFormat", "yyyy-MM-dd");
|
||||
ProductPendingEditFieldMapper.writeCoreFieldsToJson(root, pendingEdit.getCoreFields(), submittedFields);
|
||||
ProductPendingEditFieldMapper.writeFixedDepositFieldsToJson(root, pendingEdit.getFixedDepositFields(), submittedFields);
|
||||
if (submittedFields.contains("glAccountMapping")) {
|
||||
ProductPendingEditFieldMapper.writeGlAccountMappingToJson(root, pendingEdit.getGlAccountMappingFields());
|
||||
}
|
||||
if (submittedFields.contains("charges")) {
|
||||
ProductPendingEditFieldMapper.writeChargesToJson(root,
|
||||
this.pendingEditChargeRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
if (submittedFields.contains("glArrayMappings")) {
|
||||
ProductPendingEditFieldMapper.writeGlArrayMappingsToJson(root,
|
||||
this.pendingEditGlMappingRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
final JsonCommand replayedCommand = JsonCommand.fromJsonElement(productId, root, this.fromApiJsonHelper);
|
||||
final CommandProcessingResult result = updateInternal(productId, replayedCommand, false);
|
||||
|
||||
pendingEdit.markApproved(checker);
|
||||
this.productPendingEditRepository.saveAndFlush(pendingEdit);
|
||||
@@ -239,12 +303,32 @@ public class FixedDepositProductWritePlatformServiceJpaRepositoryImpl implements
|
||||
return existing.get();
|
||||
}
|
||||
}
|
||||
final Set<String> submittedFields = new java.util.HashSet<>(
|
||||
this.pendingEditSubmittedFieldRepository.findFieldNamesByPendingEditId(pendingEdit.getId()));
|
||||
final JsonObject root = new JsonObject();
|
||||
root.addProperty("locale", "en");
|
||||
root.addProperty("dateFormat", "yyyy-MM-dd");
|
||||
ProductPendingEditFieldMapper.writeCoreFieldsToJson(root, pendingEdit.getCoreFields(), submittedFields);
|
||||
ProductPendingEditFieldMapper.writeFixedDepositFieldsToJson(root, pendingEdit.getFixedDepositFields(), submittedFields);
|
||||
if (submittedFields.contains("glAccountMapping")) {
|
||||
ProductPendingEditFieldMapper.writeGlAccountMappingToJson(root, pendingEdit.getGlAccountMappingFields());
|
||||
}
|
||||
if (submittedFields.contains("charges")) {
|
||||
ProductPendingEditFieldMapper.writeChargesToJson(root,
|
||||
this.pendingEditChargeRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
if (submittedFields.contains("glArrayMappings")) {
|
||||
ProductPendingEditFieldMapper.writeGlArrayMappingsToJson(root,
|
||||
this.pendingEditGlMappingRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
final String commandJson = GSON.toJson(root);
|
||||
|
||||
final CommandSource auditEntry = CommandSource.builder() //
|
||||
.actionName("UPDATE") //
|
||||
.entityName("FIXEDDEPOSITPRODUCT") //
|
||||
.resourceGetUrl("/fixeddepositproducts/" + productId) //
|
||||
.resourceId(productId) //
|
||||
.commandAsJson(pendingEdit.getProposedPayloadJson()) //
|
||||
.commandAsJson(commandJson) //
|
||||
.maker(pendingEdit.getMaker()) //
|
||||
.madeOnDate(DateUtils.getAuditOffsetDateTime()) //
|
||||
.status(CommandProcessingResultType.AWAITING_APPROVAL.getValue()) //
|
||||
|
||||
+97
-6
@@ -52,10 +52,18 @@ import org.apache.fineract.portfolio.savings.SavingsApiConstants;
|
||||
import org.apache.fineract.portfolio.savings.data.DepositProductDataValidator;
|
||||
import org.apache.fineract.portfolio.savings.domain.DepositProductAssembler;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEdit;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditCharge;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditChargeRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditFieldMapper;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditGlMapping;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditGlMappingRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditSubmittedField;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditSubmittedFieldRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.RecurringDepositProduct;
|
||||
import org.apache.fineract.portfolio.savings.domain.RecurringDepositProductRepository;
|
||||
import org.apache.fineract.portfolio.savings.exception.RecurringDepositProductNotFoundException;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.apache.fineract.portfolio.savings.exception.SavingsProductEditPendingApprovalException;
|
||||
import org.apache.fineract.portfolio.savings.exception.SavingsProductNoPendingEditException;
|
||||
import org.apache.fineract.portfolio.savings.exception.SavingsProductSelfApprovalNotAllowedException;
|
||||
@@ -68,6 +76,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
@RequiredArgsConstructor
|
||||
public class RecurringDepositProductWritePlatformServiceJpaRepositoryImpl implements RecurringDepositProductWritePlatformService {
|
||||
|
||||
private static final com.google.gson.Gson GSON = new com.google.gson.Gson();
|
||||
private final PlatformSecurityContext context;
|
||||
private final RecurringDepositProductRepository recurringDepositProductRepository;
|
||||
private final DepositProductDataValidator fromApiJsonDataValidator;
|
||||
@@ -75,6 +84,9 @@ public class RecurringDepositProductWritePlatformServiceJpaRepositoryImpl implem
|
||||
private final ProductToGLAccountMappingWritePlatformService accountMappingWritePlatformService;
|
||||
private final InterestRateChartAssembler chartAssembler;
|
||||
private final ProductPendingEditRepository productPendingEditRepository;
|
||||
private final ProductPendingEditSubmittedFieldRepository pendingEditSubmittedFieldRepository;
|
||||
private final ProductPendingEditChargeRepository pendingEditChargeRepository;
|
||||
private final ProductPendingEditGlMappingRepository pendingEditGlMappingRepository;
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
private final CommandSourceRepository commandSourceRepository;
|
||||
|
||||
@@ -108,10 +120,16 @@ public class RecurringDepositProductWritePlatformServiceJpaRepositoryImpl implem
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult update(final Long productId, final JsonCommand command) {
|
||||
return updateInternal(productId, command, true);
|
||||
}
|
||||
|
||||
private CommandProcessingResult updateInternal(final Long productId, final JsonCommand command, final boolean validate) {
|
||||
|
||||
try {
|
||||
this.context.authenticatedUser();
|
||||
this.fromApiJsonDataValidator.validateForRecurringDepositUpdate(command.json());
|
||||
if (validate) {
|
||||
this.fromApiJsonDataValidator.validateForRecurringDepositUpdate(command.json());
|
||||
}
|
||||
|
||||
final RecurringDepositProduct product = this.recurringDepositProductRepository.findById(productId)
|
||||
.orElseThrow(() -> new RecurringDepositProductNotFoundException(productId));
|
||||
@@ -180,7 +198,22 @@ public class RecurringDepositProductWritePlatformServiceJpaRepositoryImpl implem
|
||||
|
||||
this.fromApiJsonDataValidator.validateForRecurringDepositUpdate(command.json());
|
||||
|
||||
final ProductPendingEdit pendingEdit = new ProductPendingEdit(ProductPendingEdit.TYPE_RD, productId, maker, command.json());
|
||||
final ProductPendingEdit pendingEdit = new ProductPendingEdit(ProductPendingEdit.TYPE_RD, productId, maker);
|
||||
|
||||
final java.util.Set<String> submitted = ProductPendingEditFieldMapper.populateCoreFields(command, pendingEdit.getCoreFields());
|
||||
final java.util.Set<String> fdSubmitted = ProductPendingEditFieldMapper.populateFixedDepositFields(command, pendingEdit.getFixedDepositFields());
|
||||
final java.util.Set<String> rdSubmitted = ProductPendingEditFieldMapper.populateRecurringDepositFields(command, pendingEdit.getRecurringDepositFields());
|
||||
final boolean glMappingSubmitted = ProductPendingEditFieldMapper.populateGlAccountMapping(command, pendingEdit.getGlAccountMappingFields());
|
||||
|
||||
if (!fdSubmitted.isEmpty()) {
|
||||
submitted.addAll(fdSubmitted);
|
||||
}
|
||||
if (!rdSubmitted.isEmpty()) {
|
||||
submitted.addAll(rdSubmitted);
|
||||
}
|
||||
if (glMappingSubmitted) {
|
||||
submitted.add("glAccountMapping");
|
||||
}
|
||||
|
||||
final CommandSource auditEntry = CommandSource.builder() //
|
||||
.actionName("UPDATE") //
|
||||
@@ -199,6 +232,24 @@ public class RecurringDepositProductWritePlatformServiceJpaRepositoryImpl implem
|
||||
|
||||
this.productPendingEditRepository.saveAndFlush(pendingEdit);
|
||||
|
||||
for (final String fieldName : submitted) {
|
||||
this.pendingEditSubmittedFieldRepository.save(new ProductPendingEditSubmittedField(pendingEdit, fieldName));
|
||||
}
|
||||
|
||||
final List<Long> chargeIds = ProductPendingEditFieldMapper.extractChargeIds(command);
|
||||
if (chargeIds != null) {
|
||||
this.pendingEditSubmittedFieldRepository.save(new ProductPendingEditSubmittedField(pendingEdit, "charges"));
|
||||
for (final Long chargeId : chargeIds) {
|
||||
this.pendingEditChargeRepository.save(new ProductPendingEditCharge(pendingEdit, chargeId));
|
||||
}
|
||||
}
|
||||
|
||||
final List<ProductPendingEditGlMapping> glMappings = ProductPendingEditFieldMapper.extractGlArrayMappings(command, pendingEdit);
|
||||
if (glMappings != null) {
|
||||
this.pendingEditSubmittedFieldRepository.save(new ProductPendingEditSubmittedField(pendingEdit, "glArrayMappings"));
|
||||
this.pendingEditGlMappingRepository.saveAll(glMappings);
|
||||
}
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(product.getId()) //
|
||||
.build();
|
||||
@@ -217,9 +268,28 @@ public class RecurringDepositProductWritePlatformServiceJpaRepositoryImpl implem
|
||||
throw new SavingsProductSelfApprovalNotAllowedException(productId);
|
||||
}
|
||||
|
||||
final JsonCommand replayedCommand = JsonCommand.fromJsonElement(productId,
|
||||
this.fromApiJsonHelper.parse(pendingEdit.getProposedPayloadJson()), this.fromApiJsonHelper);
|
||||
final CommandProcessingResult result = update(productId, replayedCommand);
|
||||
final Set<String> submittedFields = new java.util.HashSet<>(
|
||||
this.pendingEditSubmittedFieldRepository.findFieldNamesByPendingEditId(pendingEdit.getId()));
|
||||
submittedFields.remove("fdType");
|
||||
final JsonObject root = new JsonObject();
|
||||
root.addProperty("locale", "en");
|
||||
root.addProperty("dateFormat", "yyyy-MM-dd");
|
||||
ProductPendingEditFieldMapper.writeCoreFieldsToJson(root, pendingEdit.getCoreFields(), submittedFields);
|
||||
ProductPendingEditFieldMapper.writeFixedDepositFieldsToJson(root, pendingEdit.getFixedDepositFields(), submittedFields);
|
||||
ProductPendingEditFieldMapper.writeRecurringDepositFieldsToJson(root, pendingEdit.getRecurringDepositFields(), submittedFields);
|
||||
if (submittedFields.contains("glAccountMapping")) {
|
||||
ProductPendingEditFieldMapper.writeGlAccountMappingToJson(root, pendingEdit.getGlAccountMappingFields());
|
||||
}
|
||||
if (submittedFields.contains("charges")) {
|
||||
ProductPendingEditFieldMapper.writeChargesToJson(root,
|
||||
this.pendingEditChargeRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
if (submittedFields.contains("glArrayMappings")) {
|
||||
ProductPendingEditFieldMapper.writeGlArrayMappingsToJson(root,
|
||||
this.pendingEditGlMappingRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
final JsonCommand replayedCommand = JsonCommand.fromJsonElement(productId, root, this.fromApiJsonHelper);
|
||||
final CommandProcessingResult result = updateInternal(productId, replayedCommand, false);
|
||||
|
||||
pendingEdit.markApproved(checker);
|
||||
this.productPendingEditRepository.saveAndFlush(pendingEdit);
|
||||
@@ -239,12 +309,33 @@ public class RecurringDepositProductWritePlatformServiceJpaRepositoryImpl implem
|
||||
return existing.get();
|
||||
}
|
||||
}
|
||||
final Set<String> submittedFields = new java.util.HashSet<>(
|
||||
this.pendingEditSubmittedFieldRepository.findFieldNamesByPendingEditId(pendingEdit.getId()));
|
||||
final JsonObject root = new JsonObject();
|
||||
root.addProperty("locale", "en");
|
||||
root.addProperty("dateFormat", "yyyy-MM-dd");
|
||||
ProductPendingEditFieldMapper.writeCoreFieldsToJson(root, pendingEdit.getCoreFields(), submittedFields);
|
||||
ProductPendingEditFieldMapper.writeFixedDepositFieldsToJson(root, pendingEdit.getFixedDepositFields(), submittedFields);
|
||||
ProductPendingEditFieldMapper.writeRecurringDepositFieldsToJson(root, pendingEdit.getRecurringDepositFields(), submittedFields);
|
||||
if (submittedFields.contains("glAccountMapping")) {
|
||||
ProductPendingEditFieldMapper.writeGlAccountMappingToJson(root, pendingEdit.getGlAccountMappingFields());
|
||||
}
|
||||
if (submittedFields.contains("charges")) {
|
||||
ProductPendingEditFieldMapper.writeChargesToJson(root,
|
||||
this.pendingEditChargeRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
if (submittedFields.contains("glArrayMappings")) {
|
||||
ProductPendingEditFieldMapper.writeGlArrayMappingsToJson(root,
|
||||
this.pendingEditGlMappingRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
final String commandJson = GSON.toJson(root);
|
||||
|
||||
final CommandSource auditEntry = CommandSource.builder() //
|
||||
.actionName("UPDATE") //
|
||||
.entityName("RECURRINGDEPOSITPRODUCT") //
|
||||
.resourceGetUrl("/recurringdepositproducts/" + productId) //
|
||||
.resourceId(productId) //
|
||||
.commandAsJson(pendingEdit.getProposedPayloadJson()) //
|
||||
.commandAsJson(commandJson) //
|
||||
.maker(pendingEdit.getMaker()) //
|
||||
.madeOnDate(DateUtils.getAuditOffsetDateTime()) //
|
||||
.status(CommandProcessingResultType.AWAITING_APPROVAL.getValue()) //
|
||||
|
||||
+49
-32
@@ -45,12 +45,19 @@ import org.apache.fineract.portfolio.savings.domain.SavingsProductDepositLimitKy
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityConfigRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityLimitRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductDepositLimitKycRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEdit;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditSubmittedFieldRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditChargeRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditGlMappingRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditFieldMapper;
|
||||
import org.apache.fineract.portfolio.savings.exception.SavingsProductNoPendingEditException;
|
||||
import org.apache.fineract.portfolio.savings.exception.SavingsProductNotFoundException;
|
||||
import org.apache.fineract.portfolio.tax.data.TaxGroupData;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import java.util.Set;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class SavingsProductReadPlatformServiceImpl implements SavingsProductReadPlatformService {
|
||||
@@ -63,6 +70,10 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
|
||||
private final SavingsProductFacilityConfigRepository facilityConfigRepository;
|
||||
private final SavingsProductFacilityLimitRepository facilityLimitRepository;
|
||||
private final SavingsProductDepositLimitKycRepository depositLimitKycRepository;
|
||||
private final ProductPendingEditRepository productPendingEditRepository;
|
||||
private final ProductPendingEditSubmittedFieldRepository pendingEditSubmittedFieldRepository;
|
||||
private final ProductPendingEditChargeRepository pendingEditChargeRepository;
|
||||
private final ProductPendingEditGlMappingRepository pendingEditGlMappingRepository;
|
||||
private static final Gson GSON = new Gson();
|
||||
private static final Type OTHER_GL_MAPPINGS_TYPE = new TypeToken<List<Map<String, Object>>>() {}.getType();
|
||||
private static final Type OTHER_GL_MAPPINGS_MAP_TYPE = new TypeToken<Map<String, List<Map<String, Object>>>>() {}.getType();
|
||||
@@ -173,43 +184,49 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
|
||||
}
|
||||
|
||||
private static final String PENDING_EDIT_SCHEMA = "spt.id as tempId, spt.product_id as savingsProductId, "
|
||||
+ "sp.name as savingsProductName, spt.maker_id as makerId, maker.username as makerUsername, "
|
||||
+ "spt.checker_id as checkerId, checker.username as checkerUsername, spt.created_on as createdOn, "
|
||||
+ "spt.checked_on as checkedOn, spt.status as status, spt.reject_reason as rejectReason, "
|
||||
+ "spt.proposed_payload_json as proposedPayloadJson "
|
||||
+ "from m_savings_product_temp spt "
|
||||
+ "sp.name as savingsProductName, spt.createdby_id as makerId, maker.username as makerUsername, "
|
||||
+ "spt.lastmodifiedby_id as checkerId, checker.username as checkerUsername, spt.created_date as createdOn, "
|
||||
+ "spt.lastmodified_date as checkedOn, spt.status as status, spt.reject_reason as rejectReason "
|
||||
+ "from m_saving_product_temp spt "
|
||||
+ "join m_savings_product sp on sp.id = spt.product_id "
|
||||
+ "join m_appuser maker on maker.id = spt.maker_id "
|
||||
+ "left join m_appuser checker on checker.id = spt.checker_id "
|
||||
+ "join m_appuser maker on maker.id = spt.createdby_id "
|
||||
+ "left join m_appuser checker on checker.id = spt.lastmodifiedby_id "
|
||||
+ "where spt.product_type = 'SAVINGS' ";
|
||||
|
||||
private static final RowMapper<SavingsProductTempData> PENDING_EDIT_MAPPER = (rs, rowNum) -> {
|
||||
final SavingsProductTempData data = new SavingsProductTempData();
|
||||
data.setId(rs.getLong("tempId"));
|
||||
data.setSavingsProductId(rs.getLong("savingsProductId"));
|
||||
data.setSavingsProductName(rs.getString("savingsProductName"));
|
||||
data.setMakerId(rs.getLong("makerId"));
|
||||
data.setMakerUsername(rs.getString("makerUsername"));
|
||||
data.setCheckerId(JdbcSupport.getLong(rs, "checkerId"));
|
||||
data.setCheckerUsername(rs.getString("checkerUsername"));
|
||||
data.setCreatedOn(rs.getTimestamp("createdOn") == null ? null : rs.getTimestamp("createdOn").toLocalDateTime());
|
||||
data.setCheckedOn(rs.getTimestamp("checkedOn") == null ? null : rs.getTimestamp("checkedOn").toLocalDateTime());
|
||||
data.setStatus(rs.getString("status"));
|
||||
data.setRejectReason(rs.getString("rejectReason"));
|
||||
final String proposedPayloadJson = rs.getString("proposedPayloadJson");
|
||||
if (proposedPayloadJson != null) {
|
||||
final Map<String, Object> proposedChanges = GSON.fromJson(proposedPayloadJson,
|
||||
new TypeToken<Map<String, Object>>() {}.getType());
|
||||
data.setProposedChanges(proposedChanges);
|
||||
}
|
||||
return data;
|
||||
};
|
||||
private RowMapper<SavingsProductTempData> getPendingEditRowMapper() {
|
||||
return (rs, rowNum) -> {
|
||||
final SavingsProductTempData data = new SavingsProductTempData();
|
||||
data.setId(rs.getLong("tempId"));
|
||||
data.setSavingsProductId(rs.getLong("savingsProductId"));
|
||||
data.setSavingsProductName(rs.getString("savingsProductName"));
|
||||
data.setMakerId(rs.getLong("makerId"));
|
||||
data.setMakerUsername(rs.getString("makerUsername"));
|
||||
data.setCheckerId(JdbcSupport.getLong(rs, "checkerId"));
|
||||
data.setCheckerUsername(rs.getString("checkerUsername"));
|
||||
data.setCreatedOn(rs.getTimestamp("createdOn") == null ? null : rs.getTimestamp("createdOn").toLocalDateTime());
|
||||
data.setCheckedOn(rs.getTimestamp("checkedOn") == null ? null : rs.getTimestamp("checkedOn").toLocalDateTime());
|
||||
data.setStatus(rs.getString("status"));
|
||||
data.setRejectReason(rs.getString("rejectReason"));
|
||||
|
||||
final Long tempId = data.getId();
|
||||
final java.util.Optional<ProductPendingEdit> opt = this.productPendingEditRepository.findById(tempId);
|
||||
if (opt.isPresent()) {
|
||||
final ProductPendingEdit pendingEdit = opt.get();
|
||||
final Set<String> submittedFields = new java.util.HashSet<>(
|
||||
this.pendingEditSubmittedFieldRepository.findFieldNamesByPendingEditId(pendingEdit.getId()));
|
||||
final Map<String, Object> proposedChanges = ProductPendingEditFieldMapper.reconstructProposedChangesMap(
|
||||
pendingEdit, submittedFields, this.pendingEditChargeRepository, this.pendingEditGlMappingRepository, null, GSON);
|
||||
data.setProposedChanges(proposedChanges);
|
||||
}
|
||||
return data;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SavingsProductTempData> retrieveAllPendingEdits() {
|
||||
this.context.authenticatedUser();
|
||||
final String sql = "select " + PENDING_EDIT_SCHEMA + "and spt.status = 'PENDING' order by spt.created_on desc";
|
||||
return this.jdbcTemplate.query(sql, PENDING_EDIT_MAPPER);
|
||||
final String sql = "select " + PENDING_EDIT_SCHEMA + "and spt.status = 'PENDING' order by spt.created_date desc";
|
||||
return this.jdbcTemplate.query(sql, getPendingEditRowMapper());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -217,7 +234,7 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
|
||||
this.context.authenticatedUser();
|
||||
final String sql = "select " + PENDING_EDIT_SCHEMA + "and spt.status = 'PENDING' and spt.product_id = ?";
|
||||
try {
|
||||
return this.jdbcTemplate.queryForObject(sql, PENDING_EDIT_MAPPER, new Object[] { productId }); // NOSONAR
|
||||
return this.jdbcTemplate.queryForObject(sql, getPendingEditRowMapper(), new Object[] { productId }); // NOSONAR
|
||||
} catch (final EmptyResultDataAccessException e) {
|
||||
throw new SavingsProductNoPendingEditException(productId);
|
||||
}
|
||||
@@ -271,7 +288,7 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
|
||||
sqlBuilder.append("sp.enable_lockin_period as enableLockinPeriod, ");
|
||||
sqlBuilder.append("sp.balance_frequency as balanceFrequency, ");
|
||||
sqlBuilder.append("sp.account_closed_zero_balance_in_day_closing as accountClosedZeroBalanceInDayClosing, ");
|
||||
sqlBuilder.append("exists(select 1 from m_savings_product_temp spt where spt.product_id = sp.id "
|
||||
sqlBuilder.append("exists(select 1 from m_saving_product_temp spt where spt.product_id = sp.id "
|
||||
+ "and spt.product_type = 'SAVINGS' and spt.status = 'PENDING') as isPendingApproval ");
|
||||
|
||||
sqlBuilder.append("from m_savings_product sp ");
|
||||
|
||||
+53
-42
@@ -87,6 +87,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
@RequiredArgsConstructor
|
||||
public class SavingsProductWritePlatformServiceJpaRepositoryImpl implements SavingsProductWritePlatformService {
|
||||
|
||||
private static final com.google.gson.Gson GSON = new com.google.gson.Gson();
|
||||
private final PlatformSecurityContext context;
|
||||
private final SavingsProductRepository savingProductRepository;
|
||||
private final SavingsProductDataValidator fromApiJsonDataValidator;
|
||||
@@ -324,7 +325,7 @@ public class SavingsProductWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
// Reuses the same validator the direct-update path uses, so bad data can't sit "pending" undetected.
|
||||
this.fromApiJsonDataValidator.validateForUpdate(command.json(), product);
|
||||
|
||||
final ProductPendingEdit pendingEdit = new ProductPendingEdit(ProductPendingEdit.TYPE_SAVINGS, productId, maker, command.json());
|
||||
final ProductPendingEdit pendingEdit = new ProductPendingEdit(ProductPendingEdit.TYPE_SAVINGS, productId, maker);
|
||||
|
||||
// Typed-column storage: extract every recognised field into the pending edit's own columns
|
||||
// (plus satellite rows for the 1:many pieces) instead of relying solely on the JSON blob
|
||||
@@ -409,44 +410,32 @@ public class SavingsProductWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
throw new SavingsProductSelfApprovalNotAllowedException(productId);
|
||||
}
|
||||
|
||||
// Replay through the real update path so charges, GL/accounting mappings and other related
|
||||
// tables are applied exactly as a direct edit would apply them - not hand-copied field by
|
||||
// field. The replay JSON is rebuilt from this row's typed columns/satellite tables (the
|
||||
// manifest records exactly which top-level parameters the maker actually submitted); pending
|
||||
// edits created before this cutover have no manifest rows, so they fall back to replaying the
|
||||
// legacy JSON blob directly.
|
||||
final Set<String> submittedFields = new java.util.HashSet<>(
|
||||
this.pendingEditSubmittedFieldRepository.findFieldNamesByPendingEditId(pendingEdit.getId()));
|
||||
final JsonCommand replayedCommand;
|
||||
if (submittedFields.isEmpty()) {
|
||||
replayedCommand = JsonCommand.fromJsonElement(productId, this.fromApiJsonHelper.parse(pendingEdit.getProposedPayloadJson()),
|
||||
this.fromApiJsonHelper);
|
||||
} else {
|
||||
final JsonObject root = new JsonObject();
|
||||
root.addProperty("locale", "en");
|
||||
root.addProperty("dateFormat", "yyyy-MM-dd");
|
||||
ProductPendingEditFieldMapper.writeCoreFieldsToJson(root, pendingEdit.getCoreFields(), submittedFields);
|
||||
ProductPendingEditFieldMapper.writeFacilityConfigToJson(root, pendingEdit.getFacilityConfigFields(),
|
||||
submittedFields.contains("accountFacilityConfig"));
|
||||
ProductPendingEditFieldMapper.writeDepositLimitKycToJson(root, pendingEdit.getDepositLimitKycFields(),
|
||||
submittedFields.contains("depositLimitKyc"));
|
||||
if (submittedFields.contains("glAccountMapping")) {
|
||||
ProductPendingEditFieldMapper.writeGlAccountMappingToJson(root, pendingEdit.getGlAccountMappingFields());
|
||||
}
|
||||
if (submittedFields.contains("charges")) {
|
||||
ProductPendingEditFieldMapper.writeChargesToJson(root,
|
||||
this.pendingEditChargeRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
if (submittedFields.contains("accountFacilityLimits")) {
|
||||
ProductPendingEditFieldMapper.writeFacilityLimitsToJson(root,
|
||||
this.pendingEditFacilityLimitRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
if (submittedFields.contains("glArrayMappings")) {
|
||||
ProductPendingEditFieldMapper.writeGlArrayMappingsToJson(root,
|
||||
this.pendingEditGlMappingRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
replayedCommand = JsonCommand.fromJsonElement(productId, root, this.fromApiJsonHelper);
|
||||
final JsonObject root = new JsonObject();
|
||||
root.addProperty("locale", "en");
|
||||
root.addProperty("dateFormat", "yyyy-MM-dd");
|
||||
ProductPendingEditFieldMapper.writeCoreFieldsToJson(root, pendingEdit.getCoreFields(), submittedFields);
|
||||
ProductPendingEditFieldMapper.writeFacilityConfigToJson(root, pendingEdit.getFacilityConfigFields(),
|
||||
submittedFields.contains("accountFacilityConfig"));
|
||||
ProductPendingEditFieldMapper.writeDepositLimitKycToJson(root, pendingEdit.getDepositLimitKycFields(),
|
||||
submittedFields.contains("depositLimitKyc"));
|
||||
if (submittedFields.contains("glAccountMapping")) {
|
||||
ProductPendingEditFieldMapper.writeGlAccountMappingToJson(root, pendingEdit.getGlAccountMappingFields());
|
||||
}
|
||||
if (submittedFields.contains("charges")) {
|
||||
ProductPendingEditFieldMapper.writeChargesToJson(root,
|
||||
this.pendingEditChargeRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
if (submittedFields.contains("accountFacilityLimits")) {
|
||||
ProductPendingEditFieldMapper.writeFacilityLimitsToJson(root,
|
||||
this.pendingEditFacilityLimitRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
if (submittedFields.contains("glArrayMappings")) {
|
||||
ProductPendingEditFieldMapper.writeGlArrayMappingsToJson(root,
|
||||
this.pendingEditGlMappingRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
final JsonCommand replayedCommand = JsonCommand.fromJsonElement(productId, root, this.fromApiJsonHelper);
|
||||
final CommandProcessingResult result = update(productId, replayedCommand);
|
||||
|
||||
pendingEdit.markApproved(checker);
|
||||
@@ -460,11 +449,6 @@ public class SavingsProductWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Every edit submitted through submitEditForApproval() links a CommandSource audit row. This fallback only
|
||||
* matters for pending edits that were created before that linking existed - it backfills one now so approve
|
||||
* and reject always leave an entry in m_portfolio_command_source, with no silent no-op case.
|
||||
*/
|
||||
private CommandSource findOrCreateAuditEntry(final ProductPendingEdit pendingEdit, final Long productId) {
|
||||
if (pendingEdit.getCommandSourceId() != null) {
|
||||
final java.util.Optional<CommandSource> existing = this.commandSourceRepository.findById(pendingEdit.getCommandSourceId());
|
||||
@@ -472,12 +456,39 @@ public class SavingsProductWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
return existing.get();
|
||||
}
|
||||
}
|
||||
final Set<String> submittedFields = new java.util.HashSet<>(
|
||||
this.pendingEditSubmittedFieldRepository.findFieldNamesByPendingEditId(pendingEdit.getId()));
|
||||
final JsonObject root = new JsonObject();
|
||||
root.addProperty("locale", "en");
|
||||
root.addProperty("dateFormat", "yyyy-MM-dd");
|
||||
ProductPendingEditFieldMapper.writeCoreFieldsToJson(root, pendingEdit.getCoreFields(), submittedFields);
|
||||
ProductPendingEditFieldMapper.writeFacilityConfigToJson(root, pendingEdit.getFacilityConfigFields(),
|
||||
submittedFields.contains("accountFacilityConfig"));
|
||||
ProductPendingEditFieldMapper.writeDepositLimitKycToJson(root, pendingEdit.getDepositLimitKycFields(),
|
||||
submittedFields.contains("depositLimitKyc"));
|
||||
if (submittedFields.contains("glAccountMapping")) {
|
||||
ProductPendingEditFieldMapper.writeGlAccountMappingToJson(root, pendingEdit.getGlAccountMappingFields());
|
||||
}
|
||||
if (submittedFields.contains("charges")) {
|
||||
ProductPendingEditFieldMapper.writeChargesToJson(root,
|
||||
this.pendingEditChargeRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
if (submittedFields.contains("accountFacilityLimits")) {
|
||||
ProductPendingEditFieldMapper.writeFacilityLimitsToJson(root,
|
||||
this.pendingEditFacilityLimitRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
if (submittedFields.contains("glArrayMappings")) {
|
||||
ProductPendingEditFieldMapper.writeGlArrayMappingsToJson(root,
|
||||
this.pendingEditGlMappingRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
final String commandJson = GSON.toJson(root);
|
||||
|
||||
final CommandSource auditEntry = CommandSource.builder() //
|
||||
.actionName("UPDATE") //
|
||||
.entityName("SAVINGSPRODUCT") //
|
||||
.resourceGetUrl("/savingsproducts/" + productId) //
|
||||
.resourceId(productId) //
|
||||
.commandAsJson(pendingEdit.getProposedPayloadJson()) //
|
||||
.commandAsJson(commandJson) //
|
||||
.maker(pendingEdit.getMaker()) //
|
||||
.madeOnDate(DateUtils.getAuditOffsetDateTime()) //
|
||||
.status(CommandProcessingResultType.AWAITING_APPROVAL.getValue()) //
|
||||
|
||||
+33
-8
@@ -97,6 +97,9 @@ import org.apache.fineract.portfolio.savings.domain.SavingsProductDepositLimitKy
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityConfig;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityConfigRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditSubmittedFieldRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditChargeRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditGlMappingRepository;
|
||||
import org.apache.fineract.commands.domain.CommandSourceRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityLimit;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityLimitRepository;
|
||||
@@ -311,8 +314,14 @@ public class SavingsConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(DepositProductReadPlatformService.class)
|
||||
public DepositProductReadPlatformService depositProductReadPlatformService(PlatformSecurityContext context, JdbcTemplate jdbcTemplate,
|
||||
InterestRateChartReadPlatformService interestRateChartReadPlatformService) {
|
||||
return new DepositProductReadPlatformServiceImpl(context, jdbcTemplate, interestRateChartReadPlatformService);
|
||||
InterestRateChartReadPlatformService interestRateChartReadPlatformService,
|
||||
ProductPendingEditRepository productPendingEditRepository,
|
||||
ProductPendingEditSubmittedFieldRepository pendingEditSubmittedFieldRepository,
|
||||
ProductPendingEditChargeRepository pendingEditChargeRepository,
|
||||
ProductPendingEditGlMappingRepository pendingEditGlMappingRepository) {
|
||||
return new DepositProductReadPlatformServiceImpl(context, jdbcTemplate, interestRateChartReadPlatformService,
|
||||
productPendingEditRepository, pendingEditSubmittedFieldRepository,
|
||||
pendingEditChargeRepository, pendingEditGlMappingRepository);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -327,11 +336,16 @@ public class SavingsConfiguration {
|
||||
FixedDepositProductRepository fixedDepositProductRepository, DepositProductDataValidator fromApiJsonDataValidator,
|
||||
DepositProductAssembler depositProductAssembler,
|
||||
ProductToGLAccountMappingWritePlatformService accountMappingWritePlatformService, InterestRateChartAssembler chartAssembler,
|
||||
ProductPendingEditRepository productPendingEditRepository, FromJsonHelper fromApiJsonHelper,
|
||||
ProductPendingEditRepository productPendingEditRepository,
|
||||
ProductPendingEditSubmittedFieldRepository pendingEditSubmittedFieldRepository,
|
||||
ProductPendingEditChargeRepository pendingEditChargeRepository,
|
||||
ProductPendingEditGlMappingRepository pendingEditGlMappingRepository,
|
||||
FromJsonHelper fromApiJsonHelper,
|
||||
CommandSourceRepository commandSourceRepository) {
|
||||
return new FixedDepositProductWritePlatformServiceJpaRepositoryImpl(context, fixedDepositProductRepository,
|
||||
fromApiJsonDataValidator, depositProductAssembler, accountMappingWritePlatformService, chartAssembler,
|
||||
productPendingEditRepository, fromApiJsonHelper, commandSourceRepository);
|
||||
productPendingEditRepository, pendingEditSubmittedFieldRepository, pendingEditChargeRepository,
|
||||
pendingEditGlMappingRepository, fromApiJsonHelper, commandSourceRepository);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -354,11 +368,16 @@ public class SavingsConfiguration {
|
||||
RecurringDepositProductRepository recurringDepositProductRepository, DepositProductDataValidator fromApiJsonDataValidator,
|
||||
DepositProductAssembler depositProductAssembler,
|
||||
ProductToGLAccountMappingWritePlatformService accountMappingWritePlatformService, InterestRateChartAssembler chartAssembler,
|
||||
ProductPendingEditRepository productPendingEditRepository, FromJsonHelper fromApiJsonHelper,
|
||||
ProductPendingEditRepository productPendingEditRepository,
|
||||
ProductPendingEditSubmittedFieldRepository pendingEditSubmittedFieldRepository,
|
||||
ProductPendingEditChargeRepository pendingEditChargeRepository,
|
||||
ProductPendingEditGlMappingRepository pendingEditGlMappingRepository,
|
||||
FromJsonHelper fromApiJsonHelper,
|
||||
CommandSourceRepository commandSourceRepository) {
|
||||
return new RecurringDepositProductWritePlatformServiceJpaRepositoryImpl(context, recurringDepositProductRepository,
|
||||
fromApiJsonDataValidator, depositProductAssembler, accountMappingWritePlatformService, chartAssembler,
|
||||
productPendingEditRepository, fromApiJsonHelper, commandSourceRepository);
|
||||
productPendingEditRepository, pendingEditSubmittedFieldRepository, pendingEditChargeRepository,
|
||||
pendingEditGlMappingRepository, fromApiJsonHelper, commandSourceRepository);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -481,9 +500,15 @@ public class SavingsConfiguration {
|
||||
@ConditionalOnMissingBean(SavingsProductReadPlatformService.class)
|
||||
public SavingsProductReadPlatformService savingsProductReadPlatformService(PlatformSecurityContext context, JdbcTemplate jdbcTemplate,
|
||||
FineractEntityAccessUtil fineractEntityAccessUtil, SavingsProductFacilityConfigRepository facilityConfigRepository,
|
||||
SavingsProductFacilityLimitRepository facilityLimitRepository, SavingsProductDepositLimitKycRepository depositLimitKycRepository) {
|
||||
SavingsProductFacilityLimitRepository facilityLimitRepository, SavingsProductDepositLimitKycRepository depositLimitKycRepository,
|
||||
ProductPendingEditRepository productPendingEditRepository,
|
||||
ProductPendingEditSubmittedFieldRepository pendingEditSubmittedFieldRepository,
|
||||
ProductPendingEditChargeRepository pendingEditChargeRepository,
|
||||
ProductPendingEditGlMappingRepository pendingEditGlMappingRepository) {
|
||||
return new SavingsProductReadPlatformServiceImpl(context, jdbcTemplate, fineractEntityAccessUtil, facilityConfigRepository,
|
||||
facilityLimitRepository, depositLimitKycRepository);
|
||||
facilityLimitRepository, depositLimitKycRepository,
|
||||
productPendingEditRepository, pendingEditSubmittedFieldRepository,
|
||||
pendingEditChargeRepository, pendingEditGlMappingRepository);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
+47
-29
@@ -56,6 +56,12 @@ import org.apache.fineract.portfolio.shareproducts.exception.ShareProductNoPendi
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEdit;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditSubmittedFieldRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditChargeRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditGlMappingRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditFieldMapper;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class ShareProductReadPlatformServiceImpl implements ShareProductReadPlatformService {
|
||||
@@ -66,6 +72,10 @@ public class ShareProductReadPlatformServiceImpl implements ShareProductReadPlat
|
||||
private final ShareProductDropdownReadPlatformService shareProductDropdownReadPlatformService;
|
||||
private final AccountingDropdownReadPlatformService accountingDropdownReadPlatformService;
|
||||
private final ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService;
|
||||
private final ProductPendingEditRepository productPendingEditRepository;
|
||||
private final ProductPendingEditSubmittedFieldRepository pendingEditSubmittedFieldRepository;
|
||||
private final ProductPendingEditChargeRepository pendingEditChargeRepository;
|
||||
private final ProductPendingEditGlMappingRepository pendingEditGlMappingRepository;
|
||||
private final PaginationHelper shareProductDataPaginationHelper;
|
||||
private final DatabaseSpecificSQLGenerator sqlGenerator;
|
||||
|
||||
@@ -159,47 +169,55 @@ public class ShareProductReadPlatformServiceImpl implements ShareProductReadPlat
|
||||
private static final Gson GSON = new Gson();
|
||||
|
||||
private static final String PENDING_EDIT_SCHEMA = "spt.id as tempId, spt.product_id as savingsProductId, "
|
||||
+ "sp.name as savingsProductName, spt.maker_id as makerId, maker.username as makerUsername, "
|
||||
+ "spt.checker_id as checkerId, checker.username as checkerUsername, spt.created_on as createdOn, "
|
||||
+ "spt.checked_on as checkedOn, spt.status as status, spt.reject_reason as rejectReason, "
|
||||
+ "spt.proposed_payload_json as proposedPayloadJson "
|
||||
+ "from m_savings_product_temp spt "
|
||||
+ "sp.name as savingsProductName, spt.createdby_id as makerId, maker.username as makerUsername, "
|
||||
+ "spt.lastmodifiedby_id as checkerId, checker.username as checkerUsername, spt.created_date as createdOn, "
|
||||
+ "spt.lastmodified_date as checkedOn, spt.status as status, spt.reject_reason as rejectReason "
|
||||
+ "from m_saving_product_temp spt "
|
||||
+ "join m_share_product sp on sp.id = spt.product_id "
|
||||
+ "join m_appuser maker on maker.id = spt.maker_id "
|
||||
+ "left join m_appuser checker on checker.id = spt.checker_id "
|
||||
+ "join m_appuser maker on maker.id = spt.createdby_id "
|
||||
+ "left join m_appuser checker on checker.id = spt.lastmodifiedby_id "
|
||||
+ "where spt.product_type = 'SHARE' ";
|
||||
|
||||
private static final RowMapper<SavingsProductTempData> PENDING_EDIT_MAPPER = (rs, rowNum) -> {
|
||||
final SavingsProductTempData data = new SavingsProductTempData();
|
||||
data.setId(rs.getLong("tempId"));
|
||||
data.setSavingsProductId(rs.getLong("savingsProductId"));
|
||||
data.setSavingsProductName(rs.getString("savingsProductName"));
|
||||
data.setMakerId(rs.getLong("makerId"));
|
||||
data.setMakerUsername(rs.getString("makerUsername"));
|
||||
data.setCheckerId(JdbcSupport.getLong(rs, "checkerId"));
|
||||
data.setCheckerUsername(rs.getString("checkerUsername"));
|
||||
data.setCreatedOn(rs.getTimestamp("createdOn") == null ? null : rs.getTimestamp("createdOn").toLocalDateTime());
|
||||
data.setCheckedOn(rs.getTimestamp("checkedOn") == null ? null : rs.getTimestamp("checkedOn").toLocalDateTime());
|
||||
data.setStatus(rs.getString("status"));
|
||||
data.setRejectReason(rs.getString("rejectReason"));
|
||||
final String proposedPayloadJson = rs.getString("proposedPayloadJson");
|
||||
if (proposedPayloadJson != null) {
|
||||
data.setProposedChanges(GSON.fromJson(proposedPayloadJson, new TypeToken<Map<String, Object>>() {}.getType()));
|
||||
}
|
||||
return data;
|
||||
};
|
||||
private RowMapper<SavingsProductTempData> getPendingEditRowMapper() {
|
||||
return (rs, rowNum) -> {
|
||||
final SavingsProductTempData data = new SavingsProductTempData();
|
||||
data.setId(rs.getLong("tempId"));
|
||||
data.setSavingsProductId(rs.getLong("savingsProductId"));
|
||||
data.setSavingsProductName(rs.getString("savingsProductName"));
|
||||
data.setMakerId(rs.getLong("makerId"));
|
||||
data.setMakerUsername(rs.getString("makerUsername"));
|
||||
data.setCheckerId(JdbcSupport.getLong(rs, "checkerId"));
|
||||
data.setCheckerUsername(rs.getString("checkerUsername"));
|
||||
data.setCreatedOn(rs.getTimestamp("createdOn") == null ? null : rs.getTimestamp("createdOn").toLocalDateTime());
|
||||
data.setCheckedOn(rs.getTimestamp("checkedOn") == null ? null : rs.getTimestamp("checkedOn").toLocalDateTime());
|
||||
data.setStatus(rs.getString("status"));
|
||||
data.setRejectReason(rs.getString("rejectReason"));
|
||||
|
||||
final Long tempId = data.getId();
|
||||
final java.util.Optional<ProductPendingEdit> opt = this.productPendingEditRepository.findById(tempId);
|
||||
if (opt.isPresent()) {
|
||||
final ProductPendingEdit pendingEdit = opt.get();
|
||||
final Set<String> submittedFields = new java.util.HashSet<>(
|
||||
this.pendingEditSubmittedFieldRepository.findFieldNamesByPendingEditId(pendingEdit.getId()));
|
||||
final Map<String, Object> proposedChanges = ProductPendingEditFieldMapper.reconstructProposedChangesMap(
|
||||
pendingEdit, submittedFields, this.pendingEditChargeRepository, this.pendingEditGlMappingRepository, null, GSON);
|
||||
data.setProposedChanges(proposedChanges);
|
||||
}
|
||||
return data;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SavingsProductTempData> retrieveAllPendingEdits() {
|
||||
final String sql = "select " + PENDING_EDIT_SCHEMA + "and spt.status = 'PENDING' order by spt.created_on desc";
|
||||
return this.jdbcTemplate.query(sql, PENDING_EDIT_MAPPER);
|
||||
final String sql = "select " + PENDING_EDIT_SCHEMA + "and spt.status = 'PENDING' order by spt.created_date desc";
|
||||
return this.jdbcTemplate.query(sql, getPendingEditRowMapper());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SavingsProductTempData retrievePendingEdit(final Long productId) {
|
||||
final String sql = "select " + PENDING_EDIT_SCHEMA + "and spt.status = 'PENDING' and spt.product_id = ?";
|
||||
try {
|
||||
return this.jdbcTemplate.queryForObject(sql, PENDING_EDIT_MAPPER, new Object[] { productId }); // NOSONAR
|
||||
return this.jdbcTemplate.queryForObject(sql, getPendingEditRowMapper(), new Object[] { productId }); // NOSONAR
|
||||
} catch (final EmptyResultDataAccessException e) {
|
||||
throw new ShareProductNoPendingEditException(productId);
|
||||
}
|
||||
|
||||
+75
-4
@@ -22,7 +22,9 @@ import com.google.gson.JsonElement;
|
||||
import jakarta.persistence.PersistenceException;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
@@ -52,6 +54,14 @@ import org.apache.fineract.portfolio.shareproducts.exception.ShareProductEditPen
|
||||
import org.apache.fineract.portfolio.shareproducts.exception.ShareProductNoPendingEditException;
|
||||
import org.apache.fineract.portfolio.shareproducts.exception.ShareProductSelfApprovalNotAllowedException;
|
||||
import org.apache.fineract.portfolio.shareproducts.serialization.ShareProductDataSerializer;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditSubmittedField;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditSubmittedFieldRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditCharge;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditChargeRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditGlMapping;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditGlMappingRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditFieldMapper;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.orm.jpa.JpaSystemException;
|
||||
@@ -61,6 +71,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
@RequiredArgsConstructor
|
||||
public class ShareProductWritePlatformServiceJpaRepositoryImpl implements ShareProductWritePlatformService {
|
||||
|
||||
private static final com.google.gson.Gson GSON = new com.google.gson.Gson();
|
||||
private final ShareProductRepositoryWrapper repository;
|
||||
private final ShareProductDataSerializer serializer;
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
@@ -70,6 +81,9 @@ public class ShareProductWritePlatformServiceJpaRepositoryImpl implements ShareP
|
||||
private final BusinessEventNotifierService businessEventNotifierService;
|
||||
private final PlatformSecurityContext context;
|
||||
private final ProductPendingEditRepository productPendingEditRepository;
|
||||
private final ProductPendingEditSubmittedFieldRepository pendingEditSubmittedFieldRepository;
|
||||
private final ProductPendingEditChargeRepository pendingEditChargeRepository;
|
||||
private final ProductPendingEditGlMappingRepository pendingEditGlMappingRepository;
|
||||
private final CommandSourceRepository commandSourceRepository;
|
||||
|
||||
@Override
|
||||
@@ -208,7 +222,13 @@ public class ShareProductWritePlatformServiceJpaRepositoryImpl implements ShareP
|
||||
throw new ShareProductEditPendingApprovalException(productId);
|
||||
}
|
||||
|
||||
final ProductPendingEdit pendingEdit = new ProductPendingEdit(ProductPendingEdit.TYPE_SHARE, productId, maker, command.json());
|
||||
final ProductPendingEdit pendingEdit = new ProductPendingEdit(ProductPendingEdit.TYPE_SHARE, productId, maker);
|
||||
|
||||
final java.util.Set<String> submitted = ProductPendingEditFieldMapper.populateShareOnlyFields(command, pendingEdit.getShareOnlyFields());
|
||||
final boolean glMappingSubmitted = ProductPendingEditFieldMapper.populateGlAccountMapping(command, pendingEdit.getGlAccountMappingFields());
|
||||
if (glMappingSubmitted) {
|
||||
submitted.add("glAccountMapping");
|
||||
}
|
||||
|
||||
final CommandSource auditEntry = CommandSource.builder() //
|
||||
.actionName("UPDATE") //
|
||||
@@ -227,6 +247,24 @@ public class ShareProductWritePlatformServiceJpaRepositoryImpl implements ShareP
|
||||
|
||||
this.productPendingEditRepository.saveAndFlush(pendingEdit);
|
||||
|
||||
for (final String fieldName : submitted) {
|
||||
this.pendingEditSubmittedFieldRepository.save(new ProductPendingEditSubmittedField(pendingEdit, fieldName));
|
||||
}
|
||||
|
||||
final List<Long> chargeIds = ProductPendingEditFieldMapper.extractChargeIds(command);
|
||||
if (chargeIds != null) {
|
||||
this.pendingEditSubmittedFieldRepository.save(new ProductPendingEditSubmittedField(pendingEdit, "charges"));
|
||||
for (final Long chargeId : chargeIds) {
|
||||
this.pendingEditChargeRepository.save(new ProductPendingEditCharge(pendingEdit, chargeId));
|
||||
}
|
||||
}
|
||||
|
||||
final List<ProductPendingEditGlMapping> glMappings = ProductPendingEditFieldMapper.extractGlArrayMappings(command, pendingEdit);
|
||||
if (glMappings != null) {
|
||||
this.pendingEditSubmittedFieldRepository.save(new ProductPendingEditSubmittedField(pendingEdit, "glArrayMappings"));
|
||||
this.pendingEditGlMappingRepository.saveAll(glMappings);
|
||||
}
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(product.getId()) //
|
||||
.build();
|
||||
@@ -245,8 +283,23 @@ public class ShareProductWritePlatformServiceJpaRepositoryImpl implements ShareP
|
||||
throw new ShareProductSelfApprovalNotAllowedException(productId);
|
||||
}
|
||||
|
||||
final JsonCommand replayedCommand = JsonCommand.fromJsonElement(productId,
|
||||
this.fromApiJsonHelper.parse(pendingEdit.getProposedPayloadJson()), this.fromApiJsonHelper);
|
||||
final Set<String> submittedFields = new java.util.HashSet<>(
|
||||
this.pendingEditSubmittedFieldRepository.findFieldNamesByPendingEditId(pendingEdit.getId()));
|
||||
final JsonObject root = new JsonObject();
|
||||
root.addProperty("locale", "en");
|
||||
ProductPendingEditFieldMapper.writeShareOnlyFieldsToJson(root, pendingEdit.getShareOnlyFields(), submittedFields);
|
||||
if (submittedFields.contains("glAccountMapping")) {
|
||||
ProductPendingEditFieldMapper.writeGlAccountMappingToJson(root, pendingEdit.getGlAccountMappingFields());
|
||||
}
|
||||
if (submittedFields.contains("charges")) {
|
||||
ProductPendingEditFieldMapper.writeChargesToJson(root,
|
||||
this.pendingEditChargeRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
if (submittedFields.contains("glArrayMappings")) {
|
||||
ProductPendingEditFieldMapper.writeGlArrayMappingsToJson(root,
|
||||
this.pendingEditGlMappingRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
final JsonCommand replayedCommand = JsonCommand.fromJsonElement(productId, root, this.fromApiJsonHelper);
|
||||
final CommandProcessingResult result = updateProduct(productId, replayedCommand);
|
||||
|
||||
pendingEdit.markApproved(checker);
|
||||
@@ -267,12 +320,30 @@ public class ShareProductWritePlatformServiceJpaRepositoryImpl implements ShareP
|
||||
return existing.get();
|
||||
}
|
||||
}
|
||||
final Set<String> submittedFields = new java.util.HashSet<>(
|
||||
this.pendingEditSubmittedFieldRepository.findFieldNamesByPendingEditId(pendingEdit.getId()));
|
||||
final JsonObject root = new JsonObject();
|
||||
root.addProperty("locale", "en");
|
||||
ProductPendingEditFieldMapper.writeShareOnlyFieldsToJson(root, pendingEdit.getShareOnlyFields(), submittedFields);
|
||||
if (submittedFields.contains("glAccountMapping")) {
|
||||
ProductPendingEditFieldMapper.writeGlAccountMappingToJson(root, pendingEdit.getGlAccountMappingFields());
|
||||
}
|
||||
if (submittedFields.contains("charges")) {
|
||||
ProductPendingEditFieldMapper.writeChargesToJson(root,
|
||||
this.pendingEditChargeRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
if (submittedFields.contains("glArrayMappings")) {
|
||||
ProductPendingEditFieldMapper.writeGlArrayMappingsToJson(root,
|
||||
this.pendingEditGlMappingRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
final String commandJson = GSON.toJson(root);
|
||||
|
||||
final CommandSource auditEntry = CommandSource.builder() //
|
||||
.actionName("UPDATE") //
|
||||
.entityName("SHAREPRODUCT") //
|
||||
.resourceGetUrl("/products/share/" + productId) //
|
||||
.resourceId(productId) //
|
||||
.commandAsJson(pendingEdit.getProposedPayloadJson()) //
|
||||
.commandAsJson(commandJson) //
|
||||
.maker(pendingEdit.getMaker()) //
|
||||
.madeOnDate(DateUtils.getAuditOffsetDateTime()) //
|
||||
.status(CommandProcessingResultType.AWAITING_APPROVAL.getValue()) //
|
||||
|
||||
+15
-2
@@ -32,6 +32,9 @@ import org.apache.fineract.organisation.monetary.service.CurrencyReadPlatformSer
|
||||
import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService;
|
||||
import org.apache.fineract.portfolio.products.service.ShareProductReadPlatformService;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditSubmittedFieldRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditChargeRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.ProductPendingEditGlMappingRepository;
|
||||
import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountReadPlatformService;
|
||||
import org.apache.fineract.portfolio.shareproducts.domain.ShareProductDividentPayOutDetailsRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.shareproducts.domain.ShareProductRepositoryWrapper;
|
||||
@@ -89,9 +92,15 @@ public class ShareProductsConfiguration {
|
||||
ShareProductDropdownReadPlatformService shareProductDropdownReadPlatformService,
|
||||
AccountingDropdownReadPlatformService accountingDropdownReadPlatformService,
|
||||
ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService,
|
||||
PaginationHelper shareProductDataPaginationHelper, DatabaseSpecificSQLGenerator sqlGenerator) {
|
||||
PaginationHelper shareProductDataPaginationHelper, DatabaseSpecificSQLGenerator sqlGenerator,
|
||||
ProductPendingEditRepository productPendingEditRepository,
|
||||
ProductPendingEditSubmittedFieldRepository pendingEditSubmittedFieldRepository,
|
||||
ProductPendingEditChargeRepository pendingEditChargeRepository,
|
||||
ProductPendingEditGlMappingRepository pendingEditGlMappingRepository) {
|
||||
return new ShareProductReadPlatformServiceImpl(jdbcTemplate, currencyReadPlatformService, chargeReadPlatformService,
|
||||
shareProductDropdownReadPlatformService, accountingDropdownReadPlatformService, accountMappingReadPlatformService,
|
||||
productPendingEditRepository, pendingEditSubmittedFieldRepository,
|
||||
pendingEditChargeRepository, pendingEditGlMappingRepository,
|
||||
shareProductDataPaginationHelper, sqlGenerator);
|
||||
}
|
||||
|
||||
@@ -105,10 +114,14 @@ public class ShareProductsConfiguration {
|
||||
BusinessEventNotifierService businessEventNotifierService,
|
||||
PlatformSecurityContext context,
|
||||
ProductPendingEditRepository productPendingEditRepository,
|
||||
ProductPendingEditSubmittedFieldRepository pendingEditSubmittedFieldRepository,
|
||||
ProductPendingEditChargeRepository pendingEditChargeRepository,
|
||||
ProductPendingEditGlMappingRepository pendingEditGlMappingRepository,
|
||||
CommandSourceRepository commandSourceRepository) {
|
||||
return new ShareProductWritePlatformServiceJpaRepositoryImpl(repository, serializer, fromApiJsonHelper,
|
||||
shareProductDividentPayOutDetailsRepository, shareProductDividendAssembler, accountMappingWritePlatformService,
|
||||
businessEventNotifierService, context, productPendingEditRepository, commandSourceRepository);
|
||||
businessEventNotifierService, context, productPendingEditRepository, pendingEditSubmittedFieldRepository,
|
||||
pendingEditChargeRepository, pendingEditGlMappingRepository, commandSourceRepository);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+8
-13
@@ -39,7 +39,7 @@ import org.apache.fineract.useradministration.domain.AppUser;
|
||||
* (covering charges, GL/accounting mappings and other related tables, not just scalar columns).
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "m_savings_product_temp")
|
||||
@Table(name = "m_saving_product_temp")
|
||||
@Getter
|
||||
@Setter
|
||||
public class ProductPendingEdit extends AbstractPersistableCustom<Long> {
|
||||
@@ -61,17 +61,17 @@ public class ProductPendingEdit extends AbstractPersistableCustom<Long> {
|
||||
private String productType;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "maker_id", nullable = false)
|
||||
@JoinColumn(name = "createdby_id", nullable = false)
|
||||
private AppUser maker;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "checker_id")
|
||||
@JoinColumn(name = "lastmodifiedby_id")
|
||||
private AppUser checker;
|
||||
|
||||
@Column(name = "created_on", nullable = false)
|
||||
@Column(name = "created_date", nullable = false)
|
||||
private LocalDateTime createdOn;
|
||||
|
||||
@Column(name = "checked_on")
|
||||
@Column(name = "lastmodified_date")
|
||||
private LocalDateTime checkedOn;
|
||||
|
||||
@Column(name = "status", nullable = false, length = 20)
|
||||
@@ -80,9 +80,7 @@ public class ProductPendingEdit extends AbstractPersistableCustom<Long> {
|
||||
@Column(name = "reject_reason", length = 500)
|
||||
private String rejectReason;
|
||||
|
||||
@Lob
|
||||
@Column(name = "proposed_payload_json", nullable = false)
|
||||
private String proposedPayloadJson;
|
||||
|
||||
|
||||
/**
|
||||
* "<productType>:<productId>" while PENDING, NULL otherwise - the real DB-level lock. Unique constraints treat
|
||||
@@ -130,11 +128,10 @@ public class ProductPendingEdit extends AbstractPersistableCustom<Long> {
|
||||
|
||||
protected ProductPendingEdit() {}
|
||||
|
||||
public ProductPendingEdit(final String productType, final Long productId, final AppUser maker, final String proposedPayloadJson) {
|
||||
public ProductPendingEdit(final String productType, final Long productId, final AppUser maker) {
|
||||
this.productType = productType;
|
||||
this.productId = productId;
|
||||
this.maker = maker;
|
||||
this.proposedPayloadJson = proposedPayloadJson;
|
||||
this.createdOn = LocalDateTime.now();
|
||||
this.status = STATUS_PENDING;
|
||||
this.pendingLockKey = lockKeyFor(productType, productId);
|
||||
@@ -176,9 +173,7 @@ public class ProductPendingEdit extends AbstractPersistableCustom<Long> {
|
||||
return this.rejectReason;
|
||||
}
|
||||
|
||||
public String getProposedPayloadJson() {
|
||||
return this.proposedPayloadJson;
|
||||
}
|
||||
|
||||
|
||||
public Long getCommandSourceId() {
|
||||
return this.commandSourceId;
|
||||
|
||||
+302
-2
@@ -20,6 +20,7 @@ package org.apache.fineract.portfolio.savings.domain;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -308,10 +309,25 @@ public final class ProductPendingEditFieldMapper {
|
||||
f.setAllowDebitTxnAfterDueDate(command.booleanObjectValueOfParameterNamed("allowDebitTxnAfterDueDate"));
|
||||
present.add("allowDebitTxnAfterDueDate");
|
||||
}
|
||||
if (command.hasParameter("depositTypeEnum")) {
|
||||
f.setDepositTypeEnum(command.integerValueOfParameterNamed("depositTypeEnum"));
|
||||
present.add("depositTypeEnum");
|
||||
}
|
||||
if (command.hasParameter("withdrawalFeeAmount")) {
|
||||
f.setWithdrawalFeeAmount(command.bigDecimalValueOfParameterNamed("withdrawalFeeAmount"));
|
||||
present.add("withdrawalFeeAmount");
|
||||
}
|
||||
if (command.hasParameter("withdrawalFeeTypeEnum")) {
|
||||
f.setWithdrawalFeeTypeEnum(command.integerValueOfParameterNamed("withdrawalFeeTypeEnum"));
|
||||
present.add("withdrawalFeeTypeEnum");
|
||||
}
|
||||
return present;
|
||||
}
|
||||
|
||||
public static void writeCoreFieldsToJson(final JsonObject root, final SavingsCoreEditFields f, final Set<String> submitted) {
|
||||
if (f == null) {
|
||||
return;
|
||||
}
|
||||
putString(root, submitted, "name", f.getName());
|
||||
putString(root, submitted, "shortName", f.getShortName());
|
||||
putString(root, submitted, "description", f.getDescription());
|
||||
@@ -377,6 +393,9 @@ public final class ProductPendingEditFieldMapper {
|
||||
putBoolean(root, submitted, "noPenaltyNomineeHeirClosure", f.getNoPenaltyNomineeHeirClosure());
|
||||
putBoolean(root, submitted, "deceasedSettlement", f.getDeceasedSettlement());
|
||||
putBoolean(root, submitted, "allowDebitTxnAfterDueDate", f.getAllowDebitTxnAfterDueDate());
|
||||
putNumber(root, submitted, "depositTypeEnum", f.getDepositTypeEnum());
|
||||
putNumber(root, submitted, "withdrawalFeeAmount", f.getWithdrawalFeeAmount());
|
||||
putNumber(root, submitted, "withdrawalFeeTypeEnum", f.getWithdrawalFeeTypeEnum());
|
||||
}
|
||||
|
||||
// ---- accountFacilityConfig (1:1 container) --------------------------------------------------
|
||||
@@ -405,7 +424,7 @@ public final class ProductPendingEditFieldMapper {
|
||||
}
|
||||
|
||||
public static void writeFacilityConfigToJson(final JsonObject root, final FacilityConfigEditFields f, final boolean submitted) {
|
||||
if (!submitted) {
|
||||
if (f == null || !submitted) {
|
||||
return;
|
||||
}
|
||||
final JsonObject config = new JsonObject();
|
||||
@@ -460,7 +479,7 @@ public final class ProductPendingEditFieldMapper {
|
||||
}
|
||||
|
||||
public static void writeDepositLimitKycToJson(final JsonObject root, final DepositLimitKycEditFields f, final boolean submitted) {
|
||||
if (!submitted) {
|
||||
if (f == null || !submitted) {
|
||||
return;
|
||||
}
|
||||
final JsonObject kyc = new JsonObject();
|
||||
@@ -505,6 +524,9 @@ public final class ProductPendingEditFieldMapper {
|
||||
}
|
||||
|
||||
public static void writeGlAccountMappingToJson(final JsonObject root, final GlAccountMappingEditFields f) {
|
||||
if (f == null) {
|
||||
return;
|
||||
}
|
||||
putNumber(root, "savingsReferenceAccountId", f.getSavingsReferenceAccountId());
|
||||
putNumber(root, "savingsControlAccountId", f.getSavingsControlAccountId());
|
||||
putNumber(root, "incomeFromFeeAccountId", f.getIncomeFromFeeAccountId());
|
||||
@@ -693,4 +715,282 @@ public final class ProductPendingEditFieldMapper {
|
||||
root.addProperty(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
public static Set<String> populateCurrentOnlyFields(final JsonCommand command, final CurrentOnlyEditFields f) {
|
||||
final Set<String> present = new java.util.HashSet<>();
|
||||
if (command.hasParameter("avgBalanceCalcPeriod")) {
|
||||
f.setAvgBalanceCalcPeriod(command.stringValueOfParameterNamed("avgBalanceCalcPeriod"));
|
||||
present.add("avgBalanceCalcPeriod");
|
||||
}
|
||||
if (command.hasParameter("validForPeriod")) {
|
||||
f.setValidForPeriod(command.stringValueOfParameterNamed("validForPeriod"));
|
||||
present.add("validForPeriod");
|
||||
}
|
||||
if (command.hasParameter("odAccountClosedZeroBalanceInDayClosing")) {
|
||||
f.setOdAccountClosedZeroBalanceInDayClosing(command.booleanObjectValueOfParameterNamed("odAccountClosedZeroBalanceInDayClosing"));
|
||||
present.add("odAccountClosedZeroBalanceInDayClosing");
|
||||
}
|
||||
return present;
|
||||
}
|
||||
|
||||
public static void writeCurrentOnlyFieldsToJson(final JsonObject root, final CurrentOnlyEditFields f, final Set<String> submitted) {
|
||||
if (f == null) {
|
||||
return;
|
||||
}
|
||||
putString(root, submitted, "avgBalanceCalcPeriod", f.getAvgBalanceCalcPeriod());
|
||||
putString(root, submitted, "validForPeriod", f.getValidForPeriod());
|
||||
putBoolean(root, submitted, "odAccountClosedZeroBalanceInDayClosing", f.getOdAccountClosedZeroBalanceInDayClosing());
|
||||
}
|
||||
|
||||
public static Set<String> populateShareOnlyFields(final JsonCommand command, final ShareOnlyEditFields f) {
|
||||
final Set<String> present = new java.util.HashSet<>();
|
||||
if (command.hasParameter("totalShares")) {
|
||||
f.setTotalShares(command.longValueOfParameterNamed("totalShares"));
|
||||
present.add("totalShares");
|
||||
}
|
||||
if (command.hasParameter("totalSharesIssued") || command.hasParameter("issuedShares")) {
|
||||
final Long val = command.hasParameter("totalSharesIssued") ? command.longValueOfParameterNamed("totalSharesIssued") : command.longValueOfParameterNamed("issuedShares");
|
||||
f.setTotalSharesIssued(val);
|
||||
present.add("totalSharesIssued");
|
||||
}
|
||||
if (command.hasParameter("unitPrice")) {
|
||||
f.setUnitPrice(command.bigDecimalValueOfParameterNamed("unitPrice"));
|
||||
present.add("unitPrice");
|
||||
}
|
||||
if (command.hasParameter("minimumShares") || command.hasParameter("minimumClientShares")) {
|
||||
final Long val = command.hasParameter("minimumShares") ? command.longValueOfParameterNamed("minimumShares") : command.longValueOfParameterNamed("minimumClientShares");
|
||||
f.setMinimumShares(val);
|
||||
present.add("minimumShares");
|
||||
}
|
||||
if (command.hasParameter("nominalShares") || command.hasParameter("nominalClientShares")) {
|
||||
final Long val = command.hasParameter("nominalShares") ? command.longValueOfParameterNamed("nominalShares") : command.longValueOfParameterNamed("nominalClientShares");
|
||||
f.setNominalShares(val);
|
||||
present.add("nominalShares");
|
||||
}
|
||||
if (command.hasParameter("maximumShares") || command.hasParameter("maximumClientShares")) {
|
||||
final Long val = command.hasParameter("maximumShares") ? command.longValueOfParameterNamed("maximumShares") : command.longValueOfParameterNamed("maximumClientShares");
|
||||
f.setMaximumShares(val);
|
||||
present.add("maximumShares");
|
||||
}
|
||||
if (command.hasParameter("allowDividendCalcForInactiveClients") || command.hasParameter("allowDividendsInactiveClients")) {
|
||||
final Boolean val = command.hasParameter("allowDividendCalcForInactiveClients") ? command.booleanObjectValueOfParameterNamed("allowDividendCalcForInactiveClients") : command.booleanObjectValueOfParameterNamed("allowDividendsInactiveClients");
|
||||
f.setAllowDividendCalcForInactiveClients(val);
|
||||
present.add("allowDividendCalcForInactiveClients");
|
||||
}
|
||||
if (command.hasParameter("minimumActivePeriodForDividends") || command.hasParameter("minimumActivePeriodFrequency")) {
|
||||
final Integer val = command.hasParameter("minimumActivePeriodForDividends") ? command.integerValueOfParameterNamed("minimumActivePeriodForDividends") : command.integerValueOfParameterNamed("minimumActivePeriodFrequency");
|
||||
f.setMinimumActivePeriodForDividends(val);
|
||||
present.add("minimumActivePeriodForDividends");
|
||||
}
|
||||
if (command.hasParameter("minimumActivePeriodFrequencyType") || command.hasParameter("minimumActivePeriodFrequencyEnum")) {
|
||||
final Integer val = command.hasParameter("minimumActivePeriodFrequencyType") ? command.integerValueOfParameterNamed("minimumActivePeriodFrequencyType") : command.integerValueOfParameterNamed("minimumActivePeriodFrequencyEnum");
|
||||
f.setMinimumActivePeriodFrequencyType(val);
|
||||
present.add("minimumActivePeriodFrequencyType");
|
||||
}
|
||||
if (command.hasParameter("shareLockinPeriod")) {
|
||||
f.setShareLockinPeriod(command.integerValueOfParameterNamed("shareLockinPeriod"));
|
||||
present.add("shareLockinPeriod");
|
||||
}
|
||||
if (command.hasParameter("shareLockinPeriodFrequencyType")) {
|
||||
f.setShareLockinPeriodFrequencyType(command.integerValueOfParameterNamed("shareLockinPeriodFrequencyType"));
|
||||
present.add("shareLockinPeriodFrequencyType");
|
||||
}
|
||||
if (command.hasParameter("externalId")) {
|
||||
f.setExternalId(command.stringValueOfParameterNamed("externalId"));
|
||||
present.add("externalId");
|
||||
}
|
||||
if (command.hasParameter("startDate")) {
|
||||
f.setStartDate(command.localDateValueOfParameterNamed("startDate"));
|
||||
present.add("startDate");
|
||||
}
|
||||
if (command.hasParameter("totalsubscribedShares")) {
|
||||
f.setTotalsubscribedShares(command.longValueOfParameterNamed("totalsubscribedShares"));
|
||||
present.add("totalsubscribedShares");
|
||||
}
|
||||
if (command.hasParameter("capitalAmount") || command.hasParameter("shareCapital")) {
|
||||
final BigDecimal val = command.hasParameter("capitalAmount") ? command.bigDecimalValueOfParameterNamed("capitalAmount") : command.bigDecimalValueOfParameterNamed("shareCapital");
|
||||
f.setCapitalAmount(val);
|
||||
present.add("shareCapital");
|
||||
}
|
||||
return present;
|
||||
}
|
||||
|
||||
public static void writeShareOnlyFieldsToJson(final JsonObject root, final ShareOnlyEditFields f, final Set<String> submitted) {
|
||||
if (f == null) {
|
||||
return;
|
||||
}
|
||||
putNumber(root, submitted, "totalShares", f.getTotalShares());
|
||||
putNumber(root, submitted, "totalSharesIssued", f.getTotalSharesIssued());
|
||||
putNumber(root, submitted, "unitPrice", f.getUnitPrice());
|
||||
putNumber(root, submitted, "minimumShares", f.getMinimumShares());
|
||||
putNumber(root, submitted, "nominalShares", f.getNominalShares());
|
||||
putNumber(root, submitted, "maximumShares", f.getMaximumShares());
|
||||
putBoolean(root, submitted, "allowDividendCalcForInactiveClients", f.getAllowDividendCalcForInactiveClients());
|
||||
putNumber(root, submitted, "minimumActivePeriodForDividends", f.getMinimumActivePeriodForDividends());
|
||||
putNumber(root, submitted, "minimumActivePeriodFrequencyType", f.getMinimumActivePeriodFrequencyType());
|
||||
putNumber(root, submitted, "shareLockinPeriod", f.getShareLockinPeriod());
|
||||
putNumber(root, submitted, "shareLockinPeriodFrequencyType", f.getShareLockinPeriodFrequencyType());
|
||||
putString(root, submitted, "externalId", f.getExternalId());
|
||||
putDate(root, submitted, "startDate", f.getStartDate());
|
||||
putNumber(root, submitted, "totalsubscribedShares", f.getTotalsubscribedShares());
|
||||
if (submitted.contains("capitalAmount") || submitted.contains("shareCapital")) {
|
||||
if (f.getCapitalAmount() != null) {
|
||||
root.addProperty("shareCapital", f.getCapitalAmount());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Set<String> populateFixedDepositFields(final JsonCommand command, final FixedDepositEditFields f) {
|
||||
final Set<String> present = new java.util.HashSet<>();
|
||||
if (command.hasParameter("fdType")) {
|
||||
f.setFdType(command.stringValueOfParameterNamed("fdType"));
|
||||
present.add("fdType");
|
||||
}
|
||||
if (command.hasParameter("preClosurePenalApplicable")) {
|
||||
f.setPreClosurePenalApplicable(command.booleanObjectValueOfParameterNamed("preClosurePenalApplicable"));
|
||||
present.add("preClosurePenalApplicable");
|
||||
}
|
||||
if (command.hasParameter("preClosurePenalInterest")) {
|
||||
f.setPreClosurePenalInterest(command.bigDecimalValueOfParameterNamed("preClosurePenalInterest"));
|
||||
present.add("preClosurePenalInterest");
|
||||
}
|
||||
if (command.hasParameter("preClosurePenalInterestOnTypeId")) {
|
||||
f.setPreClosurePenalInterestOnTypeId(command.integerValueOfParameterNamed("preClosurePenalInterestOnTypeId"));
|
||||
present.add("preClosurePenalInterestOnTypeId");
|
||||
}
|
||||
if (command.hasParameter("minDepositTerm")) {
|
||||
f.setMinDepositTerm(command.integerValueOfParameterNamed("minDepositTerm"));
|
||||
present.add("minDepositTerm");
|
||||
}
|
||||
if (command.hasParameter("maxDepositTerm")) {
|
||||
f.setMaxDepositTerm(command.integerValueOfParameterNamed("maxDepositTerm"));
|
||||
present.add("maxDepositTerm");
|
||||
}
|
||||
if (command.hasParameter("minDepositTermTypeId")) {
|
||||
f.setMinDepositTermTypeId(command.integerValueOfParameterNamed("minDepositTermTypeId"));
|
||||
present.add("minDepositTermTypeId");
|
||||
}
|
||||
if (command.hasParameter("maxDepositTermTypeId")) {
|
||||
f.setMaxDepositTermTypeId(command.integerValueOfParameterNamed("maxDepositTermTypeId"));
|
||||
present.add("maxDepositTermTypeId");
|
||||
}
|
||||
if (command.hasParameter("inMultiplesOfDepositTerm")) {
|
||||
f.setInMultiplesOfDepositTerm(command.integerValueOfParameterNamed("inMultiplesOfDepositTerm"));
|
||||
present.add("inMultiplesOfDepositTerm");
|
||||
}
|
||||
if (command.hasParameter("inMultiplesOfDepositTermTypeId")) {
|
||||
f.setInMultiplesOfDepositTermTypeId(command.integerValueOfParameterNamed("inMultiplesOfDepositTermTypeId"));
|
||||
present.add("inMultiplesOfDepositTermTypeId");
|
||||
}
|
||||
if (command.hasParameter("minDepositAmount")) {
|
||||
f.setMinDepositAmount(command.bigDecimalValueOfParameterNamed("minDepositAmount"));
|
||||
present.add("minDepositAmount");
|
||||
}
|
||||
if (command.hasParameter("maxDepositAmount")) {
|
||||
f.setMaxDepositAmount(command.bigDecimalValueOfParameterNamed("maxDepositAmount"));
|
||||
present.add("maxDepositAmount");
|
||||
}
|
||||
if (command.hasParameter("depositAmount")) {
|
||||
f.setDepositAmount(command.bigDecimalValueOfParameterNamed("depositAmount"));
|
||||
present.add("depositAmount");
|
||||
}
|
||||
return present;
|
||||
}
|
||||
|
||||
public static void writeFixedDepositFieldsToJson(final JsonObject root, final FixedDepositEditFields f, final Set<String> submitted) {
|
||||
if (f == null) {
|
||||
return;
|
||||
}
|
||||
if (f.getFdType() != null) putString(root, submitted, "fdType", f.getFdType());
|
||||
if (f.getPreClosurePenalApplicable() != null) putBoolean(root, submitted, "preClosurePenalApplicable", f.getPreClosurePenalApplicable());
|
||||
if (f.getPreClosurePenalInterest() != null) putNumber(root, submitted, "preClosurePenalInterest", f.getPreClosurePenalInterest());
|
||||
if (f.getPreClosurePenalInterestOnTypeId() != null) putNumber(root, submitted, "preClosurePenalInterestOnTypeId", f.getPreClosurePenalInterestOnTypeId());
|
||||
if (f.getMinDepositTerm() != null) putNumber(root, submitted, "minDepositTerm", f.getMinDepositTerm());
|
||||
if (f.getMaxDepositTerm() != null) putNumber(root, submitted, "maxDepositTerm", f.getMaxDepositTerm());
|
||||
if (f.getMinDepositTermTypeId() != null) putNumber(root, submitted, "minDepositTermTypeId", f.getMinDepositTermTypeId());
|
||||
if (f.getMaxDepositTermTypeId() != null) putNumber(root, submitted, "maxDepositTermTypeId", f.getMaxDepositTermTypeId());
|
||||
if (f.getInMultiplesOfDepositTerm() != null) putNumber(root, submitted, "inMultiplesOfDepositTerm", f.getInMultiplesOfDepositTerm());
|
||||
if (f.getInMultiplesOfDepositTermTypeId() != null) putNumber(root, submitted, "inMultiplesOfDepositTermTypeId", f.getInMultiplesOfDepositTermTypeId());
|
||||
if (f.getMinDepositAmount() != null) putNumber(root, submitted, "minDepositAmount", f.getMinDepositAmount());
|
||||
if (f.getMaxDepositAmount() != null) putNumber(root, submitted, "maxDepositAmount", f.getMaxDepositAmount());
|
||||
if (f.getDepositAmount() != null) putNumber(root, submitted, "depositAmount", f.getDepositAmount());
|
||||
}
|
||||
|
||||
public static Set<String> populateRecurringDepositFields(final JsonCommand command, final RecurringDepositEditFields f) {
|
||||
final Set<String> present = new java.util.HashSet<>();
|
||||
if (command.hasParameter("isMandatoryDeposit")) {
|
||||
f.setIsMandatoryDeposit(command.booleanObjectValueOfParameterNamed("isMandatoryDeposit"));
|
||||
present.add("isMandatoryDeposit");
|
||||
}
|
||||
if (command.hasParameter("allowWithdrawal")) {
|
||||
f.setAllowWithdrawal(command.booleanObjectValueOfParameterNamed("allowWithdrawal"));
|
||||
present.add("allowWithdrawal");
|
||||
}
|
||||
if (command.hasParameter("adjustAdvanceTowardsFuturePayments")) {
|
||||
f.setAdjustAdvanceTowardsFuturePayments(command.booleanObjectValueOfParameterNamed("adjustAdvanceTowardsFuturePayments"));
|
||||
present.add("adjustAdvanceTowardsFuturePayments");
|
||||
}
|
||||
return present;
|
||||
}
|
||||
|
||||
public static void writeRecurringDepositFieldsToJson(final JsonObject root, final RecurringDepositEditFields f, final Set<String> submitted) {
|
||||
if (f == null) {
|
||||
return;
|
||||
}
|
||||
if (f.getIsMandatoryDeposit() != null) putBoolean(root, submitted, "isMandatoryDeposit", f.getIsMandatoryDeposit());
|
||||
if (f.getAllowWithdrawal() != null) putBoolean(root, submitted, "allowWithdrawal", f.getAllowWithdrawal());
|
||||
if (f.getAdjustAdvanceTowardsFuturePayments() != null) putBoolean(root, submitted, "adjustAdvanceTowardsFuturePayments", f.getAdjustAdvanceTowardsFuturePayments());
|
||||
}
|
||||
|
||||
public static java.util.Map<String, Object> reconstructProposedChangesMap(
|
||||
final ProductPendingEdit pendingEdit,
|
||||
final Set<String> submittedFields,
|
||||
final ProductPendingEditChargeRepository pendingEditChargeRepository,
|
||||
final ProductPendingEditGlMappingRepository pendingEditGlMappingRepository,
|
||||
final ProductPendingEditFacilityLimitRepository pendingEditFacilityLimitRepository,
|
||||
final com.google.gson.Gson gson) {
|
||||
final JsonObject root = new JsonObject();
|
||||
root.addProperty("locale", "en");
|
||||
root.addProperty("dateFormat", "yyyy-MM-dd");
|
||||
|
||||
final String productType = pendingEdit.getProductType();
|
||||
if ((ProductPendingEdit.TYPE_SAVINGS.equals(productType) || ProductPendingEdit.TYPE_CURRENT.equals(productType) || ProductPendingEdit.TYPE_FD.equals(productType) || ProductPendingEdit.TYPE_RD.equals(productType)) && pendingEdit.getCoreFields() != null) {
|
||||
writeCoreFieldsToJson(root, pendingEdit.getCoreFields(), submittedFields);
|
||||
}
|
||||
if (ProductPendingEdit.TYPE_CURRENT.equals(productType) && pendingEdit.getCurrentOnlyFields() != null) {
|
||||
writeCurrentOnlyFieldsToJson(root, pendingEdit.getCurrentOnlyFields(), submittedFields);
|
||||
}
|
||||
if (ProductPendingEdit.TYPE_SAVINGS.equals(productType) || ProductPendingEdit.TYPE_CURRENT.equals(productType)) {
|
||||
if (submittedFields.contains("accountFacilityConfig") && pendingEdit.getFacilityConfigFields() != null) {
|
||||
writeFacilityConfigToJson(root, pendingEdit.getFacilityConfigFields(), true);
|
||||
}
|
||||
if (submittedFields.contains("depositLimitKyc") && pendingEdit.getDepositLimitKycFields() != null) {
|
||||
writeDepositLimitKycToJson(root, pendingEdit.getDepositLimitKycFields(), true);
|
||||
}
|
||||
if (submittedFields.contains("accountFacilityLimits") && pendingEditFacilityLimitRepository != null) {
|
||||
writeFacilityLimitsToJson(root, pendingEditFacilityLimitRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
}
|
||||
if ((ProductPendingEdit.TYPE_FD.equals(productType) || ProductPendingEdit.TYPE_RD.equals(productType)) && pendingEdit.getFixedDepositFields() != null) {
|
||||
writeFixedDepositFieldsToJson(root, pendingEdit.getFixedDepositFields(), submittedFields);
|
||||
}
|
||||
if (ProductPendingEdit.TYPE_RD.equals(productType) && pendingEdit.getRecurringDepositFields() != null) {
|
||||
writeRecurringDepositFieldsToJson(root, pendingEdit.getRecurringDepositFields(), submittedFields);
|
||||
}
|
||||
if (ProductPendingEdit.TYPE_SHARE.equals(productType) && pendingEdit.getShareOnlyFields() != null) {
|
||||
writeShareOnlyFieldsToJson(root, pendingEdit.getShareOnlyFields(), submittedFields);
|
||||
}
|
||||
if (submittedFields.contains("glAccountMapping") && pendingEdit.getGlAccountMappingFields() != null) {
|
||||
writeGlAccountMappingToJson(root, pendingEdit.getGlAccountMappingFields());
|
||||
}
|
||||
if (submittedFields.contains("charges") && pendingEditChargeRepository != null) {
|
||||
writeChargesToJson(root, pendingEditChargeRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
if (submittedFields.contains("glArrayMappings") && pendingEditGlMappingRepository != null) {
|
||||
writeGlArrayMappingsToJson(root, pendingEditGlMappingRepository.findByPendingEditId(pendingEdit.getId()));
|
||||
}
|
||||
|
||||
final String json = gson.toJson(root);
|
||||
return gson.fromJson(json, new com.google.gson.reflect.TypeToken<java.util.Map<String, Object>>() {}.getType());
|
||||
}
|
||||
}
|
||||
|
||||
+20
-11
@@ -48,28 +48,28 @@ public class SavingsCoreEditFields {
|
||||
@Column(name = "currency_code")
|
||||
private String currencyCode;
|
||||
|
||||
@Column(name = "digits_after_decimal")
|
||||
@Column(name = "currency_digits")
|
||||
private Integer digitsAfterDecimal;
|
||||
|
||||
@Column(name = "in_multiples_of")
|
||||
@Column(name = "currency_multiplesof")
|
||||
private Integer inMultiplesOf;
|
||||
|
||||
@Column(name = "accounting_rule")
|
||||
@Column(name = "accounting_type")
|
||||
private Integer accountingRule;
|
||||
|
||||
@Column(name = "nominal_annual_interest_rate")
|
||||
private BigDecimal nominalAnnualInterestRate;
|
||||
|
||||
@Column(name = "interest_compounding_period_type")
|
||||
@Column(name = "interest_compounding_period_enum")
|
||||
private Integer interestCompoundingPeriodType;
|
||||
|
||||
@Column(name = "interest_posting_period_type")
|
||||
@Column(name = "interest_posting_period_enum")
|
||||
private Integer interestPostingPeriodType;
|
||||
|
||||
@Column(name = "interest_calculation_type")
|
||||
@Column(name = "interest_calculation_type_enum")
|
||||
private Integer interestCalculationType;
|
||||
|
||||
@Column(name = "interest_calculation_days_in_year_type")
|
||||
@Column(name = "interest_calculation_days_in_year_type_enum")
|
||||
private Integer interestCalculationDaysInYearType;
|
||||
|
||||
@Column(name = "min_required_opening_balance")
|
||||
@@ -78,10 +78,10 @@ public class SavingsCoreEditFields {
|
||||
@Column(name = "lockin_period_frequency")
|
||||
private Integer lockinPeriodFrequency;
|
||||
|
||||
@Column(name = "lockin_period_frequency_type")
|
||||
@Column(name = "lockin_period_frequency_enum")
|
||||
private Integer lockinPeriodFrequencyType;
|
||||
|
||||
@Column(name = "withdrawal_fee_for_transfers")
|
||||
@Column(name = "withdrawal_fee_for_transfer")
|
||||
private Boolean withdrawalFeeForTransfers;
|
||||
|
||||
@Column(name = "allow_overdraft")
|
||||
@@ -102,7 +102,7 @@ public class SavingsCoreEditFields {
|
||||
@Column(name = "min_required_balance")
|
||||
private BigDecimal minRequiredBalance;
|
||||
|
||||
@Column(name = "lien_allowed")
|
||||
@Column(name = "is_lien_allowed")
|
||||
private Boolean lienAllowed;
|
||||
|
||||
@Column(name = "max_allowed_lien_limit")
|
||||
@@ -111,7 +111,7 @@ public class SavingsCoreEditFields {
|
||||
@Column(name = "min_balance_for_interest_calculation")
|
||||
private BigDecimal minBalanceForInterestCalculation;
|
||||
|
||||
@Column(name = "with_hold_tax")
|
||||
@Column(name = "withhold_tax")
|
||||
private Boolean withHoldTax;
|
||||
|
||||
@Column(name = "tax_group_id")
|
||||
@@ -231,4 +231,13 @@ public class SavingsCoreEditFields {
|
||||
|
||||
@Column(name = "allow_debit_txn_after_due_date")
|
||||
private Boolean allowDebitTxnAfterDueDate;
|
||||
|
||||
@Column(name = "deposit_type_enum")
|
||||
private Integer depositTypeEnum;
|
||||
|
||||
@Column(name = "withdrawal_fee_amount")
|
||||
private BigDecimal withdrawalFeeAmount;
|
||||
|
||||
@Column(name = "withdrawal_fee_type_enum")
|
||||
private Integer withdrawalFeeTypeEnum;
|
||||
}
|
||||
|
||||
+19
-7
@@ -32,28 +32,28 @@ public class ShareOnlyEditFields {
|
||||
@Column(name = "total_shares")
|
||||
private Long totalShares;
|
||||
|
||||
@Column(name = "total_shares_issued")
|
||||
@Column(name = "issued_shares")
|
||||
private Long totalSharesIssued;
|
||||
|
||||
@Column(name = "unit_price")
|
||||
private BigDecimal unitPrice;
|
||||
|
||||
@Column(name = "minimum_shares")
|
||||
@Column(name = "minimum_client_shares")
|
||||
private Long minimumShares;
|
||||
|
||||
@Column(name = "nominal_shares")
|
||||
@Column(name = "nominal_client_shares")
|
||||
private Long nominalShares;
|
||||
|
||||
@Column(name = "maximum_shares")
|
||||
@Column(name = "maximum_client_shares")
|
||||
private Long maximumShares;
|
||||
|
||||
@Column(name = "allow_dividend_calc_for_inactive_clients")
|
||||
@Column(name = "allow_dividends_inactive_clients")
|
||||
private Boolean allowDividendCalcForInactiveClients;
|
||||
|
||||
@Column(name = "minimum_active_period_for_dividends")
|
||||
@Column(name = "minimum_active_period_frequency")
|
||||
private Integer minimumActivePeriodForDividends;
|
||||
|
||||
@Column(name = "minimum_active_period_frequency_type")
|
||||
@Column(name = "minimum_active_period_frequency_enum")
|
||||
private Integer minimumActivePeriodFrequencyType;
|
||||
|
||||
@Column(name = "share_lockin_period")
|
||||
@@ -61,4 +61,16 @@ public class ShareOnlyEditFields {
|
||||
|
||||
@Column(name = "share_lockin_period_frequency_type")
|
||||
private Integer shareLockinPeriodFrequencyType;
|
||||
|
||||
@Column(name = "external_id")
|
||||
private String externalId;
|
||||
|
||||
@Column(name = "start_date")
|
||||
private java.time.LocalDate startDate;
|
||||
|
||||
@Column(name = "totalsubscribed_shares")
|
||||
private Long totalsubscribedShares;
|
||||
|
||||
@Column(name = "capital_amount")
|
||||
private BigDecimal capitalAmount;
|
||||
}
|
||||
|
||||
+2
@@ -49,4 +49,6 @@
|
||||
<include file="parts/2025_recreate_savings_product_temp_table.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/2026_add_pending_edit_typed_columns.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/2027_add_pending_edit_satellite_tables.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/2028_update_saving_product_temp_table.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/2029_remove_proposed_payload_json.xml" relativeToChangelogFile="true" />
|
||||
</databaseChangeLog>
|
||||
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<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">
|
||||
|
||||
<!-- 1. Rename table m_savings_product_temp to m_saving_product_temp -->
|
||||
<changeSet author="fineract" id="2028-1">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<tableExists tableName="m_savings_product_temp" />
|
||||
</preConditions>
|
||||
<renameTable oldTableName="m_savings_product_temp" newTableName="m_saving_product_temp" />
|
||||
</changeSet>
|
||||
|
||||
<!-- 2. Recreate unique constraint on pending_lock_key if needed -->
|
||||
<changeSet author="fineract" id="2028-2">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<tableExists tableName="m_saving_product_temp" />
|
||||
</preConditions>
|
||||
<dropUniqueConstraint tableName="m_saving_product_temp" constraintName="sp_temp_unq_pending_lock_key" />
|
||||
<addUniqueConstraint tableName="m_saving_product_temp" columnNames="pending_lock_key" constraintName="sp_temp_unq_pending_lock_key" />
|
||||
</changeSet>
|
||||
|
||||
<!-- 3. Rename columns to match exact user comparative list names -->
|
||||
<changeSet author="fineract" id="2028-rename-core-columns">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<tableExists tableName="m_saving_product_temp" />
|
||||
</preConditions>
|
||||
|
||||
<!-- Auditing -->
|
||||
<renameColumn tableName="m_saving_product_temp" oldColumnName="maker_id" newColumnName="createdby_id" columnDataType="BIGINT" />
|
||||
<renameColumn tableName="m_saving_product_temp" oldColumnName="checker_id" newColumnName="lastmodifiedby_id" columnDataType="BIGINT" />
|
||||
<renameColumn tableName="m_saving_product_temp" oldColumnName="created_on" newColumnName="created_date" columnDataType="DATETIME" />
|
||||
<renameColumn tableName="m_saving_product_temp" oldColumnName="checked_on" newColumnName="lastmodified_date" columnDataType="DATETIME" />
|
||||
|
||||
<!-- Core fields -->
|
||||
<renameColumn tableName="m_saving_product_temp" oldColumnName="digits_after_decimal" newColumnName="currency_digits" columnDataType="INTEGER" />
|
||||
<renameColumn tableName="m_saving_product_temp" oldColumnName="in_multiples_of" newColumnName="currency_multiplesof" columnDataType="INTEGER" />
|
||||
<renameColumn tableName="m_saving_product_temp" oldColumnName="accounting_rule" newColumnName="accounting_type" columnDataType="INTEGER" />
|
||||
<renameColumn tableName="m_saving_product_temp" oldColumnName="interest_compounding_period_type" newColumnName="interest_compounding_period_enum" columnDataType="INTEGER" />
|
||||
<renameColumn tableName="m_saving_product_temp" oldColumnName="interest_posting_period_type" newColumnName="interest_posting_period_enum" columnDataType="INTEGER" />
|
||||
<renameColumn tableName="m_saving_product_temp" oldColumnName="interest_calculation_type" newColumnName="interest_calculation_type_enum" columnDataType="INTEGER" />
|
||||
<renameColumn tableName="m_saving_product_temp" oldColumnName="interest_calculation_days_in_year_type" newColumnName="interest_calculation_days_in_year_type_enum" columnDataType="INTEGER" />
|
||||
<renameColumn tableName="m_saving_product_temp" oldColumnName="lockin_period_frequency_type" newColumnName="lockin_period_frequency_enum" columnDataType="INTEGER" />
|
||||
<renameColumn tableName="m_saving_product_temp" oldColumnName="withdrawal_fee_for_transfers" newColumnName="withdrawal_fee_for_transfer" columnDataType="BOOLEAN" />
|
||||
<renameColumn tableName="m_saving_product_temp" oldColumnName="lien_allowed" newColumnName="is_lien_allowed" columnDataType="BOOLEAN" />
|
||||
<renameColumn tableName="m_saving_product_temp" oldColumnName="with_hold_tax" newColumnName="withhold_tax" columnDataType="BOOLEAN" />
|
||||
|
||||
<!-- Share fields -->
|
||||
<renameColumn tableName="m_saving_product_temp" oldColumnName="total_shares_issued" newColumnName="issued_shares" columnDataType="BIGINT" />
|
||||
<renameColumn tableName="m_saving_product_temp" oldColumnName="minimum_shares" newColumnName="minimum_client_shares" columnDataType="BIGINT" />
|
||||
<renameColumn tableName="m_saving_product_temp" oldColumnName="nominal_shares" newColumnName="nominal_client_shares" columnDataType="BIGINT" />
|
||||
<renameColumn tableName="m_saving_product_temp" oldColumnName="maximum_shares" newColumnName="maximum_client_shares" columnDataType="BIGINT" />
|
||||
<renameColumn tableName="m_saving_product_temp" oldColumnName="minimum_active_period_for_dividends" newColumnName="minimum_active_period_frequency" columnDataType="INTEGER" />
|
||||
<renameColumn tableName="m_saving_product_temp" oldColumnName="minimum_active_period_frequency_type" newColumnName="minimum_active_period_frequency_enum" columnDataType="INTEGER" />
|
||||
<renameColumn tableName="m_saving_product_temp" oldColumnName="allow_dividend_calc_for_inactive_clients" newColumnName="allow_dividends_inactive_clients" columnDataType="BOOLEAN" />
|
||||
</changeSet>
|
||||
|
||||
<!-- 4. Add the completely new columns to m_saving_product_temp -->
|
||||
<changeSet author="fineract" id="2028-add-missing-columns">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<tableExists tableName="m_saving_product_temp" />
|
||||
</preConditions>
|
||||
<addColumn tableName="m_saving_product_temp">
|
||||
<!-- If column does not already exist, it will be added. Guard is implicit via preCondition or Liquibase will skip. -->
|
||||
<column name="deposit_type_enum" type="SMALLINT" />
|
||||
<column name="withdrawal_fee_amount" type="DECIMAL(19, 6)" />
|
||||
<column name="withdrawal_fee_type_enum" type="SMALLINT" />
|
||||
<column name="external_id" type="VARCHAR(100)" />
|
||||
<column name="start_date" type="DATE" />
|
||||
<column name="totalsubscribed_shares" type="BIGINT" />
|
||||
<column name="capital_amount" type="DECIMAL(20, 2)" />
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<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 author="fineract" id="2029-remove-proposed-payload-json">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<columnExists tableName="m_saving_product_temp" columnName="proposed_payload_json" />
|
||||
</preConditions>
|
||||
<dropColumn tableName="m_saving_product_temp" columnName="proposed_payload_json" />
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
Reference in New Issue
Block a user