composite & deleted
This commit is contained in:
63
productSync.md
Normal file
63
productSync.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# Product Sync Protocol
|
||||
|
||||
## The Sync Flow
|
||||
|
||||
1. **The POS client polls `/api/v1/init`** with its current `lastChangedProduct` cursor (e.g. `24599`). The server counts how many products have a row version greater than that cursor and returns the count.
|
||||
|
||||
2. **If `product_count > 0`**, the client fetches `/api/v1/product` with the same cursor and a `limit` (e.g. 20). The server returns the changed products ordered by row version ascending.
|
||||
|
||||
3. **The client updates its local cursor** to the highest `lastChanged` value it received in that batch (e.g. `24609`), so the next poll only fetches newer changes.
|
||||
|
||||
### Example from the log
|
||||
|
||||
```
|
||||
init with lastChangedProduct=24599 -> product_count=0 (no changes)
|
||||
init with lastChangedProduct=24599 -> product_count=1 (a new product appeared)
|
||||
product fetch lastChangedProduct=24599 -> returns product with lastChanged=24609
|
||||
init with lastChangedProduct=24609 -> product_count=0 (caught up)
|
||||
```
|
||||
|
||||
## What is `lastChangedProduct`?
|
||||
|
||||
It's the **MSSQL `bRowversion`** value -- an auto-incrementing binary counter that SQL Server bumps whenever a row is modified. The queries in `product-count.js` and `product-list.js` filter with:
|
||||
|
||||
```sql
|
||||
WHERE CONVERT(BIGINT, a.bRowversion) > @cursor
|
||||
```
|
||||
|
||||
The client simply persists the highest `lastChanged` value it received so it only gets new/changed rows on subsequent polls.
|
||||
|
||||
## How it's kept track
|
||||
|
||||
**Server side**: The cursor is stateless -- the client sends its last-known value every time. The server just runs the SQL query filtering rows above that value.
|
||||
|
||||
**Client side**: The POS client stores its `lastChangedProduct` (and `lastChangedCategory`, `lastChangedCustomerGroup`, etc.) persistently so it can resume syncing after a restart without re-downloading everything.
|
||||
|
||||
## Other entity types
|
||||
|
||||
The same pattern applies to:
|
||||
|
||||
- **Categories** (`lastChangedCategory` / `bRowversion` on `tKategorie`)
|
||||
- **Customer groups** (`lastChangedCustomerGroup` / `bRowversion` on `tKundenGruppe`)
|
||||
- **Composite products** (`lastChangedCompositeProduct` / `bRowversion` on `tArtikelBaugruppe`)
|
||||
- **Deleted entities** (`lastChangedDeletedEntity` / `bLastChanged` on `Pos.vDeletedEntity`)
|
||||
|
||||
## Deleted entity sync
|
||||
|
||||
When entities are deleted in JTL-Wawi, they appear in the `Pos.vDeletedEntity` view with their entity type:
|
||||
|
||||
| nEntityType | Entity |
|
||||
|---|---|
|
||||
| 1 | Artikel (Product) |
|
||||
| 2 | Kategorie (Category) |
|
||||
| 7 | Stückliste (Composite Product) |
|
||||
|
||||
The client polls `/v1/init` with `lastChangedDeletedEntity` cursor, and if `deletedEntity_count > 0`, fetches `/v1/deletedentity` to get the list of deleted entities. The response format is:
|
||||
|
||||
```json
|
||||
[
|
||||
{ "entityId": "123", "entityType": "1", "lastChanged": "208980" }
|
||||
]
|
||||
```
|
||||
|
||||
The client then removes these entities from its local database.
|
||||
Reference in New Issue
Block a user