# FUW02601SFLogic

## Purpose

`FUW02601SFLogic` is the **business logic controller** for the **Mailing List Addition Request** screen (FUW02601) in the x31 web application. It orchestrates a multi-step user flow — initial screen display, confirmation review, and final submission — that allows a customer to subscribe to a promotional mailing list service. The class handles service invocations for fee/pricing data, validates business constraints (mailing list capacity, contract eligibility, NG word filtering), manages error routing to the correct user-facing message, and fires a completion email upon successful registration.

## Design

This class follows the **Screen Controller / Facade** pattern common in the x31 framework. It acts as the central orchestration point between the web tier (JSP controllers) and the underlying business logic services (`FUSV0060` for read-only pricing/fee display, `FUSV0061` for write operations that register contracts). It extends `JCCWebBusinessLogic`, inheriting utilities for service invocation (`invokeService`), data bean access (`getCommonInfoBean`, `getServiceFormBean`), and web common operations.

The class manages a **three-step wizard flow**:

1. **init()** — Initial screen display: fetches fee schedules, pricing plans, NG word lists, and contract eligibility; computes whether the request is paid or free; sets up the mansion division flag.
2. **cfm()** — Confirm button: validates the user's selections against common relation checks (e.g., e-joining eligibility, update timestamp staleness).
3. **mskm()** — Submit button: persists the mailing list subscription via a chain of 11 service calls, refreshes the customer record, and sends a completion notification email.

The class is **not thread-safe** — it relies on thread-local or request-scoped `X31SDataBeanAccess` objects obtained from the framework base class. Each HTTP request instantiates a new controller.

## Key Methods

### `boolean init()`

The entry point — called when the user first loads the mailing list addition request screen (FUW02601).

**What it does:**

1. **Drills into the shared form bean** to reach nested customer/contract data structures: `commoninfoBean` → `webChgInfoBean` → `genCustKeiInfoBean` → `svcKeiInfoBean` → `svcKeiUcwkInfoBean`.
2. **Counts existing mailing list contracts** by iterating over the nested `OP_SVC_KEI_INFO` arrays, incrementing `mailingListCnt` for each active (non-terminated, non-cancelled) operation service with mailing list code (`CD00136_B003`).
3. **Builds a request parameter map** using use case ID `FUSV0060` and creates an `FUSV0060_FUSV0060OPDBMapper` to set up six screen call (SC) operations:
   - `FUSV006001SC` — Fee cost / operation service agreement check (EKK0811A010)
   - `FUSV006002SC` — Fixed unit price / option application fee list
   - `FUSV006001CC` — Initial fee list cross-call (CC)
   - `FUSV006003SC` — Business parameter management check (EZM0321A010)
   - `FUSV006004SC` — Business parameter management check (EZM0321A010)
   - `FUSV006005SC` — NG word list (front) (EZM0161B020)
4. **Invokes the service** via `invokeService(paramMap, dataMap, outputMap)`.
5. **Parses the response** through the mapper's getter methods, extracting pricing info and NG word lists into the form bean.
6. **Computes `payFlg`** by calling `getPayFlg(bean)`: `true` if the user's current mailing list count >= free allowance AND the unit price > 0; otherwise `false`.
7. **Sets free pricing info** if `payFlg` is `false`, using `JFUWebCommon.setFreePrcInfoMap()`.
8. **Sets up pricing display areas** via `JFUWebCommon.setPrcInfoArea()`.
9. **Compares available vs. existing contract counts** — throws `ERROR_CODE_0102` (contract status error) if `maxOpSvcCnt <= mailingListCnt`, meaning the user has exhausted their available contracts.
10. **Populates the form bean** with:
    - `NOW_MLLIST_STKU_CNT` — current mailing list contract count
    - `NOW_MLLIST_STKU_ZAN_CNT` — remaining available count
    - `KOKAI_SET_LIST` — a `TreeMap`-sorted list of public setting items from display definitions
    - `KEIYAKU_YAKKAN_DOI` — contract agreement checkbox, defaulting `false`
    - `MANSION_DIV` — whether this is a mansion (full-building) paid contract
    - `PAY_FLG` — paid vs. free flag
11. **Sets next-screen navigation** to FUW02601.

**Returns:** `true` on normal completion.

**Throws:** `JCCBusinessException(JFUStrConst.ERROR_CODE_0002)` if the service call fails; `ERROR_CODE_0102` if the user's contract count is exhausted.

