# Business Logic — JBSbatKKBandWidthOverLmtDtTst.execute() [350 LOC]

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

## 1. Role

### JBSbatKKBandWidthOverLmtDtTst.execute()

This method is the primary processing entry point for the **Bandwidth Over-Limit Notification Data Extraction** batch service (model name: `JBSbatKKBandWidthOverLmtDtTst`), which is part of the K-Opticom eo Customer Core System. It determines whether FTTH (Fiber To The Home) customers have exceeded their allocated bandwidth limits over the current or recent months, classifies each customer into one of three notification dispatch categories, and then assembles the appropriate output data records for downstream delivery.

The method classifies each customer into exactly one of three **send categories** (`sendKbn`):
- **`1` (Warning Notice / Yokoku)** — The customer has exceeded their bandwidth limit in the current month only, based on a search of the past 2 consecutive months. A standard notification is prepared.
- **`0` (Follow-up Only / Hikitsugi)** — The customer has exceeded their bandwidth limit for 2 consecutive months, but has NOT exceeded it for 3 consecutive months (i.e., only a continuation notice is sent, no enforcement action yet).
- **`2` (Enforcement Notice / Jishi)** — The customer has exceeded their bandwidth limit for 3 consecutive months, OR had bandwidth control enforced in the previous month. An enforcement notice is sent.

The method implements a **routing/dispatch pattern**: based on the computed `sendKbn`, it branches into two output construction paths. If email addresses are available (from either the ISP contract table or the contact table added in ANK-4468), it builds **KKIFM207** records (email notification format). If no email addresses exist, it builds **KKIFM206** records (invoice/notification format) which include the customer's full postal address and the billing contractor's address. Additionally, if the customer's skilled business code matches a suppressed list from work parameters (ANK-4552), the method locks and updates the FTTH over-limit achievement record with a control suppression flag and returns an empty output, preventing further processing.

This method serves as a **shared batch utility** called by the batch execution framework for scheduled processing. It reads from 7 database tables, queries customer and contract data, and produces output records that are subsequently dispatched either as email notifications or paper billing attachments. The method is the central orchestrator that coordinates all data gathering, decision logic, and output assembly for the bandwidth over-limit notification workflow.

## 2. Processing Pattern (Detailed Business Logic)

```mermaid
flowchart TD
    START(["execute(inMap)"])
    START --> INIT_OUTPUT["Generate outputBean"]
    INIT_OUTPUT --> EXTRACT_PARAMS["Extract svcKeiNo, sysId, pcrsCd, pplanCd, nengetsu from inMap"]
    EXTRACT_PARAMS --> DEFAULT_SEND_KBN["Set sendKbn to SEND_KBN_YOKOKU = 1"]

    DEFAULT_SEND_KBN --> CHECK_2ND_MONTH["Query 2-month consecutive over-limit"]
    CHECK_2ND_MONTH --> HAS_2ND{Has 2nd-month<br/>over-limit records?}
    HAS_2ND -->|Yes| SET_HIKITSUGI["set sendKbn to SEND_KBN_HIKITSUGI = 0"]
    HAS_2ND -->|No| CHECK_PREVIOUS_MONTH
    SET_HIKITSUGI --> CHECK_PREVIOUS_MONTH["Check previous month bandwidth control<br/>KK_SELECT_005"]

    CHECK_PREVIOUS_MONTH --> HAS_PREVIOUS{Previous month<br/>bandwidth control active?}
    HAS_PREVIOUS -->|Yes| SET_JISHI["set sendKbn to SEND_KBN_JISHI = 2"]
    HAS_PREVIOUS -->|No| QUERY_ISP
    HAS_PREVIOUS -->|Yes| QUERY_ISP
    SET_JISHI --> QUERY_ISP["Query ISP contract info<br/>KK_SELECT_062"]

    QUERY_ISP --> QUERY_CONTACT["Query contact emails<br/>CK_T_RRKS_KK_SELECT_012"]
    QUERY_CONTACT --> QUERY_CUST["Query customer info<br/>CK_T_CUST_KK_SELECT_027"]
    QUERY_CUST --> CUST_EXISTS{custInfo<br/>not null?}
    CUST_EXISTS -->|No| THROW_ERR["Throw JBSbatBusinessError"]
    CUST_EXISTS -->|Yes| GET_SCM_JGS["Get scmJgsCd from customer"]

    GET_SCM_JGS --> GET_WORK_LIST["getTikLitYksScmList - get work parameter list"]
    GET_WORK_LIST --> IS_SUPPRESSED{isTikLitYks<br/>check suppressed?}
    IS_SUPPRESSED -->|Yes| LOCK_AND_UPDATE["Lock FTTH record<br/>lockFtthTsrckJsk"]
    LOCK_AND_UPDATE --> PK_UPDATE["Update FTTH record<br/>PKUPDATE"]
    PK_UPDATE --> UPDATE_OK{update cnt >= 1?}
    UPDATE_OK -->|No| THROW_ERR
    UPDATE_OK -->|Yes| RETURN_EMPTY["Return new empty JBSbatOutputItem"]
    RETURN_EMPTY --> END_NODE(["Return outputBean"])
    IS_SUPPRESSED -->|No| QUERY_SVC_LINENUMBER["Query service line details<br/>KK_SELECT_024"]
    QUERY_SVC_LINENUMBER --> SVC_EXISTS{svcKeiKsUwInfo<br/>not null?}
    SVC_EXISTS -->|No| THROW_ERR
    SVC_EXISTS -->|Yes| QUERY_BANDWIDTH["Query bandwidth volume<br/>KK_SELECT_001"]
    QUERY_BANDWIDTH --> BW_EXISTS{tsryoInfo<br/>not null?}
    BW_EXISTS -->|No| THROW_ERR
    BW_EXISTS -->|Yes| DIVIDE_BANDWIDTH["Divide TCHI_TG_TSRYO by 1000000"]
    DIVIDE_BANDWIDTH --> EMAIL_CHECK{Has email<br/>addresses?}
    EMAIL_CHECK -->|Yes| EMAIL_LOOP["Loop: build KKIFM207 output for each email"]
    EMAIL_LOOP --> END_NODE
    EMAIL_CHECK -->|No| INVOICE_PATH["Build KKIFM206 invoice output"]
    INVOICE_PATH --> END_NODE
    THROW_ERR --> END_NODE
```

