# KKW01021SFLogic

## Purpose

`KKW01021SFLogic` is the **screen transition orchestrator** for the discount campaign service (紹介サービス) module within the JPCOnline web application. It manages user interactions on the campaign list screen (KKW01021) and history screen (KKK01022), handling actions such as viewing details, editing, deleting, and cancelling campaign contracts. This class acts as the central dispatcher that reads form data, validates campaign types, configures screen state, and navigates to the appropriate target screens — effectively serving as the controller-level logic layer between the JSF pages and the underlying business services.

## Design

The class follows a **screen controller / mediator** pattern. It extends `JCCWebBusinessLogic`, which provides base utilities for session management, DataBean access, and screen info handling. Rather than performing domain logic itself, `KKW01021SFLogic` orchestrates:

1. **Data extraction** — pulling form data from `X31SDataBeanAccess` via `getServiceFormBean()`
2. **Data preparation** — converting the DataBean into a `BeanMap` and extracting relevant fields (selected campaign, customer contract list, etc.)
3. **Validation** — checking campaign type codes and jurisdictional flags before allowing certain operations
4. **Screen state configuration** — using `JCCWebCommon.setScreenInfo()` and `setScreenId()` to pass data and return-screen context to the target screen
5. **Navigation** — delegating to private screen-transition helpers (`moveToNextOtherScreen`, `backToNextOtherScreen`)

The class is tightly coupled to the web presentation layer (JSF pages) and operates on a per-request basis. It is not thread-safe, as it relies on instance state inherited from `JCCWebBusinessLogic` (session-scoped DataBeans).

## Key Methods

### Lifecycle / Entry Points

#### `actionInit() → boolean`

The primary entry point for the initial display of the campaign list screen. It determines which screen is being requested (KKW01021 for the list, KKW01022 for the history) by reading `NEXT_SCREEN_ID` from the common info bean, then dispatches to either `actionInitKKW01021()` or `actionInitKKW022()`. Both initialization methods:
- Set the screen name in the common info bean
- Retrieve screen information via `JCCWebCommon.getScreenInfo(this)`
- Extract the customer contract continuation list (`HKTGI_CUST_KEI_HKTGI_LIST`)
- Register return-screen mappings so that target screens know how to navigate back
- Call `editWribCampaignList()` to populate the campaign list

#### `actionIntr() → boolean` (v7.00.00)

Handles a transition to the introduction/registration screen (KKW01027) for customer referral services. It re-displays info, copies the customer contract list to the target screen's data, and sets up popup screen info for two downstream screens (KKW01027 and KKW01037).

#### `actionCash() → boolean` (ANK-3610)

Handles navigation to the CASHPOST remittance registration screen (KKW22401). It extracts the customer contract list from the service form bean and passes it as screen info, setting the return destination back to KKW01021.

### CRUD-like Screen Actions

#### `actionAdd() → boolean`

Triggers the "new registration" button on the campaign list screen. It:
1. Re-displays info (to preserve state after post-backs)
2. Extracts the customer contract list and selected campaign data
3. Configures screen info for the add screen (KKW01027) with the customer contract list
4. Calls `moveToNextOtherScreen(Screen.KKW01027)`

This navigates to a separate add-form screen where the user enters details for a new discount campaign contract.

#### `actionUpdate() → boolean`

Handles the "edit" button press on the list screen. The flow is:
1. Re-displays info and retrieves the `SELECTED` index from the bean map
2. Gets the campaign list (`CAMPAIGN_ICRN`) and extracts the selected campaign by index
3. Reads the contract number (`NO_03`) and contract type (`KEI_KIND_03`) into arrays
4. **Validates the discount type code** via `isNotErrChkWribTypeCd()` — if the selected campaign uses "42: Quota-locked discount" (契約割引き), the update is blocked and an error message is set
5. Extracts customer contract continuation list and sets screen info for KKW01024 (the update screen)
6. Navigates to the update screen with `moveToNextOtherScreen(Screen.KKW01024)`

#### `actionDelete() → boolean`

Handles the "cancel/delete" button press. Key steps:
1. Re-displays info, extracts the selected campaign by the `SELECTED` index
2. **Business rule check**: If the campaign's discount service code is `WRIB_SVC_CD_CHO_WARI` (long-term usage discount), the operation is rejected with error `EKB0290-JW` — long-term discounts cannot be cancelled through this screen
3. **Juratictional special corp check** via `checkJctSpclCp()` — if `SAME_KAISEN_FLG_03` is `"0"`, the cancellation is blocked with error `EKBF190_KW`
4. **Type code validation** via `isNotErrChkWribTypeCd()` — blocks "42: Quota-locked discount" type cancellations
5. Sets screen info for KKW01030 (the cancellation selection screen) with contract number list, contract type list, and a select type of `WRIB_DSL_CNCL` (cancel single)
6. Navigates to the cancellation confirmation screen

#### `actionBulkDelete() → boolean`

