# Business Logic — JKKPrcSimulationCC.makeSvcGrpList() [153 LOC]

| Field | Value |
|-------|-------|
| Fully Qualified Name | `com.fujitsu.futurity.bp.custom.common.JKKPrcSimulationCC` |
| Layer | CC / Common Component (package `com.fujitsu.futurity.bp.custom.common`) |
| Module | `common` (Package: `com.fujitsu.futurity.bp.custom.common`) |

## 1. Role

### JKKPrcSimulationCC.makeSvcGrpList()

This method performs **discount eligibility group routing** for the price simulation subsystem. Given a list of service records extracted from the shared `commonInfo` context, it partitions those services into **six distinct discount registration condition patterns** (割引登録条件コード別パターン). Each pattern represents a different business rule for grouping services when determining which discount services apply during pricing simulation.

The method implements a **routing/dispatch design pattern**: it iteratively builds five groups based on different grouping keys (all services together, by invoice contract number, by service contract line number, and by invoice+line combinations), and then labels each group with a corresponding discount condition code. The returned list is a sequence of group maps, each carrying a `WRIB_ADD_JOKEN_CD` (discount registration condition code) and a `SVC_GRP_LIST` (the group of matching services).

The six discount conditions covered are:
1. **No condition** (JOKEN_NON) -- all services grouped as a single group, used when no grouping restriction applies.
2. **Same customer** (CUST) -- services grouped by customer ID (eoID), used for customer-level discount rules.
3. **Same invoice** (SEI) -- services grouped by billing contract/invoice number, used for invoice-level discount rules.
4. **Same customer + same invoice** (CUST_SEI) -- services grouped first by customer, then by invoice within each customer.
5. **Same line** (KAISEN) -- services grouped by service contract line detail number, used for line-level discount rules.
6. **Same invoice + same line** (SEI_KAISEN) -- services grouped by the composite key of invoice number and line detail number.

This method is a shared utility called internally by `chkMainWribSvc()`, which uses the grouped results to match discount service conditions against actual services. It plays a central role in the discount application logic of the price simulation screen (KKSV0553).

## 2. Processing Pattern (Detailed Business Logic)

