# FUW02201SFLogic

## Purpose

`FUW02201SFLogic` is the central business logic controller for the **Mail Virus Check Service Subscription** screen in the K-Opticom web platform. It handles the complete lifecycle of a user subscribing to a mail virus protection add-on service — from initial screen display (showing pricing, plan details, and contract terms) through user confirmation and final submission, including sending a completion notification email. This class sits at the intersection of the presentation layer and the backend service layer for subscription screens `FUW02201` (price display/confirmation), `FUW02202` (confirmation), and `FUW02203` (completion).

## Design

This class follows the **Controller** pattern within a web MVC architecture. It extends `JCCWebBusinessLogic`, which provides the base framework for web-facing business logic (service invocation, bean access, and exception handling). The class orchestrates three main activities:

1. **Initialization (`init`)** — Validates the user's current contract state, navigates a deeply nested bean hierarchy to extract subscription context, invokes several read-only backend SC (Service Component) use cases to fetch pricing and cost data, and prepares the display bean with fee information, payment flags, and mansion-type flags.

2. **Submission (`mskm`)** — Performs the actual subscription registration by invoking a chain of write-side backend services (contract registration, inspection, conclusion, service start), handles relation-check errors (optimistic locking / stale contract), refreshes the customer data, sends a completion email, and redirects to the completion screen.

3. **Navigation (`cfm`, `back`)** — Handles button presses for moving between the confirmation and completion screens.

The class is tightly coupled to a nested `X31SDataBeanAccess` bean hierarchy that models the business entities:

```
ServiceFormBean
    └── CommonInfoBean
        └── WEB_CHG_INFO (WebChangeInfo)
            └── GEN_CUST_KEI_INFO (CurrentCustomerContractInfo)
                └── SVC_KEI_INFO (ServiceContractInfo)
                    ├── SEIKY_KEI_INFO (BillingContractInfo)
                    ├── SVC_KEI_UCWK_INFO (ServiceContractDetailInfo)
                    │   └── OP_SVC_KEI_INFO (OptionServiceContractInfo)
                    │       └── SBOP_SVC_KEI_INFO (SubOptionServiceContractInfo)
```

This hierarchy must be traversed in every method that processes subscription data, which is a notable code smell indicating deeply coupled data access.

## Key Methods

### `init()` — boolean

**What it does:** Prepares the initial display of the mail virus check service subscription screen. This is the most complex and longest method in the class (245 lines), acting as a facade that performs validation, pricing queries, and UI setup in a single call.

**Steps:**

1. **Device check** — Calls `JFUWebCommon.checkOrosi(this)` to verify the request is coming from a valid device.

2. **Bean hierarchy traversal** — Retrieves the `ServiceFormBean` and `CommonInfoBean`, then drills down through `WEB_CHG_INFO` → `GEN_CUST_KEI_INFO` → `SVC_KEI_INFO` → `SEIKY_KEI_INFO`, `SVC_KEI_UCWK_INFO`, `OP_SVC_KEI_INFO`, and `SBOP_SVC_KEI_INFO` to build references to every level of the business data model.

3. **Pricing group evaluation** — Extracts the price group code (`prcGrpCd`) and contract payment method code (`kanyuKeiPayHoshikiCd`) to determine whether the user's account type is a "mansion-type (all-unified)" plan. Sets the `MANSION_DIV` flag accordingly.

4. **State validation** — Verifies:
   - The billing contract status (`SEIKY_KEI_STAT`) must be `"100"` (active). Throws `JCCBusinessException` with error `0102` if not.
   - The option service contract number (`opSvcKeiNo`) must not be null. Throws error `0002` (system error) if missing.
   - POP ID and Mail Address (`popid`, `mlad`) must be set. Throws error `0102` if not.
   - The option service contract status (`opSvcKeiStat`) must be `"020"` (inspected), `"030"` (concluded), or `"100"` (in service). Throws error `0102` if not.

