This is an automated email from the ASF dual-hosted git repository. avikg pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/fineract-cn-deposit-account-management.git
The following commit(s) were added to refs/heads/develop by this push: new e7d7e51 collections new b91f5d9 Merge pull request #25 from fynmanoj/collections-api e7d7e51 is described below commit e7d7e51384f449c82ad20e9abac66a7f370d0589 Author: Manoj <ma...@fynarfin.io> AuthorDate: Tue Apr 27 22:54:47 2021 +0530 collections --- .../v1/collection/domain/data/AttendanceEnum.java | 23 +++ .../collection/domain/data/CollectionsRequest.java | 126 ++++++++++++ .../domain/data/CollectionsResponse.java | 75 ++++++++ .../collection/domain/data/IndividualPayments.java | 108 +++++++++++ .../v1/collection/domain/data/TokenEntities.java | 23 +++ .../api/v1/collection/domain/data/TokenStatus.java | 24 +++ service/build.gradle | 3 +- .../internal/command/CreateCollectionsCommand.java | 32 +++ .../internal/command/UpdateCollectionsCommand.java | 38 ++++ .../command/handler/CollectionsCommandHandler.java | 121 ++++++++++++ .../service/internal/mapper/CollectionsMapper.java | 95 +++++++++ .../internal/repository/CollectionsEntity.java | 214 +++++++++++++++++++++ .../internal/repository/CollectionsRepository.java | 28 +++ .../repository/IndividualCollectionsEntity.java | 115 +++++++++++ .../IndividualCollectionsRepository.java | 26 +++ .../repository/SelfExpiringTokenEntity.java | 103 ++++++++++ .../repository/SelfExpiringTokenRepository.java | 26 +++ .../internal/service/CollectionsService.java | 46 +++++ .../internal/service/SelfExpiringTokenService.java | 82 ++++++++ .../service/rest/CollectionsRestController.java | 104 ++++++++++ service/src/main/resources/application.yml | 8 + .../{V11__collections.sql => V10__collections.sql} | 15 +- .../db/migrations/postgresql/V8__transaction.sql | 5 +- ..._to_sub_txn.sql => V9__ibb_conf_to_sub_txn.sql} | 4 +- .../postgresql/V9__transaction_update.sql | 30 --- 25 files changed, 1434 insertions(+), 40 deletions(-) diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/collection/domain/data/AttendanceEnum.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/collection/domain/data/AttendanceEnum.java new file mode 100644 index 0000000..8b68b65 --- /dev/null +++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/collection/domain/data/AttendanceEnum.java @@ -0,0 +1,23 @@ +/* + * 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; + +public enum AttendanceEnum { + PRESENT, + ABSENT; +} diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/collection/domain/data/CollectionsRequest.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/collection/domain/data/CollectionsRequest.java new file mode 100644 index 0000000..a91eefc --- /dev/null +++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/collection/domain/data/CollectionsRequest.java @@ -0,0 +1,126 @@ +/* + * 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 javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +public class CollectionsRequest { + private String txnDate; + @NotNull + private BigDecimal amount; + private String currency; + private String remarks; + @NotNull + private String accountId; + private String subtxnId; + private BigDecimal fee; + private List<IndividualPayments> individualPayments; + private String reference; + + public CollectionsRequest() { + } + + public CollectionsRequest(String txnDate, BigDecimal amount, String currency, String remarks, + String accountId, String subtxnId, BigDecimal fee, + List<IndividualPayments> individualPayments, String reference) { + this.txnDate = txnDate; + this.amount = amount; + this.currency = currency; + this.remarks = remarks; + this.accountId = accountId; + this.subtxnId = subtxnId; + this.fee = fee; + this.individualPayments = individualPayments; + this.reference = reference; + } + + public String getTxnDate() { + return txnDate; + } + + public void setTxnDate(String txnDate) { + this.txnDate = txnDate; + } + + public BigDecimal getAmount() { + return amount; + } + + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + + public String getCurrency() { + return currency; + } + + public void setCurrency(String currency) { + this.currency = currency; + } + + public String getRemarks() { + return remarks; + } + + public void setRemarks(String remarks) { + this.remarks = remarks; + } + + public String getAccountId() { + return accountId; + } + + public void setAccountId(String accountId) { + this.accountId = accountId; + } + + public String getSubtxnId() { + return subtxnId; + } + + public void setSubtxnId(String subtxnId) { + this.subtxnId = subtxnId; + } + + public BigDecimal getFee() { + return fee; + } + + public void setFee(BigDecimal fee) { + this.fee = fee; + } + + public List<IndividualPayments> getIndividualPayments() { + return individualPayments; + } + + public void setIndividualPayments(List<IndividualPayments> individualPayments) { + this.individualPayments = individualPayments; + } + + public String getReference() { + return reference; + } + + public void setReference(String reference) { + this.reference = reference; + } +} diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/collection/domain/data/CollectionsResponse.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/collection/domain/data/CollectionsResponse.java new file mode 100644 index 0000000..4f64b57 --- /dev/null +++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/collection/domain/data/CollectionsResponse.java @@ -0,0 +1,75 @@ +/* + * 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 com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + +import java.time.LocalDateTime; +import java.util.List; +@JsonInclude(JsonInclude.Include.NON_NULL) +public class CollectionsResponse { + private String reference; + private String token; + @JsonFormat(pattern = "yyyy-MMMM-dd hh:mm:ss") + private LocalDateTime tokenExpiresBy; + private List<IndividualPayments> individualPayments; + + public CollectionsResponse() { + } + + public CollectionsResponse(String reference, String token, LocalDateTime tokenExpiresBy, List<IndividualPayments> individualPayments) { + this.reference = reference; + this.token = token; + this.tokenExpiresBy = tokenExpiresBy; + this.individualPayments = individualPayments; + } + + public String getReference() { + return reference; + } + + public void setReference(String reference) { + this.reference = reference; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + public LocalDateTime getTokenExpiresBy() { + return tokenExpiresBy; + } + + public void setTokenExpiresBy(LocalDateTime tokenExpiresBy) { + this.tokenExpiresBy = tokenExpiresBy; + } + + public List<IndividualPayments> getIndividualPayments() { + return individualPayments; + } + + public void setIndividualPayments(List<IndividualPayments> individualPayments) { + this.individualPayments = individualPayments; + } +} diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/collection/domain/data/IndividualPayments.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/collection/domain/data/IndividualPayments.java new file mode 100644 index 0000000..d0e6401 --- /dev/null +++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/collection/domain/data/IndividualPayments.java @@ -0,0 +1,108 @@ +/* + * 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 com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonInclude; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDateTime; +@JsonInclude(JsonInclude.Include.NON_NULL) +public class IndividualPayments{ + @NotNull + private String accountNumber; + private BigDecimal amount; + private AttendanceEnum attendance; + private String reference; + private String token; + @JsonFormat(pattern = "yyyy-MMMM-dd hh:mm:ss") + private LocalDateTime tokenExpiresBy; + + public IndividualPayments() { + } + + public IndividualPayments(String accountNumber, BigDecimal amount, AttendanceEnum attendance, String reference) { + this.accountNumber = accountNumber; + this.amount = amount; + this.attendance = attendance; + this.reference = reference; + } + + public IndividualPayments(String accountNumber, AttendanceEnum attendance, String reference, + BigDecimal amount, String token, LocalDateTime tokenExpiresBy){ + this.accountNumber = accountNumber; + this.attendance = attendance; + this.reference =reference; + this.token = token; + this.tokenExpiresBy = tokenExpiresBy; + this.amount = amount; + } + + public String getAccountNumber() { + return accountNumber; + } + + public void setAccountNumber(String accountNumber) { + this.accountNumber = accountNumber; + } + + public BigDecimal getAmount() { + return amount; + } + + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + + public String getAttendance() { + return attendance==null? null: attendance.name(); + } + + public void setAttendance(String attendance) { + this.attendance = AttendanceEnum.valueOf(attendance); + } + + public String getReference() { + return reference; + } + + public void setReference(String reference) { + this.reference = reference; + } + + public void setAttendance(AttendanceEnum attendance) { + this.attendance = attendance; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + public LocalDateTime getTokenExpiresBy() { + return tokenExpiresBy; + } + + public void setTokenExpiresBy(LocalDateTime tokenExpiresBy) { + this.tokenExpiresBy = tokenExpiresBy; + } +} \ No newline at end of file diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/collection/domain/data/TokenEntities.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/collection/domain/data/TokenEntities.java new file mode 100644 index 0000000..9bc0576 --- /dev/null +++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/collection/domain/data/TokenEntities.java @@ -0,0 +1,23 @@ +/* + * 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; + +public enum TokenEntities { + COLLECTION, + INDV_COLLECTION; +} diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/collection/domain/data/TokenStatus.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/collection/domain/data/TokenStatus.java new file mode 100644 index 0000000..ca3773e --- /dev/null +++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/collection/domain/data/TokenStatus.java @@ -0,0 +1,24 @@ +/* + * 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; + +public enum TokenStatus { + ACTIVE, + USED, + EXPIRED; +} diff --git a/service/build.gradle b/service/build.gradle index dc4325f..64d471b 100644 --- a/service/build.gradle +++ b/service/build.gradle @@ -62,7 +62,8 @@ dependencies { [group: 'org.hibernate', name: 'hibernate-validator', version: versions.validator], [group: 'org.threeten', name: 'threeten-extra', version: '1.2'], [group: 'io.netty', name: 'netty-all', version: '4.1.39.Final'], - [group: 'io.netty', name: 'netty-transport-native-epoll', version: '4.1.39.Final'] + [group: 'io.netty', name: 'netty-transport-native-epoll', version: '4.1.39.Final'], + [group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: '2.8.8'] ) } diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/CreateCollectionsCommand.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/CreateCollectionsCommand.java new file mode 100644 index 0000000..c602629 --- /dev/null +++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/CreateCollectionsCommand.java @@ -0,0 +1,32 @@ +/* + * 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.CollectionsRequest; + +public class CreateCollectionsCommand { + private final CollectionsRequest collectionRequest; + + public CreateCollectionsCommand(CollectionsRequest collectionRequest) { + this.collectionRequest = collectionRequest; + } + + public CollectionsRequest getCollectionRequest() { + return collectionRequest; + } +} diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/UpdateCollectionsCommand.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/UpdateCollectionsCommand.java new file mode 100644 index 0000000..3f1f85a --- /dev/null +++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/UpdateCollectionsCommand.java @@ -0,0 +1,38 @@ +/* + * 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.CollectionsRequest; + +public class UpdateCollectionsCommand { + private final String collectionsReference; + private final CollectionsRequest collectionRequest; + + public UpdateCollectionsCommand(String collectionsReference, CollectionsRequest collectionRequest) { + this.collectionsReference = collectionsReference; + this.collectionRequest = collectionRequest; + } + + public CollectionsRequest getCollectionRequest() { + return collectionRequest; + } + + public String getCollectionsReference() { + return collectionsReference; + } +} diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/CollectionsCommandHandler.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/CollectionsCommandHandler.java new file mode 100644 index 0000000..1b77e0d --- /dev/null +++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/CollectionsCommandHandler.java @@ -0,0 +1,121 @@ +/* + * 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.handler; + +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.service.ServiceConstants; +import org.apache.fineract.cn.deposit.service.internal.command.CreateCollectionsCommand; +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.lang.ServiceException; +import org.slf4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.transaction.annotation.Transactional; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.Clock; +import java.time.LocalDateTime; +import java.util.Optional; + +@Aggregate +public class CollectionsCommandHandler { + private final Logger logger; + private final ProductInstanceRepository productInstanceRepository; + private final SubTransactionTypeRepository subTransactionTypeRepository; + private final CollectionsRepository collectionsRepository; + private final SelfExpiringTokenService selfExpiringTokenService; + + @Autowired + public CollectionsCommandHandler(@Qualifier(ServiceConstants.LOGGER_NAME) Logger logger, + ProductInstanceRepository productInstanceRepository, + SubTransactionTypeRepository subTransactionTypeRepository, + CollectionsRepository collectionsRepository, + SelfExpiringTokenService selfExpiringTokenService) { + this.logger = logger; + this.productInstanceRepository = productInstanceRepository; + this.subTransactionTypeRepository = subTransactionTypeRepository; + this.collectionsRepository = collectionsRepository; + this.selfExpiringTokenService = selfExpiringTokenService; + } + + @Transactional + @CommandHandler(logStart = CommandLogLevel.INFO, logFinish = CommandLogLevel.INFO) + public CollectionsResponse saveCollection(@NotNull CreateCollectionsCommand command) { + + CollectionsEntity collectionsEntity = CollectionsMapper.map(command.getCollectionRequest(), + productInstanceRepository, subTransactionTypeRepository); + + //create self expiring tokens + LocalDateTime currentTime = getNow(); + collectionsEntity.setToken(this.selfExpiringTokenService.generateAndSaveToken(TokenEntities.COLLECTION.name(), collectionsEntity.getCollectionReference(), currentTime)); + + collectionsEntity.getIndvCollections().forEach( + x-> { + SelfExpiringTokenEntity token = selfExpiringTokenService.generateAndSaveToken(TokenEntities.INDV_COLLECTION.name(), x.getIndividualCollectionReference(), currentTime); + x.setToken(token); + } + ); + + //save collections + collectionsRepository.save(collectionsEntity); + + return CollectionsMapper.map(collectionsEntity); + } + + @Transactional + @CommandHandler(logStart = CommandLogLevel.INFO, logFinish = CommandLogLevel.INFO) + public CollectionsResponse updateCollection(@NotNull UpdateCollectionsCommand command) { + + CollectionsEntity collectionsEntity = this.collectionsRepository.findByCollectionReference(command.getCollectionsReference()) + .orElseThrow(() -> ServiceException.notFound("Collection {0} not found", command.getCollectionsReference())); + + collectionsEntity.setAmount(BigDecimal.ZERO); + collectionsEntity.getIndvCollections().forEach(x->{ + Optional<IndividualPayments> individualPaymentsOptional = command.getCollectionRequest().getIndividualPayments().stream().filter(a -> x.getAccount().getAccountIdentifier().equals(a.getAccountNumber())).findFirst(); + if(individualPaymentsOptional.isPresent()){ + IndividualPayments individualPayment = individualPaymentsOptional.get(); + x.setAttendance(individualPayment.getAttendance()); + if(individualPayment.getAmount() != null) { + x.setAmount(individualPayment.getAmount()); + } + collectionsEntity.setAmount(collectionsEntity.getAmount().add(x.getAmount())); + } + } + ); + + //save collections + collectionsRepository.save(collectionsEntity); + + return CollectionsMapper.map(collectionsEntity); + } + + private static LocalDateTime getNow() { + return LocalDateTime.now(Clock.systemUTC()); + } + + +} diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/mapper/CollectionsMapper.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/mapper/CollectionsMapper.java new file mode 100644 index 0000000..adba9d6 --- /dev/null +++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/mapper/CollectionsMapper.java @@ -0,0 +1,95 @@ +/* + * 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.mapper; + +import org.apache.fineract.cn.api.util.UserContextHolder; +import org.apache.fineract.cn.deposit.api.v1.collection.domain.data.AttendanceEnum; +import org.apache.fineract.cn.deposit.api.v1.collection.domain.data.CollectionsRequest; +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.service.internal.repository.*; +import org.apache.fineract.cn.lang.ServiceException; + +import java.math.BigDecimal; +import java.time.Clock; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.UUID; +import java.util.stream.Collectors; + +public class CollectionsMapper { + private CollectionsMapper() { + super(); + } + + public static CollectionsEntity map(CollectionsRequest collectionsRequest, + ProductInstanceRepository accountRepository, + SubTransactionTypeRepository subTxnRepository){ + CollectionsEntity entity = new CollectionsEntity(); + + if(collectionsRequest.getTxnDate() != null) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MMMM-dd"); + entity.setTransactionDate(LocalDate.parse(collectionsRequest.getTxnDate(), formatter).atStartOfDay()); + }else { + entity.setTransactionDate(getNow()); + } + entity.setAmount(BigDecimal.ZERO); + entity.setTransportFeeAmount(collectionsRequest.getFee()); + entity.setCurrency(collectionsRequest.getCurrency()); + entity.setRemarks(collectionsRequest.getRemarks()); + entity.setAccount(accountRepository.findByAccountIdentifier(collectionsRequest.getAccountId()).orElseThrow(() -> ServiceException.notFound("Account {0} not found.", collectionsRequest.getAccountId()))); + entity.setSubTxnType(subTxnRepository.findByIdentifier(collectionsRequest.getSubtxnId()).orElseThrow(() -> ServiceException.notFound("Sub Txn Type {0} not found.", collectionsRequest.getSubtxnId()))); + entity.setStatus("INIT"); + entity.setCollectionReference(UUID.randomUUID().toString()); + entity.setCreatedBy(getLoginUser()); + entity.setCreatedOn(getNow()); + entity.setLastModifiedBy(getLoginUser()); + entity.setLastModifiedOn(getNow()); + entity.setIndvCollections(collectionsRequest.getIndividualPayments().stream().map(x-> { + IndividualCollectionsEntity indv = new IndividualCollectionsEntity(); + indv.setCollection(entity); + indv.setAccount(accountRepository.findByAccountIdentifier(x.getAccountNumber()).orElseThrow(() -> ServiceException.notFound("Account {0} not found.", x.getAccountNumber()))); + indv.setAccountExternalId(x.getAccountNumber()); + indv.setAmount(x.getAmount()); + indv.setIndividualCollectionReference(UUID.randomUUID().toString()); + entity.setAmount(entity.getAmount().add(x.getAmount())); + return indv; + }).collect(Collectors.toSet())); + return entity; + } + + public static CollectionsResponse map(CollectionsEntity collectionsEntity){ + return new CollectionsResponse(collectionsEntity.getCollectionReference(), + collectionsEntity.getToken().getToken(), + collectionsEntity.getToken().getTokenExpiresBy(), + collectionsEntity.getIndvCollections().stream().map( x ->{ + return new IndividualPayments(x.getAccount().getAccountIdentifier(), + x.getAttendance() == null ? null: AttendanceEnum.valueOf(x.getAttendance()), + x.getIndividualCollectionReference(), x.getAmount(), + x.getToken().getToken(), x.getToken().getTokenExpiresBy()); + }).collect(Collectors.toList())); + } + + private static LocalDateTime getNow() { + return LocalDateTime.now(Clock.systemUTC()); + } + private static String getLoginUser() { + return UserContextHolder.checkedGetUser(); + } +} diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/CollectionsEntity.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/CollectionsEntity.java new file mode 100644 index 0000000..33d01b8 --- /dev/null +++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/CollectionsEntity.java @@ -0,0 +1,214 @@ +/* + * 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.repository; + +import org.apache.fineract.cn.deposit.api.v1.instance.domain.ProductInstance; +import org.apache.fineract.cn.postgresql.util.LocalDateTimeConverter; + +import javax.persistence.*; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.Set; + +@Entity +@Table(name = "shed_collections") +public class CollectionsEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id", nullable = false) + private Long id; + + @Column(name = "transaction_date") + @Convert(converter = LocalDateTimeConverter.class) + private LocalDateTime transactionDate; + + @Column(name = "amount", nullable = false) + private BigDecimal amount; + + @Column(name = "transport_fee_amount", nullable = false) + private BigDecimal transportFeeAmount; + + @Column(name = "currency", length = 10) + private String currency; + + @Column(name = "remarks", length = 1024) + private String remarks; + + @ManyToOne(fetch = FetchType.EAGER, optional = false) + @JoinColumn(name = "account_identifier", nullable = false, unique = true, referencedColumnName = "account_identifier") + private ProductInstanceEntity account; + + @ManyToOne(fetch = FetchType.EAGER, optional = false) + @JoinColumn(name = "sub_txn_type_id", nullable = false, unique = true, referencedColumnName = "identifier") + private SubTransactionTypeEntity subTxnType; + + @Column(name = "status", length = 20) + private String status; + + @Column(name = "c_reference", length = 36) + private String collectionReference; + + @Column(name = "created_by", nullable = false, length = 32) + private String createdBy; + + @Column(name = "created_on", nullable = false) + @Convert(converter = LocalDateTimeConverter.class) + private LocalDateTime createdOn; + + @Column(name = "last_modified_by", length = 32) + private String lastModifiedBy; + + @Column(name = "last_modified_on") + @Convert(converter = LocalDateTimeConverter.class) + private LocalDateTime lastModifiedOn; + + @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) + @JoinColumn(name = "collections_id") // we need to duplicate the physical information + private Set<IndividualCollectionsEntity> indvCollections; + + @ManyToOne(fetch = FetchType.EAGER, optional = false) + @JoinColumn(name = "token", nullable = false, unique = true) + private SelfExpiringTokenEntity token; + + public CollectionsEntity() { + } + + public LocalDateTime getTransactionDate() { + return transactionDate; + } + + public void setTransactionDate(LocalDateTime transactionDate) { + this.transactionDate = transactionDate; + } + + public BigDecimal getAmount() { + return amount; + } + + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + + public BigDecimal getTransportFeeAmount() { + return transportFeeAmount; + } + + public void setTransportFeeAmount(BigDecimal transportFeeAmount) { + this.transportFeeAmount = transportFeeAmount; + } + + public String getCurrency() { + return currency; + } + + public void setCurrency(String currency) { + this.currency = currency; + } + + public String getRemarks() { + return remarks; + } + + public void setRemarks(String remarks) { + this.remarks = remarks; + } + + public ProductInstanceEntity getAccount() { + return account; + } + + public void setAccount(ProductInstanceEntity account) { + this.account = account; + } + + public SubTransactionTypeEntity getSubTxnType() { + return subTxnType; + } + + public void setSubTxnType(SubTransactionTypeEntity subTxnType) { + this.subTxnType = subTxnType; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCollectionReference() { + return collectionReference; + } + + public void setCollectionReference(String collectionReference) { + this.collectionReference = collectionReference; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public LocalDateTime getCreatedOn() { + return createdOn; + } + + public void setCreatedOn(LocalDateTime createdOn) { + this.createdOn = createdOn; + } + + public String getLastModifiedBy() { + return lastModifiedBy; + } + + public void setLastModifiedBy(String lastModifiedBy) { + this.lastModifiedBy = lastModifiedBy; + } + + public LocalDateTime getLastModifiedOn() { + return lastModifiedOn; + } + + public void setLastModifiedOn(LocalDateTime lastModifiedOn) { + this.lastModifiedOn = lastModifiedOn; + } + + public Set<IndividualCollectionsEntity> getIndvCollections() { + return indvCollections; + } + + public void addToIndvCollections(IndividualCollectionsEntity indvCollection) { + this.indvCollections.add(indvCollection); + } + + public void setIndvCollections(Set<IndividualCollectionsEntity> indvCollections) { + this.indvCollections = indvCollections; + } + + public SelfExpiringTokenEntity getToken() { + return token; + } + + public void setToken(SelfExpiringTokenEntity token) { + this.token = token; + } +} diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/CollectionsRepository.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/CollectionsRepository.java new file mode 100644 index 0000000..40948ab --- /dev/null +++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/CollectionsRepository.java @@ -0,0 +1,28 @@ +/* + * 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.repository; + +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface CollectionsRepository extends JpaRepository<CollectionsEntity, Long> { + + Optional<CollectionsEntity> findByCollectionReference(String collectionReference); + +} diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/IndividualCollectionsEntity.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/IndividualCollectionsEntity.java new file mode 100644 index 0000000..48a83f0 --- /dev/null +++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/IndividualCollectionsEntity.java @@ -0,0 +1,115 @@ +/* + * 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.repository; + +import org.apache.fineract.cn.deposit.api.v1.instance.domain.ProductInstance; + +import javax.persistence.*; +import java.math.BigDecimal; + +@Entity +@Table(name = "shed_collections_inidividual") +public class IndividualCollectionsEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id", nullable = false) + private Long id; + + @ManyToOne(fetch = FetchType.EAGER, optional = false, cascade = CascadeType.ALL) + @JoinColumn(name = "collections_id", nullable = false, unique = true) + private CollectionsEntity collection; + + @ManyToOne(fetch = FetchType.EAGER, optional = false) + @JoinColumn(name = "account_identifier", nullable = false, unique = true, referencedColumnName = "account_identifier") + private ProductInstanceEntity account; + + @Column(name = "account_external_id", length = 64) + private String accountExternalId; + + @Column(name = "amount", nullable = false) + private BigDecimal amount; + + @Column(name = "i_reference", length = 36) + private String individualCollectionReference; + + @Column(name = "attendance", length = 10) + private String attendance; + + @ManyToOne(fetch = FetchType.EAGER, optional = false) + @JoinColumn(name = "token", nullable = false, unique = true) + private SelfExpiringTokenEntity token; + + public IndividualCollectionsEntity() { + } + + public CollectionsEntity getCollection() { + return collection; + } + + public void setCollection(CollectionsEntity collection) { + this.collection = collection; + } + + public ProductInstanceEntity getAccount() { + return account; + } + + public void setAccount(ProductInstanceEntity account) { + this.account = account; + } + + public String getAccountExternalId() { + return accountExternalId; + } + + public void setAccountExternalId(String accountExternalId) { + this.accountExternalId = accountExternalId; + } + + public BigDecimal getAmount() { + return amount; + } + + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + + public String getIndividualCollectionReference() { + return individualCollectionReference; + } + + public void setIndividualCollectionReference(String individualCollectionReference) { + this.individualCollectionReference = individualCollectionReference; + } + + public String getAttendance() { + return attendance; + } + + public void setAttendance(String attendance) { + this.attendance = attendance; + } + + public SelfExpiringTokenEntity getToken() { + return token; + } + + public void setToken(SelfExpiringTokenEntity token) { + this.token = token; + } +} diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/IndividualCollectionsRepository.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/IndividualCollectionsRepository.java new file mode 100644 index 0000000..03797d8 --- /dev/null +++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/IndividualCollectionsRepository.java @@ -0,0 +1,26 @@ +/* + * 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.repository; + +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface IndividualCollectionsRepository extends JpaRepository<IndividualCollectionsEntity, Long> { + Optional<IndividualCollectionsEntity> findByIndividualCollectionReference(String individualCollectionReference); +} diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/SelfExpiringTokenEntity.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/SelfExpiringTokenEntity.java new file mode 100644 index 0000000..3d9d992 --- /dev/null +++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/SelfExpiringTokenEntity.java @@ -0,0 +1,103 @@ +/* + * 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.repository; + +import org.apache.fineract.cn.postgresql.util.LocalDateTimeConverter; + +import javax.persistence.*; +import java.time.LocalDateTime; + +@Entity +@Table(name = "shed_self_expiring_tokens") +public class SelfExpiringTokenEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id", nullable = false) + private Long id; + + @Column(name = "token", length = 10) + private String token; + + @Column(name = "created_time") + @Convert(converter = LocalDateTimeConverter.class) + private LocalDateTime createdTime; + + @Column(name = "token_expires_by") + @Convert(converter = LocalDateTimeConverter.class) + private LocalDateTime tokenExpiresBy; + + @Column(name = "status", length = 10) + private String status; + + @Column(name = "entity_type", length = 36) + private String entityType; + + @Column(name = "entity_reference", length = 36) + private String entityReference; + + public SelfExpiringTokenEntity() { + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + public LocalDateTime getCreatedTime() { + return createdTime; + } + + public void setCreatedTime(LocalDateTime createdTime) { + this.createdTime = createdTime; + } + + public LocalDateTime getTokenExpiresBy() { + return tokenExpiresBy; + } + + public void setTokenExpiresBy(LocalDateTime tokenExpiresBy) { + this.tokenExpiresBy = tokenExpiresBy; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getEntityType() { + return entityType; + } + + public void setEntityType(String entityType) { + this.entityType = entityType; + } + + public String getEntityReference() { + return entityReference; + } + + public void setEntityReference(String entityReference) { + this.entityReference = entityReference; + } +} diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/SelfExpiringTokenRepository.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/SelfExpiringTokenRepository.java new file mode 100644 index 0000000..a49f4b9 --- /dev/null +++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/SelfExpiringTokenRepository.java @@ -0,0 +1,26 @@ +/* + * 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.repository; + +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface SelfExpiringTokenRepository extends JpaRepository<SelfExpiringTokenEntity, Long> { + Optional<SelfExpiringTokenEntity> findByTokenAndStatus(String token, String status); +} diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/service/CollectionsService.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/service/CollectionsService.java new file mode 100644 index 0000000..dd91df9 --- /dev/null +++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/service/CollectionsService.java @@ -0,0 +1,46 @@ +/* + * 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.service; + +import org.apache.fineract.cn.deposit.api.v1.collection.domain.data.CollectionsResponse; +import org.apache.fineract.cn.deposit.service.ServiceConstants; +import org.apache.fineract.cn.deposit.service.internal.mapper.CollectionsMapper; +import org.apache.fineract.cn.deposit.service.internal.repository.CollectionsRepository; +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.stereotype.Service; + +@Service +public class CollectionsService { + private final Logger logger; + private final CollectionsRepository collectionsRepository; + + @Autowired + public CollectionsService(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger, + CollectionsRepository collectionsRepository) { + this.collectionsRepository = collectionsRepository; + this.logger = logger; + } + + public CollectionsResponse fetchCollection(String collectionReference){ + return CollectionsMapper.map(this.collectionsRepository.findByCollectionReference(collectionReference) + .orElseThrow(() -> ServiceException.notFound("collection {0} not found ", collectionReference))); + } +} diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/service/SelfExpiringTokenService.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/service/SelfExpiringTokenService.java new file mode 100644 index 0000000..dae344e --- /dev/null +++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/service/SelfExpiringTokenService.java @@ -0,0 +1,82 @@ +/* + * 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.service; + +import org.apache.fineract.cn.deposit.api.v1.collection.domain.data.TokenStatus; +import org.apache.fineract.cn.deposit.service.ServiceConstants; +import org.apache.fineract.cn.deposit.service.internal.repository.SelfExpiringTokenEntity; +import org.apache.fineract.cn.deposit.service.internal.repository.SelfExpiringTokenRepository; +import org.slf4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.security.SecureRandom; +import java.time.LocalDateTime; +import java.util.Random; + +@Service +public class SelfExpiringTokenService { + private final SelfExpiringTokenRepository selfExpiringTokenRepository; + private final Logger logger; + + @Value("${config.otpTokenLength}") + private Integer otpTokenLength; + + @Value("${config.tokenExpiryInSeconds}") + private Integer tokenExpiryInSeconds; + + @Autowired + public SelfExpiringTokenService(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger, + SelfExpiringTokenRepository selfExpiringTokenRepository) { + this.selfExpiringTokenRepository = selfExpiringTokenRepository; + this.logger = logger; + } + + public SelfExpiringTokenEntity generateAndSaveToken(String entityType, String entityReference, LocalDateTime currentTime){ + SelfExpiringTokenEntity entity = new SelfExpiringTokenEntity(); + entity.setToken(generateUniqueToken()); + + LocalDateTime tokenExpiresBy = currentTime.plusSeconds(tokenExpiryInSeconds); + entity.setCreatedTime(currentTime); + entity.setTokenExpiresBy(tokenExpiresBy); + entity.setStatus(TokenStatus.ACTIVE.name()); + entity.setEntityType(entityType); + entity.setEntityReference(entityReference); + this.selfExpiringTokenRepository.save(entity); + return entity; + } + + private String generateUniqueToken(){ + String token = generateRandomToken(otpTokenLength); + while(this.selfExpiringTokenRepository.findByTokenAndStatus(token, TokenStatus.ACTIVE.name()).isPresent()){ + token = generateRandomToken(otpTokenLength); + } + return token; + } + private String generateRandomToken(Integer length){ + final char[] buf = new char[length]; + final String alphanum = "0123456789" ; + final char[] symbols = alphanum.toCharArray(); + final Random random= new SecureRandom(); + for (int idx = 0; idx < buf.length; ++idx) + buf[idx] = symbols[random.nextInt(symbols.length)]; + return new String(buf); + } +} diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/rest/CollectionsRestController.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/rest/CollectionsRestController.java new file mode 100644 index 0000000..3c0b30b --- /dev/null +++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/rest/CollectionsRestController.java @@ -0,0 +1,104 @@ +/* + * 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.rest; + +import org.apache.fineract.cn.anubis.annotation.AcceptedTokenType; +import org.apache.fineract.cn.anubis.annotation.Permittable; +import org.apache.fineract.cn.command.domain.CommandCallback; +import org.apache.fineract.cn.command.gateway.CommandGateway; +import org.apache.fineract.cn.deposit.api.v1.PermittableGroupIds; +import org.apache.fineract.cn.deposit.api.v1.collection.domain.data.CollectionsRequest; +import org.apache.fineract.cn.deposit.api.v1.collection.domain.data.CollectionsResponse; +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.UpdateCollectionsCommand; +import org.apache.fineract.cn.deposit.service.internal.service.CollectionsService; +import org.slf4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/collection") +public class CollectionsRestController { + private final Logger logger; + private final CommandGateway commandGateway; + private final CollectionsService collectionsService; + + @Autowired + public CollectionsRestController(@Qualifier(ServiceConstants.LOGGER_NAME) Logger logger, + CommandGateway commandGateway, + CollectionsService collectionsService) { + this.logger = logger; + this.commandGateway = commandGateway; + this.collectionsService = collectionsService; + } + @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.INSTANCE_MANAGEMENT) + @RequestMapping( + value = "", + method = RequestMethod.POST, + consumes = MediaType.APPLICATION_JSON_VALUE, + produces = MediaType.APPLICATION_JSON_VALUE + ) + public + @ResponseBody + ResponseEntity<CollectionsResponse> saveCollection(@RequestBody CollectionsRequest requestData) + throws Throwable { + CommandCallback<CollectionsResponse> result = commandGateway.process(new CreateCollectionsCommand(requestData), + CollectionsResponse.class); + + return ResponseEntity.ok(result.get()); + } + + + @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.INSTANCE_MANAGEMENT) + @RequestMapping( + value = "/{collectionsReference}", + method = RequestMethod.PUT, + consumes = MediaType.APPLICATION_JSON_VALUE, + produces = MediaType.APPLICATION_JSON_VALUE + ) + public + @ResponseBody + ResponseEntity<CollectionsResponse> updateCollection(@PathVariable("collectionsReference") String collectionsReference, @RequestBody CollectionsRequest requestData) + throws Throwable { + CommandCallback<CollectionsResponse> result = commandGateway.process(new UpdateCollectionsCommand(collectionsReference, requestData), + CollectionsResponse.class); + return ResponseEntity.ok(result.get()); + } + + + @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.INSTANCE_MANAGEMENT) + @RequestMapping( + value = "/{collectionsReference}", + method = RequestMethod.GET, + consumes = MediaType.APPLICATION_JSON_VALUE, + produces = MediaType.APPLICATION_JSON_VALUE + ) + public + @ResponseBody + ResponseEntity<CollectionsResponse> getCollection(@PathVariable("collectionsReference") String collectionsReference) + throws Throwable { + CollectionsResponse result = collectionsService.fetchCollection(collectionsReference); + return ResponseEntity.ok(result); + } + + +} diff --git a/service/src/main/resources/application.yml b/service/src/main/resources/application.yml index 16e3bee..7a6ef48 100644 --- a/service/src/main/resources/application.yml +++ b/service/src/main/resources/application.yml @@ -23,6 +23,9 @@ spring: enabled: false config: enabled: false + jackson: + serialization: + write_dates_as_timestamps: false eureka: client: @@ -31,6 +34,7 @@ eureka: instance: homePageUrl: "http://${eureka.hostname}:2027/deposit/v1/" + server: port: 2027 contextPath: /deposit/v1 @@ -72,3 +76,7 @@ flyway: config: fixedAccountId: true + otpTokenLength: 6 + tokenExpiryInSeconds: 172800 + + diff --git a/service/src/main/resources/db/migrations/postgresql/V11__collections.sql b/service/src/main/resources/db/migrations/postgresql/V10__collections.sql similarity index 89% rename from service/src/main/resources/db/migrations/postgresql/V11__collections.sql rename to service/src/main/resources/db/migrations/postgresql/V10__collections.sql index 43f951d..87b7275 100644 --- a/service/src/main/resources/db/migrations/postgresql/V11__collections.sql +++ b/service/src/main/resources/db/migrations/postgresql/V10__collections.sql @@ -17,7 +17,6 @@ -- under the License. -- - CREATE TABLE shed_collections ( id bigserial NOT null, transaction_date TIMESTAMP NULL, @@ -25,17 +24,18 @@ CREATE TABLE shed_collections ( transport_fee_amount numeric(15,5) NULL, currency VARCHAR(10) NULL, remarks VARCHAR(1024) NULL, - account_identifier BIGINT NULL, - sub_txn_type_id BIGINT NULL, + account_identifier varchar(34) NULL, + sub_txn_type_id varchar(32) NULL, status VARCHAR(20) NOT NULL, c_reference VARCHAR(36) NOT NULL, + token BIGINT null, created_by VARCHAR(32) NOT NULL, created_on TIMESTAMP NOT NULL, last_modified_by VARCHAR(32) NULL, last_modified_on TIMESTAMP NULL, CONSTRAINT pk_shed_collections PRIMARY KEY (id), CONSTRAINT uk_shed_collections_ref UNIQUE (c_reference), - CONSTRAINT fk_collection_sub_txn_type_id FOREIGN KEY (sub_txn_type_id) REFERENCES shed_sub_tx_type (id), + CONSTRAINT fk_collection_sub_txn_type_id FOREIGN KEY (sub_txn_type_id) REFERENCES shed_sub_tx_type (identifier), CONSTRAINT fk_collection_account_identifier FOREIGN KEY (account_identifier) REFERENCES shed_product_instances (account_identifier) ); @@ -43,10 +43,12 @@ CREATE TABLE shed_collections ( CREATE TABLE shed_collections_inidividual ( id bigserial NOT NULL, collections_id BIGINT NOT NULL, - account_identifier BIGINT NULL, + account_identifier varchar(34) NULL, account_external_id VARCHAR(64) NULL, amount numeric(15,5) NOT NULL, i_reference VARCHAR(36) NOT NULL, + attendance VARCHAR(20) null, + token BIGINT null, CONSTRAINT pk_shed_collections_inidividual PRIMARY KEY (id), CONSTRAINT uk_shed_collections_inidividual_ref UNIQUE (i_reference), CONSTRAINT fk_indidual_collections FOREIGN KEY (collections_id) REFERENCES shed_collections (id), @@ -58,10 +60,11 @@ CREATE TABLE shed_collections_inidividual ( CREATE TABLE shed_self_expiring_tokens ( id bigserial NOT NULL, token VARCHAR(10) NOT NULL, + created_time TIMESTAMP NOT null, token_expires_by TIMESTAMP NOT NULL, status VARCHAR(10) NOT NULL, entity_type VARCHAR(36) NOT NULL, entity_reference VARCHAR(36) NOT NULL, CONSTRAINT pk_shed_self_expiring_tokens PRIMARY KEY (id), CONSTRAINT uk_shed_self_expiring_tokens_token UNIQUE (token, status) -); +); \ No newline at end of file diff --git a/service/src/main/resources/db/migrations/postgresql/V8__transaction.sql b/service/src/main/resources/db/migrations/postgresql/V8__transaction.sql index 8fba6c2..e21e267 100644 --- a/service/src/main/resources/db/migrations/postgresql/V8__transaction.sql +++ b/service/src/main/resources/db/migrations/postgresql/V8__transaction.sql @@ -24,6 +24,7 @@ CREATE TABLE shed_transactions ( routing_code VARCHAR(40) NULL, external_id VARCHAR(40) NULL, a_name VARCHAR(256) NULL, + a_type VARCHAR(32) NULL, description VARCHAR(1024) NULL, transaction_type VARCHAR(32) NOT NULL, sub_txn_type VARCHAR(32) NULL, @@ -35,6 +36,7 @@ CREATE TABLE shed_transactions ( nostro_account_identifier VARCHAR(32) NULL, transaction_date TIMESTAMP NULL, expiration_date TIMESTAMP NULL, + parent_txn_id BIGINT NULL, created_by VARCHAR(32) NULL, created_on TIMESTAMP NULL, last_modified_by VARCHAR(32) NULL, @@ -42,5 +44,6 @@ CREATE TABLE shed_transactions ( CONSTRAINT pk_shed_transactions PRIMARY KEY (id), CONSTRAINT uk_shed_transactions_id UNIQUE (identifier), CONSTRAINT shed_txn_sub_txn_type_fk FOREIGN KEY (sub_txn_type) REFERENCES shed_sub_tx_type (identifier), - CONSTRAINT shed_txn_prod_instance_fk FOREIGN KEY (account_identifier) REFERENCES shed_product_instances (account_identifier) + CONSTRAINT shed_txn_prod_instance_fk FOREIGN KEY (account_identifier) REFERENCES shed_product_instances (account_identifier), + CONSTRAINT shed_txn_to_txn_fk FOREIGN KEY (parent_txn_id) REFERENCES shed_transactions (id) ); diff --git a/service/src/main/resources/db/migrations/postgresql/V10__ibb_conf_to_sub_txn.sql b/service/src/main/resources/db/migrations/postgresql/V9__ibb_conf_to_sub_txn.sql similarity index 90% rename from service/src/main/resources/db/migrations/postgresql/V10__ibb_conf_to_sub_txn.sql rename to service/src/main/resources/db/migrations/postgresql/V9__ibb_conf_to_sub_txn.sql index 1abb9af..6b3ce8a 100644 --- a/service/src/main/resources/db/migrations/postgresql/V10__ibb_conf_to_sub_txn.sql +++ b/service/src/main/resources/db/migrations/postgresql/V9__ibb_conf_to_sub_txn.sql @@ -18,7 +18,7 @@ -- ALTER TABLE shed_sub_tx_type -ADD COLUMN ibb_conf_plus_days INT 0; +ADD COLUMN ibb_conf_plus_days INT default 0; ALTER TABLE shed_sub_tx_type -ADD COLUMN ibb_conf_minus_days INT 0; +ADD COLUMN ibb_conf_minus_days INT default 0; diff --git a/service/src/main/resources/db/migrations/postgresql/V9__transaction_update.sql b/service/src/main/resources/db/migrations/postgresql/V9__transaction_update.sql deleted file mode 100644 index 07bfe2e..0000000 --- a/service/src/main/resources/db/migrations/postgresql/V9__transaction_update.sql +++ /dev/null @@ -1,30 +0,0 @@ -<<<<<<< HEAD --- --- 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. --- - -ALTER TABLE shed_transactions -ADD COLUMN a_type varchar(32) NULL; - -ALTER TABLE shed_transactions -ADD COLUMN parent_txn_id bigint NULL; - -ALTER TABLE shed_transactions -ADD CONSTRAINT shed_txn_to_txn_fk -FOREIGN KEY (parent_txn_id) -REFERENCES shed_transactions (id);