feat(share): add cashier share collection endpoint with GL posting and activation validation
- New POST /cashier/sharecollection endpoint: collects cash for share purchase, posts Dr Cash Vault / Cr Share Sundry / Cr Income GL entries, marks charges as paid and sets cashier_collected flag on the account - GET /cashier/sharecollection/:id endpoint for collection status check - Block share account activation if cashier has not collected cash first (validates m_share_cashier_collection record within last 30 days) - Skip duplicate charge GL on activation when charge already collected upfront - Suppress automatic GL posting at account submission time to prevent double entries; GL is now posted only via cashier collection endpoint - Fix JdbcTemplate injection in ShareAccountWritePlatformServiceJpaRepositoryImpl via ShareAccountsConfiguration Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
6e31ac9acd
commit
9d944d0196
+424
@@ -0,0 +1,424 @@
|
||||
package org.apache.fineract.portfolio.cashtransfer.api;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import jakarta.ws.rs.Consumes;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.POST;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Cashier Share Collection API — POST /v1/cashier/sharecollection
|
||||
*
|
||||
* Records cash received from a member for share purchase and posts GL entries:
|
||||
* Dr SHARES_REFERENCE (Cash at Vault) = shareAmount + chargeAmount
|
||||
* Cr SHARES_SUSPENSE (Share Sundry) = shareAmount
|
||||
* Cr INCOME_FROM_FEES = chargeAmount (if > 0)
|
||||
*
|
||||
* On account activation Fineract posts:
|
||||
* Dr SHARES_SUSPENSE → Cr SHARES_EQUITY
|
||||
* Activation skips charge GL if is_paid_derived = true (set here).
|
||||
*/
|
||||
@Path("/v1/cashier/sharecollection")
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public class ShareCollectionApiResource {
|
||||
|
||||
// ── acc_gl_journal_entry.type_enum ─────────────────────────────────────
|
||||
// Fineract convention: 1 = CREDIT (Cr), 2 = DEBIT (Dr)
|
||||
// Opposite of intuition — verified from Fineract AccountingProcessorHelper.
|
||||
private static final int DEBIT = 2;
|
||||
private static final int CREDIT = 1;
|
||||
|
||||
// ── CashAccountsForShares financial_account_type ───────────────────────
|
||||
private static final int FA_SHARES_REFERENCE = 1;
|
||||
private static final int FA_SHARES_SUSPENSE = 2;
|
||||
private static final int FA_INCOME_FROM_FEES = 3;
|
||||
|
||||
// ── acc_gl_journal_entry.entity_type_enum ─────────────────────────────
|
||||
// Manual cashier entries use NULL — avoids NPE in PortfolioProductType.fromInt()
|
||||
// which only handles values 1-5 and returns null for unknown values.
|
||||
|
||||
// ── acc_product_mapping.product_type for shares ────────────────────────
|
||||
private static final int PRODUCT_TYPE_SHARES = 4;
|
||||
|
||||
// ── m_share_account.status_enum ───────────────────────────────────────
|
||||
private static final int STATUS_SUBMITTED_PENDING = 100;
|
||||
|
||||
// ── Maximum days a collection record is considered valid ──────────────
|
||||
private static final int MAX_COLLECTION_AGE_DAYS = 30;
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
private final Gson gson = new Gson();
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════
|
||||
// POST — Collect cash for a share account
|
||||
// ══════════════════════════════════════════════════════════════════════
|
||||
@POST
|
||||
@Transactional
|
||||
public Response collect(final String body) {
|
||||
|
||||
final AppUser currentUser = this.context.authenticatedUser();
|
||||
currentUser.validateHasPermissionTo("CREATE_JOURNALENTRY");
|
||||
|
||||
// ── Parse request ──────────────────────────────────────────────────
|
||||
if (body == null || body.isBlank()) {
|
||||
throw new PlatformDataIntegrityException(
|
||||
"error.msg.sharecollection.request.empty",
|
||||
"Request body is required.");
|
||||
}
|
||||
final JsonObject json;
|
||||
try {
|
||||
json = JsonParser.parseString(body).getAsJsonObject();
|
||||
} catch (Exception e) {
|
||||
throw new PlatformDataIntegrityException(
|
||||
"error.msg.sharecollection.request.invalid",
|
||||
"Request body must be valid JSON.");
|
||||
}
|
||||
|
||||
final Long shareAccountId = getLong(json, "shareAccountId");
|
||||
final String transactionDateStr = getString(json, "transactionDate");
|
||||
final BigDecimal shareAmount = getBigDecimal(json, "shareAmount", "shareAmount");
|
||||
final BigDecimal chargeAmountRaw = getBigDecimal(json, "chargeAmount", "chargeAmount");
|
||||
final String note = sanitiseNote(getString(json, "note"));
|
||||
|
||||
// ── Validate inputs ────────────────────────────────────────────────
|
||||
if (shareAccountId == null) {
|
||||
throw new PlatformDataIntegrityException(
|
||||
"error.msg.sharecollection.accountid.required",
|
||||
"shareAccountId is required.");
|
||||
}
|
||||
if (shareAmount.compareTo(BigDecimal.ZERO) < 0) {
|
||||
throw new PlatformDataIntegrityException(
|
||||
"error.msg.sharecollection.shareamount.negative",
|
||||
"shareAmount cannot be negative.");
|
||||
}
|
||||
final BigDecimal safeCharge = chargeAmountRaw.compareTo(BigDecimal.ZERO) > 0
|
||||
? chargeAmountRaw : BigDecimal.ZERO;
|
||||
final BigDecimal totalAmount = shareAmount.add(safeCharge);
|
||||
if (totalAmount.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
throw new PlatformDataIntegrityException(
|
||||
"error.msg.sharecollection.total.zero",
|
||||
"Total collection amount must be greater than zero.");
|
||||
}
|
||||
|
||||
final LocalDate entryDate;
|
||||
try {
|
||||
entryDate = transactionDateStr != null
|
||||
? LocalDate.parse(transactionDateStr) : LocalDate.now();
|
||||
} catch (DateTimeParseException e) {
|
||||
throw new PlatformDataIntegrityException(
|
||||
"error.msg.sharecollection.date.invalid",
|
||||
"transactionDate must be in YYYY-MM-DD format. Received: " + transactionDateStr);
|
||||
}
|
||||
|
||||
// ── Load account + client details ──────────────────────────────────
|
||||
final Map<String, Object> acct = loadAccount(shareAccountId);
|
||||
|
||||
// ── Account must be in 'Submitted and pending approval' ───────────
|
||||
final int statusEnum = toInt(acct.get("status_enum"));
|
||||
if (statusEnum != STATUS_SUBMITTED_PENDING) {
|
||||
throw new PlatformDataIntegrityException(
|
||||
"error.msg.sharecollection.account.invalid.status",
|
||||
"Cash collection is only allowed for accounts in 'Submitted and pending approval' "
|
||||
+ "status. Account " + acct.get("account_no") + " has status code " + statusEnum + ".");
|
||||
}
|
||||
|
||||
// ── Prevent double collection ──────────────────────────────────────
|
||||
if (Boolean.TRUE.equals(acct.get("cashier_collected"))) {
|
||||
throw new PlatformDataIntegrityException(
|
||||
"error.msg.sharecollection.already.collected",
|
||||
"Cash has already been collected for share account "
|
||||
+ acct.get("account_no") + ". Re-collection is not allowed.");
|
||||
}
|
||||
|
||||
final Long officeId = toLong(acct.get("office_id"));
|
||||
final Long productId = toLong(acct.get("product_id"));
|
||||
final String currencyCode = (String) acct.get("currency_code");
|
||||
final String clientName = (String) acct.get("client_name");
|
||||
final String accountNo = (String) acct.get("account_no");
|
||||
|
||||
// ── Resolve GL accounts from product mapping ───────────────────────
|
||||
final Long glReference = resolveGl(productId, FA_SHARES_REFERENCE);
|
||||
final Long glSuspense = resolveGl(productId, FA_SHARES_SUSPENSE);
|
||||
final Long glIncome = resolveGl(productId, FA_INCOME_FROM_FEES);
|
||||
|
||||
if (glReference == null) {
|
||||
throw new PlatformDataIntegrityException(
|
||||
"error.msg.sharecollection.gl.reference.notmapped",
|
||||
"Share Reference (Cash at Vault) GL is not mapped for product " + productId
|
||||
+ ". Configure Share Product accounting mappings first.");
|
||||
}
|
||||
if (glSuspense == null) {
|
||||
throw new PlatformDataIntegrityException(
|
||||
"error.msg.sharecollection.gl.suspense.notmapped",
|
||||
"Share Suspense GL is not mapped for product " + productId
|
||||
+ ". Configure Share Product accounting mappings first.");
|
||||
}
|
||||
if (safeCharge.compareTo(BigDecimal.ZERO) > 0 && glIncome == null) {
|
||||
throw new PlatformDataIntegrityException(
|
||||
"error.msg.sharecollection.gl.income.notmapped",
|
||||
"Income from Fees GL is not mapped for product " + productId
|
||||
+ " but charge amount " + safeCharge + " is present. "
|
||||
+ "Configure Share Product accounting mappings first.");
|
||||
}
|
||||
|
||||
// ── Generate unique transaction ID ─────────────────────────────────
|
||||
final String txnId = "SC-" + shareAccountId + "-" + System.currentTimeMillis();
|
||||
final long userId = currentUser.getId();
|
||||
final String collectorName = currentUser.getUsername();
|
||||
final LocalDateTime now = LocalDateTime.now();
|
||||
|
||||
// ── Post GL journal entries ────────────────────────────────────────
|
||||
// Dr Cash at Vault (SHARES_REFERENCE) = totalAmount
|
||||
insertEntry(officeId, glReference, DEBIT, totalAmount, txnId,
|
||||
entryDate, shareAccountId, userId, now, currencyCode,
|
||||
"Share collection received for " + accountNo
|
||||
+ (note != null ? " | " + note : ""));
|
||||
|
||||
// Cr Share Sundry (SHARES_SUSPENSE) = shareAmount
|
||||
insertEntry(officeId, glSuspense, CREDIT, shareAmount, txnId,
|
||||
entryDate, shareAccountId, userId, now, currencyCode,
|
||||
"Share amount held in suspense - " + accountNo);
|
||||
|
||||
// Cr Income from Fees = chargeAmount (only if > 0)
|
||||
if (safeCharge.compareTo(BigDecimal.ZERO) > 0) {
|
||||
insertEntry(officeId, glIncome, CREDIT, safeCharge, txnId,
|
||||
entryDate, shareAccountId, userId, now, currencyCode,
|
||||
"Charge collected upfront for " + accountNo);
|
||||
|
||||
// Mark charges paid → activation will skip duplicate charge GL entry
|
||||
jdbcTemplate.update(
|
||||
"UPDATE m_share_account_charge "
|
||||
+ "SET is_paid_derived = true, "
|
||||
+ " amount_paid_derived = amount, "
|
||||
+ " amount_outstanding_derived = 0 "
|
||||
+ "WHERE account_id = ? AND is_active = true AND is_paid_derived = false",
|
||||
shareAccountId);
|
||||
}
|
||||
|
||||
// ── Flip cashier_collected flag ────────────────────────────────────
|
||||
jdbcTemplate.update(
|
||||
"UPDATE m_share_account SET cashier_collected = true WHERE id = ?",
|
||||
shareAccountId);
|
||||
|
||||
// ── Insert audit / validation record ──────────────────────────────
|
||||
jdbcTemplate.update(
|
||||
"INSERT INTO m_share_cashier_collection "
|
||||
+ "(share_account_id, collected_by_user, collected_by_name, collection_date, "
|
||||
+ " share_amount, charge_amount, total_amount, gl_transaction_id, "
|
||||
+ " office_id, currency_code, note) "
|
||||
+ "VALUES (?,?,?,?,?,?,?,?,?,?,?)",
|
||||
shareAccountId, userId, collectorName,
|
||||
java.sql.Date.valueOf(entryDate),
|
||||
shareAmount, safeCharge, totalAmount,
|
||||
txnId, officeId, currencyCode, note);
|
||||
|
||||
// ── Build GL entries summary for response ──────────────────────────
|
||||
final List<Map<String, Object>> glEntries = new ArrayList<>();
|
||||
glEntries.add(glEntryMap(resolveGlName(glReference), "Dr", totalAmount, currencyCode));
|
||||
glEntries.add(glEntryMap(resolveGlName(glSuspense), "Cr", shareAmount, currencyCode));
|
||||
if (safeCharge.compareTo(BigDecimal.ZERO) > 0) {
|
||||
glEntries.add(glEntryMap(resolveGlName(glIncome), "Cr", safeCharge, currencyCode));
|
||||
}
|
||||
|
||||
// ── Response ───────────────────────────────────────────────────────
|
||||
final Map<String, Object> resp = new LinkedHashMap<>();
|
||||
resp.put("transactionId", txnId);
|
||||
resp.put("shareAccountId", shareAccountId);
|
||||
resp.put("accountNo", accountNo);
|
||||
resp.put("clientName", clientName);
|
||||
resp.put("collectionDate", entryDate.toString());
|
||||
resp.put("collectedBy", collectorName);
|
||||
resp.put("shareAmount", shareAmount);
|
||||
resp.put("chargeAmount", safeCharge);
|
||||
resp.put("totalAmount", totalAmount);
|
||||
resp.put("currencyCode", currencyCode);
|
||||
resp.put("glEntries", glEntries);
|
||||
|
||||
return Response.ok(gson.toJson(resp)).build();
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════
|
||||
// GET — Check collection status for a share account
|
||||
// ══════════════════════════════════════════════════════════════════════
|
||||
@GET
|
||||
@Path("/{shareAccountId}")
|
||||
public Response getStatus(@PathParam("shareAccountId") final Long shareAccountId) {
|
||||
this.context.authenticatedUser();
|
||||
|
||||
try {
|
||||
final Map<String, Object> rec = jdbcTemplate.queryForMap(
|
||||
"SELECT scc.share_account_id, sa.account_no, "
|
||||
+ " mc.display_name AS client_name, "
|
||||
+ " scc.collected_by_name, scc.collection_date, "
|
||||
+ " scc.share_amount, scc.charge_amount, scc.total_amount, "
|
||||
+ " scc.gl_transaction_id, scc.currency_code, scc.note "
|
||||
+ "FROM m_share_cashier_collection scc "
|
||||
+ "JOIN m_share_account sa ON sa.id = scc.share_account_id "
|
||||
+ "JOIN m_client mc ON mc.id = sa.client_id "
|
||||
+ "WHERE scc.share_account_id = ?",
|
||||
shareAccountId);
|
||||
|
||||
final Map<String, Object> resp = new LinkedHashMap<>();
|
||||
resp.put("collected", true);
|
||||
resp.put("shareAccountId", shareAccountId);
|
||||
resp.put("accountNo", rec.get("account_no"));
|
||||
resp.put("clientName", rec.get("client_name"));
|
||||
resp.put("collectedBy", rec.get("collected_by_name"));
|
||||
resp.put("collectionDate", rec.get("collection_date") != null
|
||||
? rec.get("collection_date").toString() : null);
|
||||
resp.put("shareAmount", rec.get("share_amount"));
|
||||
resp.put("chargeAmount", rec.get("charge_amount"));
|
||||
resp.put("totalAmount", rec.get("total_amount"));
|
||||
resp.put("transactionId", rec.get("gl_transaction_id"));
|
||||
resp.put("currencyCode", rec.get("currency_code"));
|
||||
resp.put("note", rec.get("note"));
|
||||
return Response.ok(gson.toJson(resp)).build();
|
||||
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
final Map<String, Object> resp = new LinkedHashMap<>();
|
||||
resp.put("collected", false);
|
||||
resp.put("shareAccountId", shareAccountId);
|
||||
return Response.ok(gson.toJson(resp)).build();
|
||||
}
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════════
|
||||
// Private helpers
|
||||
// ══════════════════════════════════════════════════════════════════════
|
||||
|
||||
private Map<String, Object> loadAccount(final Long shareAccountId) {
|
||||
try {
|
||||
return jdbcTemplate.queryForMap(
|
||||
"SELECT sa.id, sa.account_no, sa.status_enum, sa.product_id, "
|
||||
+ " sa.cashier_collected, sa.currency_code, "
|
||||
+ " mc.office_id, mc.display_name AS client_name "
|
||||
+ "FROM m_share_account sa "
|
||||
+ "JOIN m_client mc ON mc.id = sa.client_id "
|
||||
+ "WHERE sa.id = ?",
|
||||
shareAccountId);
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
throw new PlatformDataIntegrityException(
|
||||
"error.msg.sharecollection.account.notfound",
|
||||
"Share account with id " + shareAccountId + " does not exist.");
|
||||
}
|
||||
}
|
||||
|
||||
private Long resolveGl(final Long productId, final int financialAccountType) {
|
||||
try {
|
||||
return jdbcTemplate.queryForObject(
|
||||
"SELECT gl_account_id FROM acc_product_mapping "
|
||||
+ "WHERE product_id = ? AND product_type = ? AND financial_account_type = ?",
|
||||
Long.class, productId, PRODUCT_TYPE_SHARES, financialAccountType);
|
||||
} catch (IncorrectResultSizeDataAccessException e) {
|
||||
// covers both EmptyResultDataAccessException (0 rows) and multiple rows
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String resolveGlName(final Long glAccountId) {
|
||||
if (glAccountId == null) return "Unknown GL";
|
||||
try {
|
||||
return jdbcTemplate.queryForObject(
|
||||
"SELECT name FROM acc_gl_account WHERE id = ?",
|
||||
String.class, glAccountId);
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
return "GL-" + glAccountId;
|
||||
}
|
||||
}
|
||||
|
||||
private void insertEntry(final Long officeId, final Long glAccountId,
|
||||
final int typeEnum, final BigDecimal amount, final String txnId,
|
||||
final LocalDate entryDate, final Long shareAccountId,
|
||||
final long userId, final LocalDateTime now, final String currencyCode,
|
||||
final String description) {
|
||||
jdbcTemplate.update(
|
||||
"INSERT INTO acc_gl_journal_entry "
|
||||
+ "(account_id, office_id, currency_code, transaction_id, reversed, manual_entry, "
|
||||
+ " entry_date, type_enum, amount, description, entity_id, "
|
||||
+ " created_by, last_modified_by, created_date, lastmodified_date, "
|
||||
+ " is_running_balance_calculated, office_running_balance, "
|
||||
+ " organization_running_balance, submitted_on_date, transaction_date, "
|
||||
+ " created_on_utc, last_modified_on_utc) "
|
||||
+ "VALUES (?,?,?,?,false,true,?,?,?,?,?,?,?,?,?,false,0,0,?,?,?,?)",
|
||||
glAccountId, officeId, currencyCode, txnId,
|
||||
java.sql.Date.valueOf(entryDate), typeEnum, amount, description,
|
||||
shareAccountId, // entity_id — links entry to the share account
|
||||
userId, userId, now, now,
|
||||
java.sql.Date.valueOf(entryDate),
|
||||
java.sql.Date.valueOf(entryDate),
|
||||
now.atOffset(ZoneOffset.UTC),
|
||||
now.atOffset(ZoneOffset.UTC));
|
||||
}
|
||||
|
||||
private Map<String, Object> glEntryMap(final String account, final String type,
|
||||
final BigDecimal amount, final String currency) {
|
||||
final Map<String, Object> m = new LinkedHashMap<>();
|
||||
m.put("account", account);
|
||||
m.put("type", type);
|
||||
m.put("amount", amount);
|
||||
m.put("currency", currency);
|
||||
return m;
|
||||
}
|
||||
|
||||
private String sanitiseNote(final String raw) {
|
||||
if (raw == null || raw.isBlank()) return null;
|
||||
final String trimmed = raw.trim();
|
||||
return trimmed.length() > 490 ? trimmed.substring(0, 490) : trimmed;
|
||||
}
|
||||
|
||||
private Long toLong(final Object o) {
|
||||
return o instanceof Number ? ((Number) o).longValue() : null;
|
||||
}
|
||||
|
||||
private int toInt(final Object o) {
|
||||
return o instanceof Number ? ((Number) o).intValue() : 0;
|
||||
}
|
||||
|
||||
private Long getLong(final JsonObject json, final String key) {
|
||||
return json.has(key) && !json.get(key).isJsonNull() ? json.get(key).getAsLong() : null;
|
||||
}
|
||||
|
||||
private BigDecimal getBigDecimal(final JsonObject json, final String key,
|
||||
final String fieldLabel) {
|
||||
if (!json.has(key) || json.get(key).isJsonNull()) return BigDecimal.ZERO;
|
||||
try {
|
||||
return json.get(key).getAsBigDecimal();
|
||||
} catch (NumberFormatException e) {
|
||||
throw new PlatformDataIntegrityException(
|
||||
"error.msg.sharecollection.field.invalid.number",
|
||||
"Field '" + fieldLabel + "' must be a valid number.");
|
||||
}
|
||||
}
|
||||
|
||||
private String getString(final JsonObject json, final String key) {
|
||||
return json.has(key) && !json.get(key).isJsonNull() ? json.get(key).getAsString() : null;
|
||||
}
|
||||
}
|
||||
+563
-506
File diff suppressed because it is too large
Load Diff
+124
-123
@@ -1,123 +1,124 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.shareaccounts.start;
|
||||
|
||||
import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService;
|
||||
import org.apache.fineract.infrastructure.accountnumberformat.domain.AccountNumberFormatRepositoryWrapper;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
|
||||
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
|
||||
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
|
||||
import org.apache.fineract.portfolio.account.service.AccountNumberGenerator;
|
||||
import org.apache.fineract.portfolio.accounts.constants.AccountsApiConstants;
|
||||
import org.apache.fineract.portfolio.accounts.service.AccountsCommandsService;
|
||||
import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService;
|
||||
import org.apache.fineract.portfolio.client.service.ClientReadPlatformService;
|
||||
import org.apache.fineract.portfolio.note.domain.NoteRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccountAssembler;
|
||||
import org.apache.fineract.portfolio.savings.service.SavingsAccountDomainService;
|
||||
import org.apache.fineract.portfolio.savings.service.SavingsAccountReadPlatformService;
|
||||
import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccountDividendRepository;
|
||||
import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccountRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.shareaccounts.serialization.ShareAccountDataSerializer;
|
||||
import org.apache.fineract.portfolio.shareaccounts.service.PurchasedSharesReadPlatformService;
|
||||
import org.apache.fineract.portfolio.shareaccounts.service.PurchasedSharesReadPlatformServiceImpl;
|
||||
import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountChargeReadPlatformService;
|
||||
import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountChargeReadPlatformServiceImpl;
|
||||
import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountCommandsServiceImpl;
|
||||
import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountDividendReadPlatformService;
|
||||
import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountDividendReadPlatformServiceImpl;
|
||||
import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountReadPlatformService;
|
||||
import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountReadPlatformServiceImpl;
|
||||
import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountSchedularService;
|
||||
import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountSchedularServiceImpl;
|
||||
import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountWritePlatformService;
|
||||
import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountWritePlatformServiceJpaRepositoryImpl;
|
||||
import org.apache.fineract.portfolio.shareproducts.domain.ShareProductRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.shareproducts.service.ShareProductDropdownReadPlatformService;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
@Configuration
|
||||
public class ShareAccountsConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(PurchasedSharesReadPlatformService.class)
|
||||
public PurchasedSharesReadPlatformService purchasedSharesReadPlatformService(JdbcTemplate jdbcTemplate) {
|
||||
return new PurchasedSharesReadPlatformServiceImpl(jdbcTemplate);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(ShareAccountChargeReadPlatformService.class)
|
||||
public ShareAccountChargeReadPlatformService shareAccountChargeReadPlatformService(JdbcTemplate jdbcTemplate) {
|
||||
return new ShareAccountChargeReadPlatformServiceImpl(jdbcTemplate);
|
||||
}
|
||||
|
||||
@Bean(value = "SHAREACCOUNT_COMMANDSERVICE")
|
||||
@ConditionalOnMissingBean(AccountsCommandsService.class)
|
||||
public AccountsCommandsService accountsCommandsService(FromJsonHelper fromApiJsonHelper,
|
||||
ShareAccountDataSerializer shareAccountDataSerializer) {
|
||||
return new ShareAccountCommandsServiceImpl(fromApiJsonHelper, shareAccountDataSerializer);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(ShareAccountDividendReadPlatformService.class)
|
||||
public ShareAccountDividendReadPlatformService shareAccountDividendReadPlatformService(JdbcTemplate jdbcTemplate,
|
||||
ColumnValidator columnValidator, PaginationHelper paginationHelper, DatabaseSpecificSQLGenerator sqlGenerator) {
|
||||
return new ShareAccountDividendReadPlatformServiceImpl(jdbcTemplate, columnValidator, paginationHelper, sqlGenerator);
|
||||
|
||||
}
|
||||
|
||||
@Bean(value = "share" + AccountsApiConstants.READPLATFORM_NAME)
|
||||
@ConditionalOnMissingBean(ShareAccountReadPlatformService.class)
|
||||
public ShareAccountReadPlatformService shareAccountReadPlatformService(ApplicationContext applicationContext,
|
||||
ChargeReadPlatformService chargeReadPlatformService,
|
||||
ShareProductDropdownReadPlatformService shareProductDropdownReadPlatformService,
|
||||
SavingsAccountReadPlatformService savingsAccountReadPlatformService, ClientReadPlatformService clientReadPlatformService,
|
||||
ShareAccountChargeReadPlatformService shareAccountChargeReadPlatformService,
|
||||
PurchasedSharesReadPlatformService purchasedSharesReadPlatformService, JdbcTemplate jdbcTemplate,
|
||||
PaginationHelper paginationHelper, DatabaseSpecificSQLGenerator sqlGenerator) {
|
||||
return new ShareAccountReadPlatformServiceImpl(applicationContext, chargeReadPlatformService,
|
||||
shareProductDropdownReadPlatformService, savingsAccountReadPlatformService, clientReadPlatformService,
|
||||
shareAccountChargeReadPlatformService, purchasedSharesReadPlatformService, jdbcTemplate, paginationHelper, sqlGenerator);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(ShareAccountSchedularService.class)
|
||||
public ShareAccountSchedularService shareAccountSchedularService(ShareAccountDividendRepository shareAccountDividendRepository,
|
||||
SavingsAccountDomainService savingsAccountDomainService, SavingsAccountAssembler savingsAccountAssembler) {
|
||||
return new ShareAccountSchedularServiceImpl(shareAccountDividendRepository, savingsAccountDomainService, savingsAccountAssembler);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(ShareAccountWritePlatformService.class)
|
||||
public ShareAccountWritePlatformService shareAccountWritePlatformService(ShareAccountDataSerializer accountDataSerializer,
|
||||
ShareAccountRepositoryWrapper shareAccountRepository, ShareProductRepositoryWrapper shareProductRepository,
|
||||
AccountNumberGenerator accountNumberGenerator, AccountNumberFormatRepositoryWrapper accountNumberFormatRepository,
|
||||
JournalEntryWritePlatformService journalEntryWritePlatformService, NoteRepository noteRepository,
|
||||
BusinessEventNotifierService businessEventNotifierService) {
|
||||
return new ShareAccountWritePlatformServiceJpaRepositoryImpl(accountDataSerializer, shareAccountRepository, shareProductRepository,
|
||||
accountNumberGenerator, accountNumberFormatRepository, journalEntryWritePlatformService, noteRepository,
|
||||
businessEventNotifierService);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.shareaccounts.start;
|
||||
|
||||
import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService;
|
||||
import org.apache.fineract.infrastructure.accountnumberformat.domain.AccountNumberFormatRepositoryWrapper;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
|
||||
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
|
||||
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
|
||||
import org.apache.fineract.portfolio.account.service.AccountNumberGenerator;
|
||||
import org.apache.fineract.portfolio.accounts.constants.AccountsApiConstants;
|
||||
import org.apache.fineract.portfolio.accounts.service.AccountsCommandsService;
|
||||
import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService;
|
||||
import org.apache.fineract.portfolio.client.service.ClientReadPlatformService;
|
||||
import org.apache.fineract.portfolio.note.domain.NoteRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccountAssembler;
|
||||
import org.apache.fineract.portfolio.savings.service.SavingsAccountDomainService;
|
||||
import org.apache.fineract.portfolio.savings.service.SavingsAccountReadPlatformService;
|
||||
import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccountDividendRepository;
|
||||
import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccountRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.shareaccounts.serialization.ShareAccountDataSerializer;
|
||||
import org.apache.fineract.portfolio.shareaccounts.service.PurchasedSharesReadPlatformService;
|
||||
import org.apache.fineract.portfolio.shareaccounts.service.PurchasedSharesReadPlatformServiceImpl;
|
||||
import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountChargeReadPlatformService;
|
||||
import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountChargeReadPlatformServiceImpl;
|
||||
import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountCommandsServiceImpl;
|
||||
import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountDividendReadPlatformService;
|
||||
import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountDividendReadPlatformServiceImpl;
|
||||
import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountReadPlatformService;
|
||||
import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountReadPlatformServiceImpl;
|
||||
import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountSchedularService;
|
||||
import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountSchedularServiceImpl;
|
||||
import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountWritePlatformService;
|
||||
import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountWritePlatformServiceJpaRepositoryImpl;
|
||||
import org.apache.fineract.portfolio.shareproducts.domain.ShareProductRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.shareproducts.service.ShareProductDropdownReadPlatformService;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
@Configuration
|
||||
public class ShareAccountsConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(PurchasedSharesReadPlatformService.class)
|
||||
public PurchasedSharesReadPlatformService purchasedSharesReadPlatformService(JdbcTemplate jdbcTemplate) {
|
||||
return new PurchasedSharesReadPlatformServiceImpl(jdbcTemplate);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(ShareAccountChargeReadPlatformService.class)
|
||||
public ShareAccountChargeReadPlatformService shareAccountChargeReadPlatformService(JdbcTemplate jdbcTemplate) {
|
||||
return new ShareAccountChargeReadPlatformServiceImpl(jdbcTemplate);
|
||||
}
|
||||
|
||||
@Bean(value = "SHAREACCOUNT_COMMANDSERVICE")
|
||||
@ConditionalOnMissingBean(AccountsCommandsService.class)
|
||||
public AccountsCommandsService accountsCommandsService(FromJsonHelper fromApiJsonHelper,
|
||||
ShareAccountDataSerializer shareAccountDataSerializer) {
|
||||
return new ShareAccountCommandsServiceImpl(fromApiJsonHelper, shareAccountDataSerializer);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(ShareAccountDividendReadPlatformService.class)
|
||||
public ShareAccountDividendReadPlatformService shareAccountDividendReadPlatformService(JdbcTemplate jdbcTemplate,
|
||||
ColumnValidator columnValidator, PaginationHelper paginationHelper, DatabaseSpecificSQLGenerator sqlGenerator) {
|
||||
return new ShareAccountDividendReadPlatformServiceImpl(jdbcTemplate, columnValidator, paginationHelper, sqlGenerator);
|
||||
|
||||
}
|
||||
|
||||
@Bean(value = "share" + AccountsApiConstants.READPLATFORM_NAME)
|
||||
@ConditionalOnMissingBean(ShareAccountReadPlatformService.class)
|
||||
public ShareAccountReadPlatformService shareAccountReadPlatformService(ApplicationContext applicationContext,
|
||||
ChargeReadPlatformService chargeReadPlatformService,
|
||||
ShareProductDropdownReadPlatformService shareProductDropdownReadPlatformService,
|
||||
SavingsAccountReadPlatformService savingsAccountReadPlatformService, ClientReadPlatformService clientReadPlatformService,
|
||||
ShareAccountChargeReadPlatformService shareAccountChargeReadPlatformService,
|
||||
PurchasedSharesReadPlatformService purchasedSharesReadPlatformService, JdbcTemplate jdbcTemplate,
|
||||
PaginationHelper paginationHelper, DatabaseSpecificSQLGenerator sqlGenerator) {
|
||||
return new ShareAccountReadPlatformServiceImpl(applicationContext, chargeReadPlatformService,
|
||||
shareProductDropdownReadPlatformService, savingsAccountReadPlatformService, clientReadPlatformService,
|
||||
shareAccountChargeReadPlatformService, purchasedSharesReadPlatformService, jdbcTemplate, paginationHelper, sqlGenerator);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(ShareAccountSchedularService.class)
|
||||
public ShareAccountSchedularService shareAccountSchedularService(ShareAccountDividendRepository shareAccountDividendRepository,
|
||||
SavingsAccountDomainService savingsAccountDomainService, SavingsAccountAssembler savingsAccountAssembler) {
|
||||
return new ShareAccountSchedularServiceImpl(shareAccountDividendRepository, savingsAccountDomainService, savingsAccountAssembler);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(ShareAccountWritePlatformService.class)
|
||||
public ShareAccountWritePlatformService shareAccountWritePlatformService(ShareAccountDataSerializer accountDataSerializer,
|
||||
ShareAccountRepositoryWrapper shareAccountRepository, ShareProductRepositoryWrapper shareProductRepository,
|
||||
AccountNumberGenerator accountNumberGenerator, AccountNumberFormatRepositoryWrapper accountNumberFormatRepository,
|
||||
JournalEntryWritePlatformService journalEntryWritePlatformService, NoteRepository noteRepository,
|
||||
org.springframework.jdbc.core.JdbcTemplate jdbcTemplate,
|
||||
BusinessEventNotifierService businessEventNotifierService) {
|
||||
return new ShareAccountWritePlatformServiceJpaRepositoryImpl(accountDataSerializer, shareAccountRepository, shareProductRepository,
|
||||
accountNumberGenerator, accountNumberFormatRepository, journalEntryWritePlatformService, noteRepository,
|
||||
jdbcTemplate, businessEventNotifierService);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user