Similar to `actionDelete()`, but for bulk cancellation. The key difference is that it sets the select type in the target screen info to `WRIB_DSL_CNCL_ALL` (cancel all) instead of `WRIB_DSL_CNCL`. This signals the target screen to process all selected campaigns for cancellation.

#### `actionDetail() → boolean`

Handles the "details" button press. It:
1. Re-displays info, resolving the source screen (KKW01021 or KKW01022) from the common info bean
2. Extracts the selected campaign by `SELECTED` index
3. Gets contract number and contract type arrays
4. Sets screen info for KKW01023 (the detail screen)
5. Navigates to the detail screen

#### `actionHistory() → boolean`

Navigates from the list screen to the history screen (KKW01022). It re-displays info and passes the customer contract continuation list to the history screen via `setScreenInfo`.

#### `actionReturn() → boolean`

Handles the "back" button on the list screen. Calls `backToNextOtherScreen()` which reads the return-screen ID that was previously stored via `JCCWebCommon.setScreenId()` and navigates back to it.

#### `actionReturnToIcrn() → boolean`

Handles the "back" button specifically from the cancellation screen (KKW01030). It calls `moveToNextSameScreen(Screen.KKW01021)` to return to the campaign list screen, preserving the same screen session.

### Screen Navigation Helpers

#### `moveToNextSameScreen(String, String) / moveToNextSameScreen(Screen)`

Sets `NEXT_SCREEN_ID` and `NEXT_SCREEN_NAME` in the common info bean, used when navigating within the same screen session (preserves session state).

#### `moveToNextOtherScreen(String) / moveToNextOtherScreen(Screen)`

Sets only `NEXT_SCREEN_ID` in the common info bean, used when navigating to a different screen (e.g., list → detail). This does NOT set the screen name.

#### `backToNextOtherScreen()`

Reads the previously stored return screen ID via `JCCWebCommon.getScreenId(this)` and sets it as the `NEXT_SCREEN_ID`, enabling the user to navigate back to the screen they came from.

### Utility / Private Methods

#### `editWribCampaignList(X31SDataBeanAccess bean, Screen screen) → void`

A core private method that populates the campaign list displayed on the screen. It:
1. Calls the business service `KKSV0229` with `FunctionCode.ICRN_SHOKAI` to fetch campaign data
2. Filters the campaign list based on screen type:
   - **KKW01021 (list screen)**: Shows only active campaigns — contract type `"w"` (discount service) with status `"010"` (received) or `"200"` (service provision in progress); and contract type `"d"` (data extraction) with status `"010"` (received)
   - **KKW01022 (history screen)**: Shows all campaigns without filtering
3. Normalizes date fields (`STAYMD_03`, `ENDYMD_03`, `MSKM_YMD_03`) — replacing empty/invalid/max dates with empty strings for display
4. **Preserves selected campaign** on post-back: scans the result list to find the campaign matching `selectedWribSvcCd` (now `NO_03` as of v6.00.00) and sets the `SELECTED` index. If no match is found, defaults to `"0"` if campaigns exist, or `""` if the list is empty
5. Writes the filtered list back to the bean via `Mover.setBeanMapToDataBean()`

This method is the bridge between the backend service and the UI, performing the view-model transformation.

#### `isNotErrChkWribTypeCd(String typeCd, String errMsg1, String errMsg2) → boolean`

Private validation method. Checks if the given discount type code equals `"42"` (Quota-locked discount — 契約割引き). If so, sets an error message via `JPCOnlineMessageConstant.EKB5420_JW` with the provided error message strings and returns `false`. Returns `true` for all other type codes (or `null`). This prevents operations that are not allowed on quota-locked contracts.

#### `checkJctSpclCp(String sameKaisenFlg) → boolean`

Private check for jurisdictional special corporation (自治体特別GP) cancellation. If `sameKaisenFlg` equals `"0"` (flag is OFF), the operation is blocked with error `EKBF190_KW` and returns `false`. Returns `true` if the flag allows the operation. This enforces a business rule specific to municipal/government contracts.

#### `actionInitKKW01021() → void`

Full initialization for the campaign list screen (KKW01021). Sets screen name, retrieves screen info, registers return-screen mappings for **seven** downstream screens (KKW01022, KKW01023, KKW01024, KKW01026, KKW01027, KKW01029, KKW01030, KKW01032), and calls `editWribCampaignList()` to populate the list.

#### `actionInitKKW01022() → void`

Full initialization for the campaign history screen (KKW01022). Similar to `actionInitKKW01021()` but only registers KKW01023 as a return-screen and calls `editWribCampaignList()` with the history screen context.

## Relationships

