Merge pull request #25 from fynmanoj/collections-api

AL-54-Collections api
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 @@
             [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 @@
       enabled: false
     config:
       enabled: false
+  jackson:
+    serialization:
+      write_dates_as_timestamps: false
 
 eureka:
   client:
@@ -31,6 +34,7 @@
   instance:
     homePageUrl: "http://${eureka.hostname}:2027/deposit/v1/"
 
+
 server:
   port: 2027
   contextPath: /deposit/v1
@@ -72,3 +76,7 @@
 
 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 @@
   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_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_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 @@
   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 @@
   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 @@
   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);