# SignalR Endpoints and External Integrations

> Part of `Nop.Plugin.Misc.FruitBankPlugin`. See `README.md` for project overview.
> For measurement workflows see `docs/MEASUREMENT.md`.
> For data layer see `docs/DATA_LAYER.md`.

The plugin communicates with FruitBankHybridApp (MAUI client) via SignalR. Methods decorated with `[SignalR]` attributes auto-broadcast results to connected clients.

## SignalR Configuration

Configured in `PluginNopStartup`:

| Setting | Value |
|---|---|
| KeepAliveInterval | 30 seconds |
| ClientTimeoutInterval | 30 seconds |
| MaximumReceiveMessageSize | 30 MB |
| EnableDetailedErrors | true |
| StatefulReconnectBufferSize | 30 MB |
| **HubProtocol** | **`AcBinaryHubProtocol`** (singleton `IHubProtocol`) |

**Wire protocol:** `AcBinaryHubProtocol` (`AyCode.Services.SignalRs`, from `AyCode.Services.dll`) — custom binary `IHubProtocol` using `AcBinarySerializer`. Eliminates JSON+Base64 overhead. Requires `TransferFormat.Binary` → WebSocket transport only. Protocol name: `"acbinary"`. Registered as `services.AddSingleton<IHubProtocol>(new AcBinaryHubProtocol())` after `AddSignalR()`.

Hubs registered: `DevAdminSignalRHub`, `LoggerSignalRHub` (from AyCode.Core.Server).

## FruitBankHub

`Services/FruitBankHub.cs` — Minimal hub inheriting `Hub`.

| Method | Purpose |
|---|---|
| `SendMessage(string user, string message)` | Broadcast message to all connected clients |

## CustomOrderSignalREndpoint

`Areas/Admin/Controllers/CustomOrderSignalREndpoint.cs` — Order management via SignalR. Implements `ICustomOrderSignalREndpointServer`.

### Query Methods

| Method | Parameters | Returns | Broadcast Tag |
|---|---|---|---|
| `GetAllOrderDtos()` | — | Orders from last 15 days with relations | — |
| `GetOrderDtoById` | orderId | Single order with relations | — |
| `GetPendingOrderDtos()` | — | Pending status orders | — |
| `GetPendingOrderDtosForMeasuring` | lastDaysCount | Orders for measurement (unpaid, not cancelled, with DateOfReceipt) | — |
| `GetAllOrderDtoByIds` | orderIds[] | Batch retrieval | — |
| `GetAllOrderDtoByProductId` | productId | Orders containing product | — |

### Mutation Methods

| Method | Parameters | Broadcast Tag | Key Logic |
|---|---|---|---|
| `StartMeasuring` | orderId, userId | `SendOrderChanged` | Sets MeasurementOwnerId, OrderStatus=Processing, PaymentStatus=Pending |
| `SetOrderStatusToComplete` | orderId, revisorId | `SendOrderChanged` | Validates pallets, recalculates prices, updates stock, publishes OrderPaidEvent |
| `AddOrUpdateMeasuredOrderItemPallet` | OrderItemPallet | `SendOrderItemPalletChanged` | Saves pallet, triggers price recalculation |

### Order Item & Pallet Queries

| Method | Purpose |
|---|---|
| `GetOrderItemDtosByOrderId` | Items for a specific order |
| `GetOrderItemPalletsByOrderItemId` | Pallets for a specific item |
| `GetOrderItemPalletById` | Single pallet |

## StockSignalREndpointServer

`Areas/Admin/Controllers/StockSignalREndpointServer.cs` — Inventory management via SignalR.

| Method | Parameters | Key Logic |
|---|---|---|
| `GetStockTakings` | loadRelations | All stock taking sessions |
| `AddStockTaking` | StockTaking | Creates session, auto-populates items from products + pending order items |
| `CloseStockTaking` | stockTakingId | Validates all measured, applies stock corrections, marks closed |
| `UpdateStockTaking` | StockTaking | Updates session |
| `RefreshStockTakingItem` | stockTakingItemId | Refreshes measured values from pallets |
| `GetStockTakingItems` | loadRelations | All items |
| `GetStockTakingItemsByStockTakingId` | stockTakingId | Filtered items |
| `AddOrUpdateMeasuredStockTakingItemPallet` | StockTakingItemPallet | Saves pallet, refreshes item values |

