# Group Policy

## Business Scenario

To understand the basic design of group policy, user can first refer to [Policy API Overview - Group Policy section](https://docs.insuremo.com/gi_insurance_service/policy_api#group-policy) about the overall comparison between different policy types.

The key of group policy is that group and member information must be issued together as single transaction and shared with single policy number. 

In some scenarios, although a client call a group policy, they actually issue group and member policies separately with separate policy number. In our concept, it will be achieved by master policy structure instead of group.

## Typical Characteristics & Benefits

In summary, there are several characteristics of group policy as below:

1. Big number of Insureds -> Concurrent Running

The most obvious characteristics of group policy are the large number of insureds each policy might process. To ensure the smooth management of such a substantial number of insureds, the system needs to have separate running threads for each risk, enabling concurrent operation to improve processing speed.

It does not only mean isolation between each risk, but also isolation of risk operation from policy-level operation. Thus, each time the system processes a group of policies. All transaction APIs are designed based on each risk, and there will be separate APIs to accumulate risk information into the higher policy level.

Such isolation process can be also called detach process for risk or schedule which is to detach risk or schedule from standard policy object. This enables partial, separate, and concurrent persistence operations.


2. Long Waiting Time -> Asynchronous Process

For group policies, usually, the operation duration is much longer than that of an individual policy due to the large number of insureds. To ensure that such long-running processes do not trigger system timeouts, most operations must be asynchronous rather than synchronous.

Now the best way to achieve asynchronous process for group policy is to leverage our batch engine and most of the interface we expose to group policy will directly trigger batch to run.

3. Big number of information to capture -> Excel Upload

From a user's prospective, group policy not only implies a long processing cycle, but also means that the information to capture will be huge and time-consuming if all the risks are added via UI. Therefore, almost all users will prefer to use Excel to upload such a large number of Insureds and take UI just for slight modification instead of massive level entry.

Now we offer upload capability for all our data capture-related APIs. Moreover, as different users may prefer different Excel format templates for upload, the system, by leveraging our platform upload framework, enables users to configure such user-oriented Excel templates for API usage.


## Group Insured Risk

Group insured risk mostly refers to those policies that have a large number of insureds (usually more than 100), with each insured risk having its own coverage/benefit and premium calculation. Some typical group policy can be applicable to products like motor fleet, group personal accident/health/travel.

</div> note:

To facilitate users to understand how group risk policy API is called and product is configured in a real business scenario, all below documentation are used below product as example:

* Technical Product Code: `RG_TECH`
* Market Product Code: `RG001`

</div>


### Concept of Insured Group 

"Insured Group" also named as "Coverage Group" is a very important concept for group policy. In real business world, suppose we have a large number of risks, for example 1,000 insureds, there can be two scenarios:

* Scenario 1: Each Insured has different coverage & SI combinations

In this case, there's no need to have insured group and each coverage must have one set of coverage to persist.

* Scenario 2: Some Insured has same coverage & SI combinations and these combinations can be arranged

In this case, these coverage & SI combinations can be treated as different insured group and persist in the insured group level rather than under each individual risk.

It will bring a super performance benefit. For example, if we have 1,000 insured, 500 with comprehensive 1 mil SI and another 500 with Third party 1 mil SI, instead of persisting 1,000 coverage individually, it will be super performance friendly to persist only two coverage group with their coverage & SI combinations, then associate them with different risk. It will mean only two coverage (actually it’s insured group) to persist instead of total 1,000 records.


### Concept of Named Insured & Unnamed Insured

Another important factor for group policy is whether it's named insured policy or not. For a named insured policy, users need to capture detailed information about all insureds covered by the policy. Conversely, for an unnamed insured policy—though some insureds may occasionally be attached—users typically cannot record detailed information for each insured, but only input a general count of insureds.


From the system perspective, an insured group is usually required for un-named insureds. It is up to the end business users to input the total count of insureds, rather than relying on an automatic calculation based on the sum of all detailed insureds. All calculations will also be based on the insured group, ignoring whether any detailed insured is captured or not.



### Product Configuration & Policy Model

Most of product configuration for group policy are the same as single policy. 

The key difference is whether there is a need for an insured group. The user needs to attach a new "PolicyRiskGroup" object by performing the following operation:

1. In the technical product screen, set the field "**Has Insured Group**" to "**Yes**".

   ![product definition](./image/grouppolicy/grouppolicy_pd001.png)

2. Then go to data dictionary to verify "**PolicyRiskGroup**" is automatically generated with the same structure as that of **PolicyRisk**.

   ![tech dd](./image/grouppolicy/grouppolicy_dd001.png)
   
 

### New Biz-related APIs

The following is a typical illustration of how to call API to achieve the most complex issuance scenario - group risk insured.

| Step                          | API                                                                 | Behavior                                                                                                                                                                                                                     |
|-------------------------------|---------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Create Proposal               | /proposal/core/proposal/v1/createEx                                              | API must be called upon UI initialization as a pre-requisite to call the group policy API.                                                                                                                                  |
| Create risk group & coverage  |  -                                                          | It’s encouraged to have a risk group to simplify the structure. If not, configure all coverage SI into the risk level.                                                                                                      |
| Query & load existing list of risks | /proposal/core/group/proposal/risk/v1/queryGroupPolicyElementByES <br> /proposal/core/group/proposal/risk/v1/loadGroupPolicyElement | Index – PolicyRisk to be configured<br>Adopt platform search engine to search risk.                                                                                                                                         |
| Create and calculate risk via UI | /proposal/core/group/proposal/risk/v1/createGroupPolicyElementEx?NeedCalculate=Y <br> /proposal/core/group/proposal/risk/v1/updateGroupPolicyElementEx?NeedCalculate=Y | Effective date and expiry date must be equal to policy effective date and expiry date<br>Detached API call.                                                                                                                 |
| Create/update risk via upload and download | /platform-pub/v1/file (which will invoke batch – groupPolicyRiskProposalUploadBatch)<br> proposal/core/group/proposal/risk/v1/exportGroupPolicyElementByES | Upload template to be configured<br>Adopt platform upload & batch framework to maintain risk as well as perform calculation.                                                                                                 |
| Delete risk via UI            | /proposal/core/group/proposal/risk/v1/deleteGroupPolicyElement <br> /proposal/core/group/proposal/risk/v1/deleteAllGroupPolicyElementByPolicyId |-                                                                                                                                                                                                                         |
| Recalculation                 | Invoke batch  – recalculateGroupPolicyBatch                        | POI changed, for example<br>Batch provided by the platform which will calculate each risk premium, accumulate to policy level, and calculate policy level premium.                                                          |
| Bind                          | /proposal/core/proposal/v1/updateEx                                                | -                                                                                                                                                                                                                       |
| Issue                         | Invoke batch - issueGroupPolicyRiskBatch                          | Batch provided by the platform.                                                                                                                                                                                             |


* `{{server}}/proposal/core/proposal/v1/createEx`
* `{{server}}/proposal/core/group/proposal/risk/v1/createGroupPolicyElementEx?policyId={{PolicyId}}&NeedCalculate=Y&NeedValidation=Y&ValidationEventCode={{eventCode}}&NeedUW=Y&UwEventCode=UnderwritingRuleCheck&UwLangId=zh_CN`
* `{{server}}/proposal/core/group/proposal/risk/v1/updateGroupPolicyElementEx?policyId={{PolicyId}}&NeedCalculate=Y&NeedValidation=Y&ValidationEventCode={{eventCode}}&NeedUW=Y&UwEventCode=UnderwritingRuleCheck&UwLangId=zh_CN`
* `{{server}}/proposal/core/group/proposal/risk/v1/bulkUpdateGroupPolicyElement?policyId={{PolicyId}}`
* `{{server}}/proposal/core/group/proposal/risk/v1/deleteGroupPolicyElement?policyId={{PolicyId}}&policyElementId={{policyRiskId}}`
* `{{server}}/proposal/core/group/proposal/risk/v1/loadGroupPolicyElement?policyId={{PolicyId}}&policyElementId={{policyRiskId}}`
* `{{server}}/proposal/core/group/proposal/risk/v1/queryGroupPolicyElementByES?policyId={{PolicyId}}`
* `{{server}}/proposal/core/group/proposal/risk/v1/exportGroupPolicyElementByES?policyId={{PolicyId}}&uploadTemplateName=RG001GroupPolicyRiskNB`
* `{{server}}/platform-pub/v1/file?struct=RG001GroupPolicyRiskNB&policyId={{PolicyId}}`
* `{{server}}/proposal/core/group/proposal/risk/v1/sumGroupPolicyElementByDB?policyId={{PolicyId}}&modelName=PolicyRisk&objectCode=R00001&groupByFieldNames=IdType`
* `{{server}}/proposal/core/group/proposal/risk/v1/calculatePolicyLevelPremium?policyId={{PolicyId}}`
* `{{server}}/proposal/core/proposal/v1/issuePolicyEx`


#### Group Policy Persistence

##### Create Policy API

`{{server}}/proposal/core/proposal/v1/createEx`

The JSON data structure is similar with that of the single policy, and the difference is:

1. There is NO "**PolicyRiskList**" but  "**PolicyRiskGroupList**". It is required when "IsRiskGroupNotUsed" = "Y".
2. All risk related operation should be processed via separate API and not included in the policy json.

Some other typical key field definition for group policy:

*  **PolicyType**, for group policy, it should be set to **3**.
*  **IsRiskGroupNotUsed**, used to label whether the policy is set risk group or not. When "IsRiskGroupNotUsed"="N", **PolicyRiskGroupList**" is required; when "IsRiskGroupNotUsed"="Y", the coverages are set separately under each risk.
*  **IsGroupInsuredNamed**, is N by default. It is used to label whether the policy is insured named or not. 
     * If there is no real risk, only a name list is set for the group, and then set **IsGroupInsuredNamed** to be **N**. One virtual risk will be automatically generated when rating, and then the premium will be calculated based on the virtual risk's premium. The premium = the virtual risk's premium * Insured Count.
     * If the insured is named, set **IsGroupInsuredNamed** to be **Y**. The premium will be calculated for each insured, and accumulated to policy.
*  **InsuredCount**: If IsGroupInsuredNamed=Y, it will be automatically updated after policy premium is calculated successfully, or otherwise it needs manual input.

###### Create Policy (With RiskGroup) - Request Example

```json
{
    "BusinessCateCode": "1",
    "EffectiveDate": "2022-11-15",
    "ExpiryDate": "2023-11-14T23:59:59",
// highlight-start
    "PolicyType": "3",
    "IsGroupInsuredNamed": "Y",
    "IsRiskGroupNotUsed":"N"
// highlight-end
    "PolicyCustomerList": [
        {
            "CustomerName": "Jack",
            "DateOfBirth": "1988-10-01",
            "IdNo": "123456789",
            "IdType": "1",
            "IsInsured": "N",
            "IsOrgParty": "N",
            "IsPolicyHolder": "Y"
        }
    ],
    "PolicyLobList": [
        {
            // highlight-next-line
            "PolicyRiskGroupList": [  //"IsRiskGroupNotUsed"="N"
                {
                    "SequenceNumber": 1,
                    // highlight-next-line
                    "InsuredCount": 2,
                    "PolicyCoverageList": [
                        {
                            "ProductElementCode": "C0001044",
                            "SumInsured": 1000
                        }
                        ......
                    ]
                }
            ],
            "ProductCode": "RG001",
            "ProductElementCode": "RG001",
            "ProductId": 527809281,
            "TechProductCode": "RG_TECH",
            "TechProductId": 527811302
        }
    ],
    "ProductCode": "RG001",
    "ProductId": 527809281,
    "ProductVersion": "1.0",
    "ProposalDate": "2022-11-15",
    "TechProductCode": "RG_TECH",
    "TechProductId": 527811302,
    "VersionSeq": 1
}
```

###### Create Policy (Without RiskGroup) - Request Example

```json
{
    "BusinessCateCode": "1",
    "EffectiveDate": "{{EffectiveDate}}",
    "ExpiryDate": "{{ExpiryDate}}",
    "PolicyType": "3",
    "IsGroupInsuredNamed": "Y",
    "IsRiskGroupNotUsed": "Y", 
    "IsRiskGroupNotUsed":"Y"
    "CommissionRate": 0.07,
    "PolicyCustomerList": [
        {
            "CustomerName": "APITest",
            "DateOfBirth": "1988-10-01",
            "IdNo": "123456789",
            "IdType": "1",
            "IsInsured": "N",
            "IsOrgParty": "N",
            "IsPolicyHolder": "Y"
        }
    ],
    "PolicyLobList": [//"IsRiskGroupNotUsed"="Y"
        {
            "ProductCode": "RG001",
            "ProductElementCode": "RG001",
            "ProductId": 527809281,
            "TechProductCode": "RG_TECH",
            "TechProductId": 527811302
        }
    ],
    "ProductCode": "RG001",
    "ProductId": 527809281,
    "ProductVersion": "1.0",
    "ProposalDate": "2022-11-15",
    "TechProductCode": "RG_TECH",
    "TechProductId": 527811302,
    "VersionSeq": 1
}
```

##### Create/Update/Calculate/Load Group Insured API

These API are necessary if users want to perform single insured based operation via UI.

The key model is policyrisk as well as its child elements like coverage or benefit.

* `{{server}}/proposal/core/group/proposal/risk/v1/createGroupPolicyElementEx?policyId={{PolicyId}}&NeedCalculate=Y&NeedValidation=Y&ValidationEventCode={{eventCode}}&NeedUW=Y&UwEventCode=UnderwritingRuleCheck&UwLangId=zh_CN`
* `{{server}}/proposal/core/group/proposal/risk/v1/updateGroupPolicyElementEx?policyId={{PolicyId}}&NeedCalculate=Y&NeedValidation=Y&ValidationEventCode={{eventCode}}&NeedUW=Y&UwEventCode=UnderwritingRuleCheck&UwLangId=zh_CN`
* `{{server}}/proposal/core/group/proposal/risk/v1/bulkCreateGroupPolicyElementEx?policyId={{PolicyId}}&NeedCalculate=Y`
* `{{server}}/proposal/core/group/proposal/risk/v1/bulkUpdateGroupPolicyElementEx?policyId={{PolicyId}}&NeedCalculate=Y`
* `{{server}}/proposal/core/group/proposal/risk/v1/deleteGroupPolicyElement?policyId={{PolicyId}}&policyElementId={{policyRiskId}}`
* `{{server}}/proposal/core/group/proposal/risk/v1/loadGroupPolicyElement?policyId={{PolicyId}}&policyElementId={{policyRiskId}}`

For creation or update, you can choose to do calculation, validation and underwriting by setting related flags,
* **NeedCalculate**, set to Y if need rating.
* **NeedValidation**, set to Y if need validation, then you can set the customized event code(ValidationEventCode).
* **NeedUW**, set to Y if need underwriting, then you can set the customized event code (**UwEventCode**), and the returned message language (**UwLangId**). If UwEventCode is not set, the default event code "UnderwritingRuleCheck" will be taken.


###### Create/Update/Calculate/Load Group Insured(With RiskGroup) - Request Example

```json
{
 // highlight-next-line
    "@type":"PolicyRisk-R00001",
    "SumInsured": 10000,
     // highlight-next-line
    "ProductElementCode": "R00001",
    "ProductElementId": 527811449,
    "RiskName": "{{$randomLastName}}",
    "VersionSeq": 1,
     // highlight-next-line
    "IsDetached":"Y",
    "IdType":"1",
    "IdNo":"{{$timestamp}}",
    "DetachedProductId": 527809281,
     // highlight-next-line
    "RiskGroupNo":1,
    "InsuredAge": {{$randomInt}},
    "PolicyId":"{{PolicyId}}"
}
```
###### Create/Update/Calculate/Load Group Insured(Without RiskGroup) - Request Example

```json
{
    "@type": "PolicyRisk-R00001",
    "SumInsured": 10000,
    "ProductElementCode": "R00001",
    "ProductElementId": 527811449,
    "RiskName": "Risk{{$randomInt}}",
    "DateOfBirth": "2000-10-01",
    "VersionSeq": 1,
    "IsDetached": "Y",
    "IdType": "2",
    "IdNo": "{{$timestamp}}{{$randomInt}}",
    "DetachedProductId": 527809281,
    "InsuredAge": 21,
    "RiskClass": "VIP",
    "PolicyId": "{{PolicyId}}",
    "PolicyCoverageList": [   //coverage for each risk
        {
            "@type": "PolicyCoverage-PolicyCoverage",
            "ProductElementCode": "C0001044",
            "UnitSumInsured": 1000
        },
        {
            "@type": "PolicyCoverage-PolicyCoverage",
            "ProductElementCode": "C00001",
            "UnitSumInsured": 1000,
            "VersionSeq": 1
        },
        {
            "@type": "PolicyCoverage-PolicyCoverage",
            "ProductElementCode": "C0001523",
            "SumInsured": 1000
        }
    ]
}
```
###### Create/Update/Calculate/Load Group Insured(With RiskGroup) - Request Example with Premium

```json
{
    "@pk": 8242830038,
    "@type": "PolicyRisk-R00001",
    "AdjustedPremium": 0,
    "BeforeVatPremium": 184.8,
    "BusinessObjectId": 527815931,
    "Commission": 0,
    "DetachedParentPolicyLobId": 8242800007,
    "DetachedProductId": 527809281,
    "DuePremium": 197.73,
    "GrossPremium": 184.8,
    "GroupPolicyCoverageData": "H4sIAAAAAAAAANWYa0/bMBSG/0rkz2nl3JN+WkkLq4TaqgUkhBByE1M85dLZCaKa9t93Ai0brbHMpE34U5s48uXxe14fn5sf6Euz3VA0QPO6YNk2rR8pJ2vae/uIbHRC72tOr0gz57RkbYkGodMPMTS0glVUiNnqG82aSY4GgRvFTuhg30ajlv7+Pugnjo3OeC3EYScTccoqUpzTR1qkDUxnCkPOCadVMy5oCT8XL9OcTJeXi/HotfVlnrtvusFj13djD2MvtndrWjakaQUauPCC13mb7btM67zrMsUYw2R9dNj+uhbHDzwbLen3llYZnbblinI0gLUs23JSiZZT+NLBfQwrAUJo4Pc95/nvgjQwBLRENtrDnJKyGxamVeWE59bze7Sf7Qmt6D1rzpmAfm4O92fX2nvzhBSb4IYSuNfvwJ3Pzifp9V06uxovhmdjpEvwBHAnnpJfoMEPvxA85LShGSMF8ABS8HEBk2F1hX7aBsHBSjjRMRxXD86irktrAd2ZhAOHiQpH6Bzj8PRwgK30vtZiw5pOMAbqJFSCkejE1wNzQlZba0S2vbqiO8MxiovSnMPkmEugx2W2gadOJtbFAyUNBzgPhK+pMAtPpMITSbw31I4nC04pa16D+04JRJU1ftrQShgGKIqVgCRxFWkeTi2IhW+tO2vG16SyGk4qsSmIWYbsJa6SjyS+Yk3fKeo6t63Z03ZNK9saMbKuQEssE/DA27VRMnJ9R4UplpxbiR6mYblqQTSZofajjK5YEl0O1rTn56Aa1RXh1j7UOj9KYQVmIQqUiCQB5mimx0PGLbPlEyujKpFElaOZHadUwFw7BdGCQcvWJC4uVmomkd1INdPkU8bhPB+y3DolGStYw0yTjPI+lcgum5qJ8rTmJWQ5uYGC8RJ1IMl8WDNNnqSXJloLjtQ6kdmubmYMWczxVfP2GM6nqai9x/cfVdSwUoyBBP2RqX+snpZy8LEMYndSFB09iVA/zV787+pm4Cqrc6HkLDk6Sj62G7O22UBQwDjWBRzBTTei6TVOX63p8O9rnCO2vxaZZK8+VtprLFGVZuJm3NXQS5QlzVgiDc1c7c+at+hOmNtfRYpIR7UZAAA=",
    "IsDetached": "Y",
    "ParentElementType": "POLICY_LOB",
    "PolicyElementId": 8242830038,
    "PolicyId": "8242800003,517D5D10804B2FF9A4D4480F0A504F72",
    "PolicyStatus": 2,
    "PremCalcFactorHash": "20230424_171938_815,Lxw7XUhZZ138AiI/jr112yAdIYDdT5QDLjz/ZflFB6c=",
    "ProductElementCode": "R00001",
    "ProductElementId": 527811449,
    "RiskGroupNo": 1,
    "RiskName": "Connelly",
    "SumInsured": 10000,
    "TempData": {
        "Mask-IdNo": "yfPuQq68VIud58JiuyAd4Q==",
        "IdNo": "yfPuQq68VIud58JiuyAd4Q==",
        "MaskAfter-IdNo": "1682327241"
    },
    "Vat": 12.93,
    "IdNo": "1682327241",
    "IdType": "1",
    "InsuredAge": 616
}
```

###### Create/Update/Calculate/Load Group Insured(Without RiskGroup) - Request Example with Premium

```json
{
    "@pk": 954811207,
    "@type": "PolicyRisk-R00001",
    "BeforeVatPremium": 5805,
    "BusinessObjectId": 527815931,
    "CalculateTime": "2025-07-01T10:10:40",
    "DetachedParentPolicyLobId": 954811204,
    "DetachedProductId": 527809281,
    "DuePremium": 6211.35,
    "EffectiveDate": "2025-06-29",
    "ExpiryDate": "2026-06-29",
    "GrossPremium": 5805,
    "HasChildGroupElement": "Y",
    "IsDetached": "Y",
    "IsGroupElementIssued": "N",
    "IsRiskChangedAfterCalc": "N",
    "ParentElementType": "POLICY_LOB",
    "PolicyElementId": 954811207,
    "PolicyId": "954811200,8201FEA1D1F5A3307B68BEC240C58CDF",
    "PolicyPremCalcFactorHash": "XSicJGpcylUnrOV+w16IGgFmX4cxLgY2o6TXLjfKwqc=",
    "PolicyStatus": 2,
    "PremCalcFactorHash": "20250701_101039_778,7VCXbyCC+CT1l3x0tHtV2Y9FxqErir81R5YnVHqYdso=",
    "ProductElementCode": "R00001",
    "ProductElementId": 527811449,
    "RiskName": "Risk343",
    "SumInsured": 10000,
    "Vat": 406.35,
    "AgeBand": "B3",
    "DateOfBirth": "2000-10-01",
    "IdNo": "175133***8240",
    "IdType": "2",
    "InsuredAge": 24,
    "POIRate": 1,
    "PolicyCoverageList": [
        {
            "@pk": 954811209,
            "@type": "PolicyCoverage-PolicyCoverage",
            "AnnualPremium": 1935,
            "BeforeVatPremium": 1935,
            "BusinessObjectId": 527816104,
            "DuePremium": 2070.45,
            "GrossPremium": 1935,
            "IsFinalLevelCt": "Y",
            "ParentElementType": "INSURED",
            "ParentPolicyElementId": 954811207,
            "PolicyElementId": 954811209,
            "PolicyId": "954811200,8201FEA1D1F5A3307B68BEC240C58CDF",
            "PolicyStatus": 2,
            "ProductElementCode": "C0001044",
            "ProductElementId": 527811453,
            "SequenceNumber": 1,
            "SumInsured": 10000,
            "UnitSumInsured": 1000,
            "Vat": 135.45,
            "VatRate": 0.07
        },
        ...skiped...
    ],
    "RiskClass": "VIP",
    "TempData": {
        "Mask-IdNo": "LbCr4OiJg+xUpr+48AAg7g==",
        "MaskAfter-IdNo": "175133***8240"
    }
}
```

##### Query Group Insured API

* `{{server}}/proposal/core/group/proposal/risk/v1/queryGroupPolicyElementByES?policyId={{PolicyId}}`

All risks under the group policy will be automatically indexed under the "PolicyRisk" index, and users can use query group insured API to query.

![group_policy_index_risk](./image/grouppolicy/group_policy_index_risk.png)

For detailed about how to use query API, users can refer to our [Index Management Guide](https://docs.insuremo.com/ics/app_framework/search) for more details.



##### Upload/Download Insured API

These APIs are crucial for group policies, as the large number of insureds in such policies means most operations should focus on the insured upload feature.

* Download: `{{server}}/proposal/core/group/proposal/risk/v1/exportGroupPolicyElementByES?policyId={{PolicyId}}&uploadTemplateName=RG001GroupPolicyRiskNB`

* Upload: `{{server}}/platform-pub/v1/file?NeedCalPolicy=N&struct=RG001GroupPolicyRiskNB&policyId={{PolicyId}}&JobBindBusinessKey={{ProposalNo}}`

</div> note 

Uploading will invoke platform batch to complete the process. Users can navigate to the Upload Template menu to create user-friendly upload templates for importing a large number of insureds into group policies.

</div>

* Sample New Business Risk Upload Template Definition & API Call

![group_policy_upload_risk_nb](./image/grouppolicy/group_policy_upload_risk_nb.jpg)

![Upload Group Element](./image/product_cfg_sample/groupelement_upload.png)

* Sample Endorsement Risk Upload Template Definition & API Call

![group_policy_upload_risk_endo](./image/grouppolicy/group_policy_upload_risk_endo.png)

![Upload Group Element- Endosement](./image/product_cfg_sample/groupelement_upload_endo.png)

For more details about how to configure the upload template, see [Upload Template Guide](https://docs.insuremo.com/ics/app_framework/upload).



##### Get the Count of Insured API

This is help to provide some statistics information for users to query.


* `{{server}}/proposal/core/group/proposal/risk/v1/sumGroupPolicyElementByDB?policyId={{PolicyId}}&modelName=PolicyRisk&objectCode=R00001&groupByFieldNames=IdType`


##### Issue Policy API

Users can fire the same proposal issuance API for group policy but without any risk level information in the policy json object.

* `{{server}}/proposal/core/proposal/v1/issuePolicyEx`

###### Issue Policy - Request Example

```json
{
	"ProposalNo": "{{ProposalNo}}"
}
```

   
#### Group Policy Calculation

<div class="docs-caution"><span class="docs-admonitions-text">caution</span>

All below calculation sample is given with the assumption that an old rating engine is adopted. With the latest InsureMO innovation, there's a new offering called "SPOCK" which can provide a better high-performance calculation experience. For more details about SPOCK, users can refer to [SPOCK introduction](https://docs.insuremo.com/spock/InsureMO_SPOCK_introduction_simplified).


We recommend users adopt SPOCK for group policy calculations rather than the old approach mentioned below. Of course, users can still read below as part of thinking process can be useful for users to adopt SPOCK for rating as well.

</div> 

Most of group policy rating configuration are the same as single policy. It's just users need to understand that group policy rating consists of two parts:

##### Individual Risk Calculation

It will only calculate each risk's premium. It will help quickly give users a premium result to verify. 

* `{{server}}/endo/core/group/endo/risk/v1/createGroupPolicyElementEx?policyId={{PolicyId}}&endoId={{EndoId}}&needGenerateEndoContent=N&NeedCalculate=Y`
* `{{server}}/endo/core/group/endo/risk/v1/updateGroupPolicyElementEx?policyId={{PolicyId}}&endoId={{EndoId}}&NeedCalculate=Y`

This will usually some API call each risk by risk or via upload batch which includes a bulk API call.


##### Policy Level Calculation Including All Risks


1. Calculate by Multiple Risk. If there's risk group present, the premium under the RiskGroup is automatically accumulated. 

* `{{server}}/proposal/core/group/proposal/risk/v1/bulkCreateGroupPolicyElementEx?policyId={{PolicyId}}&NeedCalculate=Y`
* `{{server}}/proposal/core/group/proposal/risk/v1/bulkUpdateGroupPolicyElementEx?policyId={{PolicyId}}&NeedCalculate=Y`

2. Accumulate risk premium to policyLob. Because of large number of insured risk, unlike standard policy in which premium can directly be accumulated from insured risk to policyLob level, for group policy, user need to fire separate API to do so.

* `{{server}}/proposal/core/group/proposal/risk/v1/calculatePolicyLevelPremium?policyId={{PolicyId}}`

3. Accumulate policyLob premium to policy and perform policyLob/policy level calculation for tax, fee or installment etc.

* `{{server}}/proposal/core/proposal/v1/calculate`

At platform level, there's a reCalculateGroupPolicy batch which already includes all above-mentioned process.

Also, if users want to go to next proposal level - for example, binding the proposal to avoid re-calculation because of no update, they can first save proposal then call below API to compare whether there's any policy/risk change between last calculation and now. If there's no change, users can skip the full calculation.

* `/proposal/core/group/proposal/risk/v1/needRecalculatePremium`	


##### Rating Configuration

Below is a sample calculation sequence to illustrate the typical group policy formula. It's similar as single policy calculation but users need to consider the PolicyRiskGroup model.

![rating](./image/grouppolicy/grouppolicy_rating001.png)
    


#### Group Policy Validation

There are different levels for group policy to have validation imposed:

#### Individual Risk Validation

The API to add individual group risk is：/proposal/core/group/proposal/risk/v1/createGroupPolicyElementEx. User can append a request parameter NeedValidation=Y (/proposal/core/group/proposal/risk/v1/createGroupPolicyElementEx?NeedValidation=Y) to have validation imposed on each group risk level.

Please note that if validation fails on single risk, the risk will not perist in DB.


#### Multiple Risk Validation, Single Risk Based

If it's multiple risk to be created, either by bulkCreateGroupPolicyElementEx or bulkUpdateGroupPolicyElementEx or bulkMergeGroupPolicyElementForUploadEx, it adopts different mechnism for validation.

Because of the potential large amount it will process, platform will first persist the risk into database asynchronously, then conduct the validation. For all records that not passing validation, it will be persist in DB and platform expose an API for user to fetch via API: /proposal/core/group/v1/findGroupPolicyBatchErrorsByPolicyId.

#### Multiple Risk Validation, Multiple Risk Based

It's not supported as platform default behavior. If user want to achieve, platform can provide project team with existing group policy upload batch implementation code so that project team can achieve such complex validation on your own.

Potentially, sumGroupPolicyElementByDBWithCondition can be used to identify multiple risk scenarios:

```
curl --location 'https://ebaogi-gi-sandbox-sg.ebaocloud.com/api/platform/proposal/core/group/proposal/risk/v1/sumGroupPolicyElementByDBWithCondition?policyId=2008509459%2C2D8370DF8D2A998938A0CAB37B7AC1C7&modelName=PolicyRisk&objectCode=R00001&groupByFieldNames=IdType' \
--data '{
    "RiskClass": "CLASSA"
}'
```


#### Validation on Policy/Policy lob

User can still fire /proposal/core/proposal/v1/validate to validate like normal proposal.

    
### Endorsement-related APIs

The following is a typical illustration of how to call API to achieve the endorsement scenario for group risk insured.

| Step                                          | API                                                                                            | Behavior                                                                                            |
|-----------------------------------------------|------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------|
| Create Endorsement                            | /endo/core/endo/v1/createEx                                                                              | API must be called upon UI initialization as pre-requisite to call other group policy API           |
| Query all risks after endorsement             | /endo/core/group/endo/risk/v1/queryGroupPolicyElementAfterEndoByES?includeDeletedRecords=Y     | All latest and index maintained                                                                     |
| Query all changed risks for this endorsement  | /endo/core/group/endo/risk/v1/queryGroupPolicyElementChangedAtEndoByES?includeDeletedRecords=Y | Incremental and index maintained                                                                    |
| See specific risk information                 | /pa/core/group/pa/risk/v1/loadGroupPolicyElement                                               | Load more risk information                                                                          |
| Import all changed risks for this endorsement | Invoke batch – groupPolicyRiskEndoUploadBatch                                                  | Template defined in upload module                                                                   |
|    -                                           |     -                                                                                           | Status can be viewed in batch module                                                                |
| Export all changed risks for this endorsement | /endo/core/group/endo/risk/v1/exportGroupPolicyElementChangedAtEndoByDB                        | Incremental records only, need to go policy query to see whole records after endorsement is issued. |
| Add and calculate new risk via UI             | /endo/core/group/endo/risk/v1/createGroupPolicyElementEx?NeedCalculate=Y                             | Calculate risk and delta premium only                                                               |
| Update and calculate existing risk via UI     | /endo/core/group/endo/risk/v1/updateGroupPolicyElementEx?NeedCalculate=Y                             | Calculate risk and delta premium only                                                               |
| Delete existing risk via UI                   | /endo/core/group/endo/risk/v1/updateGroupPolicyElement                                         | Set policy status =4                                                                                |
| Undo newly added risk via UI                  | /endo/core/group/endo/risk/v1/resetChangedGroupPolicyElementAtEndo                             | Back to the original status before endo                                                             |
| Undo all changed risks for this endo          | /endo/core/group/endo/risk/v1/resetAllChangedGroupPolicyElementAtEndo                          | Back to the original status before endo                                                             |
| Recalculation                                 | Invoke batch – groupPolicyRecalculateEndoBatch                                                 | Status can be viewed in batch module                                                                |
| Reject                                        | /endo/core/group/endo/risk/v1//resetAllChangedGroupPolicyElementForEndoReject                  | Back to the original status before endo                                                             |
| Bind                                          | /proposal/core/proposal/v1/updateEx                                                                              | Not to save risk information                                                                        |
| Issue                                         | Invoke batch - groupPolicyScheduleEndoIssueBatch                                               | Status can be viewed in batch module                                                                |
| Policy Query                                  | /proposal/core/group/proposal/risk/v1/queryGroupPolicyElementByES                              | Display total risk list                                                                             |
| Policy Query by endorsement version           | /endo/core/group/endo/risk/v1/queryGroupPolicyElementAfterEndoByES                             | Display changed risk list                                                                           |


* `{{server}}/endo/core/endo/v1/createEx`
* `{{server}}/endo/core/group/endo/risk/v1/createGroupPolicyElementEx?policyId={{PolicyId}}&endoId={{EndoId}}&NeedGenerateEndoContent=N&NeedCalculate=Y`
* `{{server}}/endo/core/group/endo/risk/v1/updateGroupPolicyElementEx?policyId={{PolicyId}}&endoId={{EndoId}}&NeedCalculate=Y`
* `{{server}}/endo/core/group/endo/risk/v1/deleteGroupPolicyElement?policyId={{PolicyId}}&policyElementId={{policyRiskId}}&endoId={{EndoId}}`
* `{{server}}/endo/core/group/endo/risk/v1/bulkCreateGroupPolicyElementEx?policyId={{PolicyId}}&endoId={{EndoId}}`
* `{{server}}/endo/core/group/endo/risk/v1/bulkUpdateGroupPolicyElementEx?policyId={{PolicyId}}&endoId={{EndoId}}`
* `{{server}}/endo/core/group/endo/risk/v1/calculatePolicyAndEndoLevelPremium?policyId={{PolicyId}}&endoId={{EndoId}}`
* `{{server}}/endo/core/group/endo/risk/v1/loadGroupPolicyElement?policyId={{PolicyId}}&policyElementId={{policyRiskId}}&endoId={{EndoId}}`
* `{{server}}/endo/core/group/endo/risk/v1/queryGroupPolicyElementAfterEndoByES?policyId={{PolicyId}}&endoId={{EndoId}}`
* `{{server}}/endo/core/group/endo/risk/v1/queryGroupPolicyElementChangedAtEndoByES?policyId={{PolicyId}}&endoId={{EndoId}}&includeDeletedRecords=Y`
* `{{server}}/endo/core/group/endo/risk/v1/fetchGroupPolicyElementChangedAtEndoByDB?policyId={{PolicyId}}&endoId={{EndoId}}&startGroupPolicyElementId=0&maxRecords=50`
* `{{server}}/endo/core/group/endo/schedule/v1/sumGroupPolicyElementAfterEndoByDB?policyId={{PolicyId}}&endoId={{EndoId}}&modelName=PolicyRisk&objectCode=R00001&groupByFieldNames=IdType`
* `{{server}}/endo/core/endo/v1/updateEx`
* `{{server}}/endo/core/endo/v1/calculate`
* `{{server}}/endo/core/endo/v1/issueEndorsement`

    
    


### Sample Reference PA UI

#### Policy Information

* **Real-Named Insured** is saved to the field "**IsGroupInsuredNamed**".

![PA UI](./image/grouppolicy/grouppolicy_pa001.png)


#### Risk Group Choice


##### With Risk Group

If it's a policy with risk group, then coverage should be at risk group level and it's for each insured to link the risk group number.

* Risk Group and Coverages

The Insured Count and Due Premium will be automatically updated after successful calculation. If **Real-Named Insured** is set to **No**,  You need to input the "**Insured Count**" manually.

![PA UI](./image/grouppolicy/grouppolicy_pa002.png)


* Insured Information

The Due Premium will be automatically updated after risk is added or updated successfully.
Also the system supports to upload/download insureds.

![PA UI](./image/grouppolicy/grouppolicy_pa003.png)



##### Without Risk Group

If it's a policy without risk group, then coverage should be at each individual insured level.

![group_policy_paui_without_insuredgroup](./image/grouppolicy/group_policy_paui_without_insuredgroup.png)




## Group Schedule List

A group schedule list mostly refers to those policies with a large number of **schedule items** (usually more than 100). Each schedule item will **NOT** have its own coverage/benefit and premium calculation, but serves mostly as informational reference for claims.

Take a construction engineering policy as an example: the insured party is typically the construction site, but additional schedules for workers or equipment may also be attached.


### New Biz-related APIs

* `{{server}}/proposal/core/proposal/v1/createEx`
* `{{server}}/proposal/core/group/proposal/schedule/v1/createGroupPolicyElementEx?policyId={{PolicyId}}`
* `{{server}}/proposal/core/group/proposal/schedule/v1/updateGroupPolicyElementEx?policyId={{PolicyId}}`
* `{{server}}/proposal/core/group/proposal/schedule/v1/bulkUpdateGroupPolicyElement?policyId={{PolicyId}}`
* `{{server}}/proposal/core/group/proposal/schedule/v1/deleteGroupPolicyElement?policyId={{PolicyId}}&policyElementId={{policyScheduleId}}`
* `{{server}}/proposal/core/group/proposal/schedule/v1/sumGroupPolicyElementByDB?policyId={{PolicyId}}&modelName=Worker&objectCode=WORKER&selectClause=count(1)`
* `{{server}}/proposal/core/group/proposal/schedule/v1/exportGroupPolicyElementByES?policyId={{PolicyId}}8&uploadTemplateName=RLOCKGroupPolicyScheduleNB`
* `{{server}}/platform-pub/v1/file?struct=RLOCKGroupPolicyScheduleNB&policyId={{PolicyId}}`
* `{{server}}/proposal/core/proposal/v1/persist/calculate`
* `{{server}}/proposal/core/proposal/v1/issuePolicyEx`


#### Create Policy API

`{{server}}/proposal/core/proposal/v1/createEx`

##### Create Policy - Request Example

The JSON data structure is the same as that of the single policy.
*  PolicyType, for group policy, should be set to 3.


```json
{
    "EffectiveDate": "{{EffectiveDate}}",
    "ExpiryDate": "{{ExpiryDate}}",
    "PolicyCustomerList": [
        {
            "CustomerName": "Jack",
            "CustomerType": "IndiCustomer",
            "DateOfBirth": "1988-10-01",
            "Gender": "3",
            "IdNo": "123456789",
            "IdType": "1",
            "IsBeneficiary": "N",
            "IsCoInsured": "N",
            "IsInsured": "N",
            "IsOrgParty": "N",
            "IsPolicyHolder": "Y",
            "VersionSeq": 1,
            "TempData": {
                "Mask-IdNo": "Hy4eAmtfvwRJLr3TzyvcZA==",
                "IdNo": "Hy4eAmtfvwRJLr3TzyvcZA=="
            }
        }
    ],
    "PolicyLobList": [
        {
            "PolicyRiskList": [
                {
                    "RiskName": "InsuredName",
                    "RiskDescription": "RiskDescription",
                    "Address": "songhu 270",
                    "ConstructionPeriodStart": "2022-08-03",
                    "ConstructionPeriodEnd": "2023-08-03",
                    "MaintenancePeriodStart": "2023-08-03",
                    "MaintenancePeriodEnd": "2025-08-03",
                    "EstimatdValue": 3000000,
                    "PremiumRate": 0.2,
                    "PolicyCoverageList": [
                        {
                            "PolicyLimitDeductibleList": [
                                {
                                    "LimitDeductibleValue": 1000,
                                    "ProductElementCode": "L200080",
                                    "ProductElementId": 370546189
                                }
                            ],
                            "ProductElementCode": "C101222",
                            "SumInsured": 1000,
                            "VersionSeq": 1
                        }
                    ],
                    "ProductElementCode": "R10067",
                    "ProductElementId": 370544706,
                    "VersionSeq": 1
                }
            ],
            "ProductCode": "RLOCK",
            "ProductElementCode": "RLOCK",
            "ProductId": 370544693,
            "ProductLobId": 351925023,
            "TechProductCode": "RIENG",
            "TechProductId": 370543502,
            "TotalInsuredCount": 1,
            "VersionSeq": 1
        }
    ],
     // highlight-next-line
    "PolicyType": "3",
    "ProductCode": "RLOCK",
    "ProductId": 370544693,
    "ProductVersion": "1.0",
    "ProposalDate": "2019-04-22",
    "TechProductCode": "RIENG",
    "TechProductId": 370543502,
    "Vat": 8.5,
    "VersionSeq": 1
}
```


#### Create/Update/Delete/Load Group Schedule API

* `{{server}}/proposal/core/group/proposal/schedule/v1/createGroupPolicyElementEx?policyId={{PolicyId}}`
* `{{server}}/proposal/core/group/proposal/schedule/v1/updateGroupPolicyElementEx?policyId={{PolicyId}}`
* `{{server}}/proposal/core/group/proposal/schedule/v1/bulkUpdateGroupPolicyElement?policyId={{PolicyId}}`
* `{{server}}/proposal/core/group/proposal/schedule/v1/deleteGroupPolicyElement?policyId={{PolicyId}}&policyElementId={{policyScheduleId}}`
* `{{server}}/proposal/core/group/proposal/schedule/v1/loadGroupPolicyElement?policyId={{PolicyId}}&policyElementId={{policyScheduleId}}`
* `{{server}}/proposal/core/group/proposal/schedule/v1/sumGroupPolicyElementByDB?policyId={{PolicyId}}&modelName=Worker&objectCode=WORKER&selectClause=count(1)`

##### Create/Update/Delete/Load Group Schedule - Request Example

```json
{
 // highlight-next-line
    "@type": "Worker-WORKER",
    "Name": "xxx_NB",
    "GenderCode": "M",
    "IdNo": "{{$timestamp}}{{$randomInt}}",
    "IdType": "1",
    "DateOfBirth": "2020-12-11",
    "SequenceNumber": 1,
    "DetachedParentPolicyLobId": {{policyLobID}},
     // highlight-next-line
    "IsDetached": "Y",
    "PolicyId": "{{PolicyId}}",
    "DetachedProductId": 370544693
}
```

#### Query Group Schedule API

* `{{server}}/proposal/core/group/proposal/schedule/v1/queryGroupPolicyElementByES?policyId={{PolicyId}}`

For all the risk in the group policy, it will be automatically indexed in the index "Schedule", then users can use query group insured API to query.

![group_policy_index_schedule](./image/grouppolicy/group_policy_index_schedule.png)

For detailed about how to use query API, users can refer to our [Index Management Guide](https://docs.insuremo.com/ics/app_framework/search) for more details.


#### Upload/Download Schedule API

* Download: `{{server}}/proposal/core/group/proposal/schedule/v1/exportGroupPolicyElementByES?policyId={{PolicyId}}8&uploadTemplateName=RLOCKGroupPolicyScheduleNB`
* `Upload: {{server}}/platform-pub/v1/file?struct=RLOCKGroupPolicyScheduleNB&policyId={{PolicyId}}`

* Sample New Business Schedule Upload Template Definition & API Call

![group_policy_upload_schedule_nb](./image/grouppolicy/group_policy_upload_schedule_nb.jpg)


* Sample Endorsement Schedule Upload Template Definition & API Call

![group_policy_upload_schedule_endo](./image/grouppolicy/group_policy_upload_schedule_endo.png)



#### Calculate Premium API

* `{{server}}/proposal/core/proposal/v1/persist/calculate`

##### Request Example


```json
{{policyInfo}}
```

#### Issue Policy API

* `{{server}}/proposal/core/proposal/v1/issuePolicyEx`

##### Issue Policy - Request Example

```json
{
	"ProposalNo": "{{ProposalNo}}"
}
```

### Endorsement-related APIs

* `{{server}}/endo/core/endo/v1/createEx`
 
* `{{server}}/endo/core/group/endo/schedule/v1/createGroupPolicyElementEx?policyId={{PolicyId}}&endoId={{EndoId}}&generateEndoContent=N`
* `{{server}}/endo/core/group/endo/schedule/v1/updateGroupPolicyElementEx?policyId={{PolicyId}}&endoId={{EndoId}}`
* `{{server}}/endo/core/group/endo/schedule/v1/deleteGroupPolicyElement?policyId={{PolicyId}}&policyElementId={{policyScheduleId}}&endoId=`
 
* `{{server}}/endo/core/endo/v1/updateEx`
* `{{server}}/endo/core/endo/v1/issueEndorsement`
* `{{server}}/endo/core/group/endo/schedule/v1/queryGroupPolicyElementAfterEndoByES?policyId={{PolicyId}}&endoId={{EndoId}}`
* `{{server}}/endo/core/group/endo/schedule/v1/queryGroupPolicyElementChangedAtEndoByES?policyId={{PolicyId}}&endoId={{EndoId}}&includeDeletedRecords=Y`
* `{{server}}/endo/core/group/endo/schedule/v1/fetchSubEndoIdList?policyId={{PolicyId}}&endoId={{EndoId}}&startSubEndoIdNotIncluded=0&maxRecords=50`


### Demo Product - RLOCK

To facilitate users to understand how group risk policy API is called and product is configured in a real business scenario, they can refer to below product via the Easy PA demo environment:

* Technical Product Code: `TR_POC`
* Market Product Code: `RLOCK`

#### Product Definition

To store the name list of the insureds, create a schedule for it and add the schedule to product.

 ![product definition](./image/grouppolicy/grouppolicy_pd002.png)


#### Sample PA UI

Also the system supports to upload/download insureds.

![worker List ](./image/grouppolicy/grouppolicy_pa100.png)


## Single & Group Policy Compatible Solution

Sometimes, the delivery team adopts a single-policy solution during initial implementation but later finds that the number of risks is higher than expected, especially in occasional cases. At that point, switching to a group policy solution would be costly to implement, but if not to change, policy cannot be issued and user will always face time-out before of the large number of risks.


Once that happens, this group policy compatible solution will help. 

* Unlike standard group policy solution which requires a major detachment of all risk operation for all the APIs, this group policy compatible API will still take the policy object as the request and response body. This approach significantly reduces the effort needed to switch between solutions.


* Unlike standard single policy solution which will process all the risks together, for this group compatible solution, all risks will be processed concurrently which will greatly increase the speed of processing and less likely to face time-out issue.

This solution will help for policy with risk from 100 to 2,000. If user has policies with more than 2,000 risks, please not to adopt this solution and keep to use the standard group policy solution mentioned earlier in this chapter.


### API Specification

* Proposal Transaction

API Path: `/api/platform/policy-batch/core/group/proposal/singleCall/v1/processPolicy?batchSize=50`

This API can replace all the transactional proposal APIs such as create/update/calculate/uw/issue/attachElement operations. It takes the policy object as the request and returns the policy object as the response, similarly to the standard proposal API.

The riskCode & detachedScheduleModelNames parameter is only used when there is multiple PolicyRisk type is defined in product (or large schedule type). 

```java
@RequestMapping(value = "/processPolicy", method = RequestMethod.POST)
Policy processPolicy(@RequestBody Policy policy,
                     @SpringQueryMap ProposalOptions options,
                     @RequestParam(name="riskCode",required = false) String riskCode,
                     @RequestParam(name="detachedScheduleModelNames",required = false) List<String> detachedScheduleModelNames,
                     @RequestParam(name="batchSize",required = false,defaultValue = DEFAULT_BATCH_SIZE) Integer batchSize);
```


The ProposalOptions is used to control which operation should be done in current API call, it has following fields:
```java
private String additionalValidationEventCode;
private String needValidateForApplication;//default "N",use null value to shorten request url
private String needValidateForPolicyStructure;//default "N",use null value to shorten request url
private String needUW;//default "N",use null value to shorten request url
private String uwEventCode;
private String uwLangId;
private String needCalculate;//default "N",use null value to shorten request url
private String needGenerateProposalNo="Y";
private String needGenerateQuotationNo;//default "N",use null value to shorten request url
private String needPersist;///default "N",use null value to shorten request url. /will be set to Y if needIssue=Y
private String needIndex="Y";//wil be ignored if needPersist=N
private String needGeneratePolicyNo;////default "N",use null value to shorten request url. will be set to Y if needIssue=Y and policyNo is null
private String needIssue;//default "N",use null value to shorten request url
private String needGeneratePolicyFee;//default "N",use null value to shorten request url
private String needSign="N";//sign premium calculate
private String needAttachElement="N";
private String attachElementEventCode="AttachElement4Proposal";
```

For example, if you are calling `/proposal/core/proposal/v1/createEx` to create proposal, you just need to change API path to `/policy-batch/core/group/proposal/singleCall/v1/processPolicy?batchSize=50&needPersist=Y`, while no need to change rest of request and response body. In a very low switch cost, you will be able to have concurrent processing for policy with big amount of risks.

</div> note:

* Policy data changed in request body
1.	The “PolicyType” field must be changed from “1” to “3”

* Policy data changed in response body
1.	Policy Level
a)	Add IsGroupInsuredNamed=Y
b)	Add IsRiskGroupNotUsed=Y

2.	Risk level
a)	Set ParentPolicyElementId to null
b)	Add DetachedParentPolicyLobId, DetachedProductId, HasChildGroupElement, IsDetached

