# Business Logic — JBSBatKKKkOpDlRvAdd.selectKktSvKeiUcwk() [87 LOC]

| Field | Value |
|-------|-------|
| Fully Qualified Name | `eo.business.service.JBSBatKKKkOpDlRvAdd` |
| Layer | Service (Batch service component) |
| Module | `service` (Package: `eo.business.service`) |

## 1. Role

### JBSBatKKKkOpDlRvAdd.selectKktSvKeiUcwk()

This method performs a **service contract detail search** (サービス契約内訳の検索処理) to retrieve the active service contract line item (detail) record associated with a given service contract number (`svcKeiNo`). It queries the `T_SVC_KEI_UCWK` (service contract detail) database table using a batch-operation-date filter and the provided contract number, then applies a **latest-record resolution strategy**: if multiple detail records exist for the same contract number, it filters out records in a canceled or resolved state (status `910` / `920`) and selects the remaining record with the most recent combined reservation-application date (`RSV_APLY_YMD`) and generation-registration timestamp (`GENE_ADD_DTM`). If only one detail record exists, it is returned directly. The method returns the winning service contract detail number and its generation-registration timestamp as a two-element string array.

This method serves as a **shared utility** within the batch processing module. It implements a **routing/filter-then-select design pattern** — first loading all matching records, then applying business rules to resolve which record is "active" based on status and recency. It is called by the batch parameter-setter method `setParamKK1551KkopDsl`, which feeds its result downstream for further batch processing decisions. The method handles the business concept of **versioned service contract details** — in this system, a single service contract can accumulate multiple detail records over time (e.g., after changes, renewals, or modifications), and this method determines which version is the current active one.

## 2. Processing Pattern (Detailed Business Logic)

```mermaid
flowchart TD
    START(["selectKktSvKeiUcwk(svcKeiNo)"])
    INIT_LOCALS["Initialize local variables: svKeiUcwkNo, geneAddDtm, rsvAplyYmd, svKeiUcwkList"]
    SET_WHERE["Set whereParam = [opeDate, svcKeiNo]"]
    EXEC_SELECT["CALL executeKK_T_SVC_KEI_UCWK_KK_SELECT_114(whereParam)"]
    SELECT_NEXT["kktSvKeiUcwkMap_114 = db_KK_T_SVC_KEI_UCWK.selectNext()"]
    COND_RESULT["null != kktSvKeiUcwkMap_114?"]
    WHILE_LOOP("null != kktSvKeiUcwkMap_114?")
    NEW_MAP["svKeiUcwkMap = new HashMap<String, String>()"]
    PUT_FIELDS["Put SVC_KEI_UCWK_NO, GENE_ADD_DTM, SVC_KEI_UCWK_STAT, RSV_APLY_YMD with Rtrim"]
    ADD_LIST["svKeiUcwkList.add(svKeiUcwkMap)"]
    NEXT_RECORD["kktSvKeiUcwkMap_114 = db_KK_T_SVC_KEI_UCWK.selectNext()"]
    LIST_COUNT("svKeiUcwkList.size() > 1?")
    IF_MULTI("size > 1?")
    FOR_EACH["FOR svKeiUcwkMap in svKeiUcwkList"]
    GET_FIELDS["svcKeiUcwkStat, geneAddDtm2, rsvAplyYmd2"]
    COND_STAT("SVC_KEI_STAT_DLS_ZM=910 or SVC_KEI_STAT_CNCL_ZM=920?")
    CONTINUE["continue (skip canceled/resolved)"]
    COMPARE("rsvAplyYmd2 + geneAddDtm2 > rsvAplyYmd + geneAddDtm?")
    UPDATE_BEST["svcKeiUcwkNo = newNo, geneAddDtm = newDtm, rsvAplyYmd = newYmd"]
    SINGLE_ITEM["svKeiUcwkMap = svKeiUcwkList.get(0)"]
    SET_SINGLE["svcKeiUcwkNo = svcKeiUcwkNo, geneAddDtm = geneAddDtm"]
    LOG_CHECK("logPrint.chkLogLevel(DEBUG)?")
    PRINT_LOG["printDebugLog: svcKeiUcwkNo and geneAddDtm"]
    RESULT_ARRAY["result = new String[2]"]
    SET_RESULT["result[0]=svcKeiUcwkNo, result[1]=geneAddDtm"]
    RETURN_RESULT["return result"]
    END_NODE(["End"])

    START --> INIT_LOCALS
    INIT_LOCALS --> SET_WHERE
    SET_WHERE --> EXEC_SELECT
    EXEC_SELECT --> SELECT_NEXT
    SELECT_NEXT --> COND_RESULT
    COND_RESULT -->|true| WHILE_LOOP
    COND_RESULT -->|false| LIST_COUNT
    WHILE_LOOP --> NEW_MAP
    NEW_MAP --> PUT_FIELDS
    PUT_FIELDS --> ADD_LIST
    ADD_LIST --> NEXT_RECORD
    NEXT_RECORD --> WHILE_LOOP
    WHILE_LOOP -->|false| LIST_COUNT
    LIST_COUNT --> IF_MULTI
    IF_MULTI -->|true| FOR_EACH
    IF_MULTI -->|false| SINGLE_ITEM
    FOR_EACH --> GET_FIELDS
    GET_FIELDS --> COND_STAT
    COND_STAT -->|true| CONTINUE
    CONTINUE --> FOR_EACH
    COND_STAT -->|false| COMPARE
    COMPARE -->|true| UPDATE_BEST
    UPDATE_BEST --> FOR_EACH
    COMPARE -->|false| FOR_EACH
    FOR_EACH --> SINGLE_ITEM
    SINGLE_ITEM --> LOG_CHECK
    LOG_CHECK -->|true| PRINT_LOG
    LOG_CHECK -->|false| RESULT_ARRAY
    PRINT_LOG --> RESULT_ARRAY
    RESULT_ARRAY --> SET_RESULT
    SET_RESULT --> RETURN_RESULT
    RETURN_RESULT --> END_NODE
```

