From 21d5a4cc1a4d9c63fb181be07f3348323fb94391 Mon Sep 17 00:00:00 2001 From: Keith Woodlock Date: Mon, 9 Jul 2012 08:27:02 +0100 Subject: [PATCH] add basic fund concept to platform. --- .../org/mifosng/platform/Specifications.java | 10 ++ .../platform/api/FundsApiResource.java | 111 ++++++++++++++++++ .../platform/api/commands/FundCommand.java | 96 +++++++++++++++ .../mifosng/platform/api/data/FundData.java | 47 ++++++++ .../exceptions/FundNotFoundException.java | 11 ++ .../exceptions/OfficeNotFoundException.java | 2 +- .../mifosng/platform/fund/domain/Fund.java | 63 ++++++++++ .../platform/fund/domain/FundRepository.java | 8 ++ .../fund/service/FundCommandValidator.java | 52 ++++++++ .../fund/service/FundReadPlatformService.java | 12 ++ .../service/FundReadPlatformServiceImpl.java | 82 +++++++++++++ .../service/FundWritePlatformService.java | 13 ++ ...WritePlatformServiceJpaRepositoryImpl.java | 95 +++++++++++++++ .../main/resources/META-INF/persistence.xml | 6 +- 14 files changed, 603 insertions(+), 5 deletions(-) create mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/api/FundsApiResource.java create mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/api/commands/FundCommand.java create mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/api/data/FundData.java create mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/exceptions/FundNotFoundException.java create mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/fund/domain/Fund.java create mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/fund/domain/FundRepository.java create mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/fund/service/FundCommandValidator.java create mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/fund/service/FundReadPlatformService.java create mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/fund/service/FundReadPlatformServiceImpl.java create mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/fund/service/FundWritePlatformService.java create mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/fund/service/FundWritePlatformServiceJpaRepositoryImpl.java diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/Specifications.java b/mifosng-provider/src/main/java/org/mifosng/platform/Specifications.java index bbe288c3b..85dab2199 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/Specifications.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/Specifications.java @@ -7,6 +7,7 @@ import javax.persistence.criteria.Root; import org.mifosng.platform.client.domain.Client; import org.mifosng.platform.client.domain.Note; +import org.mifosng.platform.fund.domain.Fund; import org.mifosng.platform.loan.domain.Loan; import org.mifosng.platform.loan.domain.LoanProduct; import org.mifosng.platform.loan.domain.LoanTransaction; @@ -94,6 +95,15 @@ public final class Specifications { }; } + public static Specification fundsThatMatch(final Organisation organisation, final Long id) { + return new Specification() { + @Override + public Predicate toPredicate(final Root root, final CriteriaQuery query, final CriteriaBuilder cb) { + return cb.and(cb.equal(root.get("organisation"), organisation), cb.equal(root.get("id"), id)); + } + }; + } + public static Specification clientsThatMatch(final Organisation organisation, final Long id) { return new Specification() { diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/FundsApiResource.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/FundsApiResource.java new file mode 100644 index 000000000..d2ade11c0 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/FundsApiResource.java @@ -0,0 +1,111 @@ +package org.mifosng.platform.api; + +import java.util.Collection; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.mifosng.platform.api.commands.FundCommand; +import org.mifosng.platform.api.data.EntityIdentifier; +import org.mifosng.platform.api.data.FundData; +import org.mifosng.platform.api.infrastructure.ApiDataConversionService; +import org.mifosng.platform.api.infrastructure.ApiJSONFormattingService; +import org.mifosng.platform.fund.service.FundReadPlatformService; +import org.mifosng.platform.fund.service.FundWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +@Path("/funds") +@Component +@Scope("singleton") +public class FundsApiResource { + + private String defaultFieldList = "openingDate"; + private String allowedFieldList = "allowedParents"; + private String filterName = "myFilter"; + + @Autowired + private FundReadPlatformService readPlatformService; + + @Autowired + private FundWritePlatformService writePlatformService; + + @Autowired + private ApiDataConversionService apiDataConversionService; + + @Autowired + private ApiJSONFormattingService jsonFormattingService; + + @GET + @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveFunds(@Context UriInfo uriInfo) { + + Collection funds = this.readPlatformService.retrieveAllFunds(); + String selectedFields = ""; + return this.jsonFormattingService.convertRequest(funds, filterName, + allowedFieldList, selectedFields, uriInfo.getQueryParameters()); + } + + @POST + @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces({ MediaType.APPLICATION_JSON }) + public Response createFund(final FundCommand command) { + +// LocalDate openingLocalDate = apiDataConversionService.convertFrom( +// command.getOpeningDate(), "openingDate", +// command.getDateFormat()); +// command.setOpeningLocalDate(openingLocalDate); + + Long fundId = this.writePlatformService.createFund(command); + + return Response.ok().entity(new EntityIdentifier(fundId)).build(); + } + + @GET + @Path("{fundId}") + @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retreiveOffice(@PathParam("fundId") final Long fundId, + @QueryParam("template") String template, @Context UriInfo uriInfo) { + + FundData fund = this.readPlatformService.retrieveFund(fundId); +// if (template != null && template.equalsIgnoreCase("true")) { +// office.setAllowedParents(this.readPlatformService +// .retrieveAllowedParents(officeId)); +// } + + String selectedFields = ""; + return this.jsonFormattingService.convertRequest(fund, filterName, + allowedFieldList, selectedFields, uriInfo.getQueryParameters()); + } + + @PUT + @Path("{fundId}") + @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces({ MediaType.APPLICATION_JSON }) + public Response updateOffice(@PathParam("fundId") final Long fundId, + final FundCommand command) { + +// LocalDate openingLocalDate = apiDataConversionService.convertFrom( +// command.getOpeningDate(), "openingDate", +// command.getDateFormat()); +// command.setOpeningLocalDate(openingLocalDate); + command.setId(fundId); + + Long entityId = this.writePlatformService.updateFund(command); + + return Response.ok().entity(new EntityIdentifier(entityId)).build(); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/FundCommand.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/FundCommand.java new file mode 100644 index 000000000..2f1925849 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/FundCommand.java @@ -0,0 +1,96 @@ +package org.mifosng.platform.api.commands; + +import javax.xml.bind.annotation.XmlRootElement; + +import org.joda.time.LocalDate; + +/** + * Command used for create and update fund operations. + */ +@XmlRootElement +public class FundCommand { + + private Long id; + private String name; + private String externalId; + + private String dateFormat; + private String activatedOnDate; + private LocalDate activatedOnLocalDate; + + private String deactivatedOnDate; + private LocalDate deactivatedOnLocalDate; + + protected FundCommand() { + // + } + + public FundCommand(final String fundName, final String externalId) { + this.name = fundName; + this.externalId = externalId; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getExternalId() { + return externalId; + } + + public void setExternalId(String externalId) { + this.externalId = externalId; + } + + public String getDateFormat() { + return dateFormat; + } + + public void setDateFormat(String dateFormat) { + this.dateFormat = dateFormat; + } + + public String getActivatedOnDate() { + return activatedOnDate; + } + + public void setActivatedOnDate(String activatedOnDate) { + this.activatedOnDate = activatedOnDate; + } + + public LocalDate getActivatedOnLocalDate() { + return activatedOnLocalDate; + } + + public void setActivatedOnLocalDate(LocalDate activatedOnLocalDate) { + this.activatedOnLocalDate = activatedOnLocalDate; + } + + public String getDeactivatedOnDate() { + return deactivatedOnDate; + } + + public void setDeactivatedOnDate(String deactivatedOnDate) { + this.deactivatedOnDate = deactivatedOnDate; + } + + public LocalDate getDeactivatedOnLocalDate() { + return deactivatedOnLocalDate; + } + + public void setDeactivatedOnLocalDate(LocalDate deactivatedOnLocalDate) { + this.deactivatedOnLocalDate = deactivatedOnLocalDate; + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/FundData.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/FundData.java new file mode 100644 index 000000000..2370a3085 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/FundData.java @@ -0,0 +1,47 @@ +package org.mifosng.platform.api.data; + +import java.io.Serializable; + +import org.codehaus.jackson.map.annotate.JsonFilter; + +@JsonFilter("myFilter") +public class FundData implements Serializable { + + private Long id; + private String name; + private String externalId; + + public FundData() { + // + } + + public FundData(final Long id, final String name, final String externalId) { + this.id = id; + this.name = name; + this.externalId = externalId; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getExternalId() { + return externalId; + } + + public void setExternalId(String externalId) { + this.externalId = externalId; + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/FundNotFoundException.java b/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/FundNotFoundException.java new file mode 100644 index 000000000..dd8cfa5fd --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/FundNotFoundException.java @@ -0,0 +1,11 @@ +package org.mifosng.platform.exceptions; + +/** + * A {@link RuntimeException} thrown when fund resources are not found. + */ +public class FundNotFoundException extends AbstractPlatformResourceNotFoundException { + + public FundNotFoundException(final Long id) { + super("error.msg.fund.id.invalid", "Fund with identifier " + id + " does not exist", id); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/OfficeNotFoundException.java b/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/OfficeNotFoundException.java index cb7dad7f5..d627c2e4a 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/OfficeNotFoundException.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/OfficeNotFoundException.java @@ -5,7 +5,7 @@ package org.mifosng.platform.exceptions; */ public class OfficeNotFoundException extends AbstractPlatformResourceNotFoundException { - public OfficeNotFoundException(Long id) { + public OfficeNotFoundException(final Long id) { super("error.msg.office.id.invalid", "Office with identifier " + id + " does not exist", id); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/fund/domain/Fund.java b/mifosng-provider/src/main/java/org/mifosng/platform/fund/domain/Fund.java new file mode 100644 index 000000000..17097a18b --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/fund/domain/Fund.java @@ -0,0 +1,63 @@ +package org.mifosng.platform.fund.domain; + +import java.math.BigDecimal; +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + +import org.mifosng.platform.api.commands.FundCommand; +import org.mifosng.platform.infrastructure.AbstractAuditableCustom; +import org.mifosng.platform.organisation.domain.Organisation; +import org.mifosng.platform.user.domain.AppUser; + +@Entity +@Table(name = "org_fund") +public class Fund extends AbstractAuditableCustom { + + @ManyToOne + @JoinColumn(name = "org_id", nullable = false) + private final Organisation organisation; + + @Column(name = "name") + private String name; + + @Column(name = "external_id", length=100) + private String externalId; + + @Temporal(TemporalType.DATE) + @Column(name = "activatedon_date") + private Date activatedOnDate; + + @Temporal(TemporalType.DATE) + @Column(name = "deactivatedon_date") + private Date deactivatedOnDate; + + @Column(name = "initial_balance", scale = 6, precision = 19) + private BigDecimal initialBalance; + + public static Fund createNew(final Organisation organisation, final String fundName) { + return new Fund(organisation, fundName); + } + + protected Fund() { + this.organisation = null; + } + + private Fund(final Organisation organisation, final String fundName) { + this.organisation = organisation; + this.name = fundName; + this.initialBalance = BigDecimal.ZERO; + } + + public void update(FundCommand command) { + if (command.getName() != null) { + this.name = command.getName(); + } + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/fund/domain/FundRepository.java b/mifosng-provider/src/main/java/org/mifosng/platform/fund/domain/FundRepository.java new file mode 100644 index 000000000..d63259851 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/fund/domain/FundRepository.java @@ -0,0 +1,8 @@ +package org.mifosng.platform.fund.domain; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +public interface FundRepository extends JpaRepository, JpaSpecificationExecutor { + // no added behaviour +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/fund/service/FundCommandValidator.java b/mifosng-provider/src/main/java/org/mifosng/platform/fund/service/FundCommandValidator.java new file mode 100644 index 000000000..7350f81b5 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/fund/service/FundCommandValidator.java @@ -0,0 +1,52 @@ +package org.mifosng.platform.fund.service; + +import java.util.ArrayList; +import java.util.List; + +import org.mifosng.platform.DataValidatorBuilder; +import org.mifosng.platform.api.commands.FundCommand; +import org.mifosng.platform.api.data.ApiParameterError; +import org.mifosng.platform.exceptions.PlatformApiDataValidationException; + +public class FundCommandValidator { + + private final FundCommand command; + + public FundCommandValidator(FundCommand command) { + this.command = command; + } + + public void validateForCreate() { + + List dataValidationErrors = new ArrayList(); + + DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("fund"); + +// baseDataValidator.reset().parameter("name").value(command.getName()).notBlank(); +// baseDataValidator.reset().parameter("openingDate").value(command.getOpeningDate()).notBlank(); +// baseDataValidator.reset().parameter("externalId").value(command.getExternalId()).notExceedingLengthOf(100); +// baseDataValidator.reset().parameter("parentId").value(command.getParentId()).notNull().greaterThanZero(); +// + if (!dataValidationErrors.isEmpty()) { + throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors); + } + } + + public void validateForUpdate() { + List dataValidationErrors = new ArrayList(); + + DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("fund"); +// +// baseDataValidator.reset().parameter("id").value(command.getId()).notNull(); +// baseDataValidator.reset().parameter("name").value(command.getName()).ignoreIfNull().notBlank(); +// baseDataValidator.reset().parameter("openingDate").value(command.getOpeningDate()).ignoreIfNull().notBlank(); +// baseDataValidator.reset().parameter("externalId").value(command.getExternalId()).ignoreIfNull().notExceedingLengthOf(100); +// baseDataValidator.reset().parameter("parentId").value(command.getParentId()).ignoreIfNull().notNull().greaterThanZero(); +// +// baseDataValidator.reset().anyOfNotNull(command.getName(), command.getOpeningDate(), command.getExternalId(), command.getParentId()); +// + if (!dataValidationErrors.isEmpty()) { + throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors); + } + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/fund/service/FundReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosng/platform/fund/service/FundReadPlatformService.java new file mode 100644 index 000000000..2ecf47789 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/fund/service/FundReadPlatformService.java @@ -0,0 +1,12 @@ +package org.mifosng.platform.fund.service; + +import java.util.Collection; + +import org.mifosng.platform.api.data.FundData; + +public interface FundReadPlatformService { + + Collection retrieveAllFunds(); + + FundData retrieveFund(Long fundId); +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/fund/service/FundReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/fund/service/FundReadPlatformServiceImpl.java new file mode 100644 index 000000000..513a19939 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/fund/service/FundReadPlatformServiceImpl.java @@ -0,0 +1,82 @@ +package org.mifosng.platform.fund.service; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Collection; + +import javax.sql.DataSource; + +import org.mifosng.platform.api.data.FundData; +import org.mifosng.platform.exceptions.FundNotFoundException; +import org.mifosng.platform.security.PlatformSecurityContext; +import org.mifosng.platform.user.domain.AppUser; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; +import org.springframework.stereotype.Service; + +@Service +public class FundReadPlatformServiceImpl implements FundReadPlatformService { + + private final SimpleJdbcTemplate jdbcTemplate; + private final PlatformSecurityContext context; + + @Autowired + public FundReadPlatformServiceImpl(final PlatformSecurityContext context, + final DataSource dataSource) { + this.context = context; + this.jdbcTemplate = new SimpleJdbcTemplate(dataSource); + } + + private static final class FundMapper implements RowMapper { + + public String officeSchema() { + return " f.id as id, f.name as name, f.external_id as externalId from org_fund f "; + } + + @Override + public FundData mapRow(final ResultSet rs, final int rowNum) + throws SQLException { + + Long id = rs.getLong("id"); + String name = rs.getString("name"); + String externalId = rs.getString("externalId"); +// LocalDate openingDate = JdbcSupport.getLocalDate(rs, "openingDate"); + + return new FundData(id, name, externalId); + } + } + + @Override + public Collection retrieveAllFunds() { + + AppUser currentUser = context.authenticatedUser(); + + FundMapper rm = new FundMapper(); + String sql = "select " + + rm.officeSchema() + + " where f.org_id = ? order by f.name"; + + return this.jdbcTemplate.query(sql, rm, new Object[] {currentUser.getOrganisation().getId()}); + } + + @Override + public FundData retrieveFund(final Long fundId) { + + try { + AppUser currentUser = context.authenticatedUser(); + + FundMapper rm = new FundMapper(); + String sql = "select " + rm.officeSchema() + + " where f.org_id = ? and f.id = ?"; + + FundData selectedFund = this.jdbcTemplate.queryForObject(sql, + rm, new Object[] { currentUser.getOrganisation().getId(), fundId}); + + return selectedFund; + } catch (EmptyResultDataAccessException e) { + throw new FundNotFoundException(fundId); + } + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/fund/service/FundWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosng/platform/fund/service/FundWritePlatformService.java new file mode 100644 index 000000000..faa91a1c9 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/fund/service/FundWritePlatformService.java @@ -0,0 +1,13 @@ +package org.mifosng.platform.fund.service; + +import org.mifosng.platform.api.commands.FundCommand; +import org.springframework.security.access.prepost.PreAuthorize; + +public interface FundWritePlatformService { + + @PreAuthorize(value = "hasRole('ORGANISATION_ADMINISTRATION_SUPER_USER_ROLE')") + Long createFund(final FundCommand command); + + @PreAuthorize(value = "hasRole('ORGANISATION_ADMINISTRATION_SUPER_USER_ROLE')") + Long updateFund(final FundCommand command); +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/fund/service/FundWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/fund/service/FundWritePlatformServiceJpaRepositoryImpl.java new file mode 100644 index 000000000..4ec8f4311 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/fund/service/FundWritePlatformServiceJpaRepositoryImpl.java @@ -0,0 +1,95 @@ +package org.mifosng.platform.fund.service; + +import static org.mifosng.platform.Specifications.fundsThatMatch; + +import org.mifosng.platform.api.commands.FundCommand; +import org.mifosng.platform.exceptions.FundNotFoundException; +import org.mifosng.platform.exceptions.PlatformDataIntegrityException; +import org.mifosng.platform.fund.domain.Fund; +import org.mifosng.platform.fund.domain.FundRepository; +import org.mifosng.platform.security.PlatformSecurityContext; +import org.mifosng.platform.user.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 FundWritePlatformServiceJpaRepositoryImpl implements FundWritePlatformService { + + private final static Logger logger = LoggerFactory.getLogger(FundWritePlatformServiceJpaRepositoryImpl.class); + + private final PlatformSecurityContext context; + private final FundRepository fundRepository; + + @Autowired + public FundWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final FundRepository fundRepository) { + this.context = context; + this.fundRepository = fundRepository; + } + + @Transactional + @Override + public Long createFund(final FundCommand command) { + + try { + AppUser currentUser = context.authenticatedUser(); + + FundCommandValidator validator = new FundCommandValidator(command); + validator.validateForCreate(); + + Fund fund = Fund.createNew(currentUser.getOrganisation(), command.getName()); + + this.fundRepository.saveAndFlush(fund); + + return fund.getId(); + } catch (DataIntegrityViolationException dve) { + handleFundDataIntegrityIssues(command, dve); + return Long.valueOf(-1); + } + } + + @Transactional + @Override + public Long updateFund(final FundCommand command) { + + try { + AppUser currentUser = context.authenticatedUser(); + + FundCommandValidator validator = new FundCommandValidator(command); + validator.validateForCreate(); + + final Long fundId = command.getId(); + Fund fund = this.fundRepository.findOne(fundsThatMatch(currentUser.getOrganisation(), fundId)); + if (fund == null) { + throw new FundNotFoundException(fundId); + } + fund.update(command); + + this.fundRepository.save(fund); + + return fund.getId(); + } catch (DataIntegrityViolationException dve) { + handleFundDataIntegrityIssues(command, dve); + return Long.valueOf(-1); + } + } + + /* + * Guaranteed to throw an exception no matter what the data integrity issue is. + */ + private void handleFundDataIntegrityIssues(final FundCommand command, DataIntegrityViolationException dve) { + + Throwable realCause = dve.getMostSpecificCause(); + if (realCause.getMessage().contains("externalid_org")) { + throw new PlatformDataIntegrityException("error.msg.office.duplicate.externalId", "Office with externalId {0} already exists", "externalId", command.getExternalId()); + } else if (realCause.getMessage().contains("name_org")) { + throw new PlatformDataIntegrityException("error.msg.office.duplicate.name", "Office with name {0} already exists", "name", command.getName()); + } + + logger.error(dve.getMessage(), dve); + throw new PlatformDataIntegrityException("error.msg.office.unknown.data.integrity.issue", "Unknown data integrity issue with resource."); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/resources/META-INF/persistence.xml b/mifosng-provider/src/main/resources/META-INF/persistence.xml index f691a8e28..b24dfef18 100644 --- a/mifosng-provider/src/main/resources/META-INF/persistence.xml +++ b/mifosng-provider/src/main/resources/META-INF/persistence.xml @@ -3,10 +3,8 @@ org.hibernate.ejb.HibernatePersistence - - + +