```mermaid
flowchart TD
    START(["makeSvcGrpList(commonInfo)"])
    READ_SVC_INFO["Read svcInfoList from<br/>commonInfo[SVC_INFO_LIST]"]
    CALL_SEIKYU["Call makeSeikyuList(svcInfoList)<br/>-- extract unique seky_kei_no"]
    CALL_UTIWAKE["Call makeUtiwakeList(svcInfoList)<br/>-- extract unique kaisen_kei_no"]
    INIT_LOCAL["Initialize local variables<br/>svcGrpList, svcList, retList etc."]

    BLOCK1_START["Block 1: Same Customer Grouping"]
    INIT_BLOCK1["Init svcGrpList and svcList"]
    LOOP1_START["For each svcInfoMap in svcInfoList"]
    LOOP1_PUT["Put svc_number and add to svcList"]
    LOOP1_END["End loop for svcInfoList"]
    MAP_GROUP1["Create svcGrpInfoMap:<br/>grp_number=0, svc_list=svcList"]
    ADD_BLOCK1["Add svcGrpInfoMap to svcGrpList"]
    WRIB_NON["Map WRIB_ADD_JOKEN_CD = JOKEN_NON"]
    ADD_RET1["Add to retList"]
    WRIB_CUST["Map WRIB_ADD_JOKEN_CD = CUST"]
    ADD_RET2["Add to retList"]

    BLOCK2_START["Block 2: Same Customer + Same Invoice"]
    INIT_BLOCK2["Init svcGrpList, svcList, grpCnt2"]
    LOOP2_OUTER["For each key in seikyuKeyList"]
    LOOP2_GET_KEY["Get seikyu key"]
    INIT_LOOP2["Init svcList, ite"]
    LOOP2_INNER["While svcInfoList has next"]
    LOOP2_MATCH["If key == seky_kei_no"]
    LOOP2_PUT2["Put svc_number, add to svcList"]
    LOOP2_END["End inner loop"]
    MAP_GROUP2["Create svcGrpInfoMap:<br/>grp_number, svc_list"]
    ADD_BLOCK2["Add to svcGrpList"]
    LOOP2_END_OUTER["End outer loop"]
    WRIB_SEI["Map WRIB_ADD_JOKEN_CD = SEI"]
    ADD_RET3["Add to retList"]
    WRIB_CUST_SEI["Map WRIB_ADD_JOKEN_CD = CUST_SEI"]
    ADD_RET4["Add to retList"]

    BLOCK3_START["Block 3: Same Customer + Same Line"]
    INIT_BLOCK3["Init svcGrpList, svcList, grpCnt3"]
    LOOP3_OUTER["For each key in kaisenKeyList"]
    LOOP3_GET_KEY["Get kaisen key"]
    INIT_LOOP3["Init svcList, ite"]
    LOOP3_INNER["While svcInfoList has next"]
    LOOP3_MATCH["If key == kaisen_kei_no"]
    LOOP3_PUT["Put svc_number, add to svcList"]
    LOOP3_END["End inner loop"]
    MAP_GROUP3["Create svcGrpInfoMap:<br/>grp_number, svc_list"]
    ADD_BLOCK3["Add to svcGrpList"]
    LOOP3_END_OUTER["End outer loop"]
    WRIB_KAISEN["Map WRIB_ADD_JOKEN_CD = KAISEN"]
    ADD_RET5["Add to retList"]

    BLOCK4_START["Block 4: Same Customer +<br/>Same Invoice + Same Line"]
    INIT_BLOCK4["Init svcGrpList, svcList, grpCnt4"]
    LOOP4_OUTER["For each key1 in seikyuKeyList"]
    LOOP4_INNER["For each key2 in kaisenKeyList"]
    INIT_LOOP4["Init svcList, ite"]
    LOOP4_CHECK["If key1==seky_kei_no AND<br/>key2==kaisen_kei_no"]
    LOOP4_PUT["Put svc_number, add to svcList"]
    LOOP4_END["End inner loop"]
    MAP_GROUP4["Create svcGrpInfoMap:<br/>grp_number, svc_list"]
    ADD_BLOCK4["Add to svcGrpList"]
    LOOP4_END_OUTER["End outer loop"]
    WRIB_SEI_KAISEN["Map WRIB_ADD_JOKEN_CD = SEI_KAISEN"]
    ADD_RET6["Add to retList"]

    END_NODE["Return retList"]

    START --> READ_SVC_INFO
    READ_SVC_INFO --> CALL_SEIKYU
    CALL_SEIKYU --> CALL_UTIWAKE
    CALL_UTIWAKE --> INIT_LOCAL
    INIT_LOCAL --> BLOCK1_START
    BLOCK1_START --> INIT_BLOCK1
    INIT_BLOCK1 --> LOOP1_START
    LOOP1_START --> LOOP1_PUT
    LOOP1_PUT --> LOOP1_END
    LOOP1_END --> MAP_GROUP1
    MAP_GROUP1 --> ADD_BLOCK1
    ADD_BLOCK1 --> WRIB_NON
    WRIB_NON --> ADD_RET1
    ADD_RET1 --> WRIB_CUST
    WRIB_CUST --> ADD_RET2
    ADD_RET2 --> BLOCK2_START
    BLOCK2_START --> INIT_BLOCK2
    INIT_BLOCK2 --> LOOP2_OUTER
    LOOP2_OUTER --> LOOP2_GET_KEY
    LOOP2_GET_KEY --> INIT_LOOP2
    INIT_LOOP2 --> LOOP2_INNER
    LOOP2_INNER -->|true| LOOP2_MATCH
    LOOP2_MATCH -->|true| LOOP2_PUT2
    LOOP2_PUT2 --> LOOP2_END
    LOOP2_MATCH -->|false| LOOP2_END
    LOOP2_END -->|more| LOOP2_INNER
    LOOP2_INNER -->|done| MAP_GROUP2
    MAP_GROUP2 --> ADD_BLOCK2
    ADD_BLOCK2 -->|next key| LOOP2_OUTER
    LOOP2_OUTER -->|done| WRIB_SEI
    WRIB_SEI --> ADD_RET3
    ADD_RET3 --> WRIB_CUST_SEI
    WRIB_CUST_SEI --> ADD_RET4
    ADD_RET4 --> BLOCK3_START
    BLOCK3_START --> INIT_BLOCK3
    INIT_BLOCK3 --> LOOP3_OUTER
    LOOP3_OUTER --> LOOP3_GET_KEY
    LOOP3_GET_KEY --> INIT_LOOP3
    INIT_LOOP3 --> LOOP3_INNER
    LOOP3_INNER -->|true| LOOP3_MATCH
    LOOP3_MATCH -->|true| LOOP3_PUT
    LOOP3_PUT --> LOOP3_END
    LOOP3_MATCH -->|false| LOOP3_END
    LOOP3_END -->|more| LOOP3_INNER
    LOOP3_INNER -->|done| MAP_GROUP3
    MAP_GROUP3 --> ADD_BLOCK3
    ADD_BLOCK3 -->|next key| LOOP3_OUTER
    LOOP3_OUTER -->|done| WRIB_KAISEN
    WRIB_KAISEN --> ADD_RET5
    ADD_RET5 --> BLOCK4_START
    BLOCK4_START --> INIT_BLOCK4
    INIT_BLOCK4 --> LOOP4_OUTER
    LOOP4_OUTER --> LOOP4_INNER
    LOOP4_INNER --> INIT_LOOP4
    INIT_LOOP4 --> LOOP4_CHECK
    LOOP4_CHECK -->|true| LOOP4_PUT
    LOOP4_PUT --> LOOP4_END
    LOOP4_CHECK -->|false| LOOP4_END
    LOOP4_END -->|more| LOOP4_INNER
    LOOP4_INNER -->|done| MAP_GROUP4
    MAP_GROUP4 --> ADD_BLOCK4
    ADD_BLOCK4 -->|next key2| LOOP4_INNER
    ADD_BLOCK4 -->|next key1| LOOP4_OUTER
    LOOP4_OUTER -->|done| WRIB_SEI_KAISEN
    WRIB_SEI_KAISEN --> ADD_RET6
    ADD_RET6 --> END_NODE
```