**CRITICAL — Constant Resolution:**

| Constant | Actual Value | Business Meaning |
|----------|-------------|------------------|
| `JBSbatKKConst.SVC_KEI_STAT_DLS_ZM` | `"910"` | Service contract status: **解約済** (Resolved/Closed) |
| `JBSbatKKConst.SVC_KEI_STAT_CNCL_ZM` | `"920"` | Service contract status: **キャンセル済** (Canceled) |

**Processing flow summary:**

1. **Initialization:** Creates a `svKeiUcwkList` ArrayList to hold detail records, and initializes `svcKeiUcwkNo`, `geneAddDtm`, and `rsvAplyYmd` to empty strings.
2. **Parameter binding:** Builds a `whereParam` array with the batch operation date (`opeDate`) and the input service contract number (`svcKeiNo`).
3. **DB query execution:** Calls `executeKK_T_SVC_KEI_UCWK_KK_SELECT_114()` to execute a database SELECT against table `KK_T_SVC_KEI_UCWK` using SQL key `KK_SELECT_114`, filtering by operation date and service contract number.
4. **Record iteration:** Calls `db_KK_T_SVC_KEI_UCWK.selectNext()` to fetch each matching row, extracting `SVC_KEI_UCWK_NO`, `GENE_ADD_DTM`, `SVC_KEI_UCWK_STAT`, and `RSV_APLY_YMD` (all with `Rtrim` applied) into a HashMap, then into the result list.
5. **Multi-record resolution:** If more than one detail record exists, iterates through all of them. Skips records whose status is `910` (解約済/resolved) or `920` (キャンセル済/canceled). Among the remaining active records, selects the one with the highest lexicographic concatenation of `RSV_APLY_YMD + GENE_ADD_DTM` (latest reservation-application date and generation timestamp).
6. **Single-record branch:** If exactly one record exists, uses it directly without comparison.
7. **Debug logging:** If debug logging is enabled, logs the found `svcKeiUcwkNo` and `geneAddDtm`.
8. **Return:** Packages the result into a `String[2]` array and returns `[svcKeiUcwkNo, geneAddDtm]`.

