Merge branch 'MIFOSX-478' of git://github.com/mifoscontributer/mifosx into mifoscontributer-MIFOSX-478
This commit is contained in:
@@ -890,6 +890,22 @@
|
||||
<td><a href="#charges_update">Update a Charge</a></td>
|
||||
<td><a href="#charges_delete">Delete a Charge</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#loanproductmix">Loan Product Mix</a></td>
|
||||
<td>loanproducts?associations=productMixes</td>
|
||||
<td></td>
|
||||
<td><a href="#loanproductmix_list">List Loan Products Mix</a></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="alt">
|
||||
<td></td>
|
||||
<td>loanproducts/{productId}/productmix</td>
|
||||
<td><a href="#loanproductmix_create">Create a Loan Product Mix</a></td>
|
||||
<td><a href="#loanproductmix_retrieve">Retrieve Loan Products Mix</a></td>
|
||||
<td><a href="#loanproductmix_update">Update Loan Product Mix</a></td>
|
||||
<td><a href="#loanproductmix_delete">Delete Loan Products Mix</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1403,6 +1419,10 @@
|
||||
<td>loanproducts/template</td>
|
||||
<td><a href="#loanproducts_template">Retrieve Loan Product Template</a></td>
|
||||
</tr>
|
||||
<tr >
|
||||
<td>loanproducts/template?isProductMixTemplate=true</td>
|
||||
<td><a href="#loanproductmix_template">Retrieve Loan Product Mix Template</a></td>
|
||||
</tr>
|
||||
<tr class="alt">
|
||||
<td>loans/template?clientId={clientId}</td>
|
||||
<td><a href="#loans_template">Retrieve Loan Template</a></td>
|
||||
@@ -8043,6 +8063,355 @@ Request Body:
|
||||
</div>
|
||||
<!-- end of loan products api docs -->
|
||||
|
||||
<!-- start of loan products mix api docs -->
|
||||
<a id="loanproductmix" name="loanproductmix" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h3>Loan Products Mix</h3>
|
||||
<p>If you have the appropriate permissions, you can decide which types of products a given client or group can mix. In this way, you can restrict clients from having active loans accounts of different products at the same time.</p>
|
||||
|
||||
<table class=matrixHeading>
|
||||
<tr class="matrixHeadingBG">
|
||||
<td><div class="mifosXHeading2">Field Descriptions</div></td>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>restrictedProducts</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class=fielddesc>List of productIds to create a product mix</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a id="loanproductmix_list" name="loanproductmix_list"
|
||||
class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h4>List Loan Product Mix</h4>
|
||||
<p>Example Requests:</p>
|
||||
<div class=apiClick>loanproducts?associations=productMixes</div>
|
||||
</div>
|
||||
<div class="method-example">
|
||||
<code class="method-declaration">
|
||||
GET https://DomainName/api/v1/loanproducts?associations=productMixes
|
||||
</code>
|
||||
<code class="method-response">
|
||||
[
|
||||
{
|
||||
"productId": 1,
|
||||
"productName": "Personal Loan",
|
||||
"restrictedProducts": [
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Joint Loan",
|
||||
"includeInBorrowerCycle": false
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "Primary Loan",
|
||||
"includeInBorrowerCycle": false
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Daily Loan",
|
||||
"includeInBorrowerCycle": false
|
||||
}
|
||||
],
|
||||
"allowedProducts": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Personal Loan",
|
||||
"includeInBorrowerCycle": false
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "Personal Loan -2",
|
||||
"includeInBorrowerCycle": false
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Weekly Loan",
|
||||
"includeInBorrowerCycle": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"productId": 2,
|
||||
"productName": "Joint Loan",
|
||||
"restrictedProducts": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Personal Loan",
|
||||
"includeInBorrowerCycle": false
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "Personal Loan -2",
|
||||
"includeInBorrowerCycle": false
|
||||
}
|
||||
],
|
||||
"allowedProducts": [
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Daily Loan",
|
||||
"includeInBorrowerCycle": false
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Joint Loan",
|
||||
"includeInBorrowerCycle": false
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "Primary Loan",
|
||||
"includeInBorrowerCycle": false
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Weekly Loan",
|
||||
"includeInBorrowerCycle": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a id="loanproductmix_template" name="loanproductmix_template"
|
||||
class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h4>Retrieve Product Mix Details Template</h4>
|
||||
<p>This is a convenience resource. It can be useful when
|
||||
building maintenance user interface screens for client
|
||||
applications. The template data returned consists of any or all
|
||||
of:
|
||||
<ul>
|
||||
<li class=normalli>Field Defaults</li>
|
||||
<li class=normalli>Allowed Value Lists</li>
|
||||
</ul>
|
||||
</p>
|
||||
<p>Example Request:</p>
|
||||
<p>This request gets all the products details for which productmix is not defined.</p>
|
||||
<br/>
|
||||
<div class=apiClick>loanproducts/template?isProductMixTemplate=true</div>
|
||||
<br/><br/>
|
||||
<p>This request gets the productmix details for the specific loanproduct.</p>
|
||||
<br/>
|
||||
<div class=apiClick>loanproducts/5/productmix</div>
|
||||
<br/>
|
||||
<div class=apiClick>loanproducts/5/productmix?template=true</div>
|
||||
|
||||
</div>
|
||||
<div class="method-example">
|
||||
<code class="method-declaration">
|
||||
GET https://DomainName/api/v1/loanproducts/template?isProductMixTemplate=true
|
||||
</code>
|
||||
<code class="method-response">
|
||||
{
|
||||
"productOptions": [
|
||||
{
|
||||
"id": 5,
|
||||
"name": "Primary Loan"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Weekly Loan"
|
||||
}
|
||||
]
|
||||
}
|
||||
</code>
|
||||
<code class="method-declaration">
|
||||
GET https://DomainName/api/v1/loanproducts/5/productmix
|
||||
</code>
|
||||
<code class="method-response">
|
||||
{
|
||||
"restrictedProducts": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Personal Loan",
|
||||
"includeInBorrowerCycle": false
|
||||
}
|
||||
],
|
||||
"allowedProducts": [
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Daily Loan",
|
||||
"includeInBorrowerCycle": false
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Joint Loan",
|
||||
"includeInBorrowerCycle": false
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "Personal Loan -2",
|
||||
"includeInBorrowerCycle": false
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "Primary Loan",
|
||||
"includeInBorrowerCycle": false
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Weekly Loan",
|
||||
"includeInBorrowerCycle": false
|
||||
}
|
||||
]
|
||||
}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a id="loanproductmix_retrieve" name="loanproductmix_retrieve"
|
||||
class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h4>Retrieve Loan Product Mix</h4>
|
||||
<p>Example Requests:</p>
|
||||
<div class=apiClick>loanproducts/5/productmix</div>
|
||||
</div>
|
||||
<div class="method-example">
|
||||
<code class="method-declaration">
|
||||
GET https://DomainName/api/v1/loanproducts/5/productmix
|
||||
</code>
|
||||
<code class="method-response">
|
||||
{
|
||||
"restrictedProducts": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Personal Loan",
|
||||
"includeInBorrowerCycle": false
|
||||
}
|
||||
],
|
||||
"allowedProducts": [
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Daily Loan",
|
||||
"includeInBorrowerCycle": false
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Joint Loan",
|
||||
"includeInBorrowerCycle": false
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "Personal Loan -2",
|
||||
"includeInBorrowerCycle": false
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "Primary Loan",
|
||||
"includeInBorrowerCycle": false
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Weekly Loan",
|
||||
"includeInBorrowerCycle": false
|
||||
}
|
||||
]
|
||||
}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a id="loanproductmix_create" name="loanproductmix_create"
|
||||
class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h4>Create a Loan Product Mix</h4>
|
||||
|
||||
<table class=matrixHeading>
|
||||
<tr class="matrixHeadingBG">
|
||||
<td><div class="mifosXHeading2">Mandatory Fields</div></td>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>restrictedProducts</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="method-example">
|
||||
<code class="method-declaration">
|
||||
POST https://DomainName/api/v1/loanproducts/5/productmix
|
||||
</code>
|
||||
<code class="method-request">
|
||||
POST loanproducts/{productId}/productmix
|
||||
Content-Type: application/json
|
||||
Request Body:
|
||||
{"restrictedProducts":["1"]}
|
||||
</code>
|
||||
<code class="method-response">
|
||||
{
|
||||
"changes":{
|
||||
"restrictedProductsForMix":[1],
|
||||
"removedProductsForMix":[]
|
||||
},
|
||||
"productId":5
|
||||
}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a id="loanproductmix_update" name="loanproductmix_update"
|
||||
class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h4>Update a Loan Product Mix</h4>
|
||||
</div>
|
||||
<div class="method-example">
|
||||
<code class="method-declaration">
|
||||
PUT https://DomainName/api/v1/loanproducts/{productId}/productmix
|
||||
</code>
|
||||
<code class="method-request">
|
||||
PUT loanproducts/5/productmix
|
||||
Content-Type: application/json
|
||||
Request Body:
|
||||
{
|
||||
"restrictedProducts":["3"]
|
||||
}
|
||||
</code>
|
||||
<code class="method-response">
|
||||
{
|
||||
"changes": {
|
||||
"restrictedProductsForMix": [3],
|
||||
"removedProductsForMix": [1]
|
||||
},
|
||||
"productId": 5
|
||||
}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a id="loanproductmix_delete" name="loanproductmix_delete"
|
||||
class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h4>Delete a Loan Product Mix</h4>
|
||||
</div>
|
||||
<div class="method-example">
|
||||
<code class="method-declaration">
|
||||
DELETE https://DomainName/api/v1/loanproducts/{productId}/productmix
|
||||
</code>
|
||||
<code class="method-request">
|
||||
DELETE loanproducts/5/productmix
|
||||
</code>
|
||||
<code class="method-response">
|
||||
{
|
||||
"changes": {
|
||||
"removedProductsForMix": [3]
|
||||
},
|
||||
"productId": 5
|
||||
}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end of loan products mix api docs -->
|
||||
|
||||
<!-- start of configurations api docs -->
|
||||
<a id="configs" name="configs" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
@@ -16390,6 +16759,30 @@ GET https://DomainName/api/v1/search?query=000000111
|
||||
<td><a href="#loanproducts_update">Update a Loan Product</a></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="alt">
|
||||
<td><a href="#loanproductmix">Loan Product Mix</a></td>
|
||||
<td>loanproducts/template?isProductMixTemplate=true</td>
|
||||
<td></td>
|
||||
<td><a href="#loanproductmix_template">Retrieve Loan Product Mix Template</a></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>loanproducts?associations=productMixes</td>
|
||||
<td></td>
|
||||
<td><a href="#loanproductmix_list">List Loan Products Mix</a></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="alt">
|
||||
<td></td>
|
||||
<td>loanproducts/{productId}/productmix</td>
|
||||
<td><a href="#loanproductmix_create">Create a Loan Product Mix</a></td>
|
||||
<td><a href="#loanproductmix_retrieve">Retrieve Loan Products Mix</a></td>
|
||||
<td><a href="#loanproductmix_update">Update Loan Product Mix</a></td>
|
||||
<td><a href="#loanproductmix_delete">Delete Loan Products Mix</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#loans">Loans</a></td>
|
||||
<td>loans?calculateLoanSchedule</td>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
ALTER TABLE `m_portfolio_command_source`
|
||||
ADD COLUMN `product_id` BIGINT NULL DEFAULT NULL AFTER `processing_result_enum`;
|
||||
|
||||
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'CREATE_PRODUCTMIX', 'PRODUCTMIX', 'CREATE', 0);
|
||||
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'UPDATE_PRODUCTMIX', 'PRODUCTMIX', 'UPDATE', 0);
|
||||
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'DELETE_PRODUCTMIX', 'PRODUCTMIX', 'DELETE', 0);
|
||||
|
||||
CREATE TABLE `m_product_mix` (
|
||||
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
`product_id` BIGINT(20) NOT NULL,
|
||||
`restricted_product_id` BIGINT(20) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `FK_m_product_mix_product_id_to_m_product_loan` (`product_id`),
|
||||
INDEX `FK_m_product_mix_restricted_product_id_to_m_product_loan` (`restricted_product_id`),
|
||||
CONSTRAINT `FK_m_product_mix_restricted_product_id_to_m_product_loan` FOREIGN KEY (`restricted_product_id`) REFERENCES `m_product_loan` (`id`),
|
||||
CONSTRAINT `FK_m_product_mix_product_id_to_m_product_loan` FOREIGN KEY (`product_id`) REFERENCES `m_product_loan` (`id`)
|
||||
)
|
||||
COLLATE='utf8_general_ci'
|
||||
ENGINE=InnoDB;
|
||||
+10
-1
@@ -85,6 +85,9 @@ public class CommandSource extends AbstractPersistable<Long> {
|
||||
|
||||
@Column(name = "processing_result_enum", nullable = false)
|
||||
private Integer processingResult;
|
||||
|
||||
@Column(name = "product_id")
|
||||
private Long productId;
|
||||
|
||||
public static CommandSource fullEntryFrom(final CommandWrapper wrapper, final JsonCommand command, final AppUser maker) {
|
||||
return new CommandSource(wrapper.actionName(), wrapper.entityName(), wrapper.getHref(), command.entityId(), command.subentityId(),
|
||||
@@ -172,15 +175,21 @@ public class CommandSource extends AbstractPersistable<Long> {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void updateForAudit(final Long officeId, final Long groupId, final Long clientId, final Long loanId, final Long savingsId) {
|
||||
public void updateForAudit(final Long officeId, final Long groupId, final Long clientId, final Long loanId, final Long savingsId,
|
||||
final Long productId) {
|
||||
this.officeId = officeId;
|
||||
this.groupId = groupId;
|
||||
this.clientId = clientId;
|
||||
this.loanId = loanId;
|
||||
this.savingsId = savingsId;
|
||||
this.productId = productId;
|
||||
}
|
||||
|
||||
public String getResourceGetUrl() {
|
||||
return this.resourceGetUrl;
|
||||
}
|
||||
|
||||
public Long getProductId() {
|
||||
return this.productId;
|
||||
}
|
||||
}
|
||||
+18
-7
@@ -25,18 +25,19 @@ public class CommandWrapper {
|
||||
private final String transactionId;
|
||||
private final String supportedEntityType;
|
||||
private final Long supportedEntityId;
|
||||
private final Long productId;
|
||||
|
||||
public static CommandWrapper wrap(final String actionName, final String entityName, final Long resourceId, final Long subresourceId) {
|
||||
return new CommandWrapper(null, actionName, entityName, resourceId, subresourceId, null);
|
||||
return new CommandWrapper(null, actionName, entityName, resourceId, subresourceId, null, null);
|
||||
}
|
||||
|
||||
public static CommandWrapper fromExistingCommand(final Long commandId, final String actionName, final String entityName,
|
||||
final Long resourceId, final Long subresourceId, final String resourceGetUrl) {
|
||||
return new CommandWrapper(commandId, actionName, entityName, resourceId, subresourceId, resourceGetUrl);
|
||||
final Long resourceId, final Long subresourceId, final String resourceGetUrl, final Long productId) {
|
||||
return new CommandWrapper(commandId, actionName, entityName, resourceId, subresourceId, resourceGetUrl, productId);
|
||||
}
|
||||
|
||||
private CommandWrapper(final Long commandId, final String actionName, final String entityName, final Long resourceId,
|
||||
final Long subresourceId, final String resourceGetUrl) {
|
||||
final Long subresourceId, final String resourceGetUrl, final Long productId) {
|
||||
this.commandId = commandId;
|
||||
this.officeId = null;
|
||||
this.groupId = null;
|
||||
@@ -54,12 +55,14 @@ public class CommandWrapper {
|
||||
this.href = resourceGetUrl;
|
||||
this.json = null;
|
||||
this.transactionId = null;
|
||||
this.productId = productId;
|
||||
|
||||
}
|
||||
|
||||
public CommandWrapper(final Long officeId, final Long groupId, final Long clientId, final Long loanId, final Long savingsId,
|
||||
final String actionName, final String entityName, final Long entityId, final Long subentityId, final Long codeId,
|
||||
final String supportedEntityType, final Long supportedEntityId, final String href, final String json, final String transactionId) {
|
||||
final String supportedEntityType, final Long supportedEntityId, final String href, final String json,
|
||||
final String transactionId, final Long productId) {
|
||||
this.commandId = null;
|
||||
this.officeId = officeId;
|
||||
this.groupId = groupId;
|
||||
@@ -77,7 +80,7 @@ public class CommandWrapper {
|
||||
this.href = href;
|
||||
this.json = json;
|
||||
this.transactionId = transactionId;
|
||||
|
||||
this.productId = productId;
|
||||
}
|
||||
|
||||
public Long commandId() {
|
||||
@@ -176,6 +179,10 @@ public class CommandWrapper {
|
||||
return this.supportedEntityType;
|
||||
}
|
||||
|
||||
public Long getProductId() {
|
||||
return this.productId;
|
||||
}
|
||||
|
||||
public boolean isUpdate() {
|
||||
// permissions resource has special update which involves no resource.
|
||||
return (isPermissionResource() && isUpdateOperation()) || (isCurrencyResource() && isUpdateOperation())
|
||||
@@ -190,7 +197,7 @@ public class CommandWrapper {
|
||||
return isDeleteOperation() && this.entityId != null;
|
||||
}
|
||||
|
||||
private boolean isDeleteOperation() {
|
||||
public boolean isDeleteOperation() {
|
||||
return this.actionName.equalsIgnoreCase("DELETE");
|
||||
}
|
||||
|
||||
@@ -540,4 +547,8 @@ public class CommandWrapper {
|
||||
public boolean isClientClose() {
|
||||
return this.actionName.equalsIgnoreCase("CLOSE") && this.entityName.equalsIgnoreCase("CLIENT");
|
||||
}
|
||||
|
||||
public boolean isProductMixResource() {
|
||||
return this.entityName.equalsIgnoreCase("PRODUCTMIX");
|
||||
}
|
||||
}
|
||||
+34
-1
@@ -24,11 +24,12 @@ public class CommandWrapperBuilder {
|
||||
private String transactionId;
|
||||
private String supportedEntityType;
|
||||
private Long supportedEntityId;
|
||||
private Long productId;
|
||||
|
||||
public CommandWrapper build() {
|
||||
return new CommandWrapper(this.officeId, this.groupId, this.clientId, this.loanId, this.savingsId, this.actionName,
|
||||
this.entityName, this.entityId, this.subentityId, this.codeId, this.supportedEntityType, this.supportedEntityId, this.href,
|
||||
this.json, this.transactionId);
|
||||
this.json, this.transactionId, this.productId);
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder withLoanId(final Long withLoanId) {
|
||||
@@ -1127,4 +1128,36 @@ public class CommandWrapperBuilder {
|
||||
this.href = "/clients/" + clientId + "?command=assignStaff";
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder createProductMix(final Long productId) {
|
||||
this.actionName = "CREATE";
|
||||
this.entityName = "PRODUCTMIX";
|
||||
this.entityId = null;
|
||||
this.productId = productId;
|
||||
this.href = "/loanproducts/" + productId + "/productmix";
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder updateProductMix(final Long productId) {
|
||||
this.actionName = "UPDATE";
|
||||
this.entityName = "PRODUCTMIX";
|
||||
this.entityId = null;
|
||||
this.productId = productId;
|
||||
this.href = "/loanproducts/" + productId + "/productmix";
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder deleteProductMix(final Long productId) {
|
||||
this.actionName = "DELETE";
|
||||
this.entityName = "PRODUCTMIX";
|
||||
this.entityId = null;
|
||||
this.productId = productId;
|
||||
this.href = "/loanproducts/" + productId + "/productmix";
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder withProduct(final Long productId) {
|
||||
this.productId = productId;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -63,7 +63,7 @@ public class PortfolioCommandSourceWritePlatformServiceImpl implements Portfolio
|
||||
final JsonCommand command = JsonCommand.from(json, parsedCommand, this.fromApiJsonHelper, wrapper.getEntityName(),
|
||||
wrapper.getEntityId(), wrapper.getSubentityId(), wrapper.getGroupId(), wrapper.getClientId(), wrapper.getLoanId(),
|
||||
wrapper.getSavingsId(), wrapper.getCodeId(), wrapper.getSupportedEntityType(), wrapper.getSupportedEntityId(),
|
||||
wrapper.getTransactionId(), wrapper.getHref());
|
||||
wrapper.getTransactionId(), wrapper.getHref(), wrapper.getProductId());
|
||||
|
||||
result = this.processAndLogCommandService.processAndLogCommand(wrapper, command, isApprovedByChecker);
|
||||
} catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) {
|
||||
@@ -81,12 +81,12 @@ public class PortfolioCommandSourceWritePlatformServiceImpl implements Portfolio
|
||||
|
||||
final CommandWrapper wrapper = CommandWrapper.fromExistingCommand(makerCheckerId, commandSourceInput.getActionName(),
|
||||
commandSourceInput.getEntityName(), commandSourceInput.resourceId(), commandSourceInput.subresourceId(),
|
||||
commandSourceInput.getResourceGetUrl());
|
||||
commandSourceInput.getResourceGetUrl(), commandSourceInput.getProductId());
|
||||
|
||||
final JsonElement parsedCommand = this.fromApiJsonHelper.parse(commandSourceInput.json());
|
||||
final JsonCommand command = JsonCommand.fromExistingCommand(makerCheckerId, commandSourceInput.json(), parsedCommand,
|
||||
this.fromApiJsonHelper, commandSourceInput.getEntityName(), commandSourceInput.resourceId(),
|
||||
commandSourceInput.subresourceId(), commandSourceInput.getResourceGetUrl());
|
||||
commandSourceInput.subresourceId(), commandSourceInput.getResourceGetUrl(), commandSourceInput.getProductId());
|
||||
|
||||
final boolean makerCheckerApproval = true;
|
||||
return this.processAndLogCommandService.processAndLogCommand(wrapper, command, makerCheckerApproval);
|
||||
|
||||
+11
-1
@@ -70,7 +70,7 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
|
||||
}
|
||||
commandSourceResult.updateResourceId(result.resourceId());
|
||||
commandSourceResult.updateForAudit(result.getOfficeId(), result.getGroupId(), result.getClientId(), result.getLoanId(),
|
||||
result.getSavingsId());
|
||||
result.getSavingsId(), result.getProductId());
|
||||
|
||||
String changesOnlyJson = null;
|
||||
if (result.hasChanges()) {
|
||||
@@ -493,6 +493,16 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
|
||||
if (wrapper.isCreate()) {
|
||||
handler = this.applicationContext.getBean("createHolidayCommandHandler", NewCommandSourceHandler.class);
|
||||
}
|
||||
} else if (wrapper.isProductMixResource()) {
|
||||
if (wrapper.isCreate()) {
|
||||
handler = this.applicationContext.getBean("createProductMixCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isUpdateOperation()) {
|
||||
handler = this.applicationContext.getBean("updateProductMixCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isDeleteOperation()) {
|
||||
handler = this.applicationContext.getBean("deleteProductMixCommandHandler", NewCommandSourceHandler.class);
|
||||
} else {
|
||||
throw new UnsupportedCommandException(wrapper.commandName());
|
||||
}
|
||||
} else {
|
||||
throw new UnsupportedCommandException(wrapper.commandName());
|
||||
}
|
||||
|
||||
+11
-5
@@ -46,26 +46,27 @@ public final class JsonCommand {
|
||||
private final Long supportedEntityId;
|
||||
private final String transactionId;
|
||||
private final String url;
|
||||
private final Long productId;
|
||||
|
||||
public static JsonCommand from(final String jsonCommand, final JsonElement parsedCommand, final FromJsonHelper fromApiJsonHelper,
|
||||
final String entityName, final Long resourceId, final Long subresourceId, final Long groupId, final Long clientId,
|
||||
final Long loanId, final Long savingsId, final Long codeId, final String supportedEntityType, final Long supportedEntityId,
|
||||
final String transactionId, final String url) {
|
||||
final String transactionId, final String url, final Long productId) {
|
||||
return new JsonCommand(null, jsonCommand, parsedCommand, fromApiJsonHelper, entityName, resourceId, subresourceId, groupId,
|
||||
clientId, loanId, savingsId, codeId, supportedEntityType, supportedEntityId, transactionId, url);
|
||||
clientId, loanId, savingsId, codeId, supportedEntityType, supportedEntityId, transactionId, url, productId);
|
||||
}
|
||||
|
||||
public static JsonCommand fromExistingCommand(final Long commandId, final String jsonCommand, final JsonElement parsedCommand,
|
||||
final FromJsonHelper fromApiJsonHelper, final String entityName, final Long resourceId, final Long subresourceId,
|
||||
final String url) {
|
||||
final String url, final Long productId) {
|
||||
return new JsonCommand(commandId, jsonCommand, parsedCommand, fromApiJsonHelper, entityName, resourceId, subresourceId, null, null,
|
||||
null, null, null, null, null, null, url);
|
||||
null, null, null, null, null, null, url, productId);
|
||||
}
|
||||
|
||||
public JsonCommand(final Long commandId, final String jsonCommand, final JsonElement parsedCommand,
|
||||
final FromJsonHelper fromApiJsonHelper, final String entityName, final Long resourceId, final Long subresourceId,
|
||||
final Long groupId, final Long clientId, final Long loanId, final Long savingsId, final Long codeId,
|
||||
final String supportedEntityType, final Long supportedEntityId, final String transactionId, final String url) {
|
||||
final String supportedEntityType, final Long supportedEntityId, final String transactionId, final String url, final Long productId) {
|
||||
this.commandId = commandId;
|
||||
this.jsonCommand = jsonCommand;
|
||||
this.parsedCommand = parsedCommand;
|
||||
@@ -82,6 +83,7 @@ public final class JsonCommand {
|
||||
this.supportedEntityId = supportedEntityId;
|
||||
this.transactionId = transactionId;
|
||||
this.url = url;
|
||||
this.productId = productId;
|
||||
}
|
||||
|
||||
public String json() {
|
||||
@@ -153,6 +155,10 @@ public final class JsonCommand {
|
||||
return this.url;
|
||||
}
|
||||
|
||||
public Long getProductId() {
|
||||
return this.productId;
|
||||
}
|
||||
|
||||
private boolean differenceExists(final LocalDate baseValue, final LocalDate workingCopyValue) {
|
||||
boolean differenceExists = false;
|
||||
|
||||
|
||||
+11
-3
@@ -25,12 +25,13 @@ public class CommandProcessingResult {
|
||||
private final Map<String, Object> changes;
|
||||
@SuppressWarnings("unused")
|
||||
private final String resourceIdentifier;
|
||||
private final Long productId;
|
||||
|
||||
public static CommandProcessingResult fromDetails(final Long commandId, final Long officeId, final Long groupId, final Long clientId,
|
||||
final Long loanId, final Long savingsId, final String resourceIdentifier, final Long entityId, final String transactionId,
|
||||
final Map<String, Object> changes) {
|
||||
final Map<String, Object> changes, final Long productId) {
|
||||
return new CommandProcessingResult(commandId, officeId, groupId, clientId, loanId, savingsId, resourceIdentifier, entityId,
|
||||
transactionId, changes);
|
||||
transactionId, changes, productId);
|
||||
}
|
||||
|
||||
public static CommandProcessingResult commandOnlyResult(final Long commandId) {
|
||||
@@ -79,11 +80,12 @@ public class CommandProcessingResult {
|
||||
this.savingsId = null;
|
||||
this.transactionId = null;
|
||||
this.changes = new HashMap<String, Object>();
|
||||
this.productId = null;
|
||||
}
|
||||
|
||||
private CommandProcessingResult(final Long commandId, final Long officeId, final Long groupId, final Long clientId, final Long loanId,
|
||||
final Long savingsId, final String resourceIdentifier, final Long resourceId, final String transactionId,
|
||||
final Map<String, Object> changesOnly) {
|
||||
final Map<String, Object> changesOnly, final Long productId) {
|
||||
this.commandId = commandId;
|
||||
this.officeId = officeId;
|
||||
this.groupId = groupId;
|
||||
@@ -94,6 +96,7 @@ public class CommandProcessingResult {
|
||||
this.resourceId = resourceId;
|
||||
this.changes = changesOnly;
|
||||
this.transactionId = transactionId;
|
||||
this.productId = productId;
|
||||
}
|
||||
|
||||
private CommandProcessingResult(final Long resourceId, final Long officeId, final Long commandId, final Map<String, Object> changesOnly) {
|
||||
@@ -111,6 +114,7 @@ public class CommandProcessingResult {
|
||||
this.transactionId = null;
|
||||
this.commandId = commandId;
|
||||
this.changes = changesOnly;
|
||||
this.productId = null;
|
||||
}
|
||||
|
||||
public Long commandId() {
|
||||
@@ -161,4 +165,8 @@ public class CommandProcessingResult {
|
||||
final boolean noChanges = this.changes == null || this.changes.isEmpty();
|
||||
return !noChanges;
|
||||
}
|
||||
|
||||
public Long getProductId() {
|
||||
return this.productId;
|
||||
}
|
||||
}
|
||||
+7
-1
@@ -23,10 +23,11 @@ public class CommandProcessingResultBuilder {
|
||||
private Long entityId;
|
||||
private String transactionId;
|
||||
private Map<String, Object> changes;
|
||||
private Long productId;
|
||||
|
||||
public CommandProcessingResult build() {
|
||||
return CommandProcessingResult.fromDetails(commandId, officeId, groupId, clientId, loanId, savingsId, resourceIdentifier, entityId,
|
||||
transactionId, changes);
|
||||
transactionId, changes, productId);
|
||||
}
|
||||
|
||||
public CommandProcessingResultBuilder withCommandId(final Long withCommandId) {
|
||||
@@ -78,5 +79,10 @@ public class CommandProcessingResultBuilder {
|
||||
this.transactionId = withTransactionId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandProcessingResultBuilder withProductId(final Long productId) {
|
||||
this.productId = productId;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
+35
-4
@@ -19,6 +19,7 @@ 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.UriInfo;
|
||||
@@ -33,6 +34,7 @@ import org.mifosplatform.commands.service.CommandWrapperBuilder;
|
||||
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
|
||||
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
|
||||
import org.mifosplatform.infrastructure.codes.service.CodeValueReadPlatformService;
|
||||
import org.mifosplatform.infrastructure.core.api.ApiParameterHelper;
|
||||
import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
@@ -47,6 +49,8 @@ import org.mifosplatform.portfolio.fund.data.FundData;
|
||||
import org.mifosplatform.portfolio.fund.service.FundReadPlatformService;
|
||||
import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
|
||||
import org.mifosplatform.portfolio.loanproduct.data.TransactionProcessingStrategyData;
|
||||
import org.mifosplatform.portfolio.loanproduct.productmix.data.ProductMixData;
|
||||
import org.mifosplatform.portfolio.loanproduct.productmix.service.ProductMixReadPlatformService;
|
||||
import org.mifosplatform.portfolio.loanproduct.service.LoanDropdownReadPlatformService;
|
||||
import org.mifosplatform.portfolio.loanproduct.service.LoanProductReadPlatformService;
|
||||
import org.mifosplatform.portfolio.paymentdetail.PaymentDetailConstants;
|
||||
@@ -69,6 +73,9 @@ public class LoanProductsApiResource {
|
||||
"currencyOptions", "repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "amortizationTypeOptions",
|
||||
"interestTypeOptions", "interestCalculationPeriodTypeOptions", "transactionProcessingStrategyOptions", "chargeOptions",
|
||||
"accountingOptions", "accountingRuleOptions", "accountingMappingOptions"));
|
||||
|
||||
private final Set<String> PRODUCT_MIX_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("productId", "productName",
|
||||
"restrictedProducts", "allowedProducts", "productOptions"));
|
||||
|
||||
private final String resourceNameForPermissions = "LOANPRODUCT";
|
||||
|
||||
@@ -84,6 +91,8 @@ public class LoanProductsApiResource {
|
||||
private final ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService;
|
||||
private final CodeValueReadPlatformService codeValueReadPlatformService;
|
||||
private final AccountingDropdownReadPlatformService accountingDropdownReadPlatformService;
|
||||
private final DefaultToApiJsonSerializer<ProductMixData> productMixDataApiJsonSerializer;
|
||||
private final ProductMixReadPlatformService productMixReadPlatformService;
|
||||
|
||||
@Autowired
|
||||
public LoanProductsApiResource(final PlatformSecurityContext context, final LoanProductReadPlatformService readPlatformService,
|
||||
@@ -94,7 +103,9 @@ public class LoanProductsApiResource {
|
||||
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
|
||||
final ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService,
|
||||
final CodeValueReadPlatformService codeValueReadPlatformService,
|
||||
final AccountingDropdownReadPlatformService accountingDropdownReadPlatformService) {
|
||||
final AccountingDropdownReadPlatformService accountingDropdownReadPlatformService,
|
||||
final DefaultToApiJsonSerializer<ProductMixData> productMixDataApiJsonSerializer,
|
||||
final ProductMixReadPlatformService productMixReadPlatformService) {
|
||||
this.context = context;
|
||||
this.loanProductReadPlatformService = readPlatformService;
|
||||
this.chargeReadPlatformService = chargeReadPlatformService;
|
||||
@@ -107,6 +118,8 @@ public class LoanProductsApiResource {
|
||||
this.accountMappingReadPlatformService = accountMappingReadPlatformService;
|
||||
this.codeValueReadPlatformService = codeValueReadPlatformService;
|
||||
this.accountingDropdownReadPlatformService = accountingDropdownReadPlatformService;
|
||||
this.productMixDataApiJsonSerializer = productMixDataApiJsonSerializer;
|
||||
this.productMixReadPlatformService = productMixReadPlatformService;
|
||||
}
|
||||
|
||||
@POST
|
||||
@@ -127,10 +140,19 @@ public class LoanProductsApiResource {
|
||||
public String retrieveAllLoanProducts(@Context final UriInfo uriInfo) {
|
||||
|
||||
context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions);
|
||||
final Set<String> associationParameters = ApiParameterHelper.extractAssociationsForResponseIfProvided(uriInfo.getQueryParameters());
|
||||
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
|
||||
if (!associationParameters.isEmpty()) {
|
||||
if (associationParameters.contains("productMixes")) {
|
||||
context.authenticatedUser().validateHasReadPermission("PRODUCTMIX");
|
||||
Collection<ProductMixData> productMixes = this.productMixReadPlatformService.retrieveAllProductMixes();
|
||||
return this.productMixDataApiJsonSerializer.serialize(settings, productMixes, PRODUCT_MIX_DATA_PARAMETERS);
|
||||
}
|
||||
}
|
||||
|
||||
final Collection<LoanProductData> products = this.loanProductReadPlatformService.retrieveAllLoanProducts();
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.toApiJsonSerializer.serialize(settings, products, LOAN_PRODUCT_DATA_PARAMETERS);
|
||||
}
|
||||
|
||||
@@ -138,14 +160,22 @@ public class LoanProductsApiResource {
|
||||
@Path("template")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveTemplate(@Context final UriInfo uriInfo) {
|
||||
public String retrieveTemplate(@Context final UriInfo uriInfo, @QueryParam("isProductMixTemplate") final boolean isProductMixTemplate) {
|
||||
|
||||
context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions);
|
||||
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
|
||||
if (isProductMixTemplate) {
|
||||
context.authenticatedUser().validateHasReadPermission("PRODUCTMIX");
|
||||
|
||||
Collection<LoanProductData> productOptions = this.loanProductReadPlatformService.retrieveAvailableLoanProductsForMix();
|
||||
ProductMixData productMixData = ProductMixData.template(productOptions);
|
||||
return this.productMixDataApiJsonSerializer.serialize(settings, productMixData, PRODUCT_MIX_DATA_PARAMETERS);
|
||||
}
|
||||
|
||||
LoanProductData loanProduct = this.loanProductReadPlatformService.retrieveNewLoanProductDetails();
|
||||
loanProduct = handleTemplate(loanProduct);
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.toApiJsonSerializer.serialize(settings, loanProduct, LOAN_PRODUCT_DATA_PARAMETERS);
|
||||
}
|
||||
|
||||
@@ -237,4 +267,5 @@ public class LoanProductsApiResource {
|
||||
interestRateFrequencyTypeOptions, fundOptions, transactionProcessingStrategyOptions, accountOptions,
|
||||
accountingRuleTypeOptions);
|
||||
}
|
||||
|
||||
}
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* 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.portfolio.loanproduct.productmix.api;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
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.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.mifosplatform.commands.domain.CommandWrapper;
|
||||
import org.mifosplatform.commands.service.CommandWrapperBuilder;
|
||||
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
|
||||
import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
|
||||
import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
|
||||
import org.mifosplatform.portfolio.loanproduct.productmix.data.ProductMixData;
|
||||
import org.mifosplatform.portfolio.loanproduct.productmix.service.ProductMixReadPlatformService;
|
||||
import org.mifosplatform.portfolio.loanproduct.service.LoanProductReadPlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Path("/loanproducts/{productId}/productmix")
|
||||
@Component
|
||||
@Scope("singleton")
|
||||
public class ProductMixApiResource {
|
||||
|
||||
private final String resourceNameForPermissions = "PRODUCTMIX";
|
||||
|
||||
private final Set<String> PRODUCT_MIX_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("productId", "productName",
|
||||
"restrictedProducts", "allowedProducts", "productOptions"));
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
|
||||
private final ApiRequestParameterHelper apiRequestParameterHelper;
|
||||
private final DefaultToApiJsonSerializer<ProductMixData> toApiJsonSerializer;
|
||||
|
||||
private final ProductMixReadPlatformService productMixReadPlatformService;
|
||||
private final LoanProductReadPlatformService loanProductReadPlatformService;
|
||||
|
||||
@Autowired
|
||||
public ProductMixApiResource(final PlatformSecurityContext context,
|
||||
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
|
||||
final ApiRequestParameterHelper apiRequestParameterHelper,
|
||||
final DefaultToApiJsonSerializer<ProductMixData> toApiJsonSerializer,
|
||||
final ProductMixReadPlatformService productMixReadPlatformService,
|
||||
final LoanProductReadPlatformService loanProductReadPlatformService) {
|
||||
this.context = context;
|
||||
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
|
||||
this.apiRequestParameterHelper = apiRequestParameterHelper;
|
||||
this.toApiJsonSerializer = toApiJsonSerializer;
|
||||
this.productMixReadPlatformService = productMixReadPlatformService;
|
||||
this.loanProductReadPlatformService = loanProductReadPlatformService;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveTemplate(@PathParam("productId") final Long productId, @Context final UriInfo uriInfo) {
|
||||
|
||||
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
|
||||
|
||||
ProductMixData productMixData = this.productMixReadPlatformService.retrieveLoanProductMixDetails(productId);
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
if (settings.isTemplate()) {
|
||||
final Collection<LoanProductData> productOptions = this.loanProductReadPlatformService.retrieveAvailableLoanProductsForMix();
|
||||
productMixData = ProductMixData.withTemplateOptions(productMixData, productOptions);
|
||||
}
|
||||
return this.toApiJsonSerializer.serialize(settings, productMixData, this.PRODUCT_MIX_DATA_PARAMETERS);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String createProductMix(@PathParam("productId") final Long productId, final String apiRequestBodyAsJson) {
|
||||
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().createProductMix(productId).withJson(apiRequestBodyAsJson)
|
||||
.build();
|
||||
|
||||
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String updateProductMix(@PathParam("productId") final Long productId, final String apiRequestBodyAsJson) {
|
||||
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateProductMix(productId).withJson(apiRequestBodyAsJson)
|
||||
.build();
|
||||
|
||||
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String deleteProductMix(@PathParam("productId") final Long productId) {
|
||||
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteProductMix(productId).build();
|
||||
|
||||
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
}
|
||||
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package org.mifosplatform.portfolio.loanproduct.productmix.data;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
|
||||
|
||||
public class ProductMixData {
|
||||
|
||||
private final Long productId;
|
||||
private final String productName;
|
||||
private final Collection<LoanProductData> restrictedProducts;
|
||||
private final Collection<LoanProductData> allowedProducts;
|
||||
@SuppressWarnings("unused")
|
||||
private final Collection<LoanProductData> productOptions;
|
||||
|
||||
public ProductMixData(final Long productId, final String productName, final Collection<LoanProductData> restrictedProducts,
|
||||
final Collection<LoanProductData> allowedProducts, final Collection<LoanProductData> productOptions) {
|
||||
this.productId = productId;
|
||||
this.productName = productName;
|
||||
this.restrictedProducts = restrictedProducts;
|
||||
this.allowedProducts = allowedProducts;
|
||||
this.productOptions = productOptions;
|
||||
}
|
||||
|
||||
public static ProductMixData template(final Collection<LoanProductData> productOptions) {
|
||||
return new ProductMixData(null, null, null, null, productOptions);
|
||||
}
|
||||
|
||||
public static ProductMixData withTemplateOptions(final ProductMixData productMixData, final Collection<LoanProductData> productOptions) {
|
||||
return new ProductMixData(productMixData.productId, productMixData.productName, productMixData.restrictedProducts,
|
||||
productMixData.allowedProducts, productOptions);
|
||||
}
|
||||
|
||||
public static ProductMixData withDetails(Long productId, String productName, Collection<LoanProductData> restrictedProducts,
|
||||
Collection<LoanProductData> allowedProducts) {
|
||||
return new ProductMixData(productId, productName, restrictedProducts, allowedProducts, null);
|
||||
}
|
||||
|
||||
public static ProductMixData withRestrictedOptions(Collection<LoanProductData> restrictedProducts,
|
||||
Collection<LoanProductData> allowedProducts) {
|
||||
return new ProductMixData(null, null, restrictedProducts, allowedProducts, null);
|
||||
}
|
||||
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package org.mifosplatform.portfolio.loanproduct.productmix.domain;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_product_mix")
|
||||
public class ProductMix extends AbstractPersistable<Long> {
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "product_id", nullable = false)
|
||||
private LoanProduct product;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "restricted_product_id", nullable = false)
|
||||
private LoanProduct restrictedProduct;
|
||||
|
||||
public ProductMix() {
|
||||
//
|
||||
}
|
||||
|
||||
private ProductMix(final LoanProduct product, final LoanProduct restrictedProduct) {
|
||||
this.product = product;
|
||||
this.restrictedProduct = restrictedProduct;
|
||||
}
|
||||
|
||||
public static ProductMix createNew(final LoanProduct product, final LoanProduct restrictedProduct) {
|
||||
return new ProductMix(product, restrictedProduct);
|
||||
}
|
||||
|
||||
public Long getRestrictedProductId() {
|
||||
return this.restrictedProduct.getId();
|
||||
}
|
||||
|
||||
public Long getProductId() {
|
||||
return this.product.getId();
|
||||
}
|
||||
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package org.mifosplatform.portfolio.loanproduct.productmix.domain;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface ProductMixRepository extends JpaRepository<ProductMix, Long>, JpaSpecificationExecutor<ProductMix> {
|
||||
|
||||
public static final String GET_PRODUCTMIXES_BY_PRODUCTID_SCHEMA = "from ProductMix pm where pm.product.id = :productId";
|
||||
public static final String GET_RESTRICTED_PRODUCTIDS_SCHEMA = "Select pm.restrictedProduct.id from ProductMix pm where pm.product.id = :productId";
|
||||
public static final String GET_RESTRICTED_PRODUCTS_SCHEMA = "from ProductMix pm where pm.restrictedProduct.id = :restrictedProductId";
|
||||
|
||||
@Query(GET_PRODUCTMIXES_BY_PRODUCTID_SCHEMA)
|
||||
List<ProductMix> findByProductId(@Param("productId") Long productId);
|
||||
|
||||
@Query(GET_RESTRICTED_PRODUCTIDS_SCHEMA)
|
||||
List<Long> findRestrictedProductIdsByProductId(@Param("productId") Long productId);
|
||||
|
||||
@Query(GET_RESTRICTED_PRODUCTS_SCHEMA)
|
||||
List<ProductMix> findRestrictedProducts(@Param("restrictedProductId") Long restrictedProductId);
|
||||
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package org.mifosplatform.portfolio.loanproduct.productmix.exception;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
|
||||
|
||||
/**
|
||||
* A {@link RuntimeException} thrown when no product mixes found with the
|
||||
* productId.
|
||||
*/
|
||||
public class ProductMixNotFoundException extends AbstractPlatformResourceNotFoundException {
|
||||
|
||||
public ProductMixNotFoundException(final Long productId) {
|
||||
super("error.msg.no.product.mixes.exists", "No product mixes are defined with the productId `" + productId + "`.", productId);
|
||||
}
|
||||
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package org.mifosplatform.portfolio.loanproduct.productmix.handler;
|
||||
|
||||
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.portfolio.loanproduct.productmix.service.ProductMixWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class CreateProductMixCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final ProductMixWritePlatformService productMixWritePlatformService;
|
||||
|
||||
@Autowired
|
||||
public CreateProductMixCommandHandler(final ProductMixWritePlatformService productMixWritePlatformService) {
|
||||
|
||||
this.productMixWritePlatformService = productMixWritePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
|
||||
return this.productMixWritePlatformService.createProductMix(command.getProductId(), command);
|
||||
}
|
||||
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package org.mifosplatform.portfolio.loanproduct.productmix.handler;
|
||||
|
||||
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.portfolio.loanproduct.productmix.service.ProductMixWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class DeleteProductMixCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final ProductMixWritePlatformService productMixWritePlatformService;
|
||||
|
||||
@Autowired
|
||||
public DeleteProductMixCommandHandler(final ProductMixWritePlatformService productMixWritePlatformService) {
|
||||
|
||||
this.productMixWritePlatformService = productMixWritePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
|
||||
return this.productMixWritePlatformService.deleteProductMix(command.getProductId());
|
||||
}
|
||||
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package org.mifosplatform.portfolio.loanproduct.productmix.handler;
|
||||
|
||||
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.portfolio.loanproduct.productmix.service.ProductMixWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class UpdateProductMixCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final ProductMixWritePlatformService productMixWritePlatformService;
|
||||
|
||||
@Autowired
|
||||
public UpdateProductMixCommandHandler(final ProductMixWritePlatformService productMixWritePlatformService) {
|
||||
|
||||
this.productMixWritePlatformService = productMixWritePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
|
||||
return this.productMixWritePlatformService.updateProductMix(command.getProductId(), command);
|
||||
}
|
||||
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
package org.mifosplatform.portfolio.loanproduct.productmix.serialization;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
@Component
|
||||
public final class ProductMixDataValidator {
|
||||
|
||||
/**
|
||||
* The parameters supported for this command.
|
||||
*/
|
||||
private final Set<String> supportedParameters = new HashSet<String>(Arrays.asList("restrictedProducts"));
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
|
||||
@Autowired
|
||||
public ProductMixDataValidator(final FromJsonHelper fromApiJsonHelper) {
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
}
|
||||
|
||||
public void validateForCreate(final String json) {
|
||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, this.supportedParameters);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("productmix");
|
||||
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(json);
|
||||
|
||||
final String[] restrictedProducts = this.fromApiJsonHelper.extractArrayNamed("restrictedProducts", element);
|
||||
baseDataValidator.reset().parameter("restrictedProducts").value(restrictedProducts).arrayNotEmpty();
|
||||
if (restrictedProducts != null) {
|
||||
validateRestrictedProducts(restrictedProducts, baseDataValidator);
|
||||
}
|
||||
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
private void validateRestrictedProducts(final String[] restrictedProducts, final DataValidatorBuilder baseDataValidator) {
|
||||
for (final String restrictedId : restrictedProducts) {
|
||||
baseDataValidator.reset().parameter("restrictedProduct").value(restrictedId).notBlank().longGreaterThanZero();
|
||||
}
|
||||
}
|
||||
|
||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
|
||||
"Validation errors exist.", dataValidationErrors); }
|
||||
}
|
||||
|
||||
public void validateForUpdate(String json) {
|
||||
|
||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, this.supportedParameters);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("productmix");
|
||||
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(json);
|
||||
final String[] restrictedProducts = this.fromApiJsonHelper.extractArrayNamed("restrictedProducts", element);
|
||||
validateRestrictedProducts(restrictedProducts, baseDataValidator);
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package org.mifosplatform.portfolio.loanproduct.productmix.service;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.mifosplatform.portfolio.loanproduct.productmix.data.ProductMixData;
|
||||
|
||||
|
||||
public interface ProductMixReadPlatformService {
|
||||
|
||||
ProductMixData retrieveLoanProductMixDetails(Long productId);
|
||||
|
||||
Collection<ProductMixData> retrieveAllProductMixes();
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
package org.mifosplatform.portfolio.loanproduct.productmix.service;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
|
||||
import org.mifosplatform.portfolio.loanproduct.productmix.data.ProductMixData;
|
||||
import org.mifosplatform.portfolio.loanproduct.productmix.exception.ProductMixNotFoundException;
|
||||
import org.mifosplatform.portfolio.loanproduct.service.LoanProductReadPlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.ResultSetExtractor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class ProductMixReadPlatformServiceImpl implements ProductMixReadPlatformService {
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
private final LoanProductReadPlatformService loanProductReadPlatformService;
|
||||
|
||||
@Autowired
|
||||
public ProductMixReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource,
|
||||
final LoanProductReadPlatformService loanProductReadPlatformService) {
|
||||
this.context = context;
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
this.loanProductReadPlatformService = loanProductReadPlatformService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProductMixData retrieveLoanProductMixDetails(final Long productId) {
|
||||
try {
|
||||
|
||||
this.context.authenticatedUser();
|
||||
|
||||
final ProductMixDataExtractor extractor = new ProductMixDataExtractor(this.loanProductReadPlatformService, productId);
|
||||
|
||||
final String sql = "Select " + extractor.schema() + " where pm.product_id=? group by pm.product_id";
|
||||
|
||||
final Map<Long, ProductMixData> productMixData = this.jdbcTemplate.query(sql, extractor, new Object[] { productId });
|
||||
|
||||
return productMixData.get(productId);
|
||||
|
||||
} catch (final EmptyResultDataAccessException e) {
|
||||
throw new ProductMixNotFoundException(productId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ProductMixData> retrieveAllProductMixes() {
|
||||
|
||||
this.context.authenticatedUser();
|
||||
|
||||
final ProductMixDataExtractor extractor = new ProductMixDataExtractor(this.loanProductReadPlatformService, null);
|
||||
|
||||
final String sql = "Select " + extractor.schema() + " group by pm.product_id";
|
||||
|
||||
final Map<Long, ProductMixData> productMixData = this.jdbcTemplate.query(sql, extractor, new Object[] {});
|
||||
|
||||
return productMixData.values();
|
||||
}
|
||||
|
||||
private static final class ProductMixDataExtractor implements ResultSetExtractor<Map<Long, ProductMixData>> {
|
||||
|
||||
private final LoanProductReadPlatformService loanProductReadPlatformService;
|
||||
private final Long productId;
|
||||
|
||||
public String schema() {
|
||||
return "pm.product_id as productId, lp.name as name from m_product_mix pm join m_product_loan lp on lp.id=pm.product_id";
|
||||
}
|
||||
|
||||
public ProductMixDataExtractor(final LoanProductReadPlatformService loanProductReadPlatformService, final Long productId) {
|
||||
this.loanProductReadPlatformService = loanProductReadPlatformService;
|
||||
this.productId = productId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Long, ProductMixData> extractData(final ResultSet rs) throws SQLException, DataAccessException {
|
||||
final Map<Long, ProductMixData> extractedData = new HashMap<Long, ProductMixData>();
|
||||
|
||||
if (!rs.next()) {
|
||||
final Collection<LoanProductData> restrictedProducts = this.loanProductReadPlatformService.retrieveRestrictedProductsForMix(this.productId);
|
||||
final Collection<LoanProductData> allowedProducts = this.loanProductReadPlatformService.retrieveAllowedProductsForMix(this.productId);
|
||||
ProductMixData productMixData = ProductMixData.withRestrictedOptions(restrictedProducts, allowedProducts);
|
||||
extractedData.put(this.productId, productMixData);
|
||||
return extractedData;
|
||||
}
|
||||
/* move the cursor to starting of resultset */
|
||||
rs.beforeFirst();
|
||||
while (rs.next()) {
|
||||
final Long productId = rs.getLong("productId");
|
||||
final String name = rs.getString("name");
|
||||
final Collection<LoanProductData> restrictedProducts = this.loanProductReadPlatformService.retrieveRestrictedProductsForMix(productId);
|
||||
final Collection<LoanProductData> allowedProducts = this.loanProductReadPlatformService.retrieveAllowedProductsForMix(productId);
|
||||
final ProductMixData productMixData = ProductMixData.withDetails(productId, name, restrictedProducts, allowedProducts);
|
||||
extractedData.put(productId, productMixData);
|
||||
}
|
||||
return extractedData;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package org.mifosplatform.portfolio.loanproduct.productmix.service;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
|
||||
public interface ProductMixWritePlatformService {
|
||||
|
||||
CommandProcessingResult createProductMix(Long productId, JsonCommand command);
|
||||
|
||||
CommandProcessingResult updateProductMix(Long productId, JsonCommand command);
|
||||
|
||||
CommandProcessingResult deleteProductMix(Long productId);
|
||||
|
||||
}
|
||||
+225
@@ -0,0 +1,225 @@
|
||||
package org.mifosplatform.portfolio.loanproduct.productmix.service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository;
|
||||
import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundException;
|
||||
import org.mifosplatform.portfolio.loanproduct.productmix.domain.ProductMix;
|
||||
import org.mifosplatform.portfolio.loanproduct.productmix.domain.ProductMixRepository;
|
||||
import org.mifosplatform.portfolio.loanproduct.productmix.exception.ProductMixNotFoundException;
|
||||
import org.mifosplatform.portfolio.loanproduct.productmix.serialization.ProductMixDataValidator;
|
||||
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;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
@Service
|
||||
public class ProductMixWritePlatformServiceJpaRepositoryImpl implements ProductMixWritePlatformService {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(ProductMixWritePlatformServiceJpaRepositoryImpl.class);
|
||||
private final PlatformSecurityContext context;
|
||||
private final ProductMixDataValidator fromApiJsonDeserializer;
|
||||
private final ProductMixRepository productMixRepository;
|
||||
private final LoanProductRepository productRepository;
|
||||
|
||||
@Autowired
|
||||
public ProductMixWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
||||
final ProductMixDataValidator fromApiJsonDeserializer, final ProductMixRepository productMixRepository,
|
||||
final LoanProductRepository productRepository) {
|
||||
this.context = context;
|
||||
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
||||
this.productMixRepository = productMixRepository;
|
||||
this.productRepository = productRepository;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult createProductMix(final Long productId, final JsonCommand command) {
|
||||
|
||||
try {
|
||||
|
||||
this.context.authenticatedUser();
|
||||
|
||||
this.fromApiJsonDeserializer.validateForCreate(command.json());
|
||||
|
||||
final Set<String> restrictedIds = new HashSet<String>(Arrays.asList(command.arrayValueOfParameterNamed("restrictedProducts")));
|
||||
|
||||
// remove the existed restriction if it is not exists in restrictedIds.
|
||||
final List<Long> removedRestrictions = updateRestrictionsForProduct(productId, restrictedIds);
|
||||
final Map<Long, LoanProduct> restrictedProductsAsMap = getRestrictedProducts(restrictedIds);
|
||||
final List<ProductMix> productMixes = new ArrayList<ProductMix>();
|
||||
|
||||
createNewProductMix(restrictedProductsAsMap, productId, productMixes);
|
||||
|
||||
this.productMixRepository.save(productMixes);
|
||||
|
||||
final Map<String, Object> changes = new LinkedHashMap<String, Object>();
|
||||
changes.put("restrictedProductsForMix", restrictedProductsAsMap.keySet());
|
||||
changes.put("removedProductsForMix", removedRestrictions);
|
||||
return new CommandProcessingResultBuilder().withProductId(productId).with(changes).withCommandId(command.commandId()).build();
|
||||
} catch (final DataIntegrityViolationException dve) {
|
||||
|
||||
handleDataIntegrityIssues(dve);
|
||||
return CommandProcessingResult.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private List<Long> updateRestrictionsForProduct(final Long productId, final Set<String> restrictedIds) {
|
||||
|
||||
final List<Long> removedRestrictions = new ArrayList<Long>();
|
||||
final List<ProductMix> mixesToRemove = new ArrayList<ProductMix>();
|
||||
|
||||
final List<ProductMix> existedProductMixes = this.productMixRepository.findRestrictedProducts(productId);
|
||||
for (final ProductMix productMix : existedProductMixes) {
|
||||
if (!restrictedIds.contains(productMix.getProductId().toString())) {
|
||||
mixesToRemove.add(productMix);
|
||||
removedRestrictions.add(productMix.getId());
|
||||
}
|
||||
}
|
||||
if (!CollectionUtils.isEmpty(mixesToRemove)) {
|
||||
this.productMixRepository.delete(mixesToRemove);
|
||||
}
|
||||
return removedRestrictions;
|
||||
}
|
||||
|
||||
private void createNewProductMix(final Map<Long, LoanProduct> restrictedProductsAsMap, final Long productId,
|
||||
final List<ProductMix> productMixes) {
|
||||
|
||||
final LoanProduct productMixInstance = findByProductIdIfProvided(productId);
|
||||
for (final LoanProduct restrictedProduct : restrictedProductsAsMap.values()) {
|
||||
final ProductMix productMix = ProductMix.createNew(productMixInstance, restrictedProduct);
|
||||
productMixes.add(productMix);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult updateProductMix(final Long productId, final JsonCommand command) {
|
||||
|
||||
try {
|
||||
this.context.authenticatedUser();
|
||||
this.fromApiJsonDeserializer.validateForUpdate(command.json());
|
||||
final Map<String, Object> changes = new LinkedHashMap<String, Object>();
|
||||
|
||||
final List<ProductMix> existedProductMixes = this.productMixRepository.findByProductId(productId);
|
||||
if (CollectionUtils.isEmpty(existedProductMixes)) { throw new ProductMixNotFoundException(productId); }
|
||||
final Set<String> restrictedIds = new HashSet<String>(Arrays.asList(command.arrayValueOfParameterNamed("restrictedProducts")));
|
||||
|
||||
// updating with empty array means deleting the existed records.
|
||||
if (restrictedIds.isEmpty()) {
|
||||
final List<Long> removedRestrictedProductIds = this.productMixRepository.findRestrictedProductIdsByProductId(productId);
|
||||
this.productMixRepository.delete(existedProductMixes);
|
||||
changes.put("removedProductsForMix", removedRestrictedProductIds);
|
||||
return new CommandProcessingResultBuilder().with(changes).withProductId(productId).withCommandId(command.commandId())
|
||||
.build();
|
||||
}
|
||||
|
||||
/*
|
||||
* if restrictedProducts array is not empty delete the duplicate ids
|
||||
* which are already exists and update existedProductMixes
|
||||
*/
|
||||
final List<ProductMix> productMixesToRemove = updateRestrictedIds(restrictedIds, existedProductMixes);
|
||||
final Map<Long, LoanProduct> restrictedProductsAsMap = getRestrictedProducts(restrictedIds);
|
||||
createNewProductMix(restrictedProductsAsMap, productId, existedProductMixes);
|
||||
|
||||
this.productMixRepository.save(existedProductMixes);
|
||||
changes.put("restrictedProductsForMix", getProductIdsFromCollection(existedProductMixes));
|
||||
|
||||
if (!CollectionUtils.isEmpty(productMixesToRemove)) {
|
||||
this.productMixRepository.delete(productMixesToRemove);
|
||||
changes.put("removedProductsForMix", getProductIdsFromCollection(productMixesToRemove));
|
||||
}
|
||||
return new CommandProcessingResultBuilder().with(changes).withProductId(productId).withCommandId(command.commandId()).build();
|
||||
} catch (final DataIntegrityViolationException dve) {
|
||||
|
||||
handleDataIntegrityIssues(dve);
|
||||
return CommandProcessingResult.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private LoanProduct findByProductIdIfProvided(final Long productId) {
|
||||
|
||||
final LoanProduct product = this.productRepository.findOne(productId);
|
||||
if (product == null) { throw new LoanProductNotFoundException(productId); }
|
||||
return product;
|
||||
}
|
||||
|
||||
private Map<Long, LoanProduct> getRestrictedProducts(final Set<String> restrictedIds) {
|
||||
|
||||
final Map<Long, LoanProduct> restricrtedProducts = new HashMap<Long, LoanProduct>();
|
||||
|
||||
for (final String restrictedId : restrictedIds) {
|
||||
final Long restrictedIdAsLong = Long.valueOf(restrictedId);
|
||||
final LoanProduct restrictedProduct = findByProductIdIfProvided(Long.valueOf(restrictedId));
|
||||
restricrtedProducts.put(restrictedIdAsLong, restrictedProduct);
|
||||
}
|
||||
return restricrtedProducts;
|
||||
}
|
||||
|
||||
private void handleDataIntegrityIssues(final DataIntegrityViolationException dve) {
|
||||
logAsErrorUnexpectedDataIntegrityException(dve);
|
||||
throw new PlatformDataIntegrityException("error.msg.product.loan.unknown.data.integrity.issue",
|
||||
"Unknown data integrity issue with resource.");
|
||||
}
|
||||
|
||||
private void logAsErrorUnexpectedDataIntegrityException(final DataIntegrityViolationException dve) {
|
||||
logger.error(dve.getMessage(), dve);
|
||||
}
|
||||
|
||||
private List<ProductMix> updateRestrictedIds(final Set<String> restrictedIds, final List<ProductMix> existedProductMixes) {
|
||||
|
||||
final List<ProductMix> productMixesToRemove = new ArrayList<ProductMix>();
|
||||
for (final ProductMix productMix : existedProductMixes) {
|
||||
final String currentMixId = productMix.getRestrictedProductId().toString();
|
||||
if (restrictedIds.contains(currentMixId)) {
|
||||
restrictedIds.remove(currentMixId);
|
||||
} else {
|
||||
productMixesToRemove.add(productMix);
|
||||
}
|
||||
}
|
||||
existedProductMixes.removeAll(productMixesToRemove);
|
||||
return productMixesToRemove;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult deleteProductMix(final Long productId) {
|
||||
try {
|
||||
this.context.authenticatedUser();
|
||||
final Map<String, Object> changes = new LinkedHashMap<String, Object>();
|
||||
|
||||
final List<ProductMix> existedProductMixes = this.productMixRepository.findByProductId(productId);
|
||||
if (CollectionUtils.isEmpty(existedProductMixes)) { throw new ProductMixNotFoundException(productId); }
|
||||
this.productMixRepository.delete(existedProductMixes);
|
||||
changes.put("removedProductsForMix", getProductIdsFromCollection(existedProductMixes));
|
||||
return new CommandProcessingResultBuilder().with(changes).withProductId(productId).build();
|
||||
} catch (final DataIntegrityViolationException dve) {
|
||||
|
||||
handleDataIntegrityIssues(dve);
|
||||
return CommandProcessingResult.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private List<Long> getProductIdsFromCollection(final List<ProductMix> collection) {
|
||||
final List<Long> productIds = new ArrayList<Long>();
|
||||
for (ProductMix productMix : collection) {
|
||||
productIds.add(productMix.getRestrictedProductId());
|
||||
}
|
||||
return productIds;
|
||||
}
|
||||
|
||||
}
|
||||
+6
@@ -18,4 +18,10 @@ public interface LoanProductReadPlatformService {
|
||||
LoanProductData retrieveLoanProduct(Long productId);
|
||||
|
||||
LoanProductData retrieveNewLoanProductDetails();
|
||||
|
||||
Collection<LoanProductData> retrieveAvailableLoanProductsForMix();
|
||||
|
||||
Collection<LoanProductData> retrieveRestrictedProductsForMix(Long productId);
|
||||
|
||||
Collection<LoanProductData> retrieveAllowedProductsForMix(Long productId);
|
||||
}
|
||||
+53
@@ -197,6 +197,19 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
||||
return "lp.id as id, lp.name as name from m_product_loan lp";
|
||||
}
|
||||
|
||||
public String productMixSchema() {
|
||||
return "lp.id as id, lp.name as name FROM m_product_loan lp left join m_product_mix pm on pm.product_id=lp.id where lp.id not IN("
|
||||
+ "select lp.id from m_product_loan lp inner join m_product_mix pm on pm.product_id=lp.id)";
|
||||
}
|
||||
|
||||
public String restrictedProductsSchema() {
|
||||
return "pm.restricted_product_id as id, rp.name as name from m_product_mix pm join m_product_loan rp on rp.id = pm.restricted_product_id ";
|
||||
}
|
||||
|
||||
public String derivedRestrictedProductsSchema() {
|
||||
return "pm.product_id as id, lp.name as name from m_product_mix pm join m_product_loan lp on lp.id=pm.product_id";
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoanProductData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||
|
||||
@@ -206,4 +219,44 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
||||
return LoanProductData.lookup(id, name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<LoanProductData> retrieveAvailableLoanProductsForMix() {
|
||||
|
||||
this.context.authenticatedUser();
|
||||
|
||||
final LoanProductLookupMapper rm = new LoanProductLookupMapper();
|
||||
|
||||
final String sql = "Select " + rm.productMixSchema();
|
||||
|
||||
return this.jdbcTemplate.query(sql, rm, new Object[] {});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<LoanProductData> retrieveRestrictedProductsForMix(final Long productId) {
|
||||
|
||||
this.context.authenticatedUser();
|
||||
|
||||
final LoanProductLookupMapper rm = new LoanProductLookupMapper();
|
||||
|
||||
final String sql = "Select " + rm.restrictedProductsSchema() + " where pm.product_id=? UNION Select "
|
||||
+ rm.derivedRestrictedProductsSchema() + " where pm.restricted_product_id=?";
|
||||
|
||||
return this.jdbcTemplate.query(sql, rm, new Object[] { productId, productId });
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<LoanProductData> retrieveAllowedProductsForMix(final Long productId) {
|
||||
|
||||
this.context.authenticatedUser();
|
||||
|
||||
final LoanProductLookupMapper rm = new LoanProductLookupMapper();
|
||||
|
||||
final String sql = "Select " + rm.schema() + " where lp.id not in ("
|
||||
+ "Select pm.restricted_product_id from m_product_mix pm where pm.product_id=? " + "UNION "
|
||||
+ "Select pm.product_id from m_product_mix pm where pm.restricted_product_id=?)";
|
||||
|
||||
return this.jdbcTemplate.query(sql, rm, new Object[] { productId, productId });
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user