**Block descriptions:**

1. **Initialization** (lines 217–227): Creates the output bean, extracts service contract number (`svcKeiNo`), system ID (`sysId`), cost code (`pcrsCd`), plan code (`pplanCd`), and FTTH usage month (`nengetsu`) from the input map. Defaults the send category to `"1"` (warning notice).

2. **2-Month Over-Limit Check** (lines 231–240): Queries the `KK_T_FTTH_TSRCK_JSK` table for records where the customer exceeded limits for 2 consecutive months (month offset `-1`). If results exist, `sendKbn` is promoted to `"0"` (follow-up only).

3. **3-Month Over-Limit Check** (lines 247–259): If the previous step set `sendKbn` to `"0"` (following the removal of the 1st-of-month date guard in the OM-2015-0000836 fix), queries for 3 consecutive months of over-limit (month offset `-2`). If results exist, `sendKbn` is promoted to `"2"` (enforcement notice).

4. **Previous Month Bandwidth Control Check** (lines 267–279): Queries the `KK_T_FTTH_TSRCK_JSK` table via `KK_SELECT_005` to determine whether bandwidth control was enforced for the customer in the previous month. If the previous month had enforcement, `sendKbn` is set to `"2"` (enforcement notice for this month too).

5. **ISP Contact Data Query** (lines 284–285): Queries the `KK_T_OP_SVC_KEI` table for ISP contract information, which contains the customer's email address.

6. **Contact Data Query** (ANK-4468) (lines 290–293): Queries the `CK_T_RRKS` (contact/association) table for additional email addresses linked to the customer.

7. **Customer Information Query** (lines 295–301): Queries the `CK_T_CUST` table for the customer's name and other details. If no customer is found, a business error is thrown.

8. **Skilled Business Suppression Check** (ANK-4552) (lines 304–354): Retrieves the customer's skilled business code (`scmJgsCd`), fetches the suppressed business code list from the work parameter management table, and checks if the customer is on the suppression list. If the customer is suppressed, locks the `KK_T_FTTH_TSRCK_JSK` record, sets the bandwidth control suppression flag to `"1"` via a primary key update, and returns an empty output.

9. **Service Line Detail Query** (lines 359–365): Queries the `KK_T_SVKEI_KAISEN_UW` table for service line details (usage location info). Throws error if not found.

10. **Bandwidth Volume Query** (lines 368–381): Queries the `AC_M_TSRYO_CKTCSETE` table for the bandwidth notification volume (in micro-units), converts it to the standard unit by dividing by 1,000,000 with `ROUND_HALF_DOWN`. Throws error if not found.

11. **Email-Based Output Path** (lines 391–442): If any email addresses exist (from either the ISP list or the contact list), iterates through both lists, building **KKIFM207** output records. Deduplicates via `addedMail` hashset. Each record includes service contract number, SYSID, customer name, email address, bandwidth notification volume, and send category.

12. **Invoice-Based Output Path** (lines 446–544): If no email addresses exist, builds a **KKIFM206** invoice output record. Retrieves the billing contract info, assembles full customer address and billing contractor address using `uniteAddress()`, fetches the notification message from work parameters (`JKKBatWorkParamKanriUtil`), replaces placeholders (`%1%` through `%5%`) with customer name and date components, and sets the output.

13. **Return** (line 550): Returns the assembled `outputBean`.

## 3. Parameter Analysis

| No | Parameter Name | Type | Business Description |
|----|---------------|------|---------------------|
| 1 | `inMap` | `JBSbatServiceInterfaceMap` | Input batch parameter container carrying the FTTH service contract details. Must contain: `SVC_KEI_NO` (service contract number identifying the FTTH customer line), `SYSID` (system identifier for the batch run), `PCRS_CD` (cost code identifying the pricing tier), `PPLAN_CD` (plan code identifying the pricing plan), and `FTTH_TUSHIN_USE_YM` (FTTH communication usage year-month for lock/update targeting). |

**Instance fields read by this method:**