## 3. Parameter Analysis

| No | Parameter Name | Type | Business Description |
|----|---------------|------|---------------------|
| 1 | `svcKeiNo` | `String` | Service contract number — the unique identifier for a service contract line (the parent contract under which multiple detail records can exist). Used as a WHERE-clause filter to find all associated service contract detail records in `KK_T_SVC_KEI_UCWK`. Can be any alphanumeric string matching the contract number format used in the telecom billing system. |

**Instance fields / external state read by this method:**

| Source | Field / Object | Business Description |
|--------|---------------|---------------------|
| Instance field | `opeDate` | Batch operation date — used as a binding parameter for the DB query to filter records by the batch run date. Set by the batch framework. |
| Instance field | `db_KK_T_SVC_KEI_UCWK` | Database accessor for table `KK_T_SVC_KEI_UCWK` — the service contract detail table. Provides `selectNext()` to iterate query results. |
| Instance field | `super.logPrint` | Logging utility inherited from parent class — used for debug log output. |

## 4. CRUD Operations / Called Services

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

| CRUD | SC / CBS | SC Code | Entity / DB | Operation Description |
|------|----------|---------|-------------|----------------------|
| - | `JBSbatCommonDBInterface.setString` | (internal) | - | Sets bind variables in the parameter list before DB execution |
| R | `JBSbatCommonDBInterface.selectBySqlDefine` | (internal) | KK_T_SVC_KEI_UCWK | Executes the SQL query via `KK_SELECT_114` key against table `KK_T_SVC_KEI_UCWK`, filtered by operation date and service contract number |
| R | `db_KK_T_SVC_KEI_UCWK.selectNext` | (internal) | KK_T_SVC_KEI_UCWK | Fetches the next row from the query result cursor |
| - | `JBSbatStringUtil.Rtrim` | (internal) | - | Trims trailing whitespace from string fields |
| - | `super.logPrint.chkLogLevel` | (internal) | - | Checks if debug log level is enabled |
| - | `super.logPrint.printDebugLog` | (internal) | - | Writes debug log messages |

### Internal method analysis:

| CRUD | SC / CBS | SC Code | Entity / DB | Operation Description |
|------|----------|---------|-------------|----------------------|
| R | `executeKK_T_SVC_KEI_UCWK_KK_SELECT_114` | (internal) | KK_T_SVC_KEI_UCWK | Executed a DB query with SQL key KK_SELECT_114 to retrieve service contract detail records for the given service contract number and operation date. |

**CRUD summary:**

| CRUD | SC / CBS | SC Code | Entity / DB | Operation Description |
|------|----------|---------|-------------|----------------------|
| R | `executeKK_T_SVC_KEI_UCWK_KK_SELECT_114` | (internal) | KK_T_SVC_KEI_UCWK | DB SELECT — retrieves all service contract detail records matching the batch operation date and service contract number using SQL key KK_SELECT_114 |
| R | `db_KK_T_SVC_KEI_UCWK.selectNext` | (internal) | KK_T_SVC_KEI_UCWK | DB READ — fetches each row from the query result cursor during iteration |

## 5. Dependency Trace

| # | Caller (Screen/Batch) | Call Chain (Full Path to this Method) | Terminal (SC / CRUD / Entity) |
|---|----------------------|--------------------------------------|-------------------------------|
| 1 | Batch: `JBSBatKKKkOpDlRvAdd.setParamKK1551KkopDsl()` | `setParamKK1551KkopDsl()` -> `selectKktSvKeiUcwk(svcKeiNo)` | `executeKK_T_SVC_KEI_UCWK_KK_SELECT_114 [R] KK_T_SVC_KEI_UCWK` |

