# FUW02101SFLogic

## Purpose

`FUW02101SFLogic` is the central business-logic controller for the **Mailbox Contract Capacity Addition Request** flow (Service ID: `FUSV0051` / `FUSV0052`). It orchestrates the full three-screen user journey — initial display, confirmation review, and submission — that allows existing customers to request additional mailbox storage capacity for their plan. This class handles data retrieval, pricing calculations, option selection generation, downstream service invocation, and error translation.

## Design

This class follows the **screen controller / action logic** pattern common to the X31 web framework. It extends `JCCWebBusinessLogic` and acts as a facade over multiple downstream services and data mappers. The class manages a request lifecycle across three pages:

1. **Initial Display (init)** — loads customer contract data, calls pricing/read-only services (FUSV0051), builds the option UI (capacity tiers with costs), and renders the selection screen (`FUW02101`).
2. **Confirmation Submit (cfm)** — validates the selected capacity, invokes the full submission service chain (FUSV0052), updates subscription statuses, and navigates to the confirmation-complete screen (`FUW02102`).
3. **Submit Confirm (mskm)** — re-invokes the submission service chain (used when the user clicks the "submit" button on the confirmation screen), sends completion email, refreshes customer data, and navigates to the completion screen (`FUW02103`).
4. **Back (back)** — returns from the confirmation screen to the initial display screen, recalculating the pay flag.

## Key Methods

### `init()` → `boolean` (lines 113–258)

**Purpose:** Entry point for the initial display screen. Always returns `true` to signal successful navigation.

**What it does:**

1. **Device check** — calls `JFUWebCommon.checkOrosi(this)` to verify the requesting device (legacy device compatibility check).
2. **Customer contract data extraction** — retrieves the common info bean and calls `getCommoninfoBeanInfo()` to extract a structured map containing:
   - `ssoInfoBean` — SSO authentication info
   - `svcKeiInfoBean` — main service contract info
   - `opSvcKeiInfoBean` — option service contract info
   - `sbopSvcKeiInfoBean` — sub-option service contract info
   - `seikyKeiInfoBean` — billing contract info
3. **Service data validation** — calls `checkSvcData()` to verify the option service info exists and is valid (throws `ERROR_CODE_0102` if null).
4. **Initial display service call (FUSV0051)** — builds a parameter map with `USECASE_ID_FUSV0051`, creates an `FUSV0051_FUSV0051OPDBMapper`, and invokes two read-only service segments:
   - `setFUSV005101SC` — Pricing cost / sub-option service agreement consent
   - `setFUSV005102SC` — Fixed unit price (option application fee) list
   - Followed by `setFUSV005101CC` — Initial fee list CC
5. **Service invocation** — wraps the call in `invokeService(paramMap, dataMap, outputMap)` inside a try/catch; translates `JCCWebServiceException` to `ERROR_CODE_0002` (system error).
6. **Response mapping** — calls `getFUSV005101SC()` and `getFUSV005102SC()` to extract results back into the service form bean.
7. **Screen data setup** — sets the current POP ID, mail address, and current mailbox capacity from the option service info bean into the form bean.
8. **Mansion division flag** — calls `getMansionDiv()` to determine if this is a mansion (multi-unit building) plan.
9. **Capacity validation** — computes the possible additional capacity (`mlboxMaxCapa - mlboxCapa`) and validates:
   - If ≤ 0: throws `ERROR_CODE_0103` (contract complete error — no more capacity can be added)
   - If current capacity > 200: throws `ERROR_CODE_0102` (contract state error — user is over the eligible limit)
10. **New/add division flag** — if `sbopSvcKeiInfoBean` is null, marks this as a new addition (`newAddDiv = true`).
11. **Option data generation** — calls `createOptionData()` to build the capacity selection option buttons with pricing tiers.
12. **Pay flag calculation** — calls `setPayFlg()` to determine if the request is paid or free; if free, sets zero-cost display info.
13. **Price table mapping** — calls `JFUWebCommon.setPrcInfoArea()` to map pricing data for both the option application fee SC and the initial fee CC, plus sets the display date.
14. **Navigation setup** — sets the next screen ID via `JFUWebCommon.getScreenId(this)` and the screen name `SCREEN_NAME_FUW02101`.

