# FUW03501SFLogic

## Purpose

`FUW03501SFLogic` is the core business logic controller for the **option service plan change/view screen** in a Japanese web application (screens `FUW03501` through `FUW03504`). It orchestrates the lifecycle of users adding, modifying, or viewing their option service subscriptions — fetching pricing plan data from downstream web services, performing relational integrity checks (e.g., "Duplex connection count exceeded"), computing payment flags, and routing users between the plan selection screen, confirmation screen, submission completion screen, and viewing-only screen.

## Design

This class follows the **web business logic controller** pattern common in the Fujitsu J-COM platform. It extends `JCCWebBusinessLogic`, inheriting common web-layer infrastructure such as bean access, service invocation, and data mapping hooks. The class acts as a **facade** that:

1. **Extracts** shared form data (customer info, service contract info, option service info, authentication credentials) from the `X31SDataBeanAccess` common info bean hierarchy.
2. **Populates** request data maps via `FUSV0073` (plan list / cost) and `FUSV0074` (contract registration) mapper objects.
3. **Invokes** remote web services through `invokeService()`.
4. **Maps** service responses back into form beans.
5. **Computes** derived display flags (`payFlg`, `mansionDiv`, `chgDiv`).
6. **Routes** the user to the next screen by setting `NEXT_SCREEN_ID` and `NEXT_SCREEN_NAME` on the common info bean.

It uses two internal mapper classes:
- **`FUSV0073_FUSV0073OPDBMapper`** — used in `init()` for reading/displaying plan lists, costs, and duplex connection status.
- **`FUSV0074_FUSV0074OPDBMapper`** — used in `cfm()` and `mskm()` for contract registration/modification submissions.

## Key Methods

### `public boolean init()` [lines 120–278]

The **entry point** — the first method invoked when the user opens the plan selection screen (`FUW03501`). It performs all initialization:

1. Extracts the shared form bean (`X31SDataBeanAccess`) and populates a `commoninfoMap` containing SSO info, service contract info, option service info, billing agreement info, and derived values (current operation service code, plan string, duplex connection count, auth ID/password, price group code).
2. Creates an `FUSV0073_FUSV0073OPDBMapper` and builds a request data map by calling four setter methods in sequence:
   - `setFUSV007301SC` — Price plan list acquisition (option service code)
   - `setFUSV007301CC` — Initial cost list acquisition
   - `setFUSV007303SC` — Price cost / option service agreement acquisition
   - `setFUSV007302CC` — Daily update related check
3. Invokes the web service via `invokeService(paramMap, dataMap, outputMap)`. If the web service throws `JCCWebServiceException`, the user is immediately redirected to the system error screen (`ERROR_CODE_0002`).
4. After the service call, runs the corresponding getter mappers (`getFUSV007301SC`, `getFUSV007303SC`) to populate the form bean.
5. Computes `chgDiv` (new registration / change / view division) from the output map:
   - **`chgDiv == "0"`** (New): Sets `CHG_DIV` to `"0"` (new), sets `NOW_OP_SVC_CD` to the default duplex code, navigates to screen `FUW03501`.
   - **`chgDiv == "1"`** (Change): Sets `CHG_DIV` to `"1"` (change), populates the current plan name, auth ID, auth password, and navigates to `FUW03501` for plan selection.
   - **`chgDiv == "2"`** (View): Sets `CHG_DIV` to `"1"` (change, for reuse), navigates to screen `FUW03504` (view-only), and sets the transfer page ID with the `0PJP` suffix.
6. Computes derived flags:
   - `payFlg` — Whether payment is required (via `setPayFlg()`).
   - `mansionDiv` — Whether the user is in a mansion-type plan with payment (via `setMansionDiv()`).
7. Applies price list mapping via `mapper.getPcrsListBean(this, bean, outputMap)` and `mapper.getPriceAreaBean(bean, outputMap, prcGrpCd23, chkPayInitialCost(outputMap))`.
8. Sets the current display date via `JFUWebCommon.setPrcDspNowDay(this)`.
9. Sets `NEXT_SCREEN_ID` and `NEXT_SCREEN_NAME` on the common info bean.