**Constant Resolution:**
The method uses five discount registration condition codes from `JKKWrisvcDchskmCommonUtil`:

| Constant | Resolved Value | Business Meaning |
|----------|---------------|-----------------|
| `WRIB_ADD_JOKEN_CD_JOKEN_NON` | `"01"` | No grouping condition (all services in one group) |
| `WRIB_ADD_JOKEN_CD_CUST` | `"02"` | Same customer (eoID) |
| `WRIB_ADD_JOKEN_CD_SEI` | `"03"` | Same invoice/billing contract number |
| `WRIB_ADD_JOKEN_CD_CUST_SEI` | `"05"` | Same customer AND same invoice number |
| `WRIB_ADD_JOKEN_CD_KAISEN` | `"04"` | Same service contract line detail number |
| `WRIB_ADD_JOKEN_CD_SEI_KAISEN` | `"06"` | Same invoice number AND same line detail number |

## 3. Parameter Analysis

| No | Parameter Name | Type | Business Description |
|----|---------------|------|---------------------|
| 1 | `commonInfo` | `HashMap<String, Object>` | The shared work context map carrying all business data for the price simulation screen (KKSV0553). It contains the `SVC_INFO_LIST` key, which maps to an `ArrayList<HashMap<String, Object>>` of service records. Each service record includes fields such as `seky_kei_no` (billing contract/invoice number), `kaisen_kei_no` (service contract line detail number), `svc_cd` (service code), `prc_grp_cd` (price group code), `sokuwari_um` (instant discount flag), and others as defined in `KKSV0553_KKSV0553OP_WORK` and `KKSV0553_KKSV0553OP_WORK_SVC_INFO`. |

**Instance fields / external state read:** None. This method is fully stateless -- it only reads from the `commonInfo` parameter and local variables.

## 4. CRUD Operations / Called Services

| CRUD | SC / CBS | SC Code | Entity / DB | Operation Description |
|------|----------|---------|-------------|----------------------|
| R | `JKKPrcSimulationCC.makeSeikyuList` | - | - | Extracts unique billing contract numbers (seky_kei_no) from the service info list. Called internally to build the invoice-level grouping key list. |
| R | `JKKPrcSimulationCC.makeUtiwakeList` | - | - | Extracts unique service contract line detail numbers (kaisen_kei_no) from the service info list. Called internally to build the line-level grouping key list. |