```mermaid
flowchart TD
    A["KKW01021SFLogic<br/>Screen Transition Handler"] --> B["JCCWebBusinessLogic<br/>Base Web Logic"]
    A --> C["WEBGAMEN_KKW010210PJP<br/>List Screen Controller"]
    A --> D["WEBGAMEN_KKW010220PJP<br/>History Screen Controller"]
    A --> E["x31business_logic_KKW01021SF<br/>Business Logic Layer"]
    A --> F["Screen KKW01021<br/>Campaign List"]
    A --> G["Screen KKW01022<br/>Campaign History"]
    A --> H["Screen KKW01023<br/>Detail"]
    A --> I["Screen KKW01024<br/>Update"]
    A --> J["Screen KKW01027<br/>Add"]
    A --> K["Screen KKW01030<br/>Cancellation"]
```

### Dependencies

**Inbound (3 classes depend on this):**
- **WEBGAMEN_KKW010210PJP.xml** — The list screen controller that invokes `KKW01021SFLogic` methods for all list-screen actions (init, add, update, delete, bulk delete, detail, history, return)
- **WEBGAMEN_KKW010220PJP.xml** — The history screen controller with similar invocation patterns
- **x31business_logic_KKW01021SF.xml** — The business logic layer that delegates to this class for screen-level operations

**Outbound:**
- **JCCWebBusinessLogic** — Parent class providing session/DataBean management, screen info retrieval, and common utilities

The class uses numerous internal service beans, constants, and helper classes:
- `X31SDataBeanAccess` — Service form DataBean
- `BeanMap` — Internal subclass of `HashMap<String, Object>` with a `pair()` helper for putting key-value pairs
- `JCCWebCommon`, `JKKScreenConst`, `KKW01021SFConst`, `KKW01023SFConst`, `KKW01024SFConst`, `KKW01030SFConst` — Constants and utilities
- `Service.KKSV0229.invokeAndApplySFBean()` — Business service call for fetching campaign data
- `Screen` — Enum or constant class defining screen identifiers

## Usage Example

A typical flow for editing a discount campaign contract:

1. The user views the campaign list screen (KKW01021). The controller calls `actionInit()`, which dispatches to `actionInitKKW01021()`. This calls `editWribCampaignList()` which fetches campaigns from service `KKSV0229`, filters them, and populates the list.
2. The user selects a campaign row and clicks the "edit" button. The JSF page triggers the `actionUpdate()` method.
3. `actionUpdate()` re-displays the info (to preserve list state), extracts the selected campaign by index, validates that it's not a "42: Quota-locked discount" type, and then sets up the target screen (KKW01024) with the contract number and type.
4. The controller navigates to KKW01024, where the user edits the campaign details.
5. The user clicks "back", which triggers `actionReturn()` — the controller navigates back to KKW01021 using the return-screen ID stored during initialization.

```
User → JSF Page → WEBGAMEN_KKW010210PJP → KKW01021SFLogic.actionUpdate()
  → JCCWebCommon.setScreenInfo() → moveToNextOtherScreen(Screen.KKW01024)
  → Display KKW01024 (Update Form)
  → User clicks back → actionReturn() → backToNextOtherScreen() → KKW01021
```

## Notes for Developers

- **Not thread-safe**: This class operates on instance fields inherited from `JCCWebBusinessLogic` (DataBeans, session state). Each request gets a new instance. Do not share instances across threads.
- **Screen ID magic strings**: The class references many screen IDs (KKW01021, KKW01022, KKW01023, etc.) as constants. Adding a new screen in the campaign module requires updating both this class and the corresponding XML controller files.
- **Validation gatekeepers**: Two private methods (`isNotErrChkWribTypeCd` and `checkJctSpclCp`) gate critical operations. Any new operation that modifies campaign contracts should call these checks to enforce the same business rules.
- **State preservation**: The `reDispInfo()` method is called before every CRUD action. It's critical for post-back scenarios (e.g., if validation fails on the target screen and the user navigates back). It preserves the customer contract list and the selected campaign's service code.
- **`BeanMap` is a custom subclass**: The nested `BeanMap` class extends `HashMap<String, Object>` and adds a `pair()` convenience method. It also has a `take()` method (not shown in this file) that likely retrieves and removes values — use `take()` for values that should be consumed once (e.g., `SELECTED`).
- **Date normalization in `editWribCampaignList()`**: The method normalizes invalid date fields to empty strings. The constant `MAX_YMD` represents a sentinel "max date" value — these are treated as null and blanked for display. Be careful not to rely on these fields being non-null.
- **Version-gated changes**: The source code contains numerous version-gated change markers (e.g., `// v4.02.00 ...`, `// ANK-3383-09-00`). These indicate when specific business rules or features were added. Future changes should follow the same pattern.
- **`actionUpdate` vs `actionDelete` overlap**: Both methods perform similar validation (type code check, re-display info, extract selected campaign). The main difference is the target screen (KKW01024 for update, KKW01030 for deletion) and the additional `checkJctSpclCp` guard in delete. Consider if these could share a common validation method.
- **Error handling**: Methods return `true` on success and `false` on specific business-rule violations (not exceptions). The caller (JSF controller) interprets this boolean to decide whether to proceed with navigation or display an error. Always check the return value.