**Return:** Always `true`.

**Side effects:** Populates `ServiceFormBean` with display-ready data, option lists, and pricing information for the view layer.

---

### `cfm()` → `boolean` (lines 266–415)

**Purpose:** Handles the **confirmation button** press on the initial selection screen. Validates the user's capacity choice and invokes the submission service.

**What it does:**

1. **Data extraction** — retrieves contract info from the common info bean (same pattern as `init()`).
2. **Selected capacity parsing** — reads the user's selected capacity from the `ADD_CAPA_LIST` array in the form bean:
   - `selectValue` — the selected capacity type value
   - `gokei_capa` — total capacity after addition
   - `mskm_capa` — formatted application capacity
3. **Mansion division handling** — if the pricing group is `CD00133_04` (eo Light Net Mansion Type) and the payment method is `CD01216_003` (mansion-wide), it recalculates the mansion division flag based on whether the total capacity exceeds the free allowance.
4. **Added capacity calculation** — computes the added capacity amount (`gokei_capa - base capacity`).
5. **Pay flag recalculation** — if the original pay flag was set, recalculates based on whether total capacity exceeds free allowance.
6. **Service invocation (FUSV0052)** — invokes the full submission service chain using `FUSV0052_FUSV0052OPDBMapper` with the following segments (SC phase):
   - `setFUSV005201SC` — Application content acceptance registration
   - `setFUSV005202SC` — Option service contract (ISP) information change
   - `setFUSV005203SC` — Sub-option service contract (ISP) registration
   - `setFUSV005209SC` — Sub-option service contract (ISP) lookup
   - `setFUSV005204SC` — Sub-option service contract (ISP) lookup conclusion
   - `setFUSV005205SC` — Sub-option service contract (ISP) usage start
   - `setFUSV005206SC` — Sub-option service contract (ISP) modification
   - `setFUSV005207SC` — Progress registration
   - `setFUSV005208SC` — Application detail lookup / follow-up business委托
7. **Completion phase (CC)** — calls the corresponding CC methods to finalize agreements, handle service IF data, and issue service order data.
8. **Option service contract status** — calls `JFUWebCommon.setOpSvcKeiStatMail()` to set the option service contract status.
9. **Service invocation** — calls `invokeService()` with try/catch. Errors are handled by `checkException()` rather than rethrowing directly.
10. **Navigation** — sets next screen to `SCREEN_ID_FUW02102` / `SCREEN_NAME_FUW02102` (the confirmation complete screen).

**Return:** Always `true`.

---

### `mskm()` → `boolean` (lines 423–522)

**Purpose:** Handles the **"submit" button** on the confirmation screen. This is the final submission action that commits the capacity addition request.

**What it does:**

1. **Common relation check** — calls `JFUCommonRelationCheck.checkCommonRelation(this, USECASE_ID_FUSV0052)` to verify session integrity and guard against stale data or unauthorized access.
2. **Data extraction** — same contract info retrieval as `cfm()`.
3. **Service invocation** — uses the same `FUSV0052_FUSV0052OPDBMapper` with the same 9 SC + 5 CC segments as `cfm()`, but uses `FUNC_CD_1` instead of `FUNC_CD_2` (the submit path).
4. **Email dispatch** — calls `JFUWebCommon.sendMskmFinMail(this, MSKM_COMP_MAIL_ID)` to send the application completion notification email (mail ID: `FUW021_1`).
5. **Customer refresh** — calls `JFUWebCommon.refreshGenCustKei(this)` to refresh the current customer data after the contract update.
6. **Navigation** — sets next screen to `SCREEN_ID_FUW02103` / `SCREEN_NAME_FUW02103` (the submission completion screen).

**Return:** Always `true`.

---

### `back()` → `boolean` (lines 530–550)

**Purpose:** Handles the **"return" button** on the confirmation screen, navigating back to the initial display screen.

**What it does:**