**Call chain description:**
- The method `setParamKK1551KkopDsl()` within the same class `JBSBatKKKkOpDlRvAdd` invokes `selectKktSvKeiUcwk()` to obtain the service contract detail number and its generation timestamp, which are then used as parameters for downstream batch processing step `KK1551`.

**Terminal operations from this method:**
- `executeKK_T_SVC_KEI_UCWK_KK_SELECT_114 [R] KK_T_SVC_KEI_UCWK` — DB read of service contract detail records
- `db_KK_T_SVC_KEI_UCWK.selectNext [R] KK_T_SVC_KEI_UCWK` — DB row-by-row fetch
- `printDebugLog [-]` — debug logging (no data effect)
- `Rtrim [-]` — string trimming utility

## 6. Per-Branch Detail Blocks

**Block 1** — [SET] Local variable initialization (L4037)

The method begins by setting up local state. An empty ArrayList collects query results; three String variables are initialized to empty strings to hold the selected detail number, generation timestamp, and reservation-application date.

| # | Type | Code | Business Description |
|---|------|------|---------------------|
| 1 | SET | `svKeiUcwkList = new ArrayList<HashMap<String, String>>()` | Initialize the result container for service contract detail records |
| 2 | SET | `svcKeiUcwkNo = ""` // サービス契約内訳番号 (Service contract detail number) | Initialize selected detail number |
| 3 | SET | `geneAddDtm = ""` // 世代登録年月日時分秒 (Generation registration datetime) | Initialize generation timestamp |
| 4 | SET | `rsvAplyYmd = ""` // 予約適用年月日 (Reservation-application date) | Initialize reservation date |

**Block 2** — [SET] WHERE parameter preparation (L4046)

Prepares the bind parameter array for the DB query.

| # | Type | Code | Business Description |
|---|------|------|---------------------|
| 1 | SET | `whereParam = {opeDate, svcKeiNo}` | Bind array: [batch operation date, service contract number] |

**Block 3** — [CALL] DB query execution (L4049)

Executes the SELECT against `KK_T_SVC_KEI_UCWK`. The SQL key `KK_SELECT_114` is defined in the SQL definition file and filters by operation date and service contract number.

| # | Type | Code | Business Description |
|---|------|------|---------------------|
| 1 | CALL | `executeKK_T_SVC_KEI_UCWK_KK_SELECT_114(whereParam)` | Execute DB SELECT to retrieve service contract detail records |

**Block 4** — [SET] First record fetch (L4052)

Fetches the first row from the query result set. If the result set is empty, `kktSvKeiUcwkMap_114` will be `null`.

| # | Type | Code | Business Description |
|---|------|------|---------------------|
| 1 | SET | `kktSvKeiUcwkMap_114 = db_KK_T_SVC_KEI_UCWK.selectNext()` | Fetch first matching row from the service contract detail cursor |

**Block 5** — [IF] Result check (L4055)

Checks if any records were returned by the query. If `null`, the query found no matching detail records and the method returns empty strings.

> Condition: `null != kktSvKeiUcwkMap_114` — If records exist, proceed to iterate them. Otherwise, skip to the result assembly (Block 10).

**Block 6** — [WHILE] Record iteration (L4059)

Iterates through all returned detail records, extracting each field with trailing whitespace trimming and collecting them into the result list.