</div>

* Proposal Load

API Path: `/api/platform/policy-batch/core/group/proposal/singleCall/v1/loadPolicy?policyId=13941811042&batchSize=50`

This API can replace proposal load API and will give entire policy object in the response body.


### Rule & Rating Consideration for the Switch

If user adopts this solution, because all risk will be changed to be processed concurrently, there will be additional constraint for rule and rating behaviors. 

Below is a comparison table to depict the key rating/rule configuration difference between single and group policy.


| Scope       | Consideration Points                                        | Single Policy                                                                                          | Group Policy                                                                                                                                                                                                          |
|-------------|-------------------------------------------------------------|--------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Rating/Rule | Execution Principle                                          | Run entire policy body via single policy API call, Policy -> PolicyLob -> PolicyRisk -> PolicyCoverage | Run policy body with single risk for group policy API call, Policy -> PolicyLob -> PolicyRisk (Single) -> PolicyCoverage                                                                                              |
| Rating/Rule | One Risk Execution Depending on Another Risk Execution Risk | Support                                                                                                | Not Support                                                                                                                                                                                                           |
| Rating/Rule | DSL with level Policy/PolicyLob to fetch PolicyRisk field   | Support                                                                                                | Not Support                                                                                                                                                                                                           |
| Rating      | Premium Accumulation                                        | All handled by rating engine depending on the accumulative tickbox                                     | Following accumulation handled by rating engine depending on the accumulative tickbox: PolicyCoverage to PolicyRisk, PolicyLob to Policy. Following accumulation handled by group policy API: PolicyRisk to PolicyLob. If any customized premium related field need accumulated, please add it to DD object **PremiumCalcTemp**, make sure this field exists under the 3 objects, the **AbstractPolicyCoverage**, **Policy** and **PremiumCalcTemp**. |
| Rating      | Premium Allocation from Policy/PolicyLob to PolicyRisk      | Support                                                                                                | Not Support                                                                                                                                          