1. Retrieves common info and service form beans.
2. Sets the next screen ID to `FUW02101` (initial display).
3. Recalculates the pay flag via `setPayFlg()` to reflect the original state (since no submission occurred).
4. Returns `true`.

This is the simplest method in the class — essentially a navigation + pay flag recalculation.

---

### `checkSvcData(Map<String, Object> resultMap)` → `void` (lines 557–572)

**Purpose:** Validates that the option service info bean exists and is valid before proceeding.

**Logic:** Extracts `opSvcKeiInfoBean` from the resultMap. If it is `null`, throws `ERROR_CODE_0102` (contract state error). This guards against users who somehow reach the page without a valid active option service contract.

---

### `createOptionData(X31SDataBeanAccess bean, HashMap<String, Object> outputMap)` → `void` (lines 580–710)

**Purpose:** Generates the **capacity addition option buttons** and associated pricing data that the user sees on the initial display screen.

**Logic:**

1. Extracts the **current mailbox capacity** (`baseValue`), **free allowance** (`freeValue`), **capacity increment** (`addValue`), **max total capacity** (`endValue`), and **fixed unit price** (`tanka`).
2. Iterates through capacity tiers (using `addValue` as the step):
   - For each tier, computes the total capacity (`goukeiCapa = baseValue + addCapa`) and the **additional cost**.
   - If total capacity ≤ free allowance, cost is `0` (free).
   - If base capacity ≥ free value, cost = `tanka * (goukeiCapa - baseValue) / addValue`.
   - Otherwise, cost = `tanka * (goukeiCapa - freeValue) / addValue`.
3. Builds UI display text for each option:
   - Capacity values under 1024 MB show in MB format.
   - Values ≥ 1024 MB convert to GB (2 decimal places rounded down, then 1 decimal place rounded up).
   - Format: `"[added]MB (total mailbox capacity [total])"`
4. Populates `ADD_CAPA_LIST` array in the form bean with each option.
5. Builds a `dataList` of price map entries for `JFUWebCommon.setPrcInfoArea()` to consume later. Price entries are either `"0"` (first entry), `JFUStrConst.FREE_LABEL` (within free allowance), or the actual amount.
6. Stores the price list in `outputMap` under the key `EKK0601B001_LIST` at path `SC_TITLE_FUSV005102`.

**Side effects:** Modifies the service form bean by populating the option list; populates `outputMap` with pricing data for the view layer.

---

### `getCommoninfoBeanInfo(X31SDataBeanAccess commoninfoBean)` → `Map<String, Object>` (lines 719–837)

**Purpose:** Extracts and filters the customer's contract hierarchy from the shared common info bean. This is a critical data preparation method that navigates nested data beans to find the right option service and sub-option service records.

**Extraction path:**

```
commoninfoBean
  → WEB_CHG_INFO[0]
    → SSO_INFO[0]              → ssoInfoBean, ssoInfoSysid, ssoInfoPopid
    → GEN_CUST_KEI_INFO[0]
      → SVC_KEI_INFO[0]
        → SVC_KEI_UCWK_INFO[0]
          → OP_SVC_KEI_INFO[]  → filter to find matching opSvcKeiInfoBean
            → SBOP_SVC_KEI_INFO[] → filter to find matching sbopSvcKeiInfoBean
        → SEIKY_KEI_INFO[0]    → seikyKeiInfoBean
```

**Filtering logic for option service (opSvcKeiInfoBean):**
- Iterates through the option service info array.
- Matches records where `opSvcKeiStat` is `020` (lookup complete), `030` (concluded), or `100` (service in progress).
- AND `ssoInfoPopid.equals(popId)` AND `opSvCd == "B001"` (E-Mail).
- The first matching record is used.

**Filtering logic for sub-option service (sbopSvcKeiInfoBean):**
- Only populated if an option service was found.
- Validates that the option service has an `opSvcKeiNo` set (throws `ERROR_CODE_0002` if missing).
- Iterates through the sub-option array, skipping records with status `910` (canceled) or `920` (cancelled).
- Matches where `opSvcKeiNo` equals the option's `opSvcKeiNo` AND `sbopSvCd == "D02"` (mail capacity addition).