| Field | Type | Business Description |
|-------|------|---------------------|
| `super.opeDate` | `String` | Operation date in YYYYMMDD format (inherited from `JBSbatBusinessService`). Used in all DB queries to filter by effective date. |
| `opeDateDay` | `String` | Day portion of operation date (DD). Set during `initial()` — no longer actively used since the OM-2015-0000836 fix removed the 1st-of-month guard, but still defined. |
| `db_KK_T_FTTH_TSRCK_JSK` | `JBSbatSQLAccess` | Database access handle for the FTTH communication over-achievement record table. Used for `KK_SELECT_002`, `KK_SELECT_005`, and the PK update/lock operations. |
| `db_KK_T_OP_SVC_KEI` | `JBSbatSQLAccess` | Database access handle for the option service contract (ISP) table. Used to retrieve ISP email addresses. |
| `db_CK_T_CUST` | `JBSbatSQLAccess` | Database access handle for the customer table. Used to retrieve customer name and skilled business code. |
| `db_KK_T_SVKEI_KAISEN_UW` | `JBSbatSQLAccess` | Database access handle for the service contract line details table. Used to retrieve usage location address information. |
| `db_AC_M_TSRYO_CKTCSETE` | `JBSbatSQLAccess` | Database access handle for the bandwidth over-notification settings table. Used to retrieve the notification volume data. |
| `db_ZM_M_WORK_PARAM_KNRI` | `JBSbatSQLAccess` | Database access handle for the work parameter management table (ANK-4552 addition). Used to retrieve suppressed business codes. |
| `db_CK_T_RRKS` | `JBSbatSQLAccess` | Database access handle for the contact/association table (ANK-4468 addition). Used to retrieve additional contact email addresses. |
| `commonItem` | `JBSbatCommonItem` | Batch common parameter container (inherited). Used to retrieve work parameter messages via `JKKBatWorkParamKanriUtil`. |

## 4. CRUD Operations / Called Services

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

| CRUD | SC / CBS | SC Code | Entity / DB | Operation Description |
|------|----------|---------|-------------|----------------------|
| R | `executeKK_T_FTTH_TSRCK_JSK_KK_SELECT_002` | KK_T_FTTH_TSRCK_JSC | KK_T_FTTH_TSRCK_JSK | Queries the FTTH communication over-achievement table for 2-month or 3-month consecutive over-limit records. Returns a list of matching rows. |
| R | `db_KK_T_FTTH_TSRCK_JSK.selectBySqlDefine(KK_SELECT_005)` | KK_T_FTTH_TSRCK_JSC | KK_T_FTTH_TSRCK_JSK | Queries for previous month bandwidth control enforcement records using a custom SQL define. |
| R | `executeKK_T_OP_SVC_KEI_KK_SELECT_062` | KK_T_OP_SVC_KEI_SC | KK_T_OP_SVC_KEI | Queries the option service contract (ISP) table to retrieve ISP contract records including email addresses. |
| R | `executeCK_T_RRKS_KK_SELECT_012` | CK_T_RRKS_SC | CK_T_RRKS | Queries the contact/association table to retrieve additional contact email addresses (ANK-4468 addition). |
| R | `executeCK_T_CUST_KK_SELECT_027` | CK_T_CUST_SC | CK_T_CUST | Queries the customer table by SYSID to retrieve customer information including name and skilled business code. |
| R | `getTikLitYksScmList / executeZM_M_WORK_PARAM_KNRI_KK_SELECT_019` | ZM_M_WORK_PARAM_KNRI_SC | ZM_M_WORK_PARAM_KNRI | Queries the work parameter management table to retrieve the suppressed skilled business code list. |
| U | `executeKK_T_FTTH_TSRCK_JSK_PKUPDATE` | KK_T_FTTH_TSRCK_JSC | KK_T_FTTH_TSRCK_JSK | Primary key update: sets `TIK_CTL_YOKSI_JSSI_FLG` (bandwidth control suppression flag) to `"1"` for suppressed customers. |
| R | `executeKK_T_SVKEI_KAISEN_UW_KK_SELECT_024` | KK_T_SVKEI_KAISEN_UW_SC | KK_T_SVKEI_KAISEN_UW | Queries the service contract line details table to retrieve usage location information. |
| R | `executeAC_M_TSRYO_CKTCSETE_KK_SELECT_001` | AC_M_TSRYO_CKTCSETE_SC | AC_M_TSRYO_CKTCSETE | Queries the bandwidth over-notification settings table to retrieve the notification volume. |
| R | `executeKK_T_SEIKY_KEI_KK_SELECT_023` | KK_T_SEIKY_KEI_SC | KK_T_SEIKY_KEI | Queries the billing contract table (in invoice output path) to retrieve billing contract details and contractor address. |

## 5. Dependency Trace

The `execute` method is a batch service entry point invoked by the K-Opticom batch execution framework. It is not directly called by other Java application classes (the search returned no external callers). Instead, it is dispatched through the batch service infrastructure (`JBSbatBusinessService`) via the standard batch lifecycle: `initial()` -> `execute()` -> `terminal()`.

| # | Caller (Screen/Batch) | Call Chain (Full Path to this Method) | Terminal (SC / CRUD / Entity) |
|---|----------------------|--------------------------------------|-------------------------------|
| 1 | Batch: JBSbatFramework | `BatchScheduler.invoke` -> `JBSbatBusinessService.execute` -> `JBSbatKKBandWidthOverLmtDtTst.execute` | `KK_T_FTTH_TSRCK_JSK [R/U]`, `KK_T_OP_SVC_KEI [R]`, `CK_T_CUST [R]`, `KK_T_SVKEI_KAISEN_UW [R]`, `AC_M_TSRYO_CKTCSETE [R]`, `CK_T_RRKS [R]`, `ZM_M_WORK_PARAM_KNRI [R]` |

## 6. Per-Branch Detail Blocks

**Block 1** — [SET] Output initialization and parameter extraction (L217–227)

> Creates the output container and extracts core identification fields from the input map.

