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_update">Update a Charge</a></td>
|
||||||
<td><a href="#charges_delete">Delete a Charge</a></td>
|
<td><a href="#charges_delete">Delete a Charge</a></td>
|
||||||
</tr>
|
</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>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1403,6 +1419,10 @@
|
|||||||
<td>loanproducts/template</td>
|
<td>loanproducts/template</td>
|
||||||
<td><a href="#loanproducts_template">Retrieve Loan Product Template</a></td>
|
<td><a href="#loanproducts_template">Retrieve Loan Product Template</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr >
|
||||||
|
<td>loanproducts/template?isProductMixTemplate=true</td>
|
||||||
|
<td><a href="#loanproductmix_template">Retrieve Loan Product Mix Template</a></td>
|
||||||
|
</tr>
|
||||||
<tr class="alt">
|
<tr class="alt">
|
||||||
<td>loans/template?clientId={clientId}</td>
|
<td>loans/template?clientId={clientId}</td>
|
||||||
<td><a href="#loans_template">Retrieve Loan Template</a></td>
|
<td><a href="#loans_template">Retrieve Loan Template</a></td>
|
||||||
@@ -8043,6 +8063,355 @@ Request Body:
|
|||||||
</div>
|
</div>
|
||||||
<!-- end of loan products api docs -->
|
<!-- 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 -->
|
<!-- start of configurations api docs -->
|
||||||
<a id="configs" name="configs" class="old-syle-anchor"> </a>
|
<a id="configs" name="configs" class="old-syle-anchor"> </a>
|
||||||
<div class="method-section">
|
<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><a href="#loanproducts_update">Update a Loan Product</a></td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</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>
|
<tr>
|
||||||
<td><a href="#loans">Loans</a></td>
|
<td><a href="#loans">Loans</a></td>
|
||||||
<td>loans?calculateLoanSchedule</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
@@ -86,6 +86,9 @@ public class CommandSource extends AbstractPersistable<Long> {
|
|||||||
@Column(name = "processing_result_enum", nullable = false)
|
@Column(name = "processing_result_enum", nullable = false)
|
||||||
private Integer processingResult;
|
private Integer processingResult;
|
||||||
|
|
||||||
|
@Column(name = "product_id")
|
||||||
|
private Long productId;
|
||||||
|
|
||||||
public static CommandSource fullEntryFrom(final CommandWrapper wrapper, final JsonCommand command, final AppUser maker) {
|
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(),
|
return new CommandSource(wrapper.actionName(), wrapper.entityName(), wrapper.getHref(), command.entityId(), command.subentityId(),
|
||||||
command.json(), maker, DateTime.now());
|
command.json(), maker, DateTime.now());
|
||||||
@@ -172,15 +175,21 @@ public class CommandSource extends AbstractPersistable<Long> {
|
|||||||
return false;
|
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.officeId = officeId;
|
||||||
this.groupId = groupId;
|
this.groupId = groupId;
|
||||||
this.clientId = clientId;
|
this.clientId = clientId;
|
||||||
this.loanId = loanId;
|
this.loanId = loanId;
|
||||||
this.savingsId = savingsId;
|
this.savingsId = savingsId;
|
||||||
|
this.productId = productId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getResourceGetUrl() {
|
public String getResourceGetUrl() {
|
||||||
return this.resourceGetUrl;
|
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 transactionId;
|
||||||
private final String supportedEntityType;
|
private final String supportedEntityType;
|
||||||
private final Long supportedEntityId;
|
private final Long supportedEntityId;
|
||||||
|
private final Long productId;
|
||||||
|
|
||||||
public static CommandWrapper wrap(final String actionName, final String entityName, final Long resourceId, final Long subresourceId) {
|
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,
|
public static CommandWrapper fromExistingCommand(final Long commandId, final String actionName, final String entityName,
|
||||||
final Long resourceId, final Long subresourceId, final String resourceGetUrl) {
|
final Long resourceId, final Long subresourceId, final String resourceGetUrl, final Long productId) {
|
||||||
return new CommandWrapper(commandId, actionName, entityName, resourceId, subresourceId, resourceGetUrl);
|
return new CommandWrapper(commandId, actionName, entityName, resourceId, subresourceId, resourceGetUrl, productId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CommandWrapper(final Long commandId, final String actionName, final String entityName, final Long resourceId,
|
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.commandId = commandId;
|
||||||
this.officeId = null;
|
this.officeId = null;
|
||||||
this.groupId = null;
|
this.groupId = null;
|
||||||
@@ -54,12 +55,14 @@ public class CommandWrapper {
|
|||||||
this.href = resourceGetUrl;
|
this.href = resourceGetUrl;
|
||||||
this.json = null;
|
this.json = null;
|
||||||
this.transactionId = null;
|
this.transactionId = null;
|
||||||
|
this.productId = productId;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CommandWrapper(final Long officeId, final Long groupId, final Long clientId, final Long loanId, final Long savingsId,
|
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 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.commandId = null;
|
||||||
this.officeId = officeId;
|
this.officeId = officeId;
|
||||||
this.groupId = groupId;
|
this.groupId = groupId;
|
||||||
@@ -77,7 +80,7 @@ public class CommandWrapper {
|
|||||||
this.href = href;
|
this.href = href;
|
||||||
this.json = json;
|
this.json = json;
|
||||||
this.transactionId = transactionId;
|
this.transactionId = transactionId;
|
||||||
|
this.productId = productId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long commandId() {
|
public Long commandId() {
|
||||||
@@ -176,6 +179,10 @@ public class CommandWrapper {
|
|||||||
return this.supportedEntityType;
|
return this.supportedEntityType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getProductId() {
|
||||||
|
return this.productId;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isUpdate() {
|
public boolean isUpdate() {
|
||||||
// permissions resource has special update which involves no resource.
|
// permissions resource has special update which involves no resource.
|
||||||
return (isPermissionResource() && isUpdateOperation()) || (isCurrencyResource() && isUpdateOperation())
|
return (isPermissionResource() && isUpdateOperation()) || (isCurrencyResource() && isUpdateOperation())
|
||||||
@@ -190,7 +197,7 @@ public class CommandWrapper {
|
|||||||
return isDeleteOperation() && this.entityId != null;
|
return isDeleteOperation() && this.entityId != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isDeleteOperation() {
|
public boolean isDeleteOperation() {
|
||||||
return this.actionName.equalsIgnoreCase("DELETE");
|
return this.actionName.equalsIgnoreCase("DELETE");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -540,4 +547,8 @@ public class CommandWrapper {
|
|||||||
public boolean isClientClose() {
|
public boolean isClientClose() {
|
||||||
return this.actionName.equalsIgnoreCase("CLOSE") && this.entityName.equalsIgnoreCase("CLIENT");
|
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 transactionId;
|
||||||
private String supportedEntityType;
|
private String supportedEntityType;
|
||||||
private Long supportedEntityId;
|
private Long supportedEntityId;
|
||||||
|
private Long productId;
|
||||||
|
|
||||||
public CommandWrapper build() {
|
public CommandWrapper build() {
|
||||||
return new CommandWrapper(this.officeId, this.groupId, this.clientId, this.loanId, this.savingsId, this.actionName,
|
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.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) {
|
public CommandWrapperBuilder withLoanId(final Long withLoanId) {
|
||||||
@@ -1127,4 +1128,36 @@ public class CommandWrapperBuilder {
|
|||||||
this.href = "/clients/" + clientId + "?command=assignStaff";
|
this.href = "/clients/" + clientId + "?command=assignStaff";
|
||||||
return this;
|
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(),
|
final JsonCommand command = JsonCommand.from(json, parsedCommand, this.fromApiJsonHelper, wrapper.getEntityName(),
|
||||||
wrapper.getEntityId(), wrapper.getSubentityId(), wrapper.getGroupId(), wrapper.getClientId(), wrapper.getLoanId(),
|
wrapper.getEntityId(), wrapper.getSubentityId(), wrapper.getGroupId(), wrapper.getClientId(), wrapper.getLoanId(),
|
||||||
wrapper.getSavingsId(), wrapper.getCodeId(), wrapper.getSupportedEntityType(), wrapper.getSupportedEntityId(),
|
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);
|
result = this.processAndLogCommandService.processAndLogCommand(wrapper, command, isApprovedByChecker);
|
||||||
} catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) {
|
} catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) {
|
||||||
@@ -81,12 +81,12 @@ public class PortfolioCommandSourceWritePlatformServiceImpl implements Portfolio
|
|||||||
|
|
||||||
final CommandWrapper wrapper = CommandWrapper.fromExistingCommand(makerCheckerId, commandSourceInput.getActionName(),
|
final CommandWrapper wrapper = CommandWrapper.fromExistingCommand(makerCheckerId, commandSourceInput.getActionName(),
|
||||||
commandSourceInput.getEntityName(), commandSourceInput.resourceId(), commandSourceInput.subresourceId(),
|
commandSourceInput.getEntityName(), commandSourceInput.resourceId(), commandSourceInput.subresourceId(),
|
||||||
commandSourceInput.getResourceGetUrl());
|
commandSourceInput.getResourceGetUrl(), commandSourceInput.getProductId());
|
||||||
|
|
||||||
final JsonElement parsedCommand = this.fromApiJsonHelper.parse(commandSourceInput.json());
|
final JsonElement parsedCommand = this.fromApiJsonHelper.parse(commandSourceInput.json());
|
||||||
final JsonCommand command = JsonCommand.fromExistingCommand(makerCheckerId, commandSourceInput.json(), parsedCommand,
|
final JsonCommand command = JsonCommand.fromExistingCommand(makerCheckerId, commandSourceInput.json(), parsedCommand,
|
||||||
this.fromApiJsonHelper, commandSourceInput.getEntityName(), commandSourceInput.resourceId(),
|
this.fromApiJsonHelper, commandSourceInput.getEntityName(), commandSourceInput.resourceId(),
|
||||||
commandSourceInput.subresourceId(), commandSourceInput.getResourceGetUrl());
|
commandSourceInput.subresourceId(), commandSourceInput.getResourceGetUrl(), commandSourceInput.getProductId());
|
||||||
|
|
||||||
final boolean makerCheckerApproval = true;
|
final boolean makerCheckerApproval = true;
|
||||||
return this.processAndLogCommandService.processAndLogCommand(wrapper, command, makerCheckerApproval);
|
return this.processAndLogCommandService.processAndLogCommand(wrapper, command, makerCheckerApproval);
|
||||||
|
|||||||
+11
-1
@@ -70,7 +70,7 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
|
|||||||
}
|
}
|
||||||
commandSourceResult.updateResourceId(result.resourceId());
|
commandSourceResult.updateResourceId(result.resourceId());
|
||||||
commandSourceResult.updateForAudit(result.getOfficeId(), result.getGroupId(), result.getClientId(), result.getLoanId(),
|
commandSourceResult.updateForAudit(result.getOfficeId(), result.getGroupId(), result.getClientId(), result.getLoanId(),
|
||||||
result.getSavingsId());
|
result.getSavingsId(), result.getProductId());
|
||||||
|
|
||||||
String changesOnlyJson = null;
|
String changesOnlyJson = null;
|
||||||
if (result.hasChanges()) {
|
if (result.hasChanges()) {
|
||||||
@@ -493,6 +493,16 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
|
|||||||
if (wrapper.isCreate()) {
|
if (wrapper.isCreate()) {
|
||||||
handler = this.applicationContext.getBean("createHolidayCommandHandler", NewCommandSourceHandler.class);
|
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 {
|
} else {
|
||||||
throw new UnsupportedCommandException(wrapper.commandName());
|
throw new UnsupportedCommandException(wrapper.commandName());
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-5
@@ -46,26 +46,27 @@ public final class JsonCommand {
|
|||||||
private final Long supportedEntityId;
|
private final Long supportedEntityId;
|
||||||
private final String transactionId;
|
private final String transactionId;
|
||||||
private final String url;
|
private final String url;
|
||||||
|
private final Long productId;
|
||||||
|
|
||||||
public static JsonCommand from(final String jsonCommand, final JsonElement parsedCommand, final FromJsonHelper fromApiJsonHelper,
|
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 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 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,
|
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,
|
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 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,
|
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,
|
public JsonCommand(final Long commandId, final String jsonCommand, final JsonElement parsedCommand,
|
||||||
final FromJsonHelper fromApiJsonHelper, final String entityName, final Long resourceId, final Long subresourceId,
|
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 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.commandId = commandId;
|
||||||
this.jsonCommand = jsonCommand;
|
this.jsonCommand = jsonCommand;
|
||||||
this.parsedCommand = parsedCommand;
|
this.parsedCommand = parsedCommand;
|
||||||
@@ -82,6 +83,7 @@ public final class JsonCommand {
|
|||||||
this.supportedEntityId = supportedEntityId;
|
this.supportedEntityId = supportedEntityId;
|
||||||
this.transactionId = transactionId;
|
this.transactionId = transactionId;
|
||||||
this.url = url;
|
this.url = url;
|
||||||
|
this.productId = productId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String json() {
|
public String json() {
|
||||||
@@ -153,6 +155,10 @@ public final class JsonCommand {
|
|||||||
return this.url;
|
return this.url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getProductId() {
|
||||||
|
return this.productId;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean differenceExists(final LocalDate baseValue, final LocalDate workingCopyValue) {
|
private boolean differenceExists(final LocalDate baseValue, final LocalDate workingCopyValue) {
|
||||||
boolean differenceExists = false;
|
boolean differenceExists = false;
|
||||||
|
|
||||||
|
|||||||
+11
-3
@@ -25,12 +25,13 @@ public class CommandProcessingResult {
|
|||||||
private final Map<String, Object> changes;
|
private final Map<String, Object> changes;
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private final String resourceIdentifier;
|
private final String resourceIdentifier;
|
||||||
|
private final Long productId;
|
||||||
|
|
||||||
public static CommandProcessingResult fromDetails(final Long commandId, final Long officeId, final Long groupId, final Long clientId,
|
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 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,
|
return new CommandProcessingResult(commandId, officeId, groupId, clientId, loanId, savingsId, resourceIdentifier, entityId,
|
||||||
transactionId, changes);
|
transactionId, changes, productId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CommandProcessingResult commandOnlyResult(final Long commandId) {
|
public static CommandProcessingResult commandOnlyResult(final Long commandId) {
|
||||||
@@ -79,11 +80,12 @@ public class CommandProcessingResult {
|
|||||||
this.savingsId = null;
|
this.savingsId = null;
|
||||||
this.transactionId = null;
|
this.transactionId = null;
|
||||||
this.changes = new HashMap<String, Object>();
|
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,
|
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 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.commandId = commandId;
|
||||||
this.officeId = officeId;
|
this.officeId = officeId;
|
||||||
this.groupId = groupId;
|
this.groupId = groupId;
|
||||||
@@ -94,6 +96,7 @@ public class CommandProcessingResult {
|
|||||||
this.resourceId = resourceId;
|
this.resourceId = resourceId;
|
||||||
this.changes = changesOnly;
|
this.changes = changesOnly;
|
||||||
this.transactionId = transactionId;
|
this.transactionId = transactionId;
|
||||||
|
this.productId = productId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CommandProcessingResult(final Long resourceId, final Long officeId, final Long commandId, final Map<String, Object> changesOnly) {
|
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.transactionId = null;
|
||||||
this.commandId = commandId;
|
this.commandId = commandId;
|
||||||
this.changes = changesOnly;
|
this.changes = changesOnly;
|
||||||
|
this.productId = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long commandId() {
|
public Long commandId() {
|
||||||
@@ -161,4 +165,8 @@ public class CommandProcessingResult {
|
|||||||
final boolean noChanges = this.changes == null || this.changes.isEmpty();
|
final boolean noChanges = this.changes == null || this.changes.isEmpty();
|
||||||
return !noChanges;
|
return !noChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getProductId() {
|
||||||
|
return this.productId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+7
-1
@@ -23,10 +23,11 @@ public class CommandProcessingResultBuilder {
|
|||||||
private Long entityId;
|
private Long entityId;
|
||||||
private String transactionId;
|
private String transactionId;
|
||||||
private Map<String, Object> changes;
|
private Map<String, Object> changes;
|
||||||
|
private Long productId;
|
||||||
|
|
||||||
public CommandProcessingResult build() {
|
public CommandProcessingResult build() {
|
||||||
return CommandProcessingResult.fromDetails(commandId, officeId, groupId, clientId, loanId, savingsId, resourceIdentifier, entityId,
|
return CommandProcessingResult.fromDetails(commandId, officeId, groupId, clientId, loanId, savingsId, resourceIdentifier, entityId,
|
||||||
transactionId, changes);
|
transactionId, changes, productId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CommandProcessingResultBuilder withCommandId(final Long withCommandId) {
|
public CommandProcessingResultBuilder withCommandId(final Long withCommandId) {
|
||||||
@@ -79,4 +80,9 @@ public class CommandProcessingResultBuilder {
|
|||||||
return this;
|
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.Path;
|
||||||
import javax.ws.rs.PathParam;
|
import javax.ws.rs.PathParam;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.QueryParam;
|
||||||
import javax.ws.rs.core.Context;
|
import javax.ws.rs.core.Context;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.UriInfo;
|
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.commands.service.PortfolioCommandSourceWritePlatformService;
|
||||||
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
|
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
|
||||||
import org.mifosplatform.infrastructure.codes.service.CodeValueReadPlatformService;
|
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.api.ApiRequestParameterHelper;
|
||||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
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.fund.service.FundReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
|
import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
|
||||||
import org.mifosplatform.portfolio.loanproduct.data.TransactionProcessingStrategyData;
|
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.LoanDropdownReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.loanproduct.service.LoanProductReadPlatformService;
|
import org.mifosplatform.portfolio.loanproduct.service.LoanProductReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.paymentdetail.PaymentDetailConstants;
|
import org.mifosplatform.portfolio.paymentdetail.PaymentDetailConstants;
|
||||||
@@ -70,6 +74,9 @@ public class LoanProductsApiResource {
|
|||||||
"interestTypeOptions", "interestCalculationPeriodTypeOptions", "transactionProcessingStrategyOptions", "chargeOptions",
|
"interestTypeOptions", "interestCalculationPeriodTypeOptions", "transactionProcessingStrategyOptions", "chargeOptions",
|
||||||
"accountingOptions", "accountingRuleOptions", "accountingMappingOptions"));
|
"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";
|
private final String resourceNameForPermissions = "LOANPRODUCT";
|
||||||
|
|
||||||
private final PlatformSecurityContext context;
|
private final PlatformSecurityContext context;
|
||||||
@@ -84,6 +91,8 @@ public class LoanProductsApiResource {
|
|||||||
private final ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService;
|
private final ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService;
|
||||||
private final CodeValueReadPlatformService codeValueReadPlatformService;
|
private final CodeValueReadPlatformService codeValueReadPlatformService;
|
||||||
private final AccountingDropdownReadPlatformService accountingDropdownReadPlatformService;
|
private final AccountingDropdownReadPlatformService accountingDropdownReadPlatformService;
|
||||||
|
private final DefaultToApiJsonSerializer<ProductMixData> productMixDataApiJsonSerializer;
|
||||||
|
private final ProductMixReadPlatformService productMixReadPlatformService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public LoanProductsApiResource(final PlatformSecurityContext context, final LoanProductReadPlatformService readPlatformService,
|
public LoanProductsApiResource(final PlatformSecurityContext context, final LoanProductReadPlatformService readPlatformService,
|
||||||
@@ -94,7 +103,9 @@ public class LoanProductsApiResource {
|
|||||||
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
|
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
|
||||||
final ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService,
|
final ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService,
|
||||||
final CodeValueReadPlatformService codeValueReadPlatformService,
|
final CodeValueReadPlatformService codeValueReadPlatformService,
|
||||||
final AccountingDropdownReadPlatformService accountingDropdownReadPlatformService) {
|
final AccountingDropdownReadPlatformService accountingDropdownReadPlatformService,
|
||||||
|
final DefaultToApiJsonSerializer<ProductMixData> productMixDataApiJsonSerializer,
|
||||||
|
final ProductMixReadPlatformService productMixReadPlatformService) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.loanProductReadPlatformService = readPlatformService;
|
this.loanProductReadPlatformService = readPlatformService;
|
||||||
this.chargeReadPlatformService = chargeReadPlatformService;
|
this.chargeReadPlatformService = chargeReadPlatformService;
|
||||||
@@ -107,6 +118,8 @@ public class LoanProductsApiResource {
|
|||||||
this.accountMappingReadPlatformService = accountMappingReadPlatformService;
|
this.accountMappingReadPlatformService = accountMappingReadPlatformService;
|
||||||
this.codeValueReadPlatformService = codeValueReadPlatformService;
|
this.codeValueReadPlatformService = codeValueReadPlatformService;
|
||||||
this.accountingDropdownReadPlatformService = accountingDropdownReadPlatformService;
|
this.accountingDropdownReadPlatformService = accountingDropdownReadPlatformService;
|
||||||
|
this.productMixDataApiJsonSerializer = productMixDataApiJsonSerializer;
|
||||||
|
this.productMixReadPlatformService = productMixReadPlatformService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
@@ -127,10 +140,19 @@ public class LoanProductsApiResource {
|
|||||||
public String retrieveAllLoanProducts(@Context final UriInfo uriInfo) {
|
public String retrieveAllLoanProducts(@Context final UriInfo uriInfo) {
|
||||||
|
|
||||||
context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions);
|
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 Collection<LoanProductData> products = this.loanProductReadPlatformService.retrieveAllLoanProducts();
|
||||||
|
|
||||||
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
|
||||||
return this.toApiJsonSerializer.serialize(settings, products, LOAN_PRODUCT_DATA_PARAMETERS);
|
return this.toApiJsonSerializer.serialize(settings, products, LOAN_PRODUCT_DATA_PARAMETERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,14 +160,22 @@ public class LoanProductsApiResource {
|
|||||||
@Path("template")
|
@Path("template")
|
||||||
@Consumes({ MediaType.APPLICATION_JSON })
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
@Produces({ 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);
|
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();
|
LoanProductData loanProduct = this.loanProductReadPlatformService.retrieveNewLoanProductDetails();
|
||||||
loanProduct = handleTemplate(loanProduct);
|
loanProduct = handleTemplate(loanProduct);
|
||||||
|
|
||||||
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
|
||||||
return this.toApiJsonSerializer.serialize(settings, loanProduct, LOAN_PRODUCT_DATA_PARAMETERS);
|
return this.toApiJsonSerializer.serialize(settings, loanProduct, LOAN_PRODUCT_DATA_PARAMETERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,4 +267,5 @@ public class LoanProductsApiResource {
|
|||||||
interestRateFrequencyTypeOptions, fundOptions, transactionProcessingStrategyOptions, accountOptions,
|
interestRateFrequencyTypeOptions, fundOptions, transactionProcessingStrategyOptions, accountOptions,
|
||||||
accountingRuleTypeOptions);
|
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 retrieveLoanProduct(Long productId);
|
||||||
|
|
||||||
LoanProductData retrieveNewLoanProductDetails();
|
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";
|
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
|
@Override
|
||||||
public LoanProductData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
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);
|
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