**Notes:**
- Both `makeSeikyuList` and `makeUtiwakeList` are **Read-only** helper methods within the same class. They perform in-memory deduplication by iterating over `svcInfoList` and collecting unique keys using `ArrayList.contains()`.
- No database queries, SC codes, or entity/table operations are invoked by this method. It operates purely on in-memory data structures.

## 5. Dependency Trace

### Pre-computed evidence from code analysis graph:

No screen/batch entry points found within 8 hops. Direct callers found: 1 method.
Terminal operations from this method: `makeUtiwakeList` [-], `makeSeikyuList` [-]

| # | Caller (Screen/Batch) | Call Chain (Full Path to this Method) | Terminal (SC / CRUD / Entity) |
|---|----------------------|--------------------------------------|-------------------------------|
| 1 | Internal -- `JKKPrcSimulationCC.chkMainWribSvc` | `chkMainWribSvc(commonInfo)` -> `makeSvcGrpList(commonInfo)` | `makeSeikyuList [R] in-memory`, `makeUtiwakeList [R] in-memory` |

**Call chain detail:**
- `chkMainWribSvc` is a private method within `JKKPrcSimulationCC` that orchestrates discount service eligibility checking. It calls `makeSvcGrpList` to obtain the pre-grouped service lists organized by each discount registration condition code pattern, then iterates through actual discount service records to find matches.
- The `chkMainWribSvc` method is itself called during the price simulation workflow for screen `KKSV0553` (Price Simulation), which is the financial simulation work area for discount eligibility determination.

## 6. Per-Branch Detail Blocks

**Block 1** -- FOR (iterate svcInfoList) `(i < svcInfoList.size())` (L1442)

> Build the "same customer" grouping: all services are placed into a single group. This is the simplest grouping -- no filtering is applied, every service record is included.

| # | Type | Code |
|---|------|------|
| 1 | SET | `grpCnt1 = 0;` // Group counter initialization [L1438] |
| 2 | SET | `svcList = null; svcGrpList = null; svcGrpInfoMap = null; svcGrpListInfoMap = null;` // Local variable declarations [L1439-1441] |
| 3 | SET | `retList = new ArrayList<HashMap<String, Object>>();` // Return list [L1442] |
| 4 | SET | `svcGrpList = new ArrayList<HashMap<String,Object>>();` // Initialize group list [L1452] |
| 5 | SET | `svcList = new ArrayList<HashMap<String,Object>>();` // Initialize service list [L1453] |
| 6 | EXEC | `svcInfoMap = svcInfoList.get(i);` // Get service record [L1455] |
| 7 | SET | `svcInfoMap.put(SVC_NUMBER, j++);` // Assign sequential service number [L1456] -> `SVC_NUMBER="svc_number"` |
| 8 | EXEC | `svcList.add(svcInfoMap);` // Add to service list [L1457] |
| 9 | SET | `svcGrpInfoMap = new HashMap<String, Object>();` // Create group info map [L1460] |
| 10 | SET | `svcGrpInfoMap.put(GRP_NUMBER, grpCnt1++);` // Set group number [L1461] -> `GRP_NUMBER="grp_number"` |
| 11 | SET | `svcGrpInfoMap.put(SVC_LIST, svcList);` // Link service list to group [L1462] -> `SVC_LIST="svc_list"` |
| 12 | EXEC | `svcGrpList.add(svcGrpInfoMap);` // Add group to group list [L1463] |

**Block 1.1** -- SET (discount condition code: No Condition) `(L1465)` [WRIB_ADD_JOKEN_CD_JOKEN_NON="01"]

> Create a map entry marking this single-group structure as the "no condition" discount pattern.