## FruitBankDataController

`Controllers/FruitBankDataController.cs` — Main data API implementing `IFruitBankDataControllerServer`. Methods decorated with `[SignalR]` attributes for FruitBankHybridApp integration.

### Shipping Operations

| Method | Purpose |
|---|---|
| `GetShippings()` | Last 15 days with relations |
| `GetNotMeasuredShippings()` | Incomplete shipments |
| `GetShippingById` / `AddShipping` / `UpdateShipping` | CRUD |
| `GetShippingItems` / `AddShippingItem` / `UpdateShippingItem` | Item CRUD |
| `GetShippingItemPallets` / `AddShippingItemPallet` / `UpdateShippingItemPallet` | Pallet CRUD |
| `AddOrUpdateMeasuredShippingItemPallet` | Measurement + average weight update + cascade |
| `GetShippingDocuments` / `AddShippingDocument` | Document operations, updates product costs on add |
| `ProcessAndSaveFullShippingJson` | Parses FullProcessModel JSON, saves complete shipping data |

### Partner Operations

| Method | Purpose |
|---|---|
| `GetPartners()` | All partners |
| `GetPartnerById` / `AddPartner` / `UpdatePartner` | CRUD |

### Product & Attribute Operations

| Method | Purpose |
|---|---|
| `GetProductDtos()` | All products with GenericAttributes |
| `GetProductDtoById` | Single product |
| `GetGenericAttributeDtosByEntityIdAndKeyGroup` | Custom attributes by entity + key group |
| `AddGenericAttributeDto` / `UpdateGenericAttributeDto` | Attribute CRUD |

### User & Auth Operations

| Method | Purpose |
|---|---|
| `GetMeasuringUsers()` | Users in "Measuring" role |
| `GetCustomerRolesByCustomerId` | Customer roles |
| `LoginMeasuringUser` | Authentication with role check |

### Stock History

| Method | Purpose |
|---|---|
| `GetStockQuantityHistoryDtos()` | Last 15 days |
| `GetStockQuantityHistoryDtosByProductId` | Product-filtered history |

## InnVoice Integration (Billingo)

### InnVoiceOrderService

`Services/InnVoiceOrderService.cs` — Order synchronization with Billingo/InnVoice accounting system via XML API.

| Method | Purpose |
|---|---|
| `CreateOrdersAsync(List<OrderCreateRequest>)` | Batch order creation |
| `CreateOrderAsync(OrderCreateRequest)` | Single order creation |
| `GetOrdersByUpdateTimeAsync(DateTime)` | Query by last update time |
| `GetOrdersByDateAsync(DateTime)` | Query by order date |
| `GetOrderByTechIdAsync(int)` | Query by InnVoice tech ID |
| `GetOrderByTableIdAsync(int)` | Query by table ID |

**Models:** `OrderCreateRequest`, `OrderCreateResponse`, `InnVoiceOrder`, `InnVoiceOrderLineItem`

### InnvoiceApiService

`Services/InnvoiceApiService.cs` — Invoice CRUD with Billingo XML API.

| Method | Purpose |
|---|---|
| `GetInvoiceByIdAsync` / `GetInvoiceByNumberAsync` / `GetInvoiceByTechIdAsync` | Invoice queries |
| `GetInvoicesByDateRangeAsync` | Date-range filtered invoices |
| `CreateInvoiceAsync` / `UpdateInvoiceAsync` | Invoice CRUD |

**Models:** `Invoice`, `InvoiceLineItem`, `InvoiceCreateRequest`, `InvoiceCreateResponse`

Both services build and parse XML payloads. Called from `InnVoiceOrderController` and `InnVoiceOrderSyncController`.

## FruitBankAttributeService

`Services/FruitBankAttributeService.cs` — GenericAttribute CRUD helper for measurement-related attributes.

| Method | Purpose |
|---|---|
| `GetGenericAttributeValueAsync<TEntity, TPropType>` | Type-safe attribute retrieval |
| `GetMeasuringAttributeValuesAsync<TEntity>` | Get IsMeasurable, NetWeight, Tare, etc. as batch |
| `InsertOrUpdateMeasuringAttributeValuesAsync<TEntity>` | Upsert measurement attributes |
| `IsMeasurableEntityAsync<TEntity>` | Check if entity's product is measurable |

Supports cumulative weight updates (adds to existing value rather than replacing).