| # | Type | Code |
|---|------|------|
| 1 | SET | `outputBean = new JBSbatOutputItem()` // Create output container |
| 2 | SET | `svcKeiNo = inMap.getString(JBSbatKK_T_SVC_KEI.SVC_KEI_NO)` // Service contract number [-> SVC_KEI_NO] |
| 3 | SET | `sysId = inMap.getString(JBSbatKK_T_SVC_KEI.SYSID)` // System identifier [-> SYSID] |
| 4 | SET | `pcrsCd = inMap.getString(JBSbatKK_T_FTTH_TSRCK_JSK.PCRS_CD)` // Cost code [-> PCRS_CD] |
| 5 | SET | `pplanCd = inMap.getString(JBSbatKK_T_FTTH_TSRCK_JSK.PPLAN_CD)` // Plan code [-> PPLAN_CD] |
| 6 | SET | `nengetsu = inMap.getString(JBSbatKK_T_FTTH_TSRCK_JSK.FTTH_TUSHIN_USE_YM)` // FTTH usage year-month [-> FTTH_TUSHIN_USE_YM] |

**Block 2** — [SET] Send category default initialization (L230)

> Defaults the dispatch category to "warning notice" before over-limit checks.

| # | Type | Code |
|---|------|------|
| 1 | SET | `sendKbn = SEND_KBN_YOKOKU = "1"` // Default: warning notice [-> SEND_KBN_YOKOKU="1"] |

**Block 3** — [CALL + IF] 2-month consecutive over-limit check (L233–240)

> Queries for 2-month consecutive over-limit (offset `-1`). If found, promotes to follow-up-only status.

| # | Type | Code |
|---|------|------|
| 1 | SET | `setParamFtth2nd = {super.opeDate, "-1", svcKeiNo}` // Query params: opDate, monthOffset, svcKeiNo |
| 2 | CALL | `result2ndList = executeKK_T_FTTH_TSRCK_JSK_KK_SELECT_002(setParamFtth2nd)` // R KK_T_FTTH_TSRCK_JSK |
| 3 | IF | `result2ndList != null && !result2ndList.isEmpty()` |

**Block 3.1** — [IF-THEN] 2-month over-limit found (L236–238)

| # | Type | Code |
|---|------|------|
| 1 | SET | `sendKbn = SEND_KBN_HIKITSUGI = "0"` // Promote to follow-up-only [-> SEND_KBN_HIKITSUGI="0"] |

**Block 4** — [IF] 3-month consecutive over-limit check (L247–260)

> If `sendKbn` is `"0"` (2-month over-limit found), queries for 3-month consecutive over-limit (offset `-2`). Promotes to enforcement if found.

| # | Type | Code |
|---|------|------|
| 1 | IF | `SEND_KBN_HIKITSUGI.equals(sendKbn)` // [-> SEND_KBN_HIKITSUGI="0"] |

**Block 4.1** — [IF-THEN] 3-month over-limit query (L249–259)

| # | Type | Code |
|---|------|------|
| 1 | SET | `setParamFtth3rd = {super.opeDate, "-2", svcKeiNo}` // Query params: opDate, monthOffset, svcKeiNo |
| 2 | CALL | `result3rdList = executeKK_T_FTTH_TSRCK_JSK_KK_SELECT_002(setParamFtth3rd)` // R KK_T_FTTH_TSRCK_JSK |
| 3 | IF | `result3rdList != null && !result3rdList.isEmpty()` |

**Block 4.2** — [IF-THEN-THEN] 3-month over-limit found (L255–257)

| # | Type | Code |
|---|------|------|
| 1 | SET | `sendKbn = SEND_KBN_JISHI = "2"` // Promote to enforcement [-> SEND_KBN_JISHI="2"] |

**Block 5** — [CALL + IF] Previous month bandwidth control check (L265–280)

> Queries `KK_T_FTTH_TSRCK_JSK` via `KK_SELECT_005` to check if the customer had bandwidth control enforced in the previous month. If yes, enforces for current month too.

| # | Type | Code |
|---|------|------|
| 1 | SET | `setParamFtth4th = new JBSbatCommonDBInterface()` |
| 2 | EXEC | `setParamFtth4th.setValue(super.opeDate)` |
| 3 | EXEC | `setParamFtth4th.setValue(svcKeiNo)` |
| 4 | CALL | `this.db_KK_T_FTTH_TSRCK_JSK.selectBySqlDefine(setParamFtth4th, KK_T_FTTH_TSRCK_JSK_KK_SELECT_005)` // R KK_T_FTTH_TSRCK_JSK |
| 5 | SET | `result = this.db_KK_T_FTTH_TSRCK_JSK.selectNext()` |
| 6 | IF | `result != null` |

**Block 5.1** — [IF-THEN] Previous month enforcement detected (L274–276)

| # | Type | Code |
|---|------|------|
| 1 | SET | `sendKbn = SEND_KBN_JISHI = "2"` // Enforce this month too [-> SEND_KBN_JISHI="2"] |

**Block 6** — [CALL] ISP contract / email query (L284–285)

> Retrieves ISP contract records to find email addresses.

| # | Type | Code |
|---|------|------|
| 1 | SET | `setParamOpSvcKeiIsp = {svcKeiNo, super.opeDate}` |
| 2 | CALL | `mlList = executeKK_T_OP_SVC_KEI_KK_SELECT_062(setParamOpSvcKeiIsp)` // R KK_T_OP_SVC_KEI |

**Block 7** — [CALL] Contact/association email query (ANK-4468) (L289–293)