5. **Mail virus count** — Iterates through the sub-option service contract list (`SBOP_SVC_KEI_INFO`), counting entries that match the virus check service code (`"D03"`) and share the same option service contract number. Entries with status `"910"` (canceled) or `"920"` (terminated) are excluded. This count (`countMailVirus`) is passed to the pricing mapper for free-trial evaluation.

6. **Service invocation (read-only)** — Builds a `FUSV0057_FUSV0057OPDBMapper` and sets up five service calls via the mapper:
   - `setFUSV005701SC` — Business parameter management consultation (EZM0321A010)
   - `setFUSV005702SC` — Business parameter management consultation (EZM0321A010)
   - `setFUSV005703SC` — Price plan fixed unit price (option application fee) list consultation (EKK0601B001)
   - `setFUSV005704SC` — Price course_sub-option service consultation (EKK1881A010)
   - `setFUSV005701CC` — Initial cost list consultation (CC)
   All are called with `FUNC_CD_1` (read/consult) and the use case ID `FUSV0057`. `invokeService` is then called to execute them.

7. **Result processing** — Retrieves results from all five mappers. If the base cost is not required (`isNoBasicCost`) or the service is free (`isMuryo`), it sets free pricing info and forces `MANSION_DIV` to false. Otherwise, it sets the `PAY_FLG` and `COST_FLG` flags and re-evaluates `MANSION_DIV`.

8. **Display setup** — Calls `JFUWebCommon.setPrcInfoArea()` to populate the price display area with data from both the SC and CC results. Sets initial contract agreement flags (`KEIYAKU_YAKKAN_DOI`, `RIYO_KIYAKU_DOI`) to `false`. Sets the price display date and next-screen references. Sets the operation date via `setFuOpedate()`.

**Returns:** `true` on success. Throws `JCCBusinessException` on validation failure.

---

### `cfm()` — boolean

**What it does:** Handles the **confirm button** press on the initial display screen. It calls `execute()` with `FUNC_CD_2` (consult mode, not yet committing), then sets the next screen to `FUW02202` (the confirmation screen).

**Parameters:** None (accesses data via inherited bean methods).

**Side effects:** Modifies the `NEXT_SCREEN_NAME` and `NEXT_SCREEN_ID` in the `CommonInfoBean` to redirect to `FUW02202`.

---

### `mskm()` — boolean

**What it does:** Handles the **submit button** press on the confirmation screen. This is the critical method that actually registers the subscription with the backend. It performs:

1. **Front-end common check** — Calls `JFUWebCommon.checkCommonRelation(this, USECASE_ID_FUSV0058)` for front-end validation.

2. **Service invocation (write)** — Calls `execute()` with `FUNC_CD_1` (write mode), which invokes the full chain of backend services:
   - `setFUSV005801SC` — Subscription content acceptance registration (EKK0011D020)
   - `setFUSV005802SC` — Sub-option service contract <ISP> registration (EKK0411D010)
   - `setFUSV005807SC` — Sub-option service contract <ISP> inspection SC (EKK0411C020)
   - `setFUSV005803SC` — Sub-option service contract <ISP> inspection conclusion (EKK0411C040)
   - `setFUSV005804SC` — Sub-option service contract <ISP> use start (EKK0411C050)
   - `setFUSV005805SC` — Progress registration (EKK1091D010)
   - `setFUSV005806SC` — Subscription details inspection / follow-up work request (EKK0021C060)
   - `setFUSV005801CC` — Service IF result data transfer (JFUTransferCC)
   - `setFUSV005802CC` — Service order issuance (JKKHakkoSODCC)
   - `setFUSV005808CC` — Family pack induction necessity judgment CC

3. **Customer refresh** — Calls `JFUWebCommon.refreshGenCustKei(this)` to refresh the current customer contract information in the session.

4. **Completion email** — Calls `JFUWebCommon.sendMskmFinMail(this, MSKM_COMP_MAIL_ID)` to send the completion notification email (mail template ID `FUW022_1`).

5. **Navigation** — Sets the next screen to `FUW02203` (completion screen).

**Returns:** `true` on success. Throws `JCCBusinessException` on failure.