**Side effects:** Modifies the service form bean in-place (setting message strings for display values), sets navigation state on the common info bean.

**Always returns `true`.**

---

### `public boolean cfm()` [lines 286–367]

Handles the **confirm button** press on the submission screen (`FUW03501`). This is the "go to confirmation" step — the user has selected a plan and now needs to review before final submission.

1. Extracts shared form beans: SSO info, service contract info, billing agreement info, option service info.
2. Parses the selected plan string (`CHOICE_PPLAN_STR`) which uses underscore (`_`) as delimiter: `[serviceCode]_[priceCode]_[planCode]`. Extracts the price code (`str[1]`) and plan code (`str[2]`) and sets them on the bean.
3. Creates an `FUSV0074_FUSV0074OPDBMapper` and builds a request data map by calling eleven setter methods in sequence (all with `FUNC_CD_2`):
   - `setFUSV007401SC` — Submission content approval registration
   - `setFUSV007402SC` — Option service contract `<ISP>` registration
   - `setFUSV007408SC` — Option service contract `<ISP>` inquiry
   - `setFUSV007403SC` — Option service contract `<ISP>` inquiry binding
   - `setFUSV007404SC` — Option service contract `<ISP>` start
   - `setFUSV007409SC` — Option service contract processing fee plan change
   - `setFUSV007405SC` — Option service contract price plan change
   - `setFUSV007406SC` — Progress registration
   - `setFUSV007407SC` — Submission detail inquiry / follow-up business delegation
   - `setFUSV007401CC` — Data transfer
   - `setFUSV007402CC` — Order issuance
4. Sets the service contract status via `JFUWebCommon.setSvcKeiStat(this, dataMap)`.
5. Invokes the web service. Errors are caught and delegated to `chkServiceIfError(se)` for intelligent error classification.
6. Updates the plan name display via `setPplanName(bean, commoninfoMap, FUNC_CD_2)`.
7. Sets navigation to screen `FUW03502` (the confirmation screen).

**Always returns `true`.**

---

### `public boolean mskm()` [lines 375–489]

Handles the **submit button** press on the confirmation screen (`FUW03502`). This is the final submission step.

1. Performs a common relational check via `JFUCommonRelationCheck.checkCommonRelation(this, USECASE_ID_FUSV0074)`.
2. Extracts the same set of shared form beans as `cfm()`.
3. Creates an `FUSV0074_FUSV0074OPDBMapper` and builds a request data map by calling the **same eleven setter methods** as `cfm()`, but with `FUNC_CD_1` (different function code path).
4. Sets service contract status.
5. Invokes the web service with the same error handling.
6. Sets `AF_DIAL_NINSHO_ID_PWD` (post-submission auth ID/password) from the common info map.
7. Sets navigation to screen `FUW03503` (the submission completion screen).

**Always returns `true`.**

---

### `public boolean back()` [lines 497–508]

Handles the **back button** press on the confirmation screen (`FUW03502`). Simply navigates the user back to the plan selection screen (`FUW03501`).

**Always returns `true`.**

---

### `private static HashMap<String, Object> getCommonInfo(X31SDataBeanAccess commoninfoBean)` [lines 517–635]

A **static utility** that extracts and consolidates all relevant data from the nested `X31SDataBeanAccess` bean hierarchy into a single `HashMap`. The bean hierarchy is:

```
commoninfoBean
  └── WEB_CHG_INFO[0]
        ├── SSO_INFO[0]         → ssoInfoBean
        └── GEN_CUST_KEI_INFO[0]  → genCustKeiInfoBean
              └── SVC_KEI_INFO[0]  → svcKeiInfoBean
                    ├── PRC_GRP_CD_23
                    └── SVC_KEI_UCWK_INFO[0]  → svcKeiUcwkInfoBean
                          ├── ISP_NINSHO_ID_PWD_24
                          └── OP_SVC_KEI_INFO[n]  → loops through option services
                          └── SEIKY_KEI_INFO[k]   → loops through billing agreements
```