> Retrieves additional contact email addresses from the CK_T_RRKS table.

| # | Type | Code |
|---|------|------|
| 1 | SET | `setParamListContact = {super.opeDate, svcKeiNo, super.opeDate}` |
| 2 | CALL | `mlListContact = executeCK_T_RRKS_KK_SELECT_012(setParamListContact)` // R CK_T_RRKS |

**Block 8** — [CALL + IF] Customer information query (L295–301)

> Retrieves customer data. Throws business error if customer not found.

| # | Type | Code |
|---|------|------|
| 1 | SET | `setParamCust = {sysId, super.opeDate}` |
| 2 | CALL | `executeCK_T_CUST_KK_SELECT_027(setParamCust)` // R CK_T_CUST |
| 3 | SET | `custInfo = db_CK_T_CUST.selectNext()` |
| 4 | IF | `custInfo == null` |

**Block 8.1** — [IF-THEN] Customer not found (L299–301)

| # | Type | Code |
|---|------|------|
| 1 | THROW | `throw new JBSbatBusinessError()` |

**Block 9** — [IF] Skilled business suppression check (ANK-4552) (L304–354)

> Checks if the customer's skilled business code is in the suppression list. If suppressed, locks and updates the FTTH record, then returns empty.

| # | Type | Code |
|---|------|------|
| 1 | SET | `scmJgsCd = custInfo.getString(JBSbatCK_T_CUST.SCM_JGS_CD)` // Customer's skilled business code [-> SCM_JGS_CD] |
| 2 | CALL | `worktTikLitYksScmList = getTikLitYksScmList()` // R ZM_M_WORK_PARAM_KNRI |
| 3 | IF | `worktTikLitYksScmList != null && isTikLitYks(scmJgsCd, worktTikLitYksScmList) == true` |

**Block 9.1** — [IF-THEN] Suppressed customer — lock and update (L310–351)

| # | Type | Code |
|---|------|------|
| 1 | SET | `setMap = new JBSbatCommonDBInterface()` |
| 2 | EXEC | `setMap.setValue(JBSbatKK_T_FTTH_TSRCK_JSK.TIK_CTL_YOKSI_JSSI_FLG, TIK_CTL_YOKSI_JSSI_FLG_1 = "1")` // Set suppression flag [-> TIK_CTL_YOKSI_JSSI_FLG_1="1"] |
| 3 | SET | `whereMap = new JBSbatCommonDBInterface()` |
| 4 | EXEC | `whereMap.setValue(JBSbatKK_T_FTTH_TSRCK_JSK.SVC_KEI_NO, svcKeiNo)` |
| 5 | EXEC | `whereMap.setValue(JBSbatKK_T_FTTH_TSRCK_JSK.PCRS_CD, pcrsCd)` |
| 6 | EXEC | `whereMap.setValue(JBSbatKK_T_FTTH_TSRCK_JSK.PPLAN_CD, pplanCd)` |
| 7 | EXEC | `whereMap.setValue(JBSbatKK_T_FTTH_TSRCK_JSK.FTTH_TUSHIN_USE_YM, nengetsu)` |
| 8 | CALL | `lockFtthTsrckJsk(svcKeiNo, pcrsCd, pplanCd, nengetsu)` // Lock FTTH record for update |
| 9 | CALL | `cnt = executeKK_T_FTTH_TSRCK_JSK_PKUPDATE(setMap, whereMap)` // U KK_T_FTTH_TSRCK_JSK |
| 10 | IF | `cnt < 1` |
| 11 | THROW | `throw new JBSbatBusinessError()` |
| 12 | RETURN | `return new JBSbatOutputItem()` // Return empty — skip further processing |

**Block 10** — [CALL] Service line detail query (L359–365)

> Retrieves the service line details including usage location information.

| # | Type | Code |
|---|------|------|
| 1 | SET | `setParamSvcKeiKsUw = {svcKeiNo}` |
| 2 | CALL | `executeKK_T_SVKEI_KAISEN_UW_KK_SELECT_024(setParamSvcKeiKsUw)` // R KK_T_SVKEI_KAISEN_UW |
| 3 | SET | `svcKeiKsUwInfo = db_KK_T_SVKEI_KAISEN_UW.selectNext()` |
| 4 | IF | `svcKeiKsUwInfo == null` |

**Block 10.1** — [IF-THEN] Service line not found (L363–365)

| # | Type | Code |
|---|------|------|
| 1 | THROW | `throw new JBSbatBusinessError()` |

**Block 11** — [CALL] Bandwidth notification volume query (L368–381)

> Retrieves the bandwidth volume from `AC_M_TSRYO_CKTCSETE`, converts micro-units to standard units.

| # | Type | Code |
|---|------|------|
| 1 | SET | `setParamTsryo = {svcKeiNo, super.opeDate, "1", super.opeDate, super.opeDate, super.opeDate, UPPL_CHOK_TCH_SBT_CD_2 = "2"}` |
| 2 | CALL | `executeAC_M_TSRYO_CKTCSETE_KK_SELECT_001(setParamTsryo)` // R AC_M_TSRYO_CKTCSETE |
| 3 | SET | `tsryoInfo = db_AC_M_TSRYO_CKTCSETE.selectNext()` |
| 4 | IF | `tsryoInfo == null` |
| 5 | THROW | `throw new JBSbatBusinessError()` |
| 6 | SET | `tsryo = tsryoInfo.getBigDecimal(JBSbatAC_M_TSRYO_CKTCSETE.TCHI_TG_TSRYO).divide(new BigDecimal("1000000"), BigDecimal.ROUND_HALF_DOWN)` |
| 7 | IF | `tsryo == null` |
| 8 | THROW | `throw new JBSbatBusinessError()` |

