From 8bc0b7461f56c193206771c7c22c5f6912fa47c2 Mon Sep 17 00:00:00 2001 From: Keith Woodlock Date: Wed, 16 May 2012 22:02:04 +0100 Subject: [PATCH] add state transitions around loan to api. --- .../command/LoanStateTransitionCommand.java | 18 +++ .../org/mifosng/ui/CommonRestOperations.java | 11 -- .../mifosng/ui/CommonRestOperationsImpl.java | 92 +------------- .../ui/loan/LoanTransactionController.java | 60 --------- .../views/client/viewClientAccount.jsp | 52 ++++---- .../webapp/WEB-INF/views/view-templates.jsp | 45 +------ .../platform/WritePlatformService.java | 13 -- ...WritePlatformServiceJpaRepositoryImpl.java | 117 ------------------ .../platform/api/LoansApiResource.java | 53 ++++++++ .../service/LoanWritePlatformService.java | 14 +++ ...WritePlatformServiceJpaRepositoryImpl.java | 111 +++++++++++++++++ .../mifosng/platform/rest/LoanResource.java | 93 -------------- 12 files changed, 229 insertions(+), 450 deletions(-) diff --git a/mifosng-data/src/main/java/org/mifosng/data/command/LoanStateTransitionCommand.java b/mifosng-data/src/main/java/org/mifosng/data/command/LoanStateTransitionCommand.java index 424b82624..3aa917617 100644 --- a/mifosng-data/src/main/java/org/mifosng/data/command/LoanStateTransitionCommand.java +++ b/mifosng-data/src/main/java/org/mifosng/data/command/LoanStateTransitionCommand.java @@ -11,6 +11,8 @@ import org.joda.time.LocalDate; public class LoanStateTransitionCommand { private Long loanId; + private String dateFormat; + private String eventDateFormatted; private LocalDate eventDate; private String comment; @@ -48,4 +50,20 @@ public class LoanStateTransitionCommand { public void setEventDate(LocalDate eventDate) { this.eventDate = eventDate; } + + public String getDateFormat() { + return dateFormat; + } + + public void setDateFormat(String dateFormat) { + this.dateFormat = dateFormat; + } + + public String getEventDateFormatted() { + return eventDateFormatted; + } + + public void setEventDateFormatted(String eventDateFormatted) { + this.eventDateFormatted = eventDateFormatted; + } } \ No newline at end of file diff --git a/mifosng-individual-lending-app/src/main/java/org/mifosng/ui/CommonRestOperations.java b/mifosng-individual-lending-app/src/main/java/org/mifosng/ui/CommonRestOperations.java index 510294eb0..c256f1f44 100644 --- a/mifosng-individual-lending-app/src/main/java/org/mifosng/ui/CommonRestOperations.java +++ b/mifosng-individual-lending-app/src/main/java/org/mifosng/ui/CommonRestOperations.java @@ -5,7 +5,6 @@ import org.mifosng.data.LoanRepaymentData; import org.mifosng.data.command.AdjustLoanTransactionCommand; import org.mifosng.data.command.LoanStateTransitionCommand; import org.mifosng.data.command.LoanTransactionCommand; -import org.mifosng.data.command.UndoLoanApprovalCommand; import org.mifosng.data.command.UndoLoanDisbursalCommand; import org.springframework.security.oauth.consumer.ProtectedResourceDetails; @@ -15,16 +14,6 @@ public interface CommonRestOperations { void updateProtectedResource(ProtectedResourceDetails loadProtectedResourceDetailsById); - EntityIdentifier deleteLoan(Long loanId); - - EntityIdentifier approveLoan(LoanStateTransitionCommand command); - - EntityIdentifier undoLoanApproval(UndoLoanApprovalCommand command); - - EntityIdentifier rejectLoan(LoanStateTransitionCommand command); - - EntityIdentifier withdrawLoan(LoanStateTransitionCommand command); - EntityIdentifier disburseLoan(LoanStateTransitionCommand command); EntityIdentifier undloLoanDisbursal(UndoLoanDisbursalCommand command); diff --git a/mifosng-individual-lending-app/src/main/java/org/mifosng/ui/CommonRestOperationsImpl.java b/mifosng-individual-lending-app/src/main/java/org/mifosng/ui/CommonRestOperationsImpl.java index 81a2e0cc1..6a730b3d6 100644 --- a/mifosng-individual-lending-app/src/main/java/org/mifosng/ui/CommonRestOperationsImpl.java +++ b/mifosng-individual-lending-app/src/main/java/org/mifosng/ui/CommonRestOperationsImpl.java @@ -99,97 +99,7 @@ public class CommonRestOperationsImpl implements CommonRestOperations { } return errorList; } - - @Override - public EntityIdentifier deleteLoan(Long loanId) { - try { - URI restUri = URI.create(getBaseServerUrl().concat( - "api/protected/loan/").concat(loanId.toString())); - - ResponseEntity s = this.oauthRestServiceTemplate - .exchange(restUri, HttpMethod.DELETE, null, - EntityIdentifier.class); - - return s.getBody(); - } catch (HttpStatusCodeException e) { - ErrorResponseList errorList = parseErrors(e); - throw new ClientValidationException(errorList.getErrors()); - } - } - - @Override - public EntityIdentifier approveLoan(final LoanStateTransitionCommand command) { - try { - URI restUri = URI.create(getBaseServerUrl().concat( - "api/protected/loan/approve")); - - ResponseEntity s = this.oauthRestServiceTemplate - .postForEntity(restUri, - loanStateTransitionApplicationRequest(command), - EntityIdentifier.class); - - return s.getBody(); - } catch (HttpStatusCodeException e) { - ErrorResponseList errorList = parseErrors(e); - throw new ClientValidationException(errorList.getErrors()); - } - } - - @Override - public EntityIdentifier undoLoanApproval( - final UndoLoanApprovalCommand command) { - try { - URI restUri = URI.create(getBaseServerUrl().concat( - "api/protected/loan/undoapproval")); - - ResponseEntity s = this.oauthRestServiceTemplate - .postForEntity(restUri, undoLoanApprovalRequest(command), - EntityIdentifier.class); - - return s.getBody(); - } catch (HttpStatusCodeException e) { - ErrorResponseList errorList = parseErrors(e); - throw new ClientValidationException(errorList.getErrors()); - } - } - - @Override - public EntityIdentifier rejectLoan(final LoanStateTransitionCommand command) { - try { - URI restUri = URI.create(getBaseServerUrl().concat( - "api/protected/loan/reject")); - - ResponseEntity s = this.oauthRestServiceTemplate - .postForEntity(restUri, - loanStateTransitionApplicationRequest(command), - EntityIdentifier.class); - - return s.getBody(); - } catch (HttpStatusCodeException e) { - ErrorResponseList errorList = parseErrors(e); - throw new ClientValidationException(errorList.getErrors()); - } - } - - @Override - public EntityIdentifier withdrawLoan( - final LoanStateTransitionCommand command) { - try { - URI restUri = URI.create(getBaseServerUrl().concat( - "api/protected/loan/withdraw")); - - ResponseEntity s = this.oauthRestServiceTemplate - .postForEntity(restUri, - loanStateTransitionApplicationRequest(command), - EntityIdentifier.class); - - return s.getBody(); - } catch (HttpStatusCodeException e) { - ErrorResponseList errorList = parseErrors(e); - throw new ClientValidationException(errorList.getErrors()); - } - } - + @Override public EntityIdentifier disburseLoan( final LoanStateTransitionCommand command) { diff --git a/mifosng-individual-lending-app/src/main/java/org/mifosng/ui/loan/LoanTransactionController.java b/mifosng-individual-lending-app/src/main/java/org/mifosng/ui/loan/LoanTransactionController.java index 11ef3ed71..138dafe46 100644 --- a/mifosng-individual-lending-app/src/main/java/org/mifosng/ui/loan/LoanTransactionController.java +++ b/mifosng-individual-lending-app/src/main/java/org/mifosng/ui/loan/LoanTransactionController.java @@ -19,7 +19,6 @@ import org.mifosng.data.LoanRepaymentData; import org.mifosng.data.command.AdjustLoanTransactionCommand; import org.mifosng.data.command.LoanStateTransitionCommand; import org.mifosng.data.command.LoanTransactionCommand; -import org.mifosng.data.command.UndoLoanApprovalCommand; import org.mifosng.data.command.UndoLoanDisbursalCommand; import org.mifosng.ui.CommonRestOperations; import org.mifosng.ui.loanproduct.ClientValidationException; @@ -97,65 +96,6 @@ public class LoanTransactionController { } } - @RequestMapping(value = "/portfolio/loan/{loanId}/delete", method = RequestMethod.POST) - public @ResponseBody EntityIdentifier deleteLoan(@PathVariable("loanId") final Long loanId) { - - return this.commonRestOperations.deleteLoan(loanId); - } - - @RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/portfolio/loan/{loanId}/approve", method = RequestMethod.POST) - @ResponseStatus(HttpStatus.OK) - public @ResponseBody EntityIdentifier approveLoan( - @PathVariable("loanId") final Long loanId, - @RequestParam(value="eventDate", required=false) String eventDate, - @RequestParam(value="comment", required=false) String comment) { - - LocalDate approvalDate = parseStringToLocalDate(eventDate, "eventDate"); - - LoanStateTransitionCommand command = new LoanStateTransitionCommand(loanId, approvalDate, comment); - - return this.commonRestOperations.approveLoan(command); - } - - @RequestMapping(value = "/portfolio/loan/{loanId}/undoapproval", method = RequestMethod.POST) - public String undoLoanApproval(@PathVariable("loanId") final Long loanId) { - - UndoLoanApprovalCommand command = new UndoLoanApprovalCommand(loanId); - - EntityIdentifier clientAccountId = this.commonRestOperations - .undoLoanApproval(command); - - return "redirect:/portfolio/client/" + clientAccountId.getEntityId(); - } - - @RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/portfolio/loan/{loanId}/reject", method = RequestMethod.POST) - @ResponseStatus(HttpStatus.OK) - public @ResponseBody EntityIdentifier rejectLoan( - @PathVariable("loanId") final Long loanId, - @RequestParam(value="eventDate", required=false) String eventDate, - @RequestParam(value="comment", required=false) String comment) { - - LocalDate rejectionDate = parseStringToLocalDate(eventDate, "eventDate"); - - LoanStateTransitionCommand command = new LoanStateTransitionCommand(loanId, rejectionDate, comment); - - return this.commonRestOperations.rejectLoan(command); - } - - @RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/portfolio/loan/{loanId}/withdraw", method = RequestMethod.POST) - @ResponseStatus(HttpStatus.OK) - public @ResponseBody EntityIdentifier loanWithdrawnByClient( - @PathVariable("loanId") final Long loanId, - @RequestParam(value="eventDate", required=false) String eventDate, - @RequestParam(value="comment", required=false) String comment) { - - LocalDate withdrawnOnDate = parseStringToLocalDate(eventDate, "eventDate"); - - LoanStateTransitionCommand command = new LoanStateTransitionCommand(loanId, withdrawnOnDate, comment); - - return this.commonRestOperations.withdrawLoan(command); - } - @RequestMapping(consumes="application/x-www-form-urlencoded", produces="application/json", value = "/portfolio/loan/{loanId}/disburse", method = RequestMethod.POST) @ResponseStatus(HttpStatus.OK) public @ResponseBody EntityIdentifier disburseLoan( diff --git a/mifosng-individual-lending-app/src/main/webapp/WEB-INF/views/client/viewClientAccount.jsp b/mifosng-individual-lending-app/src/main/webapp/WEB-INF/views/client/viewClientAccount.jsp index 3a7a65515..3f2363a4a 100644 --- a/mifosng-individual-lending-app/src/main/webapp/WEB-INF/views/client/viewClientAccount.jsp +++ b/mifosng-individual-lending-app/src/main/webapp/WEB-INF/views/client/viewClientAccount.jsp @@ -251,7 +251,7 @@ $(document).ready(function() { }).dialog('open'); } - function popupDialogWithPostOnlyFormView(url, titleCode, templateSelector, width, height, tabIndex, minOffset, defaultOffset, maxOffset) { + function popupDialogWithPostOnlyFormView(postUrl, titleCode, templateSelector, width, height, tabIndex, minOffset, defaultOffset, maxOffset) { var dialogDiv = $("
"); var data = new Object(); @@ -267,13 +267,17 @@ $(document).ready(function() { $('.multiSelectedItems option').each(function(i) { $(this).attr("selected", "selected"); }); - - var form_data = $('#entityform').serialize(); - + + var newFormData = JSON.stringify($('#entityform').serializeObject()); + console.log(newFormData); + var jqxhr = $.ajax({ - url: url, + url: postUrl, type: 'POST', - data: form_data, + contentType: 'application/json', + dataType: 'json', + cache: false, + data: newFormData, success: function(data, textStatus, jqXHR) { dialogDiv.dialog("close"); $newtabs.tabs('load', tabIndex); @@ -505,29 +509,27 @@ $(document).ready(function() { offsetToDisbursalDate = data.maxDisbursedOnOffsetFromToday; $('.rejectloan').button().click(function(e) { - var linkId = this.id; var loanId = linkId.replace("rejectbtn", ""); - var url = '${rootContext}portfolio/loan/' + loanId + '/reject'; - var templateSelector = "#rejectLoanFormTemplate"; + var postUrl = 'http://localhost:8080/mifosng-provider/api/v1/loans/' + loanId + '?command=reject'; + var templateSelector = "#stateTransitionLoanFormTemplate"; var width = 500; var height = 350; var defaultOffset = offsetToSubmittedDate; - popupDialogWithPostOnlyFormView(url, 'dialog.title.reject.loan', templateSelector, width, height, currentTabIndex, offsetToSubmittedDate, defaultOffset, maxOffset); + popupDialogWithPostOnlyFormView(postUrl, 'dialog.title.reject.loan', templateSelector, width, height, currentTabIndex, offsetToSubmittedDate, defaultOffset, maxOffset); e.preventDefault(); }); $('button.rejectloan span').text(jQuery.i18n.prop('dialog.button.reject.loan')); $('.withdrawnbyapplicantloan').button().click(function(e) { - var linkId = this.id; var loanId = linkId.replace("withdrawnbyapplicantloanbtn", ""); - var url = '${rootContext}portfolio/loan/' + loanId + '/withdraw'; - var templateSelector = "#withdrawnByClientLoanFormTemplate"; + var postUrl = 'http://localhost:8080/mifosng-provider/api/v1/loans/' + loanId + '?command=withdrewbyclient'; + var templateSelector = "#stateTransitionLoanFormTemplate"; var width = 500; var height = 350; var defaultOffset = offsetToSubmittedDate; - popupDialogWithPostOnlyFormView(url, 'dialog.title.loan.withdrawn.by.client', templateSelector, width, height, currentTabIndex, offsetToSubmittedDate, defaultOffset, maxOffset) + popupDialogWithPostOnlyFormView(postUrl, 'dialog.title.loan.withdrawn.by.client', templateSelector, width, height, currentTabIndex, offsetToSubmittedDate, defaultOffset, maxOffset) e.preventDefault(); }); $('button.withdrawnbyapplicantloan span').text(jQuery.i18n.prop('dialog.button.withdrawn.by.client.loan')); @@ -536,12 +538,12 @@ $(document).ready(function() { var linkId = this.id; var loanId = linkId.replace("approvebtn", ""); - var url = '${rootContext}portfolio/loan/' + loanId + '/approve'; - var templateSelector = "#approveLoanFormTemplate"; + var postUrl = 'http://localhost:8080/mifosng-provider/api/v1/loans/' + loanId + '?command=approve'; + var templateSelector = "#stateTransitionLoanFormTemplate"; var width = 500; var height = 350; var defaultOffset = offsetToSubmittedDate; - popupDialogWithPostOnlyFormView(url, 'dialog.title.approve.loan', templateSelector, width, height, currentTabIndex, offsetToSubmittedDate, defaultOffset, maxOffset) + popupDialogWithPostOnlyFormView(postUrl, 'dialog.title.approve.loan', templateSelector, width, height, currentTabIndex, offsetToSubmittedDate, defaultOffset, maxOffset) e.preventDefault(); }); $('button.approveloan span').text(jQuery.i18n.prop('dialog.button.approve.loan')); @@ -565,10 +567,10 @@ $(document).ready(function() { var linkId = this.id; var loanId = linkId.replace("undoapprovebtn", ""); - var url = '${rootContext}portfolio/loan/' + loanId + '/undoapproval'; + var postUrl = 'http://localhost:8080/mifosng-provider/api/v1/loans/' + loanId + '/undo?command=undoapproval'; var width = 400; var height = 225; - popupConfirmationDialogAndPost(url, 'dialog.title.undo.loan.approval', width, height, currentTabIndex); + popupConfirmationDialogAndPost(postUrl, 'POST', 'dialog.title.undo.loan.approval', width, height, currentTabIndex); e.preventDefault(); }); $('button.undoapproveloan span').text(jQuery.i18n.prop('dialog.button.undo.loan.approval')); @@ -577,10 +579,10 @@ $(document).ready(function() { var linkId = this.id; var loanId = linkId.replace("undodisbursalbtn", ""); - var url = '${rootContext}portfolio/loan/' + loanId + '/undodisbursal'; + var postUrl = 'http://localhost:8080/mifosng-provider/api/v1/loans/' + loanId + '?command=undodisbursal'; var width = 400; var height = 150; - popupConfirmationDialogAndPost(url, 'dialog.title.undo.loan.disbursal', width, height, currentTabIndex); + popupConfirmationDialogAndPost(postUrl, 'POST', 'dialog.title.undo.loan.disbursal', width, height, currentTabIndex); e.preventDefault(); }); $('button.undodisbursalloan span').text(jQuery.i18n.prop('dialog.button.undo.loan.disbursal')); @@ -589,12 +591,12 @@ $(document).ready(function() { var linkId = this.id; var loanId = linkId.replace("disbursebtn", ""); - var url = '${rootContext}portfolio/loan/' + loanId + '/disburse'; - var templateSelector = "#disburseLoanFormTemplate"; + var postUrl = 'http://localhost:8080/mifosng-provider/api/v1/loans/' + loanId + '?command=disburse'; + var templateSelector = "#stateTransitionLoanFormTemplate"; var width = 500; var height = 350; var defaultOffset = offsetToApprovalDate; - popupDialogWithPostOnlyFormView(url, 'dialog.title.disburse.loan', templateSelector, width, height, currentTabIndex, offsetToSubmittedDate, defaultOffset, maxOffset) + popupDialogWithPostOnlyFormView(postUrl, 'dialog.title.disburse.loan', templateSelector, width, height, currentTabIndex, offsetToSubmittedDate, defaultOffset, maxOffset) e.preventDefault(); }); $('button.disburseloan span').text(jQuery.i18n.prop('dialog.button.disburse.loan')); @@ -603,7 +605,7 @@ $(document).ready(function() { var linkId = this.id; var loanId = linkId.replace("repaymentbtn", ""); - var url = '${rootContext}portfolio/loan/' + loanId + '/repayment'; + var url = 'http://localhost:8080/mifosng-provider/api/v1/loans/' + loanId; var templateSelector = "#transactionLoanFormTemplate"; var width = 500; var height = 350; diff --git a/mifosng-individual-lending-app/src/main/webapp/WEB-INF/views/view-templates.jsp b/mifosng-individual-lending-app/src/main/webapp/WEB-INF/views/view-templates.jsp index 805df0753..a6ab75b2b 100644 --- a/mifosng-individual-lending-app/src/main/webapp/WEB-INF/views/view-templates.jsp +++ b/mifosng-individual-lending-app/src/main/webapp/WEB-INF/views/view-templates.jsp @@ -799,51 +799,16 @@ - - - - - - - diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/WritePlatformService.java b/mifosng-provider/src/main/java/org/mifosng/platform/WritePlatformService.java index 5a36d79bf..003d007b5 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/WritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/WritePlatformService.java @@ -4,7 +4,6 @@ import org.mifosng.data.EntityIdentifier; import org.mifosng.data.command.AdjustLoanTransactionCommand; import org.mifosng.data.command.LoanStateTransitionCommand; import org.mifosng.data.command.LoanTransactionCommand; -import org.mifosng.data.command.UndoLoanApprovalCommand; import org.mifosng.data.command.UndoLoanDisbursalCommand; import org.mifosng.data.command.UpdateUsernamePasswordCommand; import org.springframework.security.access.prepost.PreAuthorize; @@ -13,18 +12,6 @@ public interface WritePlatformService { void updateUsernamePasswordOnFirstTimeLogin(UpdateUsernamePasswordCommand command); - @PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE', 'CAN_APPROVE_LOAN_ROLE', 'CAN_APPROVE_LOAN_IN_THE_PAST_ROLE')") - EntityIdentifier approveLoanApplication(LoanStateTransitionCommand command); - - @PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE', 'CAN_UNDO_LOAN_APPROVAL_ROLE')") - EntityIdentifier undoLoanApproval(UndoLoanApprovalCommand command); - - @PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE', 'CAN_REJECT_LOAN_ROLE', 'CAN_REJECT_LOAN_IN_THE_PAST_ROLE')") - EntityIdentifier rejectLoan(LoanStateTransitionCommand command); - - @PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE', 'CAN_WITHDRAW_LOAN_ROLE', 'CAN_WITHDRAW_LOAN_IN_THE_PAST_ROLE')") - EntityIdentifier withdrawLoan(LoanStateTransitionCommand command); - @PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE', 'CAN_DISBURSE_LOAN_ROLE', 'CAN_DISBURSE_LOAN_IN_THE_PAST_ROLE')") EntityIdentifier disburseLoan(LoanStateTransitionCommand command); diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/WritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/WritePlatformServiceJpaRepositoryImpl.java index e12812ad5..f4a8f4454 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/WritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/WritePlatformServiceJpaRepositoryImpl.java @@ -141,123 +141,6 @@ public class WritePlatformServiceJpaRepositoryImpl implements WritePlatformServi return Arrays.asList(errorResponse); } - @Transactional - @Override - public EntityIdentifier approveLoanApplication(final LoanStateTransitionCommand command) { - - AppUser currentUser = extractAuthenticatedUser(); - - LoanStateTransitionCommandValidator validator = new LoanStateTransitionCommandValidator(command); - validator.validate(); - - Loan loan = this.loanRepository.findOne(loansThatMatch(currentUser.getOrganisation(), command.getLoanId())); - - if (loan == null) { - throw new ApplicationDomainRuleException(loanIdentifierDoesNotExistError(command.getLoanId()), "No loan exists with id: " + command.getLoanId()); - } - - if (this.isBeforeToday(command.getEventDate()) && currentUser.canNotApproveLoanInPast()) { - ErrorResponse errorResponse = new ErrorResponse("error.msg.no.permission.to.approve.loan.in.past", "eventDate"); - throw new ApplicationDomainRuleException(Arrays.asList(errorResponse)); - } - - loan.approve(command.getEventDate(), defaultLoanLifecycleStateMachine()); - this.loanRepository.save(loan); - - if (StringUtils.isNotBlank(command.getComment())) { - Note note = Note.loanNote(currentUser.getOrganisation(), loan, command.getComment()); - this.noteRepository.save(note); - } - - return new EntityIdentifier(loan.getClient().getId()); - } - - @Transactional - @Override - public EntityIdentifier undoLoanApproval(final UndoLoanApprovalCommand command) { - - AppUser currentUser = extractAuthenticatedUser(); - - Loan loan = this.loanRepository.findOne(loansThatMatch( - currentUser.getOrganisation(), command.getLoanId())); - - if (loan == null) { - throw new ApplicationDomainRuleException(loanIdentifierDoesNotExistError(command.getLoanId()), "No loan exists with id: " + command.getLoanId()); - } - - loan.undoApproval(defaultLoanLifecycleStateMachine()); - this.loanRepository.save(loan); - - Note note = Note.loanNote(currentUser.getOrganisation(), loan, "Undo of approval."); - this.noteRepository.save(note); - - return new EntityIdentifier(loan.getClient().getId()); - } - - @Transactional - @Override - public EntityIdentifier rejectLoan(final LoanStateTransitionCommand command) { - - AppUser currentUser = (AppUser) SecurityContextHolder.getContext() - .getAuthentication().getPrincipal(); - - LoanStateTransitionCommandValidator validator = new LoanStateTransitionCommandValidator(command); - validator.validate(); - - Loan loan = this.loanRepository.findOne(loansThatMatch( - currentUser.getOrganisation(), command.getLoanId())); - - if (loan == null) { - throw new ApplicationDomainRuleException(loanIdentifierDoesNotExistError(command.getLoanId()), "No loan exists with id: " + command.getLoanId()); - } - - if (this.isBeforeToday(command.getEventDate()) && currentUser.canNotRejectLoanInPast()) { - ErrorResponse errorResponse = new ErrorResponse("error.msg.no.permission.to.reject.loan.in.past", "eventDate"); - throw new ApplicationDomainRuleException(Arrays.asList(errorResponse)); - } - - loan.reject(command.getEventDate(), defaultLoanLifecycleStateMachine()); - this.loanRepository.save(loan); - - if (StringUtils.isNotBlank(command.getComment())) { - Note note = Note.loanNote(currentUser.getOrganisation(), loan, command.getComment()); - this.noteRepository.save(note); - } - - return new EntityIdentifier(loan.getClient().getId()); - } - - @Transactional - @Override - public EntityIdentifier withdrawLoan(final LoanStateTransitionCommand command) { - AppUser currentUser = extractAuthenticatedUser(); - - LoanStateTransitionCommandValidator validator = new LoanStateTransitionCommandValidator(command); - validator.validate(); - - Loan loan = this.loanRepository.findOne(loansThatMatch( - currentUser.getOrganisation(), command.getLoanId())); - - if (loan == null) { - throw new ApplicationDomainRuleException(loanIdentifierDoesNotExistError(command.getLoanId()), "No loan exists with id: " + command.getLoanId()); - } - - if (this.isBeforeToday(command.getEventDate()) && currentUser.canNotWithdrawByClientLoanInPast()) { - ErrorResponse errorResponse = new ErrorResponse("error.msg.no.permission.to.withdraw.loan.in.past", "eventDate"); - throw new ApplicationDomainRuleException(Arrays.asList(errorResponse)); - } - - loan.withdraw(command.getEventDate(), defaultLoanLifecycleStateMachine()); - this.loanRepository.save(loan); - - if (StringUtils.isNotBlank(command.getComment())) { - Note note = Note.loanNote(currentUser.getOrganisation(), loan, command.getComment()); - this.noteRepository.save(note); - } - - return new EntityIdentifier(loan.getClient().getId()); - } - @Transactional @Override public EntityIdentifier disburseLoan(final LoanStateTransitionCommand command) { diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/LoansApiResource.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/LoansApiResource.java index 9a8739b83..13edb8226 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/LoansApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/LoansApiResource.java @@ -21,7 +21,10 @@ import org.mifosng.data.LoanAccountData; import org.mifosng.data.LoanSchedule; import org.mifosng.data.NewLoanWorkflowStepOneData; import org.mifosng.data.command.CalculateLoanScheduleCommand; +import org.mifosng.data.command.LoanStateTransitionCommand; import org.mifosng.data.command.SubmitLoanApplicationCommand; +import org.mifosng.data.command.UndoLoanApprovalCommand; +import org.mifosng.data.command.UndoLoanDisbursalCommand; import org.mifosng.platform.ReadPlatformService; import org.mifosng.platform.WritePlatformService; import org.mifosng.platform.api.infrastructure.ApiDataConversionService; @@ -151,4 +154,54 @@ public class LoansApiResource { return Response.ok().entity(identifier).build(); } + + @POST + @Path("{loanId}") + @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + @Produces({ MediaType.APPLICATION_JSON}) + public Response rejectLoanApplication(@PathParam("loanId") final Long loanId, @QueryParam("command") final String commandParam, + final LoanStateTransitionCommand command) { + + LocalDate eventDate = this.apiDataConversionService.convertFrom(command.getEventDateFormatted(), "eventDateFormatted", command.getDateFormat()); + + command.setLoanId(loanId); + command.setEventDate(eventDate); + + if (StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase("reject")) { + EntityIdentifier identifier = this.loanWritePlatformService.rejectLoan(command); + return Response.ok().entity(identifier).build(); + } else if (StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase("withdrewbyclient")) { + EntityIdentifier identifier = this.loanWritePlatformService.withdrawLoan(command); + return Response.ok().entity(identifier).build(); + } else if (StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase("approve")) { + EntityIdentifier identifier = this.loanWritePlatformService.approveLoanApplication(command); + return Response.ok().entity(identifier).build(); + } else if (StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase("undoapproval")) { + UndoLoanApprovalCommand undoCommand = new UndoLoanApprovalCommand(loanId); + EntityIdentifier identifier = this.loanWritePlatformService.undoLoanApproval(undoCommand); + return Response.ok().entity(identifier).build(); + } + + return Response.ok().build(); + } + + @POST + @Path("{loanId}/undo") + @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + @Produces({ MediaType.APPLICATION_JSON}) + public Response rejectLoanApplication(@PathParam("loanId") final Long loanId, @QueryParam("command") final String commandParam) { + + + if (StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase("undoapproval")) { + UndoLoanApprovalCommand undoCommand = new UndoLoanApprovalCommand(loanId); + EntityIdentifier identifier = this.loanWritePlatformService.undoLoanApproval(undoCommand); + return Response.ok().entity(identifier).build(); + } else if (StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase("undodisbursal")) { + UndoLoanDisbursalCommand undoCommand = new UndoLoanDisbursalCommand(loanId); + EntityIdentifier identifier = this.writePlatformService.undloLoanDisbursal(undoCommand); + return Response.ok().entity(identifier).build(); + } + + return Response.ok().build(); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanWritePlatformService.java index 79bde4024..273663003 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanWritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanWritePlatformService.java @@ -1,7 +1,9 @@ package org.mifosng.platform.loan.service; import org.mifosng.data.EntityIdentifier; +import org.mifosng.data.command.LoanStateTransitionCommand; import org.mifosng.data.command.SubmitLoanApplicationCommand; +import org.mifosng.data.command.UndoLoanApprovalCommand; import org.springframework.security.access.prepost.PreAuthorize; public interface LoanWritePlatformService { @@ -11,4 +13,16 @@ public interface LoanWritePlatformService { @PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE', 'CAN_DELETE_LOAN_THAT_IS_SUBMITTED_AND_NOT_APPROVED')") EntityIdentifier deleteLoan(Long loanId); + + @PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE', 'CAN_APPROVE_LOAN_ROLE', 'CAN_APPROVE_LOAN_IN_THE_PAST_ROLE')") + EntityIdentifier approveLoanApplication(LoanStateTransitionCommand command); + + @PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE', 'CAN_UNDO_LOAN_APPROVAL_ROLE')") + EntityIdentifier undoLoanApproval(UndoLoanApprovalCommand command); + + @PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE', 'CAN_REJECT_LOAN_ROLE', 'CAN_REJECT_LOAN_IN_THE_PAST_ROLE')") + EntityIdentifier rejectLoan(LoanStateTransitionCommand command); + + @PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE', 'CAN_WITHDRAW_LOAN_ROLE', 'CAN_WITHDRAW_LOAN_IN_THE_PAST_ROLE')") + EntityIdentifier withdrawLoan(LoanStateTransitionCommand command); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanWritePlatformServiceJpaRepositoryImpl.java index bea086818..4d0b6f94b 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/service/LoanWritePlatformServiceJpaRepositoryImpl.java @@ -11,7 +11,10 @@ import org.mifosng.data.EntityIdentifier; import org.mifosng.data.LoanSchedule; import org.mifosng.data.MoneyData; import org.mifosng.data.ScheduledLoanInstallment; +import org.mifosng.data.command.LoanStateTransitionCommand; import org.mifosng.data.command.SubmitLoanApplicationCommand; +import org.mifosng.data.command.UndoLoanApprovalCommand; +import org.mifosng.platform.LoanStateTransitionCommandValidator; import org.mifosng.platform.client.domain.Client; import org.mifosng.platform.client.domain.ClientRepository; import org.mifosng.platform.client.domain.Note; @@ -38,6 +41,7 @@ import org.mifosng.platform.loanschedule.domain.AprCalculator; import org.mifosng.platform.security.PlatformSecurityContext; import org.mifosng.platform.user.domain.AppUser; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -168,4 +172,111 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf return new EntityIdentifier(clientId); } + + @Transactional + @Override + public EntityIdentifier approveLoanApplication(final LoanStateTransitionCommand command) { + + AppUser currentUser = context.authenticatedUser(); + + LoanStateTransitionCommandValidator validator = new LoanStateTransitionCommandValidator(command); + validator.validate(); + + Loan loan = this.loanRepository.findOne(loansThatMatch(currentUser.getOrganisation(), command.getLoanId())); + if (loan == null) { + throw new PlatformResourceNotFoundException("error.msg.loan.id.invalid", "Loan with identifier {0} does not exist", command.getLoanId()); + } + + if (this.isBeforeToday(command.getEventDate()) && currentUser.canNotApproveLoanInPast()) { + throw new NoAuthorizationException("User has no authority to approve loan with a date in the past."); + } + + loan.approve(command.getEventDate(), defaultLoanLifecycleStateMachine()); + this.loanRepository.save(loan); + + if (StringUtils.isNotBlank(command.getComment())) { + Note note = Note.loanNote(currentUser.getOrganisation(), loan, command.getComment()); + this.noteRepository.save(note); + } + + return new EntityIdentifier(loan.getClient().getId()); + } + + @Transactional + @Override + public EntityIdentifier undoLoanApproval(final UndoLoanApprovalCommand command) { + + AppUser currentUser = context.authenticatedUser(); + + Loan loan = this.loanRepository.findOne(loansThatMatch(currentUser.getOrganisation(), command.getLoanId())); + if (loan == null) { + throw new PlatformResourceNotFoundException("error.msg.loan.id.invalid", "Loan with identifier {0} does not exist", command.getLoanId()); + } + + loan.undoApproval(defaultLoanLifecycleStateMachine()); + this.loanRepository.save(loan); + + Note note = Note.loanNote(currentUser.getOrganisation(), loan, "Undo of approval."); + this.noteRepository.save(note); + + return new EntityIdentifier(loan.getClient().getId()); + } + + @Transactional + @Override + public EntityIdentifier rejectLoan(final LoanStateTransitionCommand command) { + + AppUser currentUser = (AppUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + + LoanStateTransitionCommandValidator validator = new LoanStateTransitionCommandValidator(command); + validator.validate(); + + Loan loan = this.loanRepository.findOne(loansThatMatch(currentUser.getOrganisation(), command.getLoanId())); + if (loan == null) { + throw new PlatformResourceNotFoundException("error.msg.loan.id.invalid", "Loan with identifier {0} does not exist", command.getLoanId()); + } + + if (this.isBeforeToday(command.getEventDate()) && currentUser.canNotRejectLoanInPast()) { + throw new NoAuthorizationException("User has no authority to reject loan with a date in the past."); + } + + loan.reject(command.getEventDate(), defaultLoanLifecycleStateMachine()); + this.loanRepository.save(loan); + + if (StringUtils.isNotBlank(command.getComment())) { + Note note = Note.loanNote(currentUser.getOrganisation(), loan, command.getComment()); + this.noteRepository.save(note); + } + + return new EntityIdentifier(loan.getClient().getId()); + } + + @Transactional + @Override + public EntityIdentifier withdrawLoan(final LoanStateTransitionCommand command) { + + AppUser currentUser = context.authenticatedUser(); + + LoanStateTransitionCommandValidator validator = new LoanStateTransitionCommandValidator(command); + validator.validate(); + + Loan loan = this.loanRepository.findOne(loansThatMatch(currentUser.getOrganisation(), command.getLoanId())); + if (loan == null) { + throw new PlatformResourceNotFoundException("error.msg.loan.id.invalid", "Loan with identifier {0} does not exist", command.getLoanId()); + } + + if (this.isBeforeToday(command.getEventDate()) && currentUser.canNotWithdrawByClientLoanInPast()) { + throw new NoAuthorizationException("User has no authority to mark loan as withdrawn by client with a date in the past."); + } + + loan.withdraw(command.getEventDate(), defaultLoanLifecycleStateMachine()); + this.loanRepository.save(loan); + + if (StringUtils.isNotBlank(command.getComment())) { + Note note = Note.loanNote(currentUser.getOrganisation(), loan, command.getComment()); + this.noteRepository.save(note); + } + + return new EntityIdentifier(loan.getClient().getId()); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/rest/LoanResource.java b/mifosng-provider/src/main/java/org/mifosng/platform/rest/LoanResource.java index 9a135142a..04ef41585 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/rest/LoanResource.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/rest/LoanResource.java @@ -22,7 +22,6 @@ import org.mifosng.data.LoanRepaymentData; import org.mifosng.data.command.AdjustLoanTransactionCommand; import org.mifosng.data.command.LoanStateTransitionCommand; import org.mifosng.data.command.LoanTransactionCommand; -import org.mifosng.data.command.UndoLoanApprovalCommand; import org.mifosng.data.command.UndoLoanDisbursalCommand; import org.mifosng.platform.ReadPlatformService; import org.mifosng.platform.ReadPlatformServiceImpl; @@ -49,98 +48,6 @@ public class LoanResource { @Autowired private WritePlatformService writePlatformService; - - @POST - @Path("approve") - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - public Response approveLoanApplication(final LoanStateTransitionCommand command) { - - try { - EntityIdentifier identifier = this.writePlatformService.approveLoanApplication(command); - - return Response.ok().entity(identifier).build(); - } catch (UnAuthenticatedUserException e) { - throw new WebApplicationException(Response.status(Status.UNAUTHORIZED).build()); - } catch (AccessDeniedException e) { - ErrorResponse errorResponse = new ErrorResponse("error.msg.no.permission", "id"); - ErrorResponseList list = new ErrorResponseList(Arrays.asList(errorResponse)); - throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(list).build()); - } catch (ApplicationDomainRuleException e) { - throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getErrors())).build()); - } catch (NewDataValidationException e) { - throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getValidationErrors())).build()); - } - } - - @POST - @Path("undoapproval") - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - public Response undoLoanApproval(final UndoLoanApprovalCommand command) { - - try { - EntityIdentifier identifier = this.writePlatformService.undoLoanApproval(command); - - return Response.ok().entity(identifier).build(); - } catch (UnAuthenticatedUserException e) { - throw new WebApplicationException(Response.status(Status.UNAUTHORIZED).build()); - } catch (AccessDeniedException e) { - ErrorResponse errorResponse = new ErrorResponse("error.msg.no.permission", "id"); - ErrorResponseList list = new ErrorResponseList(Arrays.asList(errorResponse)); - throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(list).build()); - } catch (ApplicationDomainRuleException e) { - throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getErrors())).build()); - } catch (NewDataValidationException e) { - throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getValidationErrors())).build()); - } - } - - @POST - @Path("reject") - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - public Response rejectLoanApplication(final LoanStateTransitionCommand command) { - - try { - EntityIdentifier identifier = this.writePlatformService.rejectLoan(command); - - return Response.ok().entity(identifier).build(); - } catch (UnAuthenticatedUserException e) { - throw new WebApplicationException(Response.status(Status.UNAUTHORIZED).build()); - } catch (AccessDeniedException e) { - ErrorResponse errorResponse = new ErrorResponse("error.msg.no.permission", "id"); - ErrorResponseList list = new ErrorResponseList(Arrays.asList(errorResponse)); - throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(list).build()); - } catch (ApplicationDomainRuleException e) { - throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getErrors())).build()); - } catch (NewDataValidationException e) { - throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getValidationErrors())).build()); - } - } - - @POST - @Path("withdraw") - @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - public Response withdrawLoanApplication(final LoanStateTransitionCommand command) { - - try { - EntityIdentifier identifier = this.writePlatformService.withdrawLoan(command); - - return Response.ok().entity(identifier).build(); - } catch (UnAuthenticatedUserException e) { - throw new WebApplicationException(Response.status(Status.UNAUTHORIZED).build()); - } catch (AccessDeniedException e) { - ErrorResponse errorResponse = new ErrorResponse("error.msg.no.permission", "id"); - ErrorResponseList list = new ErrorResponseList(Arrays.asList(errorResponse)); - throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(list).build()); - } catch (ApplicationDomainRuleException e) { - throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getErrors())).build()); - } catch (NewDataValidationException e) { - throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(new ErrorResponseList(e.getValidationErrors())).build()); - } - } @POST @Path("disburse")