The method returns a map with keys:
- `SSO_INFO`, `SVC_KEI_INFO`, `SEIKY_KEI_INFO`, `OP_SVC_KEI_INFO` — the extracted beans
- `DIAL_CONNECT_NOW_CNT` — count of active option service contracts
- `PRC_GRP_CD_23` — price group code
- `NOW_OP_SVC_CD`, `NOW_PCRS_CD`, `NOW_PPLAN_CD` — individual components of the current plan
- `NOW_PPLAN_STR` — combined string: `[opSvcCd]_[pcrsCd]_[pplanCd]`
- `NOW_DIAL_NISHO_ID` — auth ID for duplex connection
- `AF_DIAL_NINSHO_ID_PWD` — post-auth password
- `OP_SVC_KEI_NO_28`, `GENE_ADD_DTM_28`, `LAST_UPD_DTM_28` — operation service metadata

**Important:** The loop over `OP_SVC_KEI_INFO` selects the **last matching** option service contract where the service code equals the default duplex code (`CD00136_B020`) and the status is neither "cancelled" (`910`) nor "terminated" (`920`).

---

### `private X31SDataBeanAccess setPplanName(X31SDataBeanAccess bean, HashMap<String, Object> inMap, String func_code)` [lines 646–665]

Sets the **display name** of the current or post-change price plan in the bean. Uses `JFUWebCommon.getDispItemsAsMap()` to read plan name mappings from a configuration path (`DISPSETTING/SETTING[@screenId='FUW03501']/DISPTEXT[@groupid='PPLAN_NM']`).

- If `func_code == FUNC_CD_1`: Sets `NOW_PPLAN_NM` from `inMap` (pre-change, initial display).
- If `func_code == FUNC_CD_2`: Sets `AF_PPLAN_NM` from the bean's `CHOICE_PPLAN_STR` (post-change, after submission).

**Returns the modified bean.**

---

### `private boolean setMansionDiv(X31SDataBeanAccess bean, HashMap commoninfoMap, HashMap<Object, Object> outputMap, X31SDataBeanAccess commoninfoBean)` [lines 676–700]

Determines whether the user is on a **mansion-type** plan with payment. Returns `true` if all three conditions hold:

1. Price group code is `"04"` (mansion type)
2. Subscription payment method code is `"003"` (all units, unified payment)
3. Either `payFlg` is `true` (payment required) OR there are initial costs (`chkPayInitialCost(outputMap)`)

---

### `private boolean setPayFlg(X31SDataBeanAccess bean, HashMap<Object, Object> outputMap)` [lines 709–736]

Determines whether **payment is required**. Returns `true` if and only if the plan has a fixed unit price (`chkPayKoteiTanka()` returns `true`) **and** there are no free uses remaining (muryoCnt <= 0). Otherwise returns `false`.

---

### `private boolean chkPayKoteiTanka(HashMap outputMap)` [lines 744–786]

Checks whether any plan in the `EKK0591B001CBSMsg1List` (price plan list from `FUSV007301SC`) has a **fixed unit price** (`PPLAN_KOTEI_AMNT`) greater than zero. Returns `true` if at least one plan line has a non-zero fixed price.

---

### `private boolean chkPayInitialCost(HashMap outputMap)` [lines 794–822]

Checks whether there are any **initial costs** in the `EKK0721A010CBSMsg1List` (initial cost list from `FUSV007301CC`). Returns `true` if the list is non-empty.

---

### `private void chkServiceIfError(JCCWebServiceException se)` [lines 829–884]

Handles **web service relational check errors** by inspecting the exception's message metadata (template ID, item ID, status, error flag) and mapping to specific business exceptions:

| Condition | Status | Error Flag | Item ID | Business Exception |
|---|---|---|---|---|
| Duplex connection service contract count exceeded | `RELATION_ERR` | `EG` | `op_svc_cd` | `ERROR_CODE_0102` (contract state error) |
| Duplex connection count exceeded (general) | `RELATION_ERR` | `EC` | `op_svc_kei_no` | `ERROR_CODE_0102` |
| Plan start date is before operational date | `RELATION_ERR` | `EA` | `plan_staymd` | `ERROR_CODE_0101` (usage restriction error) |
| Contract number + price code set, but service code is duplex | `RELATION_ERR` | `EE` | `pcrs_cd` | `ERROR_CODE_0204` (update impossible error) |
| Any other case | (any) | (any) | (any) | `ERROR_CODE_0002` (system error) |

