Merge pull request #21 from fynmanoj/statement-api
Statement-API
diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/EventConstants.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/EventConstants.java
index 8f8a101..1f70ac1 100644
--- a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/EventConstants.java
+++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/EventConstants.java
@@ -50,6 +50,9 @@
String PUT_PRODUCT_INSTANCE = "put-product-instance";
String SELECTOR_PUT_PRODUCT_INSTANCE = SELECTOR_NAME + " = '" + PUT_PRODUCT_INSTANCE + "'";
+ String POST_SUB_TXN_TYPE = "post-sub-txn-type";
+ String PUT_SUB_TXN_TYPE = "put-sub-txn-type";
+
String ACTIVATE_PRODUCT_INSTANCE_COMMAND = "ACTIVATE";
String CLOSE_PRODUCT_INSTANCE_COMMAND = "CLOSE";
String PRODUCT_INSTANCE_TRANSACTION = "TRANSACTION";
diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/instance/domain/SubTransactionType.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/instance/domain/SubTransactionType.java
new file mode 100644
index 0000000..4bb6d4b
--- /dev/null
+++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/instance/domain/SubTransactionType.java
@@ -0,0 +1,105 @@
+/*
+ * 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.instance.domain;
+
+import org.hibernate.validator.constraints.NotBlank;
+
+import javax.validation.constraints.NotNull;
+
+public class SubTransactionType {
+ @NotBlank
+ private String identifier;
+ @NotBlank
+ private String name;
+ private String description;
+ @NotNull
+ private Boolean cashPayment;
+ @NotNull
+ private Boolean active;
+ private Integer orderPosition;
+ private Integer tranType;
+ private String ledgerAccount;
+
+ public SubTransactionType() {
+ }
+
+ public String getIdentifier() {
+ return identifier;
+ }
+
+ public void setIdentifier(String identifier) {
+ this.identifier = identifier;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public Boolean getCashPayment() {
+ return cashPayment;
+ }
+
+ public void setCashPayment(Boolean cashPayment) {
+ this.cashPayment = cashPayment;
+ }
+
+ public Boolean getActive() {
+ return active;
+ }
+
+ public void setActive(Boolean active) {
+ this.active = active;
+ }
+
+ public Integer getOrderPosition() {
+ return orderPosition;
+ }
+
+ public void setOrderPosition(Integer orderPosition) {
+ this.orderPosition = orderPosition;
+ }
+
+ public Integer getTranType() {
+ return tranType;
+ }
+
+ public void setTranType(Integer tranType) {
+ this.tranType = tranType;
+ }
+
+ public String getLedgerAccount() {
+ return ledgerAccount;
+ }
+
+ public void setLedgerAccount(String ledgerAccount) {
+ this.ledgerAccount = ledgerAccount;
+ }
+}
diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/ActionState.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/ActionState.java
new file mode 100644
index 0000000..3a8ab82
--- /dev/null
+++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/ActionState.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.transaction.domain.data;
+
+public enum ActionState {
+ ACCEPTED,
+ REJECTED
+}
diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/ExtensionData.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/ExtensionData.java
new file mode 100644
index 0000000..746e5e4
--- /dev/null
+++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/ExtensionData.java
@@ -0,0 +1,58 @@
+/*
+ * 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.transaction.domain.data;
+
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.NotNull;
+
+public class ExtensionData {
+
+ @NotNull
+ @Length(min = 1, max = 128)
+ private String key;
+
+ @NotNull
+ @Length(min = 1, max = 128)
+ private String value;
+
+ public ExtensionData() {
+ }
+
+ public ExtensionData(@NotNull String key, @NotNull String value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ protected void setKey(String key) {
+ this.key = key;
+ }
+
+ protected void setValue(String value) {
+ this.value = value;
+ }
+}
diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/GeoCodeData.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/GeoCodeData.java
new file mode 100644
index 0000000..e165489
--- /dev/null
+++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/GeoCodeData.java
@@ -0,0 +1,57 @@
+/*
+ * 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.transaction.domain.data;
+
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+
+public class GeoCodeData {
+
+ @NotNull
+ @Pattern(regexp = "^(\\+|-)?(?:90(?:(?:\\.0{1,6})?)|(?:[0-9]|[1-8][0-9])(?:(?:\\.[0-9]{1,6})?))$")
+ private String latitude;
+
+ @NotNull
+ @Pattern(regexp = "^(\\+|-)?(?:180(?:(?:\\.0{1,6})?)|(?:[0-9]|[1-9][0-9]|1[0-7][0-9])(?:(?:\\.[0-9]{1,6})?))$")
+ private String longitude;
+
+ public GeoCodeData() {
+ }
+
+ public GeoCodeData(String latitude, String longitude) {
+ this.latitude = latitude;
+ this.longitude = longitude;
+ }
+
+ public String getLatitude() {
+ return latitude;
+ }
+
+ public String getLongitude() {
+ return longitude;
+ }
+
+ public void setLatitude(String latitude) {
+ this.latitude = latitude;
+ }
+
+ public void setLongitude(String longitude) {
+ this.longitude = longitude;
+ }
+}
diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/MoneyData.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/MoneyData.java
new file mode 100644
index 0000000..96a1625
--- /dev/null
+++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/MoneyData.java
@@ -0,0 +1,78 @@
+/*
+ * 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.transaction.domain.data;
+
+import org.apache.fineract.cn.deposit.api.v1.definition.domain.Currency;
+import org.apache.fineract.cn.deposit.api.v1.transaction.utils.MathUtil;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.Digits;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+
+public class MoneyData {
+
+ @NotNull
+ @Min(0)
+ @Digits(integer = 15, fraction = 4) // interoperation schema allows integer = 18, AccountEntity amount allows fraction = 5
+ private BigDecimal amount;
+
+ @NotNull
+ @Length(min = 3, max = 3)
+ private String currency;
+
+ public MoneyData() {
+ }
+
+ public MoneyData(BigDecimal amount, String currency) {
+ this.amount = amount;
+ this.currency = currency;
+ }
+
+ public static MoneyData build(BigDecimal amount, String currency) {
+ return amount == null ? null : new MoneyData(amount, currency);
+ }
+
+ public static MoneyData build(BigDecimal amount, Currency currency) {
+ return amount == null ? null : build(amount, currency.getCode());
+ }
+
+ public BigDecimal getAmount() {
+ return amount;
+ }
+
+ public String getCurrency() {
+ return currency;
+ }
+
+ public void normalizeAmount(@NotNull Currency currency) {
+ if (!currency.getCode().equals(this.currency))
+ throw new UnsupportedOperationException("Internal error: Invalid currency " + currency.getCode());
+ MathUtil.normalize(amount, currency);
+ }
+
+ public void setAmount(BigDecimal amount) {
+ this.amount = amount;
+ }
+
+ public void setCurrency(String currency) {
+ this.currency = currency;
+ }
+}
diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/StatementResponse.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/StatementResponse.java
new file mode 100644
index 0000000..c6fc79e
--- /dev/null
+++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/StatementResponse.java
@@ -0,0 +1,90 @@
+/*
+ * 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.transaction.domain.data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+public class StatementResponse {
+ private String transactionCode;
+ private String tranType;
+ private BigDecimal amount;
+ private LocalDateTime transactionDate;
+ private String subTxnType;
+ private String type;
+ private String description;
+
+ public StatementResponse() {
+ }
+
+ public String getTransactionCode() {
+ return transactionCode;
+ }
+
+ public void setTransactionCode(String transactionCode) {
+ this.transactionCode = transactionCode;
+ }
+
+ public String getTranType() {
+ return tranType;
+ }
+
+ public void setTranType(String tranType) {
+ this.tranType = tranType;
+ }
+
+ public BigDecimal getAmount() {
+ return amount;
+ }
+
+ public void setAmount(BigDecimal amount) {
+ this.amount = amount;
+ }
+
+ public LocalDateTime getTransactionDate() {
+ return transactionDate;
+ }
+
+ public void setTransactionDate(LocalDateTime transactionDate) {
+ this.transactionDate = transactionDate;
+ }
+
+ public String getSubTxnType() {
+ return subTxnType;
+ }
+
+ public void setSubTxnType(String subTxnType) {
+ this.subTxnType = subTxnType;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+}
diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/TransactionActionType.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/TransactionActionType.java
new file mode 100644
index 0000000..efa253d
--- /dev/null
+++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/TransactionActionType.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.api.v1.transaction.domain.data;
+
+public enum TransactionActionType {
+
+ WITHDRAWAL,
+ DEPOSIT,
+ ;
+}
diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/TransactionRequestData.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/TransactionRequestData.java
new file mode 100644
index 0000000..deb16ae
--- /dev/null
+++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/TransactionRequestData.java
@@ -0,0 +1,154 @@
+/*
+ * 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.transaction.domain.data;
+
+import org.apache.fineract.cn.deposit.api.v1.definition.domain.Currency;
+import org.hibernate.validator.constraints.Length;
+import org.hibernate.validator.constraints.NotEmpty;
+
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+import java.beans.Transient;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+public class TransactionRequestData {
+
+ public static final String IDENTIFIER_SEPARATOR = "_";
+
+ @NotNull
+ //@Pattern(regexp = "^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$")
+ private String transactionCode;
+
+ //@Pattern(regexp = "^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$")
+ private String requestCode;
+
+ private String routingCode;
+ private String externalId;
+
+ @NotEmpty
+ @Length(max = 32)
+ private String accountId;
+
+ @Length(max = 128)
+ private String note;
+
+ private LocalDateTime expiration;
+
+ private MoneyData amount;
+ //private GeoCodeData geoCode;
+
+ private String subTxnId;
+
+ public TransactionRequestData() {
+ }
+
+ public TransactionRequestData(String transactionCode, String requestCode, String routingCode, String externalId, String accountId,
+ String note, LocalDateTime expiration,
+ MoneyData amount, String subTxnId) {
+ this.transactionCode = transactionCode;
+ this.requestCode = requestCode;
+ this.routingCode = routingCode;
+ this.externalId = externalId;
+ this.accountId = accountId;
+ this.note = note;
+ this.expiration = expiration;
+ this.amount = amount;
+ //this.geoCode = geoCode;
+ this.subTxnId = subTxnId;
+ }
+
+ @NotNull
+ public String getTransactionCode() {
+ return transactionCode;
+ }
+
+ public String getRequestCode() {
+ return requestCode;
+ }
+
+ @NotNull
+ public String getAccountId() {
+ return accountId;
+ }
+
+ @NotNull
+ public MoneyData getAmount() {
+ return amount;
+ }
+
+ public String getNote() {
+ return note;
+ }
+
+ public void setNote(String note) {
+ this.note = note;
+ }
+
+ public LocalDateTime getExpiration() {
+ return expiration;
+ }
+
+ public LocalDate getExpirationLocalDate() {
+ return expiration == null ? null : expiration.toLocalDate();
+ }
+
+ public void setExpiration(LocalDateTime expiration) {
+ this.expiration = expiration;
+ }
+
+ public void normalizeAmounts(@NotNull Currency currency) {
+ amount.normalizeAmount(currency);
+ }
+
+ protected void setTransactionCode(String transactionCode) {
+ this.transactionCode = transactionCode;
+ }
+
+ protected void setRequestCode(String requestCode) {
+ this.requestCode = requestCode;
+ }
+
+ protected void setAccountId(String accountId) {
+ this.accountId = accountId;
+ }
+
+ protected void setAmount(MoneyData amount) {
+ this.amount = amount;
+ }
+
+ public String getRoutingCode() {
+ return routingCode;
+ }
+
+ public String getExternalId() {
+ return externalId;
+ }
+
+ public String getSubTxnId() {
+ return subTxnId;
+ }
+
+ @Transient
+ @NotNull
+ public String getIdentifier() {
+ return transactionCode;
+ }
+
+}
diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/TransactionResponseData.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/TransactionResponseData.java
new file mode 100644
index 0000000..237e627
--- /dev/null
+++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/TransactionResponseData.java
@@ -0,0 +1,90 @@
+/*
+ * 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.transaction.domain.data;
+
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+public class TransactionResponseData {
+
+
+ @NotNull
+ private final String transactionCode;
+
+ private final String routingCode;
+ private final String externalId;
+
+ @NotNull
+ private final ActionState state;
+
+ private final String expiration;
+
+
+
+ private String completedTimestamp;
+
+
+ @NotNull
+ @Pattern(regexp = "^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$")
+ private final String requestCode;
+
+ public TransactionResponseData(String transactionCode, String routingCode, String externalId,
+ ActionState state, String expiration,
+ String requestCode,
+ String completedTimestamp) {
+ this.transactionCode = transactionCode;
+ this.routingCode = routingCode;
+ this.externalId = externalId;
+ this.state = state;
+ this.expiration = expiration;
+ this.requestCode = requestCode;
+ this.completedTimestamp =completedTimestamp;
+ }
+
+ public String getTransactionCode() {
+ return transactionCode;
+ }
+
+ public ActionState getState() {
+ return state;
+ }
+
+ public String getExpiration() {
+ return expiration;
+ }
+
+ public String getRequestCode() {
+ return requestCode;
+ }
+
+ public static TransactionResponseData build(String routingCode, String externalId, @NotNull String requestCode,
+ @NotNull ActionState state,
+ LocalDateTime expiration,
+ @NotNull String txnIdentifier, LocalDateTime completedTimestamp) {
+ return new TransactionResponseData(txnIdentifier, routingCode, externalId, state, format(expiration), requestCode,
+ format(completedTimestamp));
+ }
+
+
+ protected static String format(LocalDateTime date) {
+ return date == null ? null : date.format(DateTimeFormatter.ISO_DATE_TIME);
+ }
+}
diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/TransactionTypeEnum.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/TransactionTypeEnum.java
new file mode 100644
index 0000000..19ef964
--- /dev/null
+++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/TransactionTypeEnum.java
@@ -0,0 +1,106 @@
+/*
+ * 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.transaction.domain.data;
+
+/**
+ * @code org.apache.fineract.cn.accounting.service.internal.repository.AccountEntryEntity.type
+ */
+public enum TransactionTypeEnum {
+
+ ACCOUNT_OPENING("ACCO"),
+ ACCOUNT_CLOSING("ACCC"),
+ ACCOUNT_TRANSFER("ACCT"),
+
+ ACH_CREDIT("ACDT"),
+ ACH_DEBIT("ADBT"),
+ ACH_ADJUSTMENTS("ADJT"),
+ ACH_PREAUTHORISED("APAC"),
+ ACH_RETURN("ARET"),
+ ACH_REVERSAL("AREV"),
+ ACH_SETTLEMENT("ASET"),
+ ACH_TRANSACTION("ATXN"),
+
+ ARP_DEBIT("ARPD"),
+ CURRENCY_DEPOSIT("FCDP"),
+ CURRENCY_WITHDRAWAL("FCWD"),
+
+ BRANCH_TRANSFER("BACT"),
+ BRANCH_DEPOSIT("BCDP"),
+ BRANCH_WITHDRAWAL("BCWD"),
+
+ DEPOSIT("CDPT"),
+ WITHDRAWAL("CWDL"),
+ CASH_LETTER("CASH"),
+
+ CHEQUE("CCHQ"),
+ BRANCH_CHEQUE("BCHQ"),
+ CERTIFIED_CHEQUE("CCCH"),
+ CROSSED_CHEQUE("CRCQ"),
+ CHEQUE_REVERSAL("CQRV"),
+ CHEQUE_OPEN("OPCQ"),
+ CHEQUE_ORDER("ORCQ"),
+
+ CHARGES_PAYMENT("CHRG"),
+ FEES_PAYMENT("FEES"),
+ TAXES_PAYMENT("TAXE"),
+ PRINCIPAL_PAYMENT("PPAY"),
+ INTEREST_PAYMENT("INTR"),
+
+ DIRECTDEBIT_PAYMENT("PMDD"),
+ DIRECTDEBIT_PREAUTHORISED("PADD"),
+ BRANCH_DIRECTDEBIT("BBDD"),
+
+ SMARTCARD_PAYMENT("SMRT"),
+ POINTOFSALE_CREDITCARD("POSC"),
+ POINTOFSALE_DEBITCARD("POSD"),
+ POINTOFSALE_PAYMENT("POSP"),
+
+ DOMESTIC_CREDIT("DMCT"),
+ INTRACOMPANY_TRANSFER("ICCT"),
+
+ MIXED_DEPOSIT("MIXD"),
+ MISCELLANEOUS_DEPOSIT("MSCD"),
+ OTHER("OTHR"),
+
+ CONTROLLED_DISBURSEMENT("CDIS"),
+ CONTROLLED_DISBURSEMENT2("DSBR"),
+ CREDIT_ADJUSTMENT("CAJT"),
+ DEBIT_ADJUSTMENT("DAJT"),
+ EXCHANGERATE_ADJUSTMENT("ERTA"),
+ YID_ADJUSTMENT("YTDA"),
+ REIMBURSEMENT("RIMB"),
+ DRAWDOWN("DDWN"),
+
+ ERROR_NOTAVAILABLE("NTAV"),
+ ERROR_POSTING("PSTE"),
+ ERROR_CANCELLATION("RCDD"),
+ ERROR_CANCELLATION2("RPCR"),
+ ERROR_ZEROBALANCE("ZABA"),
+ ;
+
+ private final String code;
+
+ TransactionTypeEnum(String code) {
+ this.code = code;
+ }
+
+ public String getCode() {
+ return code;
+ }
+}
diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/utils/MathUtil.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/utils/MathUtil.java
new file mode 100644
index 0000000..ae43db6
--- /dev/null
+++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/utils/MathUtil.java
@@ -0,0 +1,325 @@
+/*
+ * 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.transaction.utils;
+
+import org.apache.fineract.cn.deposit.api.v1.definition.domain.Currency;
+
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.math.MathContext;
+import java.math.RoundingMode;
+
+public class MathUtil {
+
+ public static final MathContext DEFAULT_MATH_CONTEXT = new MathContext(2, RoundingMode.HALF_EVEN);
+ public static final MathContext CALCULATION_MATH_CONTEXT = new MathContext(5, RoundingMode.HALF_EVEN);
+
+ public static Double nullToZero(Double value) {
+ return nullToDefault(value, 0D);
+ }
+
+ public static Double nullToDefault(Double value, Double def) {
+ return value == null ? def : value;
+ }
+
+ public static Double zeroToNull(Double value) {
+ return isEmpty(value) ? null : value;
+ }
+
+ /** @return parameter value or ZERO if it is negative */
+ public static Double negativeToZero(Double value) {
+ return isGreaterThanZero(value) ? value : 0D;
+ }
+
+ public static boolean isEmpty(Double value) {
+ return value == null || value.equals(0D);
+ }
+
+ public static boolean isGreaterThanZero(Double value) {
+ return value != null && value > 0D;
+ }
+
+ public static boolean isLessThanZero(Double value) {
+ return value != null && value < 0D;
+ }
+
+ public static boolean isZero(Double value) {
+ return value != null && value.equals(0D);
+ }
+
+ public static boolean isEqualTo(Double first, Double second) {
+ return nullToZero(first).equals(nullToZero(second));
+ }
+
+ public static boolean isGreaterThan(Double first, Double second) {
+ return nullToZero(first) > nullToZero(second);
+ }
+
+ public static boolean isLessThan(Double first, Double second) {
+ return nullToZero(first) < nullToZero(second);
+ }
+
+ public static boolean isGreaterThanOrEqualTo(Double first, Double second) {
+ return nullToZero(first) >= nullToZero(second);
+ }
+
+ public static boolean isLessThanOrEqualZero(Double value) {
+ return nullToZero(value) <= 0D;
+ }
+
+ /** @return parameter value or negated value to positive */
+ public static Double abs(Double value) {
+ return value == null ? 0D : Math.abs(value);
+ }
+
+ /** @return calculates minimum of the two values considering null values
+ * @param notNull if true then null parameter is omitted, otherwise returns null */
+ public static Double min(Double first, Double second, boolean notNull) {
+ return first == null
+ ? (notNull ? second : null)
+ : second == null ? (notNull ? first : null) : Math.min(first, second);
+ }
+
+ /** @return calculates minimum of the values considering null values
+ * @param notNull if true then null parameter is omitted, otherwise returns null */
+ public static Double min(Double first, Double second, Double third, boolean notNull) {
+ return min(min(first, second, notNull), third, notNull);
+ }
+
+ /** @return sum the two values considering null values */
+ public static Double add(Double first, Double second) {
+ return first == null
+ ? second
+ : second == null ? first : first + second;
+ }
+
+ /** @return sum the values considering null values */
+ public static Double add(Double first, Double second, Double third) {
+ return add(add(first, second), third);
+ }
+
+ /** @return sum the values considering null values */
+ public static Double add(Double first, Double second, Double third, Double fourth) {
+ return add(add(add(first, second), third), fourth);
+ }
+
+ /** @return sum the values considering null values */
+ public static Double add(Double first, Double second, Double third, Double fourth, Double fifth) {
+ return add(add(add(add(first, second), third), fourth), fifth);
+ }
+
+ /** @return first minus second considering null values, maybe negative */
+ public static Double subtract(Double first, Double second) {
+ return first == null
+ ? null
+ : second == null ? first : first - second;
+ }
+
+ /** @return first minus the others considering null values, maybe negative */
+ public static Double subtractToZero(Double first, Double second, Double third) {
+ return subtractToZero(subtract(first, second), third);
+ }
+
+ /** @return first minus the others considering null values, maybe negative */
+ public static Double subtractToZero(Double first, Double second, Double third, Double fourth) {
+ return subtractToZero(subtract(subtract(first, second), third), fourth);
+ }
+
+ /** @return NONE negative first minus second considering null values */
+ public static Double subtractToZero(Double first, Double second) {
+ return negativeToZero(subtract(first, second));
+ }
+
+ /** @return BigDecimal with scale set to the 'digitsAfterDecimal' of the parameter currency */
+ public static Double normalize(Double amount, @NotNull Currency currency) {
+ return amount == null ? null : normalize(BigDecimal.valueOf(amount), currency).doubleValue();
+ }
+
+ /** @return BigDecimal with scale set to the 'digitsAfterDecimal' of the parameter currency */
+ public static Double normalize(Double amount, @NotNull MathContext mc) {
+ return amount == null ? null : normalize(BigDecimal.valueOf(amount), mc).doubleValue();
+ }
+
+ /** @return BigDecimal null safe negate */
+ public static Double negate(Double amount) {
+ return isEmpty(amount) ? amount : amount * -1;
+ }
+
+
+ // ----------------- BigDecimal -----------------
+
+ public static BigDecimal nullToZero(BigDecimal value) {
+ return nullToDefault(value, BigDecimal.ZERO);
+ }
+
+ public static BigDecimal nullToDefault(BigDecimal value, BigDecimal def) {
+ return value == null ? def : value;
+ }
+
+ public static BigDecimal zeroToNull(BigDecimal value) {
+ return isEmpty(value) ? null : value;
+ }
+
+ /** @return parameter value or ZERO if it is negative */
+ public static BigDecimal negativeToZero(BigDecimal value) {
+ return isGreaterThanZero(value) ? value : BigDecimal.ZERO;
+ }
+
+ public static boolean isEmpty(BigDecimal value) {
+ return value == null || BigDecimal.ZERO.compareTo(value) == 0;
+ }
+
+ public static boolean isGreaterThanZero(BigDecimal value) {
+ return value != null && value.compareTo(BigDecimal.ZERO) > 0;
+ }
+
+ public static boolean isLessThanZero(BigDecimal value) {
+ return value != null && value.compareTo(BigDecimal.ZERO) < 0;
+ }
+
+ public static boolean isZero(BigDecimal value) {
+ return value != null && value.compareTo(BigDecimal.ZERO) == 0;
+ }
+
+ public static boolean isEqualTo(BigDecimal first, BigDecimal second) {
+ return nullToZero(first).compareTo(nullToZero(second)) == 0;
+ }
+
+ public static boolean isGreaterThan(BigDecimal first, BigDecimal second) {
+ return nullToZero(first).compareTo(nullToZero(second)) > 0;
+ }
+
+ public static boolean isLessThan(BigDecimal first, BigDecimal second) {
+ return nullToZero(first).compareTo(nullToZero(second)) < 0;
+ }
+
+ public static boolean isGreaterThanOrEqualTo(BigDecimal first, BigDecimal second) {
+ return nullToZero(first).compareTo(nullToZero(second)) >= 0;
+ }
+
+ public static boolean isLessThanOrEqualZero(BigDecimal value) {
+ return nullToZero(value).compareTo(BigDecimal.ZERO) <= 0;
+ }
+
+ /** @return parameter value or negated value to positive */
+ public static BigDecimal abs(BigDecimal value) {
+ return value == null ? BigDecimal.ZERO : value.abs();
+ }
+
+ /** @return calculates minimum of the two values considering null values
+ * @param notNull if true then null parameter is omitted, otherwise returns null */
+ public static BigDecimal min(BigDecimal first, BigDecimal second, boolean notNull) {
+ return notNull
+ ? first == null
+ ? second
+ : second == null ? first : min(first, second, false)
+ : isLessThan(first, second) ? first : second;
+ }
+
+ /** @return calculates minimum of the values considering null values
+ * @param notNull if true then null parameter is omitted, otherwise returns null */
+ public static BigDecimal min(BigDecimal first, BigDecimal second, BigDecimal third, boolean notNull) {
+ return min(min(first, second, notNull), third, notNull);
+ }
+
+ /** @return sum the two values considering null values */
+ public static BigDecimal add(BigDecimal first, BigDecimal second) {
+ return add(first, second, CALCULATION_MATH_CONTEXT);
+ }
+
+ /** @return sum the two values considering null values */
+ public static BigDecimal add(BigDecimal first, BigDecimal second, MathContext mc) {
+ return first == null
+ ? second
+ : second == null ? first : first.add(second, mc);
+ }
+
+ /** @return sum the values considering null values */
+ public static BigDecimal add(BigDecimal first, BigDecimal second, BigDecimal third) {
+ return add(first, second, third, CALCULATION_MATH_CONTEXT);
+ }
+
+ /** @return sum the values considering null values */
+ public static BigDecimal add(BigDecimal first, BigDecimal second, BigDecimal third, MathContext mc) {
+ return add(add(first, second, mc), third, mc);
+ }
+
+ /** @return sum the values considering null values */
+ public static BigDecimal add(BigDecimal first, BigDecimal second, BigDecimal third, BigDecimal fourth) {
+ return add(first, second, third, fourth, CALCULATION_MATH_CONTEXT);
+ }
+
+ /** @return sum the values considering null values */
+ public static BigDecimal add(BigDecimal first, BigDecimal second, BigDecimal third, BigDecimal fourth, MathContext mc) {
+ return add(add(add(first, second, mc), third, mc), fourth, mc);
+ }
+
+ /** @return sum the values considering null values */
+ public static BigDecimal add(BigDecimal first, BigDecimal second, BigDecimal third, BigDecimal fourth, BigDecimal fifth) {
+ return add(first, second, third, fourth, fifth, CALCULATION_MATH_CONTEXT);
+ }
+
+ /** @return sum the values considering null values */
+ public static BigDecimal add(BigDecimal first, BigDecimal second, BigDecimal third, BigDecimal fourth, BigDecimal fifth, MathContext mc) {
+ return add(add(add(add(first, second, mc), third, mc), fourth, mc), fifth, mc);
+ }
+
+ /** @return first minus second considering null values, maybe negative */
+ public static BigDecimal subtract(BigDecimal first, BigDecimal second) {
+ return first == null
+ ? null
+ : second == null ? first : first.subtract(second, CALCULATION_MATH_CONTEXT);
+ }
+
+ /** @return NONE negative first minus second considering null values */
+ public static BigDecimal subtractToZero(BigDecimal first, BigDecimal second) {
+ return negativeToZero(subtract(first, second));
+ }
+
+ /** @return first minus the others considering null values, maybe negative */
+ public static BigDecimal subtractToZero(BigDecimal first, BigDecimal second, BigDecimal third) {
+ MathContext mc = CALCULATION_MATH_CONTEXT;
+ return subtractToZero(subtract(first, second), third);
+ }
+
+ /** @return first minus the others considering null values, maybe negative */
+ public static BigDecimal subtractToZero(BigDecimal first, BigDecimal second, BigDecimal third, BigDecimal fourth) {
+ return subtractToZero(subtract(subtract(first, second), third), fourth);
+ }
+
+ /** @return BigDecimal with scale set to the 'digitsAfterDecimal' of the parameter currency */
+ public static BigDecimal normalize(BigDecimal amount, @NotNull Currency currency) {
+ return amount == null ? null : amount.setScale(currency.getScale(), CALCULATION_MATH_CONTEXT.getRoundingMode());
+ }
+
+ /** @return BigDecimal with scale set to the 'digitsAfterDecimal' of the parameter currency */
+ public static BigDecimal normalize(BigDecimal amount, @NotNull MathContext mc) {
+ return amount == null ? null : amount.setScale(mc.getPrecision(), mc.getRoundingMode());
+ }
+
+ /** @return BigDecimal null safe negate */
+ public static BigDecimal negate(BigDecimal amount) {
+ return negate(amount, CALCULATION_MATH_CONTEXT);
+ }
+
+ /** @return BigDecimal null safe negate */
+ public static BigDecimal negate(BigDecimal amount, MathContext mc) {
+ return isEmpty(amount) ? amount : amount.negate(mc);
+ }
+}
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/CreateSubTxnTypeCommand.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/CreateSubTxnTypeCommand.java
new file mode 100644
index 0000000..394d0ee
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/CreateSubTxnTypeCommand.java
@@ -0,0 +1,34 @@
+/*
+ * 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.instance.domain.SubTransactionType;
+
+public class CreateSubTxnTypeCommand {
+ private final SubTransactionType subTransactionType;
+
+ public CreateSubTxnTypeCommand(final SubTransactionType subTransactionType) {
+ super();
+ this.subTransactionType = subTransactionType;
+ }
+
+ public SubTransactionType subTransactionType() {
+ return subTransactionType;
+ }
+}
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/TransactionCommand.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/TransactionCommand.java
new file mode 100644
index 0000000..631fb55
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/TransactionCommand.java
@@ -0,0 +1,40 @@
+/*
+ * 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.transaction.domain.data.TransactionActionType;
+import org.apache.fineract.cn.deposit.api.v1.transaction.domain.data.TransactionRequestData;
+
+public class TransactionCommand {
+ private final TransactionRequestData transactionRequest;
+ private final TransactionActionType action;
+
+ public TransactionCommand(TransactionRequestData transactionRequest, TransactionActionType action) {
+ this.transactionRequest = transactionRequest;
+ this.action = action;
+ }
+
+ public TransactionRequestData getTransactionRequest() {
+ return transactionRequest;
+ }
+
+ public TransactionActionType getAction() {
+ return action;
+ }
+}
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/UpdateSubTxnTypeCommand.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/UpdateSubTxnTypeCommand.java
new file mode 100644
index 0000000..8e1e18b
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/UpdateSubTxnTypeCommand.java
@@ -0,0 +1,34 @@
+/*
+ * 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.instance.domain.SubTransactionType;
+
+public class UpdateSubTxnTypeCommand {
+ private final SubTransactionType subTransactionType;
+
+ public UpdateSubTxnTypeCommand(final SubTransactionType subTransactionType) {
+ super();
+ this.subTransactionType = subTransactionType;
+ }
+
+ public SubTransactionType subTransactionType() {
+ return this.subTransactionType;
+ }
+}
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/InterestCalculator.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/InterestCalculator.java
index 79dcc60..7d2a71a 100644
--- a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/InterestCalculator.java
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/InterestCalculator.java
@@ -457,7 +457,7 @@
final BigDecimal annualInterest = amount.multiply(baseFactor.pow(periods).subtract(BigDecimal.ONE));
return annualInterest
- .divide(BigDecimal.valueOf(lengthOfYear),
+ .divide( BigDecimal.valueOf(lengthOfYear),
amount.scale() + INTEREST_PRECISION, BigDecimal.ROUND_HALF_EVEN);
}
}
\ No newline at end of file
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/ProductInstanceAggregate.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/ProductInstanceAggregate.java
index 0ea7f07..15b7aae 100644
--- a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/ProductInstanceAggregate.java
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/ProductInstanceAggregate.java
@@ -50,6 +50,7 @@
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.transaction.annotation.Transactional;
@Aggregate
@@ -60,6 +61,9 @@
private final ProductDefinitionRepository productDefinitionRepository;
private final AccountingService accountingService;
+ @Value("${config.fixedAccountId}")
+ private Boolean fixedAccountId;
+
@Autowired
public ProductInstanceAggregate(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
final ProductInstanceRepository productInstanceRepository,
@@ -89,7 +93,7 @@
this.productInstanceRepository.findByCustomerIdentifier(productInstance.getCustomerIdentifier());
final int accountSuffix = currentProductInstances.size() + 1;
- final String accountNumber =
+ final String accountNumber = fixedAccountId ? productInstance.getCustomerIdentifier() :
productInstance.getCustomerIdentifier() +
"." + productDefinitionEntity.getEquityLedgerIdentifier() +
"." + String.format("%05d", accountSuffix);
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/SubTxnTypeAggrigate.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/SubTxnTypeAggrigate.java
new file mode 100644
index 0000000..b56c690
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/SubTxnTypeAggrigate.java
@@ -0,0 +1,78 @@
+/*
+ * 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.accounting.api.v1.client.LedgerManager;
+import org.apache.fineract.cn.command.annotation.Aggregate;
+import org.apache.fineract.cn.command.annotation.CommandHandler;
+import org.apache.fineract.cn.command.annotation.EventEmitter;
+import org.apache.fineract.cn.deposit.api.v1.EventConstants;
+import org.apache.fineract.cn.deposit.api.v1.instance.domain.SubTransactionType;
+import org.apache.fineract.cn.deposit.service.ServiceConstants;
+import org.apache.fineract.cn.deposit.service.internal.command.CreateSubTxnTypeCommand;
+import org.apache.fineract.cn.deposit.service.internal.command.UpdateSubTxnTypeCommand;
+import org.apache.fineract.cn.deposit.service.internal.mapper.SubTransactionTypeMapper;
+import org.apache.fineract.cn.deposit.service.internal.repository.SubTransactionTypeEntity;
+import org.apache.fineract.cn.deposit.service.internal.repository.SubTransactionTypeRepository;
+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;
+
+@Aggregate
+public class SubTxnTypeAggrigate {
+ private final Logger logger;
+ private final LedgerManager ledgerManager;
+ private final SubTransactionTypeRepository subTransactionTypeRepository;
+
+ @Autowired
+ public SubTxnTypeAggrigate(@Qualifier(ServiceConstants.LOGGER_NAME) Logger logger,
+ LedgerManager ledgerManager,
+ SubTransactionTypeRepository subTransactionTypeRepository) {
+ this.logger = logger;
+ this.ledgerManager = ledgerManager;
+ this.subTransactionTypeRepository = subTransactionTypeRepository;
+ }
+
+ @CommandHandler
+ @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.POST_SUB_TXN_TYPE)
+ @Transactional
+ public String createProductInstance(final CreateSubTxnTypeCommand createSubTxnTypeCommand) {
+ final SubTransactionType subTransactionType = createSubTxnTypeCommand.subTransactionType();
+
+ final SubTransactionTypeEntity subTransactionTypeEntity = SubTransactionTypeMapper.map(subTransactionType);
+ this.subTransactionTypeRepository.save(subTransactionTypeEntity);
+ return subTransactionTypeEntity.getIdentifier();
+ }
+
+ @CommandHandler
+ @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.PUT_SUB_TXN_TYPE)
+ @Transactional
+ public String updateProductInstance(final UpdateSubTxnTypeCommand createSubTxnTypeCommand) {
+ final SubTransactionType subTransactionType = createSubTxnTypeCommand.subTransactionType();
+
+ final SubTransactionTypeEntity subTransactionTypeEntity = subTransactionTypeRepository.findByIdentifier(subTransactionType.getIdentifier())
+ .orElseThrow(() ->
+ ServiceException.notFound("Sub transaction type {0} not found.", subTransactionType.getIdentifier()));
+ SubTransactionTypeMapper.update(subTransactionTypeEntity, subTransactionType);
+ this.subTransactionTypeRepository.save(subTransactionTypeEntity);
+ return subTransactionTypeEntity.getIdentifier();
+ }
+}
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/TransactionCommandHandler.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/TransactionCommandHandler.java
new file mode 100644
index 0000000..f3740ad
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/TransactionCommandHandler.java
@@ -0,0 +1,71 @@
+/*
+ * 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.transaction.domain.data.TransactionResponseData;
+import org.apache.fineract.cn.deposit.service.ServiceConstants;
+import org.apache.fineract.cn.deposit.service.internal.command.TransactionCommand;
+import org.apache.fineract.cn.deposit.service.internal.command.TransactionProcessedCommand;
+import org.apache.fineract.cn.deposit.service.internal.repository.ProductInstanceEntity;
+import org.apache.fineract.cn.deposit.service.internal.service.TransactionService;
+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.time.Clock;
+import java.time.LocalDateTime;
+import java.util.Optional;
+
+@Aggregate
+public class TransactionCommandHandler {
+ private final Logger logger;
+ private final TransactionService transactionService;
+
+ @Autowired
+ public TransactionCommandHandler(@Qualifier(ServiceConstants.LOGGER_NAME)Logger logger,
+ TransactionService transactionService) {
+ this.logger = logger;
+ this.transactionService = transactionService;
+ }
+
+ @NotNull
+ @Transactional
+ @CommandHandler(logStart = CommandLogLevel.INFO, logFinish = CommandLogLevel.INFO)
+ public TransactionResponseData performTransfer(@NotNull TransactionCommand command) {
+ switch (command.getAction()) {
+ case WITHDRAWAL: {
+ //command = dataValidator.validatePrepareTransfer(command);
+ return transactionService.withdraw(command);
+ }
+ case DEPOSIT: {
+ //command = dataValidator.validateCommitTransfer(command);
+ return transactionService.deposit(command);
+ }
+ default:
+ return null;
+ }
+ }
+
+}
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/mapper/SubTransactionTypeMapper.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/mapper/SubTransactionTypeMapper.java
new file mode 100644
index 0000000..af3c639
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/mapper/SubTransactionTypeMapper.java
@@ -0,0 +1,70 @@
+/*
+ * 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.deposit.api.v1.instance.domain.SubTransactionType;
+import org.apache.fineract.cn.deposit.service.internal.repository.SubTransactionTypeEntity;
+
+public class SubTransactionTypeMapper {
+
+ public SubTransactionTypeMapper() {
+ }
+
+ public static SubTransactionTypeEntity map(SubTransactionType subTransactionType){
+ SubTransactionTypeEntity subTransactionTypeEntity = new SubTransactionTypeEntity();
+ subTransactionTypeEntity.setIdentifier(subTransactionType.getIdentifier());
+ subTransactionTypeEntity.setName(subTransactionType.getName());
+ subTransactionTypeEntity.setDescription(subTransactionType.getDescription());
+ subTransactionTypeEntity.setCashPayment(subTransactionType.getCashPayment());
+ subTransactionTypeEntity.setActive(subTransactionType.getActive());
+ subTransactionTypeEntity.setOrderPosition(subTransactionType.getOrderPosition());
+ subTransactionTypeEntity.setTranType(subTransactionType.getTranType());
+ subTransactionTypeEntity.setLedgerAccount(subTransactionType.getLedgerAccount());
+ return subTransactionTypeEntity;
+ }
+
+ public static SubTransactionType map(SubTransactionTypeEntity subTransactionTypeEntity) {
+ SubTransactionType subTransactionType = new SubTransactionType();
+ subTransactionType.setIdentifier(subTransactionTypeEntity.getIdentifier());
+ subTransactionType.setName(subTransactionTypeEntity.getName());
+ subTransactionType.setDescription(subTransactionTypeEntity.getDescription());
+ subTransactionType.setCashPayment(subTransactionTypeEntity.getCashPayment());
+ subTransactionType.setActive(subTransactionTypeEntity.getActive());
+ subTransactionType.setOrderPosition(subTransactionTypeEntity.getOrderPosition());
+ subTransactionType.setTranType(subTransactionTypeEntity.getTranType());
+ subTransactionType.setLedgerAccount(subTransactionTypeEntity.getLedgerAccount());
+ return subTransactionType;
+ }
+ public static void update(SubTransactionTypeEntity subTransactionTypeEntity, SubTransactionType subTransactionType){
+ if(subTransactionType.getName() != null)
+ subTransactionTypeEntity.setName(subTransactionType.getName());
+ if(subTransactionType.getDescription() != null)
+ subTransactionTypeEntity.setDescription(subTransactionType.getDescription());
+ if(subTransactionType.getCashPayment() != null)
+ subTransactionTypeEntity.setCashPayment(subTransactionType.getCashPayment());
+ if(subTransactionType.getActive() != null)
+ subTransactionTypeEntity.setActive(subTransactionType.getActive());
+ if(subTransactionType.getOrderPosition() != null)
+ subTransactionTypeEntity.setOrderPosition(subTransactionType.getOrderPosition());
+ if(subTransactionType.getTranType() != null)
+ subTransactionTypeEntity.setTranType(subTransactionType.getTranType());
+ if(subTransactionType.getLedgerAccount() != null)
+ subTransactionTypeEntity.setLedgerAccount(subTransactionType.getLedgerAccount());
+ }
+}
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/SubTransactionTypeEntity.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/SubTransactionTypeEntity.java
new file mode 100644
index 0000000..ba9e525
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/SubTransactionTypeEntity.java
@@ -0,0 +1,130 @@
+/*
+ * 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 javax.persistence.*;
+
+@Entity
+@Table(name = "shed_sub_tx_type")
+public class SubTransactionTypeEntity {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "id", nullable = false)
+ private Long id;
+
+ @Column(name = "identifier", nullable = false)
+ private String identifier;
+
+ @Column(name = "a_name", nullable = false)
+ private String name;
+
+ @Column(name = "description", nullable = false)
+ private String description;
+
+ @Column(name = "is_cash_payment", nullable = false)
+ private Boolean isCashPayment;
+
+ @Column(name = "is_active", nullable = false)
+ private Boolean isActive;
+
+ @Column(name = "order_position", nullable = false)
+ private Integer orderPosition;
+
+ @Column(name = "tran_type_enum", nullable = false)
+ private Integer tranType;
+
+ @Column(name = "ledger_account_identifier", nullable = false)
+ private String ledgerAccount;
+
+ public SubTransactionTypeEntity() {
+ super();
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getIdentifier() {
+ return identifier;
+ }
+
+ public void setIdentifier(String identifier) {
+ this.identifier = identifier;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public Boolean getCashPayment() {
+ return isCashPayment;
+ }
+
+ public void setCashPayment(Boolean cashPayment) {
+ isCashPayment = cashPayment;
+ }
+
+ public Boolean getActive() {
+ return isActive;
+ }
+
+ public void setActive(Boolean active) {
+ isActive = active;
+ }
+
+ public Integer getOrderPosition() {
+ return orderPosition;
+ }
+
+ public void setOrderPosition(Integer orderPosition) {
+ this.orderPosition = orderPosition;
+ }
+
+ public Integer getTranType() {
+ return tranType;
+ }
+
+ public void setTranType(Integer tranType) {
+ this.tranType = tranType;
+ }
+
+ public String getLedgerAccount() {
+ return ledgerAccount;
+ }
+
+ public void setLedgerAccount(String ledgerAccount) {
+ this.ledgerAccount = ledgerAccount;
+ }
+}
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/SubTransactionTypeRepository.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/SubTransactionTypeRepository.java
new file mode 100644
index 0000000..53f32cb
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/SubTransactionTypeRepository.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.List;
+import java.util.Optional;
+
+public interface SubTransactionTypeRepository extends JpaRepository<SubTransactionTypeEntity, Long> {
+ Optional<SubTransactionTypeEntity> findByIdentifier(final String identifier);
+}
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/TransactionEntity.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/TransactionEntity.java
new file mode 100644
index 0000000..59b028b
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/TransactionEntity.java
@@ -0,0 +1,294 @@
+/*
+ * 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.transaction.domain.data.ActionState;
+import org.apache.fineract.cn.deposit.api.v1.transaction.domain.data.TransactionTypeEnum;
+import org.apache.fineract.cn.postgresql.util.LocalDateTimeConverter;
+
+import javax.persistence.*;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Entity
+@Table(name = "shed_transactions")
+public class TransactionEntity {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "id")
+ private Long id;
+
+ @Column(name = "identifier", nullable = false, length = 36)
+ private String identifier;
+
+ @Column(name = "account_identifier", length = 36)
+ private String accountId;
+
+ @Column(name = "routing_code", length = 256)
+ private String routingCode;
+
+ @Column(name = "external_id", length = 256)
+ private String externalId;
+
+ @Column(name = "a_name", length = 256)
+ private String name;
+
+ @Column(name = "description", length = 1024)
+ private String description;
+
+ @Column(name = "transaction_type", nullable = false, length = 32)
+ @Enumerated(EnumType.STRING)
+ private TransactionTypeEnum transactionType;
+
+ @Column(name = "sub_txn_type", length = 36)
+ private String subTxnType;
+
+ @Column(name = "amount", nullable = false)
+ private BigDecimal amount;
+
+
+ @Column(name = "fee_amount")
+ private BigDecimal feeAmount;
+
+ @Column(name = "state", nullable = false, length = 32)
+ @Enumerated(EnumType.STRING)
+ private ActionState state;
+
+ @Column(name = "customer_account_identifier", nullable = false, length = 32)
+ private String customerAccountIdentifier;
+
+ @Column(name = "payable_account_identifier", length = 32)
+ private String prepareAccountIdentifier;
+
+ @Column(name = "nostro_account_identifier", length = 32)
+ private String nostroAccountIdentifier;
+
+ @Column(name = "transaction_date")
+ @Convert(converter = LocalDateTimeConverter.class)
+ private LocalDateTime transactionDate;
+
+ @Column(name = "expiration_date")
+ @Convert(converter = LocalDateTimeConverter.class)
+ private LocalDateTime expirationDate;
+
+ @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;
+
+ @Column(name = "a_type", length = 32)
+ private String type;
+
+ @ManyToOne(fetch = FetchType.EAGER, optional = true, cascade = CascadeType.ALL)
+ @JoinColumn(name = "parent_txn_id", nullable = false)
+ private TransactionEntity parentTransaction;
+
+ public TransactionEntity() {
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public String getIdentifier() {
+ return identifier;
+ }
+
+ public void setIdentifier(String identifier) {
+ this.identifier = identifier;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public TransactionTypeEnum getTransactionType() {
+ return transactionType;
+ }
+
+ public void setTransactionType(TransactionTypeEnum transactionType) {
+ this.transactionType = transactionType;
+ }
+
+ public BigDecimal getAmount() {
+ return amount;
+ }
+
+ public void setAmount(BigDecimal amount) {
+ this.amount = amount;
+ }
+
+ public ActionState getState() {
+ return state;
+ }
+
+ public void setState(ActionState state) {
+ this.state = state;
+ }
+
+ public String getCustomerAccountIdentifier() {
+ return customerAccountIdentifier;
+ }
+
+ public void setCustomerAccountIdentifier(String customerAccountIdentifier) {
+ this.customerAccountIdentifier = customerAccountIdentifier;
+ }
+
+ public String getPrepareAccountIdentifier() {
+ return prepareAccountIdentifier;
+ }
+
+ public void setPrepareAccountIdentifier(String prepareAccountIdentifier) {
+ this.prepareAccountIdentifier = prepareAccountIdentifier;
+ }
+
+ public String getNostroAccountIdentifier() {
+ return nostroAccountIdentifier;
+ }
+
+ public void setNostroAccountIdentifier(String nostroAccountIdentifier) {
+ this.nostroAccountIdentifier = nostroAccountIdentifier;
+ }
+
+ public LocalDateTime getTransactionDate() {
+ return transactionDate;
+ }
+
+ public void setTransactionDate(LocalDateTime transactionDate) {
+ this.transactionDate = transactionDate;
+ }
+
+ public LocalDateTime getExpirationDate() {
+ return expirationDate;
+ }
+
+ public void setExpirationDate(LocalDateTime expirationDate) {
+ this.expirationDate = expirationDate;
+ }
+
+ 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 BigDecimal getFeeAmount() {
+ return feeAmount;
+ }
+
+ public void setFeeAmount(BigDecimal feeAmount) {
+ this.feeAmount = feeAmount;
+ }
+
+ public String getRoutingCode() {
+ return routingCode;
+ }
+
+ public void setRoutingCode(String routingCode) {
+ this.routingCode = routingCode;
+ }
+
+ public String getExternalId() {
+ return externalId;
+ }
+
+ public void setExternalId(String externalId) {
+ this.externalId = externalId;
+ }
+
+ public String getSubTxnType() {
+ return subTxnType;
+ }
+
+ public void setSubTxnType(String subTxnType) {
+ this.subTxnType = subTxnType;
+ }
+
+ public String getAccountId() {
+ return accountId;
+ }
+
+ public void setAccountId(String accountId) {
+ this.accountId = accountId;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public TransactionEntity getParentTransaction() {
+ return parentTransaction;
+ }
+
+ public void setParentTransaction(TransactionEntity parentTransaction) {
+ this.parentTransaction = parentTransaction;
+ }
+}
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/TransactionRepository.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/TransactionRepository.java
new file mode 100644
index 0000000..b59bc94
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/TransactionRepository.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.cn.deposit.service.internal.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Optional;
+
+public interface TransactionRepository extends JpaRepository<TransactionEntity, Long> {
+ Optional<TransactionEntity> findByIdentifier(final String identifier);
+
+ List<TransactionEntity> findByAccountId(final String accountId);
+
+ List<TransactionEntity> findByAccountIdAndTransactionDateBetween(final String accountId, LocalDateTime fromDate,
+ LocalDateTime toDate);
+}
+
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/service/SubTxnTypesService.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/service/SubTxnTypesService.java
new file mode 100644
index 0000000..a9e84bc
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/service/SubTxnTypesService.java
@@ -0,0 +1,77 @@
+/*
+ * 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.commons.lang.StringUtils;
+import org.apache.fineract.cn.accounting.api.v1.client.LedgerManager;
+import org.apache.fineract.cn.accounting.api.v1.domain.Account;
+import org.apache.fineract.cn.deposit.api.v1.instance.domain.ProductInstance;
+import org.apache.fineract.cn.deposit.api.v1.instance.domain.SubTransactionType;
+import org.apache.fineract.cn.deposit.service.ServiceConstants;
+import org.apache.fineract.cn.deposit.service.internal.mapper.ProductInstanceMapper;
+import org.apache.fineract.cn.deposit.service.internal.mapper.SubTransactionTypeMapper;
+import org.apache.fineract.cn.deposit.service.internal.repository.SubTransactionTypeRepository;
+import org.apache.fineract.cn.deposit.service.internal.service.helper.AccountingService;
+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;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+@Service
+public class SubTxnTypesService {
+ private final Logger logger;
+ private final SubTransactionTypeRepository subTransactionTypeRepository;
+ private final LedgerManager ledgerManager;
+
+ @Autowired
+ public SubTxnTypesService(@Qualifier(ServiceConstants.LOGGER_NAME) Logger logger,
+ SubTransactionTypeRepository subTransactionTypeRepository,
+ LedgerManager ledgerManager) {
+ this.logger = logger;
+ this.subTransactionTypeRepository = subTransactionTypeRepository;
+ this.ledgerManager = ledgerManager;
+ }
+
+ public Optional<SubTransactionType> findByIdentifier(final String identifier) {
+ return this.subTransactionTypeRepository.findByIdentifier(identifier).map(SubTransactionTypeMapper::map);
+ }
+ public List<SubTransactionType> findAll() {
+ return this.subTransactionTypeRepository.findAll()
+ .stream().map(SubTransactionTypeMapper::map).collect(Collectors.toList());
+ }
+
+ public Boolean subTxnTypeExists(final String identifier) {
+ return this.findByIdentifier(identifier).isPresent();
+ }
+
+ public Boolean ledgerExists(SubTransactionType subTransactionType){
+ if(StringUtils.isNotBlank(subTransactionType.getLedgerAccount())){
+ if(this.ledgerManager.findAccount(subTransactionType.getLedgerAccount()) == null){
+ throw ServiceException.conflict("Ledger Account not found.", subTransactionType.getLedgerAccount());
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/service/TransactionService.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/service/TransactionService.java
new file mode 100644
index 0000000..82b0f8e
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/service/TransactionService.java
@@ -0,0 +1,440 @@
+/*
+ * 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.commons.lang.StringUtils;
+import org.apache.fineract.cn.accounting.api.v1.client.LedgerManager;
+import org.apache.fineract.cn.accounting.api.v1.domain.Account;
+import org.apache.fineract.cn.accounting.api.v1.domain.Creditor;
+import org.apache.fineract.cn.accounting.api.v1.domain.Debtor;
+import org.apache.fineract.cn.accounting.api.v1.domain.JournalEntry;
+import org.apache.fineract.cn.api.util.UserContextHolder;
+import org.apache.fineract.cn.deposit.api.v1.definition.domain.Action;
+import org.apache.fineract.cn.deposit.api.v1.definition.domain.Charge;
+import org.apache.fineract.cn.deposit.api.v1.definition.domain.Currency;
+import org.apache.fineract.cn.deposit.api.v1.definition.domain.ProductDefinition;
+import org.apache.fineract.cn.deposit.api.v1.instance.domain.ProductInstance;
+import org.apache.fineract.cn.deposit.api.v1.instance.domain.SubTransactionType;
+import org.apache.fineract.cn.deposit.api.v1.transaction.domain.data.*;
+import org.apache.fineract.cn.deposit.api.v1.transaction.utils.MathUtil;
+import org.apache.fineract.cn.deposit.service.ServiceConstants;
+import org.apache.fineract.cn.deposit.service.internal.command.TransactionCommand;
+import org.apache.fineract.cn.deposit.service.internal.repository.ProductInstanceEntity;
+import org.apache.fineract.cn.deposit.service.internal.repository.ProductInstanceRepository;
+import org.apache.fineract.cn.deposit.service.internal.repository.TransactionEntity;
+import org.apache.fineract.cn.deposit.service.internal.repository.TransactionRepository;
+import org.apache.fineract.cn.lang.DateConverter;
+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.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.math.MathContext;
+import java.time.Clock;
+import java.time.LocalDateTime;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+@Service
+public class TransactionService {
+ private final Logger logger;
+ private final LedgerManager ledgerManager;
+ private final ProductInstanceService productInstanceService;
+ private final ProductDefinitionService productDefinitionService;
+ private final ActionService actionService;
+ private final SubTxnTypesService subTxnTypesService;
+ private final TransactionRepository transactionRepository;
+ private final ProductInstanceRepository productInstanceRepository;
+
+ public static final String DEBIT = "DEBIT";
+ public static final String CREDIT = "CREDIT";
+
+ @Autowired
+ public TransactionService(@Qualifier(ServiceConstants.LOGGER_NAME) Logger logger, LedgerManager ledgerManager,
+ ProductInstanceService productInstanceService,
+ ProductDefinitionService productDefinitionService, ActionService actionService,
+ SubTxnTypesService subTxnTypesService, TransactionRepository transactionRepository, ProductInstanceRepository productInstanceRepository) {
+ this.logger = logger;
+ this.ledgerManager = ledgerManager;
+ this.productInstanceService = productInstanceService;
+ this.productDefinitionService = productDefinitionService;
+ this.actionService = actionService;
+ this.subTxnTypesService = subTxnTypesService;
+ this.transactionRepository = transactionRepository;
+ this.productInstanceRepository = productInstanceRepository;
+ }
+
+ @Transactional
+ public TransactionResponseData withdraw(TransactionCommand command) {
+ TransactionRequestData request = command.getTransactionRequest();
+ AccountWrapper accountWrapper = validateAndGetAccount(request, TransactionTypeEnum.WITHDRAWAL);
+ LocalDateTime transactionDate = getNow();
+ //get txntype charges
+ List<Charge> charges = getCharges(accountWrapper.account.getIdentifier(), TransactionTypeEnum.WITHDRAWAL);
+ //todo: get subTxnType charges
+
+ TransactionEntity txn = doWithdraw(request, accountWrapper, charges, getNow());
+
+
+ return TransactionResponseData.build(request.getRoutingCode(), request.getExternalId(),
+ request.getRequestCode(), ActionState.ACCEPTED,
+ null, txn.getIdentifier(), transactionDate);
+ }
+
+ @Transactional
+ public TransactionResponseData deposit(TransactionCommand command) {
+ TransactionRequestData request = command.getTransactionRequest();
+ AccountWrapper accountWrapper = validateAndGetAccount(request, TransactionTypeEnum.DEPOSIT);
+ LocalDateTime transactionDate = getNow();
+ //get txntype charges
+ List<Charge> charges = getCharges(accountWrapper.account.getIdentifier(), TransactionTypeEnum.DEPOSIT);
+ //todo: get subTxnType charges
+ TransactionEntity txn = doDeposit(request, accountWrapper, charges, getNow());
+
+ return TransactionResponseData.build(request.getRoutingCode(), request.getExternalId(),
+ request.getRequestCode(), ActionState.ACCEPTED,
+ null, txn.getIdentifier(), transactionDate);
+ }
+
+ private TransactionEntity doDeposit(TransactionRequestData request, AccountWrapper accountWrapper, List<Charge> charges, LocalDateTime transactionDate) {
+ BigDecimal amount = request.getAmount().getAmount();
+
+ TransactionEntity txn = createTransaction(request,TransactionTypeEnum.DEPOSIT, transactionDate, CREDIT, null);
+ String debitAccountIdentifier = accountWrapper.productDefinition.getCashAccountIdentifier();
+ /* if subtxn is provided and it has an account configured the do debit that account*/
+ if(StringUtils.isNotBlank(request.getSubTxnId())){
+ Optional<SubTransactionType> subTxnTypeOpt = this.subTxnTypesService.findByIdentifier(request.getSubTxnId());
+ if(subTxnTypeOpt.isPresent()) {
+ txn.setSubTxnType(subTxnTypeOpt.get().getIdentifier());
+ if (subTxnTypeOpt.get().getLedgerAccount() != null) {
+ debitAccountIdentifier = subTxnTypeOpt.get().getLedgerAccount();
+ }
+ }
+ }
+ final JournalEntry journalEntry = createJournalEntry(txn.getIdentifier(), TransactionTypeEnum.DEPOSIT.getCode(),
+ DateConverter.toIsoString(transactionDate), request.getNote(), getLoginUser());
+
+ HashSet<Debtor> debtors = new HashSet<>(1);
+ HashSet<Creditor> creditors = new HashSet<>(1);
+
+ addCreditor(accountWrapper.account.getIdentifier(), amount.doubleValue(), creditors);
+ addDebtor(debitAccountIdentifier, amount.doubleValue(), debtors);
+
+
+ prepareCharges(request, accountWrapper, charges, debtors, creditors, txn);
+
+ if (debtors.isEmpty()) // must be same size as creditors
+ throw ServiceException.badRequest("Debit and Credit doesn't match");
+
+ journalEntry.setDebtors(debtors);
+ journalEntry.setCreditors(creditors);
+
+ transactionRepository.save(txn);
+
+ ledgerManager.createJournalEntry(journalEntry);
+ return txn;
+ }
+
+
+ private TransactionEntity doWithdraw(@NotNull TransactionRequestData request, @NotNull AccountWrapper accountWrapper,
+ List<Charge> charges, LocalDateTime transactionDate) {
+ BigDecimal amount = request.getAmount().getAmount();
+
+ TransactionEntity txn = createTransaction(request, TransactionTypeEnum.WITHDRAWAL, transactionDate, DEBIT, null);
+
+ String creditAccountIdentifier = accountWrapper.productDefinition.getCashAccountIdentifier();
+ /* if subtxn is provided and it has an account configured the do credit that account*/
+ if(StringUtils.isNotBlank(request.getSubTxnId())){
+ Optional<SubTransactionType> subTxnTypeOpt = this.subTxnTypesService.findByIdentifier(request.getSubTxnId());
+ if(subTxnTypeOpt.isPresent()) {
+ txn.setSubTxnType(subTxnTypeOpt.get().getIdentifier());
+ if (subTxnTypeOpt.get().getLedgerAccount() != null) {
+ creditAccountIdentifier = subTxnTypeOpt.get().getLedgerAccount();
+ }
+ }
+ }
+ final JournalEntry journalEntry = createJournalEntry(txn.getIdentifier(), TransactionTypeEnum.WITHDRAWAL.getCode(),
+ DateConverter.toIsoString(transactionDate), request.getNote(), getLoginUser());
+
+ HashSet<Debtor> debtors = new HashSet<>(1);
+ HashSet<Creditor> creditors = new HashSet<>(1);
+
+ addCreditor(creditAccountIdentifier, amount.doubleValue(), creditors);
+ addDebtor(accountWrapper.account.getIdentifier(), amount.doubleValue(), debtors);
+
+ prepareCharges(request, accountWrapper, charges, debtors, creditors, txn);
+
+ if (debtors.isEmpty()) // must be same size as creditors
+ throw ServiceException.badRequest("Debit and Credit doesn't match");
+
+ journalEntry.setDebtors(debtors);
+ journalEntry.setCreditors(creditors);
+ transactionRepository.save(txn);
+ ledgerManager.createJournalEntry(journalEntry);
+ return txn;
+ }
+
+
+
+ private void prepareCharges(@NotNull TransactionRequestData request, @NotNull AccountWrapper accountWrapper,
+ @NotNull List<Charge> charges, HashSet<Debtor> debtors, HashSet<Creditor> creditors,
+ TransactionEntity txn) {
+
+
+ BigDecimal amount = request.getAmount().getAmount();
+ Currency currency = accountWrapper.productDefinition.getCurrency();
+
+ BigDecimal total = MathUtil.normalize(calcTotalCharges(charges, amount), currency);
+ if (MathUtil.isEmpty(total)) {
+ return;
+ }
+ txn.setFeeAmount(total);
+
+ if (creditors == null) {
+ creditors = new HashSet<>(1);
+ }
+ if (debtors == null) {
+ debtors = new HashSet<>(charges.size());
+ }
+ for(Charge charge : charges){
+ addCreditor(charge.getIncomeAccountIdentifier(), calcChargeAmount(amount, charge).doubleValue(), creditors);
+ addDebtor(accountWrapper.account.getIdentifier(), calcChargeAmount(amount, charge).doubleValue(), debtors);
+ createTransaction(request,TransactionTypeEnum.CHARGES_PAYMENT, getNow(), DEBIT, txn);
+ }
+
+ }
+
+
+
+ private AccountWrapper validateAndGetAccount(@NotNull TransactionRequestData request, TransactionTypeEnum txnType) {
+ //TODO: error handling
+ String accountId = request.getAccountId();
+ Account account = ledgerManager.findAccount(accountId);
+ validateAccount(request, account);
+
+ ProductInstance product = productInstanceService.findByAccountIdentifier(accountId).get();
+ ProductDefinition productDefinition = productDefinitionService.findProductDefinition(product.getProductIdentifier()).get();
+
+ Currency currency = productDefinition.getCurrency();
+ if (!currency.getCode().equals(request.getAmount().getCurrency()))
+ throw new UnsupportedOperationException();
+
+ request.normalizeAmounts(currency);
+
+ Double withdrawableBalance = getWithdrawableBalance(account, productDefinition);
+ if (txnType == TransactionTypeEnum.WITHDRAWAL && withdrawableBalance < request.getAmount().getAmount().doubleValue())
+ throw new UnsupportedOperationException();
+
+ return new AccountWrapper(account, product, productDefinition, withdrawableBalance);
+ }
+
+ Double getWithdrawableBalance(Account account, ProductDefinition productDefinition) {
+ // on-hold amount, if any, is subtracted to payable account
+ return MathUtil.subtractToZero(account.getBalance(), productDefinition.getMinimumBalance());
+ }
+
+
+ private void validateAccount(@NotNull TransactionRequestData request, Account account) {
+ validateAccount(account);
+
+ String accountId = account.getIdentifier();
+
+ if (account.getHolders() != null) { // customer account
+ ProductInstance product = productInstanceService.findByAccountIdentifier(accountId).get();
+ ProductDefinition productDefinition = productDefinitionService.findProductDefinition(product.getProductIdentifier()).get();
+ if (!Boolean.TRUE.equals(productDefinition.getActive()))
+ throw new UnsupportedOperationException("Product Definition is inactive");
+
+ Currency currency = productDefinition.getCurrency();
+ if (!currency.getCode().equals(request.getAmount().getCurrency()))
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ private void validateAccount(Account account) {
+ if (account == null)
+ throw new UnsupportedOperationException("Account not found");
+ if (!account.getState().equals(Account.State.OPEN.name()))
+ throw new UnsupportedOperationException("Account is in state " + account.getState());
+ }
+
+ public List<Charge> getCharges(String accountIdentifier, TransactionTypeEnum transactionType) {
+ List<Action> actions = actionService.fetchActions();
+
+ List<String> actionIds = actions
+ .stream()
+ .filter(action -> action.getTransactionType().equals(transactionType.getCode()))
+ .map(Action::getIdentifier)
+ .collect(Collectors.toList());
+
+ ProductInstance product = productInstanceService.findByAccountIdentifier(accountIdentifier).get();
+ ProductDefinition productDefinition = productDefinitionService.findProductDefinition(product.getProductIdentifier()).get();
+
+ return productDefinition.getCharges()
+ .stream()
+ .filter(charge -> actionIds.contains(charge.getActionIdentifier()))
+ .collect(Collectors.toList());
+ }
+ // Util
+
+
+ private LocalDateTime getNow() {
+ return LocalDateTime.now(Clock.systemUTC());
+ }
+ private String getLoginUser() {
+ return UserContextHolder.checkedGetUser();
+ }
+
+
+ private JournalEntry createJournalEntry(String actionIdentifier, String transactionType, String transactionDate, String message, String loginUser) {
+ final JournalEntry journalEntry = new JournalEntry();
+ journalEntry.setTransactionIdentifier(actionIdentifier);
+ journalEntry.setTransactionType(transactionType);
+ journalEntry.setTransactionDate(transactionDate);
+ journalEntry.setMessage(message);
+ journalEntry.setClerk(loginUser);
+ return journalEntry;
+ }
+
+ private void addCreditor(String accountNumber, double amount, HashSet<Creditor> creditors) {
+ Creditor creditor = new Creditor();
+ creditor.setAccountNumber(accountNumber);
+ creditor.setAmount(Double.toString(amount));
+ creditors.add(creditor);
+ }
+
+ private void addDebtor(String accountNumber, double amount, HashSet<Debtor> debtors) {
+ Debtor debtor = new Debtor();
+ debtor.setAccountNumber(accountNumber);
+ debtor.setAmount(Double.toString(amount));
+ debtors.add(debtor);
+ }
+
+ private BigDecimal calcChargeAmount(BigDecimal amount, Charge charge) {
+ return calcChargeAmount(amount, charge, null, false);
+ }
+
+ private BigDecimal calcChargeAmount(@NotNull BigDecimal amount, @NotNull Charge charge, Currency currency, boolean norm) {
+ Double value = charge.getAmount();
+ if (value == null)
+ return null;
+
+ BigDecimal portion = BigDecimal.valueOf(100.00d);
+ MathContext mc = MathUtil.CALCULATION_MATH_CONTEXT;
+ BigDecimal feeAmount = BigDecimal.valueOf(MathUtil.nullToZero(charge.getAmount()));
+ BigDecimal result = charge.getProportional()
+ ? amount.multiply(feeAmount.divide(portion, mc), mc)
+ : feeAmount;
+ return norm ? MathUtil.normalize(result, currency) : result;
+ }
+
+ @NotNull
+ private BigDecimal calcTotalCharges(@NotNull List<Charge> charges, BigDecimal amount) {
+ return charges.stream().map(charge -> calcChargeAmount(amount, charge)).reduce(MathUtil::add).orElse(BigDecimal.ZERO);
+ }
+
+
+ private TransactionEntity createTransaction(TransactionRequestData request, TransactionTypeEnum txnType,
+ LocalDateTime transactionDate, String tranType,
+ TransactionEntity parent) {
+ TransactionEntity txn = new TransactionEntity();
+ UUID uuid=UUID.randomUUID();
+
+ while(transactionRepository.findByIdentifier(uuid.toString()).isPresent()){
+ uuid=UUID.randomUUID();
+ }
+
+ txn.setIdentifier(uuid.toString());
+ txn.setRoutingCode(request.getRoutingCode());
+ txn.setExternalId(request.getExternalId());
+ txn.setTransactionType(txnType);
+ txn.setAmount(request.getAmount().getAmount());
+ //txn.setFeeAmount();
+ txn.setState(ActionState.ACCEPTED);
+ //txn.setCustomerAccountIdentifier();
+ txn.setTransactionDate(transactionDate);
+ txn.setExpirationDate(request.getExpiration());
+ txn.setCreatedBy(getLoginUser());
+ txn.setCreatedOn(getNow());
+ /*txn.setLastModifiedBy();
+ txn.setLastModifiedOn();*/
+ markLastTransaction(request.getAccountId(), transactionDate);
+ txn.setAccountId(request.getAccountId());
+ txn.setType(tranType);
+ txn.setParentTransaction(parent);
+ transactionRepository.save(txn);
+ return txn;
+ }
+
+ private void markLastTransaction(final String productInstanceIdentifier, LocalDateTime transactionDate) {
+ final Optional<ProductInstanceEntity> optionalProductInstance =
+ this.productInstanceRepository.findByAccountIdentifier(productInstanceIdentifier);
+
+ final ProductInstanceEntity productInstanceEntity = optionalProductInstance.orElseThrow(() ->
+ ServiceException.notFound("Product instance {0} not found.", productInstanceIdentifier));
+
+ productInstanceEntity.setLastTransactionDate(transactionDate);
+
+ this.productInstanceRepository.save(productInstanceEntity);
+
+ }
+ public List<StatementResponse> fetchStatement(String accountId,
+ LocalDateTime fromDateTime,
+ LocalDateTime toDateTime) {
+ return transactionRepository.findByAccountIdAndTransactionDateBetween(accountId, fromDateTime, toDateTime)
+ .stream().map(txn -> {
+ StatementResponse statementObj = new StatementResponse();
+ statementObj.setTransactionCode(txn.getIdentifier());
+ statementObj.setTranType(txn.getTransactionType().name());
+ statementObj.setAmount(txn.getAmount());
+ statementObj.setTransactionDate(txn.getTransactionDate());
+ statementObj.setSubTxnType(txn.getSubTxnType());
+ statementObj.setType(txn.getType());
+ statementObj.setDescription(txn.getDescription());
+ return statementObj;
+ }).collect(Collectors.toList());
+ }
+
+ public static class AccountWrapper {
+ @NotNull
+ private final Account account;
+ @NotNull
+ private final ProductInstance product;
+ @NotNull
+ private final ProductDefinition productDefinition;
+ @NotNull
+ private final Double withdrawableBalance;
+
+ public AccountWrapper(Account account, ProductInstance product, ProductDefinition productDefinition, Double withdrawableBalance) {
+ this.account = account;
+ this.product = product;
+ this.productDefinition = productDefinition;
+ this.withdrawableBalance = withdrawableBalance;
+ }
+ }
+}
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/rest/ProductInstanceRestController.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/rest/ProductInstanceRestController.java
index d9025c9..aece9a3 100644
--- a/service/src/main/java/org/apache/fineract/cn/deposit/service/rest/ProductInstanceRestController.java
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/rest/ProductInstanceRestController.java
@@ -18,37 +18,34 @@
*/
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.gateway.CommandGateway;
import org.apache.fineract.cn.deposit.api.v1.EventConstants;
import org.apache.fineract.cn.deposit.api.v1.PermittableGroupIds;
import org.apache.fineract.cn.deposit.api.v1.instance.domain.AvailableTransactionType;
import org.apache.fineract.cn.deposit.api.v1.instance.domain.ProductInstance;
+import org.apache.fineract.cn.deposit.api.v1.transaction.domain.data.StatementResponse;
import org.apache.fineract.cn.deposit.service.ServiceConstants;
-import org.apache.fineract.cn.deposit.service.internal.command.ActivateProductInstanceCommand;
-import org.apache.fineract.cn.deposit.service.internal.command.CloseProductInstanceCommand;
-import org.apache.fineract.cn.deposit.service.internal.command.CreateProductInstanceCommand;
-import org.apache.fineract.cn.deposit.service.internal.command.TransactionProcessedCommand;
-import org.apache.fineract.cn.deposit.service.internal.command.UpdateProductInstanceCommand;
+import org.apache.fineract.cn.deposit.service.internal.command.*;
import org.apache.fineract.cn.deposit.service.internal.service.ProductInstanceService;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import javax.validation.Valid;
-import org.apache.fineract.cn.anubis.annotation.AcceptedTokenType;
-import org.apache.fineract.cn.anubis.annotation.Permittable;
-import org.apache.fineract.cn.command.gateway.CommandGateway;
+import org.apache.fineract.cn.deposit.service.internal.service.TransactionService;
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.format.annotation.DateTimeFormat;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
@RestController
@RequestMapping("/instances")
@@ -57,15 +54,18 @@
private final Logger logger;
private final CommandGateway commandGateway;
private final ProductInstanceService productInstanceService;
+ private final TransactionService transactionService;
@Autowired
public ProductInstanceRestController(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
final CommandGateway commandGateway,
- final ProductInstanceService productInstanceService) {
+ final ProductInstanceService productInstanceService,
+ TransactionService transactionService) {
super();
this.logger = logger;
this.commandGateway = commandGateway;
this.productInstanceService = productInstanceService;
+ this.transactionService = transactionService;
}
@Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.INSTANCE_MANAGEMENT)
@@ -199,4 +199,32 @@
.orElseThrow(() -> ServiceException.notFound("Product instance {0} not found.", identifier))
);
}
+
+ @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.INSTANCE_MANAGEMENT)
+ @RequestMapping(
+ value = "/{identifier}/statement",
+ method = RequestMethod.GET,
+ consumes = MediaType.ALL_VALUE,
+ produces = MediaType.APPLICATION_JSON_VALUE
+ )
+ @ResponseBody
+ ResponseEntity<List<StatementResponse>> statement(@PathVariable("identifier") final String identifier,
+ @RequestParam("fromDate")
+ @DateTimeFormat(pattern = "dd.MM.yyyy") Date fromDate,
+ @RequestParam("toDate")
+ @DateTimeFormat(pattern = "dd.MM.yyyy") Date toDate
+ ) {
+ LocalDateTime fromDateTime = convertToLocalDateTime(fromDate);
+ LocalDateTime toDateTime = convertToLocalDateTime(toDate);
+
+ List<StatementResponse> statement= transactionService.fetchStatement(identifier, fromDateTime, toDateTime);
+
+ return ResponseEntity.ok(statement);
+ }
+
+ private LocalDateTime convertToLocalDateTime(Date dateToConvert) {
+ return dateToConvert.toInstant()
+ .atZone(ZoneId.systemDefault())
+ .toLocalDateTime();
+ }
}
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/rest/SubTxnTypeRestController.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/rest/SubTxnTypeRestController.java
new file mode 100644
index 0000000..8a875f4
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/rest/SubTxnTypeRestController.java
@@ -0,0 +1,132 @@
+/*
+ * 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.commons.lang.StringUtils;
+import org.apache.fineract.cn.anubis.annotation.AcceptedTokenType;
+import org.apache.fineract.cn.anubis.annotation.Permittable;
+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.instance.domain.ProductInstance;
+import org.apache.fineract.cn.deposit.api.v1.instance.domain.SubTransactionType;
+import org.apache.fineract.cn.deposit.service.ServiceConstants;
+import org.apache.fineract.cn.deposit.service.internal.command.CreateSubTxnTypeCommand;
+import org.apache.fineract.cn.deposit.service.internal.command.UpdateSubTxnTypeCommand;
+import org.apache.fineract.cn.deposit.service.internal.service.SubTxnTypesService;
+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.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+import java.util.List;
+import java.util.Optional;
+
+@RestController
+@RequestMapping("/subtxntype")
+public class SubTxnTypeRestController {
+ private final Logger logger;
+ private final CommandGateway commandGateway;
+ private final SubTxnTypesService service;
+
+ @Autowired
+ public SubTxnTypeRestController(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+ CommandGateway commandGateway,
+ SubTxnTypesService service) {
+ this.logger = logger;
+ this.commandGateway = commandGateway;
+ this.service = service;
+ }
+
+ @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.DEFINITION_MANAGEMENT)
+ @RequestMapping(
+ value = "",
+ method = RequestMethod.POST,
+ consumes = MediaType.APPLICATION_JSON_VALUE,
+ produces = MediaType.APPLICATION_JSON_VALUE
+ )
+ public
+ @ResponseBody
+ ResponseEntity<Void> create(@RequestBody @Valid final SubTransactionType subTransactionType) {
+
+ if (this.service.subTxnTypeExists(subTransactionType.getIdentifier())) {
+ throw ServiceException.conflict("Sub Txn Type {0} already exists.", subTransactionType.getIdentifier());
+ }
+
+ this.service.ledgerExists(subTransactionType);
+
+ this.commandGateway.process(new CreateSubTxnTypeCommand(subTransactionType));
+ return ResponseEntity.accepted().build();
+ }
+
+ @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.DEFINITION_MANAGEMENT)
+ @RequestMapping(
+ value = "",
+ method = RequestMethod.GET,
+ consumes = MediaType.ALL_VALUE,
+ produces = MediaType.APPLICATION_JSON_VALUE
+ )
+ public
+ @ResponseBody
+ ResponseEntity<List<SubTransactionType>> fetchSubTxnTypes() {
+ return ResponseEntity.ok(this.service.findAll());
+ }
+
+
+ @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.DEFINITION_MANAGEMENT)
+ @RequestMapping(
+ value = "/{identifier}",
+ method = RequestMethod.GET,
+ consumes = MediaType.APPLICATION_JSON_VALUE,
+ produces = MediaType.APPLICATION_JSON_VALUE
+ )
+ public
+ @ResponseBody
+ ResponseEntity<SubTransactionType> fetchOne(@PathVariable("identifier") final String identifier) {
+ Optional<SubTransactionType> optSubTxnType = service.findByIdentifier(identifier);
+ if (!optSubTxnType.isPresent()) {
+ throw ServiceException.notFound("Sub transaction type {0} not found.", identifier);
+ }
+ return ResponseEntity.ok(optSubTxnType.get());
+ }
+
+
+ @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.DEFINITION_MANAGEMENT)
+ @RequestMapping(
+ value = "/{identifier}",
+ method = RequestMethod.PUT,
+ produces = MediaType.APPLICATION_JSON_VALUE,
+ consumes = MediaType.APPLICATION_JSON_VALUE
+ )
+ public
+ @ResponseBody
+ ResponseEntity<Void> updateCustomer(@PathVariable("identifier") final String identifier,
+ @RequestBody final SubTransactionType subTransactionType) {
+ if (this.service.subTxnTypeExists(identifier)) {
+ this.commandGateway.process(new UpdateSubTxnTypeCommand(subTransactionType));
+ } else {
+ throw ServiceException.notFound("Sub transaction type {0} not found.", identifier);
+ }
+ return ResponseEntity.accepted().build();
+ }
+
+}
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/rest/TransactionRestController.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/rest/TransactionRestController.java
new file mode 100644
index 0000000..3b6e278
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/rest/TransactionRestController.java
@@ -0,0 +1,79 @@
+/*
+ * 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.instance.domain.SubTransactionType;
+import org.apache.fineract.cn.deposit.api.v1.transaction.domain.data.TransactionActionType;
+import org.apache.fineract.cn.deposit.api.v1.transaction.domain.data.TransactionRequestData;
+import org.apache.fineract.cn.deposit.api.v1.transaction.domain.data.TransactionResponseData;
+import org.apache.fineract.cn.deposit.api.v1.transaction.domain.data.TransactionTypeEnum;
+import org.apache.fineract.cn.deposit.service.ServiceConstants;
+import org.apache.fineract.cn.deposit.service.internal.command.CreateSubTxnTypeCommand;
+import org.apache.fineract.cn.deposit.service.internal.command.TransactionCommand;
+import org.apache.fineract.cn.deposit.service.internal.service.SubTxnTypesService;
+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.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+
+@RestController
+@RequestMapping("/transaction")
+public class TransactionRestController {
+ private final Logger logger;
+ private final CommandGateway commandGateway;
+ private final SubTxnTypesService service;
+
+ @Autowired
+ public TransactionRestController(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+ CommandGateway commandGateway,
+ SubTxnTypesService service) {
+ this.logger = logger;
+ this.commandGateway = commandGateway;
+ this.service = service;
+ }
+
+ @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<TransactionResponseData> performTxn(@RequestParam("action") String action, @RequestBody TransactionRequestData requestData)
+ throws Throwable {
+ CommandCallback<TransactionResponseData> result = commandGateway.process(new TransactionCommand(requestData, TransactionActionType.valueOf(action)),
+ TransactionResponseData.class);
+
+ return ResponseEntity.ok(result.get());
+ }
+
+}
diff --git a/service/src/main/resources/application.yml b/service/src/main/resources/application.yml
index 26e8854..16e3bee 100644
--- a/service/src/main/resources/application.yml
+++ b/service/src/main/resources/application.yml
@@ -1,4 +1,4 @@
-#
+ #
# 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
@@ -69,3 +69,6 @@
flyway:
enabled: false
+
+config:
+ fixedAccountId: true
diff --git a/service/src/main/resources/db/migrations/postgresql/V7__sub_txn_type.sql b/service/src/main/resources/db/migrations/postgresql/V7__sub_txn_type.sql
new file mode 100644
index 0000000..0078941
--- /dev/null
+++ b/service/src/main/resources/db/migrations/postgresql/V7__sub_txn_type.sql
@@ -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.
+--
+
+CREATE TABLE shed_sub_tx_type (
+ id bigserial NOT NULL,
+ identifier varchar(32) NOT NULL,
+ a_name varchar(256) NOT NULL,
+ description varchar(2048) NULL,
+ is_cash_payment bool NOT NULL,
+ is_active bool NOT null,
+ order_position int8 NOT null,
+ tran_type_enum int8 NULL,
+ ledger_account_identifier varchar(32) NULL,
+ CONSTRAINT shed_sub_tx_type_pk PRIMARY KEY (id),
+ CONSTRAINT shed_sub_tx_type_identifier_uq UNIQUE (identifier)
+);
\ 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
new file mode 100644
index 0000000..9acf61e
--- /dev/null
+++ b/service/src/main/resources/db/migrations/postgresql/V8__transaction.sql
@@ -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.
+--
+
+CREATE TABLE shed_transactions (
+ id bigserial NOT NULL,
+ identifier VARCHAR(40) NOT NULL,
+ account_identifier VARCHAR(32) NOT NULL,
+ routing_code VARCHAR(40) NULL,
+ external_id VARCHAR(40) NULL,
+ a_name VARCHAR(256) NULL,
+ description VARCHAR(1024) NULL,
+ transaction_type VARCHAR(32) NOT NULL,
+ sub_txn_type VARCHAR(32) NULL,
+ amount numeric(15,5) NOT NULL,
+ fee_amount numeric(15,5) NULL,
+ state VARCHAR(32) NOT NULL,
+ customer_account_identifier VARCHAR(32) NULL,
+ payable_account_identifier VARCHAR(32) NULL,
+ nostro_account_identifier VARCHAR(32) NULL,
+ transaction_date TIMESTAMP NULL,
+ expiration_date TIMESTAMP NULL,
+ created_by VARCHAR(32) NULL,
+ created_on TIMESTAMP NULL,
+ last_modified_by VARCHAR(32) NULL,
+ last_modified_on TIMESTAMP NULL,
+ 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)
+);
\ No newline at end of file
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
new file mode 100644
index 0000000..450715a
--- /dev/null
+++ b/service/src/main/resources/db/migrations/postgresql/V9__transaction_update.sql
@@ -0,0 +1,30 @@
+--
+-- 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);
\ No newline at end of file
diff --git a/shared.gradle b/shared.gradle
index 5d8ffee..a95dc9d 100644
--- a/shared.gradle
+++ b/shared.gradle
@@ -29,6 +29,7 @@
frameworkanubis : '0.1.0-BUILD-SNAPSHOT',
frameworkledger : '0.1.0-BUILD-SNAPSHOT',
frameworkrhythm : '0.1.0-BUILD-SNAPSHOT',
+ frameworkdeposit : '0.1.0-BUILD-SNAPSHOT',
javamoneylib : '0.9-SNAPSHOT',
validator : '5.3.0.Final'
]