Skip to content
This repository has been archived by the owner on Jan 11, 2024. It is now read-only.

settlement-api-for-collection-and-txn-value-date #29

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.fineract.cn.deposit.api.v1.collection.domain.data;

/**
* @author manoj
*/
public enum CollectionStatusEnum {
INIT,
PROCESSING,
COLLECTED;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.fineract.cn.deposit.api.v1.collection.domain.data;

import java.math.BigDecimal;

/**
* @author manoj
*/
public class SettleCollectionsRequest {
private String token;
private BigDecimal amount;

private String transactionCode;
private String requestCode;
private String routingCode;
private String externalId;
private String note;
private String txnDate;

public SettleCollectionsRequest() {
}

public SettleCollectionsRequest(String token, BigDecimal amount, String transactionCode,
String requestCode, String routingCode, String externalId, String note,
String txnDate) {
this.token = token;
this.amount = amount;
this.transactionCode = transactionCode;
this.requestCode = requestCode;
this.routingCode = routingCode;
this.externalId = externalId;
this.note = note;
this.txnDate = txnDate;
}

public String getToken() {
return token;
}

public void setToken(String token) {
this.token = token;
}

public BigDecimal getAmount() {
return amount;
}

public void setAmount(BigDecimal amount) {
this.amount = amount;
}

public String getTransactionCode() {
return transactionCode;
}

public void setTransactionCode(String transactionCode) {
this.transactionCode = transactionCode;
}

public String getRequestCode() {
return requestCode;
}

public void setRequestCode(String requestCode) {
this.requestCode = requestCode;
}

public String getRoutingCode() {
return routingCode;
}

public void setRoutingCode(String routingCode) {
this.routingCode = routingCode;
}

public String getExternalId() {
return externalId;
}

public void setExternalId(String externalId) {
this.externalId = externalId;
}

public String getNote() {
return note;
}

public void setNote(String note) {
this.note = note;
}

public String getTxnDate() {
return txnDate;
}

public void setTxnDate(String txnDate) {
this.txnDate = txnDate;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,16 @@ public class TransactionRequestData {
@Length(max = 32)
private String toAccountId;

private String transactionDate;

public TransactionRequestData() {
}

public TransactionRequestData(String transactionCode, String requestCode, String routingCode, String externalId, String accountId,
String note, LocalDateTime expiration,
MoneyData amount, String subTxnId,
String fromAccountId, String toAccountId) {
String fromAccountId, String toAccountId,
String transactionDate) {
this.transactionCode = transactionCode;
this.requestCode = requestCode;
this.routingCode = routingCode;
Expand All @@ -81,6 +84,7 @@ public TransactionRequestData(String transactionCode, String requestCode, String
this.subTxnId = subTxnId;
this.fromAccountId = fromAccountId;
this.toAccountId = toAccountId;
this.transactionDate = transactionDate;
}

@NotNull
Expand Down Expand Up @@ -175,4 +179,12 @@ public String getToAccountId() {
public void setToAccountId(String toAccountId) {
this.toAccountId = toAccountId;
}

public String getTransactionDate() {
return transactionDate;
}

public void setTransactionDate(String transactionDate) {
this.transactionDate = transactionDate;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.fineract.cn.deposit.service.internal.command;

import org.apache.fineract.cn.deposit.api.v1.collection.domain.data.SettleCollectionsRequest;

/**
* @author manoj
*/
public class SettleCollectionsCommand {
private SettleCollectionsRequest settleCollectionsRequest;

public SettleCollectionsCommand(SettleCollectionsRequest settleCollectionsRequest) {
this.settleCollectionsRequest = settleCollectionsRequest;
}

public SettleCollectionsRequest getSettleCollectionsRequest() {
return settleCollectionsRequest;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,23 @@
import org.apache.fineract.cn.command.annotation.Aggregate;
import org.apache.fineract.cn.command.annotation.CommandHandler;
import org.apache.fineract.cn.command.annotation.CommandLogLevel;
import org.apache.fineract.cn.deposit.api.v1.collection.domain.data.CollectionsResponse;
import org.apache.fineract.cn.deposit.api.v1.collection.domain.data.IndividualPayments;
import org.apache.fineract.cn.deposit.api.v1.collection.domain.data.TokenEntities;
import org.apache.fineract.cn.deposit.api.v1.collection.domain.data.*;
import org.apache.fineract.cn.deposit.api.v1.transaction.domain.data.MoneyData;
import org.apache.fineract.cn.deposit.api.v1.transaction.domain.data.TransactionActionType;
import org.apache.fineract.cn.deposit.api.v1.transaction.domain.data.TransactionRequestData;
import org.apache.fineract.cn.deposit.service.ServiceConstants;
import org.apache.fineract.cn.deposit.service.internal.command.CreateCollectionsCommand;
import org.apache.fineract.cn.deposit.service.internal.command.SettleCollectionsCommand;
import org.apache.fineract.cn.deposit.service.internal.command.UpdateCollectionsCommand;
import org.apache.fineract.cn.deposit.service.internal.mapper.CollectionsMapper;
import org.apache.fineract.cn.deposit.service.internal.repository.*;
import org.apache.fineract.cn.deposit.service.internal.service.SelfExpiringTokenService;
import org.apache.fineract.cn.deposit.service.rest.TransactionRestController;
import org.apache.fineract.cn.lang.ServiceException;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Lazy;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.constraints.NotNull;
Expand All @@ -47,19 +51,25 @@ public class CollectionsCommandHandler {
private final ProductInstanceRepository productInstanceRepository;
private final SubTransactionTypeRepository subTransactionTypeRepository;
private final CollectionsRepository collectionsRepository;
private final IndividualCollectionsRepository individualCollectionsRepository;
private final SelfExpiringTokenService selfExpiringTokenService;
private final TransactionRestController transactionRestController;

@Autowired
public CollectionsCommandHandler(@Qualifier(ServiceConstants.LOGGER_NAME) Logger logger,
ProductInstanceRepository productInstanceRepository,
SubTransactionTypeRepository subTransactionTypeRepository,
CollectionsRepository collectionsRepository,
SelfExpiringTokenService selfExpiringTokenService) {
IndividualCollectionsRepository individualCollectionsRepository,
SelfExpiringTokenService selfExpiringTokenService,
@Lazy TransactionRestController transactionRestController) {
this.logger = logger;
this.productInstanceRepository = productInstanceRepository;
this.subTransactionTypeRepository = subTransactionTypeRepository;
this.collectionsRepository = collectionsRepository;
this.individualCollectionsRepository = individualCollectionsRepository;
this.selfExpiringTokenService = selfExpiringTokenService;
this.transactionRestController = transactionRestController;
}

@Transactional
Expand Down Expand Up @@ -117,5 +127,79 @@ private static LocalDateTime getNow() {
return LocalDateTime.now(Clock.systemUTC());
}

@Transactional
@CommandHandler(logStart = CommandLogLevel.INFO, logFinish = CommandLogLevel.INFO)
public CollectionsResponse settleCollection(@NotNull SettleCollectionsCommand command) throws Throwable {
SettleCollectionsRequest request = command.getSettleCollectionsRequest();
//1. find which collection it is
SelfExpiringTokenEntity token = this.selfExpiringTokenService.fetchActiveToken(request.getToken());
CollectionsEntity collectionsEntity;
if(TokenEntities.COLLECTION.name().equals(token.getEntityType())){
//if group collection, deposit individual, then transfer to group

collectionsEntity = this.collectionsRepository.findByCollectionReference(token.getEntityReference())
.orElseThrow(() -> ServiceException.notFound("Collection {0} not found", token.getEntityReference()));
//validate amount
if(collectionsEntity.getAmount().compareTo(request.getAmount()) !=0){
throw ServiceException.internalError("Amount mismatch");
}
if(CollectionStatusEnum.COLLECTED.name().equals(collectionsEntity.getStatus())){
throw ServiceException.internalError("Already Collected");
}


for (IndividualCollectionsEntity individualCollectionsEntity : collectionsEntity.getIndvCollections()) {
if (individualCollectionsEntity.getAttendance().equals(AttendanceEnum.PRESENT.name())) {
//deposit
TransactionRequestData depositReq = new TransactionRequestData(request.getTransactionCode(), request.getRequestCode(),
request.getRoutingCode(), request.getExternalId(), individualCollectionsEntity.getAccount().getAccountIdentifier(),
request.getNote(), null,
MoneyData.build(individualCollectionsEntity.getAmount(), individualCollectionsEntity.getCollection().getCurrency()),
collectionsEntity.getSubTxnType().getIdentifier(), null, null, request.getTxnDate());

transactionRestController.performTxn(TransactionActionType.DEPOSIT.name(), depositReq);

//transfer
TransactionRequestData transferReq = new TransactionRequestData(request.getTransactionCode(), request.getRequestCode(),
request.getRoutingCode(), request.getExternalId(), null,
request.getNote(), null,
MoneyData.build(individualCollectionsEntity.getAmount(), individualCollectionsEntity.getCollection().getCurrency()),
collectionsEntity.getSubTxnType().getIdentifier(), individualCollectionsEntity.getAccount().getAccountIdentifier(), collectionsEntity.getAccount().getAccountIdentifier(),
request.getTxnDate());

transactionRestController.performTxn(TransactionActionType.TRANSFER.name(), transferReq);

this.selfExpiringTokenService.markTokenAsUsed(individualCollectionsEntity.getToken());
}
}
this.selfExpiringTokenService.markTokenAsUsed(collectionsEntity.getToken());
collectionsEntity.setStatus(CollectionStatusEnum.COLLECTED.name());
collectionsRepository.save(collectionsEntity);
}else{
//if individual collection, deposit to individual account
IndividualCollectionsEntity individualCollectionsEntity = this.individualCollectionsRepository.findByIndividualCollectionReference(token.getEntityReference())
.orElseThrow(() -> ServiceException.notFound("Collection {0} not found", token.getEntityReference()));
collectionsEntity = individualCollectionsEntity.getCollection();
//validate amount
if(individualCollectionsEntity.getAmount().compareTo(request.getAmount()) != 0){
throw ServiceException.internalError("Amount mismatch");
}
if(CollectionStatusEnum.COLLECTED.name().equals(collectionsEntity.getStatus())){
throw ServiceException.internalError("Already Collected");
}
//add txn Date and subTxnType
//deposit
TransactionRequestData depositReq = new TransactionRequestData(request.getTransactionCode(), request.getRequestCode(),
request.getRoutingCode(), request.getExternalId(), individualCollectionsEntity.getAccount().getAccountIdentifier(),
request.getNote(), null,
MoneyData.build(individualCollectionsEntity.getAmount(), individualCollectionsEntity.getCollection().getCurrency()),
collectionsEntity.getSubTxnType().getIdentifier(), null, null, request.getTxnDate());

transactionRestController.performTxn(TransactionActionType.DEPOSIT.name(), depositReq);
this.selfExpiringTokenService.markTokenAsUsed(individualCollectionsEntity.getToken());
collectionsEntity.setStatus(CollectionStatusEnum.PROCESSING.name());
collectionsRepository.save(collectionsEntity);
}
return CollectionsMapper.map(collectionsEntity);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ public String createProductInstance(final CreateProductInstanceCommand createPro

productInstanceEntity.setCreatedBy(UserContextHolder.checkedGetUser());
productInstanceEntity.setCreatedOn(LocalDateTime.now(Clock.systemUTC()));
productInstanceEntity.setState("PENDING");
if(StringUtils.isBlank(productInstanceEntity.getState()))
productInstanceEntity.setState("PENDING");

this.productInstanceRepository.save(productInstanceEntity);
return productInstance.getCustomerIdentifier();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,9 @@ public TransactionResponseData performTransfer(@NotNull TransactionCommand comma

switch (command.getAction()) {
case WITHDRAWAL: {
//command = dataValidator.validatePrepareTransfer(command);
return transactionService.withdraw(command);
}
case DEPOSIT: {
//command = dataValidator.validateCommitTransfer(command);
return transactionService.deposit(command);
}
case TRANSFER: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public class SelfExpiringTokenEntity {
@Convert(converter = LocalDateTimeConverter.class)
private LocalDateTime tokenExpiresBy;

/*TokenStatus*/
@Column(name = "status", length = 10)
private String status;

Expand Down
Loading