### `boolean cfm()`

Handles the **confirm button** press on the mailing list addition request screen.

**What it does:**

1. Obtains the shared form bean.
2. Delegates to `cfmMskmSyori(CHEK_CFM, commoninfoBean)` with target `"cfm"`. This performs:
   - Drills into nested customer → service → billing data beans.
   - Resolves the user's chosen "public setting" display name from their selection.
   - Invokes the `FUSV0061` use case (`FUSV0061`) with `FUNC_CD_2` (confirmation mode).
   - Sets up 10 service operations for the confirmation path (registration, agreement, inquiry, binding, start, e-joining registration, progress registration, detail inquiry, service IF data transfer CC, audit condition registration CC).
   - If a `JCCWebServiceException` is thrown, delegates to `checkException(se, "cfm")` to map specific error codes to business exceptions.
3. **Sets next-screen navigation** to screen FUW02602 (the submission/review screen).

**Returns:** `true` on normal completion.

**Throws:** `JCCBusinessException` with various codes depending on error conditions (see `checkException`).

### `boolean mskm()`

Handles the **submit button** press — the final action that commits the mailing list subscription.

**What it does:**

1. Performs a **common relation check** via `JFUCommonRelationCheck.checkCommonRelation(this, "FUSV0061")` — validates cross-screen consistency.
2. Obtains the shared form bean.
3. Delegates to `cfmMskmSyori(CHEK_MSKM, commoninfoBean)` with target `"mskm"`. This is nearly identical to the confirm path but uses `FUNC_CD_1` (execution mode) instead of confirmation mode. The same 10 service operations run, and errors are routed through `checkException(se, "mskm")`.
4. **Refreshes the current customer information** via `JFUWebCommon.refreshGenCustKei(this)` — ensures the customer data cache reflects the newly created contract.
5. **Sends a completion email** via `JFUWebCommon.sendMskmFinMail(this, "FUW026_1")`.
6. **Sets next-screen navigation** to screen FUW02603 (the completion/confirmation screen).

**Returns:** `true` on normal completion.

**Throws:** `JCCBusinessException` with codes such as `0101` (usage limit error), `0204` (update impossibility error), or `0102` (contract status error).

### `void checkException(JCCWebServiceException se, String isTarget)`

A **private error routing method** that inspects a `JCCWebServiceException` and re-throws a domain-appropriate `JCCBusinessException` based on the error context. The `isTarget` parameter distinguishes between the confirm (`"cfm"`) and submit (`"mskm"`) flows, which have slightly different error handling rules.

**Error types detected** (via template ID, item ID, error flag, and status):

| Template | Item | Error Flag | `isTarget` | Mapped Exception | Meaning |
|---|---|---|---|---|---|
| `EKK0361D010` (OpSvcContract ISP) | `mllist_nm` | `EB` (usage limit) | `cfm` | Rethrow original | Business exception |
| `EKK0361D010` | `mllist_nm` | `EB` | `mskm` | `ERROR_CODE_0101` | Usage limit error |
| `EKK0361D010` | `mllist_nm` | `EA` (NG word) | `cfm` | Rethrow original | Business exception |
| `EKK0361D010` | `mllist_nm` | `EA` | `mskm` | `ERROR_CODE_0101` | Usage limit error |
| `EKK0361D010` | `aging_tg_value` | `EA` | `cfm` | Rethrow original | Business exception |
| `EKK0361D010` | `upd_dtm_bf` | `EA` | either | `ERROR_CODE_0204` | Update impossibility (stale data) |
| `EKK0361D010` | `op_svc_cd` | `EE` (contract limit) | either | `ERROR_CODE_0102` | Contract status error |
| `EZM0111D010` (E-joining target) | `aging_tg_value` | `EA` | `cfm` | Rethrow original | Business exception |

Any error not matching the above patterns falls through to a catch-all `ERROR_CODE_0002`.

### `void cfmMskmSyori(String isTarget, X31SDataBeanAccess commoninfoBean)`

A **private shared handler** used by both `cfm()` and `mskm()`. It contains the bulk of the business logic for processing the user's form data and invoking the underlying services.

**What it does:**

