diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java index 6c2f3aa4b..4e42e6a30 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java @@ -375,6 +375,30 @@ public class CommandWrapper { public boolean isLoanResource() { return this.entityName.equalsIgnoreCase("LOAN"); } + + public boolean isTellerResource() { + return this.entityName.equalsIgnoreCase("TELLER"); + } + + public boolean isAllocateCashier() { + return this.actionName.equalsIgnoreCase("ALLOCATECASHIER"); + } + + public boolean isUpdateCashierAllocation() { + return this.actionName.equalsIgnoreCase("UPDATECASHIERALLOCATION"); + } + + public boolean isDeleteCashierAllocation() { + return this.actionName.equalsIgnoreCase("DELETECASHIERALLOCATION"); + } + + public boolean isAllocateCashToCashier() { + return this.actionName.equalsIgnoreCase("ALLOCATECASHTOCASHIER"); + } + + public boolean isSettleCashFromCashier() { + return this.actionName.equalsIgnoreCase("SETTLECASHFROMCASHIER"); + } public boolean isLoanChargeResource() { return this.entityName.equalsIgnoreCase("LOANCHARGE"); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java index 9f15a214e..fa344563a 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java @@ -23,6 +23,7 @@ public class CommandWrapperBuilder { private String transactionId; private Long productId; private Long templateId; + private Long tellerId; public CommandWrapper build() { return new CommandWrapper(this.officeId, this.groupId, this.clientId, this.loanId, this.savingsId, this.actionName, @@ -58,6 +59,11 @@ public class CommandWrapperBuilder { this.subentityId = withSubEntityId; return this; } + + public CommandWrapperBuilder withTellerId(final Long withTellerId) { + this.tellerId = withTellerId; + return this; + } public CommandWrapperBuilder withJson(final String withJson) { this.json = withJson; @@ -2112,4 +2118,73 @@ public class CommandWrapperBuilder { this.href = "/rescheduleloans/" + requestId + "?command=reject"; return this; } + + public CommandWrapperBuilder createTeller() { + this.actionName = "CREATE"; + this.entityName = "TELLER"; + this.entityId = null; + this.href = "/tellers/templates"; + return this; + } + + public CommandWrapperBuilder updateTeller(final Long tellerId) { + this.actionName = "UPDATE"; + this.entityName = "TELLER"; + this.entityId = tellerId; + this.href = "/tellers/" + tellerId; + return this; + } + + public CommandWrapperBuilder deleteTeller(final Long tellerId) { + this.actionName = "DELETE"; + this.entityName = "TELLER"; + this.entityId = tellerId; + this.href = "/tellers/" + tellerId; + return this; + } + + public CommandWrapperBuilder allocateTeller(final long tellerId) { + this.actionName = "ALLOCATECASHIER"; + this.entityName = "TELLER"; + this.entityId = tellerId; + this.href = "/tellers/" + tellerId + "/cashiers/templates"; + return this; + } + + public CommandWrapperBuilder updateAllocationTeller(final Long tellerId, final Long cashierId) { + this.actionName = "UPDATECASHIERALLOCATION"; + this.entityName = "TELLER"; + this.entityId = tellerId; + this.subentityId = cashierId; + this.href = "/tellers/" + tellerId + "/cashiers/" + cashierId; + return this; + } + + public CommandWrapperBuilder deleteAllocationTeller(final Long tellerId, final Long cashierId) { + this.actionName = "DELETECASHIERALLOCATION"; + this.entityName = "TELLER"; + this.entityId = tellerId; + this.subentityId = cashierId; + this.href = "/tellers/" + tellerId + "/cashiers/" + cashierId; + return this; + } + + public CommandWrapperBuilder allocateCashToCashier(final Long tellerId, final Long cashierId) { + this.actionName = "ALLOCATECASHTOCASHIER"; + this.entityName = "TELLER"; + this.entityId = tellerId; + this.subentityId = cashierId; + this.href = "/tellers/" + tellerId + "/cashiers/" + cashierId + "/allocate"; + return this; + } + + public CommandWrapperBuilder settleCashFromCashier(final Long tellerId, final Long cashierId) { + this.actionName = "SETTLECASHFROMCASHIER"; + this.entityName = "TELLER"; + this.entityId = tellerId; + this.subentityId = cashierId; + this.href = "/tellers/" + tellerId + "/cashiers/" + cashierId + "/settle"; + return this; + } + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java index bb146845e..04975cb79 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java @@ -261,6 +261,26 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer } else { throw new UnsupportedCommandException(wrapper.commandName()); } + } else if (wrapper.isTellerResource()) { + if (wrapper.isCreate()) { + handler = this.applicationContext.getBean("createTellerCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isUpdate()) { + handler = this.applicationContext.getBean("updateTellerCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isDelete()) { + handler = this.applicationContext.getBean("deleteTellerCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isAllocateCashier()) { + handler = this.applicationContext.getBean("allocateCashierToTellerCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isUpdateCashierAllocation()) { + handler = this.applicationContext.getBean("updateCashierAllocationCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isDeleteCashierAllocation()) { + handler = this.applicationContext.getBean("deleteCashierAllocationCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isAllocateCashToCashier()) { + handler = this.applicationContext.getBean("allocateCashToCashierCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isSettleCashFromCashier()) { + handler = this.applicationContext.getBean("settleCashFromCashierCommandHandler", NewCommandSourceHandler.class); + } else { + throw new UnsupportedCommandException(wrapper.commandName()); + } } else if (wrapper.isCollateralResource()) { if (wrapper.isCreate()) { handler = this.applicationContext.getBean("createCollateralCommandHandler", NewCommandSourceHandler.class); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/api/CashierApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/api/CashierApiResource.java new file mode 100644 index 000000000..9b59f50bb --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/api/CashierApiResource.java @@ -0,0 +1,52 @@ +package org.mifosplatform.organisation.teller.api; + +import org.joda.time.format.DateTimeFormatter; +import org.joda.time.format.ISODateTimeFormat; +import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService; +import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer; +import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; +import org.mifosplatform.organisation.teller.data.CashierData; +import org.mifosplatform.organisation.teller.service.TellerManagementReadPlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import java.util.Collection; +import java.util.Date; + +@Path("cashiers") +@Component +@Scope("singleton") +public class CashierApiResource { + + private final PlatformSecurityContext securityContext; + private final DefaultToApiJsonSerializer jsonSerializer; + private final TellerManagementReadPlatformService readPlatformService; + private final PortfolioCommandSourceWritePlatformService commandWritePlatformService; + + @Autowired + public CashierApiResource(PlatformSecurityContext securityContext, DefaultToApiJsonSerializer jsonSerializer, + TellerManagementReadPlatformService readPlatformService, + PortfolioCommandSourceWritePlatformService commandWritePlatformService) { + this.securityContext = securityContext; + this.jsonSerializer = jsonSerializer; + this.readPlatformService = readPlatformService; + this.commandWritePlatformService = commandWritePlatformService; + } + + @GET + @Consumes({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON}) + @Produces(MediaType.APPLICATION_JSON) + public String getCashierData(@QueryParam("officeId") final Long officeId, @QueryParam("tellerId") final Long tellerId, + @QueryParam("staffId") final Long staffId, @QueryParam("date") final String date) { + final DateTimeFormatter dateFormatter = ISODateTimeFormat.basicDate(); + + final Date dateRestriction = (date != null ? dateFormatter.parseDateTime(date).toDate() : new Date()); + + final Collection allCashiers = this.readPlatformService.getCashierData(officeId, tellerId, staffId, dateRestriction); + + return this.jsonSerializer.serialize(allCashiers); + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/api/TellerApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/api/TellerApiResource.java new file mode 100644 index 000000000..d0774aafa --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/api/TellerApiResource.java @@ -0,0 +1,317 @@ +package org.mifosplatform.organisation.teller.api; + +import org.joda.time.format.DateTimeFormatter; +import org.joda.time.format.ISODateTimeFormat; +import org.mifosplatform.commands.domain.CommandWrapper; +import org.mifosplatform.commands.service.CommandWrapperBuilder; +import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer; +import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; +import org.mifosplatform.organisation.teller.data.CashierData; +import org.mifosplatform.organisation.teller.data.CashierTransactionData; +import org.mifosplatform.organisation.teller.data.CashierTransactionsWithSummaryData; +import org.mifosplatform.organisation.teller.data.TellerData; +import org.mifosplatform.organisation.teller.data.TellerJournalData; +import org.mifosplatform.organisation.teller.data.TellerTransactionData; +import org.mifosplatform.organisation.teller.domain.Teller; +import org.mifosplatform.organisation.teller.service.TellerManagementReadPlatformService; +import org.mifosplatform.organisation.teller.util.DateRange; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import java.util.Collection; +import java.util.Date; + +@Path("tellers") +@Component +@Scope("singleton") +public class TellerApiResource { + + private final PlatformSecurityContext securityContext; + private final DefaultToApiJsonSerializer jsonSerializer; + private final TellerManagementReadPlatformService readPlatformService; + private final PortfolioCommandSourceWritePlatformService commandWritePlatformService; + + @Autowired + public TellerApiResource(PlatformSecurityContext securityContext, DefaultToApiJsonSerializer jsonSerializer, + TellerManagementReadPlatformService readPlatformService, PortfolioCommandSourceWritePlatformService commandWritePlatformService) { + super(); + this.securityContext = securityContext; + this.jsonSerializer = jsonSerializer; + this.readPlatformService = readPlatformService; + this.commandWritePlatformService = commandWritePlatformService; + } + + @GET + @Consumes({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON}) + @Produces(MediaType.APPLICATION_JSON) + public String getTellerData(@QueryParam("officeId") final Long officeId) { + final Collection foundTellers = this.readPlatformService.getTellers(officeId); + + return this.jsonSerializer.serialize(foundTellers); + } + + @Path("{tellerId}") + @GET + @Consumes({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON}) + @Produces(MediaType.APPLICATION_JSON) + public String findTeller(@PathParam("tellerId") final Long tellerId) { + final TellerData teller = this.readPlatformService.findTeller(tellerId); + + return this.jsonSerializer.serialize(teller); + } + + @POST + @Consumes({MediaType.APPLICATION_JSON}) + @Produces(MediaType.APPLICATION_JSON) + public String createTeller(final String tellerData) { + final CommandWrapper request = new CommandWrapperBuilder().createTeller().withJson(tellerData).build(); + + final CommandProcessingResult result = this.commandWritePlatformService.logCommandSource(request); + + return this.jsonSerializer.serialize(result); + } + + @Path("{tellerId}") + @PUT + @Consumes({MediaType.APPLICATION_JSON}) + @Produces(MediaType.APPLICATION_JSON) + public String updateTeller(@PathParam("tellerId") final Long tellerId, final String tellerData) { + final CommandWrapper request = new CommandWrapperBuilder().updateTeller(tellerId).withJson(tellerData).build(); + + final CommandProcessingResult result = this.commandWritePlatformService.logCommandSource(request); + + return this.jsonSerializer.serialize(result); + } + + @Path("{tellerId}") + @DELETE + @Consumes({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON}) + @Produces(MediaType.APPLICATION_JSON) + public String deleteTeller(@PathParam("tellerId") final Long tellerId) { + final CommandWrapper request = new CommandWrapperBuilder().deleteTeller(tellerId).build(); + + final CommandProcessingResult result = this.commandWritePlatformService.logCommandSource(request); + + return this.jsonSerializer.serialize(result); + } + + @GET + @Path("{tellerId}/cashiers") + @Consumes({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON}) + @Produces(MediaType.APPLICATION_JSON) + public String getCashierData(@PathParam("tellerId") final Long tellerId, @QueryParam("fromdate") final String fromDateStr, + @QueryParam("todate") final String toDateStr) { + final DateTimeFormatter dateFormatter = ISODateTimeFormat.basicDate(); + + final Date fromDate = (fromDateStr != null ? dateFormatter.parseDateTime(fromDateStr).toDate() : new Date()); + final Date toDate = (toDateStr != null ? dateFormatter.parseDateTime(toDateStr).toDate() : new Date()); + + final TellerData teller = this.readPlatformService.findTeller(tellerId); + final Collection cashiers = this.readPlatformService.getCashiersForTeller(tellerId, fromDate, toDate); + + CashiersForTeller cashiersForTeller = new CashiersForTeller(); + cashiersForTeller.cashiers = cashiers; + cashiersForTeller.tellerId = tellerId; + cashiersForTeller.tellerName = teller.getName(); + cashiersForTeller.officeId = teller.getOfficeId(); + cashiersForTeller.officeName = teller.getOfficeName(); + + return this.jsonSerializer.serialize(cashiersForTeller); + } + + @GET + @Path("{tellerId}/cashiers/{cashierId}") + @Consumes({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON}) + @Produces(MediaType.APPLICATION_JSON) + public String findCashierData(@PathParam("tellerId") final Long tellerId, @PathParam("cashierId") final Long cashierId) { + final CashierData cashier = this.readPlatformService.findCashier(cashierId); + + return this.jsonSerializer.serialize(cashier); + } + + @GET + @Path("{tellerId}/cashiers/template") + @Consumes({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON}) + @Produces(MediaType.APPLICATION_JSON) + public String getCashierTemplate(@PathParam("tellerId") final Long tellerId) { + + final TellerData teller = this.readPlatformService.findTeller(tellerId); + Long officeId = teller.getOfficeId(); + + final CashierData cashier = + this.readPlatformService.retrieveCashierTemplate(officeId, tellerId, true); + + return this.jsonSerializer.serialize(cashier); + } + + @POST + @Path("{tellerId}/cashiers") + @Consumes({MediaType.APPLICATION_JSON}) + @Produces(MediaType.APPLICATION_JSON) + public String createCashier(@PathParam("tellerId") final Long tellerId, final String cashierData) { + final CommandWrapper request = new CommandWrapperBuilder().allocateTeller(tellerId).withJson(cashierData).build(); + + final CommandProcessingResult result = this.commandWritePlatformService.logCommandSource(request); + + return this.jsonSerializer.serialize(result); + } + + @PUT + @Path("{tellerId}/cashiers/{cashierId}") + @Consumes({MediaType.APPLICATION_JSON}) + @Produces(MediaType.APPLICATION_JSON) + public String updateCashier(@PathParam("tellerId") final Long tellerId, @PathParam("cashierId") final Long cashierId, final String cashierDate) { + final CommandWrapper request = new CommandWrapperBuilder().updateAllocationTeller(tellerId, cashierId).withJson(cashierDate).build(); + + final CommandProcessingResult result = this.commandWritePlatformService.logCommandSource(request); + + return this.jsonSerializer.serialize(result); + } + + @DELETE + @Path("{tellerId}/cashiers/{cashierId}") + @Consumes({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON}) + @Produces(MediaType.APPLICATION_JSON) + public String deleteCashier(@PathParam("tellerId") final Long tellerId, @PathParam("cashierId") final Long cashierId) { + final CommandWrapper request = new CommandWrapperBuilder().deleteAllocationTeller(tellerId, cashierId).build(); + + final CommandProcessingResult result = this.commandWritePlatformService.logCommandSource(request); + + return this.jsonSerializer.serialize(result); + } + + @POST + @Path("{tellerId}/cashiers/{cashierId}/allocate") + @Consumes({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON}) + @Produces(MediaType.APPLICATION_JSON) + public String allocateCashToCashier (@PathParam("tellerId") final Long tellerId, @PathParam("cashierId") final Long cashierId, final String cashierTxnData) { + final CommandWrapper request = new CommandWrapperBuilder().allocateCashToCashier(tellerId, cashierId).withJson(cashierTxnData).build(); + + final CommandProcessingResult result = this.commandWritePlatformService.logCommandSource(request); + + return this.jsonSerializer.serialize(result); + + } + + @POST + @Path("{tellerId}/cashiers/{cashierId}/settle") + @Consumes({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON}) + @Produces(MediaType.APPLICATION_JSON) + public String settleCashFromCashier (@PathParam("tellerId") final Long tellerId, @PathParam("cashierId") final Long cashierId, final String cashierTxnData) { + final CommandWrapper request = new CommandWrapperBuilder().settleCashFromCashier(tellerId, cashierId).withJson(cashierTxnData).build(); + + final CommandProcessingResult result = this.commandWritePlatformService.logCommandSource(request); + + return this.jsonSerializer.serialize(result); + + } + + @GET + @Path("{tellerId}/cashiers/{cashierId}/transactions") + @Consumes({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON}) + @Produces(MediaType.APPLICATION_JSON) + public String getTransactionsForCashier (@PathParam("tellerId") final Long tellerId, + @PathParam("cashierId") final Long cashierId, + final String fromDateStr, final String toDateStr) { + final TellerData teller = this.readPlatformService.findTeller(tellerId); + final CashierData cashier = this.readPlatformService.findCashier(cashierId); + + final Date fromDate = null; + final Date toDate = null; + + final Collection cashierTxns = + this.readPlatformService.retrieveCashierTransactions(cashierId, + true, fromDate, toDate); + + return this.jsonSerializer.serialize(cashierTxns); + } + + @GET + @Path("{tellerId}/cashiers/{cashierId}/summaryandtransactions") + @Consumes({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON}) + @Produces(MediaType.APPLICATION_JSON) + public String getTransactionsWtihSummaryForCashier (@PathParam("tellerId") final Long tellerId, + @PathParam("cashierId") final Long cashierId, + final String fromDateStr, final String toDateStr) { + final TellerData teller = this.readPlatformService.findTeller(tellerId); + final CashierData cashier = this.readPlatformService.findCashier(cashierId); + + final Date fromDate = null; + final Date toDate = null; + + final CashierTransactionsWithSummaryData cashierTxnWithSummary = + this.readPlatformService.retrieveCashierTransactionsWithSummary + (cashierId, + true, fromDate, toDate); + + return this.jsonSerializer.serialize(cashierTxnWithSummary); + } + + @GET + @Path("{tellerId}/cashiers/{cashierId}/transactions/template") + @Consumes({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON}) + @Produces(MediaType.APPLICATION_JSON) + public String getCashierTxnTemplate(@PathParam("tellerId") final Long tellerId, @PathParam("cashierId") final Long cashierId) { + + final CashierTransactionData cashierTxnTemplate = + this.readPlatformService.retrieveCashierTxnTemplate(cashierId); + + return this.jsonSerializer.serialize(cashierTxnTemplate); + } + + + + @GET + @Path("{tellerId}/transactions") + @Consumes({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON}) + @Produces(MediaType.APPLICATION_JSON) + public String getTransactionData(@PathParam("tellerId") final Long tellerId, + @QueryParam("dateRange") final String dateRange) { + final DateRange dateRangeHolder = DateRange.fromString(dateRange); + + final Collection transactions = + this.readPlatformService.fetchTellerTransactionsByTellerId(tellerId, dateRangeHolder.getStartDate(), dateRangeHolder.getEndDate()); + + return this.jsonSerializer.serialize(transactions); + } + + @GET + @Path("{tellerId}/transactions/{transactionId}") + @Consumes({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON}) + @Produces(MediaType.APPLICATION_JSON) + public String findTransactionData(@PathParam("tellerId") final Long tellerid, + @PathParam("transactionId") final Long transactionId) { + final TellerTransactionData transaction = this.readPlatformService.findTellerTransaction(transactionId); + + return this.jsonSerializer.serialize(transaction); + } + + @GET + @Path("{tellerId}/journals") + @Consumes({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON}) + @Produces(MediaType.APPLICATION_JSON) + public String getJournalData(@PathParam("tellerId") final Long tellerId, + @QueryParam("cashierId") final Long cashierDate, + @QueryParam("dateRange") final String dateRange) { + final DateRange dateRangeHolder = DateRange.fromString(dateRange); + + final Collection journals = + this.readPlatformService.fetchTellerJournals(tellerId, cashierDate, dateRangeHolder.getStartDate(), dateRangeHolder.getEndDate()); + + return this.jsonSerializer.serialize(journals); + } + + private class CashiersForTeller { + public Long tellerId; + public String tellerName; + public Long officeId; + public String officeName; + public Collection cashiers; + + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/api/TellerJournalApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/api/TellerJournalApiResource.java new file mode 100644 index 000000000..92ad16ea1 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/api/TellerJournalApiResource.java @@ -0,0 +1,46 @@ +package org.mifosplatform.organisation.teller.api; + +import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer; +import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; +import org.mifosplatform.organisation.teller.data.TellerData; +import org.mifosplatform.organisation.teller.data.TellerJournalData; +import org.mifosplatform.organisation.teller.service.TellerManagementReadPlatformService; +import org.mifosplatform.organisation.teller.util.DateRange; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import java.util.Collection; + +@Path("cashiersjournal") +@Component +@Scope("singleton") +public class TellerJournalApiResource { + + private final PlatformSecurityContext securityContext; + private final DefaultToApiJsonSerializer jsonSerializer; + private final TellerManagementReadPlatformService readPlatformService; + + @Autowired + public TellerJournalApiResource(final PlatformSecurityContext securityContext, final DefaultToApiJsonSerializer jsonSerializer, + final TellerManagementReadPlatformService readPlatformService) { + super(); + this.securityContext = securityContext; + this.jsonSerializer = jsonSerializer; + this.readPlatformService = readPlatformService; + } + + @GET + @Consumes({MediaType.TEXT_HTML, MediaType.APPLICATION_JSON}) + @Produces(MediaType.APPLICATION_JSON) + public String getJournalData(@QueryParam("officeId") final Long officeId, @QueryParam("tellerId") final Long tellerId, + @QueryParam("cashierId") final Long cashierId, @QueryParam("dateRange") final String dateRange) { + final DateRange dateRangeHolder = DateRange.fromString(dateRange); + + final Collection journals = this.readPlatformService.getJournals(officeId, tellerId, cashierId, dateRangeHolder.getStartDate(), dateRangeHolder.getEndDate()); + + return this.jsonSerializer.serialize(journals); + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/data/CashierData.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/data/CashierData.java new file mode 100644 index 000000000..39c1fe92d --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/data/CashierData.java @@ -0,0 +1,225 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.data; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Date; + +import org.joda.time.LocalDate; +import org.mifosplatform.infrastructure.codes.data.CodeValueData; +import org.mifosplatform.organisation.office.data.OfficeData; +import org.mifosplatform.organisation.staff.data.StaffData; +import org.mifosplatform.portfolio.client.data.ClientData; +import org.mifosplatform.portfolio.savings.data.SavingsProductData; + +/** + * Represents a cashier, providing access to the cashier's office, staff + * information, teller, and more. + * + * @author Markus Geiss +<<<<<<< HEAD + * @since 2.0.0 + * @see org.mifosplatform.organisation.teller.domain.Cashier + * @since 2.0.0 + */ +public final class CashierData implements Serializable { + + private final Long id; + private final Long tellerId; + private final Long officeId; + private final Long staffId; + private final String description; + private final Date startDate; + private final Date endDate; + private final Boolean isFullDay; + private final String startTime; + private final String endTime; + + // Template fields + private final String officeName; + private final String tellerName; + private final String staffName; + private final Collection staffOptions; + + /* + * Creates a new cashier. + */ + private CashierData(final Long id, final Long officeId, String officeName, + final Long staffId, final String staffName, final Long tellerId, final String tellerName, + final String description, + final Date startDate, final Date endDate, final Boolean isFullDay, + final String startTime, final String endTime, Collection staffOptions) { + this.id = id; + this.officeId = officeId; + this.staffId = staffId; + this.tellerId = tellerId; + this.description = description; + this.startDate = startDate; + this.endDate = endDate; + this.isFullDay = isFullDay; + this.startTime = startTime; + this.endTime = endTime; + + this.officeName = officeName; + this.tellerName = tellerName; + this.staffName = staffName; + this.staffOptions = staffOptions; + + } + + /** + * Creates a new cashier. + *

+ *

The valid from/to dates may be used to define a time period in which + * the cashier is assignable to a teller.

+ *

+ *

The start/end times may be used to define a time period in which + * the cashier works part time.

+ * + * @param id the primary key of this cashier + * @param officeId the primary key of the related office + * @param staffId the primary key of the related staff + * @param tellerId the primary key of the related teller + * @param description the description of this cashier + * @param validFrom the valid from date of this cashier + * @param validTo the valid to date of this cashier + * @param partTime the part time flag of this cashier + * @param startTime the start time of this cashier + * @param endTime the end time of this cashier + * @return the cashier + */ + public static CashierData instance(final Long id, final Long officeId, String officeName, + final Long staffId, final String staffName, final Long tellerId, final String tellerName, + final String description, final Date startDate, final Date endDate, + final Boolean isFullDay, final String startTime, final String endTime) { + return new CashierData(id, officeId, officeName, staffId, staffName, tellerId, tellerName, + description, startDate, endDate, isFullDay, startTime, endTime, null); + } + + /* + * Creates a new cashier. + */ + public static CashierData template (final Long officeId, final String officeName, + final Long tellerId, final String tellerName, final Collection staffOptions) { + return new CashierData(null, officeId, officeName, null, null, tellerId, tellerName, + null, null, null, null, null, null, staffOptions); + } + + /** + * Returns the primary key of this cashier. + * + * @return the primary key of this cashier + */ + public Long getId() { + return id; + } + + /** + * Returns the primary key of this cashiers related office. + * + * @return the primary key of this cashiers related office + */ + public Long getOfficeId() { + return officeId; + } + + /** + * Returns the primary key of this cashiers related staff. + * + * @return the primary key of this cashiers related staff + */ + public Long getStaffId() { + return staffId; + } + + /** + * Returns the primary key of this cashiers related teller. + * + * @return the primary key of this cashiers related teller + */ + public Long getTellerId() { + return tellerId; + } + + /** + * Returns the description of this cashier. + * + * @return the description of this cashier + */ + public String getDescription() { + return description; + } + + /** + * Returns the valid from date of this cashier. + *

+ *

The valid from/to dates may be used to define a time period in which + * the cashier is assignable to a teller.

+ * + * @return the valid from date of this cashier + */ + public Date getStartDate() { + return startDate; + } + + /** + * Returns the valid to date of this cashier. + *

+ *

The valid from/to dates may be used to define a time period in which + * the cashier is assignable to a teller.

+ * + * @return the valid to date of this cashier + */ + public Date getEndDate() { + return endDate; + } + + /** + * Returns whether this cashier works part time or not. + * + * @return {@code true} if this cashier works part time; {@code false} otherwise + */ + public Boolean isFullDay() { + return isFullDay; + } + + /** + * Returns the start time of this cashier. + *

+ *

The start/end times may be used to define a time period in which + * the cashier works part time.

+ * + * @return the start time of this cashier + */ + public String getStartTime() { + return startTime; + } + + /** + * Returns the end time of this cashier. + *

+ *

The start/end times may be used to define a time period in which + * the cashier works part time.

+ * + * @return the start time of this cashier + */ + public String getEndTime() { + return endTime; + } + + public String getOfficeName() { + return officeName; + } + + public String getTellerName() { + return tellerName; + } + + public String getStaffName() { + return staffName; + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/data/CashierTransactionData.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/data/CashierTransactionData.java new file mode 100644 index 000000000..6a43bf0ea --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/data/CashierTransactionData.java @@ -0,0 +1,161 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.data; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Collection; +import java.util.Date; + +import org.joda.time.LocalDate; +import org.mifosplatform.infrastructure.codes.data.CodeValueData; +import org.mifosplatform.organisation.office.data.OfficeData; +import org.mifosplatform.organisation.staff.data.StaffData; +import org.mifosplatform.organisation.teller.domain.CashierTxnType; +import org.mifosplatform.portfolio.client.data.ClientData; +import org.mifosplatform.portfolio.savings.data.SavingsProductData; + +public final class CashierTransactionData implements Serializable { + + private final Long id; + private final Long cashierId; + private final CashierTxnType txnType; + private final BigDecimal txnAmount; + private final Date txnDate; + private final Long entityId; + private final String entityType; + private final String txnNote; + private final Date createdDate; + + // Template fields + private final Long officeId; + private final String officeName; + private final Long tellerId; + private final String tellerName; + private final String cashierName; + + private final CashierData cashierData; + private final Date startDate; + private final Date endDate; + + /* + * Creates a new cashier. + */ + private CashierTransactionData(final Long id, final Long cashierId, CashierTxnType txnType, + final BigDecimal txnAmount, final Date txnDate, String txnNote, + String entityType, Long entityId, Date createdDate, + Long officeId, String officeName, Long tellerId, String tellerName, String cashierName, + CashierData cashierData, Date startDate, Date endDate ) { + this.id = id; + this.cashierId = cashierId; + this.txnType = txnType; + this.txnAmount = txnAmount; + this.txnDate = txnDate; + this.txnNote = txnNote; + this.entityType = entityType; + this.entityId = entityId; + this.createdDate = createdDate; + + this.officeId = officeId; + this.officeName = officeName; + this.tellerId = tellerId; + this.tellerName = tellerName; + this.cashierName = cashierName; + this.cashierData = cashierData; + + this.startDate = startDate; + this.endDate = endDate; + } + + public static CashierTransactionData instance(final Long id, final Long cashierId, CashierTxnType txnType, + final BigDecimal txnAmount, final Date txnDate, final String txnNote, + final String entityType, final Long entityId, final Date createdDate, + final Long officeId, final String officeName, final Long tellerId, + final String tellerName, final String cashierName, final CashierData cashierData, + Date startDate, Date endDate) { + return new CashierTransactionData(id, cashierId, txnType, txnAmount, txnDate, txnNote, entityType, + entityId, createdDate, officeId, officeName, tellerId, + tellerName, cashierName, cashierData, startDate, endDate); + } + + public static CashierTransactionData template (final Long cashierId, + final Long tellerId, final String tellerName, + final Long officeId, final String officeName, final String cashierName, + final CashierData cashierData, Date startDate, Date endDate) { + return new CashierTransactionData(null, cashierId, null, null, null, null, null, + null, null, officeId, officeName, tellerId, tellerName, cashierName, cashierData, + startDate, endDate); + } + + public Long getId() { + return id; + } + + public Long getCashierId() { + return cashierId; + } + + public CashierTxnType getTxnType() { + return txnType; + } + + public BigDecimal getTxnAmount() { + return txnAmount; + } + + public Date getTxnDate() { + return txnDate; + } + + public String getTxnNote() { + return txnNote; + } + + public String getEntityType() { + return entityType; + } + + public Long getEntityId() { + return entityId; + } + + public Date getCreatedDate() { + return createdDate; + } + + public Long getOfficeId() { + return officeId; + } + + public String getOfficeName() { + return officeName; + } + + public Long getTellerId() { + return tellerId; + } + + public String getTellerName() { + return tellerName; + } + + public String getCashierName() { + return cashierName; + } + + public Date getStartDate() { + return startDate; + } + + public Date getEndDate() { + return endDate; + } + + public CashierData getCashierData() { + return cashierData; + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/data/CashierTransactionTypeTotalsData.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/data/CashierTransactionTypeTotalsData.java new file mode 100644 index 000000000..f93627b1b --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/data/CashierTransactionTypeTotalsData.java @@ -0,0 +1,39 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.data; + +import java.io.Serializable; +import java.math.BigDecimal; + +public final class CashierTransactionTypeTotalsData implements Serializable { + private final Integer cashierTxnType; + private final BigDecimal cashTotal; + + private CashierTransactionTypeTotalsData ( + final Integer cashierTxnType, + final BigDecimal cashTotal + ) { + this.cashierTxnType = cashierTxnType; + this.cashTotal = cashTotal; + } + + public static CashierTransactionTypeTotalsData instance( + final Integer cashierTxnType, + final BigDecimal cashTotal + ) { + return new CashierTransactionTypeTotalsData( + cashierTxnType, cashTotal); + } + + public Integer getCashierTxnType() { + return cashierTxnType; + } + + public BigDecimal getCashTotal() { + return cashTotal; + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/data/CashierTransactionsWithSummaryData.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/data/CashierTransactionsWithSummaryData.java new file mode 100644 index 000000000..12828da14 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/data/CashierTransactionsWithSummaryData.java @@ -0,0 +1,122 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.data; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Collection; + +public final class CashierTransactionsWithSummaryData implements Serializable { + + private final BigDecimal sumCashAllocation; + private final BigDecimal sumInwardCash; + private final BigDecimal sumOutwardCash; + private final BigDecimal sumCashSettlement; + private final BigDecimal netCash; + private final String officeName; + private final long tellerId; + private final String tellerName; + private final long cashierId; + private final String cashierName; + + private final Collection cashierTransactions; + + private CashierTransactionsWithSummaryData( + final Collection cashierTransactions, + final BigDecimal sumCashAllocation, + final BigDecimal sumInwardCash, + final BigDecimal sumOutwardCash, + final BigDecimal sumCashSettlement, + final BigDecimal netCash, + final String officeName, + final Long tellerId, + final String tellerName, + final Long cashierId, + final String cashierName + ) { + this.cashierTransactions = cashierTransactions; + this.sumCashAllocation = sumCashAllocation; + this.sumInwardCash = sumInwardCash; + this.sumOutwardCash = sumOutwardCash; + this.sumCashSettlement = sumCashSettlement; + this.netCash = netCash; + this.officeName = officeName; + this.tellerId = tellerId; + this.tellerName = tellerName; + this.cashierId = cashierId; + this.cashierName = cashierName; + } + + public static CashierTransactionsWithSummaryData instance( + final Collection cashierTransactions, + final BigDecimal sumCashAllocation, + final BigDecimal sumInwardCash, + final BigDecimal sumOutwardCash, + final BigDecimal sumCashSettlement, + final String officeName, + final Long tellerId, + final String tellerName, + final Long cashierId, + final String cashierName + ) { + + final BigDecimal netCash = + sumCashAllocation.add(sumInwardCash). + subtract(sumOutwardCash). + subtract(sumCashSettlement); + return new CashierTransactionsWithSummaryData( + cashierTransactions, + sumCashAllocation, + sumInwardCash, + sumOutwardCash, + sumCashSettlement, netCash, + officeName, tellerId, tellerName, cashierId, cashierName); + } + + public BigDecimal getSumCashAllocation() { + return sumCashAllocation; + } + + public BigDecimal getSumInwardCash() { + return sumInwardCash; + } + + public BigDecimal getSumOutwardCash() { + return sumOutwardCash; + } + + public BigDecimal getSumCashSettlement() { + return sumCashSettlement; + } + + public BigDecimal getNetCash() { + return netCash; + } + + public String getOfficeName() { + return officeName; + } + + public Long getTellerId() { + return tellerId; + } + + public String getTellerName() { + return tellerName; + } + + public Long getCashierId() { + return cashierId; + } + + public String getCashierName() { + return cashierName; + } + public Collection getCashierTransactions() { + return cashierTransactions; + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/data/TellerData.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/data/TellerData.java new file mode 100644 index 000000000..b7f061a1b --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/data/TellerData.java @@ -0,0 +1,147 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.data; + +import org.joda.time.LocalDate; +import org.mifosplatform.infrastructure.core.data.EnumOptionData; +import org.mifosplatform.organisation.office.data.OfficeData; +import org.mifosplatform.organisation.staff.data.StaffData; +import org.mifosplatform.organisation.teller.domain.TellerStatus; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Date; + +/** + * {@code TellerData} represents an immutable data object for teller data. + * + * @version 1.0 +<<<<<<< HEAD + * @since 2.0.0 + * @see java.io.Serializable + * @since 2.0.0 + */ +public final class TellerData implements Serializable { + + private final Long id; + private final Long officeId; + private final Long debitAccountId; + private final Long creditAccountId; + private final String name; + + private final String description; + private final LocalDate startDate; + private final LocalDate endDate; + private final TellerStatus status; + private final Boolean hasTransactions; + private final Boolean hasMappedCashiers; + + private String officeName; + + private final Collection officeOptions; + private final Collection staffOptions; + + /* + * Sole private CTOR to create a new instance. + */ + private TellerData(final Long id, final Long officeId, final Long debitAccountId, final Long creditAccountId, + final String name, final String description, final LocalDate startDate, final LocalDate endDate, + final TellerStatus status, final Boolean hasTransactions, final Boolean hasMappedCashiers) { + super(); + this.id = id; + this.officeId = officeId; + this.debitAccountId = debitAccountId; + this.creditAccountId = creditAccountId; + this.name = name; + this.description = description; + this.startDate = startDate; + this.endDate = endDate; + this.status = status; + this.hasTransactions = hasTransactions; + this.hasMappedCashiers = hasMappedCashiers; + this.officeOptions = null; + this.staffOptions = null; + } + + /** + * Creates a new teller data object. + * + * @param id - id of the teller + * @param officeId - id of the related office + * @param debitAccountId - id of the debit account to use + * @param creditAccountId - id of the credit account to use + * @param name - name of the teller + * @param description - description of the teller + * @param startDate - date when the teller becomes available + * @param endDate - date when the teller becomes unavailable + * @param status - current state of the teller, eg. active, inactive, pending + * @param hasTransactions - indicates that this teller already is used to perform postings + * @param hasMappedCashiers - indicates that the teller already has @code Cashier}s assigned to it + * @return the new created {@code TellerData} + */ + public static TellerData instance(final Long id, final Long officeId, final Long debitAccountId, + final Long creditAccountId, final String name, final String description, + final LocalDate startDate, final LocalDate endDate, final TellerStatus status, + final String officeName, + final Boolean hasTransactions, final Boolean hasMappedCashiers) { + TellerData tellerData = new TellerData(id, officeId, debitAccountId, creditAccountId, name, description, startDate, endDate, + status, hasTransactions, hasMappedCashiers); + tellerData.officeName = officeName; + return tellerData; + } + + public static TellerData lookup(final Long id, final String name) { + return new TellerData(id, null, null, null, name, null, null, null, null, null, null); + } + + public Long getId() { + return this.id; + } + + public Long getOfficeId() { + return this.officeId; + } + + public Long getDebitAccountId() { + return this.debitAccountId; + } + + public Long getCreditAccountId() { + return this.creditAccountId; + } + + public String getName() { + return this.name; + } + + public String getOfficeName() { + return this.officeName; + } + + public String getDescription() { + return this.description; + } + + public LocalDate getStartDate() { + return this.startDate; + } + + public LocalDate getEndDate() { + return this.endDate; + } + + public TellerStatus getStatus() { + return this.status; + } + + public Boolean hasTransactions() { + return this.hasTransactions; + } + + public Boolean hasMappedCashiers() { + return this.hasMappedCashiers; + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/data/TellerJournalData.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/data/TellerJournalData.java new file mode 100644 index 000000000..3fc1d4f3c --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/data/TellerJournalData.java @@ -0,0 +1,99 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.data; + +import java.io.Serializable; +import java.util.Date; + +/** + * {@code TellerJournalData} represents an immutable journal data object. + * + * @version 1.0.0 +<<<<<<< HEAD + * @since 2.0.0 + * @see java.io.Serializable + * @since 2.0.0 + */ +public final class TellerJournalData implements Serializable { + + private final Long officeId; + private final Long tellerId; + private final Date day; + private final Double openingBalance; + private final Double settledBalance; + private final Double closingBalance; + private final Double sumReceipts; + private final Double sumPayments; + + /* + * Sole private CTOR to create a new instance. + */ + private TellerJournalData(final Long officeId, final Long tellerId, final Date day, final Double openingBalance, + final Double settledBalance, final Double closingBalance, final Double sumReceipts, + final Double sumPayments) { + this.officeId = officeId; + this.tellerId = tellerId; + this.day = day; + this.openingBalance = openingBalance; + this.settledBalance = settledBalance; + this.closingBalance = closingBalance; + this.sumReceipts = sumReceipts; + this.sumPayments = sumPayments; + } + + /** + * Create a new teller journal data object. + * + * @param officeId - id of related office + * @param tellerId - id of related teller + * @param day - day of this journals data + * @param openingBalance - balance at the time of opening the teller + * @param settledBalance - balance at the time od settling the teller + * @param closingBalance - balance at the time of closing the teller + * @param sumReceipts - sum of all posted receipts + * @param sumPayments - sum of all posted payments + * @return the new created {@code TellerJournalData} + */ + public static TellerJournalData instance(final Long officeId, final Long tellerId, final Date day, + final Double openingBalance, final Double settledBalance, + final Double closingBalance, final Double sumReceipts, + final Double sumPayments) { + return new TellerJournalData(officeId, tellerId, day, openingBalance, settledBalance, closingBalance, sumReceipts, + sumPayments); + } + + public Long getOfficeId() { + return officeId; + } + + public Long getTellerId() { + return tellerId; + } + + public Date getDay() { + return day; + } + + public Double getOpeningBalance() { + return openingBalance; + } + + public Double getSettledBalance() { + return settledBalance; + } + + public Double getClosingBalance() { + return closingBalance; + } + + public Double getSumReceipts() { + return sumReceipts; + } + + public Double getSumPayments() { + return sumPayments; + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/data/TellerTransactionData.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/data/TellerTransactionData.java new file mode 100644 index 000000000..f81ad52f4 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/data/TellerTransactionData.java @@ -0,0 +1,99 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.data; + +import org.mifosplatform.infrastructure.core.data.EnumOptionData; + +import java.io.Serializable; +import java.util.Date; + +/** + * {@code TellerTransactionData} represents an immutable data object for a transction. + * + * @version 1.0.0 +<<<<<<< HEAD + * @since 2.0.0 + * @see java.io.Serializable + * @since 2.0.0 + */ +public final class TellerTransactionData implements Serializable { + + private final Long id; + private final Long officeId; + private final Long tellerId; + private final Long cashierId; + private final Long clientId; + private final EnumOptionData type; + private final Double amount; + private final Date postingDate; + + /* + * Sole private CTOR to create a new instance + */ + private TellerTransactionData(final Long id, final Long officeId, final Long tellerId, final Long cashierId, + final Long clientId, final EnumOptionData type, final Double amount, + final Date postingDate) { + this.id = id; + this.officeId = officeId; + this.tellerId = tellerId; + this.cashierId = cashierId; + this.clientId = clientId; + this.type = type; + this.amount = amount; + this.postingDate = postingDate; + } + + /** + * Creates a new teller transaction data object. + * + * @param id - id of the transaction + * @param officeId - id of the related office + * @param tellerId - id of the related teller + * @param cashierId - id of the cashier + * @param clientId - id of the client + * @param type - type of transaction (eg receipt, payment, open, close, settle) + * @param amount - amount of the transaction + * @param postingDate - posting date of the transaction + * @return the new created {@code TellerTransactionData} + */ + public static TellerTransactionData instance(final Long id, final Long officeId, final Long tellerId, final Long cashierId, + final Long clientId, final EnumOptionData type, final Double amount, + final Date postingDate) { + return new TellerTransactionData(id, officeId, tellerId, cashierId, clientId, type, amount, postingDate); + } + + public Long getId() { + return id; + } + + public Long getOfficeId() { + return officeId; + } + + public Long getTellerId() { + return tellerId; + } + + public Long getCashierId() { + return cashierId; + } + + public Long getClientId() { + return clientId; + } + + public EnumOptionData getType() { + return type; + } + + public Double getAmount() { + return amount; + } + + public Date getPostingDate() { + return postingDate; + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/Cashier.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/Cashier.java new file mode 100644 index 000000000..a3848ee49 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/Cashier.java @@ -0,0 +1,376 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.domain; + + +import org.joda.time.LocalDate; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.organisation.office.domain.Office; +import org.mifosplatform.organisation.staff.domain.Staff; +import org.springframework.data.jpa.domain.AbstractPersistable; + +import javax.persistence.*; +import java.util.Date; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Provides the base model for a cashier. Represents a row in the "m_cashiers" database table, with + * each column mapped to a property of this class. + * + * @author Markus Geiss + * @since 2.0.0 + */ +@Entity +@Table(name = "m_cashiers", uniqueConstraints = { + @UniqueConstraint(name = "ux_cashiers_staff_teller", columnNames = {"staff_id", "teller_id"}) +}) +public class Cashier extends AbstractPersistable { + + // ManyToOne(fetch = FetchType.LAZY) + // JoinColumn(name = "office_id", nullable = false) + @Transient + private Office office; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "staff_id", nullable = false) + private Staff staff; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "teller_id", nullable = false) + private Teller teller; + + @Column(name = "description", nullable = true, length = 500) + private String description; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "start_date", nullable = false) + private Date startDate; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "end_date", nullable = false) + private Date endDate; + + @Column(name = "full_day", nullable = true) + private Boolean isFullDay; + + @Column(name = "start_time", nullable = true, length = 10) + private String startTime; + + @Column(name = "end_time", nullable = true, length = 10) + private String endTime; + + /** + * Creates a new cashier. + */ + public Cashier() { + super(); + } + + public static Cashier fromJson(final Office cashierOffice, + final Teller teller, + final Staff staff, + final JsonCommand command) { + // final Long tellerId = teller.getId(); + // final Long staffId = command.longValueOfParameterNamed("staffId"); + final String description = command.stringValueOfParameterNamed("description"); + final LocalDate startDate = command.localDateValueOfParameterNamed("startDate"); + final LocalDate endDate = command.localDateValueOfParameterNamed("endDate"); + final Boolean isFullDay = command.booleanObjectValueOfParameterNamed("isFullDay"); + final String startTime = command.stringValueOfParameterNamed("startTime"); + final String endTime = command.stringValueOfParameterNamed("endTime"); + + return new Cashier (cashierOffice, teller, staff, description, startDate, endDate, + isFullDay, startTime, endTime); + } + + public Cashier (Office office, Teller teller, Staff staff, + String description, LocalDate startDate, LocalDate endDate, + Boolean isFullDay, String startTime, String endTime) { + this.office = office; + this.teller = teller; + this.staff = staff; + this.description = description; + this.startDate = startDate.toDate(); + this.endDate = endDate.toDate(); + this.isFullDay = isFullDay; + this.startTime = startTime; + this.endTime = endTime; + } + + public Map update(final JsonCommand command) { + + final Map actualChanges = new LinkedHashMap<>(7); + + final String dateFormatAsInput = command.dateFormat(); + final String localeAsInput = command.locale(); + + final String descriptionParamName = "description"; + if (command.isChangeInStringParameterNamed(descriptionParamName, this.description)) { + final String newValue = command.stringValueOfParameterNamed(descriptionParamName); + actualChanges.put(descriptionParamName, newValue); + this.description = newValue; + } + + final String startDateParamName = "startDate"; + if (command.isChangeInLocalDateParameterNamed(startDateParamName, getStartLocalDate())) { + final String valueAsInput = command.stringValueOfParameterNamed(startDateParamName); + actualChanges.put(startDateParamName, valueAsInput); + actualChanges.put("dateFormat", dateFormatAsInput); + actualChanges.put("locale", localeAsInput); + + final LocalDate newValue = command.localDateValueOfParameterNamed(startDateParamName); + this.startDate = newValue.toDate(); + } + + final String endDateParamName = "endDate"; + if (command.isChangeInLocalDateParameterNamed(endDateParamName, getEndLocalDate())) { + final String valueAsInput = command.stringValueOfParameterNamed(endDateParamName); + actualChanges.put(endDateParamName, valueAsInput); + actualChanges.put("dateFormat", dateFormatAsInput); + actualChanges.put("locale", localeAsInput); + + final LocalDate newValue = command.localDateValueOfParameterNamed(endDateParamName); + this.endDate = newValue.toDate(); + } + + final Boolean isFullDay = command.booleanObjectValueOfParameterNamed("isFullDay"); + + final String isFullDayParamName = "isFullDay"; + if (command.isChangeInBooleanParameterNamed(isFullDayParamName, this.isFullDay)) { + final Boolean newValue = command.booleanObjectValueOfParameterNamed(isFullDayParamName); + actualChanges.put(isFullDayParamName, newValue); + this.isFullDay = newValue; + } + + final String startTimeParamName = "startTime"; + if (command.isChangeInStringParameterNamed(startTimeParamName, this.startTime)) { + final String newValue = command.stringValueOfParameterNamed(startTimeParamName); + actualChanges.put(startTimeParamName, newValue); + this.startTime = newValue; + } + + final String endTimeParamName = "endTime"; + if (command.isChangeInStringParameterNamed(endTimeParamName, this.endTime)) { + final String newValue = command.stringValueOfParameterNamed(endTimeParamName); + actualChanges.put(endTimeParamName, newValue); + this.endTime = newValue; + } + + return actualChanges; + } + + + + /** + * Returns the office of this cashier. + * + * @return the office of this cashier + * @see org.mifosplatform.organisation.office.domain.Office + */ + public Office getOffice() { + return office; + } + + /** + * Sets the office of this cashier. + * + * @param office the office of this cashier + * @see org.mifosplatform.organisation.office.domain.Office + */ + public void setOffice(Office office) { + this.office = office; + } + + /** + * Returns the staff of this cashier. + * + * @return the staff of this cashier + * @see org.mifosplatform.organisation.staff.domain.Staff + */ + public Staff getStaff() { + return staff; + } + + /** + * Sets the staff of this cashier. + * + * @param staff the staff of this cashier + * @see org.mifosplatform.organisation.staff.domain.Staff + */ + public void setStaff(Staff staff) { + this.staff = staff; + } + + /** + * Returns the teller of this cashier. + * + * @return the teller of this cashier + * @see org.mifosplatform.organisation.teller.domain.Teller + */ + public Teller getTeller() { + return teller; + } + + /** + * Sets the teller of this cashier. + * + * @param teller the teller of this cashier + * @see org.mifosplatform.organisation.teller.domain.Teller + */ + public void setTeller(Teller teller) { + this.teller = teller; + } + + /** + * Returns the description of this cashier. + * . + * + * @return the description of this cashier or {@code null} if not present. + */ + public String getDescription() { + return description; + } + + /** + * Sets the description of this cashier. + * + * @param description the description of this cashier + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * Returns the valid from date of this cashier. + *

+ *

The valid from/to dates may be used to define a time period in which + * the cashier is assignable to a teller.

+ * + * @return the valid from date of this cashier + */ + public Date getStartDate() { + return startDate; + } + + public LocalDate getStartLocalDate() { + LocalDate startLocalDate = null; + if (this.startDate != null) { + startLocalDate = LocalDate.fromDateFields(this.startDate); + } + return startLocalDate; + } + + /** + * Sets the valid from date of this cashier. + *

+ *

The valid from/to dates may be used to define a time period in which + * the cashier is assignable to a teller.

+ * + * @param validFrom the valid from date of this cashier + */ + public void setStartDate(Date startDate) { + this.startDate = startDate; + } + + /** + * Returns the valid to date of this cashier. + *

+ *

The valid from/to dates may be used to define a time period in which + * the cashier is assignable to a teller.

+ * + * @return the valid to date of this cashier + */ + public Date getEndDate() { + return endDate; + } + + public LocalDate getEndLocalDate() { + LocalDate endLocalDate = null; + if (this.endDate != null) { + endLocalDate = LocalDate.fromDateFields(this.endDate); + } + return endLocalDate; + } + + /** + * Sets the valid to date of this cashier. + *

+ *

The valid from/to dates may be used to define a time period in which + * the cashier is assignable to a teller.

+ * + * @param validTo the valid to date of this cashier + */ + public void setEndDate(Date endDate) { + this.endDate = endDate; + } + + /** + * Returns whether this cashier works part time or not. + * + * @return {@code true} if this cashier works part time; {@code false} otherwise + */ + public Boolean isFullDay() { + return isFullDay; + } + + /** + * Sets the part time flag of this cashier. + * + * @param partTime the part time flag of this cashier + */ + public void setFullDay (Boolean isFullDay) { + this.isFullDay = isFullDay; + } + + /** + * Returns the start time of this cashier. + *

+ *

The start/end times may be used to define a time period in which + * the cashier works part time.

+ * + * @return the start time of this cashier + */ + public String getStartTime() { + return startTime; + } + + /** + * Set the start time of this cashier. + *

+ *

The start/end times may be used to define a time period in which + * the cashier works part time.

+ * + * @param startTime the start time of this cashier + */ + public void setStartTime(String startTime) { + this.startTime = startTime; + } + + /** + * Returns the end time of this cashier. + *

+ *

The start/end times may be used to define a time period in which + * the cashier works part time.

+ * + * @return the end time of this cashier + */ + public String getEndTime() { + return endTime; + } + + /** + * Sets the end time of this cashier. + *

+ *

The start/end times may be used to define a time period in which + * the cashier works part time.

+ * + * @param endTime the end time of this cashier + */ + public void setEndTime(String endTime) { + this.endTime = endTime; + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/CashierRepository.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/CashierRepository.java new file mode 100644 index 000000000..7499c14d3 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/CashierRepository.java @@ -0,0 +1,20 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.domain; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +/** + * Provides the domain repository for accessing, adding, modifying or deleting cashiers. + * + * @author Markus Geiss + * @see org.mifosplatform.organisation.teller.domain.Cashier + * @since 2.0.0 + */ +public interface CashierRepository extends JpaRepository, JpaSpecificationExecutor { + // no added behavior +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/CashierTransaction.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/CashierTransaction.java new file mode 100644 index 000000000..2cd8e2687 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/CashierTransaction.java @@ -0,0 +1,247 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.domain; + + +import org.joda.time.LocalDate; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.organisation.office.domain.Office; +import org.springframework.data.jpa.domain.AbstractPersistable; + +import javax.persistence.*; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.LinkedHashMap; +import java.util.Map; + +@Entity +@Table(name = "m_cashier_transactions") +public class CashierTransaction extends AbstractPersistable { + + @Transient + private Office office; + + @Transient + private Teller teller; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "cashier_id", nullable = false) + private Cashier cashier; + + @Column(name = "txn_type", nullable = false) + private Integer txnType; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "txn_date", nullable = false) + private Date txnDate; + + @Column(name = "txn_amount", scale = 6, precision = 19, nullable = false) + private BigDecimal txnAmount; + + @Column(name = "txn_note", nullable = true) + private String txnNote; + + @Column(name = "entity_type", nullable = false) + private String entityType; + + @Column(name = "entity_id", nullable = false) + private Long entityId; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "created_date", nullable = false) + private Date createdDate; + + /** + * Creates a new cashier. + */ + public CashierTransaction() { + super(); + } + + public static CashierTransaction fromJson( + final Cashier cashier, + final JsonCommand command) { + final Integer txnType = command.integerValueOfParameterNamed("txnType"); + final BigDecimal txnAmount = command.bigDecimalValueOfParameterNamed("txnAmount"); + final LocalDate txnDate = command.localDateValueOfParameterNamed("txnDate"); + final String entityType = command.stringValueOfParameterNamed("entityType"); + final String txnNote = command.stringValueOfParameterNamed("txnNote"); + final Long entityId = command.longValueOfParameterNamed("entityId"); + + // TODO: get client/loan/savings details + return new CashierTransaction (cashier, txnType, txnAmount, txnDate, + entityType, entityId, txnNote); + + } + + public CashierTransaction (Cashier cashier, Integer txnType, BigDecimal txnAmount, + LocalDate txnDate, String entityType, Long entityId, String txnNote) { + this.cashier = cashier; + this.txnType = txnType; + if (txnDate != null) { + this.txnDate = txnDate.toDate(); + } + this.txnAmount = txnAmount; + this.entityType = entityType; + this.entityId = entityId; + this.txnNote = txnNote; + this.createdDate = new Date(); + } + + public Map update(final JsonCommand command) { + + final Map actualChanges = new LinkedHashMap<>(7); + + final String dateFormatAsInput = command.dateFormat(); + final String localeAsInput = command.locale(); + + final String txnTypeParamName = "txnType"; + if (command.isChangeInIntegerParameterNamed(txnTypeParamName, this.txnType)) { + final Integer newValue = command.integerValueOfParameterNamed(txnTypeParamName); + actualChanges.put(txnTypeParamName, newValue); + this.txnType = newValue; + } + + final String txnDateParamName = "txnDate"; + if (command.isChangeInLocalDateParameterNamed(txnDateParamName, getTxnLocalDate())) { + final String valueAsInput = command.stringValueOfParameterNamed(txnDateParamName); + actualChanges.put(txnDateParamName, valueAsInput); + actualChanges.put("dateFormat", dateFormatAsInput); + actualChanges.put("locale", localeAsInput); + + final LocalDate newValue = command.localDateValueOfParameterNamed(txnDateParamName); + this.txnDate = newValue.toDate(); + } + + final String txnAmountParamName = "txnAmount"; + if (command.isChangeInBigDecimalParameterNamed(txnAmountParamName, this.txnAmount)) { + final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(txnAmountParamName); + actualChanges.put(txnAmountParamName, newValue); + this.txnAmount = newValue; + } + + final String txnNoteParamName = "txnNote"; + if (command.isChangeInStringParameterNamed(txnNoteParamName, this.txnNote)) { + final String newValue = command.stringValueOfParameterNamed(txnNoteParamName); + actualChanges.put(txnNoteParamName, newValue); + this.txnNote = newValue; + } + + return actualChanges; + } + + + /** + * Returns the office of this cashier transaction. + * + * @return the office of this cashier transaction + * @see org.mifosplatform.organisation.office.domain.Office + */ + public Office getOffice() { + return office; + } + + /** + * Sets the office of this cashier transaction. + * + * @param office the office of this cashier transaction + * @see org.mifosplatform.organisation.office.domain.Office + */ + public void setOffice(Office office) { + this.office = office; + } + + /** + * Returns the teller of this cashier transaction. + * + * @return the teller of this cashier transaction + * @see org.mifosplatform.organisation.teller.domain.Teller + */ + public Teller getTeller() { + return teller; + } + + /** + * Sets the teller of this cashier transaction. + * + * @param teller the teller of this cashier transaction + * @see org.mifosplatform.organisation.teller.domain.Teller + */ + public void setTeller(Teller teller) { + this.teller = teller; + } + + /** + * Returns the transaction type of this cashier transaction. + * . + * + * @return the transaction type of this cashier transaction or {@code null} if not present. + */ + public Integer getTxnType() { + return txnType; + } + + /** + * Sets the transaction type of this cashier transaction. + * + * @param description the transaction type of this cashier transaction + */ + public void setTxnType(Integer txnType) { + this.txnType = txnType; + } + + /** + * Returns the transaction date of this cashier transaction. + * + * @return the transaction date of this cashier transaction + */ + public Date getTxnDate() { + return txnDate; + } + + public LocalDate getTxnLocalDate() { + LocalDate txnLocalDate = null; + if (this.txnDate != null) { + txnLocalDate = LocalDate.fromDateFields(this.txnDate); + } + return txnLocalDate; + } + + /** + * Sets the transaction date of this cashier transaction. + * + * @param transaction date of this cashier transaction + */ + public void setTxnDate(Date txnDate) { + this.txnDate = txnDate; + } + + public String getEntityType() { + return entityType; + } + + public void setEntityType(String entityType) { + this.entityType = entityType; + } + + public Long getEntityId() { + return entityId; + } + + public void setEntityId(Long entityId) { + this.entityId = entityId; + } + + public String getTxnNote() { + return txnNote; + } + + public void setTxnNote (String txnNote) { + this.txnNote = txnNote; + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/CashierTransactionRepository.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/CashierTransactionRepository.java new file mode 100644 index 000000000..66192e485 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/CashierTransactionRepository.java @@ -0,0 +1,13 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.domain; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +public interface CashierTransactionRepository extends JpaRepository, JpaSpecificationExecutor { + // no added behavior +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/CashierTxnType.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/CashierTxnType.java new file mode 100644 index 000000000..d686addb9 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/CashierTxnType.java @@ -0,0 +1,48 @@ +package org.mifosplatform.organisation.teller.domain; + +import java.util.HashMap; + +public class CashierTxnType { + + private Integer id; + private String value; + + public static CashierTxnType ALLOCATE = new CashierTxnType (101, "Allocate Cash"); + public static CashierTxnType SETTLE = new CashierTxnType (102, "Settle Cash"); + public static CashierTxnType INWARD_CASH_TXN = new CashierTxnType (103, "Cash In"); + public static CashierTxnType OUTWARD_CASH_TXN = new CashierTxnType (104, "Cash Out"); + + private CashierTxnType () { + } + + private CashierTxnType (Integer id, String value) { + this.id = id; + this.value = value; + } + + public Integer getId () { + return id; + } + + public String getValue () { + return value; + } + + public static CashierTxnType getCashierTxnType (Integer id) { + CashierTxnType retVal = null; + + switch(id) { + case 101: + retVal = ALLOCATE; break; + case 102: + retVal = SETTLE; break; + case 103: + retVal = INWARD_CASH_TXN; break; + case 104: + retVal = OUTWARD_CASH_TXN; break; + default: + break; + } + return retVal; + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/Teller.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/Teller.java new file mode 100644 index 000000000..a17caa4cd --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/Teller.java @@ -0,0 +1,276 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.domain; + +import org.apache.commons.lang.StringUtils; +import org.joda.time.LocalDate; +import org.mifosplatform.accounting.glaccount.domain.GLAccount; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.organisation.office.domain.Office; +import org.mifosplatform.organisation.office.exception.RootOfficeParentCannotBeUpdated; +import org.springframework.data.jpa.domain.AbstractPersistable; + +import javax.persistence.*; + +import java.util.Date; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +@Entity +@Table(name = "m_tellers", uniqueConstraints = { + @UniqueConstraint(name = "ux_tellers_name", columnNames = {"name"}) +}) +public class Teller extends AbstractPersistable { + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "office_id", nullable = false) + private Office office; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "debit_account_id", nullable = false) + private GLAccount debitAccount; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "credit_account_id", nullable = false) + private GLAccount creditAccount; + + @Column(name = "name", nullable = false, length = 100) + private String name; + + @Column(name = "description", nullable = true, length = 500) + private String description; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "valid_from", nullable = false) + private Date startDate; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "valid_to", nullable = false) + private Date endDate; + + @Column(name = "state", nullable = false) + private Integer status; + + @OneToMany(mappedBy = "teller", fetch = FetchType.LAZY) + private Set cashiers; + + @OneToMany(mappedBy = "teller", fetch = FetchType.LAZY) + private Set tellerTransactions; + + public Teller() { + super(); + } + + private Teller (final Office staffOffice, final String name, final String description, final LocalDate startDate, + final LocalDate endDate, final TellerStatus status) { + + this.name = StringUtils.defaultIfEmpty(name, null); + this.description = StringUtils.defaultIfEmpty(description, null); + if (startDate != null) { + this.startDate = startDate.toDateTimeAtStartOfDay().toDate(); + } + if (endDate != null) { + this.endDate = endDate.toDateTimeAtStartOfDay().toDate(); + } + if (status != null) { + this.status = status.getValue(); + } + this.office = staffOffice; + + /* + if (StringUtils.isNotBlank(name)) { + this.name = name.trim(); + } else { + this.name = null; + } + + if (StringUtils.isNotBlank(description)) { + this.description = description.trim(); + } else { + this.description = null; + } */ + + } + + + public static Teller fromJson(final Office tellerOffice, final JsonCommand command) { + final String name = command.stringValueOfParameterNamed("name"); + final String description = command.stringValueOfParameterNamed("description"); + final LocalDate startDate = command.localDateValueOfParameterNamed("startDate"); + final LocalDate endDate = command.localDateValueOfParameterNamed("endDate"); + final Integer tellerStatusInt = command.integerValueOfParameterNamed("status"); + final TellerStatus status = TellerStatus.fromInt(tellerStatusInt); + + return new Teller (tellerOffice, name, description, startDate, endDate, status); + } + + public Map update(Office tellerOffice, final JsonCommand command) { + + final Map actualChanges = new LinkedHashMap<>(7); + + final String dateFormatAsInput = command.dateFormat(); + final String localeAsInput = command.locale(); + + final String officeIdParamName = "officeId"; + if (command.isChangeInLongParameterNamed(officeIdParamName, this.officeId())) { + final long newValue = command.longValueOfParameterNamed(officeIdParamName); + actualChanges.put(officeIdParamName, newValue); + this.office = tellerOffice; + } + + final String nameParamName = "name"; + if (command.isChangeInStringParameterNamed(nameParamName, this.name)) { + final String newValue = command.stringValueOfParameterNamed(nameParamName); + actualChanges.put(nameParamName, newValue); + this.name = newValue; + } + + final String descriptionParamName = "description"; + if (command.isChangeInStringParameterNamed(descriptionParamName, this.description)) { + final String newValue = command.stringValueOfParameterNamed(descriptionParamName); + actualChanges.put(descriptionParamName, newValue); + this.description = newValue; + } + + final String startDateParamName = "startDate"; + if (command.isChangeInLocalDateParameterNamed(startDateParamName, getStartLocalDate())) { + final String valueAsInput = command.stringValueOfParameterNamed(startDateParamName); + actualChanges.put(startDateParamName, valueAsInput); + actualChanges.put("dateFormat", dateFormatAsInput); + actualChanges.put("locale", localeAsInput); + + final LocalDate newValue = command.localDateValueOfParameterNamed(startDateParamName); + this.startDate = newValue.toDate(); + } + + final String endDateParamName = "endDate"; + if (command.isChangeInLocalDateParameterNamed(endDateParamName, getEndLocalDate())) { + final String valueAsInput = command.stringValueOfParameterNamed(endDateParamName); + actualChanges.put(endDateParamName, valueAsInput); + actualChanges.put("dateFormat", dateFormatAsInput); + actualChanges.put("locale", localeAsInput); + + final LocalDate newValue = command.localDateValueOfParameterNamed(endDateParamName); + this.endDate = newValue.toDate(); + } + + final String statusParamName = "status"; + if (command.isChangeInIntegerParameterNamed(statusParamName, getStatus())) { + final Integer valueAsInput = command.integerValueOfParameterNamed(statusParamName); + actualChanges.put(statusParamName, valueAsInput); + final Integer newValue = command.integerValueOfParameterNamed(statusParamName); + final TellerStatus status = TellerStatus.fromInt(newValue); + if (status != TellerStatus.INVALID) { + this.status = status.getValue(); + } + } + + return actualChanges; + } + + + + public Office getOffice() { + return office; + } + + public void setOffice(Office office) { + this.office = office; + } + + public GLAccount getDebitAccount() { + return debitAccount; + } + + public void setDebitAccount(GLAccount debitAccount) { + this.debitAccount = debitAccount; + } + + public GLAccount getCreditAccount() { + return creditAccount; + } + + public void setCreditAccount(GLAccount creditAccount) { + this.creditAccount = creditAccount; + } + + 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 Date getStartDate() { + return startDate; + } + + public LocalDate getStartLocalDate() { + LocalDate startLocalDate = null; + if (this.startDate != null) { + startLocalDate = LocalDate.fromDateFields(this.startDate); + } + return startLocalDate; + } + + public void setStartDate(Date startDate) { + this.startDate = startDate; + } + + public Date getEndDate() { + return endDate; + } + + public LocalDate getEndLocalDate() { + LocalDate endLocalDate = null; + if (this.endDate != null) { + endLocalDate = LocalDate.fromDateFields(this.endDate); + } + return endLocalDate; + } + + public void setEndDate(Date endDate) { + this.endDate = endDate; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Long officeId() { + return this.office.getId(); + } + + public Set getCashiers() { + return cashiers; + } + + public void setCashiers(Set cashiers) { + this.cashiers = cashiers; + } + + public Set getTransactions() { + return tellerTransactions; + } + + public void setTransactions(Set tellerTransactions) { + this.tellerTransactions = tellerTransactions; + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/TellerJournal.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/TellerJournal.java new file mode 100644 index 000000000..2c34dd692 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/TellerJournal.java @@ -0,0 +1,9 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.domain; + +public class TellerJournal { +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/TellerRepository.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/TellerRepository.java new file mode 100644 index 000000000..389cb52ec --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/TellerRepository.java @@ -0,0 +1,21 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.domain; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.Collection; + +/** + * Provides the domain repository for accessing, adding, modifying or deleting tellers. + * + * @see org.mifosplatform.organisation.teller.domain.Teller + * @since 2.0.0 + */ +public interface TellerRepository extends JpaRepository, JpaSpecificationExecutor { + Collection findTellerByOfficeId(Long officeId); +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/TellerStatus.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/TellerStatus.java new file mode 100644 index 000000000..53182e9e4 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/TellerStatus.java @@ -0,0 +1,77 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package org.mifosplatform.organisation.teller.domain; + +/** + * Enum representation of teller status states. + */ + +public enum TellerStatus { + + INVALID(0, "tellerStatusType.invalid"), + PENDING(100, "tellerStatusType.pending"), + ACTIVE(300, "tellerStatusType.active"), + INACTIVE(400, "tellerStatusType.inactive"), + CLOSED(600, "tellerStatusType.closed"); + + private final Integer value; + private final String code; + + public static TellerStatus fromInt(final Integer statusValue) { + + TellerStatus status = TellerStatus.INVALID; + switch (statusValue) { + case 100: + status = TellerStatus.PENDING; + break; + case 300: + status = TellerStatus.ACTIVE; + break; + case 400: + status = TellerStatus.INACTIVE; + break; + case 600: + status = TellerStatus.CLOSED; + break; + } + return status; + } + + private TellerStatus(final Integer value, final String code) { + this.value = value; + this.code = code; + } + + public boolean hasStateOf(final TellerStatus state) { + return this.value.equals(state.getValue()); + } + + public Integer getValue() { + return this.value; + } + + public String getCode() { + return this.code; + } + + public boolean isPending() { + return this.value.equals(TellerStatus.PENDING.getValue()); + } + + public boolean isActive() { + return this.value.equals(TellerStatus.ACTIVE.getValue()); + } + + public boolean isClosed() { + return this.value.equals(TellerStatus.CLOSED.getValue()); + } + + public boolean isInactive() { + return this.value.equals(TellerStatus.INACTIVE.getValue()); + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/TellerTransaction.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/TellerTransaction.java new file mode 100644 index 000000000..95a00a2fb --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/TellerTransaction.java @@ -0,0 +1,104 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.domain; + +import org.mifosplatform.organisation.office.domain.Office; +import org.mifosplatform.portfolio.client.domain.Client; +import org.springframework.data.jpa.domain.AbstractPersistable; + +import javax.persistence.*; +import java.util.Date; + +@Entity +@Table(name = "m_teller_transactions") +public class TellerTransaction extends AbstractPersistable { + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "office_id", nullable = false) + private Office office; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "teller_id", nullable = false) + private Teller teller; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "cashier_id", nullable = false) + private Cashier cashier; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "client_id", nullable = false) + private Client client; + + @Column(name = "type", nullable = false) + private Integer type; + + @Column(name = "amount", nullable = false) + private Double amount; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "posting_date", nullable = false) + private Date postingDate; + + public TellerTransaction() { + super(); + } + + public Office getOffice() { + return office; + } + + public void setOffice(Office office) { + this.office = office; + } + + public Teller getTeller() { + return teller; + } + + public void setTeller(Teller teller) { + this.teller = teller; + } + + public Cashier getCashier() { + return cashier; + } + + public void setCashier(Cashier cashier) { + this.cashier = cashier; + } + + public Client getClient() { + return client; + } + + public void setClient(Client client) { + this.client = client; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public Double getAmount() { + return amount; + } + + public void setAmount(Double amount) { + this.amount = amount; + } + + public Date getPostingDate() { + return postingDate; + } + + public void setPostingDate(Date postingDate) { + this.postingDate = postingDate; + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/TellerTransactionRepository.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/TellerTransactionRepository.java new file mode 100644 index 000000000..908ca4468 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/TellerTransactionRepository.java @@ -0,0 +1,20 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.domain; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +/** + * Provides the domain repository for accessing, adding, modifying or deleting teller transactions. + * + * @see org.mifosplatform.organisation.teller.domain.TellerTransaction + * @since 2.0.0 + */ +public interface TellerTransactionRepository extends JpaRepository, + JpaSpecificationExecutor { + // no added behavior +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/exception/CashierNotFoundException.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/exception/CashierNotFoundException.java new file mode 100644 index 000000000..33809157d --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/exception/CashierNotFoundException.java @@ -0,0 +1,29 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.exception; + +import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceNotFoundException; + +/** + * Indicates that a cashier could not be found. + * + * @author Markus Geiss + * @since 2.0.0 + */ +public class CashierNotFoundException extends AbstractPlatformResourceNotFoundException { + + private static final String ERROR_MESSAGE_CODE = "error.msg.cashier.not.found"; + private static final String DEFAULT_ERROR_MESSAGE = "Cashier with identifier {0,number,long} not found!"; + + /** + * Creates a new instance. + * + * @param cashierId the primary key of the cashier + */ + public CashierNotFoundException(Long cashierId) { + super(ERROR_MESSAGE_CODE, DEFAULT_ERROR_MESSAGE, cashierId); + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/exception/TellerNotFoundException.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/exception/TellerNotFoundException.java new file mode 100644 index 000000000..674e4e339 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/exception/TellerNotFoundException.java @@ -0,0 +1,29 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.exception; + +import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceNotFoundException; + +/** + * Indicates that a teller could not be found. + * + * @author Markus Geiss + * @since 2.0.0 + */ +public class TellerNotFoundException extends AbstractPlatformResourceNotFoundException { + + private static final String ERROR_MESSAGE_CODE = "error.msg.teller.not.found"; + private static final String DEFAULT_ERROR_MESSAGE = "Teller with identifier {0,number,long} not found!"; + + /** + * Creates a new instance. + * + * @param tellerId the primary key of the teller + */ + public TellerNotFoundException(Long tellerId) { + super(ERROR_MESSAGE_CODE, DEFAULT_ERROR_MESSAGE, tellerId); + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/AllocateCashToCashierCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/AllocateCashToCashierCommandHandler.java new file mode 100644 index 000000000..f7bd42d85 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/AllocateCashToCashierCommandHandler.java @@ -0,0 +1,36 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.mifosplatform.organisation.teller.service.TellerWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class AllocateCashToCashierCommandHandler implements NewCommandSourceHandler { + + private final TellerWritePlatformService writePlatformService; + + /** + * Creates a new instance. + * + * @param writePlatformService the {@code CashierWritePlatformService} used to access the backend + */ + @Autowired + public AllocateCashToCashierCommandHandler(final TellerWritePlatformService writePlatformService) { + super(); + this.writePlatformService = writePlatformService; + } + + @Override + public CommandProcessingResult processCommand(final JsonCommand command) { + + return this.writePlatformService.allocateCashToCashier(command.subentityId(), command); + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/AllocateCashierToTellerCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/AllocateCashierToTellerCommandHandler.java new file mode 100644 index 000000000..6ee9e621c --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/AllocateCashierToTellerCommandHandler.java @@ -0,0 +1,37 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.mifosplatform.organisation.teller.service.TellerWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class AllocateCashierToTellerCommandHandler implements NewCommandSourceHandler { + + private final TellerWritePlatformService writePlatformService; + + /** + * Creates a new instance. + * + * @param writePlatformService the {@code CashierWritePlatformService} used to access the backend + */ + @Autowired + public AllocateCashierToTellerCommandHandler(final TellerWritePlatformService writePlatformService) { + super(); + this.writePlatformService = writePlatformService; + } + + @Override + public CommandProcessingResult processCommand(final JsonCommand command) { + + return this.writePlatformService.allocateCashierToTeller( + command.entityId(), command); + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/CreateTellerCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/CreateTellerCommandHandler.java new file mode 100644 index 000000000..f1a3926e9 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/CreateTellerCommandHandler.java @@ -0,0 +1,43 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package org.mifosplatform.organisation.teller.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.mifosplatform.organisation.teller.service.TellerWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * Handles a create teller command. + * + * @author Markus Geiss + * @see org.mifosplatform.organisation.teller.service.TellerWritePlatformService + * @since 2.0.0 + */ +@Service +public class CreateTellerCommandHandler implements NewCommandSourceHandler { + + private final TellerWritePlatformService writePlatformService; + + /** + * Creates a new instance + * + * @param writePlatformService the {@code TellerWritePlatformService} used to access the backend + */ + @Autowired + public CreateTellerCommandHandler(final TellerWritePlatformService writePlatformService) { + this.writePlatformService = writePlatformService; + } + + @Override + public CommandProcessingResult processCommand(final JsonCommand command) { + return this.writePlatformService.createTeller(command); + } +} + diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/CreateTellerTransactionCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/CreateTellerTransactionCommandHandler.java new file mode 100644 index 000000000..fb78584b5 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/CreateTellerTransactionCommandHandler.java @@ -0,0 +1,28 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.mifosplatform.organisation.teller.service.TellerTransactionWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; + +public class CreateTellerTransactionCommandHandler implements NewCommandSourceHandler { + + private final TellerTransactionWritePlatformService writePlatformService; + + @Autowired + public CreateTellerTransactionCommandHandler(final TellerTransactionWritePlatformService writePlatformService) { + super(); + this.writePlatformService = writePlatformService; + } + + @Override + public CommandProcessingResult processCommand(final JsonCommand command) { + return this.writePlatformService.createTellerTransaction(command); + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/DeleteCashierAllocationCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/DeleteCashierAllocationCommandHandler.java new file mode 100644 index 000000000..5578c31fd --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/DeleteCashierAllocationCommandHandler.java @@ -0,0 +1,43 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.mifosplatform.organisation.teller.service.TellerWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * Handles a delete cashier command. + * + * @author Markus Geiss + * @see org.mifosplatform.organisation.teller.service.CashierWritePlatformService + * @since 2.0.0 + */ +@Service +public class DeleteCashierAllocationCommandHandler implements NewCommandSourceHandler { + + private final TellerWritePlatformService writePlatformService; + + /** + * Creates a new instance. + * + * @param writePlatformService the {@code CashierWritePlatformService} used to access the backend + */ + @Autowired + public DeleteCashierAllocationCommandHandler(final TellerWritePlatformService writePlatformService) { + super(); + this.writePlatformService = writePlatformService; + } + + @Override + public CommandProcessingResult processCommand(final JsonCommand command) { + return this.writePlatformService.deleteCashierAllocation(command.entityId(), + command.subentityId(), command); + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/DeleteTellerCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/DeleteTellerCommandHandler.java new file mode 100644 index 000000000..6235fb2fc --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/DeleteTellerCommandHandler.java @@ -0,0 +1,40 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.mifosplatform.organisation.teller.service.TellerWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * Handles a delete teller command. + * + * @author Markus Geiss + * @see org.mifosplatform.organisation.teller.service.TellerWritePlatformService + * @since 2.0.0 + */ +public class DeleteTellerCommandHandler implements NewCommandSourceHandler { + + private final TellerWritePlatformService writePlatformService; + + /** + * Creates a new instance + * + * @param writePlatformService the {@code TellerWritePlatformService} used to access the backend + */ + @Autowired + public DeleteTellerCommandHandler(final TellerWritePlatformService writePlatformService) { + super(); + this.writePlatformService = writePlatformService; + } + + @Override + public CommandProcessingResult processCommand(final JsonCommand command) { + return this.writePlatformService.deleteTeller(command.entityId()); + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/ModifyCashierCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/ModifyCashierCommandHandler.java new file mode 100644 index 000000000..147cdf571 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/ModifyCashierCommandHandler.java @@ -0,0 +1,41 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.mifosplatform.organisation.teller.service.CashierWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * Handles a modify cashier command. + * + * @author Markus Geiss + * @see org.mifosplatform.organisation.teller.service.CashierWritePlatformService + * @since 2.0.0 + */ +public class ModifyCashierCommandHandler implements NewCommandSourceHandler { + + private final CashierWritePlatformService writePlatformService; + + /** + * Creates a new instance. + * + * @param writePlatformService the {@code CashierWritePlatformService} used to access the backend + */ + @Autowired + public ModifyCashierCommandHandler(final CashierWritePlatformService writePlatformService) { + super(); + this.writePlatformService = writePlatformService; + } + + + @Override + public CommandProcessingResult processCommand(final JsonCommand command) { + return this.writePlatformService.modifyCashier(command.entityId(), command); + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/SettleCashFromCashierCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/SettleCashFromCashierCommandHandler.java new file mode 100644 index 000000000..0b55d0b3d --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/SettleCashFromCashierCommandHandler.java @@ -0,0 +1,36 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.mifosplatform.organisation.teller.service.TellerWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class SettleCashFromCashierCommandHandler implements NewCommandSourceHandler { + + private final TellerWritePlatformService writePlatformService; + + /** + * Creates a new instance. + * + * @param writePlatformService the {@code CashierWritePlatformService} used to access the backend + */ + @Autowired + public SettleCashFromCashierCommandHandler(final TellerWritePlatformService writePlatformService) { + super(); + this.writePlatformService = writePlatformService; + } + + @Override + public CommandProcessingResult processCommand(final JsonCommand command) { + + return this.writePlatformService.settleCashFromCashier(command.subentityId(), command); + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/UpdateCashierAllocationCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/UpdateCashierAllocationCommandHandler.java new file mode 100644 index 000000000..6551b79f7 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/UpdateCashierAllocationCommandHandler.java @@ -0,0 +1,43 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.mifosplatform.organisation.teller.service.TellerWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * Handles a delete teller command. + * + * @author Markus Geiss + * @see org.mifosplatform.organisation.teller.service.TellerWritePlatformService + * @since 2.0.0 + */ +@Service +public class UpdateCashierAllocationCommandHandler implements NewCommandSourceHandler { + + private final TellerWritePlatformService writePlatformService; + + /** + * Creates a new instance + * + * @param writePlatformService the {@code TellerWritePlatformService} used to access the backend + */ + @Autowired + public UpdateCashierAllocationCommandHandler(final TellerWritePlatformService writePlatformService) { + super(); + this.writePlatformService = writePlatformService; + } + + @Override + public CommandProcessingResult processCommand(final JsonCommand command) { + return this.writePlatformService.updateCashierAllocation(command.entityId(), + command.subentityId(), command); + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/UpdateTellerCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/UpdateTellerCommandHandler.java new file mode 100644 index 000000000..efdc701bf --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/handler/UpdateTellerCommandHandler.java @@ -0,0 +1,42 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.mifosplatform.organisation.teller.service.TellerWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * Handles a delete teller command. + * + * @author Markus Geiss + * @see org.mifosplatform.organisation.teller.service.TellerWritePlatformService + * @since 2.0.0 + */ +@Service +public class UpdateTellerCommandHandler implements NewCommandSourceHandler { + + private final TellerWritePlatformService writePlatformService; + + /** + * Creates a new instance + * + * @param writePlatformService the {@code TellerWritePlatformService} used to access the backend + */ + @Autowired + public UpdateTellerCommandHandler(final TellerWritePlatformService writePlatformService) { + super(); + this.writePlatformService = writePlatformService; + } + + @Override + public CommandProcessingResult processCommand(final JsonCommand command) { + return this.writePlatformService.modifyTeller(command.entityId(), command); + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/serialization/TellerCommandFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/serialization/TellerCommandFromApiJsonDeserializer.java new file mode 100644 index 000000000..9f7789f4d --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/serialization/TellerCommandFromApiJsonDeserializer.java @@ -0,0 +1,168 @@ +package org.mifosplatform.organisation.teller.serialization; + +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +import java.lang.reflect.Type; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang.StringUtils; +import org.joda.time.LocalDate; +import org.mifosplatform.infrastructure.core.data.ApiParameterError; +import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; +import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; +import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; +import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.google.gson.JsonElement; +import com.google.gson.reflect.TypeToken; + +/** + * Deserializer of JSON for Teller API. + */ + +@Component +public final class TellerCommandFromApiJsonDeserializer { + + /** + * The parameters supported for this command. + */ + private final Set supportedParameters = new HashSet<>(Arrays.asList( + "officeId", "name", "description", "startDate", + "endDate", "status", "dateFormat", "locale", + "isFullDay", "staffId", "startTime", "endTime", + "txnAmount","txnDate", "txnNote", "entityType", "entityId")); + + private final FromJsonHelper fromApiJsonHelper; + + @Autowired + public TellerCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper) { + this.fromApiJsonHelper = fromApiJsonHelper; + } + + public void validateForCreate(final String json) { + if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } + + final Type typeOfMap = new TypeToken>() {}.getType(); + this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, this.supportedParameters); + + final List dataValidationErrors = new ArrayList<>(); + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("teller"); + + final JsonElement element = this.fromApiJsonHelper.parse(json); + + final Long officeId = this.fromApiJsonHelper.extractLongNamed("officeId", element); + baseDataValidator.reset().parameter("officeId").value(officeId).notNull().integerGreaterThanZero(); + + final String name = this.fromApiJsonHelper.extractStringNamed("name", element); + baseDataValidator.reset().parameter("name").value(name).notBlank().notExceedingLengthOf(50); + + final String description = this.fromApiJsonHelper.extractStringNamed("description", element); + baseDataValidator.reset().parameter("description").value(description).notExceedingLengthOf(100); + + final LocalDate startDate = this.fromApiJsonHelper.extractLocalDateNamed("startDate", element); + baseDataValidator.reset().parameter("startDate").value(startDate).notNull(); + + final LocalDate endDate = this.fromApiJsonHelper.extractLocalDateNamed("endDate", element); + + final String status = this.fromApiJsonHelper.extractStringNamed("status", element); + baseDataValidator.reset().parameter("status").value(status).notBlank().notExceedingLengthOf(50); + + throwExceptionIfValidationWarningsExist(dataValidationErrors); + } + + private void throwExceptionIfValidationWarningsExist(final List dataValidationErrors) { + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", + "Validation errors exist.", dataValidationErrors); } + } + + public void validateForUpdate(final String json) { + if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } + + final Type typeOfMap = new TypeToken>() {}.getType(); + this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, this.supportedParameters); + + final List dataValidationErrors = new ArrayList<>(); + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("teller"); + + final JsonElement element = this.fromApiJsonHelper.parse(json); + + final String name = this.fromApiJsonHelper.extractStringNamed("name", element); + baseDataValidator.reset().parameter("name").value(name).notBlank().notExceedingLengthOf(50); + + final String description = this.fromApiJsonHelper.extractStringNamed("description", element); + baseDataValidator.reset().parameter("description").value(description).notBlank().notExceedingLengthOf(100); + + final LocalDate startDate = this.fromApiJsonHelper.extractLocalDateNamed("startDate", element); + baseDataValidator.reset().parameter("startDate").value(startDate).notNull(); + + final String status = this.fromApiJsonHelper.extractStringNamed("status", element); + baseDataValidator.reset().parameter("status").value(status).notBlank().notExceedingLengthOf(50); + + throwExceptionIfValidationWarningsExist(dataValidationErrors); + } + + public void validateForAllocateCashier (final String json) { + if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } + + final Type typeOfMap = new TypeToken>() {}.getType(); + this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, this.supportedParameters); + + final List dataValidationErrors = new ArrayList<>(); + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("teller"); + + final JsonElement element = this.fromApiJsonHelper.parse(json); + + final Long staffId = this.fromApiJsonHelper.extractLongNamed("staffId", element); + baseDataValidator.reset().parameter("staffId").value(staffId).notNull().integerGreaterThanZero(); + + final String description = this.fromApiJsonHelper.extractStringNamed("description", element); + baseDataValidator.reset().parameter("description").value(description).notExceedingLengthOf(100); + + final LocalDate startDate = this.fromApiJsonHelper.extractLocalDateNamed("startDate", element); + baseDataValidator.reset().parameter("startDate").value(startDate).notNull(); + + final LocalDate endDate = this.fromApiJsonHelper.extractLocalDateNamed("endDate", element); + baseDataValidator.reset().parameter("endDate").value(endDate).notNull(); + + final Boolean isFullDay = this.fromApiJsonHelper.extractBooleanNamed("isFullDay", element); + baseDataValidator.reset().parameter("isFullDay").value(isFullDay).notNull(); + + final String startTime = this.fromApiJsonHelper.extractStringNamed("startTime", element); + final String endTime = this.fromApiJsonHelper.extractStringNamed("endTime", element); + + throwExceptionIfValidationWarningsExist(dataValidationErrors); + } + + public void validateForCashTxnForCashier (final String json) { + if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } + + final Type typeOfMap = new TypeToken>() {}.getType(); + this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, this.supportedParameters); + + final List dataValidationErrors = new ArrayList<>(); + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("teller"); + + final JsonElement element = this.fromApiJsonHelper.parse(json); + + final BigDecimal txnAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("txnAmount", element); + baseDataValidator.reset().parameter("txnAmount").value(txnAmount).notNull(); + + final LocalDate txnDate = this.fromApiJsonHelper.extractLocalDateNamed("txnDate", element); + baseDataValidator.reset().parameter("txnDate").value(txnDate).notNull(); + + final String txnNote = this.fromApiJsonHelper.extractStringNamed("txnNote", element); + baseDataValidator.reset().parameter("txnNote").value(txnNote).notExceedingLengthOf(200); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/service/CashierWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/service/CashierWritePlatformService.java new file mode 100644 index 000000000..a1c87f625 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/service/CashierWritePlatformService.java @@ -0,0 +1,24 @@ +package org.mifosplatform.organisation.teller.service; + +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; + +public class CashierWritePlatformService { + + public CommandProcessingResult allocateCashierToTeller(JsonCommand command) { + // TODO Auto-generated method stub + return null; + } + + public CommandProcessingResult deleteCashier(Long entityId) { + // TODO Auto-generated method stub + return null; + } + + public CommandProcessingResult modifyCashier(Long entityId, + JsonCommand command) { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/service/TellerManagementReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/service/TellerManagementReadPlatformService.java new file mode 100644 index 000000000..a34dc19db --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/service/TellerManagementReadPlatformService.java @@ -0,0 +1,58 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.service; + +import org.mifosplatform.organisation.teller.data.CashierData; +import org.mifosplatform.organisation.teller.data.CashierTransactionData; +import org.mifosplatform.organisation.teller.data.CashierTransactionsWithSummaryData; +import org.mifosplatform.organisation.teller.data.TellerData; +import org.mifosplatform.organisation.teller.data.TellerJournalData; +import org.mifosplatform.organisation.teller.data.TellerTransactionData; + +import java.util.Collection; +import java.util.Date; + +public interface TellerManagementReadPlatformService { + + public Collection getTellers(Long officeId); + + public TellerData findTeller(Long tellerId); + + public CashierData findCashier(Long cashierId); + + public Collection getCashierData(Long officeId, Long tellerId, Long staffId, Date date); + + public Collection getTellerCashiers(Long tellerId, Date date); + + public CashierData retrieveCashierTemplate (Long officeId, Long tellerId, boolean staffInSelectedOfficeOnly); + + public CashierTransactionData retrieveCashierTxnTemplate(Long cashierId); + + public TellerTransactionData findTellerTransaction(Long transactionId); + + public Collection fetchTellerTransactionsByTellerId(Long tellerId, Date fromDate, Date toDate); + + public Collection getJournals(Long officeId, Long tellerId, Long cashierId, Date dateFrom, Date dateTo); + + public Collection fetchTellerJournals(Long tellerId, Long cashierId, Date fromDate, Date toDate); + + public Collection retrieveAllTellersForDropdown(Long officeId); + + public Collection retrieveAllTellers(String sqlSearch, Long officeId, String status); + + public Collection getCashiersForTeller(Long tellerId, Date fromDate, Date toDate); + + public Collection retrieveCashiersForTellers(String sqlSearch, + Long tellerId); + + public Collection retrieveCashierTransactions( + Long cashierId, boolean includeAllTellers, Date fromDate, + Date toDate); + + public CashierTransactionsWithSummaryData retrieveCashierTransactionsWithSummary ( + Long cashierId, boolean includeAllTellers, Date fromDate, Date toDate); + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/service/TellerManagementReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/service/TellerManagementReadPlatformServiceImpl.java new file mode 100644 index 000000000..2af7c9c2b --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/service/TellerManagementReadPlatformServiceImpl.java @@ -0,0 +1,779 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.service; + +import java.math.BigDecimal; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Collection; +import java.util.Date; +import java.util.Iterator; + +import org.apache.commons.lang.StringUtils; +import org.joda.time.LocalDate; +import org.mifosplatform.infrastructure.core.domain.JdbcSupport; +import org.mifosplatform.infrastructure.core.exception.UnrecognizedQueryParamException; +import org.mifosplatform.infrastructure.core.service.RoutingDataSource; +import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; +import org.mifosplatform.organisation.office.data.OfficeData; +import org.mifosplatform.organisation.office.service.OfficeReadPlatformService; +import org.mifosplatform.organisation.staff.data.StaffData; +import org.mifosplatform.organisation.staff.exception.StaffNotFoundException; +import org.mifosplatform.organisation.staff.service.StaffReadPlatformService; +import org.mifosplatform.organisation.teller.data.CashierData; +import org.mifosplatform.organisation.teller.data.CashierTransactionData; +import org.mifosplatform.organisation.teller.data.CashierTransactionTypeTotalsData; +import org.mifosplatform.organisation.teller.data.CashierTransactionsWithSummaryData; +import org.mifosplatform.organisation.teller.data.TellerData; +import org.mifosplatform.organisation.teller.data.TellerJournalData; +import org.mifosplatform.organisation.teller.data.TellerTransactionData; +import org.mifosplatform.organisation.teller.domain.CashierTxnType; +import org.mifosplatform.organisation.teller.domain.TellerStatus; +import org.mifosplatform.useradministration.domain.AppUser; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +@Service +public class TellerManagementReadPlatformServiceImpl implements TellerManagementReadPlatformService { + + private final JdbcTemplate jdbcTemplate; + private final PlatformSecurityContext context; + private final TellerLookupMapper lookupMapper = new TellerLookupMapper(); + private final TellerInOfficeHierarchyMapper tellerInOfficeHierarchyMapper = new TellerInOfficeHierarchyMapper(); + private final OfficeReadPlatformService officeReadPlatformService; + private final StaffReadPlatformService staffReadPlatformService; + + @Autowired + public TellerManagementReadPlatformServiceImpl(final PlatformSecurityContext context, + final RoutingDataSource dataSource, + final OfficeReadPlatformService officeReadPlatformService, + StaffReadPlatformService staffReadPlatformService + ) { + this.context = context; + this.jdbcTemplate = new JdbcTemplate(dataSource); + this.officeReadPlatformService = officeReadPlatformService; + this.staffReadPlatformService = staffReadPlatformService; + } + + private static final class TellerMapper implements RowMapper { + + public String schema() { + + final StringBuilder sqlBuilder = new StringBuilder(400); + + sqlBuilder.append("t.id as id,t.office_id as office_id, t.name as teller_name, t.description as description, "); + sqlBuilder.append("t.valid_from as start_date, t.valid_to as end_date, t.state as status, o.name as office_name, "); + sqlBuilder.append("t.debit_account_id as debit_account_id, t.credit_account_id as credit_account_id "); + sqlBuilder.append("from m_tellers t "); + sqlBuilder.append("join m_office o on o.id = t.office_id "); + + return sqlBuilder.toString(); + } + + @Override + public TellerData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + + final Long id = rs.getLong("id"); + final Long officeId = rs.getLong("office_id"); + final String tellerName = rs.getString("teller_name"); + final String description = rs.getString("description"); + final String officeName = rs.getString("office_name"); + TellerStatus tellerStatus = null; + final Integer status = rs.getInt("status"); + if (status != null) { + tellerStatus = TellerStatus.fromInt(status); + } + final Long debitAccountId = rs.getLong("debit_account_id"); + final Long creditAccountId = rs.getLong("credit_account_id"); + + final LocalDate startDate = JdbcSupport.getLocalDate(rs, "start_date"); + final LocalDate endDate = JdbcSupport.getLocalDate(rs, "end_date"); + + return TellerData.instance(id, officeId, debitAccountId, creditAccountId, + tellerName, description, startDate, endDate, tellerStatus, officeName, null, null); + } + } + + private static final class TellerInOfficeHierarchyMapper implements RowMapper { + + public String schema() { + + final StringBuilder sqlBuilder = new StringBuilder(200); + + sqlBuilder.append("t.id as id,t.office_id as office_id, t.name as teller_name, t.description as description, "); + sqlBuilder.append("t.valid_from as start_date, t.valid_to as end_date, t.state as status, o.name as office_name "); + sqlBuilder.append("t.debit_account_id as debit_account_id, t.credit_account_id as credit_account_id "); + sqlBuilder.append("from m_office o "); + sqlBuilder.append("join m_office ohierarchy on o.hierarchy like concat(ohierarchy.hierarchy, '%') "); + sqlBuilder.append("join m_tellers t on t.office_id = ohierarchy.id and s.is_active=1 "); + + sqlBuilder.append("where o.id = ? "); + + return sqlBuilder.toString(); + } + + @Override + public TellerData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + + final Long id = rs.getLong("id"); + final String tellerName = rs.getString("teller_name"); + final String description = rs.getString("description"); + final String officeName = rs.getString("office_name"); + final Long officeId = rs.getLong("office_id"); + TellerStatus tellerStatus = null; + final Integer status = rs.getInt("status"); + if (status != null) { + tellerStatus = TellerStatus.fromInt(status); + } + final Long debitAccountId = rs.getLong("debit_account_id"); + final Long creditAccountId = rs.getLong("credit_account_id"); + + final LocalDate startDate = JdbcSupport.getLocalDate(rs, "start_date"); + final LocalDate endDate = JdbcSupport.getLocalDate(rs, "end_date"); + + return TellerData.instance(id, officeId, debitAccountId, creditAccountId, + tellerName, description, startDate, endDate, tellerStatus, officeName, null, null); + + } + } + + private static final class TellerLookupMapper implements RowMapper { + + private final String schemaSql; + + public TellerLookupMapper() { + + final StringBuilder sqlBuilder = new StringBuilder(100); + sqlBuilder.append("t.id as id, t.name as teller_name "); + sqlBuilder.append("from m_tellers t "); + + this.schemaSql = sqlBuilder.toString(); + } + + public String schema() { + return this.schemaSql; + } + + @Override + public TellerData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + + final Long id = rs.getLong("id"); + final String tellerName = rs.getString("teller_name"); + return TellerData.lookup(id, tellerName); + } + } + + @Override + public Collection retrieveAllTellersForDropdown(final Long officeId) { + + final Long defaultOfficeId = defaultToUsersOfficeIfNull(officeId); + + final String sql = "select " + this.lookupMapper.schema() + " where s.office_id = ? and s.is_active=1 "; + + return this.jdbcTemplate.query(sql, this.lookupMapper, new Object[] { defaultOfficeId }); + } + + private Long defaultToUsersOfficeIfNull(final Long officeId) { + Long defaultOfficeId = officeId; + if (defaultOfficeId == null) { + defaultOfficeId = this.context.authenticatedUser().getOffice().getId(); + } + return defaultOfficeId; + } + + @Override + public TellerData findTeller(final Long tellerId) { + + try { + final TellerMapper tm = new TellerMapper(); + final String sql = "select " + tm.schema() + " where t.id = ?"; + + return this.jdbcTemplate.queryForObject(sql, tm, new Object[] { tellerId }); + } catch (final EmptyResultDataAccessException e) { + throw new StaffNotFoundException(tellerId); + } + } + + @Override + public Collection retrieveAllTellers(final String sqlSearch, final Long officeId, final String status) { + final String extraCriteria = getTellerCriteria(sqlSearch, officeId, status); + return retrieveAllTeller(extraCriteria); + } + + private Collection retrieveAllTeller(final String extraCriteria) { + + final TellerMapper tm = new TellerMapper(); + String sql = "select " + tm.schema(); + if (StringUtils.isNotBlank(extraCriteria)) { + sql += " where " + extraCriteria; + } + sql = sql + " order by t.teller_name"; + return this.jdbcTemplate.query(sql, tm, new Object[] {}); + } + + private String getTellerCriteria(final String sqlSearch, final Long officeId, final String status) { + + final StringBuffer extraCriteria = new StringBuffer(200); + + if (sqlSearch != null) { + extraCriteria.append(" and (").append(sqlSearch).append(")"); + } + if (officeId != null) { + extraCriteria.append(" and office_id = ").append(officeId).append(" "); + } + // Passing status parameter to get ACTIVE (By Default), INACTIVE or ALL + // (Both active and Inactive) employees + if (status.equalsIgnoreCase("active")) { + extraCriteria.append(" and status = 300 "); + } else if (status.equalsIgnoreCase("inActive")) { + extraCriteria.append(" and status = 0 "); + } else if (status.equalsIgnoreCase("all")) {} else { + throw new UnrecognizedQueryParamException("status", status, new Object[] { "all", "active", "inactive" }); + } + + if (StringUtils.isNotBlank(extraCriteria.toString())) { + extraCriteria.delete(0, 4); + } + + // remove begin four letter including a space from the string. + return extraCriteria.toString(); + } + + @Override + public Collection getTellers(Long officeId) { + return retrieveAllTellers (false); + } + + @Override + public Collection getCashiersForTeller(Long tellerId, + Date fromDate, Date toDate) { + return retrieveCashiersForTellers (null, tellerId); + } + + @Override + public Collection retrieveCashiersForTellers(final String sqlSearch, final Long tellerId) { + final String extraCriteria = getTellerCriteria(sqlSearch, tellerId); + return fetchCashiers (extraCriteria); + } + + private String getTellerCriteria(final String sqlSearch, final Long tellerId) { + + final StringBuffer extraCriteria = new StringBuffer(200); + + if (sqlSearch != null) { + extraCriteria.append(" and (").append(sqlSearch).append(")"); + } + if (tellerId != null) { + extraCriteria.append(" and teller_id = ").append(tellerId).append(" "); + } + + // remove begin four letter including a space from the string. + if (StringUtils.isNotBlank(extraCriteria.toString())) { + extraCriteria.delete(0, 4); + } + + return extraCriteria.toString(); + } + + private Collection fetchCashiers (final String extraCriteria) { + + final CashierMapper cm = new CashierMapper(); + String sql = "select " + cm.schema(); + if (StringUtils.isNotBlank(extraCriteria)) { + sql += " where " + extraCriteria; + } + sql = sql + " order by teller_name"; + return this.jdbcTemplate.query(sql, cm, new Object[] {}); + } + + + @Override + public CashierData findCashier(Long cashierId) { + try { + final CashierMapper cm = new CashierMapper(); + final String sql = "select " + cm.schema() + " where c.id = ?"; + + return this.jdbcTemplate.queryForObject(sql, cm, new Object[] { cashierId }); + } catch (final EmptyResultDataAccessException e) { + throw new StaffNotFoundException(cashierId); + } + } + + @Override + public Collection getCashierData(Long officeId, Long tellerId, + Long staffId, Date date) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Collection getTellerCashiers(Long tellerId, Date date) { + // TODO Auto-generated method stub + return null; + } + + @Override + public TellerTransactionData findTellerTransaction(Long transactionId) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Collection fetchTellerTransactionsByTellerId( + Long tellerId, Date fromDate, Date toDate) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Collection getJournals(Long officeId, + Long tellerId, Long cashierId, Date dateFrom, Date dateTo) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Collection fetchTellerJournals(Long tellerId, + Long cashierId, Date fromDate, Date toDate) { + // TODO Auto-generated method stub + return null; + } + + + @Cacheable(value = "tellers", key = "T(org.mifosplatform.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat(#root.target.context.authenticatedUser().getOffice().getHierarchy()+'of')") + public Collection retrieveAllTellers(final boolean includeAllTellers) { + final AppUser currentUser = this.context.authenticatedUser(); + final String hierarchy = currentUser.getOffice().getHierarchy(); + String hierarchySearchString = null; + if (includeAllTellers) { + hierarchySearchString = "." + "%"; + } else { + hierarchySearchString = hierarchy + "%"; + } + final TellerMapper tm = new TellerMapper(); + final String sql = "select " + tm.schema() + "where o.hierarchy like ? order by o.hierarchy"; + + return this.jdbcTemplate.query(sql, tm, new Object[] { hierarchySearchString }); + } + + @Override + public CashierData retrieveCashierTemplate(Long officeId, Long tellerId, + boolean staffInSelectedOfficeOnly) { + final Long defaultOfficeId = defaultToUsersOfficeIfNull(officeId); + + final OfficeData officeData = this.officeReadPlatformService.retrieveOffice(defaultOfficeId); + String officeName = ""; + if (officeData != null) { + officeName = officeData.name(); + } + + TellerData tellerData = findTeller(tellerId); + String tellerName = ""; + if (tellerData != null) { + tellerName = tellerData.getName(); + } + + final Collection offices = this.officeReadPlatformService.retrieveAllOfficesForDropdown(); + + Collection staffOptions = null; + + final boolean loanOfficersOnly = false; + if (staffInSelectedOfficeOnly) { + staffOptions = this.staffReadPlatformService.retrieveAllStaffForDropdown(defaultOfficeId); + } else { + staffOptions = this.staffReadPlatformService.retrieveAllStaffInOfficeAndItsParentOfficeHierarchy(defaultOfficeId, + loanOfficersOnly); + } + if (CollectionUtils.isEmpty(staffOptions)) { + staffOptions = null; + } + + return CashierData.template(officeId, officeName, + tellerId, tellerName, staffOptions); + } + + @Override + public CashierTransactionData retrieveCashierTxnTemplate(Long cashierId) { + String officeName = ""; + String tellerName = ""; + String cashierName = ""; + Long officeId = null; + Long tellerId = null; + Date startDate = null; + Date endDate = null ; + + CashierData cashierData = findCashier(cashierId); + if (cashierData != null) { + cashierName = cashierData.getStaffName(); + tellerId = cashierData.getTellerId(); + if (tellerId != null) { + TellerData tellerData = findTeller(tellerId); + if (tellerData != null) { + tellerName = tellerData.getName(); + officeName = tellerData.getOfficeName(); + } + } + startDate = cashierData.getStartDate(); + endDate = cashierData.getEndDate(); + } + + return CashierTransactionData.template(cashierId, tellerId, tellerName, officeId, + officeName, cashierName, cashierData, startDate, endDate); + } + + @Override + public CashierTransactionsWithSummaryData retrieveCashierTransactionsWithSummary ( + final Long cashierId, final boolean includeAllTellers, + final Date fromDate, final Date toDate) { + final AppUser currentUser = this.context.authenticatedUser(); + final String hierarchy = currentUser.getOffice().getHierarchy(); + String hierarchySearchString = null; + if (includeAllTellers) { + hierarchySearchString = "." + "%"; + } else { + hierarchySearchString = hierarchy + "%"; + } + final CashierTransactionSummaryMapper ctsm = + new CashierTransactionSummaryMapper(); + final String sql = "select " + ctsm.cashierTxnSummarySchema() + " limit 1000"; + + Collection cashierTxnTypeTotals = + this.jdbcTemplate.query(sql, ctsm, new Object[] { + cashierId, hierarchySearchString, + cashierId, hierarchySearchString, + cashierId, hierarchySearchString }); + + Iterator itr = cashierTxnTypeTotals.iterator(); + BigDecimal allocAmount = new BigDecimal (0); + BigDecimal cashInAmount = new BigDecimal (0); + BigDecimal cashOutAmount = new BigDecimal (0); + BigDecimal settleAmount = new BigDecimal (0); + + while(itr.hasNext()) { + CashierTransactionTypeTotalsData total = itr.next(); + if (total != null) { + if ( total.getCashierTxnType() == CashierTxnType.ALLOCATE.getId() ) { + allocAmount = total.getCashTotal(); + } else if ( total.getCashierTxnType() == CashierTxnType.SETTLE.getId() ) { + settleAmount = total.getCashTotal(); + } else if ( total.getCashierTxnType() == CashierTxnType.INWARD_CASH_TXN.getId() ) { + cashInAmount = total.getCashTotal(); + } else if ( total.getCashierTxnType() == CashierTxnType.OUTWARD_CASH_TXN.getId() ) { + cashOutAmount = total.getCashTotal(); + } + } + } + + final Collection cashierTransactions = + retrieveCashierTransactions (cashierId, includeAllTellers, + fromDate, toDate); + + CashierTransactionData cashierTxnTemplate = retrieveCashierTxnTemplate (cashierId); + + CashierTransactionsWithSummaryData txnsWithSummary = + CashierTransactionsWithSummaryData.instance( + cashierTransactions, + allocAmount, + cashInAmount, + cashOutAmount, + settleAmount, + cashierTxnTemplate.getOfficeName(), + cashierTxnTemplate.getTellerId(), cashierTxnTemplate.getTellerName(), + cashierTxnTemplate.getCashierId(), cashierTxnTemplate.getCashierName() + ); + return txnsWithSummary; + } + + @Override + public Collection retrieveCashierTransactions ( + final Long cashierId, final boolean includeAllTellers, + final Date fromDate, final Date toDate) { + final AppUser currentUser = this.context.authenticatedUser(); + final String hierarchy = currentUser.getOffice().getHierarchy(); + String hierarchySearchString = null; + if (includeAllTellers) { + hierarchySearchString = "." + "%"; + } else { + hierarchySearchString = hierarchy + "%"; + } + + final CashierTransactionMapper ctm = new CashierTransactionMapper(); + + final String sql = "select * from (select " + + ctm.cashierTxnSchema() + + " where txn.cashier_id = ? and o.hierarchy like ? ) cashier_txns " + + " union (select " + + ctm.savingsTxnSchema() + + " where sav_txn.is_reversed = 0 and c.id = ? and o.hierarchy like ? and " + + " created_date between c.start_date and date_add(c.end_date, interval 1 day) " + + " and renum.enum_value in ('deposit','withdrawal fee', 'Pay Charge', 'withdrawal') ) " + + " union (select " + + ctm.loansTxnSchema() + + " where loan_txn.is_reversed = 0 and c.id = ? and o.hierarchy like ? and " + + " created_date between c.start_date and date_add(c.end_date, interval 1 day) " + + " and renum.enum_value in ('Repayment At Disbursement','Repayment', 'Recovery Payment','Disbursement') ) " + + " order by created_date "; + + return this.jdbcTemplate.query(sql, ctm, + new Object[] { cashierId, hierarchySearchString, + cashierId, hierarchySearchString, + cashierId, hierarchySearchString}); + } + + private static final class CashierMapper implements RowMapper { + + public String schema() { + + final StringBuilder sqlBuilder = new StringBuilder(400); + + sqlBuilder.append("c.id as id,c.teller_id as teller_id, t.name as teller_name, c.description as description, "); + sqlBuilder.append("c.staff_id as staff_id, s.display_name as staff_name, "); + sqlBuilder.append("c.start_date as start_date, c.end_date as end_date, "); + sqlBuilder.append("c.full_day as full_day, c.start_time as start_time, c.end_time as end_time "); + sqlBuilder.append("from m_cashiers c "); + sqlBuilder.append("join m_tellers t on t.id = c.teller_id "); + sqlBuilder.append("join m_staff s on s.id = c.staff_id "); + + return sqlBuilder.toString(); + } + + @Override + public CashierData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + + final Long id = rs.getLong("id"); + final Long tellerId = rs.getLong("teller_id"); + final String tellerName = rs.getString("teller_name"); + final Long staffId = rs.getLong("staff_id"); + final String staffName = rs.getString("staff_name"); + final String description = rs.getString("description"); + + final LocalDate startDate = JdbcSupport.getLocalDate(rs, "start_date"); + final LocalDate endDate = JdbcSupport.getLocalDate(rs, "end_date"); + final Integer fullDayFromDB = rs.getInt ("full_day"); + Boolean fullDay = false; + if (fullDayFromDB == 1) { + fullDay = true; + } + final String startTime = rs.getString("start_time"); + final String endTime = rs.getString("end_time"); + + return CashierData.instance(id, null, null, + staffId, staffName, tellerId, tellerName, + description, startDate.toDate(), endDate.toDate(), fullDay, startTime, endTime); + } + } + + private static final class CashierTransactionMapper implements RowMapper { + + public String cashierTxnSchema() { + + final StringBuilder sqlBuilder = new StringBuilder(400); + + sqlBuilder.append(" txn.id as txn_id, txn.cashier_id as cashier_id, "); + sqlBuilder.append(" txn.txn_type as txn_type, "); + sqlBuilder.append(" txn.txn_amount as txn_amount, txn.txn_date as txn_date, txn.txn_note as txn_note, "); + sqlBuilder.append(" txn.entity_type as entity_type, txn.entity_id as entity_id, txn.created_date as created_date, "); + sqlBuilder.append(" o.id as office_id, o.name as office_name, t.id as teller_id, t.name as teller_name, s.display_name as cashier_name "); + sqlBuilder.append(" from m_cashier_transactions txn "); + sqlBuilder.append(" left join m_cashiers c on c.id = txn.cashier_id "); + sqlBuilder.append(" left join m_tellers t on t.id = c.teller_id "); + sqlBuilder.append(" left join m_office o on o.id = t.office_id "); + sqlBuilder.append(" left join m_staff s on s.id = c.staff_id "); + + return sqlBuilder.toString(); + } + + public String savingsTxnSchema() { + + final StringBuilder sqlBuilder = new StringBuilder(400); + + sqlBuilder.append(" sav_txn.id as txn_id, null as cashier_id, "); + sqlBuilder.append(" case "); + sqlBuilder.append(" when renum.enum_value in ('deposit','withdrawal fee', 'Pay Charge') "); + sqlBuilder.append(" then 103 "); + sqlBuilder.append(" when renum.enum_value in ('withdrawal', '') "); + sqlBuilder.append(" then 104 "); + sqlBuilder.append(" else "); + sqlBuilder.append(" 105 "); + sqlBuilder.append(" end as txn_type, "); + sqlBuilder.append(" sav_txn.amount as txn_amount, sav_txn.transaction_date as txn_date, "); + sqlBuilder.append(" concat (renum.enum_value, ', Sav:', sav.id, '-', sav.account_no, ',Client:', cl.id, '-',cl.display_name) as txn_note, "); + sqlBuilder.append(" 'savings' as entity_type, sav.id as entity_id, sav_txn.created_date as created_date, "); + sqlBuilder.append(" o.id as office_id, o.name as office_name, null as teller_id, null as teller_name, staff.display_name as cashier_name "); + sqlBuilder.append(" from m_savings_account_transaction sav_txn "); + sqlBuilder.append(" left join r_enum_value renum on sav_txn.transaction_type_enum = renum.enum_id and renum.enum_name = 'savings_transaction_type_enum' "); + sqlBuilder.append(" left join m_savings_account sav on sav_txn.savings_account_id = sav.id "); + sqlBuilder.append(" left join m_client cl on sav.client_id = cl.id "); + sqlBuilder.append(" left join m_office o on cl.office_id = o.id "); + sqlBuilder.append(" left join m_appuser user on sav_txn.appuser_id = user.id "); + sqlBuilder.append(" left join m_staff staff on user.staff_id = staff.id "); + sqlBuilder.append(" left join m_cashiers c on c.staff_id = staff.id "); + + return sqlBuilder.toString(); + } + + public String loansTxnSchema() { + + final StringBuilder sqlBuilder = new StringBuilder(400); + + sqlBuilder.append(" loan_txn.id as txn_id, c.id as cashier_id, "); + sqlBuilder.append(" case "); + sqlBuilder.append(" when renum.enum_value in ('Repayment At Disbursement','Repayment', 'Recovery Payment') "); + sqlBuilder.append(" then 103 "); + sqlBuilder.append(" when renum.enum_value in ('Disbursement') "); + sqlBuilder.append(" then 104 "); + sqlBuilder.append(" else "); + sqlBuilder.append(" 105 "); + sqlBuilder.append(" end as cash_txn_type, "); + sqlBuilder.append(" loan_txn.amount as txn_amount, loan_txn.transaction_date as txn_date, "); + sqlBuilder.append(" concat (renum.enum_value, ', Loan:', loan.id, '-', loan.account_no, ',Client:', cl.id, '-',cl.display_name) as txn_note, "); + sqlBuilder.append(" 'loans' as entity_type, loan.id as entity_id, loan_txn.created_date as created_date, "); + sqlBuilder.append(" o.id as office_id, o.name as office_name, null as teller_id, null as teller_name, staff.display_name as cashier_name "); + sqlBuilder.append(" from m_loan_transaction loan_txn "); + sqlBuilder.append(" left join r_enum_value renum on loan_txn.transaction_type_enum = renum.enum_id and renum.enum_name = 'transaction_type_enum' "); + sqlBuilder.append(" left join m_loan loan on loan_txn.loan_id = loan.id "); + sqlBuilder.append(" left join m_client cl on loan.client_id = cl.id "); + sqlBuilder.append(" left join m_office o on cl.office_id = o.id "); + sqlBuilder.append(" left join m_appuser user on loan_txn.appuser_id = user.id "); + sqlBuilder.append(" left join m_staff staff on user.staff_id = staff.id "); + sqlBuilder.append(" left join m_cashiers c on c.staff_id = staff.id "); + + return sqlBuilder.toString(); + } + + @Override + public CashierTransactionData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + + final Long id = rs.getLong("txn_id"); + final Long cashierId = rs.getLong("cashier_id"); + final Integer tType = rs.getInt("txn_type"); + final CashierTxnType txnType = CashierTxnType.getCashierTxnType(tType); + final BigDecimal txnAmount = rs.getBigDecimal("txn_amount"); + final LocalDate txnLocalDate = JdbcSupport.getLocalDate(rs, "txn_date"); + final String txnNote = rs.getString("txn_note"); + final String entityType = rs.getString("entity_type"); + final Long entityId = rs.getLong("entity_id"); + final LocalDate createdLocalDate = JdbcSupport.getLocalDate(rs, "created_date"); + + Date txnDate = null; + if (txnLocalDate != null) { + txnDate = txnLocalDate.toDate(); + } + Date createdDate = null; + if (createdLocalDate != null) { + createdDate = createdLocalDate.toDate(); + } + + final Long officeId = rs.getLong("office_id"); + final String officeName = rs.getString("office_name"); + final Long tellerId = rs.getLong("teller_id"); + final String tellerName = rs.getString("teller_name"); + final String cashierName = rs.getString("cashier_name"); + + return CashierTransactionData.instance( + id, cashierId, txnType, txnAmount, txnDate, txnNote, + entityType, entityId, createdDate, officeId, officeName, + tellerId, tellerName, cashierName, null, null, null); + } + } + + private static final class CashierTransactionSummaryMapper implements RowMapper { + + public String cashierTxnSummarySchema() { + + final StringBuilder sqlBuilder = new StringBuilder(400); + + sqlBuilder.append(" cash_txn_type, sum(txn_amount) as txn_total from "); + sqlBuilder.append(" (select * from "); + sqlBuilder.append(" (select txn.id as txn_id, txn.cashier_id as cashier_id, "); + sqlBuilder.append(" txn.txn_type as cash_txn_type, "); + sqlBuilder.append(" txn.txn_amount as txn_amount, txn.txn_date as txn_date, txn.txn_note as txn_note, "); + sqlBuilder.append(" txn.entity_type as entity_type, txn.entity_id as entity_id, txn.created_date as created_date, "); + sqlBuilder.append(" o.id as office_id, o.name as office_name, t.id as teller_id, t.name as teller_name, s.display_name as cashier_name "); + sqlBuilder.append(" from m_cashier_transactions txn "); + sqlBuilder.append(" left join m_cashiers c on c.id = txn.cashier_id "); + sqlBuilder.append(" left join m_tellers t on t.id = c.teller_id "); + sqlBuilder.append(" left join m_office o on o.id = t.office_id "); + sqlBuilder.append(" left join m_staff s on s.id = c.staff_id "); + sqlBuilder.append(" where txn.cashier_id = ? "); + sqlBuilder.append(" and o.hierarchy like ? ) cashier_txns "); + sqlBuilder.append(" UNION "); + sqlBuilder.append(" (select sav_txn.id as txn_id, c.id as cashier_id, "); + sqlBuilder.append(" case "); + sqlBuilder.append(" when renum.enum_value in ('deposit','withdrawal fee', 'Pay Charge') "); + sqlBuilder.append(" then 103 "); + sqlBuilder.append(" when renum.enum_value in ('withdrawal') "); + sqlBuilder.append(" then 104 "); + sqlBuilder.append(" else "); + sqlBuilder.append(" 105 "); + sqlBuilder.append(" end as cash_txn_type, "); + sqlBuilder.append(" sav_txn.amount as txn_amount, sav_txn.transaction_date as txn_date, "); + sqlBuilder.append(" concat (renum.enum_value, ', Sav:', sav.id, '-', sav.account_no, ',Client:', cl.id, '-',cl.display_name) as txn_note, "); + sqlBuilder.append(" 'savings' as entity_type, sav.id as entity_id, sav_txn.created_date as created_date, "); + sqlBuilder.append(" o.id as office_id, o.name as office_name, null as teller_id, null as teller_name, staff.display_name as cashier_name "); + sqlBuilder.append(" from m_savings_account_transaction sav_txn "); + sqlBuilder.append(" left join r_enum_value renum on sav_txn.transaction_type_enum = renum.enum_id and renum.enum_name = 'savings_transaction_type_enum' "); + sqlBuilder.append(" left join m_savings_account sav on sav_txn.savings_account_id = sav.id "); + sqlBuilder.append(" left join m_client cl on sav.client_id = cl.id "); + sqlBuilder.append(" left join m_office o on cl.office_id = o.id "); + sqlBuilder.append(" left join m_appuser user on sav_txn.appuser_id = user.id "); + sqlBuilder.append(" left join m_staff staff on user.staff_id = staff.id "); + sqlBuilder.append(" left join m_cashiers c on c.staff_id = staff.id "); + sqlBuilder.append(" where sav_txn.is_reversed = 0 and c.id = ? "); + sqlBuilder.append(" and o.hierarchy like ? and "); + sqlBuilder.append(" created_date between c.start_date and date_add(c.end_date, interval 1 day) "); + sqlBuilder.append(" ) "); + sqlBuilder.append(" UNION "); + sqlBuilder.append(" ( "); + sqlBuilder.append(" select loan_txn.id as txn_id, c.id as cashier_id, "); + sqlBuilder.append(" case "); + sqlBuilder.append(" when renum.enum_value in ('Repayment At Disbursement','Repayment', 'Recovery Payment') "); + sqlBuilder.append(" then 103 "); + sqlBuilder.append(" when renum.enum_value in ('Disbursement') "); + sqlBuilder.append(" then 104 "); + sqlBuilder.append(" else "); + sqlBuilder.append(" 105 "); + sqlBuilder.append(" end as cash_txn_type, "); + sqlBuilder.append(" loan_txn.amount as txn_amount, loan_txn.transaction_date as txn_date, "); + sqlBuilder.append(" concat (renum.enum_value, ', Loan:', loan.id, '-', loan.account_no, ',Client:', cl.id, '-',cl.display_name) as txn_note, "); + sqlBuilder.append(" 'loans' as entity_type, loan.id as entity_id, loan_txn.created_date as created_date, "); + sqlBuilder.append(" o.id as office_id, o.name as office_name, null as teller_id, null as teller_name, staff.display_name as cashier_name "); + sqlBuilder.append(" from m_loan_transaction loan_txn "); + sqlBuilder.append(" left join r_enum_value renum on loan_txn.transaction_type_enum = renum.enum_id and renum.enum_name = 'transaction_type_enum' "); + sqlBuilder.append(" left join m_loan loan on loan_txn.loan_id = loan.id "); + sqlBuilder.append(" left join m_client cl on loan.client_id = cl.id "); + sqlBuilder.append(" left join m_office o on cl.office_id = o.id "); + sqlBuilder.append(" left join m_appuser user on loan_txn.appuser_id = user.id "); + sqlBuilder.append(" left join m_staff staff on user.staff_id = staff.id "); + sqlBuilder.append(" left join m_cashiers c on c.staff_id = staff.id "); + sqlBuilder.append(" where loan_txn.is_reversed = 0 and c.id = ? "); + sqlBuilder.append(" and o.hierarchy like ? "); + sqlBuilder.append(" and created_date between c.start_date and date_add(c.end_date, interval 1 day) "); + sqlBuilder.append(" ) "); + sqlBuilder.append(" ) txns "); + sqlBuilder.append(" group by cash_txn_type "); + + return sqlBuilder.toString(); + } + + @Override + public CashierTransactionTypeTotalsData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + + final Integer cashierTxnType = rs.getInt("cash_txn_type"); + final BigDecimal txnTotal = rs.getBigDecimal("txn_total"); + + return CashierTransactionTypeTotalsData.instance( + cashierTxnType, txnTotal); + } + } + + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/service/TellerTransactionWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/service/TellerTransactionWritePlatformService.java new file mode 100644 index 000000000..469a5fa65 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/service/TellerTransactionWritePlatformService.java @@ -0,0 +1,26 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.service; + +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; + +/** + * Provides the local service for adding teller transactions. + * + * @see org.mifosplatform.organisation.teller.domain.TellerTransactionRepository + * @since 2.0.0 + */ +public interface TellerTransactionWritePlatformService { + + /** + * Stores teller transactions into the data base. + * + * @param command the command containing the teller transaction details + * @return the result i + */ + public CommandProcessingResult createTellerTransaction(JsonCommand command); +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/service/TellerWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/service/TellerWritePlatformService.java new file mode 100644 index 000000000..6a4d89e67 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/service/TellerWritePlatformService.java @@ -0,0 +1,76 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.organisation.teller.service; + +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.mifosplatform.useradministration.domain.AppUser; + +/** + * Provides the local service for adding, modifying and deleting tellers. + * + * @author Markus Geiss + * @see org.mifosplatform.organisation.teller.domain.TellerRepository + * @since 2.0.0 + */ +public interface TellerWritePlatformService { + + /** + * Creates a new teller. + * + * @param command the command to create a new teller + * @return {@code CommandProcessingResult} if successful + * @throws org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException + * @throws org.mifosplatform.infrastructure.core.exception.InvalidJsonException + */ + public CommandProcessingResult createTeller(JsonCommand command); + + /** + * Modifies a new teller. + * + * @param tellerId the primary key of the teller + * @param command the command to modifya new teller + * @return {@code CommandProcessingResult} if successful + * @throws org.mifosplatform.organisation.teller.exception.TellerNotFoundException + * @throws org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException + * @throws org.mifosplatform.infrastructure.core.exception.InvalidJsonException + */ + public CommandProcessingResult modifyTeller(Long tellerId, JsonCommand command); + + /** + * deletes a new teller. + * + * @param tellerId the primary key of the teller + * @return {@code CommandProcessingResult} if successful + * @throws org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException + * @throws org.mifosplatform.infrastructure.core.exception.InvalidJsonException + */ + public CommandProcessingResult deleteTeller(Long tellerId); + + /** + * Allocates a cashier to an existing teller. The allocation can be for a duration + * from a date to a date + * from a certain start time to an end time. + * + * @param command the command to allocate a cashier for a specific teller + * @return {@code CommandProcessingResult} if successful + * @throws org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException + * @throws org.mifosplatform.infrastructure.core.exception.InvalidJsonException + */ + public CommandProcessingResult allocateCashierToTeller(Long tellerId, JsonCommand command); + + CommandProcessingResult updateCashierAllocation(Long tellerId, Long cashierId, + JsonCommand command); + + CommandProcessingResult deleteCashierAllocation(final Long tellerId, Long cashierId, + JsonCommand command); + + CommandProcessingResult allocateCashToCashier(Long cashierId, + JsonCommand command); + + CommandProcessingResult settleCashFromCashier(Long cashierId, + JsonCommand command); +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/service/TellerWritePlatformServiceJpaImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/service/TellerWritePlatformServiceJpaImpl.java new file mode 100644 index 000000000..b3fc71096 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/service/TellerWritePlatformServiceJpaImpl.java @@ -0,0 +1,345 @@ +package org.mifosplatform.organisation.teller.service; + +import java.util.Map; + +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder; +import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException; +import org.mifosplatform.infrastructure.security.exception.NoAuthorizationException; +import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; +import org.mifosplatform.organisation.office.domain.Office; +import org.mifosplatform.organisation.office.domain.OfficeRepository; +import org.mifosplatform.organisation.office.exception.OfficeNotFoundException; +import org.mifosplatform.organisation.staff.domain.Staff; +import org.mifosplatform.organisation.staff.domain.StaffRepository; +import org.mifosplatform.organisation.staff.exception.StaffNotFoundException; +import org.mifosplatform.organisation.teller.domain.Cashier; +import org.mifosplatform.organisation.teller.domain.CashierRepository; +import org.mifosplatform.organisation.teller.domain.CashierTransaction; +import org.mifosplatform.organisation.teller.domain.CashierTransactionRepository; +import org.mifosplatform.organisation.teller.domain.CashierTxnType; +import org.mifosplatform.organisation.teller.domain.Teller; +import org.mifosplatform.organisation.teller.domain.TellerRepository; +import org.mifosplatform.organisation.teller.exception.CashierNotFoundException; +import org.mifosplatform.organisation.teller.exception.TellerNotFoundException; +import org.mifosplatform.organisation.teller.serialization.TellerCommandFromApiJsonDeserializer; +import org.mifosplatform.useradministration.domain.AppUser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformService { + + private final static Logger logger = LoggerFactory.getLogger(TellerWritePlatformServiceJpaImpl.class); + + private final PlatformSecurityContext context; + private final TellerCommandFromApiJsonDeserializer fromApiJsonDeserializer; + private final TellerRepository tellerRepository; + private final OfficeRepository officeRepository; + private final StaffRepository staffRepository; + private final CashierRepository cashierRepository; + private final CashierTransactionRepository cashierTxnRepository; + + @Autowired + public TellerWritePlatformServiceJpaImpl (final PlatformSecurityContext context, + final TellerCommandFromApiJsonDeserializer fromApiJsonDeserializer, + final TellerRepository tellerRepository, final OfficeRepository officeRepository, + final StaffRepository staffRepository, CashierRepository cashierRepository, + CashierTransactionRepository cashierTxnRepository) { + this.context = context; + this.fromApiJsonDeserializer = fromApiJsonDeserializer; + this.tellerRepository = tellerRepository; + this.officeRepository = officeRepository; + this.staffRepository = staffRepository; + this.cashierRepository = cashierRepository; + this.cashierTxnRepository = cashierTxnRepository; + } + + + @Override + @Transactional + public CommandProcessingResult createTeller(JsonCommand command) { + try { + final AppUser currentUser = this.context.authenticatedUser(); + + final Long officeId = command.longValueOfParameterNamed("officeId"); + + this.fromApiJsonDeserializer.validateForCreate(command.json()); + + // final Office parent = validateUserPriviledgeOnOfficeAndRetrieve(currentUser, officeId); + final Office tellerOffice = this.officeRepository.findOne(officeId); + if (tellerOffice == null) { throw new OfficeNotFoundException(officeId); } + + final Teller teller = Teller.fromJson(tellerOffice, command); + + // pre save to generate id for use in office hierarchy + this.tellerRepository.save(teller); + + return new CommandProcessingResultBuilder() // + .withCommandId(command.commandId()) // + .withEntityId(teller.getId()) // + .withOfficeId(teller.getOffice().getId()) // + .build(); + } catch (final DataIntegrityViolationException dve) { + handleTellerDataIntegrityIssues(command, dve); + return CommandProcessingResult.empty(); + } + } + + @Override + @Transactional + public CommandProcessingResult modifyTeller(Long tellerId, + JsonCommand command) { + try { + + final Long officeId = command.longValueOfParameterNamed("officeId"); + final Office tellerOffice = this.officeRepository.findOne(officeId); + if (tellerOffice == null) { throw new OfficeNotFoundException(officeId); } + + final AppUser currentUser = this.context.authenticatedUser(); + + this.fromApiJsonDeserializer.validateForUpdate(command.json()); + + final Teller teller = validateUserPriviledgeOnTellerAndRetrieve(currentUser, tellerId); + + final Map changes = teller.update(tellerOffice, command); + + if (!changes.isEmpty()) { + this.tellerRepository.saveAndFlush(teller); + } + + return new CommandProcessingResultBuilder() // + .withCommandId(command.commandId()) // + .withEntityId(teller.getId()) // + .withOfficeId(teller.officeId()) // + .with(changes) // + .build(); + } catch (final DataIntegrityViolationException dve) { + handleTellerDataIntegrityIssues(command, dve); + return CommandProcessingResult.empty(); + } + } + + /* + * used to restrict modifying operations to office that are either the users + * office or lower (child) in the office hierarchy + */ + private Teller validateUserPriviledgeOnTellerAndRetrieve(final AppUser currentUser, final Long tellerId) { + + final Long userOfficeId = currentUser.getOffice().getId(); + final Office userOffice = this.officeRepository.findOne(userOfficeId); + if (userOffice == null) { throw new OfficeNotFoundException(userOfficeId); } + + final Teller tellerToReturn = this.tellerRepository.findOne(tellerId); + if (tellerToReturn != null) { + final Long tellerOfficeId = tellerToReturn.officeId(); + if (userOffice.doesNotHaveAnOfficeInHierarchyWithId(tellerOfficeId)) { throw new NoAuthorizationException( + "User does not have sufficient priviledges to act on the provided office."); } + } else { + throw new TellerNotFoundException(tellerId); + } + + return tellerToReturn; + } + + @Override + @Transactional + public CommandProcessingResult deleteTeller(Long tellerId) { + // TODO Auto-generated method stub + return null; + } + + /* + * Guaranteed to throw an exception no matter what the data integrity issue + * is. + */ + private void handleTellerDataIntegrityIssues(final JsonCommand command, final DataIntegrityViolationException dve) { + + final Throwable realCause = dve.getMostSpecificCause(); + if (realCause.getMessage().contains("m_tellers_name_unq")) { + final String name = command.stringValueOfParameterNamed("name"); + throw new PlatformDataIntegrityException("error.msg.teller.duplicate.name", "Teller with name `" + name + "` already exists", + "name", name); + } + + logger.error(dve.getMessage(), dve); + throw new PlatformDataIntegrityException("error.msg.teller.unknown.data.integrity.issue", + "Unknown data integrity issue with resource."); + } + + + @Override + public CommandProcessingResult allocateCashierToTeller(final Long tellerId, JsonCommand command) { + try { + final AppUser currentUser = this.context.authenticatedUser(); + + // final Office parent = validateUserPriviledgeOnOfficeAndRetrieve(currentUser, officeId); + final Teller teller = this.tellerRepository.findOne(tellerId); + if (teller == null) { throw new TellerNotFoundException(tellerId); } + final Office tellerOffice = teller.getOffice(); + + final Long staffId = command.longValueOfParameterNamed("staffId"); + + this.fromApiJsonDeserializer.validateForAllocateCashier(command.json()); + + + final Staff staff = this.staffRepository.findOne(staffId); + if (staff == null) { throw new StaffNotFoundException(staffId); } + + final Cashier cashier = Cashier.fromJson(tellerOffice, teller, staff, + command); + + // pre save to generate id for use in office hierarchy + this.cashierRepository.save(cashier); + + return new CommandProcessingResultBuilder() // + .withCommandId(command.commandId()) // + .withEntityId(teller.getId()) // + .withSubEntityId(cashier.getId()) // + .build(); + } catch (final DataIntegrityViolationException dve) { + handleTellerDataIntegrityIssues(command, dve); + return CommandProcessingResult.empty(); + } + } + + @Override + @Transactional + public CommandProcessingResult updateCashierAllocation (Long tellerId, Long cashierId, + JsonCommand command) { + try { + final AppUser currentUser = this.context.authenticatedUser(); + + this.fromApiJsonDeserializer.validateForAllocateCashier(command.json()); + + final Long staffId = command.longValueOfParameterNamed("staffId"); + final Staff staff = this.staffRepository.findOne(staffId); + if (staff == null) { throw new StaffNotFoundException(staffId); } + + final Cashier cashier = validateUserPriviledgeOnCashierAndRetrieve(currentUser, tellerId, cashierId); + + cashier.setStaff(staff); + + //TODO - check if staff office and teller office match + + final Map changes = cashier.update(command); + + if (!changes.isEmpty()) { + this.cashierRepository.saveAndFlush(cashier); + } + + return new CommandProcessingResultBuilder() // + .withCommandId(command.commandId()) // + .withEntityId(cashier.getTeller().getId()) // + .withSubEntityId(cashier.getId()) // + .with(changes) // + .build(); + } catch (final DataIntegrityViolationException dve) { + handleTellerDataIntegrityIssues(command, dve); + return CommandProcessingResult.empty(); + } + } + + private Cashier validateUserPriviledgeOnCashierAndRetrieve(final AppUser currentUser, + final Long tellerId, final Long cashierId) { + + validateUserPriviledgeOnTellerAndRetrieve(currentUser, tellerId); + + final Cashier cashierToReturn = this.cashierRepository.findOne(cashierId); + + return cashierToReturn; + } + + @Override + @Transactional + public CommandProcessingResult deleteCashierAllocation (Long tellerId, Long cashierId, + JsonCommand command) { + try { + final AppUser currentUser = this.context.authenticatedUser(); + final Cashier cashier = validateUserPriviledgeOnCashierAndRetrieve(currentUser, tellerId, cashierId); + this.cashierRepository.delete(cashier); + + } catch (final DataIntegrityViolationException dve) { + handleTellerDataIntegrityIssues(command, dve); + return CommandProcessingResult.empty(); + } + + return new CommandProcessingResultBuilder() // + .withEntityId(cashierId) // + .build(); + } + + /* + @Override + public CommandProcessingResult inwardCashToCashier (final Long cashierId, + final CashierTransaction cashierTxn) { + CashierTxnType txnType = CashierTxnType.INWARD_CASH_TXN; + // pre save to generate id for use in office hierarchy + this.cashierTxnRepository.save(cashierTxn); + } */ + + @Override + public CommandProcessingResult allocateCashToCashier(final Long cashierId, JsonCommand command) { + return doTransactionForCashier(cashierId, CashierTxnType.ALLOCATE, command); // For fund allocation to cashier + } + + @Override + public CommandProcessingResult settleCashFromCashier(final Long cashierId, JsonCommand command) { + return doTransactionForCashier(cashierId, CashierTxnType.SETTLE, command); // For fund settlement from cashier + } + + private CommandProcessingResult doTransactionForCashier(final Long cashierId, + final CashierTxnType txnType, JsonCommand command) { + try { + final AppUser currentUser = this.context.authenticatedUser(); + + final Cashier cashier = this.cashierRepository.findOne(cashierId); + if (cashier == null) { throw new CashierNotFoundException(cashierId); } + + this.fromApiJsonDeserializer.validateForCashTxnForCashier(command.json()); + + final String entityType = command.stringValueOfParameterNamed("entityType"); + final Long entityId = command.longValueOfParameterNamed("entityId"); + if (entityType != null) { + if (entityType.equals("loan account")) { + // TODO : Check if loan account exists + // LoanAccount loan = null; + // if (loan == null) { throw new LoanAccountFoundException(entityId); } + } else if (entityType.equals("savings account")) { + // TODO : Check if loan account exists + // SavingsAccount savingsaccount = null; + // if (savingsaccount == null) { throw new SavingsAccountNotFoundException(entityId); } + + } if (entityType.equals("client")) { + // TODO: Check if client exists + // Client client = null; + // if (client == null) { throw new ClientNotFoundException(entityId); } + } else { + // TODO : Invalid type handling + } + } + + final CashierTransaction cashierTxn = CashierTransaction.fromJson(cashier, command); + cashierTxn.setTxnType(txnType.getId()); + + // pre save to generate id for use in office hierarchy + this.cashierTxnRepository.save(cashierTxn); + + return new CommandProcessingResultBuilder() // + .withCommandId(command.commandId()) // + .withEntityId(cashier.getId()) // + .withSubEntityId(cashierTxn.getId()) // + .build(); + } catch (final DataIntegrityViolationException dve) { + handleTellerDataIntegrityIssues(command, dve); + return CommandProcessingResult.empty(); + } + } + + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/util/DateRange.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/util/DateRange.java new file mode 100644 index 000000000..ac7f18018 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/util/DateRange.java @@ -0,0 +1,80 @@ +package org.mifosplatform.organisation.teller.util; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.StringTokenizer; + +public class DateRange { + + private static final String ISO_8601_DATE_PATTERN = "yyy-MM-dd"; + private static final String RANGE_DELIMITER = ".."; + + private Date startDate; + private Date endDate; + + public DateRange() { + super(); + } + + public Date getStartDate() { + return startDate; + } + + public void setStartDate(Date startDate) { + this.startDate = startDate; + } + + public Date getEndDate() { + return endDate; + } + + public void setEndDate(Date endDate) { + this.endDate = endDate; + } + + public static DateRange fromString(final String dateToParse) { + + final DateRange dateRange = new DateRange(); + final SimpleDateFormat sdf = new SimpleDateFormat(DateRange.ISO_8601_DATE_PATTERN); + final Calendar cal = Calendar.getInstance(); + + final String testee; + if (dateToParse == null) { + testee = sdf.format(cal.getTime()); + } else { + testee = dateToParse; + } + + final StringTokenizer tokenizer = new StringTokenizer(testee, DateRange.RANGE_DELIMITER); + + try { + cal.setTime(sdf.parse(tokenizer.nextToken())); + } catch (ParseException ex) { + + } + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + + dateRange.setStartDate(cal.getTime()); + + if (tokenizer.hasMoreTokens()) { + try { + cal.setTime(sdf.parse(tokenizer.nextToken())); + } catch (ParseException ex) { + + } + } + cal.set(Calendar.HOUR_OF_DAY, 23); + cal.set(Calendar.MINUTE, 59); + cal.set(Calendar.SECOND, 59); + cal.set(Calendar.MILLISECOND, 999); + + dateRange.setEndDate(cal.getTime()); + + return dateRange; + } +} diff --git a/mifosng-provider/src/main/resources/sql/migrations/core_db/V87002__teller_cash_management.sql b/mifosng-provider/src/main/resources/sql/migrations/core_db/V87002__teller_cash_management.sql new file mode 100644 index 000000000..f47fe20c8 --- /dev/null +++ b/mifosng-provider/src/main/resources/sql/migrations/core_db/V87002__teller_cash_management.sql @@ -0,0 +1,107 @@ +CREATE TABLE `m_tellers` ( + `id` BIGINT(20) NOT NULL AUTO_INCREMENT, + `office_id` BIGINT(20) NOT NULL, + `debit_account_id` BIGINT(20), + `credit_account_id` BIGINT(20), + `name` VARCHAR(50) NOT NULL, + `description` VARCHAR(100), + `valid_from` DATE, + `valid_to` DATE, + `state` SMALLINT(5), + PRIMARY KEY (`id`), + UNIQUE INDEX `m_tellers_name_unq` (`name`), + INDEX `IK_m_tellers_m_office` (`office_id`), + CONSTRAINT `FK_m_tellers_m_office` FOREIGN KEY (`office_id`) REFERENCES `m_office` (`id`), + CONSTRAINT `FK_m_tellers_gl_account_debit_account_id` FOREIGN KEY (`debit_account_id`) REFERENCES `acc_gl_account` (`id`), + CONSTRAINT `FK_m_tellers_gl_account_credit_account_id` FOREIGN KEY (`credit_account_id`) REFERENCES `acc_gl_account` (`id`) + ); + +CREATE TABLE `m_cashiers` ( + `id` BIGINT(20) NOT NULL AUTO_INCREMENT, + `staff_id` BIGINT(20), + `teller_id` BIGINT(20), + `description` VARCHAR(100), + `start_date` DATE, + `end_date` DATE, + `start_time` varchar(10), + `end_time` varchar(10), + `full_day` TINYINT, + PRIMARY KEY (`id`), + INDEX `IK_m_cashiers_m_staff` (`staff_id`), + INDEX `IK_m_cashiers_m_teller` (`teller_id`), + CONSTRAINT `FK_m_cashiers_m_staff` FOREIGN KEY (`staff_id`) REFERENCES `m_staff` (`id`), + CONSTRAINT `FK_m_cashiers_m_teller` FOREIGN KEY (`teller_id`) REFERENCES `m_tellers` (`id`) + ); + +CREATE TABLE `m_cashier_transactions` ( + `id` BIGINT(20) NOT NULL AUTO_INCREMENT, + `cashier_id` BIGINT(20) NOT NULL, + `txn_type` SMALLINT(5) NOT NULL, + `txn_amount` DECIMAL (19,6) NOT NULL, + `txn_date` DATE NOT NULL, + `created_date` DATETIME NOT NULL, + `entity_type` VARCHAR(50), + `entity_id` BIGINT(20), + `txn_note` VARCHAR(200), + PRIMARY KEY (`id`), + INDEX `IK_m_teller_transactions_m_cashier` (`cashier_id`), + CONSTRAINT `FK_m_teller_transactions_m_cashiers` FOREIGN KEY (`cashier_id`) REFERENCES `m_cashiers` (`id`) + ); + + + INSERT INTO m_permission ( + grouping, code, entity_name, action_name, can_maker_checker + ) values ( + 'cash_mgmt', 'CREATE_TELLER', 'TELLER', 'CREATE', 1 + ); + INSERT INTO m_permission ( + grouping, code, entity_name, action_name, can_maker_checker + ) values ( + 'cash_mgmt', 'UPDATE_TELLER', 'TELLER', 'CREATE', 1 + ); + + INSERT INTO m_permission ( + grouping, code, entity_name, action_name, can_maker_checker + ) values ( + 'cash_mgmt', 'ALLOCATECASHIER_TELLER', 'TELLER', 'ALLOCATE', 1 + ); + + INSERT INTO m_permission ( + grouping, code, entity_name, action_name, can_maker_checker + ) values ( + 'cash_mgmt', 'UPDATECASHIERALLOCATION_TELLER', 'TELLER', 'UPDATECASHIERALLOCATION', 1 + ); + + INSERT INTO m_permission ( + grouping, code, entity_name, action_name, can_maker_checker + ) values ( + 'cash_mgmt', 'DELETECASHIERALLOCATION_TELLER', 'TELLER', 'DELETECASHIERALLOCATION', 1 + ); + + INSERT INTO m_permission ( + grouping, code, entity_name, action_name, can_maker_checker + ) values ( + 'cash_mgmt', 'ALLOCATECASHTOCASHIER_TELLER', 'TELLER', 'ALLOCATECASHTOCASHIER', 1 + ); + + INSERT INTO m_permission ( + grouping, code, entity_name, action_name, can_maker_checker + ) values ( + 'cash_mgmt', 'SETTLECASHFROMCASHIER_TELLER', 'TELLER', 'SETTLECASHFROMCASHIER', 1 + ); + + INSERT INTO r_enum_value ( + enum_name, enum_id, enum_message_property, enum_value, enum_type + ) values ( + 'teller_status', 300, 'Active', 'Active',0 + ); + INSERT INTO r_enum_value ( + enum_name, enum_id, enum_message_property, enum_value, enum_type + ) values ( + 'teller_status', 400, 'Inactive', 'Inactive',0 + ); + INSERT INTO r_enum_value ( + enum_name, enum_id, enum_message_property, enum_value, enum_type + ) values ( + 'teller_status', 600, 'Closed', 'Closed',0 + ); \ No newline at end of file