| # | Type | Code |
|---|------|------|
| 1 | SET | `svcGrpListInfoMap = new HashMap<String, Object>();` [L1465] |
| 2 | SET | `svcGrpListInfoMap.put(WRIB_ADD_JOKEN_CD, WRIB_ADD_JOKEN_CD_JOKEN_NON);` // Discount condition code = No Condition [L1466] -> `WRIB_ADD_JOKEN_CD="wrrib_add_joken_cd"`, [-> `WRIB_ADD_JOKEN_CD_JOKEN_NON="01"`] |
| 3 | SET | `svcGrpListInfoMap.put(SVC_GRP_LIST, svcGrpList);` // Link group list [L1467] -> `SVC_GRP_LIST="svc_grp_list"` |
| 4 | EXEC | `retList.add(svcGrpListInfoMap);` // Add to return list [L1468] |

**Block 1.2** -- SET (discount condition code: Same Customer) `(L1470)` [WRIB_ADD_JOKEN_CD_CUST="02"]

> Add the same grouping under the "same customer" discount pattern. Since all services share the same customer by definition (they came from the same commonInfo), this produces identical grouping data.

| # | Type | Code |
|---|------|------|
| 1 | SET | `svcGrpListInfoMap = new HashMap<String, Object>();` [L1470] |
| 2 | SET | `svcGrpListInfoMap.put(WRIB_ADD_JOKEN_CD, WRIB_ADD_JOKEN_CD_CUST);` // Discount condition code = Same Customer [L1471] -> `WRIB_ADD_JOKEN_CD="wrrib_add_joken_cd"`, [-> `WRIB_ADD_JOKEN_CD_CUST="02"`] |
| 3 | SET | `svcGrpListInfoMap.put(SVC_GRP_LIST, svcGrpList);` // Link group list [L1472] |
| 4 | EXEC | `retList.add(svcGrpListInfoMap);` // Add to return list [L1473] |

**Block 2** -- FOR (iterate seikyuKeyList) `(i < seikyuKeyList.size())` `(L1478)`

> Build the "same customer + same invoice" grouping. This creates one subgroup per unique billing contract number (seky_kei_no). For each invoice number, it filters all services to only those matching that invoice. This supports invoice-level discount rules.

| # | Type | Code |
|---|------|------|
| 1 | SET | `svcGrpList = new ArrayList<HashMap<String,Object>>();` // Re-initialize group list for new grouping [L1478] |
| 2 | EXEC | `seikyuKeyList = makeSeikyuList(svcInfoList);` // Call internal helper -- extract unique billing contract numbers [L1431] |
| 3 | EXEC | `kaisenKeyList = makeUtiwakeList(svcInfoList);` // Call internal helper -- extract unique line detail numbers [L1433] |
| 4 | SET | `for (int i = 0, j = 0, grpCnt2 = 0; i < seikyuKeyList.size(); i++)` // Outer loop over unique invoice numbers [L1479] |
| 5 | SET | `key = seikyuKeyList.get(i);` // Get current invoice key [L1481] -> `key = seikyuKeyList.get(i)` |
| 6 | SET | `svcList = new ArrayList<HashMap<String,Object>>();` // Reset service list for this group [L1483] |
| 7 | EXEC | `ite = svcInfoList.iterator();` // Create iterator over all services [L1484] |
| 8 | EXEC | `while (ite.hasNext())` // Inner loop over all services [L1485] |
| 9 | SET | `svcInfoMap = ite.next();` // Get next service record [L1486] |
| 10 | IF | `key.equals(svcInfoMap.get(KKSV0553_KKSV0553OP_WORK_SVC_INFO.SEKY_KEI_NO))` // Check if service matches current invoice key [L1487] -> `SEKY_KEI_NO="seky_kei_no"` |
| 11 | SET | `svcInfoMap.put(SVC_NUMBER, j++);` // Assign sequential service number within group [L1488] |
| 12 | EXEC | `svcList.add(svcInfoMap);` // Add to group [L1489] |
| 13 | SET | `svcGrpInfoMap = new HashMap<String, Object>();` // Create group info map [L1491] |
| 14 | SET | `svcGrpInfoMap.put(GRP_NUMBER, grpCnt2++);` // Set group number [L1492] |
| 15 | SET | `svcGrpInfoMap.put(SVC_LIST, svcList);` // Link service list to group [L1493] |
| 16 | EXEC | `svcGrpList.add(svcGrpInfoMap);` // Add group to group list [L1494] |