1. **Drills into customer contract data** — iterates through `WEB_CHG_INFO` → `GEN_CUST_KEI_INFO` → `SVC_KEI_INFO` → `SEIKY_KEI_INFO` (billing) to reach the deepest nested beans needed for the service call.
2. **Resolves the selected public setting display name** — iterates over the `KOKAI_SET_LIST` array to find the bean whose value matches the user's `CHOICE_KOKAI_SET_VALUE`, then sets `CHOICE_KOKAI_SET_MEI` to the display name.
3. **Invokes use case `FUSV0061`** with a function code of `FUNC_CD_2` (confirmation) or `FUNC_CD_1` (execution), depending on `isTarget`.
4. **Sets up 10 service operations** via `FUSV0061_FUSV0061OPDBMapper`:
   - `FUSV006101SC` — Registration content acceptance registration (EKK0011D020)
   - `FUSV006102SC` — Operation service contract ISP registration (EKK0361D010)
   - `FUSV006108SC` — Operation service contract ISP inquiry
   - `FUSV006103SC` — Operation service contract ISP binding (EKK0361C030)
   - `FUSV006104SC` — Operation service contract ISP start (EKK0361C040)
   - `FUSV006105SC` — E-joining target registration (EZM0111D010)
   - `FUSV006106SC` — Progress registration (EKK1091D010)
   - `FUSV006107SC` — Application detail inquiry / follow-up business request (EKK0021C060)
   - `FUSV006101CC` — Service IF result data transfer cross-call
   - `FUSV006102CC` — Audit condition registration cross-call
5. **Sets the service contract status** via `JFUWebCommon.setSvcKeiStat()`.
6. **Invokes the service** and catches `JCCWebServiceException`, routing it through `checkException()`.

### `boolean getMansionDiv(X31SDataBeanAccess commoninfoBean, X31SDataBeanAccess bean, HashMap<String, Object> outputMap)`

Determines whether the customer's subscription qualifies as a **"mansion division"** — a special classification for full-building (mansion) contracts that are paid.

**Logic:**