**Returns:** A `Map<String, Object>` with keys: `SYSID_21`, `POP_ID_21`, `SSO_INFO`, `GEN_CUST_KEI_INFO`, `SVC_KEI_INFO`, `SVC_KEI_UCWK_INFO`, `SEIKY_KEI_INFO`, `OP_SVC_KEI_INFO`, `SBOP_SVC_KEI_INFO`.

---

### `getMansionDiv(...)` → `boolean` (lines 847–874)

**Purpose:** Determines whether this is a **mansion (multi-unit building) plan**. Returns `true` if the customer is on a mansion-wide contract with applicable charges; `false` otherwise.

**Logic:**
- Checks if the pricing group code is `CD00133_04` (eo Light Net Mansion type) AND the payment method is `CD01216_003` (mansion-wide).
- If both match AND either the fixed unit price or initial fees are charged, returns `false` (sets the flag indicating "not mansion-style display").
- Returns `false` by default.

---

### `checkException(JCCWebServiceException se)` → `void` (lines 881–932)

**Purpose:** Translates low-level service exceptions into business-level errors. Extracts template ID, item ID, status, and error flags from the exception's message metadata and maps them to specific business exceptions.

**Error mappings:**

| Template ID | Error Flag | Item ID | Mapped Error | Meaning |
|---|---|---|---|---|
| `EKK0361C050` (Option service contract - ISP info change) | `RELATION_CHECK_ERR_EB` (contract complete) | `CAPA` | `ERROR_CODE_0103` | Contract complete — cannot add more capacity |
| `EKK0361C050` | `RELATION_CHECK_ERR_EA` (update impossible) | `UPD_DTM_BF` | `ERROR_CODE_0204` | Update impossible — stale data |
| `EKK0411D010` (Sub-option service contract - ISP registration) | `RELATION_CHECK_ERR_EA` | `ADD_CAPA` | `ERROR_CODE_0102` | Contract state error |
| `EKK0411C010` (Sub-option service contract - ISP change) | `RELATION_CHECK_ERR_EJ` | `SBOP_SVC_KEI_NO` | `ERROR_CODE_0102` | Contract state error |

Any unmatched exception defaults to `ERROR_CODE_0002` (system error).

---

### `setPayFlg(...)` → `boolean` (lines 941–967)

**Purpose:** Determines whether the capacity addition request is **paid** (`true`) or **free** (`false`).

**Logic:**
- If `chkPayKoteiTanka()` returns true (fixed unit price > 0):
  - If free capacity < max capacity → `true` (paid)
  - Otherwise → `false` (free, within free allowance)
- If no fixed unit price → `false` (free)

---

### `chkPayKoteiTanka(...)` → `boolean` (lines 974–987)

**Purpose:** Simple check — returns `true` if the fixed unit price (`PPLAN_KOTEI_AMNT`) is greater than zero, meaning charges apply. Returns `false` if it's zero (free).

---

### `chkPayInitialCost(HashMap outputMap)` → `boolean` (lines 995–1023)

**Purpose:** Checks whether the **initial fee list** contains any entries (indicating charges are applicable).

**Logic:**
- Looks up the key `CC_TITLE_FUSV005101` from the outputMap.
- Within that, checks for the `EKK0721A010_LIST` key.
- If the list exists and has items → `true` (initial fees exist); otherwise `false`.

## Relationships

```mermaid
flowchart TD
    WebController["WEBGAMEN_FUW021010PJP<br/>Initial Display Controller"] --> FUW02101SFLogic["FUW02101SFLogic<br/>Mail Capacity Addition Request Logic"]
    ConfirmScreen["WEBGAMEN_FUW021020PJP<br/>Confirmation Screen Controller"] --> FUW02101SFLogic
    CompleteScreen["WEBGAMEN_FUW021030PJP<br/>Completion Screen Controller"] --> FUW02101SFLogic
    BusinessLogicX31["x31business_logic_FUW02101SF.xml<br/>Business Logic Configuration"] --> FUW02101SFLogic

    FUW02101SFLogic --> JCCWebBusinessLogic["JCCWebBusinessLogic<br/>Base Web Business Logic"]
    FUW02101SFLogic --> FUSV0051Mapper["FUSV0051_FUSV0051OPDBMapper<br/>Initial Display Mapper"]
    FUW02101SFLogic --> FUSV0052Mapper["FUSV0052_FUSV0052OPDBMapper<br/>Submit/Confirm Mapper"]
    FUW02101SFLogic --> JFUWebCommon["JFUWebCommon<br/>Shared Web Utilities"]
```

