From 3cb99328eb36fb9f4225d37995ee5120d67502e5 Mon Sep 17 00:00:00 2001 From: MithunKashyap Date: Wed, 25 Mar 2015 22:09:24 +0530 Subject: [PATCH] MIFOSX-1892:Bug fix for Teller cash management --- .../organisation/teller/domain/Cashier.java | 287 ++++++++++----- .../domain/CashierRepositoryWrapper.java | 26 ++ .../organisation/teller/domain/Teller.java | 24 +- .../domain/TellerRepositoryWrapper.java | 27 ++ .../CashierExistForTellerException.java | 20 + .../exception/InvalidDateInputException.java | 16 + .../handler/DeleteTellerCommandHandler.java | 2 + .../TellerCommandFromApiJsonDeserializer.java | 54 +-- .../TellerWritePlatformServiceJpaImpl.java | 342 ++++++++++-------- .../V249__bug_fix_teller_cash_management.sql | 13 + 10 files changed, 529 insertions(+), 282 deletions(-) create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/CashierRepositoryWrapper.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/TellerRepositoryWrapper.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/exception/CashierExistForTellerException.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/exception/InvalidDateInputException.java create mode 100644 mifosng-provider/src/main/resources/sql/migrations/core_db/V249__bug_fix_teller_cash_management.sql 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 index a3848ee49..2c52255c7 100644 --- 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 @@ -5,7 +5,6 @@ */ 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; @@ -18,21 +17,21 @@ 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. - * + * 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"}) -}) +@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 + @Transient private Office office; @ManyToOne(fetch = FetchType.LAZY) @@ -69,45 +68,44 @@ public class Cashier extends AbstractPersistable { public Cashier() { super(); } - - public static Cashier fromJson(final Office cashierOffice, - final Teller teller, - final Staff staff, - final JsonCommand command) { + + public static Cashier fromJson(final Office cashierOffice, final Teller teller, final Staff staff, final String startTime, + final String endTime, 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"); + /* + * final String startTime = + * command.stringValueOfParameterNamed("startTime"); final String + * endTime = command.stringValueOfParameterNamed("endTime"); + */ - return new Cashier (cashierOffice, teller, staff, description, startDate, endDate, - isFullDay, startTime, 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 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 localeAsInput = command.locale(); + final String descriptionParamName = "description"; if (command.isChangeInStringParameterNamed(descriptionParamName, this.description)) { final String newValue = command.stringValueOfParameterNamed(descriptionParamName); @@ -136,38 +134,66 @@ public class Cashier extends AbstractPersistable { 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.startTime="00"; this.endTime="00"; + */ 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; + + if (!isFullDay) { + String newStartHour = ""; + String newStartMin = ""; + String newEndHour = ""; + String newEndMin = ""; + final String hourStartTimeParamName = "hourStartTime"; + final String minStartTimeParamName = "minStartTime"; + final String hourEndTimeParamName = "hourEndTime"; + final String minEndTimeParamName = "minEndTime"; + if (command.isChangeInLongParameterNamed(hourStartTimeParamName, this.getHourFromStartTime()) + || command.isChangeInLongParameterNamed(minStartTimeParamName, this.getMinFromStartTime())) { + newStartHour = command.stringValueOfParameterNamed(hourStartTimeParamName); + if(newEndHour.equalsIgnoreCase("0")){ + newEndHour= newEndHour + "0"; + } + actualChanges.put(hourStartTimeParamName, newStartHour); + newStartMin = command.stringValueOfParameterNamed(minStartTimeParamName); + if(newStartMin.equalsIgnoreCase("0")){ + newStartMin= newStartMin + "0"; + } + actualChanges.put(minStartTimeParamName, newStartMin); + this.startTime = newStartHour + ":" + newStartMin; + } + + if (command.isChangeInLongParameterNamed(hourEndTimeParamName, this.getHourFromEndTime()) + || command.isChangeInLongParameterNamed(minEndTimeParamName, this.getMinFromEndTime())) { + newEndHour = command.stringValueOfParameterNamed(hourEndTimeParamName); + if(newEndHour.equalsIgnoreCase("0")){ + newEndHour= newEndHour + "0"; + } + actualChanges.put(hourEndTimeParamName, newEndHour); + newEndMin = command.stringValueOfParameterNamed(minEndTimeParamName); + if(newEndMin.equalsIgnoreCase("0")){ + newEndMin= newEndMin + "0"; + } + actualChanges.put(minEndTimeParamName, newEndMin); + this.endTime = newEndHour + ":" + newEndMin; + } + } - - 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 */ @@ -175,10 +201,47 @@ public class Cashier extends AbstractPersistable { return office; } + public Long getHourFromStartTime() { + if (this.startTime != null && !this.startTime.equalsIgnoreCase("")) { + String[] extractHourFromStartTime = this.startTime.split(":"); + Long hour = Long.parseLong(extractHourFromStartTime[1]); + return hour; + } + return null; + } + + public Long getMinFromStartTime() { + if (this.startTime != null && !this.startTime.equalsIgnoreCase("")) { + String[] extractMinFromStartTime = this.startTime.split(":"); + Long min = Long.parseLong(extractMinFromStartTime[1]); + return min; + } + return null; + } + + public Long getHourFromEndTime() { + if (this.endTime != null && !this.endTime.equalsIgnoreCase("")) { + String[] extractHourFromEndTime = this.endTime.split(":"); + Long hour = Long.parseLong(extractHourFromEndTime[0]); + return hour; + } + return null; + } + + public Long getMinFromEndTime() { + if (this.endTime != null && !this.endTime.equalsIgnoreCase("")) { + String[] extractMinFromEndTime = this.endTime.split(":"); + Long min = Long.parseLong(extractMinFromEndTime[1]); + return min; + } + return null; + } + /** * Sets the office of this cashier. - * - * @param office the office of this cashier + * + * @param office + * the office of this cashier * @see org.mifosplatform.organisation.office.domain.Office */ public void setOffice(Office office) { @@ -187,7 +250,7 @@ public class Cashier extends AbstractPersistable { /** * Returns the staff of this cashier. - * + * * @return the staff of this cashier * @see org.mifosplatform.organisation.staff.domain.Staff */ @@ -197,8 +260,9 @@ public class Cashier extends AbstractPersistable { /** * Sets the staff of this cashier. - * - * @param staff the staff of this cashier + * + * @param staff + * the staff of this cashier * @see org.mifosplatform.organisation.staff.domain.Staff */ public void setStaff(Staff staff) { @@ -207,7 +271,7 @@ public class Cashier extends AbstractPersistable { /** * Returns the teller of this cashier. - * + * * @return the teller of this cashier * @see org.mifosplatform.organisation.teller.domain.Teller */ @@ -217,8 +281,9 @@ public class Cashier extends AbstractPersistable { /** * Sets the teller of this cashier. - * - * @param teller the teller of this cashier + * + * @param teller + * the teller of this cashier * @see org.mifosplatform.organisation.teller.domain.Teller */ public void setTeller(Teller teller) { @@ -226,9 +291,8 @@ public class Cashier extends AbstractPersistable { } /** - * Returns the description of this cashier. - * . - * + * Returns the description of this cashier. . + * * @return the description of this cashier or {@code null} if not present. */ public String getDescription() { @@ -237,8 +301,9 @@ public class Cashier extends AbstractPersistable { /** * Sets the description of this cashier. - * - * @param description the description of this cashier + * + * @param description + * the description of this cashier */ public void setDescription(String description) { this.description = description; @@ -247,15 +312,17 @@ public class Cashier extends AbstractPersistable { /** * 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.

- * + *

+ * 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) { @@ -267,10 +334,13 @@ public class Cashier extends AbstractPersistable { /** * 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 + *

+ * 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; @@ -279,15 +349,17 @@ public class Cashier extends AbstractPersistable { /** * 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.

- * + *

+ * 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) { @@ -299,10 +371,13 @@ public class Cashier extends AbstractPersistable { /** * 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 + *

+ * 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; @@ -310,8 +385,9 @@ public class Cashier extends AbstractPersistable { /** * Returns whether this cashier works part time or not. - * - * @return {@code true} if this cashier works part time; {@code false} otherwise + * + * @return {@code true} if this cashier works part time; {@code false} + * otherwise */ public Boolean isFullDay() { return isFullDay; @@ -319,19 +395,22 @@ public class Cashier extends AbstractPersistable { /** * Sets the part time flag of this cashier. - * - * @param partTime the part time flag of this cashier + * + * @param partTime + * the part time flag of this cashier */ - public void setFullDay (Boolean isFullDay) { + 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.

- * + *

+ * 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() { @@ -341,10 +420,13 @@ public class Cashier extends AbstractPersistable { /** * 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 + *

+ * 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; @@ -353,9 +435,11 @@ public class Cashier extends AbstractPersistable { /** * 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.

- * + *

+ * 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() { @@ -365,10 +449,13 @@ public class Cashier extends AbstractPersistable { /** * 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 + *

+ * 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/CashierRepositoryWrapper.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/CashierRepositoryWrapper.java new file mode 100644 index 000000000..737423cad --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/CashierRepositoryWrapper.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.domain; + +import org.mifosplatform.organisation.teller.exception.TellerNotFoundException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class CashierRepositoryWrapper { + private final CashierRepository repository; + + @Autowired + public CashierRepositoryWrapper(final CashierRepository repository) { + this.repository = repository; + } + + public Cashier findOneWithNotFoundDetection(final Long id) { + final Cashier cashier = this.repository.findOne(id); + if (cashier == null) { throw new TellerNotFoundException(id); } + return cashier; + } +} 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 index a17caa4cd..d3db6886c 100644 --- 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 @@ -5,21 +5,29 @@ */ package org.mifosplatform.organisation.teller.domain; +import java.util.Date; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.persistence.UniqueConstraint; + 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"}) diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/TellerRepositoryWrapper.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/TellerRepositoryWrapper.java new file mode 100644 index 000000000..0f90ec402 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/domain/TellerRepositoryWrapper.java @@ -0,0 +1,27 @@ +/** + * 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.teller.exception.TellerNotFoundException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class TellerRepositoryWrapper { + + private final TellerRepository repository; + + @Autowired + public TellerRepositoryWrapper(final TellerRepository repository) { + this.repository = repository; + } + + public Teller findOneWithNotFoundDetection(final Long id) { + final Teller teller = this.repository.findOne(id); + if (teller == null) { throw new TellerNotFoundException(id); } + return teller; + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/exception/CashierExistForTellerException.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/exception/CashierExistForTellerException.java new file mode 100644 index 000000000..545dbb1f0 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/exception/CashierExistForTellerException.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.exception; + +import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException; + + +public class CashierExistForTellerException extends AbstractPlatformDomainRuleException{ + + private static final String ERROR_MESSAGE_CODE = "error.msg.cashier.is.associated.with.this.teller"; + private static final String DEFAULT_ERROR_MESSAGE = "Cannot delete teller, Cashier is associated for this teller "; + + public CashierExistForTellerException(Long tellerId) { + super(ERROR_MESSAGE_CODE, DEFAULT_ERROR_MESSAGE, tellerId); + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/exception/InvalidDateInputException.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/exception/InvalidDateInputException.java new file mode 100644 index 000000000..848120d88 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/teller/exception/InvalidDateInputException.java @@ -0,0 +1,16 @@ +/** + * 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; + + +public class InvalidDateInputException extends AbstractPlatformResourceNotFoundException { + + public InvalidDateInputException(final String startDate,final String endDate) { + super("error.msg.invalid.endDate", "EndDate " + endDate + " cannot be before StartDate "+startDate); + } +} \ No newline at end of file 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 index 6235fb2fc..5ed3f08a8 100644 --- 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 @@ -10,6 +10,7 @@ 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. @@ -18,6 +19,7 @@ import org.springframework.beans.factory.annotation.Autowired; * @see org.mifosplatform.organisation.teller.service.TellerWritePlatformService * @since 2.0.0 */ +@Service public class DeleteTellerCommandHandler implements NewCommandSourceHandler { private final TellerWritePlatformService writePlatformService; 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 index 865f5164e..da355a6a0 100644 --- 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 @@ -22,6 +22,7 @@ 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.mifosplatform.organisation.teller.exception.InvalidDateInputException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -38,11 +39,9 @@ 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", "currencyCode")); + private final Set supportedParameters = new HashSet<>(Arrays.asList("officeId", "name", "description", "startDate", "endDate", + "status", "dateFormat", "locale", "isFullDay", "staffId", "hourStartTime", "minStartTime", "hourEndTime", "minEndTime", + "txnAmount", "txnDate", "txnNote", "entityType", "entityId", "currencyCode")); private final FromJsonHelper fromApiJsonHelper; @@ -64,7 +63,7 @@ public final class TellerCommandFromApiJsonDeserializer { 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); @@ -75,10 +74,14 @@ public final class TellerCommandFromApiJsonDeserializer { baseDataValidator.reset().parameter("startDate").value(startDate).notNull(); final LocalDate endDate = this.fromApiJsonHelper.extractLocalDateNamed("endDate", element); - + baseDataValidator.reset().parameter("startDate").value(endDate).ignoreIfNull(); + final String status = this.fromApiJsonHelper.extractStringNamed("status", element); baseDataValidator.reset().parameter("status").value(status).notBlank().notExceedingLengthOf(50); + if (endDate != null) { + if (endDate.isAfter(startDate)) { throw new InvalidDateInputException(startDate.toString(), endDate.toString()); } + } throwExceptionIfValidationWarningsExist(dataValidationErrors); } @@ -106,14 +109,14 @@ public final class TellerCommandFromApiJsonDeserializer { 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) { + + public void validateForAllocateCashier(final String json) { if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } final Type typeOfMap = new TypeToken>() {}.getType(); @@ -126,7 +129,7 @@ public final class TellerCommandFromApiJsonDeserializer { 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); @@ -135,17 +138,26 @@ public final class TellerCommandFromApiJsonDeserializer { 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); - + + if (!isFullDay) { + final String hourStartTime = this.fromApiJsonHelper.extractStringNamed("hourStartTime", element); + baseDataValidator.reset().parameter("startTime").value(hourStartTime).notBlank(); + final String minStartTime = this.fromApiJsonHelper.extractStringNamed("minStartTime", element); + baseDataValidator.reset().parameter("startTime").value(minStartTime).notBlank(); + final String hourEndTime = this.fromApiJsonHelper.extractStringNamed("hourEndTime", element); + baseDataValidator.reset().parameter("hourEndTime").value(hourEndTime).notBlank(); + final String minEndTime = this.fromApiJsonHelper.extractStringNamed("minEndTime", element); + baseDataValidator.reset().parameter("minEndTime").value(minEndTime).notBlank(); + + } + throwExceptionIfValidationWarningsExist(dataValidationErrors); } - - public void validateForCashTxnForCashier (final String json) { + + public void validateForCashTxnForCashier(final String json) { if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } final Type typeOfMap = new TypeToken>() {}.getType(); @@ -156,15 +168,15 @@ public final class TellerCommandFromApiJsonDeserializer { final JsonElement element = this.fromApiJsonHelper.parse(json); - final BigDecimal txnAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("txnAmount", element); + 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); - + final String currencyCode = this.fromApiJsonHelper.extractStringNamed("currencyCode", element); baseDataValidator.reset().parameter("currencyCode").value(currencyCode).notExceedingLengthOf(3); } 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 index ff774baa7..08343f6c3 100644 --- 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 @@ -6,14 +6,15 @@ package org.mifosplatform.organisation.teller.service; import java.util.Map; +import java.util.Set; import org.mifosplatform.accounting.common.AccountingConstants.FINANCIAL_ACTIVITY; import org.mifosplatform.accounting.financialactivityaccount.domain.FinancialActivityAccount; import org.mifosplatform.accounting.financialactivityaccount.domain.FinancialActivityAccountRepositoryWrapper; import org.mifosplatform.accounting.glaccount.domain.GLAccount; import org.mifosplatform.accounting.journalentry.domain.JournalEntry; -import org.mifosplatform.accounting.journalentry.domain.JournalEntryType; import org.mifosplatform.accounting.journalentry.domain.JournalEntryRepository; +import org.mifosplatform.accounting.journalentry.domain.JournalEntryType; import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder; @@ -33,6 +34,8 @@ 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.domain.TellerRepositoryWrapper; +import org.mifosplatform.organisation.teller.exception.CashierExistForTellerException; import org.mifosplatform.organisation.teller.exception.CashierNotFoundException; import org.mifosplatform.organisation.teller.exception.TellerNotFoundException; import org.mifosplatform.organisation.teller.serialization.TellerCommandFromApiJsonDeserializer; @@ -47,51 +50,50 @@ import org.springframework.transaction.annotation.Transactional; @Service public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformService { - private final static Logger logger = LoggerFactory.getLogger(TellerWritePlatformServiceJpaImpl.class); + private final static Logger logger = LoggerFactory.getLogger(TellerWritePlatformServiceJpaImpl.class); private final PlatformSecurityContext context; private final TellerCommandFromApiJsonDeserializer fromApiJsonDeserializer; private final TellerRepository tellerRepository; + private final TellerRepositoryWrapper tellerRepositoryWrapper; private final OfficeRepository officeRepository; private final StaffRepository staffRepository; private final CashierRepository cashierRepository; private final CashierTransactionRepository cashierTxnRepository; private final JournalEntryRepository glJournalEntryRepository; private final FinancialActivityAccountRepositoryWrapper financialActivityAccountRepositoryWrapper; - - + @Autowired - public TellerWritePlatformServiceJpaImpl (final PlatformSecurityContext context, - final TellerCommandFromApiJsonDeserializer fromApiJsonDeserializer, - final TellerRepository tellerRepository, final OfficeRepository officeRepository, - final StaffRepository staffRepository, CashierRepository cashierRepository, - CashierTransactionRepository cashierTxnRepository, + public TellerWritePlatformServiceJpaImpl(final PlatformSecurityContext context, + final TellerCommandFromApiJsonDeserializer fromApiJsonDeserializer, final TellerRepository tellerRepository, + final TellerRepositoryWrapper tellerRepositoryWrapper, final OfficeRepository officeRepository, + final StaffRepository staffRepository, CashierRepository cashierRepository, CashierTransactionRepository cashierTxnRepository, JournalEntryRepository glJournalEntryRepository, - FinancialActivityAccountRepositoryWrapper financialActivityAccountRepositoryWrapper - ) { + FinancialActivityAccountRepositoryWrapper financialActivityAccountRepositoryWrapper) { this.context = context; this.fromApiJsonDeserializer = fromApiJsonDeserializer; this.tellerRepository = tellerRepository; + this.tellerRepositoryWrapper = tellerRepositoryWrapper; this.officeRepository = officeRepository; this.staffRepository = staffRepository; this.cashierRepository = cashierRepository; this.cashierTxnRepository = cashierTxnRepository; this.glJournalEntryRepository = glJournalEntryRepository; - this.financialActivityAccountRepositoryWrapper = financialActivityAccountRepositoryWrapper; + this.financialActivityAccountRepositoryWrapper = financialActivityAccountRepositoryWrapper; } - - @Override - @Transactional - public CommandProcessingResult createTeller(JsonCommand command) { - try { + @Override + @Transactional + public CommandProcessingResult createTeller(JsonCommand command) { + try { this.context.authenticatedUser(); - + final Long officeId = command.longValueOfParameterNamed("officeId"); this.fromApiJsonDeserializer.validateForCreate(command.json()); - - // final Office parent = validateUserPriviledgeOnOfficeAndRetrieve(currentUser, officeId); + + // final Office parent = + // validateUserPriviledgeOnOfficeAndRetrieve(currentUser, officeId); final Office tellerOffice = this.officeRepository.findOne(officeId); if (tellerOffice == null) { throw new OfficeNotFoundException(officeId); } @@ -109,15 +111,14 @@ public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformSer handleTellerDataIntegrityIssues(command, dve); return CommandProcessingResult.empty(); } - } + } - @Override - @Transactional - public CommandProcessingResult modifyTeller(Long tellerId, - JsonCommand command) { + @Override + @Transactional + public CommandProcessingResult modifyTeller(Long tellerId, JsonCommand command) { try { - - final Long officeId = command.longValueOfParameterNamed("officeId"); + + final Long officeId = command.longValueOfParameterNamed("officeId"); final Office tellerOffice = this.officeRepository.findOne(officeId); if (tellerOffice == null) { throw new OfficeNotFoundException(officeId); } @@ -143,9 +144,9 @@ public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformSer 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 */ @@ -166,14 +167,27 @@ public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformSer return tellerToReturn; } - - @Override - @Transactional - public CommandProcessingResult deleteTeller(Long tellerId) { - // TODO Auto-generated method stub - return null; - } - + + @Override + @Transactional + public CommandProcessingResult deleteTeller(Long tellerId) { + // TODO Auto-generated method stub + + Teller teller = tellerRepositoryWrapper.findOneWithNotFoundDetection(tellerId); + Set isTellerIdPresentInCashier = teller.getCashiers(); + + for (final Cashier tellerIdInCashier : isTellerIdPresentInCashier) { + if (tellerIdInCashier.getTeller().getId().toString().equalsIgnoreCase(tellerId.toString())) { throw new CashierExistForTellerException( + tellerId); } + + } + tellerRepository.delete(teller); + return new CommandProcessingResultBuilder() // + .withEntityId(teller.getId()) // + .build(); + + } + /* * Guaranteed to throw an exception no matter what the data integrity issue * is. @@ -192,27 +206,46 @@ public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformSer "Unknown data integrity issue with resource."); } - - @Override - public CommandProcessingResult allocateCashierToTeller(final Long tellerId, JsonCommand command) { - try { + @Override + public CommandProcessingResult allocateCashierToTeller(final Long tellerId, JsonCommand command) { + try { this.context.authenticatedUser(); - - // final Office parent = validateUserPriviledgeOnOfficeAndRetrieve(currentUser, officeId); + Long hourStartTime; + Long minStartTime; + Long hourEndTime; + Long minEndTime; + String startTime = " "; + String endTime = " "; 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 Boolean isFullDay = command.booleanObjectValueOfParameterNamed("isFullDay"); + if (!isFullDay) { + hourStartTime = command.longValueOfParameterNamed("hourStartTime"); + minStartTime = command.longValueOfParameterNamed("minStartTime"); - final Cashier cashier = Cashier.fromJson(tellerOffice, teller, staff, - command); + if (minStartTime == 0) + startTime = hourStartTime.toString() + ":" + minStartTime.toString() + "0"; + else + startTime = hourStartTime.toString() + ":" + minStartTime.toString(); + + hourEndTime = command.longValueOfParameterNamed("hourEndTime"); + minEndTime = command.longValueOfParameterNamed("minEndTime"); + if (minEndTime == 0) + endTime = hourEndTime.toString() + ":" + minEndTime.toString() + "0"; + else + endTime = hourEndTime.toString() + ":" + minEndTime.toString(); + + } + + final Cashier cashier = Cashier.fromJson(tellerOffice, teller, staff, startTime, endTime, command); this.cashierRepository.save(cashier); @@ -225,26 +258,25 @@ public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformSer handleTellerDataIntegrityIssues(command, dve); return CommandProcessingResult.empty(); } - } + } - @Override - @Transactional - public CommandProcessingResult updateCashierAllocation (Long tellerId, Long cashierId, - JsonCommand command) { + @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 + + // TODO - check if staff office and teller office match final Map changes = cashier.update(command); @@ -262,22 +294,20 @@ public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformSer handleTellerDataIntegrityIssues(command, dve); return CommandProcessingResult.empty(); } - } + } + + private Cashier validateUserPriviledgeOnCashierAndRetrieve(final AppUser currentUser, final Long tellerId, final Long cashierId) { + + validateUserPriviledgeOnTellerAndRetrieve(currentUser, tellerId); - 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) { + @Transactional + public CommandProcessingResult deleteCashierAllocation(Long tellerId, Long cashierId, JsonCommand command) { try { final AppUser currentUser = this.context.authenticatedUser(); final Cashier cashier = validateUserPriviledgeOnCashierAndRetrieve(currentUser, tellerId, cashierId); @@ -288,108 +318,115 @@ public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformSer 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 + return new CommandProcessingResultBuilder() // + .withEntityId(cashierId) // + .build(); } - private CommandProcessingResult doTransactionForCashier(final Long cashierId, - final CashierTxnType txnType, JsonCommand command) { - try { + /* + * @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 - } + 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()); this.cashierTxnRepository.save(cashierTxn); - + // Pass the journal entries - FinancialActivityAccount mainVaultFinancialActivityAccount = this.financialActivityAccountRepositoryWrapper. - findByFinancialActivityTypeWithNotFoundDetection( - FINANCIAL_ACTIVITY.CASH_AT_MAINVAULT.getValue()); - FinancialActivityAccount tellerCashFinancialActivityAccount = this.financialActivityAccountRepositoryWrapper. - findByFinancialActivityTypeWithNotFoundDetection( - FINANCIAL_ACTIVITY.CASH_AT_TELLER.getValue()); + FinancialActivityAccount mainVaultFinancialActivityAccount = this.financialActivityAccountRepositoryWrapper + .findByFinancialActivityTypeWithNotFoundDetection(FINANCIAL_ACTIVITY.CASH_AT_MAINVAULT.getValue()); + FinancialActivityAccount tellerCashFinancialActivityAccount = this.financialActivityAccountRepositoryWrapper + .findByFinancialActivityTypeWithNotFoundDetection(FINANCIAL_ACTIVITY.CASH_AT_TELLER.getValue()); GLAccount creditAccount = null; GLAccount debitAccount = null; - if (txnType.equals(CashierTxnType.ALLOCATE) ) { - debitAccount = tellerCashFinancialActivityAccount.getGlAccount(); - creditAccount = mainVaultFinancialActivityAccount.getGlAccount(); - } else if (txnType.equals(CashierTxnType.SETTLE) ) { - debitAccount = mainVaultFinancialActivityAccount.getGlAccount(); - creditAccount = tellerCashFinancialActivityAccount.getGlAccount(); - } - + if (txnType.equals(CashierTxnType.ALLOCATE)) { + debitAccount = tellerCashFinancialActivityAccount.getGlAccount(); + creditAccount = mainVaultFinancialActivityAccount.getGlAccount(); + } else if (txnType.equals(CashierTxnType.SETTLE)) { + debitAccount = mainVaultFinancialActivityAccount.getGlAccount(); + creditAccount = tellerCashFinancialActivityAccount.getGlAccount(); + } + final Office cashierOffice = cashier.getTeller().getOffice(); - - final Long time = System.currentTimeMillis(); - final String uniqueVal = String.valueOf(time) + currentUser.getId() + cashierOffice.getId(); - final String transactionId = Long.toHexString(Long.parseLong(uniqueVal)); - - final JournalEntry debitJournalEntry = JournalEntry.createNew( - cashierOffice, null, // payment detail - debitAccount, "USD", // FIXME: Take currency code from the transaction - transactionId, false, // manual entry - cashierTxn.getTxnDate(), JournalEntryType.DEBIT, cashierTxn.getTxnAmount(), - cashierTxn.getTxnNote(), // Description - null, null, null, // entity Type, entityId, reference number - null, null); // Loan and Savings Txn - final JournalEntry creditJournalEntry = JournalEntry.createNew( - cashierOffice, null, // payment detail - creditAccount, "USD", // FIXME: Take currency code from the transaction - transactionId, false, // manual entry - cashierTxn.getTxnDate(), JournalEntryType.CREDIT, cashierTxn.getTxnAmount(), - cashierTxn.getTxnNote(), // Description - null, null, null, // entity Type, entityId, reference number - null, null); // Loan and Savings Txn - - this.glJournalEntryRepository.saveAndFlush(debitJournalEntry); - this.glJournalEntryRepository.saveAndFlush(creditJournalEntry); + + final Long time = System.currentTimeMillis(); + final String uniqueVal = String.valueOf(time) + currentUser.getId() + cashierOffice.getId(); + final String transactionId = Long.toHexString(Long.parseLong(uniqueVal)); + + final JournalEntry debitJournalEntry = JournalEntry.createNew(cashierOffice, null, // payment + // detail + debitAccount, "USD", // FIXME: Take currency code from the + // transaction + transactionId, false, // manual entry + cashierTxn.getTxnDate(), JournalEntryType.DEBIT, cashierTxn.getTxnAmount(), cashierTxn.getTxnNote(), // Description + null, null, null, // entity Type, entityId, reference number + null, null); // Loan and Savings Txn + final JournalEntry creditJournalEntry = JournalEntry.createNew(cashierOffice, null, // payment + // detail + creditAccount, "USD", // FIXME: Take currency code from the + // transaction + transactionId, false, // manual entry + cashierTxn.getTxnDate(), JournalEntryType.CREDIT, cashierTxn.getTxnAmount(), cashierTxn.getTxnNote(), // Description + null, null, null, // entity Type, entityId, reference number + null, null); // Loan and Savings Txn + + this.glJournalEntryRepository.saveAndFlush(debitJournalEntry); + this.glJournalEntryRepository.saveAndFlush(creditJournalEntry); return new CommandProcessingResultBuilder() // .withCommandId(command.commandId()) // @@ -400,7 +437,6 @@ public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformSer handleTellerDataIntegrityIssues(command, dve); return CommandProcessingResult.empty(); } - } - + } } diff --git a/mifosng-provider/src/main/resources/sql/migrations/core_db/V249__bug_fix_teller_cash_management.sql b/mifosng-provider/src/main/resources/sql/migrations/core_db/V249__bug_fix_teller_cash_management.sql new file mode 100644 index 000000000..2e62b8af3 --- /dev/null +++ b/mifosng-provider/src/main/resources/sql/migrations/core_db/V249__bug_fix_teller_cash_management.sql @@ -0,0 +1,13 @@ +UPDATE m_permission SET +action_name="UPDATE" +WHERE +code = "UPDATE_TELLER"; + +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`) VALUES ('cash_mgmt', 'DELETE_TELLER', 'TELLER', 'DELETE'); + + +ALTER TABLE `m_cashier_transactions` + DROP FOREIGN KEY `FK_m_teller_transactions_m_cashiers`; + +ALTER TABLE `m_cashier_transactions` + ADD CONSTRAINT `FK_m_teller_transactions_m_cashiers` FOREIGN KEY (`cashier_id`) REFERENCES `m_cashiers` (`id`) ON UPDATE CASCADE ON DELETE CASCADE; \ No newline at end of file