## Relationships

```mermaid
flowchart TD
    subgraph Consumers["Consumers (inbound)"]
        P0PJP["WEBGAMEN_FUW035010PJP"]
        P20PJP["WEBGAMEN_FUW035020PJP"]
        P30PJP["WEBGAMEN_FUW035030PJP"]
        P40PJP["WEBGAMEN_FUW035040PJP"]
        BLL["x31business_logic_FUW03501SF"]
    end

    subgraph Core["Core Logic"]
        FUW["FUW03501SFLogic"]
    end

    subgraph Dependencies["Outbound Dependencies"]
        JCC["JCCWebBusinessLogic"]
        MAPPER["FUSV0073_FUSV0073OPDBMapper"]
        MAPPER2["FUSV0074_FUSV0074OPDBMapper"]
        X31BEAN["X31SDataBeanAccess"]
    end

    P0PJP -->|references| FUW
    P20PJP -->|references| FUW
    P30PJP -->|references| FUW
    P40PJP -->|references| FUW
    BLL -->|references| FUW
    FUW -->|extends| JCC
    FUW -->|uses| MAPPER
    FUW -->|uses| MAPPER2
    FUW -->|uses| X31BEAN
```

### Inbound (5 dependents)

- **`WEBGAMEN_FUW035010PJP.xml`** — References this class for the plan selection screen (`FUW03501`), the entry point.
- **`WEBGAMEN_FUW035020PJP.xml`** — References this class for the confirmation screen (`FUW03502`).
- **`WEBGAMEN_FUW035030PJP.xml`** — References this class for the submission completion screen (`FUW03503`).
- **`WEBGAMEN_FUW035040PJP.xml`** — References this class for the viewing screen (`FUW03504`).
- **`x31business_logic_FUW03501SF.xml`** — Business logic XML that references this class, likely defining configuration or routing metadata.

### Outbound

- **`JCCWebBusinessLogic`** — This class extends it, inheriting `getCommonInfoBean()`, `getServiceFormBean()`, and `invokeService()`.

## Flow of Use

```mermaid
sequenceDiagram
    participant Client
    participant SVC as FUW03501SFLogic
    participant Mapper1 as FUSV0073 Mapper
    participant Mapper2 as FUSV0074 Mapper
    participant WS as WebService
    participant Bean as CommonInfoBean

    Client->>SVC: init()
    SVC->>Bean: getCommonInfoBean()
    Bean-->>SVC: commoninfoMap
    SVC->>Mapper1: setFUSV007301SC
    Mapper1-->>SVC: dataMap
    SVC->>Mapper1: setFUSV007301CC
    Mapper1-->>SVC: dataMap
    SVC->>Mapper1: setFUSV007303SC
    Mapper1-->>SVC: dataMap
    SVC->>Mapper1: setFUSV007302CC
    Mapper1-->>SVC: dataMap
    SVC->>WS: invokeService
    WS-->>SVC: outputMap
    SVC->>Mapper1: getFUSV007301SC
    Mapper1-->>SVC: mapped data
    SVC->>Mapper1: getFUSV007303SC
    Mapper1-->>SVC: mapped data
    SVC-->>Client: true

    Client->>SVC: cfm()
    SVC->>Bean: getCommonInfoBean()
    Bean-->>SVC: commoninfoMap
    SVC->>Mapper2: setFUSV007401SC through setFUSV007402CC
    Mapper2-->>SVC: dataMap
    SVC->>WS: invokeService
    WS-->>SVC: outputMap
    SVC->>SVC: setPplanName
    SVC-->>Client: true (redirect to FUW03502)

    Client->>SVC: mskm()
    SVC->>Bean: getCommonInfoBean()
    Bean-->>SVC: commoninfoMap
    SVC->>Mapper2: setFUSV007401SC through setFUSV007402CC
    Mapper2-->>SVC: dataMap
    SVC->>WS: invokeService
    WS-->>SVC: outputMap
    SVC->>SVC: setPplanName
    SVC-->>Client: true (redirect to FUW03503)
```