**Inbound connections (4):**

| Dependent | Role |
|---|---|
| `WEBGAMEN_FUW021010PJP.xml` | Initial display screen controller — invokes `FUW02101SFLogic.init()` to populate the capacity addition request form |
| `WEBGAMEN_FUW021020PJP.xml` | Confirmation screen controller — invokes `cfm()` or `mskm()` for the submission path |
| `WEBGAMEN_FUW021030PJP.xml` | Completion screen controller — invoked after successful submission |
| `x31business_logic_FUW02101SF.xml` | Business logic configuration — wires the service ID, usecase mapping, and error handling |

**Outbound dependencies:**
- `JCCWebBusinessLogic` — the base class providing `invokeService()`, `getCommonInfoBean()`, `getServiceFormBean()`, and shared utility methods.

## Usage Example

This class is used as part of a three-step web flow:

```
1. User navigates to the mailbox capacity addition page
   → WEBGAMEN_FUW021010PJP.xml invokes init()
   → init() loads contract data, calls FUSV0051 service, builds option buttons
   → Renders the selection screen with capacity options and pricing

2. User selects a capacity and clicks "Next" (confirmation)
   → WEBGAMEN_FUW021020PJP.xml invokes cfm()
   → cfm() validates selection, calls FUSV0052 service (2 segments)
   → Renders the confirmation screen

3. User confirms and clicks "Submit"
   → WEBGAMEN_FUW021020PJP.xml invokes mskm()
   → mskm() calls FUSV0052 service (full chain), sends completion email
   → Navigates to completion screen (FUW02103)
```

Each method returns `true` to signal successful navigation. Errors are thrown as `JCCBusinessException` with specific error codes (`0102` = contract state error, `0103` = contract complete, `0204` = update impossible, `0002` = system error).

## Notes for Developers

- **Thread safety:** This class is not thread-safe. Each HTTP request creates a new instance (per the X31 framework lifecycle). The instance fields are none — only static constants are shared.
- **No instance state:** The class has no non-static fields. All data flows through method parameters, the inherited bean objects, and local variables. This makes it safe to call methods in sequence within a single request.
- **Error handling asymmetry:** `init()` catches `JCCWebServiceException` and always rethrows as `ERROR_CODE_0002` (system error). In contrast, `cfm()` and `mskm()` pass exceptions to `checkException()` which maps specific error templates to business-level codes. This asymmetry exists because `init()` only calls read-only services (FUSV0051), while `cfm()`/`mskm()` call write services (FUSV0052) that can produce domain-specific errors.
- **Capacity conversion:** The 1024 MB threshold for GB conversion is used consistently. The conversion applies `ROUND_DOWN` to 2 decimal places, then `ROUND_UP` to 1 decimal place — e.g., 1536 MB → 1.50 GB → 1.5 GB.
- **Free capacity logic:** A customer's "free capacity" (`MRYO_CAPA`) determines whether any addition costs apply. The free allowance can cover some or all of the requested addition. The system handles partial charge cases correctly (cost = unit price × charged portion / increment).
- **Mansion plan special handling:** Customers on mansion-wide contracts (`CD00133_04`) have special pay flag and division logic. The `getMansionDiv()` method is called to determine whether certain UI elements should be displayed.
- **The `newAddDiv` flag** — set based on whether `sbopSvcKeiInfoBean` is null. This indicates whether this is a first-time capacity addition versus a subsequent one.
- **Next screen IDs are hardcoded** as constants referenced via `JFUScreenConst` — changing the screen flow requires updating both this class and the corresponding `JFUScreenConst` values.
