# protocol-retailer

The `protocol-retailer` module provides the definitive implementation of the Retailer (POI-PIS) protocol. It is the primary high-level communication language between Sale Systems (ECR) and Payment Terminals (POI) within the App2AppSDK, featuring robust support for both XML and JSON data encapsulations.

## Overview

### `pl.novelpay.retailer`

The initialization and orchestration root for the protocol.

- src/main/java/pl/novelpay/retailer/RetailerProtocol.kt: The concrete implementation of `pl.novelpay.protocol.Protocol`.

- src/main/java/pl/novelpay/retailer/RetailerProtocolFactory.kt: The singleton factory that assembles the complex dependency graph of the Retailer module.

### `pl.novelpay.retailer.configuration`

Static environment and identity definitions.

- src/main/java/pl/novelpay/retailer/configuration/RetailerConfiguration.kt: Defines crucial terminal identification attributes such as `poiID`, `saleID`, and `SoftwareComponent` metadata.

### `pl.novelpay.retailer.client`

The primary developer surface for interacting with the Retailer protocol.

- src/main/java/pl/novelpay/retailer/RetailerProtocol.kt: An exhaustive API contract defining business capabilities (`sendPaymentRequest`, `sendReversalRequest`, etc.).

- src/main/java/pl/novelpay/retailer/client/RetailerCommunicationInterfaceImpl.kt: The concrete router that binds high-level SDK method calls to underlying domain message generation.

### `pl.novelpay.retailer.message`

The domain model declarations, strictly categorized by intent.

- `request.*`: Initiators of operations (e.g., src/main/java/pl/novelpay/retailer/message/request/RetailerPaymentRequest.kt, src/main/java/pl/novelpay/retailer/message/request/RetailerLoginRequest.kt).

- `response.*`: Results of operations (e.g., src/main/java/pl/novelpay/retailer/message/response/RetailerPaymentResponse.kt).

- src/main/java/pl/novelpay/retailer/message/RetailerRawMessageType.kt: The low-level envelope representing the raw XML/JSON string before domain parsing.

### `pl.novelpay.retailer.conversion`

The transformation engine powering the protocol.

- src/main/java/pl/novelpay/retailer/conversion/RetailerRawDomainConverterImpl.kt: Uses strategy patterns (src/main/java/pl/novelpay/retailer/converter/set/RetailerConvertersSet.kt) to map parsed XML/JSON into concrete Kotlin data classes.

- src/main/java/pl/novelpay/retailer/conversion/RetailerRawTypeConverterImpl.kt: The `RawReader` implementation that performs the initial text analysis to determine message type.

### `pl.novelpay.retailer.runtime`

Session and state persistence.

- src/main/java/pl/novelpay/retailer/runtime/RetailerProtocolRuntimeStorage.kt: Maintains dynamic configuration like the active `MessageFormat` (XML vs JSON) and session IDs.

## Standard Usage Example

    // Obtain the communication interface interface
    val retailerApi = sdk.provideCommunicationInterface(RetailerCommunicationInterface::class)

    // Configure protocol optimizations dynamically
    retailerApi.switchMessageFormat(MessageFormat.JSON)

    // Dispatch a domain operation
    retailerApi.sendPaymentRequest(
        PaymentRequestMessageArguments.RegularPaymentRequestMessageArguments(
            amount = 125.50,
            currency = "PLN"
        )
    )

Content copied to clipboard

## Protocol Versioning and Message Migration

To ensure backward compatibility between the SDK and the payment application, the SDK implements a message migration mechanism. This system allows the SDK to modify outgoing domain messages on-the-fly to conform to the specific protocol version supported by the connected payment application.

### The Migration Process

1. Version Detection: When the SDK establishes a connection, it queries the payment application to get the specific version of the `Retailer` protocol it is using. This is handled by `ProtocolVersionMigrationEnvironmentImpl`, which makes an IPC call to the server.

2. Migration Execution: Before a `DomainMessage` is sent, it passes through the `MigrateSendingDomainMessage` processor. This processor applies a list of registered migrations to the message. Each migration is a class that extends `MessageMigration`.

3. Conditional Logic: Inside each migration class, the `ServerClientMigrationEnvironment` provides helper functions like `forVersions(...)` and `notForVersions(...)` to execute logic conditionally based on the detected protocol version.

### Example: `DonationsMigration`

A practical example is the `DonationsMigration`. If a new `donations` field was added in version `1.3` of the protocol, older versions of the payment application would not understand it. This migration ensures that for any protocol version that is not `1.3`, the `donations` field is removed from the `RetailerPaymentRequest` before it is sent.

    // DonationsMigration.kt
    class DonationsMigration : MessageMigration() {
        override fun migrate(message: DomainMessage): DomainMessage =
            // Only run this logic for versions that are NOT "1.3"
            serverClientMigrationEnvironment.notForVersions("1.3") { version ->
                when (message) {
                    is RetailerPaymentRequest -> message.copy(
                        // Remove the unsupported field
                        marketpayPaymentExtensions = extensions.copy(additionalAmount = null)
                    )
                    else -> message
                }
            } ?: message // If the version is 1.3, return the original message
    }

Content copied to clipboard

### Important: Maintaining Migrations

> It is crucial to maintain migration classes as new protocol versions are released. For example, the `DonationsMigration` uses `notForVersions("1.3")`. If a new version `1.4` is released (which presumably supports donations), this logic would incorrectly remove the donations field when communicating with a `1.4` server.

> To prevent this, migrations must be updated to be explicit about the versions they target. The logic should be changed to either:

> - Specify incompatible versions: `forVersions("1.0", "1.1", "1.2") { ... }`

> - Explicitly exclude all newer versions: `notForVersions("1.3", "1.4") { ... }`

> Forgetting to update these classes will lead to incorrect message formatting and potential communication failures with new server versions.

## Packages

pl.novelpay.protocol.converter.utls
Link copied to clipboard
jvm
pl.novelpay.retailer
Link copied to clipboard
jvm
pl.novelpay.retailer.analyze.validator
Link copied to clipboard
jvm
pl.novelpay.retailer.configuration
Link copied to clipboard
jvm
pl.novelpay.retailer.extensions
Link copied to clipboard
jvm
pl.novelpay.retailer.message
Link copied to clipboard
jvm
pl.novelpay.retailer.message.notification
Link copied to clipboard
jvm
pl.novelpay.retailer.message.payment
Link copied to clipboard
jvm
pl.novelpay.retailer.message.request
Link copied to clipboard
jvm
pl.novelpay.retailer.message.request.display
Link copied to clipboard
jvm
pl.novelpay.retailer.message.response
Link copied to clipboard
jvm
pl.novelpay.retailer.message.response.admin
Link copied to clipboard
jvm
pl.novelpay.retailer.migration
Link copied to clipboard
jvm
pl.novelpay.retailer.parser.admin
Link copied to clipboard
jvm
pl.novelpay.retailer.parser.exception
Link copied to clipboard
jvm
pl.novelpay.retailer.runtime
Link copied to clipboard
jvm
pl.novelpay.retailer.wrapper.exception
Link copied to clipboard
jvm