MIFOSX-172: wip - support for loan disbursal and undo with reversing transactions.
This commit is contained in:
@@ -1085,7 +1085,6 @@ CREATE TABLE `m_loan_transaction` (
|
|||||||
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
`loan_id` bigint(20) NOT NULL,
|
`loan_id` bigint(20) NOT NULL,
|
||||||
`transaction_type_enum` smallint(5) NOT NULL,
|
`transaction_type_enum` smallint(5) NOT NULL,
|
||||||
`contra_id` bigint(20) DEFAULT NULL,
|
|
||||||
`transaction_date` date NOT NULL,
|
`transaction_date` date NOT NULL,
|
||||||
`amount` decimal(19,6) NOT NULL,
|
`amount` decimal(19,6) NOT NULL,
|
||||||
`createdby_id` bigint(20) DEFAULT NULL,
|
`createdby_id` bigint(20) DEFAULT NULL,
|
||||||
@@ -1096,11 +1095,10 @@ CREATE TABLE `m_loan_transaction` (
|
|||||||
`interest_portion_derived` decimal(19,6) DEFAULT NULL,
|
`interest_portion_derived` decimal(19,6) DEFAULT NULL,
|
||||||
`fee_charges_portion_derived` decimal(19,6) DEFAULT NULL,
|
`fee_charges_portion_derived` decimal(19,6) DEFAULT NULL,
|
||||||
`penalty_charges_portion_derived` decimal(19,6) DEFAULT NULL,
|
`penalty_charges_portion_derived` decimal(19,6) DEFAULT NULL,
|
||||||
|
`is_reversed` tinyint(1) NOT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `FKCFCEA42640BE0710` (`loan_id`),
|
KEY `FKCFCEA42640BE0710` (`loan_id`),
|
||||||
KEY `FKCFCEA426FC69F3F1` (`contra_id`),
|
CONSTRAINT `FKCFCEA42640BE0710` FOREIGN KEY (`loan_id`) REFERENCES `m_loan` (`id`)
|
||||||
CONSTRAINT `FKCFCEA42640BE0710` FOREIGN KEY (`loan_id`) REFERENCES `m_loan` (`id`),
|
|
||||||
CONSTRAINT `FKCFCEA426FC69F3F1` FOREIGN KEY (`contra_id`) REFERENCES `m_loan_transaction` (`id`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
@@ -1939,4 +1937,4 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||||
|
|
||||||
-- Dump completed on 2013-02-14 23:47:02
|
-- Dump completed on 2013-02-18 13:20:24
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
ALTER TABLE `m_loan_transaction`
|
||||||
|
ADD COLUMN `is_reversed` TINYINT(1) NOT NULL AFTER `penalty_charges_portion_derived`;
|
||||||
|
|
||||||
|
-- === update is_reversed column to true for all fields where contra_id is not null
|
||||||
|
|
||||||
|
UPDATE `m_loan_transaction` SET `is_reversed` = 1 WHERE contra_id is not null;
|
||||||
|
|
||||||
|
ALTER TABLE `m_loan_transaction` DROP FOREIGN KEY `FKCFCEA426FC69F3F1`;
|
||||||
|
ALTER TABLE `m_loan_transaction`
|
||||||
|
DROP COLUMN `contra_id` ,
|
||||||
|
DROP INDEX `FKCFCEA426FC69F3F1`;
|
||||||
+1
-1
@@ -221,7 +221,7 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*** Debit loan Portfolio and credit Fund source for Disbursal **/
|
/*** Debit loan Portfolio and credit Fund source for Disbursal **/
|
||||||
if (loanTransactionDTO.isDisbursement()) {
|
if (loanTransactionDTO.isDisbursement() && !loanTransactionDTO.isContra()) {
|
||||||
|
|
||||||
final GLAccount loanPortfolioAccount = getLinkedFinAccountForLoanProduct(loanProductId,
|
final GLAccount loanPortfolioAccount = getLinkedFinAccountForLoanProduct(loanProductId,
|
||||||
CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO);
|
CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO);
|
||||||
|
|||||||
+33
-55
@@ -1106,40 +1106,6 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
handleDisbursementTransaction(expectedDisbursedOnLocalDate);
|
handleDisbursementTransaction(expectedDisbursedOnLocalDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Object> deriveDisbursementData(final CurrencyData currencyData, final List<Long> existingTransactionIds) {
|
|
||||||
|
|
||||||
final Map<String, Object> accountingBridgeData = new LinkedHashMap<String, Object>(20);
|
|
||||||
|
|
||||||
accountingBridgeData.put("loanId", this.getId());
|
|
||||||
accountingBridgeData.put("loanProductId", this.productId());
|
|
||||||
accountingBridgeData.put("officeId", this.getOfficeId());
|
|
||||||
accountingBridgeData.put("cashBasedAccountingEnabled", this.isCashBasedAccountingEnabledOnLoanProduct());
|
|
||||||
accountingBridgeData.put("accrualBasedAccountingEnabled", this.isAccrualBasedAccountingEnabledOnLoanProduct());
|
|
||||||
|
|
||||||
final List<Map<String, Object>> newLoanTransactions = new ArrayList<Map<String, Object>>();
|
|
||||||
final List<LoanTransaction> disbursementTransactions = findDisbursementTransactions();
|
|
||||||
for (LoanTransaction loanTransaction : disbursementTransactions) {
|
|
||||||
if (!existingTransactionIds.contains(loanTransaction.getId())) {
|
|
||||||
newLoanTransactions.add(loanTransaction.toMapData(currencyData));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
accountingBridgeData.put("newLoanTransactions", newLoanTransactions);
|
|
||||||
|
|
||||||
return accountingBridgeData;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<LoanTransaction> findDisbursementTransactions() {
|
|
||||||
List<LoanTransaction> found = new ArrayList<LoanTransaction>();
|
|
||||||
for (LoanTransaction transaction : this.loanTransactions) {
|
|
||||||
if (transaction.isDisbursement() || transaction.isRepaymentAtDisbursement()) {
|
|
||||||
found.add(transaction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Collection<Long> findExistingTransactionIds() {
|
private Collection<Long> findExistingTransactionIds() {
|
||||||
|
|
||||||
Collection<Long> ids = new ArrayList<Long>();
|
Collection<Long> ids = new ArrayList<Long>();
|
||||||
@@ -1151,9 +1117,22 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
return ids;
|
return ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Collection<Long> findExistingReversedTransactionIds() {
|
||||||
|
|
||||||
|
final Collection<Long> ids = new ArrayList<Long>();
|
||||||
|
|
||||||
|
for (LoanTransaction transaction : this.loanTransactions) {
|
||||||
|
if (transaction.isReversed()) {
|
||||||
|
ids.add(transaction.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
|
||||||
public Map<String, Object> disburse(final AppUser currentUser, final JsonCommand command,
|
public Map<String, Object> disburse(final AppUser currentUser, final JsonCommand command,
|
||||||
final LoanLifecycleStateMachine loanLifecycleStateMachine, final ApplicationCurrency currency,
|
final LoanLifecycleStateMachine loanLifecycleStateMachine, final ApplicationCurrency currency,
|
||||||
final List<Long> existingTransactionIds) {
|
final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds) {
|
||||||
|
|
||||||
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
|
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
|
||||||
|
|
||||||
@@ -1161,6 +1140,10 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
|
|
||||||
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSED, LoanStatus.fromInt(this.loanStatus));
|
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSED, LoanStatus.fromInt(this.loanStatus));
|
||||||
if (!statusEnum.hasStateOf(LoanStatus.fromInt(this.loanStatus))) {
|
if (!statusEnum.hasStateOf(LoanStatus.fromInt(this.loanStatus))) {
|
||||||
|
|
||||||
|
existingTransactionIds.addAll(findExistingTransactionIds());
|
||||||
|
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
||||||
|
|
||||||
this.loanStatus = statusEnum.getValue();
|
this.loanStatus = statusEnum.getValue();
|
||||||
actualChanges.put("status", LoanEnumerations.status(this.loanStatus));
|
actualChanges.put("status", LoanEnumerations.status(this.loanStatus));
|
||||||
|
|
||||||
@@ -1186,8 +1169,6 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
if (isRepaymentScheduleRegenerationRequiredForDisbursement(disbursedOn)) {
|
if (isRepaymentScheduleRegenerationRequiredForDisbursement(disbursedOn)) {
|
||||||
regenerateRepaymentSchedule(currency);
|
regenerateRepaymentSchedule(currency);
|
||||||
}
|
}
|
||||||
|
|
||||||
existingTransactionIds.addAll(findExistingTransactionIds());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return actualChanges;
|
return actualChanges;
|
||||||
@@ -1276,7 +1257,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Object> undoDisbursal(final LoanLifecycleStateMachine loanLifecycleStateMachine,
|
public Map<String, Object> undoDisbursal(final LoanLifecycleStateMachine loanLifecycleStateMachine,
|
||||||
final List<Long> existingTransactionIds) {
|
final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds) {
|
||||||
|
|
||||||
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
|
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
|
||||||
|
|
||||||
@@ -1291,8 +1272,9 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
actualChanges.put("disbursedOnDate", "");
|
actualChanges.put("disbursedOnDate", "");
|
||||||
|
|
||||||
existingTransactionIds.addAll(findExistingTransactionIds());
|
existingTransactionIds.addAll(findExistingTransactionIds());
|
||||||
|
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
||||||
|
|
||||||
contraExistingTransactions();
|
reverseExistingTransactions();
|
||||||
|
|
||||||
updateLoanToPreDisbursalState();
|
updateLoanToPreDisbursalState();
|
||||||
}
|
}
|
||||||
@@ -1300,18 +1282,11 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
return actualChanges;
|
return actualChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final void contraExistingTransactions() {
|
private final void reverseExistingTransactions() {
|
||||||
|
|
||||||
// final List<LoanTransaction> contras = new
|
|
||||||
// ArrayList<LoanTransaction>();
|
|
||||||
for (LoanTransaction transaction : this.loanTransactions) {
|
for (LoanTransaction transaction : this.loanTransactions) {
|
||||||
if (transaction.isNotContra()) {
|
transaction.reverse();
|
||||||
LoanTransaction contra = transaction.contra();
|
|
||||||
// contras.add(contra);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// this.loanTransactions.addAll(contras);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateLoanToPreDisbursalState() {
|
private void updateLoanToPreDisbursalState() {
|
||||||
@@ -1415,7 +1390,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
private List<LoanTransaction> retreiveListOfTransactionsPostDisbursement() {
|
private List<LoanTransaction> retreiveListOfTransactionsPostDisbursement() {
|
||||||
List<LoanTransaction> repaymentsOrWaivers = new ArrayList<LoanTransaction>();
|
List<LoanTransaction> repaymentsOrWaivers = new ArrayList<LoanTransaction>();
|
||||||
for (LoanTransaction transaction : this.loanTransactions) {
|
for (LoanTransaction transaction : this.loanTransactions) {
|
||||||
if (!transaction.isDisbursement() && transaction.isNotContra()) {
|
if (!transaction.isDisbursement() && transaction.isNotReversed()) {
|
||||||
repaymentsOrWaivers.add(transaction);
|
repaymentsOrWaivers.add(transaction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1462,7 +1437,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
|
|
||||||
LocalDate currentTransactionDate = loanTransaction.getTransactionDate();
|
LocalDate currentTransactionDate = loanTransaction.getTransactionDate();
|
||||||
for (LoanTransaction previousTransaction : loanTransactions) {
|
for (LoanTransaction previousTransaction : loanTransactions) {
|
||||||
if (!previousTransaction.isDisbursement() && previousTransaction.isNotContra()) {
|
if (!previousTransaction.isDisbursement() && previousTransaction.isNotReversed()) {
|
||||||
if (currentTransactionDate.isBefore(previousTransaction.getTransactionDate())
|
if (currentTransactionDate.isBefore(previousTransaction.getTransactionDate())
|
||||||
|| currentTransactionDate.isEqual(previousTransaction.getTransactionDate())) {
|
|| currentTransactionDate.isEqual(previousTransaction.getTransactionDate())) {
|
||||||
isChronologicallyLatestRepaymentOrWaiver = false;
|
isChronologicallyLatestRepaymentOrWaiver = false;
|
||||||
@@ -1480,7 +1455,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
|
|
||||||
LocalDate currentTransactionDate = loanTransaction.getTransactionDate();
|
LocalDate currentTransactionDate = loanTransaction.getTransactionDate();
|
||||||
for (LoanTransaction previousTransaction : loanTransactions) {
|
for (LoanTransaction previousTransaction : loanTransactions) {
|
||||||
if (previousTransaction.isNotContra()) {
|
if (previousTransaction.isNotReversed()) {
|
||||||
if (currentTransactionDate.isBefore(previousTransaction.getTransactionDate())
|
if (currentTransactionDate.isBefore(previousTransaction.getTransactionDate())
|
||||||
|| currentTransactionDate.isEqual(previousTransaction.getTransactionDate())) {
|
|| currentTransactionDate.isEqual(previousTransaction.getTransactionDate())) {
|
||||||
isChronologicallyLatestRepaymentOrWaiver = false;
|
isChronologicallyLatestRepaymentOrWaiver = false;
|
||||||
@@ -1574,7 +1549,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
throw new InvalidLoanTransactionTypeException("transaction", "adjustment.is.not.allowed.on.closed.loan", errorMessage);
|
throw new InvalidLoanTransactionTypeException("transaction", "adjustment.is.not.allowed.on.closed.loan", errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
transactionForAdjustment.contra();
|
transactionForAdjustment.reverse();
|
||||||
if (newTransactionDetail.isRepayment() || newTransactionDetail.isInterestWaiver()) {
|
if (newTransactionDetail.isRepayment() || newTransactionDetail.isInterestWaiver()) {
|
||||||
handleRepaymentOrWaiverTransaction(newTransactionDetail, loanLifecycleStateMachine, transactionForAdjustment);
|
handleRepaymentOrWaiverTransaction(newTransactionDetail, loanLifecycleStateMachine, transactionForAdjustment);
|
||||||
}
|
}
|
||||||
@@ -2137,7 +2112,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
return getCurrencyCode().equalsIgnoreCase(matchingCurrencyCode);
|
return getCurrencyCode().equalsIgnoreCase(matchingCurrencyCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getCurrencyCode() {
|
public String getCurrencyCode() {
|
||||||
return this.loanRepaymentScheduleDetail.getPrincipal().getCurrencyCode();
|
return this.loanRepaymentScheduleDetail.getPrincipal().getCurrencyCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2256,7 +2231,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
return this.loanOfficer;
|
return this.loanOfficer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Object> deriveAccountingBridgeData(final CurrencyData currencyData, final List<Long> existingTransactionIds) {
|
public Map<String, Object> deriveAccountingBridgeData(final CurrencyData currencyData, final List<Long> existingTransactionIds,
|
||||||
|
final List<Long> existingReversedTransactionIds) {
|
||||||
|
|
||||||
final Map<String, Object> accountingBridgeData = new LinkedHashMap<String, Object>();
|
final Map<String, Object> accountingBridgeData = new LinkedHashMap<String, Object>();
|
||||||
accountingBridgeData.put("loanId", this.getId());
|
accountingBridgeData.put("loanId", this.getId());
|
||||||
@@ -2267,7 +2243,9 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
|
|
||||||
final List<Map<String, Object>> newLoanTransactions = new ArrayList<Map<String, Object>>();
|
final List<Map<String, Object>> newLoanTransactions = new ArrayList<Map<String, Object>>();
|
||||||
for (LoanTransaction transaction : this.loanTransactions) {
|
for (LoanTransaction transaction : this.loanTransactions) {
|
||||||
if (!existingTransactionIds.contains(transaction.getId())) {
|
if (transaction.isReversed() && !existingReversedTransactionIds.contains(transaction.getId())) {
|
||||||
|
newLoanTransactions.add(transaction.toMapData(currencyData));
|
||||||
|
} else if (!existingTransactionIds.contains(transaction.getId())) {
|
||||||
newLoanTransactions.add(transaction.toMapData(currencyData));
|
newLoanTransactions.add(transaction.toMapData(currencyData));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+374
-381
@@ -28,82 +28,76 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
|
|||||||
|
|
||||||
@ManyToOne(optional = false)
|
@ManyToOne(optional = false)
|
||||||
@JoinColumn(name = "loan_id")
|
@JoinColumn(name = "loan_id")
|
||||||
private Loan loan;
|
private Loan loan;
|
||||||
|
|
||||||
@Column(name = "installment", nullable=false)
|
@Column(name = "installment", nullable = false)
|
||||||
private final Integer installmentNumber;
|
private final Integer installmentNumber;
|
||||||
|
|
||||||
@Temporal(TemporalType.DATE)
|
@Temporal(TemporalType.DATE)
|
||||||
@Column(name = "fromdate", nullable=true)
|
@Column(name = "fromdate", nullable = true)
|
||||||
private final Date fromDate;
|
private final Date fromDate;
|
||||||
|
|
||||||
@Temporal(TemporalType.DATE)
|
@Temporal(TemporalType.DATE)
|
||||||
@Column(name = "duedate", nullable=false)
|
@Column(name = "duedate", nullable = false)
|
||||||
private final Date dueDate;
|
private final Date dueDate;
|
||||||
|
|
||||||
@Column(name = "principal_amount", scale=6, precision=19, nullable=true)
|
@Column(name = "principal_amount", scale = 6, precision = 19, nullable = true)
|
||||||
private BigDecimal principal;
|
private BigDecimal principal;
|
||||||
|
|
||||||
@Column(name = "principal_completed_derived", scale=6, precision=19, nullable=true)
|
@Column(name = "principal_completed_derived", scale = 6, precision = 19, nullable = true)
|
||||||
private BigDecimal principalCompleted;
|
private BigDecimal principalCompleted;
|
||||||
|
|
||||||
@Column(name = "principal_writtenoff_derived", scale=6, precision=19, nullable=true)
|
@Column(name = "principal_writtenoff_derived", scale = 6, precision = 19, nullable = true)
|
||||||
private BigDecimal principalWrittenOff;
|
private BigDecimal principalWrittenOff;
|
||||||
|
|
||||||
@Column(name = "interest_amount", scale=6, precision=19, nullable=true)
|
@Column(name = "interest_amount", scale = 6, precision = 19, nullable = true)
|
||||||
private BigDecimal interest;
|
private BigDecimal interest;
|
||||||
|
|
||||||
@Column(name = "interest_completed_derived", scale = 6, precision = 19, nullable=true)
|
@Column(name = "interest_completed_derived", scale = 6, precision = 19, nullable = true)
|
||||||
private BigDecimal interestCompleted;
|
private BigDecimal interestCompleted;
|
||||||
|
|
||||||
@Column(name = "interest_waived_derived", scale = 6, precision = 19, nullable=true)
|
@Column(name = "interest_waived_derived", scale = 6, precision = 19, nullable = true)
|
||||||
private BigDecimal interestWaived;
|
private BigDecimal interestWaived;
|
||||||
|
|
||||||
@Column(name = "interest_writtenoff_derived", scale=6, precision=19, nullable=true)
|
@Column(name = "interest_writtenoff_derived", scale = 6, precision = 19, nullable = true)
|
||||||
private BigDecimal interestWrittenOff;
|
private BigDecimal interestWrittenOff;
|
||||||
|
|
||||||
@Column(name = "fee_charges_amount", scale=6, precision=19, nullable=true)
|
@Column(name = "fee_charges_amount", scale = 6, precision = 19, nullable = true)
|
||||||
private BigDecimal feeCharges;
|
private BigDecimal feeCharges;
|
||||||
|
|
||||||
@Column(name = "fee_charges_completed_derived", scale=6, precision=19, nullable=true)
|
@Column(name = "fee_charges_completed_derived", scale = 6, precision = 19, nullable = true)
|
||||||
private BigDecimal feeChargesCompleted;
|
private BigDecimal feeChargesCompleted;
|
||||||
|
|
||||||
@Column(name = "fee_charges_writtenoff_derived", scale=6, precision=19, nullable=true)
|
@Column(name = "fee_charges_writtenoff_derived", scale = 6, precision = 19, nullable = true)
|
||||||
private BigDecimal feeChargesWrittenOff;
|
private BigDecimal feeChargesWrittenOff;
|
||||||
|
|
||||||
@Column(name = "fee_charges_waived_derived", scale=6, precision=19, nullable=true)
|
@Column(name = "fee_charges_waived_derived", scale = 6, precision = 19, nullable = true)
|
||||||
private BigDecimal feeChargesWaived;
|
private BigDecimal feeChargesWaived;
|
||||||
|
|
||||||
@Column(name = "penalty_charges_amount", scale=6, precision=19, nullable=true)
|
@Column(name = "penalty_charges_amount", scale = 6, precision = 19, nullable = true)
|
||||||
private BigDecimal penaltyCharges;
|
private BigDecimal penaltyCharges;
|
||||||
|
|
||||||
@Column(name = "penalty_charges_completed_derived", scale=6, precision=19, nullable=true)
|
@Column(name = "penalty_charges_completed_derived", scale = 6, precision = 19, nullable = true)
|
||||||
private BigDecimal penaltyChargesCompleted;
|
private BigDecimal penaltyChargesCompleted;
|
||||||
|
|
||||||
@Column(name = "penalty_charges_writtenoff_derived", scale=6, precision=19, nullable=true)
|
@Column(name = "penalty_charges_writtenoff_derived", scale = 6, precision = 19, nullable = true)
|
||||||
private BigDecimal penaltyChargesWrittenOff;
|
private BigDecimal penaltyChargesWrittenOff;
|
||||||
|
|
||||||
@Column(name = "penalty_charges_waived_derived", scale=6, precision=19, nullable=true)
|
@Column(name = "penalty_charges_waived_derived", scale = 6, precision = 19, nullable = true)
|
||||||
private BigDecimal penaltyChargesWaived;
|
private BigDecimal penaltyChargesWaived;
|
||||||
|
|
||||||
@Column(name="completed_derived", nullable=false)
|
@Column(name = "completed_derived", nullable = false)
|
||||||
private boolean completed;
|
private boolean completed;
|
||||||
|
|
||||||
protected LoanRepaymentScheduleInstallment() {
|
protected LoanRepaymentScheduleInstallment() {
|
||||||
this.installmentNumber = null;
|
this.installmentNumber = null;
|
||||||
this.fromDate = null;
|
this.fromDate = null;
|
||||||
this.dueDate = null;
|
this.dueDate = null;
|
||||||
this.completed = false;
|
this.completed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LoanRepaymentScheduleInstallment(
|
public LoanRepaymentScheduleInstallment(final Loan loan, final Integer installmentNumber, final LocalDate fromDate,
|
||||||
final Loan loan,
|
final LocalDate dueDate, final BigDecimal principal, final BigDecimal interest, final BigDecimal feeCharges,
|
||||||
final Integer installmentNumber,
|
|
||||||
final LocalDate fromDate,
|
|
||||||
final LocalDate dueDate,
|
|
||||||
final BigDecimal principal,
|
|
||||||
final BigDecimal interest,
|
|
||||||
final BigDecimal feeCharges,
|
|
||||||
final BigDecimal penaltyCharges) {
|
final BigDecimal penaltyCharges) {
|
||||||
this.loan = loan;
|
this.loan = loan;
|
||||||
this.installmentNumber = installmentNumber;
|
this.installmentNumber = installmentNumber;
|
||||||
@@ -116,15 +110,15 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
|
|||||||
this.completed = false;
|
this.completed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private BigDecimal defaultToNullIfZero(final BigDecimal value) {
|
private BigDecimal defaultToNullIfZero(final BigDecimal value) {
|
||||||
BigDecimal result = value;
|
BigDecimal result = value;
|
||||||
if (BigDecimal.ZERO.compareTo(value) == 0) {
|
if (BigDecimal.ZERO.compareTo(value) == 0) {
|
||||||
result = null;
|
result = null;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Loan getLoan() {
|
public Loan getLoan() {
|
||||||
return this.loan;
|
return this.loan;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,324 +127,323 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
|
|||||||
}
|
}
|
||||||
|
|
||||||
public LocalDate getFromDate() {
|
public LocalDate getFromDate() {
|
||||||
LocalDate fromLocalDate = null;
|
LocalDate fromLocalDate = null;
|
||||||
if (this.fromDate != null) {
|
if (this.fromDate != null) {
|
||||||
fromLocalDate = new LocalDate(this.fromDate);
|
fromLocalDate = new LocalDate(this.fromDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fromLocalDate;
|
return fromLocalDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LocalDate getDueDate() {
|
public LocalDate getDueDate() {
|
||||||
return new LocalDate(this.dueDate);
|
return new LocalDate(this.dueDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money getPrincipal(final MonetaryCurrency currency) {
|
public Money getPrincipal(final MonetaryCurrency currency) {
|
||||||
return Money.of(currency, this.principal);
|
return Money.of(currency, this.principal);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money getPrincipalCompleted(final MonetaryCurrency currency) {
|
|
||||||
return Money.of(currency, this.principalCompleted);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money getPrincipalWrittenOff(final MonetaryCurrency currency) {
|
|
||||||
return Money.of(currency, this.principalWrittenOff);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money getPrincipalOutstanding(final MonetaryCurrency currency) {
|
|
||||||
final Money principalAccountedFor = getPrincipalCompleted(currency).plus(getPrincipalWrittenOff(currency));
|
|
||||||
return getPrincipal(currency).minus(principalAccountedFor);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money getInterest(final MonetaryCurrency currency) {
|
|
||||||
return Money.of(currency, this.interest);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money getInterestCompleted(final MonetaryCurrency currency) {
|
|
||||||
return Money.of(currency, this.interestCompleted);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money getInterestWaived(final MonetaryCurrency currency) {
|
|
||||||
return Money.of(currency, this.interestWaived);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money getInterestWrittenOff(final MonetaryCurrency currency) {
|
|
||||||
return Money.of(currency, this.interestWrittenOff);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money getInterestOutstanding(final MonetaryCurrency currency) {
|
|
||||||
final Money interestAccountedFor = getInterestCompleted(currency).plus(getInterestWaived(currency)).plus(getInterestWrittenOff(currency));
|
|
||||||
return getInterest(currency).minus(interestAccountedFor);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money getFeeCharges(final MonetaryCurrency currency) {
|
|
||||||
return Money.of(currency, this.feeCharges);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money getFeeChargesCompleted(final MonetaryCurrency currency) {
|
|
||||||
return Money.of(currency, this.feeChargesCompleted);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money getFeeChargesWaived(final MonetaryCurrency currency) {
|
|
||||||
return Money.of(currency, this.feeChargesWaived);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money getFeeChargesWrittenOff(final MonetaryCurrency currency) {
|
|
||||||
return Money.of(currency, this.feeChargesWrittenOff);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money getFeeChargesOutstanding(final MonetaryCurrency currency) {
|
|
||||||
final Money feeChargesAccountedFor = getFeeChargesCompleted(currency).plus(getFeeChargesWaived(currency)).plus(getFeeChargesWrittenOff(currency));
|
|
||||||
return getFeeCharges(currency).minus(feeChargesAccountedFor);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money getPenaltyCharges(final MonetaryCurrency currency) {
|
|
||||||
return Money.of(currency, this.penaltyCharges);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money getPenaltyChargesCompleted(final MonetaryCurrency currency) {
|
|
||||||
return Money.of(currency, this.penaltyChargesCompleted);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money getPenaltyChargesWaived(final MonetaryCurrency currency) {
|
|
||||||
return Money.of(currency, this.penaltyChargesWaived);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money getPenaltyChargesWrittenOff(final MonetaryCurrency currency) {
|
|
||||||
return Money.of(currency, this.penaltyChargesWrittenOff);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money getPenaltyChargesOutstanding(final MonetaryCurrency currency) {
|
|
||||||
final Money feeChargesAccountedFor = getPenaltyChargesCompleted(currency).plus(getPenaltyChargesWaived(currency)).plus(getPenaltyChargesWrittenOff(currency));
|
|
||||||
return getPenaltyCharges(currency).minus(feeChargesAccountedFor);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isInterestDue(final MonetaryCurrency currency) {
|
public Money getPrincipalCompleted(final MonetaryCurrency currency) {
|
||||||
return getInterestOutstanding(currency).isGreaterThanZero();
|
return Money.of(currency, this.principalCompleted);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money getTotalPrincipalAndInterest(final MonetaryCurrency currency) {
|
|
||||||
return getPrincipal(currency).plus(getInterest(currency));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money getTotalOutstanding(final MonetaryCurrency currency) {
|
|
||||||
return getPrincipalOutstanding(currency).plus(getInterestOutstanding(currency)).plus(getFeeChargesOutstanding(currency)).plus(getPenaltyChargesOutstanding(currency));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateLoan(final Loan loan) {
|
|
||||||
this.loan = loan;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isFullyCompleted() {
|
|
||||||
return this.completed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isNotFullyCompleted() {
|
public Money getPrincipalWrittenOff(final MonetaryCurrency currency) {
|
||||||
return !this.completed;
|
return Money.of(currency, this.principalWrittenOff);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPrincipalNotCompleted(final MonetaryCurrency currency) {
|
|
||||||
return !isPrincipalCompleted(currency);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isPrincipalCompleted(final MonetaryCurrency currency) {
|
|
||||||
return getPrincipalOutstanding(currency).isZero();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void resetDerivedComponents() {
|
public Money getPrincipalOutstanding(final MonetaryCurrency currency) {
|
||||||
this.principalCompleted = null;
|
final Money principalAccountedFor = getPrincipalCompleted(currency).plus(getPrincipalWrittenOff(currency));
|
||||||
this.principalWrittenOff = null;
|
return getPrincipal(currency).minus(principalAccountedFor);
|
||||||
this.interestCompleted = null;
|
}
|
||||||
this.interestWaived = null;
|
|
||||||
this.interestWrittenOff = null;
|
|
||||||
this.feeChargesCompleted = null;
|
|
||||||
this.feeChargesWaived = null;
|
|
||||||
this.feeChargesWrittenOff = null;
|
|
||||||
this.penaltyChargesCompleted = null;
|
|
||||||
this.penaltyChargesWaived = null;
|
|
||||||
this.penaltyChargesWrittenOff = null;
|
|
||||||
|
|
||||||
this.completed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money payPenaltyChargesComponent(final Money transactionAmountRemaining) {
|
public Money getInterest(final MonetaryCurrency currency) {
|
||||||
|
return Money.of(currency, this.interest);
|
||||||
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
}
|
||||||
Money penaltyPortionOfTransaction = Money.zero(currency);
|
|
||||||
|
|
||||||
final Money penaltyChargesDue = getPenaltyChargesOutstanding(currency);
|
|
||||||
if (transactionAmountRemaining.isGreaterThanOrEqualTo(penaltyChargesDue)) {
|
|
||||||
this.penaltyChargesCompleted = getPenaltyChargesCompleted(currency).plus(penaltyChargesDue).getAmount();
|
|
||||||
penaltyPortionOfTransaction = penaltyPortionOfTransaction.plus(penaltyChargesDue);
|
|
||||||
} else {
|
|
||||||
this.penaltyChargesCompleted = getPenaltyChargesCompleted(currency).plus(transactionAmountRemaining).getAmount();
|
|
||||||
penaltyPortionOfTransaction = penaltyPortionOfTransaction.plus(transactionAmountRemaining);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.penaltyChargesCompleted = defaultToNullIfZero(this.penaltyChargesCompleted);
|
|
||||||
|
|
||||||
this.completed = getTotalOutstanding(currency).isZero();
|
|
||||||
|
|
||||||
return penaltyPortionOfTransaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money payFeeChargesComponent(final Money transactionAmountRemaining) {
|
|
||||||
|
|
||||||
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
|
||||||
Money feePortionOfTransaction = Money.zero(currency);
|
|
||||||
|
|
||||||
final Money feeChargesDue = getFeeChargesOutstanding(currency);
|
|
||||||
if (transactionAmountRemaining.isGreaterThanOrEqualTo(feeChargesDue)) {
|
|
||||||
this.feeChargesCompleted = getFeeChargesCompleted(currency).plus(feeChargesDue).getAmount();
|
|
||||||
feePortionOfTransaction = feePortionOfTransaction.plus(feeChargesDue);
|
|
||||||
} else {
|
|
||||||
this.feeChargesCompleted = getFeeChargesCompleted(currency).plus(transactionAmountRemaining).getAmount();
|
|
||||||
feePortionOfTransaction = feePortionOfTransaction.plus(transactionAmountRemaining);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.feeChargesCompleted = defaultToNullIfZero(this.feeChargesCompleted);
|
|
||||||
|
|
||||||
this.completed = getTotalOutstanding(currency).isZero();
|
|
||||||
|
|
||||||
return feePortionOfTransaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money payInterestComponent(final Money transactionAmountRemaining) {
|
|
||||||
|
|
||||||
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
|
||||||
Money interestPortionOfTransaction = Money.zero(currency);
|
|
||||||
|
|
||||||
final Money interestDue = getInterestOutstanding(currency);
|
|
||||||
if (transactionAmountRemaining.isGreaterThanOrEqualTo(interestDue)) {
|
|
||||||
this.interestCompleted = getInterestCompleted(currency).plus(interestDue).getAmount();
|
|
||||||
interestPortionOfTransaction = interestPortionOfTransaction.plus(interestDue);
|
|
||||||
} else {
|
|
||||||
this.interestCompleted = getInterestCompleted(currency).plus(transactionAmountRemaining).getAmount();
|
|
||||||
interestPortionOfTransaction = interestPortionOfTransaction.plus(transactionAmountRemaining);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.interestCompleted = defaultToNullIfZero(this.interestCompleted);
|
|
||||||
|
|
||||||
this.completed = getTotalOutstanding(currency).isZero();
|
|
||||||
|
|
||||||
return interestPortionOfTransaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money payPrincipalComponent(final Money transactionAmountRemaining) {
|
public Money getInterestCompleted(final MonetaryCurrency currency) {
|
||||||
|
return Money.of(currency, this.interestCompleted);
|
||||||
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
}
|
||||||
Money principalPortionOfTransaction = Money.zero(currency);
|
|
||||||
|
|
||||||
final Money principalDue = getPrincipalOutstanding(currency);
|
|
||||||
if (transactionAmountRemaining.isGreaterThanOrEqualTo(principalDue)) {
|
|
||||||
this.principalCompleted = getPrincipalCompleted(currency).plus(principalDue).getAmount();
|
|
||||||
principalPortionOfTransaction = principalPortionOfTransaction.plus(principalDue);
|
|
||||||
} else {
|
|
||||||
this.principalCompleted = getPrincipalCompleted(currency).plus(transactionAmountRemaining).getAmount();
|
|
||||||
principalPortionOfTransaction = principalPortionOfTransaction.plus(transactionAmountRemaining);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.principalCompleted = defaultToNullIfZero(this.principalCompleted);
|
|
||||||
|
|
||||||
this.completed = getTotalOutstanding(currency).isZero();
|
|
||||||
|
|
||||||
return principalPortionOfTransaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money waiveInterestComponent(final Money transactionAmountRemaining) {
|
public Money getInterestWaived(final MonetaryCurrency currency) {
|
||||||
MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
return Money.of(currency, this.interestWaived);
|
||||||
Money waivedInterestPortionOfTransaction = Money.zero(currency);
|
}
|
||||||
|
|
||||||
Money interestDue = getInterestOutstanding(currency);
|
|
||||||
if (transactionAmountRemaining.isGreaterThanOrEqualTo(interestDue)) {
|
|
||||||
this.interestWaived = getInterestWaived(currency).plus(interestDue).getAmount();
|
|
||||||
waivedInterestPortionOfTransaction = waivedInterestPortionOfTransaction.plus(interestDue);
|
|
||||||
} else {
|
|
||||||
this.interestWaived = getInterestWaived(currency).plus(transactionAmountRemaining).getAmount();
|
|
||||||
waivedInterestPortionOfTransaction = waivedInterestPortionOfTransaction.plus(transactionAmountRemaining);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.interestWaived = defaultToNullIfZero(this.interestWaived);
|
|
||||||
|
|
||||||
this.completed = getTotalOutstanding(currency).isZero();
|
|
||||||
|
|
||||||
return waivedInterestPortionOfTransaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money waivePenaltyChargesComponent(final Money transactionAmountRemaining) {
|
|
||||||
MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
|
||||||
Money waivedPenaltyChargesPortionOfTransaction = Money.zero(currency);
|
|
||||||
|
|
||||||
Money penanltiesDue = getPenaltyChargesOutstanding(currency);
|
|
||||||
if (transactionAmountRemaining.isGreaterThanOrEqualTo(penanltiesDue)) {
|
|
||||||
this.penaltyChargesWaived = getPenaltyChargesWaived(currency).plus(penanltiesDue).getAmount();
|
|
||||||
waivedPenaltyChargesPortionOfTransaction = waivedPenaltyChargesPortionOfTransaction.plus(penanltiesDue);
|
|
||||||
} else {
|
|
||||||
this.penaltyChargesWaived = getPenaltyChargesWaived(currency).plus(transactionAmountRemaining).getAmount();
|
|
||||||
waivedPenaltyChargesPortionOfTransaction = waivedPenaltyChargesPortionOfTransaction.plus(transactionAmountRemaining);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.penaltyChargesWaived = defaultToNullIfZero(this.penaltyChargesWaived);
|
|
||||||
|
|
||||||
this.completed = getTotalOutstanding(currency).isZero();
|
|
||||||
|
|
||||||
return waivedPenaltyChargesPortionOfTransaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money waiveFeeChargesComponent(final Money transactionAmountRemaining) {
|
|
||||||
MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
|
||||||
Money waivedFeeChargesPortionOfTransaction = Money.zero(currency);
|
|
||||||
|
|
||||||
Money feesDue = getPenaltyChargesOutstanding(currency);
|
|
||||||
if (transactionAmountRemaining.isGreaterThanOrEqualTo(feesDue)) {
|
|
||||||
this.feeChargesWaived = getFeeChargesWaived(currency).plus(feesDue).getAmount();
|
|
||||||
waivedFeeChargesPortionOfTransaction = waivedFeeChargesPortionOfTransaction.plus(feesDue);
|
|
||||||
} else {
|
|
||||||
this.feeChargesWaived = getFeeChargesWaived(currency).plus(transactionAmountRemaining).getAmount();
|
|
||||||
waivedFeeChargesPortionOfTransaction = waivedFeeChargesPortionOfTransaction.plus(transactionAmountRemaining);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.feeChargesWaived = defaultToNullIfZero(this.feeChargesWaived);
|
|
||||||
|
|
||||||
this.completed = getTotalOutstanding(currency).isZero();
|
|
||||||
|
|
||||||
return waivedFeeChargesPortionOfTransaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money writeOffOutstandingPrincipal(final MonetaryCurrency currency) {
|
|
||||||
|
|
||||||
final Money principalDue = getPrincipalOutstanding(currency);
|
|
||||||
this.principalWrittenOff = defaultToNullIfZero(principalDue.getAmount());
|
|
||||||
this.completed = getTotalOutstanding(currency).isZero();
|
|
||||||
|
|
||||||
return principalDue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Money writeOffOutstandingInterest(final MonetaryCurrency currency) {
|
|
||||||
|
|
||||||
final Money interestDue = getInterestOutstanding(currency);
|
|
||||||
this.interestWrittenOff = defaultToNullIfZero(interestDue.getAmount());
|
|
||||||
this.completed = getTotalOutstanding(currency).isZero();
|
|
||||||
|
|
||||||
return interestDue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isOverdueOn(final LocalDate transactionDate) {
|
public Money getInterestWrittenOff(final MonetaryCurrency currency) {
|
||||||
return this.getDueDate().isBefore(transactionDate);
|
return Money.of(currency, this.interestWrittenOff);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateChargePortion(
|
public Money getInterestOutstanding(final MonetaryCurrency currency) {
|
||||||
final Money feeChargesDue,
|
final Money interestAccountedFor = getInterestCompleted(currency).plus(getInterestWaived(currency)).plus(
|
||||||
final Money feeChargesWaived,
|
getInterestWrittenOff(currency));
|
||||||
final Money feeChargesWrittenOff,
|
return getInterest(currency).minus(interestAccountedFor);
|
||||||
final Money penaltyChargesDue,
|
}
|
||||||
final Money penaltyChargesWaived,
|
|
||||||
final Money penaltyChargesWrittenOff) {
|
public Money getFeeCharges(final MonetaryCurrency currency) {
|
||||||
this.feeCharges = defaultToNullIfZero(feeChargesDue.getAmount());
|
return Money.of(currency, this.feeCharges);
|
||||||
this.feeChargesWaived = defaultToNullIfZero(feeChargesWaived.getAmount());
|
}
|
||||||
this.feeChargesWrittenOff = defaultToNullIfZero(feeChargesWrittenOff.getAmount());
|
|
||||||
this.penaltyCharges = defaultToNullIfZero(penaltyChargesDue.getAmount());
|
public Money getFeeChargesCompleted(final MonetaryCurrency currency) {
|
||||||
this.penaltyChargesWaived = defaultToNullIfZero(penaltyChargesWaived.getAmount());
|
return Money.of(currency, this.feeChargesCompleted);
|
||||||
this.penaltyChargesWrittenOff = defaultToNullIfZero(penaltyChargesWrittenOff.getAmount());
|
}
|
||||||
}
|
|
||||||
|
public Money getFeeChargesWaived(final MonetaryCurrency currency) {
|
||||||
|
return Money.of(currency, this.feeChargesWaived);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Money getFeeChargesWrittenOff(final MonetaryCurrency currency) {
|
||||||
|
return Money.of(currency, this.feeChargesWrittenOff);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Money getFeeChargesOutstanding(final MonetaryCurrency currency) {
|
||||||
|
final Money feeChargesAccountedFor = getFeeChargesCompleted(currency).plus(getFeeChargesWaived(currency)).plus(
|
||||||
|
getFeeChargesWrittenOff(currency));
|
||||||
|
return getFeeCharges(currency).minus(feeChargesAccountedFor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Money getPenaltyCharges(final MonetaryCurrency currency) {
|
||||||
|
return Money.of(currency, this.penaltyCharges);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Money getPenaltyChargesCompleted(final MonetaryCurrency currency) {
|
||||||
|
return Money.of(currency, this.penaltyChargesCompleted);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Money getPenaltyChargesWaived(final MonetaryCurrency currency) {
|
||||||
|
return Money.of(currency, this.penaltyChargesWaived);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Money getPenaltyChargesWrittenOff(final MonetaryCurrency currency) {
|
||||||
|
return Money.of(currency, this.penaltyChargesWrittenOff);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Money getPenaltyChargesOutstanding(final MonetaryCurrency currency) {
|
||||||
|
final Money feeChargesAccountedFor = getPenaltyChargesCompleted(currency).plus(getPenaltyChargesWaived(currency)).plus(
|
||||||
|
getPenaltyChargesWrittenOff(currency));
|
||||||
|
return getPenaltyCharges(currency).minus(feeChargesAccountedFor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInterestDue(final MonetaryCurrency currency) {
|
||||||
|
return getInterestOutstanding(currency).isGreaterThanZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Money getTotalPrincipalAndInterest(final MonetaryCurrency currency) {
|
||||||
|
return getPrincipal(currency).plus(getInterest(currency));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Money getTotalOutstanding(final MonetaryCurrency currency) {
|
||||||
|
return getPrincipalOutstanding(currency).plus(getInterestOutstanding(currency)).plus(getFeeChargesOutstanding(currency))
|
||||||
|
.plus(getPenaltyChargesOutstanding(currency));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateLoan(final Loan loan) {
|
||||||
|
this.loan = loan;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFullyCompleted() {
|
||||||
|
return this.completed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNotFullyCompleted() {
|
||||||
|
return !this.completed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPrincipalNotCompleted(final MonetaryCurrency currency) {
|
||||||
|
return !isPrincipalCompleted(currency);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPrincipalCompleted(final MonetaryCurrency currency) {
|
||||||
|
return getPrincipalOutstanding(currency).isZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetDerivedComponents() {
|
||||||
|
this.principalCompleted = null;
|
||||||
|
this.principalWrittenOff = null;
|
||||||
|
this.interestCompleted = null;
|
||||||
|
this.interestWaived = null;
|
||||||
|
this.interestWrittenOff = null;
|
||||||
|
this.feeChargesCompleted = null;
|
||||||
|
this.feeChargesWaived = null;
|
||||||
|
this.feeChargesWrittenOff = null;
|
||||||
|
this.penaltyChargesCompleted = null;
|
||||||
|
this.penaltyChargesWaived = null;
|
||||||
|
this.penaltyChargesWrittenOff = null;
|
||||||
|
|
||||||
|
this.completed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Money payPenaltyChargesComponent(final Money transactionAmountRemaining) {
|
||||||
|
|
||||||
|
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
||||||
|
Money penaltyPortionOfTransaction = Money.zero(currency);
|
||||||
|
|
||||||
|
final Money penaltyChargesDue = getPenaltyChargesOutstanding(currency);
|
||||||
|
if (transactionAmountRemaining.isGreaterThanOrEqualTo(penaltyChargesDue)) {
|
||||||
|
this.penaltyChargesCompleted = getPenaltyChargesCompleted(currency).plus(penaltyChargesDue).getAmount();
|
||||||
|
penaltyPortionOfTransaction = penaltyPortionOfTransaction.plus(penaltyChargesDue);
|
||||||
|
} else {
|
||||||
|
this.penaltyChargesCompleted = getPenaltyChargesCompleted(currency).plus(transactionAmountRemaining).getAmount();
|
||||||
|
penaltyPortionOfTransaction = penaltyPortionOfTransaction.plus(transactionAmountRemaining);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.penaltyChargesCompleted = defaultToNullIfZero(this.penaltyChargesCompleted);
|
||||||
|
|
||||||
|
this.completed = getTotalOutstanding(currency).isZero();
|
||||||
|
|
||||||
|
return penaltyPortionOfTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Money payFeeChargesComponent(final Money transactionAmountRemaining) {
|
||||||
|
|
||||||
|
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
||||||
|
Money feePortionOfTransaction = Money.zero(currency);
|
||||||
|
|
||||||
|
final Money feeChargesDue = getFeeChargesOutstanding(currency);
|
||||||
|
if (transactionAmountRemaining.isGreaterThanOrEqualTo(feeChargesDue)) {
|
||||||
|
this.feeChargesCompleted = getFeeChargesCompleted(currency).plus(feeChargesDue).getAmount();
|
||||||
|
feePortionOfTransaction = feePortionOfTransaction.plus(feeChargesDue);
|
||||||
|
} else {
|
||||||
|
this.feeChargesCompleted = getFeeChargesCompleted(currency).plus(transactionAmountRemaining).getAmount();
|
||||||
|
feePortionOfTransaction = feePortionOfTransaction.plus(transactionAmountRemaining);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.feeChargesCompleted = defaultToNullIfZero(this.feeChargesCompleted);
|
||||||
|
|
||||||
|
this.completed = getTotalOutstanding(currency).isZero();
|
||||||
|
|
||||||
|
return feePortionOfTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Money payInterestComponent(final Money transactionAmountRemaining) {
|
||||||
|
|
||||||
|
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
||||||
|
Money interestPortionOfTransaction = Money.zero(currency);
|
||||||
|
|
||||||
|
final Money interestDue = getInterestOutstanding(currency);
|
||||||
|
if (transactionAmountRemaining.isGreaterThanOrEqualTo(interestDue)) {
|
||||||
|
this.interestCompleted = getInterestCompleted(currency).plus(interestDue).getAmount();
|
||||||
|
interestPortionOfTransaction = interestPortionOfTransaction.plus(interestDue);
|
||||||
|
} else {
|
||||||
|
this.interestCompleted = getInterestCompleted(currency).plus(transactionAmountRemaining).getAmount();
|
||||||
|
interestPortionOfTransaction = interestPortionOfTransaction.plus(transactionAmountRemaining);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.interestCompleted = defaultToNullIfZero(this.interestCompleted);
|
||||||
|
|
||||||
|
this.completed = getTotalOutstanding(currency).isZero();
|
||||||
|
|
||||||
|
return interestPortionOfTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Money payPrincipalComponent(final Money transactionAmountRemaining) {
|
||||||
|
|
||||||
|
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
||||||
|
Money principalPortionOfTransaction = Money.zero(currency);
|
||||||
|
|
||||||
|
final Money principalDue = getPrincipalOutstanding(currency);
|
||||||
|
if (transactionAmountRemaining.isGreaterThanOrEqualTo(principalDue)) {
|
||||||
|
this.principalCompleted = getPrincipalCompleted(currency).plus(principalDue).getAmount();
|
||||||
|
principalPortionOfTransaction = principalPortionOfTransaction.plus(principalDue);
|
||||||
|
} else {
|
||||||
|
this.principalCompleted = getPrincipalCompleted(currency).plus(transactionAmountRemaining).getAmount();
|
||||||
|
principalPortionOfTransaction = principalPortionOfTransaction.plus(transactionAmountRemaining);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.principalCompleted = defaultToNullIfZero(this.principalCompleted);
|
||||||
|
|
||||||
|
this.completed = getTotalOutstanding(currency).isZero();
|
||||||
|
|
||||||
|
return principalPortionOfTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Money waiveInterestComponent(final Money transactionAmountRemaining) {
|
||||||
|
MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
||||||
|
Money waivedInterestPortionOfTransaction = Money.zero(currency);
|
||||||
|
|
||||||
|
Money interestDue = getInterestOutstanding(currency);
|
||||||
|
if (transactionAmountRemaining.isGreaterThanOrEqualTo(interestDue)) {
|
||||||
|
this.interestWaived = getInterestWaived(currency).plus(interestDue).getAmount();
|
||||||
|
waivedInterestPortionOfTransaction = waivedInterestPortionOfTransaction.plus(interestDue);
|
||||||
|
} else {
|
||||||
|
this.interestWaived = getInterestWaived(currency).plus(transactionAmountRemaining).getAmount();
|
||||||
|
waivedInterestPortionOfTransaction = waivedInterestPortionOfTransaction.plus(transactionAmountRemaining);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.interestWaived = defaultToNullIfZero(this.interestWaived);
|
||||||
|
|
||||||
|
this.completed = getTotalOutstanding(currency).isZero();
|
||||||
|
|
||||||
|
return waivedInterestPortionOfTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Money waivePenaltyChargesComponent(final Money transactionAmountRemaining) {
|
||||||
|
MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
||||||
|
Money waivedPenaltyChargesPortionOfTransaction = Money.zero(currency);
|
||||||
|
|
||||||
|
Money penanltiesDue = getPenaltyChargesOutstanding(currency);
|
||||||
|
if (transactionAmountRemaining.isGreaterThanOrEqualTo(penanltiesDue)) {
|
||||||
|
this.penaltyChargesWaived = getPenaltyChargesWaived(currency).plus(penanltiesDue).getAmount();
|
||||||
|
waivedPenaltyChargesPortionOfTransaction = waivedPenaltyChargesPortionOfTransaction.plus(penanltiesDue);
|
||||||
|
} else {
|
||||||
|
this.penaltyChargesWaived = getPenaltyChargesWaived(currency).plus(transactionAmountRemaining).getAmount();
|
||||||
|
waivedPenaltyChargesPortionOfTransaction = waivedPenaltyChargesPortionOfTransaction.plus(transactionAmountRemaining);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.penaltyChargesWaived = defaultToNullIfZero(this.penaltyChargesWaived);
|
||||||
|
|
||||||
|
this.completed = getTotalOutstanding(currency).isZero();
|
||||||
|
|
||||||
|
return waivedPenaltyChargesPortionOfTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Money waiveFeeChargesComponent(final Money transactionAmountRemaining) {
|
||||||
|
MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
|
||||||
|
Money waivedFeeChargesPortionOfTransaction = Money.zero(currency);
|
||||||
|
|
||||||
|
Money feesDue = getPenaltyChargesOutstanding(currency);
|
||||||
|
if (transactionAmountRemaining.isGreaterThanOrEqualTo(feesDue)) {
|
||||||
|
this.feeChargesWaived = getFeeChargesWaived(currency).plus(feesDue).getAmount();
|
||||||
|
waivedFeeChargesPortionOfTransaction = waivedFeeChargesPortionOfTransaction.plus(feesDue);
|
||||||
|
} else {
|
||||||
|
this.feeChargesWaived = getFeeChargesWaived(currency).plus(transactionAmountRemaining).getAmount();
|
||||||
|
waivedFeeChargesPortionOfTransaction = waivedFeeChargesPortionOfTransaction.plus(transactionAmountRemaining);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.feeChargesWaived = defaultToNullIfZero(this.feeChargesWaived);
|
||||||
|
|
||||||
|
this.completed = getTotalOutstanding(currency).isZero();
|
||||||
|
|
||||||
|
return waivedFeeChargesPortionOfTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Money writeOffOutstandingPrincipal(final MonetaryCurrency currency) {
|
||||||
|
|
||||||
|
final Money principalDue = getPrincipalOutstanding(currency);
|
||||||
|
this.principalWrittenOff = defaultToNullIfZero(principalDue.getAmount());
|
||||||
|
this.completed = getTotalOutstanding(currency).isZero();
|
||||||
|
|
||||||
|
return principalDue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Money writeOffOutstandingInterest(final MonetaryCurrency currency) {
|
||||||
|
|
||||||
|
final Money interestDue = getInterestOutstanding(currency);
|
||||||
|
this.interestWrittenOff = defaultToNullIfZero(interestDue.getAmount());
|
||||||
|
this.completed = getTotalOutstanding(currency).isZero();
|
||||||
|
|
||||||
|
return interestDue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOverdueOn(final LocalDate transactionDate) {
|
||||||
|
return this.getDueDate().isBefore(transactionDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateChargePortion(final Money feeChargesDue, final Money feeChargesWaived, final Money feeChargesWrittenOff,
|
||||||
|
final Money penaltyChargesDue, final Money penaltyChargesWaived, final Money penaltyChargesWrittenOff) {
|
||||||
|
this.feeCharges = defaultToNullIfZero(feeChargesDue.getAmount());
|
||||||
|
this.feeChargesWaived = defaultToNullIfZero(feeChargesWaived.getAmount());
|
||||||
|
this.feeChargesWrittenOff = defaultToNullIfZero(feeChargesWrittenOff.getAmount());
|
||||||
|
this.penaltyCharges = defaultToNullIfZero(penaltyChargesDue.getAmount());
|
||||||
|
this.penaltyChargesWaived = defaultToNullIfZero(penaltyChargesWaived.getAmount());
|
||||||
|
this.penaltyChargesWrittenOff = defaultToNullIfZero(penaltyChargesWrittenOff.getAmount());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+104
-125
@@ -10,12 +10,10 @@ import java.util.Date;
|
|||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.persistence.CascadeType;
|
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.JoinColumn;
|
import javax.persistence.JoinColumn;
|
||||||
import javax.persistence.ManyToOne;
|
import javax.persistence.ManyToOne;
|
||||||
import javax.persistence.OneToOne;
|
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
import javax.persistence.Temporal;
|
import javax.persistence.Temporal;
|
||||||
import javax.persistence.TemporalType;
|
import javax.persistence.TemporalType;
|
||||||
@@ -36,7 +34,7 @@ import org.mifosplatform.useradministration.domain.AppUser;
|
|||||||
*/
|
*/
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "m_loan_transaction")
|
@Table(name = "m_loan_transaction")
|
||||||
public class LoanTransaction extends AbstractAuditableCustom<AppUser, Long> {
|
public final class LoanTransaction extends AbstractAuditableCustom<AppUser, Long> {
|
||||||
|
|
||||||
@ManyToOne(optional = false)
|
@ManyToOne(optional = false)
|
||||||
@JoinColumn(name = "loan_id", nullable = false)
|
@JoinColumn(name = "loan_id", nullable = false)
|
||||||
@@ -64,9 +62,8 @@ public class LoanTransaction extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
@Column(name = "transaction_type_enum", nullable = false)
|
@Column(name = "transaction_type_enum", nullable = false)
|
||||||
private final Integer typeOf;
|
private final Integer typeOf;
|
||||||
|
|
||||||
@OneToOne(optional = true, cascade = { CascadeType.PERSIST })
|
@Column(name = "is_reversed", nullable = false)
|
||||||
@JoinColumn(name = "contra_id")
|
private boolean reversed;
|
||||||
private LoanTransaction contra;
|
|
||||||
|
|
||||||
protected LoanTransaction() {
|
protected LoanTransaction() {
|
||||||
this.loan = null;
|
this.loan = null;
|
||||||
@@ -98,21 +95,10 @@ public class LoanTransaction extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
return waiver;
|
return waiver;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static LoanTransaction contra(final LoanTransaction originalTransaction) {
|
|
||||||
LoanTransaction contra = new LoanTransaction(null, LoanTransactionType.CONTRA, originalTransaction.getAmount().negate(),
|
|
||||||
new LocalDate(originalTransaction.getDateOf()));
|
|
||||||
contra.updateContra(originalTransaction);
|
|
||||||
return contra;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static LoanTransaction writeoff(final Loan loan, final LocalDate writeOffDate) {
|
public static LoanTransaction writeoff(final Loan loan, final LocalDate writeOffDate) {
|
||||||
return new LoanTransaction(loan, LoanTransactionType.WRITEOFF, null, writeOffDate);
|
return new LoanTransaction(loan, LoanTransactionType.WRITEOFF, null, writeOffDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateContra(final LoanTransaction transaction) {
|
|
||||||
this.contra = transaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
private LoanTransaction(final Loan loan, final LoanTransactionType type, final BigDecimal amount, final LocalDate date) {
|
private LoanTransaction(final Loan loan, final LoanTransactionType type, final BigDecimal amount, final LocalDate date) {
|
||||||
this.loan = loan;
|
this.loan = loan;
|
||||||
this.typeOf = type.getValue();
|
this.typeOf = type.getValue();
|
||||||
@@ -120,108 +106,21 @@ public class LoanTransaction extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
this.dateOf = date.toDateMidnight().toDate();
|
this.dateOf = date.toDateMidnight().toDate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public BigDecimal getAmount() {
|
public void reverse() {
|
||||||
return this.amount;
|
this.reversed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money getAmount(final MonetaryCurrency currency) {
|
public void resetDerivedComponents() {
|
||||||
return Money.of(currency, this.amount);
|
this.principalPortion = null;
|
||||||
|
this.interestPortion = null;
|
||||||
|
this.feeChargesPortion = null;
|
||||||
|
this.penaltyChargesPortion = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LocalDate getTransactionDate() {
|
|
||||||
return new LocalDate(this.dateOf);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Date getDateOf() {
|
|
||||||
return dateOf;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LoanTransactionType getTypeOf() {
|
|
||||||
return LoanTransactionType.fromInt(this.typeOf);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRepayment() {
|
|
||||||
return LoanTransactionType.REPAYMENT.equals(getTypeOf()) && isNotContra();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isNotRepayment() {
|
|
||||||
return !isRepayment();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isNotContra() {
|
|
||||||
return this.contra == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isContra() {
|
|
||||||
return this.contra != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDisbursement() {
|
|
||||||
return LoanTransactionType.DISBURSEMENT.equals(getTypeOf());
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRepaymentAtDisbursement() {
|
|
||||||
return LoanTransactionType.REPAYMENT_AT_DISBURSEMENT.equals(getTypeOf());
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isInterestWaiver() {
|
|
||||||
return LoanTransactionType.WAIVE_INTEREST.equals(getTypeOf()) && isNotContra();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isChargesWaiver() {
|
|
||||||
return LoanTransactionType.WAIVE_CHARGES.equals(getTypeOf()) && isNotContra();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isNotInterestWaiver() {
|
|
||||||
return !isInterestWaiver();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isWaiver() {
|
|
||||||
return isInterestWaiver() || isChargesWaiver();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isNotWaiver() {
|
|
||||||
return !isInterestWaiver() && !isChargesWaiver();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isWriteOff() {
|
|
||||||
return getTypeOf().isWriteOff() && isNotContra();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isIdentifiedBy(final Long identifier) {
|
|
||||||
return this.getId().equals(identifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isBelongingToLoanOf(final Loan check) {
|
|
||||||
return this.loan.getId().equals(check.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isNotBelongingToLoanOf(final Loan check) {
|
|
||||||
return !isBelongingToLoanOf(check);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LoanTransaction contra() {
|
|
||||||
this.contra = LoanTransaction.contra(this);
|
|
||||||
contra.updateLoan(this.loan);
|
|
||||||
|
|
||||||
return this.contra;
|
|
||||||
}
|
|
||||||
|
|
||||||
// public LoanTransaction newContra() {
|
|
||||||
// // should update some flag old entry being contra'd
|
|
||||||
// LoanTransaction contra = LoanTransaction.contra(this);
|
|
||||||
// contra.updateLoan(this.loan);
|
|
||||||
// return contra;
|
|
||||||
// }
|
|
||||||
|
|
||||||
public void updateLoan(final Loan loan) {
|
public void updateLoan(final Loan loan) {
|
||||||
this.loan = loan;
|
this.loan = loan;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isNonZero() {
|
|
||||||
return this.amount.subtract(BigDecimal.ZERO).doubleValue() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This updates the derived fields of a loan transaction for the principal,
|
* This updates the derived fields of a loan transaction for the principal,
|
||||||
* interest and interest waived portions.
|
* interest and interest waived portions.
|
||||||
@@ -282,11 +181,92 @@ public class LoanTransaction extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
return this.penaltyChargesPortion;
|
return this.penaltyChargesPortion;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetDerivedComponents() {
|
public BigDecimal getAmount() {
|
||||||
this.principalPortion = null;
|
return this.amount;
|
||||||
this.interestPortion = null;
|
}
|
||||||
this.feeChargesPortion = null;
|
|
||||||
this.penaltyChargesPortion = null;
|
public Money getAmount(final MonetaryCurrency currency) {
|
||||||
|
return Money.of(currency, this.amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDate getTransactionDate() {
|
||||||
|
return new LocalDate(this.dateOf);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getDateOf() {
|
||||||
|
return dateOf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoanTransactionType getTypeOf() {
|
||||||
|
return LoanTransactionType.fromInt(this.typeOf);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isReversed() {
|
||||||
|
return this.reversed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNotReversed() {
|
||||||
|
return !isReversed();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRepayment() {
|
||||||
|
return LoanTransactionType.REPAYMENT.equals(getTypeOf()) && isNotReversed();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNotRepayment() {
|
||||||
|
return !isRepayment();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDisbursement() {
|
||||||
|
return LoanTransactionType.DISBURSEMENT.equals(getTypeOf()) && isNotReversed();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRepaymentAtDisbursement() {
|
||||||
|
return LoanTransactionType.REPAYMENT_AT_DISBURSEMENT.equals(getTypeOf()) && isNotReversed();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isRecoveryRepayment() {
|
||||||
|
return LoanTransactionType.RECOVERY_REPAYMENT.equals(getTypeOf()) && isNotReversed();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInterestWaiver() {
|
||||||
|
return LoanTransactionType.WAIVE_INTEREST.equals(getTypeOf()) && isNotReversed();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isChargesWaiver() {
|
||||||
|
return LoanTransactionType.WAIVE_CHARGES.equals(getTypeOf()) && isNotReversed();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNotInterestWaiver() {
|
||||||
|
return !isInterestWaiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isWaiver() {
|
||||||
|
return isInterestWaiver() || isChargesWaiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNotWaiver() {
|
||||||
|
return !isInterestWaiver() && !isChargesWaiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isWriteOff() {
|
||||||
|
return getTypeOf().isWriteOff() && isNotReversed();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isIdentifiedBy(final Long identifier) {
|
||||||
|
return this.getId().equals(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isBelongingToLoanOf(final Loan check) {
|
||||||
|
return this.loan.getId().equals(check.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNotBelongingToLoanOf(final Loan check) {
|
||||||
|
return !isBelongingToLoanOf(check);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNonZero() {
|
||||||
|
return this.amount.subtract(BigDecimal.ZERO).doubleValue() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isGreaterThan(final Money monetaryAmount) {
|
public boolean isGreaterThan(final Money monetaryAmount) {
|
||||||
@@ -318,19 +298,18 @@ public class LoanTransaction extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
public Map<String, Object> toMapData(final CurrencyData currencyData) {
|
public Map<String, Object> toMapData(final CurrencyData currencyData) {
|
||||||
final Map<String, Object> thisTransactionData = new LinkedHashMap<String, Object>();
|
final Map<String, Object> thisTransactionData = new LinkedHashMap<String, Object>();
|
||||||
|
|
||||||
LoanTransactionType type = LoanTransactionType.fromInt(this.typeOf);
|
|
||||||
final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(this.typeOf);
|
final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(this.typeOf);
|
||||||
|
|
||||||
thisTransactionData.put("id", this.getId());
|
thisTransactionData.put("id", this.getId());
|
||||||
thisTransactionData.put("type", transactionType);
|
thisTransactionData.put("type", transactionType);
|
||||||
thisTransactionData.put("disbursement", type.isDisbursement());
|
thisTransactionData.put("disbursement", Boolean.valueOf(this.isDisbursement()));
|
||||||
thisTransactionData.put("repaymentAtDisbursement", type.isRepaymentAtDisbursement());
|
thisTransactionData.put("repaymentAtDisbursement", Boolean.valueOf(this.isRepaymentAtDisbursement()));
|
||||||
thisTransactionData.put("repayment", type.isRepayment());
|
thisTransactionData.put("repayment", Boolean.valueOf(this.isRepayment()));
|
||||||
thisTransactionData.put("recoveryRepayment", type.isRecoveryRepayment());
|
thisTransactionData.put("recoveryRepayment", Boolean.valueOf(this.isRecoveryRepayment()));
|
||||||
thisTransactionData.put("contra", type.isContra());
|
thisTransactionData.put("contra", Boolean.valueOf(this.isReversed()));
|
||||||
thisTransactionData.put("waiveInterest", type.isWaiveInterest());
|
thisTransactionData.put("waiveInterest", Boolean.valueOf(this.isInterestWaiver()));
|
||||||
thisTransactionData.put("waiveCharges", type.isWaiveCharges());
|
thisTransactionData.put("waiveCharges", Boolean.valueOf(this.isChargesWaiver()));
|
||||||
thisTransactionData.put("writeOff", type.isWriteOff());
|
thisTransactionData.put("writeOff", Boolean.valueOf(this.isWriteOff()));
|
||||||
|
|
||||||
thisTransactionData.put("date", this.getTransactionDate());
|
thisTransactionData.put("date", this.getTransactionDate());
|
||||||
thisTransactionData.put("currency", currencyData);
|
thisTransactionData.put("currency", currencyData);
|
||||||
|
|||||||
+7
-11
@@ -77,35 +77,31 @@ public enum LoanTransactionType {
|
|||||||
return loanTransactionType;
|
return loanTransactionType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean isDisbursement() {
|
public boolean isDisbursement() {
|
||||||
return this.value.equals(LoanTransactionType.DISBURSEMENT.getValue());
|
return this.value.equals(LoanTransactionType.DISBURSEMENT.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean isRepaymentAtDisbursement() {
|
public boolean isRepaymentAtDisbursement() {
|
||||||
return this.value.equals(LoanTransactionType.REPAYMENT_AT_DISBURSEMENT.getValue());
|
return this.value.equals(LoanTransactionType.REPAYMENT_AT_DISBURSEMENT.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean isRepayment() {
|
public boolean isRepayment() {
|
||||||
return this.value.equals(LoanTransactionType.REPAYMENT.getValue());
|
return this.value.equals(LoanTransactionType.REPAYMENT.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean isRecoveryRepayment() {
|
public boolean isRecoveryRepayment() {
|
||||||
return this.value.equals(LoanTransactionType.RECOVERY_REPAYMENT.getValue());
|
return this.value.equals(LoanTransactionType.RECOVERY_REPAYMENT.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean isContra() {
|
public boolean isWaiveInterest() {
|
||||||
return this.value.equals(LoanTransactionType.CONTRA.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean isWaiveInterest() {
|
|
||||||
return this.value.equals(LoanTransactionType.WAIVE_INTEREST.getValue());
|
return this.value.equals(LoanTransactionType.WAIVE_INTEREST.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean isWaiveCharges() {
|
public boolean isWaiveCharges() {
|
||||||
return this.value.equals(LoanTransactionType.WAIVE_CHARGES.getValue());
|
return this.value.equals(LoanTransactionType.WAIVE_CHARGES.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean isWriteOff() {
|
public boolean isWriteOff() {
|
||||||
return this.value.equals(LoanTransactionType.WRITEOFF.getValue());
|
return this.value.equals(LoanTransactionType.WRITEOFF.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+3
-3
@@ -12,7 +12,7 @@ import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceN
|
|||||||
*/
|
*/
|
||||||
public class LoanNotFoundException extends AbstractPlatformResourceNotFoundException {
|
public class LoanNotFoundException extends AbstractPlatformResourceNotFoundException {
|
||||||
|
|
||||||
public LoanNotFoundException(Long id) {
|
public LoanNotFoundException(final Long id) {
|
||||||
super("error.msg.loan.id.invalid", "Loan with identifier " + id + " does not exist", id);
|
super("error.msg.loan.id.invalid", "Loan with identifier " + id + " does not exist", id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -200,7 +200,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
// repayments at time of disbursement (e.g. charges)
|
// repayments at time of disbursement (e.g. charges)
|
||||||
String sql = "select "
|
String sql = "select "
|
||||||
+ rm.LoanPaymentsSchema()
|
+ rm.LoanPaymentsSchema()
|
||||||
+ " where tr.loan_id = ? and tr.transaction_type_enum not in (0, 3) and tr.contra_id is null order by tr.transaction_date ASC";
|
+ " where tr.loan_id = ? and tr.transaction_type_enum not in (0, 3) and tr.is_reversed=0 order by tr.transaction_date ASC";
|
||||||
return this.jdbcTemplate.query(sql, rm, new Object[] { loanId });
|
return this.jdbcTemplate.query(sql, rm, new Object[] { loanId });
|
||||||
} catch (EmptyResultDataAccessException e) {
|
} catch (EmptyResultDataAccessException e) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
+13
-14
@@ -130,13 +130,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
|
|
||||||
final ApplicationCurrency currency = this.applicationCurrencyRepository.findOneByCode(loan.getPrincpal().getCurrencyCode());
|
final ApplicationCurrency currency = this.applicationCurrencyRepository.findOneByCode(loan.getPrincpal().getCurrencyCode());
|
||||||
|
|
||||||
/***
|
|
||||||
* In cases where an "Undo disbursement is done and the loan is
|
|
||||||
* disbursed again, we need to ensure the old transactions are entered
|
|
||||||
* again in accounting
|
|
||||||
***/
|
|
||||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||||
final Map<String, Object> changes = loan.disburse(currentUser, command, defaultLoanLifecycleStateMachine(), currency, existingTransactionIds);
|
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||||
|
final Map<String, Object> changes = loan.disburse(currentUser, command, defaultLoanLifecycleStateMachine(), currency,
|
||||||
|
existingTransactionIds, existingReversedTransactionIds);
|
||||||
if (!changes.isEmpty()) {
|
if (!changes.isEmpty()) {
|
||||||
this.loanRepository.save(loan);
|
this.loanRepository.save(loan);
|
||||||
|
|
||||||
@@ -144,8 +141,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
Note note = Note.loanNote(loan, noteText);
|
Note note = Note.loanNote(loan, noteText);
|
||||||
this.noteRepository.save(note);
|
this.noteRepository.save(note);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Map<String, Object> accountingBridgeData = loan.deriveDisbursementData(currency.toData(), existingTransactionIds);
|
final Map<String, Object> accountingBridgeData = loan.deriveAccountingBridgeData(currency.toData(), existingTransactionIds,
|
||||||
|
existingReversedTransactionIds);
|
||||||
journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,7 +167,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
final Loan loan = retrieveLoanBy(loanId);
|
final Loan loan = retrieveLoanBy(loanId);
|
||||||
|
|
||||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||||
final Map<String, Object> changes = loan.undoDisbursal(defaultLoanLifecycleStateMachine(), existingTransactionIds);
|
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||||
|
final Map<String, Object> changes = loan.undoDisbursal(defaultLoanLifecycleStateMachine(), existingTransactionIds,
|
||||||
|
existingReversedTransactionIds);
|
||||||
if (!changes.isEmpty()) {
|
if (!changes.isEmpty()) {
|
||||||
this.loanRepository.saveAndFlush(loan);
|
this.loanRepository.saveAndFlush(loan);
|
||||||
|
|
||||||
@@ -179,10 +179,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
this.noteRepository.save(note);
|
this.noteRepository.save(note);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Loan loanRefetch = retrieveLoanBy(loanId);
|
final ApplicationCurrency currency = this.applicationCurrencyRepository.findOneByCode(loan.getCurrencyCode());
|
||||||
|
final Map<String, Object> accountingBridgeData = loan.deriveAccountingBridgeData(currency.toData(), existingTransactionIds,
|
||||||
final ApplicationCurrency currency = this.applicationCurrencyRepository.findOneByCode(loan.getPrincpal().getCurrencyCode());
|
existingReversedTransactionIds);
|
||||||
final Map<String, Object> accountingBridgeData = loanRefetch.deriveAccountingBridgeData(currency.toData(), existingTransactionIds);
|
|
||||||
journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -736,7 +735,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
LoanTransactionDTO loanTransactionDTO = new LoanTransactionDTO(loanTransaction.getId().toString(), loanTransaction.getDateOf(),
|
LoanTransactionDTO loanTransactionDTO = new LoanTransactionDTO(loanTransaction.getId().toString(), loanTransaction.getDateOf(),
|
||||||
loanTransaction.getAmount(), loanTransaction.getPrincipalPortion(), loanTransaction.getInterestPortion(),
|
loanTransaction.getAmount(), loanTransaction.getPrincipalPortion(), loanTransaction.getInterestPortion(),
|
||||||
loanTransaction.getFeePortion(), loanTransaction.getPenaltyChargesPortion(), loanTransaction.isDisbursement(),
|
loanTransaction.getFeePortion(), loanTransaction.getPenaltyChargesPortion(), loanTransaction.isDisbursement(),
|
||||||
loanTransaction.isRepayment(), loanTransaction.isRepaymentAtDisbursement(), loanTransaction.isContra(),
|
loanTransaction.isRepayment(), loanTransaction.isRepaymentAtDisbursement(), loanTransaction.isReversed(),
|
||||||
loanTransaction.isWriteOff());
|
loanTransaction.isWriteOff());
|
||||||
loanTransactionDTOs.add(loanTransactionDTO);
|
loanTransactionDTOs.add(loanTransactionDTO);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user