## Unique Check for Group Insured 

Unique Group Insured (both schedule and risk) key to check is set in rate table - **GroupPolicyElementConfig** (Under menu **Rule & Rating > Configuration Table**).

As showed below, the same IdType and IdNo should be unique. If there is no related configuration record for current product, the below error will pop up:

```
Can not find result in rate table, code:GroupPolicyElementConfig, version:1 conditions:{ModelName=xx,ProductCOde=xx,ObjectCode=xx}
```

System will also give an error if there's duplicate insured existing based on the configuration:

```
Caused by: java.lang.RuntimeException: There is a existing record[policyElementId=1970616756] with same unique property[IdType,IdNo] in database! at 
```


![GroupPolicyElementConfig](./image/grouppolicy/grouppolicy_uniqueKeyConfig.png)


## Q&A

### If I'm not using InsureMO for rating, do I need adopt group policy structure?

The essence of group policy is to DETACH the risk not only for calculation but also for persistence. As long as risk number is larger than 100, the system will not be able to persist it efficiently, so we need to detach risk from lob and policy level, allowing each risk to be processed and persisted concurrently.

For calculation in particular:

1.	No matter whether you are using GIMO rating or SPOCK, for performance consideration, you need to:  
Step 1: calculate each risk first (detached and concurrently)  
Step 2: accumulate to lob and policy level  
Step 3: do policy wide calculation e.g., tax fee, commission etc.

2.	If you are using third party rating engine, they might only calculate risk premium or they might be able to calculate all risk and policy premium. Anyway, when they send back the calculation result, we still need to persist it as mentioned above.

Also, during the analysis, there are other points to remind:

1.	All process should be implemented via asynchronous way (e.g., by using batch to achieve). Otherwise, it’s easy to face timeout during transaction.

2.	If there are multiple risks sharing some coverage set, users can adopt risk group concept to further simplify the payload.


### If I have a question schedule which contains more than 1,000 questions, how to handle?

Our group policy API has two usage:

1.	Group insured risk
2.	Group schedule

Although it is not necessarily a risk, the schedule is a perfect match for scenario 2 above.

Whenever users encounters a large schedule, they should detach it from the standard proposal API and leverage the group schedule API to all kinds of operations such as save, load or query.


### How can I fetch all existing risk data for one group risk policy?

You can use `/proposal/core/group/proposal/risk/v1/fetchGroupPolicyElementByDB` this API to fetch. Given the potential for a large number of risks, you must implement a pagination mechanism to fetch.

The paging function is implemented by the “prePolicyElementId” parameter. You should pass the last policyElementId for next page queries and the maxRecords parameter should less then 500.