---

### `back()` — boolean

**What it does:** Handles the **return button** press on the confirmation screen. Simply sets the next screen back to `FUW02201` (the initial display/price screen) without invoking any backend services. This is a pure navigation action.

---

### `execute(X31SDataBeanAccess commoninfoBean, String funcCd)` — void

**What it does:** The core service invocation method shared by `cfm()` and `mskm()`. It builds the complete parameter set from the bean hierarchy and invokes the FUSV0058 use case (subscription submission) against the backend.

**Parameters:**
- `commoninfoBean` — The shared form bean containing customer and contract context.
- `funcCd` — Function code: `"1"` for write (submit) or `"2"` for consult (confirm preview).

**Steps:**
1. Traverses the same nested bean hierarchy as `init()` (ServiceFormBean → CommonInfoBean → WebChangeInfo → CurrentCustomerContractInfo → ServiceContractInfo → BillingContractInfo → ServiceContractDetailInfo → OptionServiceContractInfo).
2. Builds a `FUSV0058_FUSV0058OPDBMapper` and populates it with ten service calls (registration, contract management, inspection, order issuance, data transfer, etc.).
3. Calls `invokeService(paramMap, dataMap, outputMap)` to execute the backend.
4. On `JCCWebServiceException`, delegates to `checkException()` for error classification.

**Throws:** `JCCBusinessException` (via `checkException`) or propagates unexpected exceptions.

---

### `checkException(JCCWebServiceException se)` — void

**What it does:** Analyzes a `JCCWebServiceException` from the backend and re-throws a more user-friendly `JCCBusinessException` based on the specific error condition.

**Error classification logic:**
- **Relation check error with `EKK0411D010` + flag `"EA"` + item `"op_svc_kei_no"`** — The option service contract number is invalid for a relation check. Maps to `ERROR_CODE_0103`.
- **Relation check error with `EKK0411D010` / `EKK0411C040` / `EKK0411C050` + flag `"EA"` + item `"upd_dtm_bf"`** — Optimistic locking failure (the contract record was modified by another process since the user loaded the page). Maps to `ERROR_CODE_0204` (duplicate/modification error).
- **All other cases** — Maps to `ERROR_CODE_0002` (system error).

**Design note:** The method extracts `templateId`, `itemId`, `status`, and `itemCheckErr` from the exception's message metadata to distinguish between different backend validation failures. The comment notes that the "related check" path only ever has one message at index 0.

---

### `setFuOpedate(X31SDataBeanAccess commonInfoBean, String opeDate)` — void

**What it does:** Sets the operation date (used for auditing / logging) into the front-common-info bean's `FU_OPEDATE_05` field. This is a simple utility called during initialization to propagate the current operation date into the shared context.

## Relationships

```mermaid
flowchart TD
    A["WEBGAMEN_FUW022010PJP"] -->|"calls"| B["FUW02201SFLogic"]
    C["WEBGAMEN_FUW022020PJP"] -->|"calls"| B
    D["WEBGAMEN_FUW022030PJP"] -->|"calls"| B
    E["x31business_logic_FUW02201SF"] -->|"references"| B
    B -->|"extends"| F["JCCWebBusinessLogic"]
    B -->|"uses"| G["FUSV0058_FUSV0058OPDBMapper"]
    B -->|"uses"| H["FUSV0057_FUSV0057OPDBMapper"]
    B -->|"uses"| I["X31SDataBeanAccess"]
    B -->|"uses"| J["JCCWebServiceException"]
```

### Inbound (who uses this class)

- **WEBGAMEN_FUW022010PJP.xml** — The JPXML page definition for the initial display screen (`FUW02201`). References this logic class to wire up the `init()` method as the action handler.
- **WEBGAMEN_FUW022020PJP.xml** — The JPXML page definition for the confirmation screen (`FUW02202`). References this logic class to wire up the `cfm()` (confirm) and `back()` methods.
- **WEBGAMEN_FUW022030PJP.xml** — The JPXML page definition for the completion screen (`FUW02203`). References this logic class to wire up the `mskm()` (submit) method.
- **x31business_logic_FUW02201SF.xml** — The business logic definition file. References this class as the implementation for the mail virus check service subscription business logic.