| # | Type | Code | Business Description |
|---|------|------|---------------------|
| 1 | SET | `svKeiUcwkMap = new HashMap<String, String>()` | Create map for current record |
| 2 | CALL | `kktSvKeiUcwkMap_114.getString(JBSbatKK_T_SVC_KEI_UCWK.SVC_KEI_UCWK_NO)` | Get service contract detail number |
| 3 | CALL | `JBSbatStringUtil.Rtrim(...)` // Trim trailing whitespace | Clean up the detail number field |
| 4 | SET | `svKeiUcwkMap.put("SVC_KEI_UCWK_NO", ...)` | Store detail number in map |
| 5 | CALL | `kktSvKeiUcwkMap_114.getString(JBSbatKK_T_SVC_KEI_UCWK.GENE_ADD_DTM)` | Get generation registration datetime |
| 6 | CALL | `JBSbatStringUtil.Rtrim(...)` | Clean up the datetime field |
| 7 | SET | `svKeiUcwkMap.put("GENE_ADD_DTM", ...)` | Store generation timestamp in map |
| 8 | CALL | `kktSvKeiUcwkMap_114.getString(JBSbatKK_T_SVC_KEI_UCWK.SVC_KEI_UCWK_STAT)` | Get service contract detail status |
| 9 | CALL | `JBSbatStringUtil.Rtrim(...)` | Clean up the status field |
| 10 | SET | `svKeiUcwkMap.put("SVC_KEI_UCWK_STAT", ...)` | Store status in map |
| 11 | CALL | `kktSvKeiUcwkMap_114.getString(JBSbatKK_T_SVC_KEI_UCWK.RSV_APLY_YMD)` | Get reservation-application date |
| 12 | CALL | `JBSbatStringUtil.Rtrim(...)` | Clean up the date field |
| 13 | SET | `svKeiUcwkMap.put("RSV_APLY_YMD", ...)` | Store reservation date in map |
| 14 | CALL | `svKeiUcwkList.add(svKeiUcwkMap)` | Add this record to the result list |
| 15 | SET | `kktSvKeiUcwkMap_114 = db_KK_T_SVC_KEI_UCWK.selectNext()` | Fetch next row (continuation condition) |

**Block 7** — [IF] Multiple records check (L4071)

After iteration, determines if more than one detail record was found. If yes, applies the **latest-record resolution logic** to select the active record.

> Condition: `svKeiUcwkList != null && svKeiUcwkList.size() > 1` — Multiple detail records exist for this contract number.

**Block 8** — [FOR] Multi-record resolution loop (L4075)

Iterates through all detail records to find the best active one. Applies two filtering rules:
1. **Status exclusion:** Records with status `910` (解約済/resolved) or `920` (キャンセル済/canceled) are skipped.
2. **Recency comparison:** Among remaining records, the one with the highest `RSV_APLY_YMD + GENE_ADD_DTM` concatenation is selected as the latest.

| # | Type | Code | Business Description |
|---|------|------|---------------------|
| 1 | SET | `svcKeiUcwkStat = svKeiUcwkMap.get("SVC_KEI_UCWK_STAT")` | Get status of current record |
| 2 | SET | `geneAddDtm2 = svKeiUcwkMap.get("GENE_ADD_DTM")` | Get generation timestamp of current record |
| 3 | SET | `rsvAplyYmd2 = svKeiUcwkMap.get("RSV_APLY_YMD")` | Get reservation date of current record |

**Block 8.1** — [IF] Status exclusion check (L4080-4082)

> `[SVC_KEI_STAT_DLS_ZM="910"]` or `[SVC_KEI_STAT_CNCL_ZM="920"]` — ステイタスが解約済・キャンセル済の場合 (If status is Resolved or Canceled)

| # | Type | Code | Business Description |
|---|------|------|---------------------|
| 1 | EXEC | `continue` // ステイタスが解約済・キャンセル済の場合 (Skip canceled/resolved records) | Skip this record; do not consider it as a candidate for the active detail |

**Block 8.2** — [ELSE-IF] Recency comparison (L4083-4088)

> `(rsvAplyYmd + geneAddDtm).compareTo(rsvAplyYmd2 + geneAddDtm2) < 0` — If the current record's combined date+timestamp is **greater than** the best so far, replace it.

| # | Type | Code | Business Description |
|---|------|------|---------------------|
| 1 | SET | `svcKeiUcwkNo = svKeiUcwkMap.get("SVC_KEI_UCWK_NO")` | Update best detail number |
| 2 | SET | `geneAddDtm = geneAddDtm2` | Update best generation timestamp |
| 3 | SET | `rsvAplyYmd = rsvAplyYmd2` | Update best reservation date |