**Block 2.1** -- SET (discount condition code: Same Invoice) `(L1497)` [WRIB_ADD_JOKEN_CD_SEI="03"]

> After building invoice-level groups, add them under the "same invoice" discount pattern.

| # | Type | Code |
|---|------|------|
| 1 | SET | `svcGrpListInfoMap = new HashMap<String, Object>();` [L1497] |
| 2 | SET | `svcGrpListInfoMap.put(WRIB_ADD_JOKEN_CD, WRIB_ADD_JOKEN_CD_SEI);` // Discount condition code = Same Invoice [L1498] -> `WRIB_ADD_JOKEN_CD="wrrib_add_joken_cd"`, [-> `WRIB_ADD_JOKEN_CD_SEI="03"`] |
| 3 | SET | `svcGrpListInfoMap.put(SVC_GRP_LIST, svcGrpList);` // Link group list [L1499] |
| 4 | EXEC | `retList.add(svcGrpListInfoMap);` // Add to return list [L1500] |

**Block 2.2** -- SET (discount condition code: Same Customer + Same Invoice) `(L1502)` [WRIB_ADD_JOKEN_CD_CUST_SEI="05"]

> Add the same invoice-level grouping under the "same customer + same invoice" discount pattern. Since services in the sharedInfo are already same-customer, the invoice grouping implies both customer and invoice match.

| # | Type | Code |
|---|------|------|
| 1 | SET | `svcGrpListInfoMap = new HashMap<String, Object>();` [L1502] |
| 2 | SET | `svcGrpListInfoMap.put(WRIB_ADD_JOKEN_CD, WRIB_ADD_JOKEN_CD_CUST_SEI);` // Discount condition code = Same Customer + Same Invoice [L1503] -> `WRIB_ADD_JOKEN_CD="wrrib_add_joken_cd"`, [-> `WRIB_ADD_JOKEN_CD_CUST_SEI="05"`] |
| 3 | SET | `svcGrpListInfoMap.put(SVC_GRP_LIST, svcGrpList);` // Link group list [L1504] |
| 4 | EXEC | `retList.add(svcGrpListInfoMap);` // Add to return list [L1505] |

**Block 3** -- FOR (iterate kaisenKeyList) `(i < kaisenKeyList.size())` `(L1510)`

> Build the "same customer + same line" grouping. Creates one subgroup per unique service contract line detail number (kaisen_kei_no). Filters services by line number, supporting line-level discount rules.

| # | Type | Code |
|---|------|------|
| 1 | SET | `svcGrpList = new ArrayList<HashMap<String,Object>>();` // Re-initialize [L1510] |
| 2 | SET | `for (int i = 0, j = 0, grpCnt3 = 0; i < kaisenKeyList.size(); i++)` // Outer loop over unique line numbers [L1511] |
| 3 | SET | `key = kaisenKeyList.get(i);` // Get current line key [L1513] |
| 4 | SET | `svcList = new ArrayList<HashMap<String,Object>>();` // Reset service list [L1515] |
| 5 | EXEC | `ite = svcInfoList.iterator();` // Create iterator [L1516] |
| 6 | EXEC | `while (ite.hasNext())` // Inner loop over all services [L1517] |
| 7 | SET | `svcInfoMap = ite.next();` // Get next service record [L1518] |
| 8 | IF | `key.equals(svcInfoMap.get(KKSV0553_KKSV0553OP_WORK_SVC_INFO.KAISEN_KEI_NO))` // Check if service matches current line key [L1519] -> `KAISEN_KEI_NO="kaisen_kei_no"` |
| 9 | SET | `svcInfoMap.put(SVC_NUMBER, j++);` // Assign sequential number within group [L1520] |
| 10 | EXEC | `svcList.add(svcInfoMap);` // Add to group [L1521] |
| 11 | SET | `svcGrpInfoMap = new HashMap<String, Object>();` // Create group info map [L1523] |
| 12 | SET | `svcGrpInfoMap.put(GRP_NUMBER, grpCnt3++);` // Set group number [L1524] |
| 13 | SET | `svcGrpInfoMap.put(SVC_LIST, svcList);` // Link service list to group [L1525] |
| 14 | EXEC | `svcGrpList.add(svcGrpInfoMap);` // Add group to group list [L1526] |