A typical user flow:

1. **`init()`** loads the plan selection screen (`FUW03501`). The service is called to fetch available price plans, costs, and duplex connection status. The user selects a plan.
2. **`cfm()`** submits the plan selection to the confirmation screen (`FUW03502`). The service registers the contract and performs various ISP-related operations.
3. **`mskm()`** finalizes the submission from the confirmation screen, redirecting to the completion screen (`FUW03503`) with the new auth ID/password.
4. **`back()`** allows the user to return from the confirmation screen to the plan selection screen.
5. **`init()`** can also route to `FUW03504` (view-only screen) if the user's contract is in a "view" state (chgDiv == `"2"`).

## Class Diagram

```mermaid
classDiagram
    class FUW03501SFLogic {
        -static final String USECASE_ID_FUSV0073
        -static final String USECASE_ID_FUSV0074
        -static final String EKK0361D010
        -static final String EKK0351C120
        -static final String FUSV007301SC
        -static final String FUSV007301CC
        -static final String FUSV007302CC
        +boolean init()
        +boolean cfm()
        +boolean mskm()
        +boolean back()
        -HashMap~String, Object~ getCommonInfo()
        -X31SDataBeanAccess setPplanName()
        -boolean setMansionDiv()
        -boolean setPayFlg()
        -boolean chkPayKoteiTanka()
        -boolean chkPayInitialCost()
        -void chkServiceIfError()
    }
    class JCCWebBusinessLogic {
        <<base class>>
        +getCommonInfoBean()
        +getServiceFormBean()
        +invokeService()
        +setTransferPageId()
    }
    class X31SDataBeanAccess {
        <<data bean>>
        +sendMessageString()
        +sendMessageBoolean()
        +getDataBeanArray()
    }
    FUW03501SFLogic --|> JCCWebBusinessLogic : extends
    FUW03501SFLogic --> X31SDataBeanAccess : uses
    FUW03501SFLogic --> FUSV0073_FUSV0073OPDBMapper : uses
    FUW03501SFLogic --> FUSV0074_FUSV0074OPDBMapper : uses
```

## Notes for Developers

- **All public methods return `true`** — they never signal success/failure via return value. Errors are raised as exceptions (`JCCBusinessException`, `JCCWebServiceException`).
- **Thread safety is not a concern** — each request creates a new instance of this logic class (standard for web frameworks). No shared mutable state exists at the instance level; all constants are `static final`.
- **Screen routing is implicit** — the method determines the next screen by setting `NEXT_SCREEN_ID` and `NEXT_SCREEN_NAME` on the common info bean. The actual navigation is handled by the framework.
- **The `chgDiv` value** controls the branching logic in `init()`. It comes from the service response (specifically from the `FUSV007302CC` mapper output). Values `"0"`, `"1"`, `"2"` represent new, change, and view respectively.
- **The plan string** (`NOW_PPLAN_STR`) uses underscore as a delimiter: `[serviceCode]_[priceCode]_[planCode]`. This string is parsed in `cfm()` to extract individual components.
- **Error classification in `chkServiceIfError`** maps specific `templateid`/`itemid`/`errFlg` combinations to business-specific error codes. If none match, it falls through to the generic system error (`ERROR_CODE_0002`). Adding new error conditions requires updating this method.
- **The `setMansionDiv` flag** is a compound condition: the user must be in price group `"04"` (mansion), payment method `"003"` (unified), AND have either a paid plan or initial costs. This affects what UI elements are shown.
- **`getCommonInfo`** iterates over all `OP_SVC_KEI_INFO` entries and selects the last matching one where the service code is the default duplex code and the status is not cancelled or terminated. This means the "current" plan is determined by iteration order, not by a specific sort or timestamp.
- **Free usage tracking** — the `DIAL_CONNECT_KEI_MURYO` field holds the total free usage count, and `DIAL_CONNECT_NOW_CNT` holds the number of active option service contracts. The remaining free count is computed as `freeCount - nowCount` in `init()`.