**Block 12** — [IF] Email output path (L392–444)

> If either the ISP list or the contact list has email addresses, build KKIFM207 output records for each unique email.

| # | Type | Code |
|---|------|------|
| 1 | IF | `!mlList.isEmpty() || !mlListContact.isEmpty()` |

**Block 12.1** — [IF-THEN] Email records exist — first loop: ISP emails (L396–428)

| # | Type | Code |
|---|------|------|
| 1 | SET | `addedMail = new HashSet<String>()` // Deduplication hashset |
| 2 | FOR | `i = 0` to `mlList.size()` |
| 3 | SET | `opSvcKeiIspInfo = mlList.get(i)` |
| 4 | SET | `mlad = opSvcKeiIspInfo.getString(JBSbatKK_T_OPSVKEI_ISP.MLAD)` // Email address [-> MLAD] |
| 5 | SET | `kkifm207Map = new JBSbatServiceInterfaceMap()` |
| 6 | EXEC | `kkifm207Map.setString(JBSbatKKIFM207.SVC_KEI_NO, svcKeiNo)` |
| 7 | EXEC | `kkifm207Map.setString(JBSbatKKIFM207.SYSID, sysId)` |
| 8 | EXEC | `kkifm207Map.setString(JBSbatKKIFM207.KEISHA_NM, custInfo.getString(JBSbatCK_T_CUST.CUST_NM))` |
| 9 | EXEC | `kkifm207Map.setString(JBSbatKKIFM207.MLAD, mlad)` |
| 10 | EXEC | `kkifm207Map.setString(JBSbatKKIFM207.TIKI_SGN_TCHI_TSHIRYO, tsryo.toString())` |
| 11 | EXEC | `kkifm207Map.setString(JBSbatKKIFM207.SEND_KBN, sendKbn)` |
| 12 | EXEC | `kkifm207Map.setOutFlg(true)` |
| 13 | EXEC | `outputBean.addOutMapList_2(kkifm207Map)` |
| 14 | EXEC | `addedMail.add(mlad)` // Track for dedup |

**Block 12.2** — [FOR] Second loop: contact emails (ANK-4468) (L430–442)

| # | Type | Code |
|---|------|------|
| 1 | FOR | `i = 0` to `mlListContact.size()` |
| 2 | SET | `opSvcKeiIspInfoFromContact = mlListContact.get(i)` |
| 3 | SET | `mlad = opSvcKeiIspInfoFromContact.getString(JBSbatKK_T_OPSVKEI_ISP.MLAD)` |
| 4 | IF | `!addedMail.contains(mlad) && !"".equals(mlad) && mlad != null` // Dedup + non-empty check |

**Block 12.2.1** — [IF-THEN] New unique email from contact (L432–442)

| # | Type | Code |
|---|------|------|
| 1 | SET | `kkifm207Map = new JBSbatServiceInterfaceMap()` |
| 2 | EXEC | `kkifm207Map.setString(JBSbatKKIFM207.SVC_KEI_NO, svcKeiNo)` |
| 3 | EXEC | `kkifm207Map.setString(JBSbatKKIFM207.SYSID, sysId)` |
| 4 | EXEC | `kkifm207Map.setString(JBSbatKKIFM207.KEISHA_NM, custInfo.getString(JBSbatCK_T_CUST.CUST_NM))` |
| 5 | EXEC | `kkifm207Map.setString(JBSbatKKIFM207.MLAD, mlad)` |
| 6 | EXEC | `kkifm207Map.setString(JBSbatKKIFM207.TIKI_SGN_TCHI_TSHIRYO, tsryo.toString())` |
| 7 | EXEC | `kkifm207Map.setString(JBSbatKKIFM207.SEND_KBN, sendKbn)` |
| 8 | EXEC | `kkifm207Map.setOutFlg(true)` |
| 9 | EXEC | `outputBean.addOutMapList_2(kkifm207Map)` |

**Block 13** — [ELSE] Invoice output path (L446–546)

> No email addresses found. Build a KKIFM206 invoice notification output instead.

| # | Type | Code |
|---|------|------|
| 1 | IF | `SEND_KBN_YOKOKU.equals(sendKbn) || SEND_KBN_JISHI.equals(sendKbn)` |

**Block 13.1** — [IF-ELSE] Determine work parameter code (L451–461)

| # | Type | Code |
|---|------|------|
| 1 | IF | `SEND_KBN_YOKOKU.equals(sendKbn)` // [-> SEND_KBN_YOKOKU="1"] |
| 2 | SET | `gymPrmCd = GYM_KNR_PRM_CD_YKK = "KK_TIK_LMT_YKK_TCH"` // Warning notice message code |
| 3 | ELSE IF | `SEND_KBN_JISHI.equals(sendKbn)` // [-> SEND_KBN_JISHI="2"] |
| 4 | SET | `gymPrmCd = GYM_KNR_PRM_CD_JSSI = "KK_TIK_LMT_JSSI_TCH"` // Enforcement notice message code |
| 5 | IF | `tsryoInfo.getBigDecimal(JBSbatAC_M_TSRYO_CKTCSETE.TCHI_TG_TSRYO) != null` |
| 6 | SET | `tsryoMsg = tsryo.toString()` |
| 7 | ELSE | `tsryoMsg = ""` |
| 8 | CALL | `msg = JKKBatWorkParamKanriUtil.getWorkParamSetteValue(commonItem, gymPrmCd)` // Get template message |
| 9 | EXEC | `msg = msg.replaceAll("%1%", custInfo.getString(JBSbatCK_T_CUST.CUST_NM))` // Replace customer name |
| 10 | EXEC | `msg = msg.replaceAll("%2%", super.opeDate.substring(0, 4))` // Year |
| 11 | EXEC | `msg = msg.replaceAll("%3%", super.opeDate.substring(4, 6))` // Month |
| 12 | EXEC | `msg = msg.replaceAll("%4%", super.opeDate.substring(6, 8))` // Day |
| 13 | EXEC | `msg = msg.replaceAll("%5%", tsryoMsg)` // Bandwidth volume |