**Block 3.1** -- SET (discount condition code: Same Line) `(L1529)` [WRIB_ADD_JOKEN_CD_KAISEN="04"]

> Add line-level groups under the "same line" discount pattern.

| # | Type | Code |
|---|------|------|
| 1 | SET | `svcGrpListInfoMap = new HashMap<String, Object>();` [L1529] |
| 2 | SET | `svcGrpListInfoMap.put(WRIB_ADD_JOKEN_CD, WRIB_ADD_JOKEN_CD_KAISEN);` // Discount condition code = Same Line [L1530] -> `WRIB_ADD_JOKEN_CD="wrrib_add_joken_cd"`, [-> `WRIB_ADD_JOKEN_CD_KAISEN="04"`] |
| 3 | SET | `svcGrpListInfoMap.put(SVC_GRP_LIST, svcGrpList);` // Link group list [L1531] |
| 4 | EXEC | `retList.add(svcGrpListInfoMap);` // Add to return list [L1532] |

**Block 4** -- FOR (nested loops: seikyuKeyList x kaisenKeyList) `(L1537)`

> Build the "same customer + same invoice + same line" grouping. This uses a nested loop: for each invoice number (outer), iterate through all line numbers (inner), and for each invoice+line pair, filter services matching both keys. This creates the most granular grouping, supporting compound invoice+line discount rules.

| # | Type | Code |
|---|------|------|
| 1 | SET | `svcGrpList = new ArrayList<HashMap<String,Object>>();` // Re-initialize [L1537] |
| 2 | SET | `for (int i = 0, j = 0, grpCnt4 = 0; i < seikyuKeyList.size(); i++)` // Outer loop over unique invoice numbers [L1538] |
| 3 | SET | `key1 = seikyuKeyList.get(i);` // Get invoice key [L1540] |
| 4 | SET | `for (int k = 0; k < kaisenKeyList.size(); k++)` // Inner loop over unique line numbers [L1542] |
| 5 | SET | `key2 = kaisenKeyList.get(k);` // Get line key [L1544] |
| 6 | SET | `svcList = new ArrayList<HashMap<String,Object>>();` // Reset service list [L1546] |
| 7 | EXEC | `ite = svcInfoList.iterator();` // Create iterator [L1547] |
| 8 | EXEC | `while (ite.hasNext())` // Innermost loop over all services [L1548] |
| 9 | SET | `svcInfoMap = ite.next();` // Get next service [L1549] |
| 10 | IF | `key1.equals(svcInfoMap.get(KKSV0553_KKSV0553OP_WORK_SVC_INFO.SEKY_KEI_NO)) && key2.equals(svcInfoMap.get(KKSV0553_KKSV0553OP_WORK_SVC_INFO.KAISEN_KEI_NO))` // Check both invoice and line match [L1550-1551] -> `SEKY_KEI_NO="seky_kei_no"`, `KAISEN_KEI_NO="kaisen_kei_no"` |
| 11 | SET | `svcInfoMap.put(SVC_NUMBER, j++);` // Assign sequential number within group [L1552] |
| 12 | EXEC | `svcList.add(svcInfoMap);` // Add to group [L1553] |
| 13 | SET | `svcGrpInfoMap = new HashMap<String, Object>();` // Create group info map [L1555] |
| 14 | SET | `svcGrpInfoMap.put(GRP_NUMBER, grpCnt4++);` // Set group number [L1556] |
| 15 | SET | `svcGrpInfoMap.put(SVC_LIST, svcList);` // Link service list [L1557] |
| 16 | EXEC | `svcGrpList.add(svcGrpInfoMap);` // Add group to group list [L1558] |

**Block 4.1** -- SET (discount condition code: Same Invoice + Same Line) `(L1561)` [WRIB_ADD_JOKEN_CD_SEI_KAISEN="06"]

> Add the invoice+line composite groups under the final discount pattern.

