feat(cashier): remove GL entries for vault-to-cashier transfers (Option A)
ALLOCATE (vault→cashier) and SETTLE (cashier→vault) no longer post DR CASH_AT_TELLER / CR CASH_AT_MAINVAULT journal entries. Rationale: Cash transfer between vault and teller drawer is an internal physical movement — the denomination/amount is already tracked operationally via m_cash_transfer and m_cash_settlement tables. A single Cash in Hand GL (CASH_AT_MAINVAULT) covers all bank cash. GL entries now only occur on actual customer deposit/withdrawal transactions (SAVINGS_REFERENCE ↔ SAVINGS_CONTROL), keeping the GL clean and RBI-compliant. Removed unused imports and field injections: JournalEntryRepository, FinancialActivityAccountRepositoryWrapper, FinancialActivity, FinancialActivityAccount, GLAccount, JournalEntry, JournalEntryType Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
8bf28a8033
commit
6bdcac7b77
+399
-451
@@ -1,451 +1,399 @@
|
|||||||
/**
|
/**
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
* or more contributor license agreements. See the NOTICE file
|
* or more contributor license agreements. See the NOTICE file
|
||||||
* distributed with this work for additional information
|
* distributed with this work for additional information
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
* to you under the Apache License, Version 2.0 (the
|
* to you under the Apache License, Version 2.0 (the
|
||||||
* "License"); you may not use this file except in compliance
|
* "License"); you may not use this file except in compliance
|
||||||
* with the License. You may obtain a copy of the License at
|
* with the License. You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing,
|
* Unless required by applicable law or agreed to in writing,
|
||||||
* software distributed under the License is distributed on an
|
* software distributed under the License is distributed on an
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
* KIND, either express or implied. See the License for the
|
* KIND, either express or implied. See the License for the
|
||||||
* specific language governing permissions and limitations
|
* specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
package org.apache.fineract.organisation.teller.service;
|
package org.apache.fineract.organisation.teller.service;
|
||||||
|
|
||||||
import jakarta.persistence.PersistenceException;
|
import jakarta.persistence.PersistenceException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
import org.apache.fineract.accounting.common.AccountingConstants.FinancialActivity;
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
import org.apache.fineract.accounting.financialactivityaccount.domain.FinancialActivityAccount;
|
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||||
import org.apache.fineract.accounting.financialactivityaccount.domain.FinancialActivityAccountRepositoryWrapper;
|
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||||
import org.apache.fineract.accounting.glaccount.domain.GLAccount;
|
import org.apache.fineract.infrastructure.core.exception.ErrorHandler;
|
||||||
import org.apache.fineract.accounting.journalentry.domain.JournalEntry;
|
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||||
import org.apache.fineract.accounting.journalentry.domain.JournalEntryRepository;
|
import org.apache.fineract.infrastructure.security.exception.NoAuthorizationException;
|
||||||
import org.apache.fineract.accounting.journalentry.domain.JournalEntryType;
|
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
import org.apache.fineract.organisation.office.domain.Office;
|
||||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper;
|
||||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
|
import org.apache.fineract.organisation.staff.domain.Staff;
|
||||||
import org.apache.fineract.infrastructure.core.exception.ErrorHandler;
|
import org.apache.fineract.organisation.staff.domain.StaffRepository;
|
||||||
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
|
import org.apache.fineract.organisation.staff.exception.StaffNotFoundException;
|
||||||
import org.apache.fineract.infrastructure.security.exception.NoAuthorizationException;
|
import org.apache.fineract.organisation.teller.data.CashierTransactionDataValidator;
|
||||||
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
import org.apache.fineract.organisation.teller.domain.Cashier;
|
||||||
import org.apache.fineract.organisation.office.domain.Office;
|
import org.apache.fineract.organisation.teller.domain.CashierRepository;
|
||||||
import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper;
|
import org.apache.fineract.organisation.teller.domain.CashierTransaction;
|
||||||
import org.apache.fineract.organisation.staff.domain.Staff;
|
import org.apache.fineract.organisation.teller.domain.CashierTransactionRepository;
|
||||||
import org.apache.fineract.organisation.staff.domain.StaffRepository;
|
import org.apache.fineract.organisation.teller.domain.CashierTxnType;
|
||||||
import org.apache.fineract.organisation.staff.exception.StaffNotFoundException;
|
import org.apache.fineract.organisation.teller.domain.Teller;
|
||||||
import org.apache.fineract.organisation.teller.data.CashierTransactionDataValidator;
|
import org.apache.fineract.organisation.teller.domain.TellerRepositoryWrapper;
|
||||||
import org.apache.fineract.organisation.teller.domain.Cashier;
|
import org.apache.fineract.organisation.teller.exception.CashierExistForTellerException;
|
||||||
import org.apache.fineract.organisation.teller.domain.CashierRepository;
|
import org.apache.fineract.organisation.teller.exception.CashierNotFoundException;
|
||||||
import org.apache.fineract.organisation.teller.domain.CashierTransaction;
|
import org.apache.fineract.organisation.teller.serialization.TellerCommandFromApiJsonDeserializer;
|
||||||
import org.apache.fineract.organisation.teller.domain.CashierTransactionRepository;
|
import org.apache.fineract.useradministration.domain.AppUser;
|
||||||
import org.apache.fineract.organisation.teller.domain.CashierTxnType;
|
import org.springframework.dao.DataIntegrityViolationException;
|
||||||
import org.apache.fineract.organisation.teller.domain.Teller;
|
import org.springframework.orm.jpa.JpaSystemException;
|
||||||
import org.apache.fineract.organisation.teller.domain.TellerRepositoryWrapper;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.apache.fineract.organisation.teller.exception.CashierExistForTellerException;
|
|
||||||
import org.apache.fineract.organisation.teller.exception.CashierNotFoundException;
|
@AllArgsConstructor
|
||||||
import org.apache.fineract.organisation.teller.serialization.TellerCommandFromApiJsonDeserializer;
|
@Slf4j
|
||||||
import org.apache.fineract.useradministration.domain.AppUser;
|
public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformService {
|
||||||
import org.springframework.dao.DataIntegrityViolationException;
|
|
||||||
import org.springframework.orm.jpa.JpaSystemException;
|
private final PlatformSecurityContext context;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
private final TellerCommandFromApiJsonDeserializer fromApiJsonDeserializer;
|
||||||
|
private final TellerRepositoryWrapper tellerRepositoryWrapper;
|
||||||
@AllArgsConstructor
|
private final OfficeRepositoryWrapper officeRepositoryWrapper;
|
||||||
@Slf4j
|
private final StaffRepository staffRepository;
|
||||||
public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformService {
|
private final CashierRepository cashierRepository;
|
||||||
|
private final CashierTransactionRepository cashierTxnRepository;
|
||||||
private final PlatformSecurityContext context;
|
private final CashierTransactionDataValidator cashierTransactionDataValidator;
|
||||||
private final TellerCommandFromApiJsonDeserializer fromApiJsonDeserializer;
|
|
||||||
private final TellerRepositoryWrapper tellerRepositoryWrapper;
|
@Override
|
||||||
private final OfficeRepositoryWrapper officeRepositoryWrapper;
|
@Transactional
|
||||||
private final StaffRepository staffRepository;
|
public CommandProcessingResult createTeller(JsonCommand command) {
|
||||||
private final CashierRepository cashierRepository;
|
try {
|
||||||
private final CashierTransactionRepository cashierTxnRepository;
|
this.context.authenticatedUser();
|
||||||
private final JournalEntryRepository glJournalEntryRepository;
|
|
||||||
private final FinancialActivityAccountRepositoryWrapper financialActivityAccountRepositoryWrapper;
|
final Long officeId = command.longValueOfParameterNamed("officeId");
|
||||||
private final CashierTransactionDataValidator cashierTransactionDataValidator;
|
|
||||||
|
this.fromApiJsonDeserializer.validateForCreateAndUpdateTeller(command.json());
|
||||||
@Override
|
|
||||||
@Transactional
|
// final Office parent =
|
||||||
public CommandProcessingResult createTeller(JsonCommand command) {
|
// validateUserPriviledgeOnOfficeAndRetrieve(currentUser, officeId);
|
||||||
try {
|
final Office tellerOffice = this.officeRepositoryWrapper.findOneWithNotFoundDetection(officeId);
|
||||||
this.context.authenticatedUser();
|
final Teller teller = Teller.fromJson(tellerOffice, command);
|
||||||
|
|
||||||
final Long officeId = command.longValueOfParameterNamed("officeId");
|
// pre save to generate id for use in office hierarchy
|
||||||
|
this.tellerRepositoryWrapper.saveAndFlush(teller);
|
||||||
this.fromApiJsonDeserializer.validateForCreateAndUpdateTeller(command.json());
|
|
||||||
|
return new CommandProcessingResultBuilder() //
|
||||||
// final Office parent =
|
.withCommandId(command.commandId()) //
|
||||||
// validateUserPriviledgeOnOfficeAndRetrieve(currentUser, officeId);
|
.withEntityId(teller.getId()) //
|
||||||
final Office tellerOffice = this.officeRepositoryWrapper.findOneWithNotFoundDetection(officeId);
|
.withOfficeId(teller.getOffice().getId()) //
|
||||||
final Teller teller = Teller.fromJson(tellerOffice, command);
|
.build();
|
||||||
|
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
|
||||||
// pre save to generate id for use in office hierarchy
|
handleTellerDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
|
||||||
this.tellerRepositoryWrapper.saveAndFlush(teller);
|
return CommandProcessingResult.empty();
|
||||||
|
} catch (final PersistenceException dve) {
|
||||||
return new CommandProcessingResultBuilder() //
|
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
|
||||||
.withCommandId(command.commandId()) //
|
handleTellerDataIntegrityIssues(command, throwable, dve);
|
||||||
.withEntityId(teller.getId()) //
|
return CommandProcessingResult.empty();
|
||||||
.withOfficeId(teller.getOffice().getId()) //
|
}
|
||||||
.build();
|
}
|
||||||
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
|
|
||||||
handleTellerDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
|
@Override
|
||||||
return CommandProcessingResult.empty();
|
@Transactional
|
||||||
} catch (final PersistenceException dve) {
|
public CommandProcessingResult modifyTeller(Long tellerId, JsonCommand command) {
|
||||||
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
|
try {
|
||||||
handleTellerDataIntegrityIssues(command, throwable, dve);
|
|
||||||
return CommandProcessingResult.empty();
|
final Long officeId = command.longValueOfParameterNamed("officeId");
|
||||||
}
|
final Office tellerOffice = this.officeRepositoryWrapper.findOneWithNotFoundDetection(officeId);
|
||||||
}
|
final AppUser currentUser = this.context.authenticatedUser();
|
||||||
|
|
||||||
@Override
|
this.fromApiJsonDeserializer.validateForCreateAndUpdateTeller(command.json());
|
||||||
@Transactional
|
|
||||||
public CommandProcessingResult modifyTeller(Long tellerId, JsonCommand command) {
|
final Teller teller = validateUserPriviledgeOnTellerAndRetrieve(currentUser, tellerId);
|
||||||
try {
|
|
||||||
|
final Map<String, Object> changes = teller.update(tellerOffice, command);
|
||||||
final Long officeId = command.longValueOfParameterNamed("officeId");
|
|
||||||
final Office tellerOffice = this.officeRepositoryWrapper.findOneWithNotFoundDetection(officeId);
|
if (!changes.isEmpty()) {
|
||||||
final AppUser currentUser = this.context.authenticatedUser();
|
this.tellerRepositoryWrapper.saveAndFlush(teller);
|
||||||
|
}
|
||||||
this.fromApiJsonDeserializer.validateForCreateAndUpdateTeller(command.json());
|
|
||||||
|
return new CommandProcessingResultBuilder() //
|
||||||
final Teller teller = validateUserPriviledgeOnTellerAndRetrieve(currentUser, tellerId);
|
.withCommandId(command.commandId()) //
|
||||||
|
.withEntityId(teller.getId()) //
|
||||||
final Map<String, Object> changes = teller.update(tellerOffice, command);
|
.withOfficeId(teller.officeId()) //
|
||||||
|
.with(changes) //
|
||||||
if (!changes.isEmpty()) {
|
.build();
|
||||||
this.tellerRepositoryWrapper.saveAndFlush(teller);
|
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
|
||||||
}
|
handleTellerDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
|
||||||
|
return CommandProcessingResult.empty();
|
||||||
return new CommandProcessingResultBuilder() //
|
} catch (final PersistenceException dve) {
|
||||||
.withCommandId(command.commandId()) //
|
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
|
||||||
.withEntityId(teller.getId()) //
|
handleTellerDataIntegrityIssues(command, throwable, dve);
|
||||||
.withOfficeId(teller.officeId()) //
|
return CommandProcessingResult.empty();
|
||||||
.with(changes) //
|
}
|
||||||
.build();
|
}
|
||||||
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
|
|
||||||
handleTellerDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
|
/*
|
||||||
return CommandProcessingResult.empty();
|
* used to restrict modifying operations to office that are either the users office or lower (child) in the office
|
||||||
} catch (final PersistenceException dve) {
|
* hierarchy
|
||||||
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
|
*/
|
||||||
handleTellerDataIntegrityIssues(command, throwable, dve);
|
private Teller validateUserPriviledgeOnTellerAndRetrieve(final AppUser currentUser, final Long tellerId) {
|
||||||
return CommandProcessingResult.empty();
|
|
||||||
}
|
final Long userOfficeId = currentUser.getOffice().getId();
|
||||||
}
|
final Office userOffice = this.officeRepositoryWrapper.findOfficeHierarchy(userOfficeId);
|
||||||
|
final Teller tellerToReturn = this.tellerRepositoryWrapper.findOneWithNotFoundDetection(tellerId);
|
||||||
/*
|
final Long tellerOfficeId = tellerToReturn.officeId();
|
||||||
* used to restrict modifying operations to office that are either the users office or lower (child) in the office
|
if (userOffice.doesNotHaveAnOfficeInHierarchyWithId(tellerOfficeId)) {
|
||||||
* hierarchy
|
throw new NoAuthorizationException("User does not have sufficient priviledges to act on the provided office.");
|
||||||
*/
|
}
|
||||||
private Teller validateUserPriviledgeOnTellerAndRetrieve(final AppUser currentUser, final Long tellerId) {
|
return tellerToReturn;
|
||||||
|
}
|
||||||
final Long userOfficeId = currentUser.getOffice().getId();
|
|
||||||
final Office userOffice = this.officeRepositoryWrapper.findOfficeHierarchy(userOfficeId);
|
@Override
|
||||||
final Teller tellerToReturn = this.tellerRepositoryWrapper.findOneWithNotFoundDetection(tellerId);
|
@Transactional
|
||||||
final Long tellerOfficeId = tellerToReturn.officeId();
|
public CommandProcessingResult deleteTeller(Long tellerId) {
|
||||||
if (userOffice.doesNotHaveAnOfficeInHierarchyWithId(tellerOfficeId)) {
|
// TODO Auto-generated method stub
|
||||||
throw new NoAuthorizationException("User does not have sufficient priviledges to act on the provided office.");
|
|
||||||
}
|
Teller teller = tellerRepositoryWrapper.findOneWithNotFoundDetection(tellerId);
|
||||||
return tellerToReturn;
|
Set<Cashier> isTellerIdPresentInCashier = teller.getCashiers();
|
||||||
}
|
|
||||||
|
for (final Cashier tellerIdInCashier : isTellerIdPresentInCashier) {
|
||||||
@Override
|
if (tellerIdInCashier.getTeller().getId().toString().equalsIgnoreCase(tellerId.toString())) {
|
||||||
@Transactional
|
throw new CashierExistForTellerException(tellerId);
|
||||||
public CommandProcessingResult deleteTeller(Long tellerId) {
|
}
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
}
|
||||||
Teller teller = tellerRepositoryWrapper.findOneWithNotFoundDetection(tellerId);
|
tellerRepositoryWrapper.delete(teller);
|
||||||
Set<Cashier> isTellerIdPresentInCashier = teller.getCashiers();
|
return new CommandProcessingResultBuilder() //
|
||||||
|
.withEntityId(teller.getId()) //
|
||||||
for (final Cashier tellerIdInCashier : isTellerIdPresentInCashier) {
|
.build();
|
||||||
if (tellerIdInCashier.getTeller().getId().toString().equalsIgnoreCase(tellerId.toString())) {
|
|
||||||
throw new CashierExistForTellerException(tellerId);
|
}
|
||||||
}
|
|
||||||
|
/*
|
||||||
}
|
* Guaranteed to throw an exception no matter what the data integrity issue is.
|
||||||
tellerRepositoryWrapper.delete(teller);
|
*/
|
||||||
return new CommandProcessingResultBuilder() //
|
private void handleTellerDataIntegrityIssues(final JsonCommand command, final Throwable realCause, final Exception dve) {
|
||||||
.withEntityId(teller.getId()) //
|
if (realCause.getMessage().contains("m_tellers_name_unq")) {
|
||||||
.build();
|
final String name = command.stringValueOfParameterNamed("name");
|
||||||
|
throw new PlatformDataIntegrityException("error.msg.teller.duplicate.name", "Teller with name `" + name + "` already exists",
|
||||||
}
|
"name", name);
|
||||||
|
}
|
||||||
/*
|
|
||||||
* Guaranteed to throw an exception no matter what the data integrity issue is.
|
log.error("Error occured.", dve);
|
||||||
*/
|
throw ErrorHandler.getMappable(dve, "error.msg.teller.unknown.data.integrity.issue",
|
||||||
private void handleTellerDataIntegrityIssues(final JsonCommand command, final Throwable realCause, final Exception dve) {
|
"Unknown data integrity issue with resource: " + realCause.getMessage());
|
||||||
if (realCause.getMessage().contains("m_tellers_name_unq")) {
|
}
|
||||||
final String name = command.stringValueOfParameterNamed("name");
|
|
||||||
throw new PlatformDataIntegrityException("error.msg.teller.duplicate.name", "Teller with name `" + name + "` already exists",
|
@Override
|
||||||
"name", name);
|
public CommandProcessingResult allocateCashierToTeller(final Long tellerId, JsonCommand command) {
|
||||||
}
|
try {
|
||||||
|
this.context.authenticatedUser();
|
||||||
log.error("Error occured.", dve);
|
Long hourStartTime;
|
||||||
throw ErrorHandler.getMappable(dve, "error.msg.teller.unknown.data.integrity.issue",
|
Long minStartTime;
|
||||||
"Unknown data integrity issue with resource: " + realCause.getMessage());
|
Long hourEndTime;
|
||||||
}
|
Long minEndTime;
|
||||||
|
String startTime = " ";
|
||||||
@Override
|
String endTime = " ";
|
||||||
public CommandProcessingResult allocateCashierToTeller(final Long tellerId, JsonCommand command) {
|
final Teller teller = this.tellerRepositoryWrapper.findOneWithNotFoundDetection(tellerId);
|
||||||
try {
|
final Office tellerOffice = teller.getOffice();
|
||||||
this.context.authenticatedUser();
|
|
||||||
Long hourStartTime;
|
final Long staffId = command.longValueOfParameterNamed("staffId");
|
||||||
Long minStartTime;
|
|
||||||
Long hourEndTime;
|
this.fromApiJsonDeserializer.validateForAllocateCashier(command.json());
|
||||||
Long minEndTime;
|
|
||||||
String startTime = " ";
|
final Staff staff = this.staffRepository.findById(staffId).orElseThrow(() -> new StaffNotFoundException(staffId));
|
||||||
String endTime = " ";
|
final Boolean isFullDay = command.booleanObjectValueOfParameterNamed("isFullDay");
|
||||||
final Teller teller = this.tellerRepositoryWrapper.findOneWithNotFoundDetection(tellerId);
|
if (!isFullDay) {
|
||||||
final Office tellerOffice = teller.getOffice();
|
hourStartTime = command.longValueOfParameterNamed("hourStartTime");
|
||||||
|
minStartTime = command.longValueOfParameterNamed("minStartTime");
|
||||||
final Long staffId = command.longValueOfParameterNamed("staffId");
|
|
||||||
|
if (minStartTime == 0) {
|
||||||
this.fromApiJsonDeserializer.validateForAllocateCashier(command.json());
|
startTime = hourStartTime.toString() + ":" + minStartTime.toString() + "0";
|
||||||
|
} else {
|
||||||
final Staff staff = this.staffRepository.findById(staffId).orElseThrow(() -> new StaffNotFoundException(staffId));
|
startTime = hourStartTime.toString() + ":" + minStartTime.toString();
|
||||||
final Boolean isFullDay = command.booleanObjectValueOfParameterNamed("isFullDay");
|
}
|
||||||
if (!isFullDay) {
|
|
||||||
hourStartTime = command.longValueOfParameterNamed("hourStartTime");
|
hourEndTime = command.longValueOfParameterNamed("hourEndTime");
|
||||||
minStartTime = command.longValueOfParameterNamed("minStartTime");
|
minEndTime = command.longValueOfParameterNamed("minEndTime");
|
||||||
|
if (minEndTime == 0) {
|
||||||
if (minStartTime == 0) {
|
endTime = hourEndTime.toString() + ":" + minEndTime.toString() + "0";
|
||||||
startTime = hourStartTime.toString() + ":" + minStartTime.toString() + "0";
|
} else {
|
||||||
} else {
|
endTime = hourEndTime.toString() + ":" + minEndTime.toString();
|
||||||
startTime = hourStartTime.toString() + ":" + minStartTime.toString();
|
}
|
||||||
}
|
|
||||||
|
}
|
||||||
hourEndTime = command.longValueOfParameterNamed("hourEndTime");
|
final Cashier cashier = Cashier.fromJson(tellerOffice, teller, staff, startTime, endTime, command);
|
||||||
minEndTime = command.longValueOfParameterNamed("minEndTime");
|
this.cashierTransactionDataValidator.validateCashierAllowedDateAndTime(cashier, teller);
|
||||||
if (minEndTime == 0) {
|
|
||||||
endTime = hourEndTime.toString() + ":" + minEndTime.toString() + "0";
|
this.cashierRepository.save(cashier);
|
||||||
} else {
|
|
||||||
endTime = hourEndTime.toString() + ":" + minEndTime.toString();
|
return new CommandProcessingResultBuilder() //
|
||||||
}
|
.withCommandId(command.commandId()) //
|
||||||
|
.withEntityId(teller.getId()) //
|
||||||
}
|
.withSubEntityId(cashier.getId()) //
|
||||||
final Cashier cashier = Cashier.fromJson(tellerOffice, teller, staff, startTime, endTime, command);
|
.build();
|
||||||
this.cashierTransactionDataValidator.validateCashierAllowedDateAndTime(cashier, teller);
|
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
|
||||||
|
handleTellerDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
|
||||||
this.cashierRepository.save(cashier);
|
return CommandProcessingResult.empty();
|
||||||
|
} catch (final PersistenceException dve) {
|
||||||
return new CommandProcessingResultBuilder() //
|
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
|
||||||
.withCommandId(command.commandId()) //
|
handleTellerDataIntegrityIssues(command, throwable, dve);
|
||||||
.withEntityId(teller.getId()) //
|
return CommandProcessingResult.empty();
|
||||||
.withSubEntityId(cashier.getId()) //
|
}
|
||||||
.build();
|
}
|
||||||
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
|
|
||||||
handleTellerDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
|
@Override
|
||||||
return CommandProcessingResult.empty();
|
@Transactional
|
||||||
} catch (final PersistenceException dve) {
|
public CommandProcessingResult updateCashierAllocation(Long tellerId, Long cashierId, JsonCommand command) {
|
||||||
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
|
try {
|
||||||
handleTellerDataIntegrityIssues(command, throwable, dve);
|
final AppUser currentUser = this.context.authenticatedUser();
|
||||||
return CommandProcessingResult.empty();
|
|
||||||
}
|
this.fromApiJsonDeserializer.validateForAllocateCashier(command.json());
|
||||||
}
|
|
||||||
|
final Long staffId = command.longValueOfParameterNamed("staffId");
|
||||||
@Override
|
final Staff staff = this.staffRepository.findById(staffId).orElseThrow(() -> new StaffNotFoundException(staffId));
|
||||||
@Transactional
|
|
||||||
public CommandProcessingResult updateCashierAllocation(Long tellerId, Long cashierId, JsonCommand command) {
|
final Cashier cashier = validateUserPriviledgeOnCashierAndRetrieve(currentUser, tellerId, cashierId);
|
||||||
try {
|
|
||||||
final AppUser currentUser = this.context.authenticatedUser();
|
cashier.setStaff(staff);
|
||||||
|
|
||||||
this.fromApiJsonDeserializer.validateForAllocateCashier(command.json());
|
// TODO - check if staff office and teller office match
|
||||||
|
|
||||||
final Long staffId = command.longValueOfParameterNamed("staffId");
|
final Map<String, Object> changes = cashier.update(command);
|
||||||
final Staff staff = this.staffRepository.findById(staffId).orElseThrow(() -> new StaffNotFoundException(staffId));
|
|
||||||
|
if (!changes.isEmpty()) {
|
||||||
final Cashier cashier = validateUserPriviledgeOnCashierAndRetrieve(currentUser, tellerId, cashierId);
|
this.cashierRepository.saveAndFlush(cashier);
|
||||||
|
}
|
||||||
cashier.setStaff(staff);
|
|
||||||
|
return new CommandProcessingResultBuilder() //
|
||||||
// TODO - check if staff office and teller office match
|
.withCommandId(command.commandId()) //
|
||||||
|
.withEntityId(cashier.getTeller().getId()) //
|
||||||
final Map<String, Object> changes = cashier.update(command);
|
.withSubEntityId(cashier.getId()) //
|
||||||
|
.with(changes) //
|
||||||
if (!changes.isEmpty()) {
|
.build();
|
||||||
this.cashierRepository.saveAndFlush(cashier);
|
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
|
||||||
}
|
handleTellerDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
|
||||||
|
return CommandProcessingResult.empty();
|
||||||
return new CommandProcessingResultBuilder() //
|
} catch (final PersistenceException dve) {
|
||||||
.withCommandId(command.commandId()) //
|
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
|
||||||
.withEntityId(cashier.getTeller().getId()) //
|
handleTellerDataIntegrityIssues(command, throwable, dve);
|
||||||
.withSubEntityId(cashier.getId()) //
|
return CommandProcessingResult.empty();
|
||||||
.with(changes) //
|
}
|
||||||
.build();
|
}
|
||||||
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
|
|
||||||
handleTellerDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
|
private Cashier validateUserPriviledgeOnCashierAndRetrieve(final AppUser currentUser, final Long tellerId, final Long cashierId) {
|
||||||
return CommandProcessingResult.empty();
|
|
||||||
} catch (final PersistenceException dve) {
|
validateUserPriviledgeOnTellerAndRetrieve(currentUser, tellerId);
|
||||||
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
|
|
||||||
handleTellerDataIntegrityIssues(command, throwable, dve);
|
return this.cashierRepository.findById(cashierId).orElse(null);
|
||||||
return CommandProcessingResult.empty();
|
}
|
||||||
}
|
|
||||||
}
|
@Override
|
||||||
|
@Transactional
|
||||||
private Cashier validateUserPriviledgeOnCashierAndRetrieve(final AppUser currentUser, final Long tellerId, final Long cashierId) {
|
public CommandProcessingResult deleteCashierAllocation(Long tellerId, Long cashierId, JsonCommand command) {
|
||||||
|
try {
|
||||||
validateUserPriviledgeOnTellerAndRetrieve(currentUser, tellerId);
|
final AppUser currentUser = this.context.authenticatedUser();
|
||||||
|
final Cashier cashier = validateUserPriviledgeOnCashierAndRetrieve(currentUser, tellerId, cashierId);
|
||||||
return this.cashierRepository.findById(cashierId).orElse(null);
|
this.cashierRepository.delete(cashier);
|
||||||
}
|
|
||||||
|
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
|
||||||
@Override
|
handleTellerDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
|
||||||
@Transactional
|
return CommandProcessingResult.empty();
|
||||||
public CommandProcessingResult deleteCashierAllocation(Long tellerId, Long cashierId, JsonCommand command) {
|
} catch (final PersistenceException dve) {
|
||||||
try {
|
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
|
||||||
final AppUser currentUser = this.context.authenticatedUser();
|
handleTellerDataIntegrityIssues(command, throwable, dve);
|
||||||
final Cashier cashier = validateUserPriviledgeOnCashierAndRetrieve(currentUser, tellerId, cashierId);
|
return CommandProcessingResult.empty();
|
||||||
this.cashierRepository.delete(cashier);
|
}
|
||||||
|
|
||||||
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
|
return new CommandProcessingResultBuilder() //
|
||||||
handleTellerDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
|
.withEntityId(cashierId) //
|
||||||
return CommandProcessingResult.empty();
|
.build();
|
||||||
} catch (final PersistenceException dve) {
|
}
|
||||||
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
|
|
||||||
handleTellerDataIntegrityIssues(command, throwable, dve);
|
/*
|
||||||
return CommandProcessingResult.empty();
|
* @Override public CommandProcessingResult inwardCashToCashier (final Long cashierId, final CashierTransaction
|
||||||
}
|
* cashierTxn) { CashierTxnType txnType = CashierTxnType.INWARD_CASH_TXN; // pre save to generate id for use in
|
||||||
|
* office hierarchy this.cashierTxnRepository.save(cashierTxn); }
|
||||||
return new CommandProcessingResultBuilder() //
|
*/
|
||||||
.withEntityId(cashierId) //
|
|
||||||
.build();
|
@Override
|
||||||
}
|
public CommandProcessingResult allocateCashToCashier(final Long cashierId, JsonCommand command) {
|
||||||
|
return doTransactionForCashier(cashierId, CashierTxnType.ALLOCATE, command); // For
|
||||||
/*
|
// fund
|
||||||
* @Override public CommandProcessingResult inwardCashToCashier (final Long cashierId, final CashierTransaction
|
// allocation
|
||||||
* cashierTxn) { CashierTxnType txnType = CashierTxnType.INWARD_CASH_TXN; // pre save to generate id for use in
|
// to
|
||||||
* office hierarchy this.cashierTxnRepository.save(cashierTxn); }
|
// cashier
|
||||||
*/
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CommandProcessingResult allocateCashToCashier(final Long cashierId, JsonCommand command) {
|
public CommandProcessingResult settleCashFromCashier(final Long cashierId, JsonCommand command) {
|
||||||
return doTransactionForCashier(cashierId, CashierTxnType.ALLOCATE, command); // For
|
|
||||||
// fund
|
this.cashierTransactionDataValidator.validateSettleCashAndCashOutTransactions(cashierId, command);
|
||||||
// allocation
|
|
||||||
// to
|
return doTransactionForCashier(cashierId, CashierTxnType.SETTLE, command); // For
|
||||||
// cashier
|
// fund
|
||||||
}
|
// settlement
|
||||||
|
// from
|
||||||
@Override
|
// cashier
|
||||||
public CommandProcessingResult settleCashFromCashier(final Long cashierId, JsonCommand command) {
|
}
|
||||||
|
|
||||||
this.cashierTransactionDataValidator.validateSettleCashAndCashOutTransactions(cashierId, command);
|
private CommandProcessingResult doTransactionForCashier(final Long cashierId, final CashierTxnType txnType, JsonCommand command) {
|
||||||
|
try {
|
||||||
return doTransactionForCashier(cashierId, CashierTxnType.SETTLE, command); // For
|
final AppUser currentUser = this.context.authenticatedUser();
|
||||||
// fund
|
|
||||||
// settlement
|
final Cashier cashier = this.cashierRepository.findById(cashierId).orElseThrow(() -> new CashierNotFoundException(cashierId));
|
||||||
// from
|
|
||||||
// cashier
|
this.fromApiJsonDeserializer.validateForCashTxnForCashier(command.json());
|
||||||
}
|
|
||||||
|
// TODO: can we please remove this whole block?!? this is 20 lines of dead code!!!
|
||||||
private CommandProcessingResult doTransactionForCashier(final Long cashierId, final CashierTxnType txnType, JsonCommand command) {
|
final String entityType = command.stringValueOfParameterNamed("entityType");
|
||||||
try {
|
if (entityType != null) {
|
||||||
final AppUser currentUser = this.context.authenticatedUser();
|
if (entityType.equals("loan account")) {
|
||||||
|
// TODO : Check if loan account exists
|
||||||
final Cashier cashier = this.cashierRepository.findById(cashierId).orElseThrow(() -> new CashierNotFoundException(cashierId));
|
// LoanAccount loan = null;
|
||||||
|
// if (loan == null) { throw new
|
||||||
this.fromApiJsonDeserializer.validateForCashTxnForCashier(command.json());
|
// LoanAccountFoundException(entityId); }
|
||||||
|
} else if (entityType.equals("savings account")) {
|
||||||
// TODO: can we please remove this whole block?!? this is 20 lines of dead code!!!
|
// TODO : Check if loan account exists
|
||||||
final String entityType = command.stringValueOfParameterNamed("entityType");
|
// SavingsAccount savingsaccount = null;
|
||||||
if (entityType != null) {
|
// if (savingsaccount == null) { throw new
|
||||||
if (entityType.equals("loan account")) {
|
// SavingsAccountNotFoundException(entityId); }
|
||||||
// TODO : Check if loan account exists
|
|
||||||
// LoanAccount loan = null;
|
}
|
||||||
// if (loan == null) { throw new
|
if (entityType.equals("client")) {
|
||||||
// LoanAccountFoundException(entityId); }
|
// TODO: Check if client exists
|
||||||
} else if (entityType.equals("savings account")) {
|
// Client client = null;
|
||||||
// TODO : Check if loan account exists
|
// if (client == null) { throw new
|
||||||
// SavingsAccount savingsaccount = null;
|
// ClientNotFoundException(entityId); }
|
||||||
// if (savingsaccount == null) { throw new
|
} else {
|
||||||
// SavingsAccountNotFoundException(entityId); }
|
// TODO : Invalid type handling
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (entityType.equals("client")) {
|
|
||||||
// TODO: Check if client exists
|
final CashierTransaction cashierTxn = CashierTransaction.fromJson(cashier, command);
|
||||||
// Client client = null;
|
cashierTxn.setTxnType(txnType.getId());
|
||||||
// if (client == null) { throw new
|
|
||||||
// ClientNotFoundException(entityId); }
|
this.cashierTxnRepository.save(cashierTxn);
|
||||||
} else {
|
|
||||||
// TODO : Invalid type handling
|
// GL entries skipped for vault-to-cashier (ALLOCATE) and cashier-to-vault (SETTLE)
|
||||||
}
|
// transfers. Cash is internal bank physical movement — denomination tracking is
|
||||||
}
|
// handled operationally via m_cash_transfer / m_cash_settlement tables.
|
||||||
|
// GL impact happens only on customer deposit/withdrawal transactions.
|
||||||
final CashierTransaction cashierTxn = CashierTransaction.fromJson(cashier, command);
|
|
||||||
cashierTxn.setTxnType(txnType.getId());
|
return new CommandProcessingResultBuilder() //
|
||||||
|
.withCommandId(command.commandId()) //
|
||||||
this.cashierTxnRepository.save(cashierTxn);
|
.withEntityId(cashier.getId()) //
|
||||||
|
.withSubEntityId(cashierTxn.getId()) //
|
||||||
// Pass the journal entries
|
.build();
|
||||||
FinancialActivityAccount mainVaultFinancialActivityAccount = this.financialActivityAccountRepositoryWrapper
|
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
|
||||||
.findByFinancialActivityTypeWithNotFoundDetection(FinancialActivity.CASH_AT_MAINVAULT.getValue());
|
handleTellerDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
|
||||||
FinancialActivityAccount tellerCashFinancialActivityAccount = this.financialActivityAccountRepositoryWrapper
|
return CommandProcessingResult.empty();
|
||||||
.findByFinancialActivityTypeWithNotFoundDetection(FinancialActivity.CASH_AT_TELLER.getValue());
|
} catch (final PersistenceException dve) {
|
||||||
GLAccount creditAccount = null;
|
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
|
||||||
GLAccount debitAccount = null;
|
handleTellerDataIntegrityIssues(command, throwable, dve);
|
||||||
if (txnType.equals(CashierTxnType.ALLOCATE)) {
|
return CommandProcessingResult.empty();
|
||||||
debitAccount = tellerCashFinancialActivityAccount.getGlAccount();
|
}
|
||||||
creditAccount = mainVaultFinancialActivityAccount.getGlAccount();
|
}
|
||||||
} else if (txnType.equals(CashierTxnType.SETTLE)) {
|
|
||||||
debitAccount = mainVaultFinancialActivityAccount.getGlAccount();
|
}
|
||||||
creditAccount = tellerCashFinancialActivityAccount.getGlAccount();
|
|
||||||
}
|
|
||||||
|
|
||||||
final Office cashierOffice = cashier.getTeller().getOffice();
|
|
||||||
|
|
||||||
final Long time = System.currentTimeMillis();
|
|
||||||
final String uniqueVal = String.valueOf(time) + currentUser.getId() + cashierOffice.getId();
|
|
||||||
final String transactionId = Long.toHexString(Long.parseLong(uniqueVal));
|
|
||||||
|
|
||||||
final JournalEntry debitJournalEntry = JournalEntry.createNew(cashierOffice, null, // payment
|
|
||||||
// detail
|
|
||||||
debitAccount, cashierTxn.getCurrencyCode(),
|
|
||||||
|
|
||||||
transactionId, false, // manual entry
|
|
||||||
cashierTxn.getTxnDate(), JournalEntryType.DEBIT, cashierTxn.getTxnAmount(), cashierTxn.getTxnNote(), // Description
|
|
||||||
null, null, null, // entity Type, entityId, reference number
|
|
||||||
null, null, null, null); // Loan
|
|
||||||
// and
|
|
||||||
// Savings
|
|
||||||
// Txn
|
|
||||||
|
|
||||||
final JournalEntry creditJournalEntry = JournalEntry.createNew(cashierOffice, null, // payment
|
|
||||||
// detail
|
|
||||||
creditAccount, cashierTxn.getCurrencyCode(),
|
|
||||||
|
|
||||||
transactionId, false, // manual entry
|
|
||||||
cashierTxn.getTxnDate(), JournalEntryType.CREDIT, cashierTxn.getTxnAmount(), cashierTxn.getTxnNote(), // Description
|
|
||||||
null, null, null, // entity Type, entityId, reference number
|
|
||||||
null, null, null, null); // Loan
|
|
||||||
// and
|
|
||||||
// Savings
|
|
||||||
// Txn
|
|
||||||
|
|
||||||
this.glJournalEntryRepository.saveAndFlush(debitJournalEntry);
|
|
||||||
this.glJournalEntryRepository.saveAndFlush(creditJournalEntry);
|
|
||||||
|
|
||||||
return new CommandProcessingResultBuilder() //
|
|
||||||
.withCommandId(command.commandId()) //
|
|
||||||
.withEntityId(cashier.getId()) //
|
|
||||||
.withSubEntityId(cashierTxn.getId()) //
|
|
||||||
.build();
|
|
||||||
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
|
|
||||||
handleTellerDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
|
|
||||||
return CommandProcessingResult.empty();
|
|
||||||
} catch (final PersistenceException dve) {
|
|
||||||
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
|
|
||||||
handleTellerDataIntegrityIssues(command, throwable, dve);
|
|
||||||
return CommandProcessingResult.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user