**Block 13.2** — [CALL] Billing contract query (L468–476)

| # | Type | Code |
|---|------|------|
| 1 | SET | `paramSetSeikyKei = {svcKeiNo, super.opeDate}` |
| 2 | CALL | `executeKK_T_SEIKY_KEI_KK_SELECT_023(paramSetSeikyKei)` // R KK_T_SEIKY_KEI |
| 3 | SET | `seikyKeiInfo = db_KK_T_SEIKY_KEI.selectNext()` |
| 4 | IF | `seikyKeiInfo == null` |
| 5 | THROW | `throw new JBSbatBusinessError()` |

**Block 13.3** — [SET] KKIFM206 output assembly (L480–542)

| # | Type | Code |
|---|------|------|
| 1 | SET | `kkifm206Map = new JBSbatServiceInterfaceMap()` |
| 2 | EXEC | `kkifm206Map.setString(JBSbatKKIFM206.SVC_KEI_NO, svcKeiNo)` |
| 3 | EXEC | `kkifm206Map.setString(JBSbatKKIFM206.SYSID, sysId)` |
| 4 | EXEC | `kkifm206Map.setString(JBSbatKKIFM206.SEIKY_KEI_NO, seikyKeiInfo.getString(JBSbatKK_T_SEIKY_KEI.SEIKY_KEI_NO))` |
| 5 | EXEC | `kkifm206Map.setString(JBSbatKKIFM206.KEISHA_NM, custInfo.getString(JBSbatCK_T_CUST.CUST_NM))` |
| 6 | EXEC | `kkifm206Map.setString(JBSbatKKIFM206.KEISHA_PCD, custInfo.getString(JBSbatCK_T_CUST.KEISHA_PCD))` |
| 7 | CALL | `keiShaAdd = uniteAddress(stateNm, cityNm, oaztsu, azchoNm, adrTtm, adrRm, bnchigo)` // Assemble customer address |
| 8 | EXEC | `kkifm206Map.setString(JBSbatKKIFM206.KEISHA_ADD, keiShaAdd)` |
| 9 | EXEC | `kkifm206Map.setString(JBSbatKKIFM206.SEIKY_SOHUS_NM, seikyKeiInfo.getString(JBSbatKK_T_SEIKY_KEI.SOHUS_NM))` |
| 10 | EXEC | `kkifm206Map.setString(JBSbatKKIFM206.SEIKY_SOHUS_PCD, seikyKeiInfo.getString(JBSbatKK_T_SEIKY_KEI.SOHUS_PCD))` |
| 11 | CALL | `sohusAdd = uniteAddress(seiky_state, seiky_city, seiky_oaztsu, seiky_azcho, seiky_adrttm, seiky_adrrm, seiky_bnchigo)` // Assemble contractor address |
| 12 | EXEC | `kkifm206Map.setString(JBSbatKKIFM206.SEIKY_SOHUS_ADD, sohusAdd)` |
| 13 | EXEC | `kkifm206Map.setString(JBSbatKKIFM206.RIYO_BSH_PCD, svcKeiKsUwInfo.getString(JBSbatKK_T_SVKEI_KAISEN_UW.KAISEN_PLACE_PCD))` |
| 14 | CALL | `riyoAdd = uniteAddress(riyo_state, riyo_city, riyo_oaztsu, riyo_azcho, riyo_adrttm, riyo_adrrm, riyo_bnchigo)` // Assemble usage location address |
| 15 | EXEC | `kkifm206Map.setString(JBSbatKKIFM206.RIYO_BSH_ADD, riyoAdd)` |
| 16 | EXEC | `kkifm206Map.setString(JBSbatKKIFM206.TCHI_MSG, msg)` |
| 17 | EXEC | `kkifm206Map.setOutFlg(true)` |
| 18 | EXEC | `outputBean.addOutMapList(kkifm206Map)` |

**Block 14** — [RETURN] Final return (L550)

| # | Type | Code |
|---|------|------|
| 1 | RETURN | `return outputBean` // Return assembled output |

## 7. Glossary

