Files
JiriUhlirandClaude Opus 5 225161e4ca revize endpointu: cteni NullableProperty, filtr v UTC, attachments
Kontrola vsech 180 operaci proti falesnemu iDoklad API a round trip
331 modelu SDK v obou smerech.

- SdkNullablePropertyConverter doplnuje cteni NullableProperty<T>.
  Konvertor SDK umi jen zapis, takze PATCH s takovou polozkou koncil
  prazdnou 500 uz pri cteni tela. Tykalo se 29 modelu. Zapis zustava
  na konvertoru SDK, odchozi payload se nemeni.
- Datum uvnitr NullableProperty se normalizuje na UTC stejne jako
  zbytek serializace.
- ListModifiers parsuje datum ve filtru s AdjustToUniversal a
  AssumeUniversal. Filtr se zonou se drive posouval o offset.
- POST /attachments kontroluje FileName a FileBytes, SDK na ne sahalo
  bez kontroly na null a vracelo neosetrenou 500.
- ExceptionHandlingMiddleware ma posledni zachyt, zadny request uz
  nekonci prazdnou 500.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 11:13:21 +02:00

73 lines
3.8 KiB
Markdown

# Revize všech endpointů po opravě datumů
Kontrola navazuje na [datumy-utc.md](datumy-utc.md). Cílem bylo najít další místa se stejnou
povahou chyby, tedy vstup, který služba přijme, ale SDK nebo iDoklad ho odmítne, případně
tichý posun hodnoty.
## Jak se to ověřovalo
1. Reflexní round trip všech 331 modelů SDK (Post, Patch, Get) přesně tím nastavením
serializace, které používá služba: serializace odpovědi i deserializace requestu.
2. Běh služby proti falešnému iDoklad API, které zachytává odchozí requesty. Projeto všech
180 operací z OpenAPI dokumentu a zkontrolováno, co se skutečně odesílá.
3. Porovnání klienta `iDoklad.cs` proti OpenAPI dokumentu služby, cesta i HTTP metoda.
## Nálezy a opravy
### 1. PATCH padal na NullableProperty (vážné)
Patch modely používají `NullableProperty<T>`, aby šlo odlišit nevyplněnou položku od položky
nastavené na null. Konvertor SDK `NullablePropertyJsonConverter` umí jen zápis, jeho `ReadJson`
vyhazuje `NotImplementedException`, protože SDK Patch modely nikdy nedeserializuje. Tato služba
je deserializovat musí, takže PATCH s takovou položkou skončil prázdnou 500 už při čtení těla.
Týkalo se to 29 modelů, mimo jiné `IssuedInvoicePatchModel`, `ReceivedInvoicePatchModel`,
`ProformaInvoicePatchModel`, `ContactPatchModel` a `CreditNotePatchModel`. Endpoint spadl podle
toho, které položky klient poslal, takže se chyba projevovala nepravidelně.
Oprava: `Infrastructure/SdkNullablePropertyConverter.cs` čtení doplňuje, zápis nechává na
konvertoru SDK, takže odchozí payload se nemění. Zaregistrováno v `SdkContractResolver`.
Ověřeno, že sémantika zůstává správná: položka vynechaná v těle requestu se do iDokladu
neodešle. PATCH tedy nepřepisuje pole, která klient neuvedl.
### 2. Datum uvnitř NullableProperty nebylo v UTC
Když je na položce konvertor, Newtonsoft předá hodnotu jako řetězec a `DateTimeZoneHandling`
se na ni neuplatní. Datum uvnitř `NullableProperty<DateTime>` proto zůstávalo `Unspecified`
a narazilo by na stejnou kontrolu SDK jako u vydaných faktur. Konvertor hodnotu normalizuje
stejným pravidlem jako zbytek serializace.
### 3. Filtr s časovou zónou posouval čas (tiché)
`Client/ListModifiers.cs` parsoval datum ve filtru bez příznaků zóny. Filtr
`(DateOfTaxing~gte~2024-01-01T00:00:00Z)` se do iDokladu odeslal jako `2024-01-01 01:00:00`,
tedy posunutý o hodinu, a `+02:00` se posunulo o dvě. Chyba nic nenahlásila, jen vracela jiná
data. Opraveno na `AdjustToUniversal | AssumeUniversal`.
### 4. POST /attachments vracel prázdnou 500
`AttachmentUploadModel` nemá žádné validační atributy a SDK sahá na jméno souboru bez kontroly
na null. Chybějící `FileName` nebo `FileBytes` tedy skončily neošetřenou `NullReferenceException`.
Doplněna kontrola v `IntegrationController`, chybějící pole nyní vrací 400.
### 5. Poslední záchyt v middleware
`ExceptionHandlingMiddleware` má nově i `catch (Exception)`. Neočekávaná chyba se zaloguje
a vrátí jako 400 nebo 500 s typem výjimky v těle. Žádný request už nekončí prázdnou 500,
ze které nebylo poznat vůbec nic.
## Co bylo v pořádku
- Query parametr `lastCheck` u `GET /system/code-books/changes`. Binder MVC normalizuje
hodnotu na UTC správně, `Z` i offset i tvar bez zóny dávají správný okamžik.
- Serializace odpovědí. Round trip 331 modelů proběhl bez chyby v obou směrech.
- Klient `iDoklad.cs`. Ze 177 rozpoznaných volání neodpovídá službě ani jedno špatnou cestou
nebo metodou.
## Výsledek
Všech 180 operací proti falešnému iDoklad API: 125 vrátilo 200, 55 vrátilo 400 kvůli
záměrně neúplnému testovacímu tělu, žádná nevrátila 5xx. Původní tělo z logu klienta,
které chybu odstartovalo, projde a do iDokladu odejde se správnými datumy.