1. Extracts `freeValue` (free allowance count), `nowMllistStkuCnt` (current mailing list count), and `tanka` (fixed unit price) from the form bean.
2. Gets the price group code and contract payment method code from the service contract info.
3. If the price group is `"04"` (eo光ネットマンションタイプ / eo Light Net Mansion Type) AND the payment method is `"003"` (full-building / 全戸一括), then:
   - Returns `true` if `nowMllistStkuCnt >= freeValue` AND `tanka > 0` (current count exceeds free allowance and there's a cost), OR if there are initial fees in the response data.
   - Returns `false` otherwise.
4. If the customer is not a mansion-type, returns `false`.

**Returns:** `true` if mansion division with payment; `false` otherwise.

### `boolean getPayFlg(X31SDataBeanAccess bean)`

A **simple pricing decision** — determines whether the mailing list addition request is a paid or free service.

**Logic:** Returns `true` if `nowMllistStkuCnt >= freeValue` AND `tanka > 0`; `false` otherwise.

**Returns:** `true` = paid, `false` = free.

## Relationships

### Who depends on `FUW02601SFLogic`

Four XML configuration files reference this class as a screen logic controller:

```mermaid
flowchart TD
    subgraph WebViews["Web Screen Controllers (JSP Layer)"]
        JP_XML["WEBGAMEN_FUW026010PJP<br/>Confirm screen"]
        JP2_XML["WEBGAMEN_FUW026020PJP<br/>Submit screen"]
        JP3_XML["WEBGAMEN_FUW026030PJP<br/>Completion screen"]
        BL_XML["x31business_logic_FUW02601SF<br/>Screen entry/bridge"]
    end

    subgraph Logic["Business Logic Layer"]
        LOGIC["FUW02601SFLogic<br/>Mailing List Add Request"]
    end

    subgraph Inherited["Base Framework"]
        BASE["JCCWebBusinessLogic<br/>Web business logic base"]
    end

    JP_XML -->|"invokeService"| LOGIC
    JP2_XML -->|"invokeService"| LOGIC
    JP3_XML -->|"invokeService"| LOGIC
    BL_XML -->|"delegate"| LOGIC
    LOGIC -->|"extends"| BASE
```

- **WEBGAMEN_FUW026010PJP.xml** — Screen controller for the initial display and confirm steps (calls `init()`, `cfm()`, `back()`).
- **WEBGAMEN_FUW026020PJP.xml** — Screen controller for the submit step (calls `mskm()`).
- **WEBGAMEN_FUW026030PJP.xml** — Screen controller for the completion screen (likely reads the result but may delegate setup to this logic).
- **x31business_logic_FUW02601SF.xml** — The business logic entry point that bridges screen controllers to `FUW02601SFLogic`.

### Outbound dependencies

- **`JCCWebBusinessLogic`** (extends) — Provides `invokeService()`, `getCommonInfoBean()`, `getServiceFormBean()`, and other framework utilities for web-tier business logic classes.
- **`FUSV0060_FUSV0060OPDBMapper`** — Mapper for the FUSV0060 use case, handling read-only fee/pricing/parameter queries.
- **`FUSV0061_FUSV0061OPDBMapper`** — Mapper for the FUSV0061 use case, handling write operations (contract registration, binding, start).
- **`JFUWebCommon`, `JFUCommonRelationCheck`** — Shared framework utilities for web operations and cross-check validation.
- **`JCCWebServiceException`, `JCCBusinessException`** — Exception types from the framework for service-level and business-level errors.

## Usage Example

The class is never instantiated directly by application code. Instead, it is wired into the x31 framework's screen controller XML and invoked through the standard request-processing pipeline:

```
User flow:

  1. User navigates to FUW02601 (mailing list add screen)
     → WEBGAMEN_FUW026010PJP calls FUW02601SFLogic.init()
     → Service fetches fee schedules, pricing plans, NG words
     → Screen renders with pricing info, agreement checkbox, mansion flag

  2. User fills the form and clicks "Confirm"
     → WEBGAMEN_FUW026010PJP calls FUW02601SFLogic.cfm()
     → Common relation checks validate eligibility
     → Screen navigates to FUW02602 (confirm display)

  3. User clicks "Submit" on confirm screen
     → WEBGAMEN_FUW026020PJP calls FUW02601SFLogic.mskm()
     → 11 services register the contract end-to-end
     → Customer data refreshed, completion email sent
     → Screen navigates to FUW02603 (completion screen)

  4. User clicks "Back" on confirm screen
     → WEBGAMEN_FUW026010PJP calls FUW02601SFLogic.back()
     → Screen navigates back to FUW02601
```

The typical code path within a JSP controller looks like:

```java
// In a screen controller's execute method:
FUW02601SFLogic logic = new FUW02601SFLogic();
String result = logic.init(); // Returns "true" or "false"
```

## Notes for Developers

- **Not thread-safe**: The class uses request-scoped data beans obtained from the base class (`getCommonInfoBean()`, `getServiceFormBean()`). Do not reuse instances across requests.

- **Error code routing is critical**: `checkException()` is the sole error translation layer. Any new error type from the underlying services must be added there, or it will fall through to the catch-all `ERROR_CODE_0002`. The mapping differs between confirm (`cfm`) and submit (`mskm`) paths — note that in confirm mode, certain template/item/error-flag combinations result in rethrowing the original exception (business exception) rather than converting to a system error code.

- **Mailing list count comparison**: In `init()`, the comparison `maxOpSvcCnt <= mailingListCnt` means the error is thrown when the user's *current* contract count equals or exceeds the *maximum available*. This is a "no remaining capacity" guard. Be careful when modifying — the `<=` (not `<`) is intentional: if you have 0 remaining, you cannot add.

- **The mansion division and pay flag share identical logic**: `getMansionDiv()` and `getPayFlg()` use the same `nowMllistStkuCnt >= freeValue && tanka > 0` check, but `getMansionDiv()` additionally requires the price group code to be `"04"` (eo mansion type) and the payment method to be `"003"` (full-building). The mansion div also checks for initial fees in the response data.

- **The confirm and submit paths differ only in function code**: `FUNC_CD_2` (confirmation mode) for `cfm()`, `FUNC_CD_1` (execution mode) for `mskm()`. The same underlying services run in both cases, but the confirmation mode likely performs validation-only operations while execution mode commits changes.

- **Completion email is sent in `mskm()` only**: The `FUW026_1` mail ID triggers the completion notification. This is not sent during confirmation.

- **Nested bean drilling**: The code extensively drills into `X31SDataBeanAccess` arrays — typically `WEB_CHG_INFO` → `GEN_CUST_KEI_INFO` → `SVC_KEI_INFO` → `SEIKY_KEI_INFO` (or `SVC_KEI_UCWK_INFO` → `OP_SVC_KEI_INFO`). Any change to the shared form bean structure will likely require updates in both `init()` and `cfmMskmSyori()`.

- **The `KEIYAKU_YAKKAN_DOI` (contract agreement) checkbox defaults to `false`**: The user must actively check it to proceed. There is no automatic agreement based on prior state.