**Block 9** — [ELSE-IF] Single record branch (L4090-4094)

If exactly one detail record was returned (not more, not zero), use it directly without comparison.

| # | Type | Code | Business Description |
|---|------|------|---------------------|
| 1 | SET | `svKeiUcwkMap = svKeiUcwkList.get(0)` | Get the single record |
| 2 | SET | `svcKeiUcwkNo = svKeiUcwkMap.get("SVC_KEI_UCWK_NO")` | Extract the detail number |
| 3 | SET | `geneAddDtm = svKeiUcwkMap.get("GENE_ADD_DTM")` | Extract the generation timestamp |

**Block 10** — [IF] Debug logging (L4100-4105)

> `super.logPrint.chkLogLevel(JBSbatLogUtil.MODE_DEBUG)` — If debug log level is enabled

| # | Type | Code | Business Description |
|---|------|------|---------------------|
| 1 | EXEC | `super.logPrint.printDebugLog("サービス契約内訳検索（サービス契約内訳番号）: " + svcKeiUcwkNo)` // サービス契約内訳検索 (Service contract detail search) | Log the selected detail number |
| 2 | EXEC | `super.logPrint.printDebugLog("サービス契約内訳検索（世代登録年月日時分秒）: " + geneAddDtm)` | Log the generation timestamp |

**Block 11** — [RETURN] Result assembly (L4107-4111)

| # | Type | Code | Business Description |
|---|------|------|---------------------|
| 1 | SET | `result = new String[2]` | Create result array |
| 2 | SET | `result[0] = svcKeiUcwkNo` | Service contract detail number |
| 3 | SET | `result[1] = geneAddDtm` | Generation registration datetime |
| 4 | RETURN | `return result` | Return both values to caller |

## 7. Glossary

| Term | Type | Business Meaning |
|------|------|------------------|
| `svc_kei_no` | Field | Service contract number — the unique identifier for a service contract line item in the telecom billing system. |
| `svc_kei_ucwk_no` | Field | Service contract detail number — a unique identifier for each detail record under a service contract. Also known as the service contract inner-division number (サービス契約内訳番号). |
| `gene_add_dtm` | Field | Generation registration datetime — the timestamp when this detail record version was created/registered in the system (世代登録年月日時分秒). Used for version resolution. |
| `rsv_apl_ymd` | Field | Reservation-application date — the date when a reservation or application was applied to this record (予約適用年月日). Used for recency comparison. |
| `svc_kei_ucwk_stat` | Field | Service contract detail status — the current lifecycle status of a service contract detail record. |
| `ope_date` | Field | Batch operation date — the processing date used as a filter in batch queries to ensure records are selected for the correct batch run. |
| `SVC_KEI_STAT_DLS_ZM` | Constant | Status code "910" — 解約済 (Resolved/Closed). The service contract detail has been resolved/closed and should not be considered active. |
| `SVC_KEI_STAT_CNCL_ZM` | Constant | Status code "920" — キャンセル済 (Canceled). The service contract detail has been canceled and should not be considered active. |
| `KK_T_SVC_KEI_UCWK` | Table | Service contract detail table — stores all detail records (line items) for service contracts. Each service contract can have multiple detail records over time. |
| `KK_SELECT_114` | SQL key | SQL definition key used to query `KK_T_SVC_KEI_UCWK` by operation date and service contract number. |
| `svKeiUcwkList` | Variable | List of service contract detail records retrieved from the DB, each stored as a `HashMap<String, String>`. |
| `whereParam` | Variable | Bind parameter array `[opeDate, svcKeiNo]` passed to the DB query executor. |
| `logPrint` | Instance field | Debug logging utility inherited from the parent class. Controls debug log output via `chkLogLevel` and `printDebugLog`. |
