table changes on Maker-Checker workflow for Products, with approval-based updates and product locking to prevent concurrent edits
This commit is contained in:
+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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user