| # | Type | Code |
|---|------|------|
| 1 | SET | `svcGrpListInfoMap = new HashMap<String, Object>();` [L1561] |
| 2 | SET | `svcGrpListInfoMap.put(WRIB_ADD_JOKEN_CD, WRIB_ADD_JOKEN_CD_SEI_KAISEN);` // Discount condition code = Same Invoice + Same Line [L1562] -> `WRIB_ADD_JOKEN_CD="wrrib_add_joken_cd"`, [-> `WRIB_ADD_JOKEN_CD_SEI_KAISEN="06"`] |
| 3 | SET | `svcGrpListInfoMap.put(SVC_GRP_LIST, svcGrpList);` // Link group list [L1563] |
| 4 | EXEC | `retList.add(svcGrpListInfoMap);` // Add to return list [L1564] |

**Block 5** -- RETURN `(L1567)`

| # | Type | Code |
|---|------|------|
| 1 | RETURN | `return retList;` // Return the fully populated list of 6 discount-condition-group maps [L1567] |

## 7. Glossary

| Term | Type | Business Meaning |
|------|------|------------------|
| `seky_kei_no` | Field | Billing contract number (invoice number) -- the key identifier for a billing contract line in K-Opticom's customer base system |
| `kaisen_kei_no` | Field | Service contract line detail number -- identifies a specific line within a service contract, used for line-level grouping |
| `svc_cd` | Field | Service code -- identifies the type of service (e.g., FTTH, Mail, ENUM) |
| `prc_grp_cd` | Field | Price group code -- groups services for pricing purposes |
| `sokuwari_um` | Field | Instant discount flag -- indicates whether an instant discount applies to the service |
| `family_pack_um` | Field | Family pack flag -- indicates whether the service is part of a family pack bundle |
| `pcrs_cd` | Field | Price course code -- identifies the pricing course (e.g., F01 for Family Pack, F02 for Omakase Anshin Set) |
| `pplan_cd` | Field | Price plan code -- identifies the specific pricing plan |
| `op_svc_list` | Field | Option service list -- list of optional/add-on services attached to the main service |
| `sbop_svc_list` | Field | Sub-option service list -- list of sub-option services |
| `seiopsvc_list` | Field | Billing option service list -- option services related to billing |
| `kktk_svc_list` | Field | Equipment provision service list -- services related to equipment provision (e.g., router, set-top box) |
| `SVC_INFO_LIST` | Field | Service information list -- the key in commonInfo holding the ArrayList of service records |
| `wrrib_add_joken_cd` | Field | Discount registration condition code -- the code that determines which grouping pattern a service group belongs to |
| `grp_number` | Field | Group number -- sequential index within a discount condition group |
| `svc_list` | Field | Service list -- the list of service records within a group |
| `svc_grp_list` | Field | Service group list -- the list of all groups under a single discount condition |
| `svc_number` | Field | Service number -- sequential index assigned to each service within its group |
| WRIB_ADD_JOKEN_CD_JOKEN_NON | Constant | Discount condition code "01" -- No condition; all services grouped together without restrictions |
| WRIB_ADD_JOKEN_CD_CUST | Constant | Discount condition code "02" -- Same customer (eoID); services grouped by customer |
| WRIB_ADD_JOKEN_CD_SEI | Constant | Discount condition code "03" -- Same invoice; services grouped by billing contract number |
| WRIB_ADD_JOKEN_CD_CUST_SEI | Constant | Discount condition code "05" -- Same customer AND same invoice; services grouped by both customer and invoice |
| WRIB_ADD_JOKEN_CD_KAISEN | Constant | Discount condition code "04" -- Same line; services grouped by service contract line detail number |
| WRIB_ADD_JOKEN_CD_SEI_KAISEN | Constant | Discount condition code "06" -- Same invoice AND same line; services grouped by invoice and line composite key |
| eoID | Business term | Customer ID (enterprise ID) -- unique identifier for a K-Opticom customer account |
| KKSV0553 | Screen | Price Simulation screen -- the business screen for pricing simulation in the customer base system |
| JKKPrcSimulationCC | Class | Price Simulation Common Component -- the shared component class handling price simulation business logic |
| `chkMainWribSvc` | Method | Main discount service eligibility check -- the caller method that uses this grouped result to match discount conditions |
| FTTH | Business term | Fiber To The Home -- fiber-optic internet service offered by K-Opticom |
| K-Opticom | Business term | Japanese telecommunications carrier (customer base system name: eo) |
