# YspSimulator

A fake Yalamanchili (YSP) server for developing and testing QRMiddleLayer
without access to the real YSP hosts. It covers two things:

- **The Narada card API** from "Narada-CORE-REST-API Specifications V2.3"
  (the PDFs are not committed; get them from the team). QRMiddleLayer doesn't call this API yet.
- **The YSP calls QRMiddleLayer already makes**: payment notifications and
  merchant onboarding. There is no spec for these, so the simulator accepts what
  QRMiddleLayer sends and replies in the shape QRMiddleLayer parses.

```bash
mix deps.get
mix run --no-halt                  # port 4180; override with YSP_SIM_PORT=...
mix test
```

Restart the simulator after pulling changes. A running instance keeps serving the old code.

## Terminal log

In dev (Logger level `:info`) every call to the simulator, except `/_sim/*`,
prints a request block when it arrives and a response block when it is sent:

```
▶▶ req-7f3a 14:02:11.482 POST /naradaapiservices/api/v1/accountfunding ───
[req-7f3a] headers: [...]
[req-7f3a] request: { ...pretty JSON... }
◀◀ req-7f3a 200 in 12ms ───
[req-7f3a] response: { ...pretty JSON... }
```

The `req-` id is generated per call. Every line carries it, so `grep req-7f3a`
isolates one call. A call that never answers (`timeout` mode) shows only its
request block. To run a private copy on another port:
`YSP_SIM_PORT=4181 mix run --no-halt`.

## Pointing QRMiddleLayer at the simulator

Start the simulator first (`mix run --no-halt`, port 4180), then point QRMiddleLayer at it.

**Payment notifications.** On the `main` branch, QRMiddleLayer reads the YSP
notification URL from `config :da_product_app, :ysp_notification` in its
`config/config.exs` (`default_url`, currently a hardcoded host). To test against
the simulator, change it locally, without committing:

```elixir
config :da_product_app, :ysp_notification, %{
  default_url: "http://localhost:4180/mercuryapi/notify_payment",
  max_retry_attempts: 3,
  retry_interval_seconds: 30
}
```

**Merchant onboarding.** `main` has no YSP onboarding client yet. Versions of
QRMiddleLayer that do have one read these environment variables in
`config/runtime.exs`:

```bash
YSP_NOTIFICATION_URL=http://localhost:4180/mercuryapi/notify_payment \
YSP_ONBOARDING_BASE_URL=http://localhost:4180/naradaapiservices/yse \
YSP_PRIVATE_KEY_PATH=/path/to/private.pem \
mix phx.server
```

Onboarding requests are signed, so QRMiddleLayer needs a private key. For local
testing, generate a throwaway pair and give the public half to the simulator:

```bash
openssl genrsa -out /tmp/ysp_dev_private.pem 2048
openssl rsa -in /tmp/ysp_dev_private.pem -pubout -out /tmp/ysp_dev_public.pem
YSP_SIM_PUBLIC_KEY_PATH=/tmp/ysp_dev_public.pem mix run --no-halt
```

If `YSP_SIM_PUBLIC_KEY_PATH` isn't set, the simulator only checks that the
signature headers are present and well-formed.

## Endpoints

Only 14 of the 40 card endpoints are active. The payment notification and the
merchant routes are not card endpoints and are always on. The other 26 card
endpoints are still in the code but answer `404` with
`{"error": "endpoint_not_enabled", "message": "<name> is not enabled in this simulator"}`
and do not use up the `txnRefNo`. The list is in
`lib/ysp_simulator/active_endpoints.ex`: add a name there to switch an endpoint
back on. The gate is the `gate_endpoints` setting (on in `config/config.exs`,
off in the test environment so every endpoint is tested).

### Active endpoints

| What | Description | Method + path | Notes |
|---|---|---|---|
| 4.1 Purchase Card | Enrol a new customer and issue a card; maps to /customerregistration endpoint | `POST /naradaapiservices/api/v1/customerregistration` | apikey `APNCRD` |
| 4.2 Update Customer Details | Update KYC and personal details for an existing cardholder | `POST /naradaapiservices/api/v1/customerupdate` | apikey `APUPCR` |
| 4.3 Get Card Details | Retrieve card metadata including proxy number, status, and expiry | `POST /naradaapiservices/api/v1/carddetails` | apikey `APCHDT` |
| 4.4 Block/Unblock | Administratively block or restore a card | `POST /naradaapiservices/api/v1/cardlockunlock` | apikey `ACDSTS` |
| 4.5 Card Activation | Activate a newly issued card post-delivery | `POST /naradaapiservices/api/v1/cardactivation` | apikey `APCDAC` |
| 4.6 Card Replacement | Issue a replacement card for lost, stolen, or damaged cards | `GET /naradaapiservices/api/v1/cardreplacement` (JSON body; POST also accepted) | apikey `APCDRP` |
| 4.8 Load Card | Add funds to a card account (active or inactive card) | `POST /naradaapiservices/api/v1/accountfunding` | apikey `APLCRD` |
| 4.9 Query Balance | Retrieve the real-time available and ledger balance | `GET /naradaapiservices/api/v1/cardbalance` (JSON body) | apikey `APACBL` |
| 4.12 Get X Transactions | Fetch the last N transactions for a card account | `GET /naradaapiservices/api/v1/transactiondetails` (JSON body; POST also accepted) | apikey `APXTXN` |
| 4.13 Debit/Credit the Account | Post a manual debit or credit to a card account | `POST /naradaapiservices/api/v1/debitcreditaccount` | apikey `APCRDR` |
| 4.14 Fund Transfer | Transfer funds between internal accounts | `POST /naradaapiservices/api/v1/fundtransfer` | apikey `APFDTR` |
| 4.16 Card Order | Submit a card order for personalised/physical card production | `POST /naradaapiservices/api/v1/cardorder` | apikey `APCROR` |
| 4.20 Status Request | Retrieve the current operational status of any prior transaction | `GET /naradaapiservices/api/v1/statusrequest` (JSON body; POST also accepted) | apikey `APSTRQ` |
| 4.30 Card Order Status | Check the fulfilment status of a submitted card order | `GET /naradaapiservices/api/v1/cardorderstatus` (JSON body; POST also accepted) | apikey `APCOST` |