| Term | Type | Business Meaning |
|------|------|------------------|
| `svc_kei_no` | Field | Service contract number — the unique identifier for a customer's FTTH service line contract |
| `sys_id` | Field | System identifier — the system code used to identify the processing system within the batch framework |
| `pcrs_cd` | Field | Cost code — pricing tier code that identifies the customer's billing cost structure |
| `pplan_cd` | Field | Plan code — pricing plan code that identifies the specific service plan the customer has subscribed to |
| `nengetsu` / `ftth_tushin_use_ym` | Field | FTTH communication usage year-month — the month for which over-achievement records are locked/updated |
| `send_kbn` | Field | Send category — dispatch classification: `"1"` = Warning Notice (Yokoku), `"0"` = Follow-up Only (Hikitsugi), `"2"` = Enforcement Notice (Jishi) |
| `send_kbn_yokoku` | Constant | Dispatch category value `"1"` — Warning notice, sent when customer has exceeded bandwidth in the current month only |
| `send_kbn_hikitsugi` | Constant | Dispatch category value `"0"` — Follow-up only, sent when customer has exceeded limits for 2 consecutive months but not 3 |
| `send_kbn_jishi` | Constant | Dispatch category value `"2"` — Enforcement notice, sent when customer has exceeded limits for 3 consecutive months or had previous-month enforcement |
| `gym_prm_cd_ykk` | Constant | Work parameter code `"KK_TIK_LMT_YKK_TCH"` — Message template key for warning notice notifications |
| `gym_prm_cd_jssi` | Constant | Work parameter code `"KK_TIK_LMT_JSSI_TCH"` — Message template key for enforcement notice notifications |
| `scm_jgs_cd` | Field | Skilled business code (Skilled Market Business Provider Code) — identifies the skilled business provider type for the customer; used in suppression logic |
| `tik_ctl_yoksi_jssi_flg` | Field | Bandwidth control suppression implementation flag — when set to `"1"`, suppresses further processing for customers on the suppression list |
| `tik_ctl_yoksi_jssi_flg_1` | Constant | Suppression flag value `"1"` — indicates suppression enforcement is active |
| `t_c_y_scm_jgs_cd` | Constant | Work parameter ID `"T_C_Y_SCM_JGS_CD"` — the parameter key used to look up suppressed skilled business codes in the work parameter table |
| `uppl_chok_tch_sbt_cd_2` | Constant | Upper limit notification type code `"2"` — identifies the bandwidth over-notification setting configuration |
| `tchi_tg_tsryo` | Field | Total communication volume — the bandwidth usage volume in micro-units (divided by 1,000,000 for display) |
| `mlad` | Field | Mail address — the customer's email address stored in the ISP contract table |
| `keisha_nm` | Field | Company/customer name — the registered name of the customer |
| `keisha_pcd` | Field | Company postal code — the customer's postal code |
| `keisha_add` | Field | Company address — assembled customer address from 7 sub-fields (prefecture, city, district, block/chome, building name, room number, landmark) |
| `seiky_kei_no` | Field | Billing contract number — the contract number associated with the billing/invoice |
| `sohus_nm` / `sohus_pcd` / `sohus_add` | Field | Billing contractor name/postal code/address — the name and full address of the invoice addressee |
| `riyo_bsh_pcd` / `riyo_bsh_add` | Field | Usage location postal code/address — the address of the service usage location |
| `tchi_msg` | Field | Notification message — the dynamically generated notification text with placeholders replaced |
| KKIFM206 | Entity/Format | Invoice notification output format — used when no email is available; includes full billing and address details |
| KKIFM207 | Entity/Format | Email notification output format — used when email addresses are available; simpler record with just essential fields |
| KK_T_FTTH_TSRCK_JSK | DB Table | FTTH Communication Over-Achievement Record — stores FTTH bandwidth usage over-limit records, used for consecutive-month checks and suppression flag updates |
| KK_T_OP_SVC_KEI | DB Table | Option Service Contract Table — stores ISP (internet service provider) contract records including email addresses |
| CK_T_CUST | DB Table | Customer Table — stores customer master data including name, address, postal code, and skilled business code |
| KK_T_SVKEI_KAISEN_UW | DB Table | Service Contract Line Details Table — stores service line-specific information including usage location details |
| AC_M_TSRYO_CKTCSETE | DB Table | Bandwidth Over-Notification Settings Table — stores bandwidth usage notification volume configuration |
| CK_T_RRKS | DB Table | Contact/Association Table — stores additional contact information including email addresses linked to customers (added in ANK-4468) |
| ZM_M_WORK_PARAM_KNRI | DB Table | Work Parameter Management Table — stores operational parameters including suppression business codes (added in ANK-4552) |
| FTTH | Business term | Fiber To The Home — fiber-optic internet service offered by K-Opticom |
| ISP | Business term | Internet Service Provider — the internet access service component of the FTTH contract |
| Bandwidth Control | Business process | Enforcement mechanism where customers exceeding their allocated bandwidth for multiple consecutive months are subject to throttling; the batch service determines whether to notify customers about this |
| Skilled Business | Business term | Skilled Market Provider — a specialized service provider type in the Japanese telecom domain; certain skilled business types may be excluded (suppressed) from bandwidth control enforcement |
| JBSbatBusinessError | Exception | Custom business exception thrown when required data is missing (customer not found, service line not found, bandwidth data missing, or update fails) |
| ANK-4468 | Change ticket | Addition for "eo Hikari Simple Plan" — added contact table (CK_T_RRKS) email query and deduplicated multi-email output support |
| ANK-4552 | Change ticket | Suppression response for specific users — added skilled business code comparison against work parameter suppression list, with lock/update on FTTH over-achievement record |
| KT1-2013-0000794 | Change ticket | Previous month bandwidth control check — added KK_SELECT_005 query to detect if control was enforced last month |
| OM-2015-0000836 | Change ticket | Removed 1st-of-month band restriction — removed the `opeDateDay != "01"` guard from the 3-month over-limit check so enforcement runs even on the 1st of the month |