### Outbound (what this class depends on)

- **`JCCWebBusinessLogic`** — The parent class providing the service invocation framework (`invokeService()`), bean accessors (`getServiceFormBean()`, `getCommonInfoBean()`), and base exception handling.
- **`FUSV0057_FUSV0057OPDBMapper`** — Read-side mapper used in `init()` to fetch pricing plans, course info, and initial cost data from the backend.
- **`FUSV0058_FUSV0058OPDBMapper`** — Write-side mapper used in `execute()` to submit the subscription, register contracts, and issue service orders.
- **`X31SDataBeanAccess` / `X31SDataBeanAccessArray`** — The data container classes that hold the nested bean hierarchy representing customer contracts, service subscriptions, and option configurations.
- **`JCCWebServiceException`** — Exception type thrown by backend service invocations, analyzed by `checkException()` for user-friendly error mapping.

## Usage Example

The typical calling pattern flows through the JPXML framework:

```
User browses to FUW02201 screen
    ↓
Framework instantiates WEBGAMEN_FUW022010PJP, calls FUW02201SFLogic.init()
    ↓
init() validates contract state, fetches pricing, sets display flags, returns true
    ↓
Framework renders FUW02201 JSP with pricing table, contract checkboxes
    ↓
User clicks "Confirm" button
    ↓
Framework calls FUW02201SFLogic.cfm() → execute(FUNC_CD_2) → next screen FUW02202
    ↓
Framework renders FUW02202 JSP with summary for review
    ↓
User clicks "Submit" button
    ↓
Framework calls FUW02201SFLogic.mskm() → execute(FUNC_CD_1) → backend registration → email → next screen FUW02203
    ↓
Framework renders FUW02203 JSP with completion message
```

Alternatively, if the user clicks "Return" on the confirmation screen:

```
User clicks "Return" button
    ↓
Framework calls FUW02201SFLogic.back() → next screen FUW02201
```

## Notes for Developers

- **Bean hierarchy is rigid** — Every method that accesses subscription data traverses the same seven-level deep bean chain. Any change to this hierarchy requires updating it in both `init()` and `execute()`. Consider extracting this traversal into a helper method.

- **Stateful error mapping** — The `checkException()` method makes assumptions about exception structure (e.g., that `moreInfo[0]` always exists). If the backend ever returns an empty message list, this will throw an `ArrayIndexOutOfBoundsException`.

- **Optimistic locking errors** — The `ERROR_CODE_0204` (stale data) error is the most likely cause of submission failures in production. Users may encounter this if they keep the confirmation page open for an extended period. The error message should guide them to restart the flow.

- **Free pricing overrides mansion type** — When `isMuryo || isNoBasicCost` evaluates to true, the method explicitly sets `MANSION_DIV` to `false` even if the user's plan type would normally indicate a mansion. This is intentional — free tiers don't require mansion-style pricing.

- **Thread safety** — The class has no instance fields that store per-request state (all data is read through the bean hierarchy and local variables), so it should be safe for use by multiple concurrent requests within the same instance, following the typical JP framework pattern.

- **Usecase IDs for tracing** — Two use case IDs are used: `FUSV0057` for read-only pricing queries (in `init()`) and `FUSV0058` for the subscription write operation (in `mskm()`). These can be used to correlate this class's behavior with backend logs.

- **Hardcoded screen IDs** — Next-screen references are hardcoded as string literals (`SCREEN_NAME_FUW02201`, etc.). If screens are renamed, these references must be updated manually.

- **Commented-out code** — The `setFUSV005808CC` mapper call has a `// mapper.getFUSV005808CC(bean, outputMap);` line commented out below the `invokeService` call (annotated with `ANK-3149-00-00`). This appears to be a deferred retrieval that was intentionally removed. Verify this is intentional before adding new mapper result retrievals.