### Other routes (always on)

These are not card endpoints, so the gate does not apply to them.

| What | Method + path | Notes |
|---|---|---|
| Payment notification | `POST /mercuryapi/notify_payment` | Any JSON object → 200 `{"status": "received", "txnRefNo": ...}` |
| Merchant registration | `POST /naradaapiservices/yse/aps/api/v1/merchants/registration` | Needs `requestId` and `merchant.id`; approved immediately |
| Registration inquiry | `POST /naradaapiservices/yse/aps/api/v1/merchants/inquiryRegistrationStatus` | Needs `merchantId`; `APPROVED` or `RECORD_NOT_FOUND` |

### Inactive endpoints (answer 404)

| What | Method + path | Notes |
|---|---|---|
| 4.7 Account Addition | `POST /naradaapiservices/api/v1/accountaddition` | apikey `APACAD` |
| 4.10 Amount Refund | `POST /naradaapiservices/api/v1/amountrefund` | apikey `APCRND` |
| 4.11 Account Closure | `POST /naradaapiservices/api/v1/accountclosure` | apikey `APACCL` |
| 4.15 Exchange Rate | `POST /naradaapiservices/api/v1/exchangerate` | apikey `APFREX` |
| 4.17 Card Receipt | `POST /naradaapiservices/api/v1/cardreceipt` | apikey `APSTRC` |
| 4.18 Update Stock Details | `POST /naradaapiservices/api/v1/updatestockdetails` | apikey `APSKUP` |
| 4.19 Get Stock Details | `GET /naradaapiservices/api/v1/stockdetails` (JSON body; POST also accepted) | apikey `APGTSD` |
| 4.21 Change Password | `POST /naradaapiservices/api/v1/changepassword` | apikey `ACHPSS` |
| 4.22 Access Rights | `GET /naradaapiservices/api/v1/accessrights` (JSON body; POST also accepted) | apikey `APACRT` |
| 4.23 PIN Retrieval | `GET /naradaapiservices/api/v1/pinretrieval` (JSON body; POST also accepted) | apikey `APIPIR` |
| 4.24 ATM PIN Verification | `POST /naradaapiservices/api/v1/atmpinverification` | apikey `APIVER` |
| 4.25 ATM PIN Change | `POST /naradaapiservices/api/v1/atmpinchange` | apikey `APICHG` |
| 4.26 Assign Override Settings | `GET /naradaapiservices/api/v1/assignoverridesettings` (JSON body; POST also accepted) | apikey `AOVRST` |
| 4.27 Alert Settings | `POST /naradaapiservices/api/v1/alertsettings` | apikey `APALTS` |
| 4.28 Get Card Number | `GET /naradaapiservices/api/v1/cardnumberdetail` (JSON body; POST also accepted) | apikey `APIGCN` |
| 4.29 Get CSC Enquiry | `GET /naradaapiservices/api/v1/cscenquiry` (JSON body; POST also accepted) | apikey `ACSENQ` |
| 4.31 IVR PIN Set | `POST /naradaapiservices/api/v1/ivrpinset` | apikey `APIIVR` |
| 4.32 IVR PIN Change | `POST /naradaapiservices/api/v1/ivrpinchange` | apikey `APIIVC` |
| 4.34 IVR PIN Validation | `POST /naradaapiservices/api/v1/ivrpinvalidation` | apikey `APIPNV` |
| 4.35 Reset Web Password | `POST /naradaapiservices/api/v1/resetwebpassword` | apikey `APFORP` |
| 4.36 Retrieve Web Profile | `POST /naradaapiservices/api/v1/retrievewebprofile` (GET also accepted) | apikey `APUSPF` |
| 4.37 ATM PIN Set | `POST /naradaapiservices/api/v1/atmpinset` | apikey `APINST` |
| 4.38 New OTP Request | `POST /naradaapiservices/api/v1/newotprequest` | apikey `AFPOTP` |
| 4.39 OTP Validation | `POST /naradaapiservices/api/v1/otpvalidation` | apikey `AVPOTP` |
| 4.41 Set Limit Details | `POST /naradaapiservices/api/v1/setlimit` | apikey `ASTLMT` (not in the spec) |
| 4.42 Get Limit Details | `POST /naradaapiservices/api/v1/getlimit` (GET also accepted) | apikey `AGTLMT` (not in the spec) |

## More documentation

- [How the card API works](docs/how-it-works.md): the shared headers and checks, card numbers and statuses, and how to add an endpoint
- [What each endpoint does](docs/endpoints.md)
- [Exchange rates](docs/exchange-rates.md) and [PINs](docs/pins.md)
- [Simulator routes](docs/simulator-routes.md) (`/_sim/*`) and [seed data and config](docs/seed-data-and-config.md)
- [Behaviour the specs don't define](docs/behaviour/README.md): every choice the simulator made where the spec is silent
