# Datumy v requestech a UTC kontrola SDK ## Problém `POST /issued-invoices` (a stejně tak další Post/Patch endpointy) končil chybou HTTP 500 s prázdným tělem. V logu kontejneru: ```text IdokladSdk.Exceptions.IdokladValidationException: Model is not valid. DateTime must be in UTC format. DateTime must be in UTC format. DateTime must be in UTC format. DateTime must be in UTC format at IdokladSdk.Clients.BaseClient.ValidateModel[T](T model) at IdokladSdk.Clients.BaseClient.PostAsync[TPostModel,TGetModel](String resource, TPostModel model, ...) ``` Chyby byly čtyři, protože model faktury má čtyři datumy: `DateOfIssue`, `DateOfMaturity`, `DateOfTaxing` a `DateOfVatApplication`. Příčina: - Klient posílá datum bez časové zóny, například `"DateOfIssue":"2026-08-25"`. - Newtonsoft s výchozím `DateTimeZoneHandling.RoundtripKind` takovou hodnotu načte jako `DateTimeKind.Unspecified`. - SDK před odesláním requestu validuje model a u každé položky `DateTime` vyžaduje `Kind == Utc`. Validace tedy selhala ještě předtím, než se cokoli odeslalo do iDokladu. - `IdokladValidationException` dědí z `System.ComponentModel.DataAnnotations.ValidationException`, ne z `IdokladBaseException`. `ExceptionHandlingMiddleware` ji proto nezachytil a request skončil jako neošetřená 500 bez těla. Z odpovědi nebylo poznat, co je špatně. Ověřeno, že s tím nesouvisí změna serializace z [serializace-odpovedi.md](serializace-odpovedi.md). Deserializace stejného JSONu dává `Kind=Unspecified` shodně s původním `DefaultContractResolver` i s novým `SdkContractResolver`. ## Řešení | Soubor | Změna | | --- | --- | | `Program.cs` | `SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc` | | `Infrastructure/ExceptionHandlingMiddleware.cs` | nový `catch (IdokladValidationException)` mapovaný na HTTP 400 | Detaily: - `DateTimeZoneHandling.Utc` u hodnoty bez zóny pouze nastaví `Kind` na `Utc`, hodnotu neposouvá. Z `"2026-08-25"` vznikne `2026-08-25T00:00:00Z`, takže datum zůstává stejné. - Hodnota, která zónu nese (například `"2026-08-25T10:00:00+02:00"`), se přepočítá do UTC. To je požadované chování, iDoklad pracuje s UTC. - Nastavení platí pro celý serializer, tedy pro všechny agendy, ne jen pro vydané faktury. - Nový `catch` vrací `problem+json` se statusem 400, zprávou ze SDK a seznamem vadných vlastností v poli `invalidProperties`. Validační chyba už neskončí jako prázdná 500. ## Ověření 1. `dotnet build -c Release` bez chyb. 2. Deserializace původního JSONu z logu klienta: - před změnou všechny čtyři datumy `Kind=Unspecified` - po změně všechny čtyři `Kind=Utc` a shodná hodnota data 3. Běh služby lokálně, `POST /issued-invoices` se stejným tělem, jaké dřív padalo: - dříve: HTTP 500, prázdné tělo, v logu `DateTime must be in UTC format` - nyní: HTTP 401 `invalid_client`, tedy request prošel validací a došel až k přihlášení do iDokladu (test běžel s neplatnými credentials) 4. Model s chybějícími povinnými poli vrací HTTP 400 se seznamem chyb. Po nasazení musí projít: ```text POST https://services.csbot.cz/apps/idoklad/issued-invoices ``` s datumy ve tvaru `2026-08-25`.