Pomoc z rysunkami ekranow, kafelki na cala szerokosc, kalkulator na danych GUS i Eurostatu
Deploy Polska Lokalnie / deploy (push) Successful in 22s
Deploy Polska Lokalnie / deploy (push) Successful in 22s
Pomoc i kontakt: - kanaly kontaktu wypelniaja szerokosc panelu (auto-fit zamiast czterech kolumn) - FAQ podzielone na cztery moduly, 21 pytan, ze schematycznymi rysunkami ekranow (inline SVG w helpIllustrations.tsx - nie zrzuty, wiec nie dezaktualizuja sie) - menu konta nie przykleja sie juz nad trescia na telefonie i tablecie Kafelki wyboru: - kolumna nie schodzi ponizej czytelnej szerokosci, podpisy lamia sie miedzy slowami zamiast po literach (bylo widoczne na monitorach ok. 1440 px) Kalkulator zdolnosci kredytowej: - rodzaj oprocentowania decyduje o buforze: 2,5 p.p. przy stalym, 5 p.p. przy zmiennym (wczesniej zawsze 2,5 p.p., co zawyzalo zdolnosc przy zmiennej stopie o ok. 100 tys. zl) - nowy modul market: przecietne wynagrodzenie z GUS BDL i stopa rynku pienieznego 3M z Eurostatu, odswiezane co tydzien, publiczny GET /api/market-indicators - prog wyzszego DStI i podpowiadane oprocentowanie licza sie z tych wskaznikow, z podpisem zrodla i okresu; brak danych = wartosci zapasowe Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -55,6 +55,8 @@ public class SecurityConfig {
|
||||
.requestMatchers(HttpMethod.GET, "/api/og/**").permitAll()
|
||||
// Historia srednich cen z ogloszen - publiczna, jak same ogloszenia.
|
||||
.requestMatchers(HttpMethod.GET, "/api/price-history").permitAll()
|
||||
// Wskazniki rynkowe kalkulatora zdolnosci - dane publiczne z GUS i Eurostatu.
|
||||
.requestMatchers(HttpMethod.GET, "/api/market-indicators").permitAll()
|
||||
.requestMatchers(HttpMethod.GET, "/api/articles", "/api/articles/**").permitAll()
|
||||
.requestMatchers(HttpMethod.POST, "/api/articles").authenticated()
|
||||
.requestMatchers(HttpMethod.GET, "/api/banners").permitAll()
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
package pl.polskalokalnie.market;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Stopa rynku pienieznego dla Polski z Eurostatu (zbior irt_st_m, seria IRT_M3 - stawka 3-miesieczna,
|
||||
* czyli odpowiednik WIBOR 3M). Dane miesieczne, bez klucza dostepu.
|
||||
*
|
||||
* DLACZEGO NIE NBP: NBP publikuje srednie oprocentowanie nowych kredytow mieszkaniowych, ale pliki
|
||||
* lezą pod adresami zmieniajacymi sie co miesiac, a strony nbp.pl sa chronione przed automatycznym
|
||||
* pobieraniem (odpowiadaja strona bota zamiast trescia). Dziala tylko static.nbp.pl z plikiem cen
|
||||
* mieszkan, ktory juz pobieramy w module historii cen.
|
||||
*/
|
||||
@Component
|
||||
public class EurostatRateClient {
|
||||
|
||||
static final String URL = "https://ec.europa.eu/eurostat/api/dissemination/statistics/1.0/data/irt_st_m"
|
||||
+ "?format=JSON&geo=PL&int_rt=IRT_M3&lastTimePeriod=6";
|
||||
|
||||
/** Wartosc stopy w procentach wraz z miesiacem, ktorego dotyczy ("2026-08"). */
|
||||
public record Rate(BigDecimal percent, String period) {
|
||||
}
|
||||
|
||||
private final HttpClient http = HttpClient.newBuilder()
|
||||
.connectTimeout(Duration.ofSeconds(15))
|
||||
.followRedirects(HttpClient.Redirect.NORMAL)
|
||||
.build();
|
||||
private final ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public Rate latestThreeMonthRate() throws IOException, InterruptedException {
|
||||
HttpRequest request = HttpRequest.newBuilder(URI.create(URL))
|
||||
.timeout(Duration.ofSeconds(30))
|
||||
.header("Accept", "application/json")
|
||||
.GET()
|
||||
.build();
|
||||
HttpResponse<String> response = http.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
|
||||
if (response.statusCode() != 200) {
|
||||
throw new IOException("Eurostat odpowiedzial " + response.statusCode());
|
||||
}
|
||||
return parseLatest(mapper.readTree(response.body()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Odpowiedz w formacie JSON-stat: wartosci leza w mapie "value" pod indeksem plaskim, a wymiar
|
||||
* czasu ma wlasne indeksy. Przy jednej serii (geo=PL, int_rt=IRT_M3) indeks czasu jest zarazem
|
||||
* indeksem wartosci, ale zamiast na tym polegac dobieramy wartosc po indeksie z wymiaru "time".
|
||||
*/
|
||||
static Rate parseLatest(JsonNode root) throws IOException {
|
||||
JsonNode values = root.path("value");
|
||||
JsonNode periods = root.path("dimension").path("time").path("category").path("index");
|
||||
if (values.isMissingNode() || periods.isMissingNode() || periods.isEmpty()) {
|
||||
throw new IOException("Eurostat: odpowiedz bez danych");
|
||||
}
|
||||
|
||||
// Najpozniejszy miesiac z dostepna wartoscia - ostatnie okresy bywaja jeszcze puste.
|
||||
Map.Entry<String, JsonNode> latest = null;
|
||||
for (var it = periods.fields(); it.hasNext(); ) {
|
||||
Map.Entry<String, JsonNode> entry = it.next();
|
||||
if (values.has(String.valueOf(entry.getValue().asInt())) && (latest == null
|
||||
|| Comparator.<String>naturalOrder().compare(entry.getKey(), latest.getKey()) > 0)) {
|
||||
latest = entry;
|
||||
}
|
||||
}
|
||||
if (latest == null) {
|
||||
throw new IOException("Eurostat: brak wartosci dla ktoregokolwiek miesiaca");
|
||||
}
|
||||
BigDecimal percent = values.path(String.valueOf(latest.getValue().asInt())).decimalValue();
|
||||
if (percent.signum() <= 0) {
|
||||
throw new IOException("Eurostat: nieprawidlowa wartosc stopy " + percent);
|
||||
}
|
||||
return new Rate(percent, latest.getKey());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package pl.polskalokalnie.market;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* Pojedynczy wskaznik rynkowy pobierany z zewnatrz (przecietne wynagrodzenie, stopa rynku
|
||||
* pieniężnego). Trzymamy ostatnia znana wartosc razem z okresem, ktorego dotyczy, i momentem
|
||||
* pobrania - dzieki temu kalkulator moze pokazac zrodlo i date, a nieudany import niczego nie psuje.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "market_indicators")
|
||||
public class MarketIndicator {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "indicator_key", nullable = false, unique = true, length = 40)
|
||||
private String key;
|
||||
|
||||
@Column(nullable = false, precision = 12, scale = 4)
|
||||
private BigDecimal value;
|
||||
|
||||
/** Okres, ktorego dotyczy wartosc, w formie podanej przez zrodlo: "2025" albo "2026-08". */
|
||||
@Column(name = "as_of", nullable = false, length = 20)
|
||||
private String asOf;
|
||||
|
||||
/** Nazwa zrodla pokazywana uzytkownikowi, np. "GUS, Bank Danych Lokalnych". */
|
||||
@Column(nullable = false, length = 120)
|
||||
private String source;
|
||||
|
||||
@Column(name = "fetched_at", nullable = false)
|
||||
private Instant fetchedAt;
|
||||
|
||||
protected MarketIndicator() {
|
||||
}
|
||||
|
||||
public MarketIndicator(String key, BigDecimal value, String asOf, String source, Instant fetchedAt) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
this.asOf = asOf;
|
||||
this.source = source;
|
||||
this.fetchedAt = fetchedAt;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public BigDecimal getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(BigDecimal value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getAsOf() {
|
||||
return asOf;
|
||||
}
|
||||
|
||||
public void setAsOf(String asOf) {
|
||||
this.asOf = asOf;
|
||||
}
|
||||
|
||||
public String getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
public void setSource(String source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public Instant getFetchedAt() {
|
||||
return fetchedAt;
|
||||
}
|
||||
|
||||
public void setFetchedAt(Instant fetchedAt) {
|
||||
this.fetchedAt = fetchedAt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package pl.polskalokalnie.market;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* Wskazniki rynkowe dla kalkulatora zdolnosci - publiczne, jak sam kalkulator.
|
||||
* Odpowiedz niesie tez zrodlo i okres, zeby interfejs mogl je podpisac przy liczbach.
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/market-indicators")
|
||||
public class MarketIndicatorController {
|
||||
|
||||
public record IndicatorResponse(String key, BigDecimal value, String asOf, String source, Instant fetchedAt) {
|
||||
}
|
||||
|
||||
private final MarketIndicatorService service;
|
||||
|
||||
public MarketIndicatorController(MarketIndicatorService service) {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public List<IndicatorResponse> list() {
|
||||
return service.all().stream()
|
||||
.map(indicator -> new IndicatorResponse(indicator.getKey(), indicator.getValue(),
|
||||
indicator.getAsOf(), indicator.getSource(), indicator.getFetchedAt()))
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package pl.polskalokalnie.market;
|
||||
|
||||
import java.util.Optional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface MarketIndicatorRepository extends JpaRepository<MarketIndicator, Long> {
|
||||
|
||||
Optional<MarketIndicator> findByKey(String key);
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package pl.polskalokalnie.market;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import pl.polskalokalnie.pricehistory.GusBdlClient;
|
||||
|
||||
/**
|
||||
* Wskazniki rynkowe dla kalkulatora zdolnosci kredytowej - pobierane raz w tygodniu, tak jak ceny
|
||||
* transakcyjne w module historii cen. Nieudane pobranie zostawia poprzednia wartosc; gdy zadnej
|
||||
* jeszcze nie ma, kalkulator korzysta z wartosci zapasowych wpisanych w interfejsie.
|
||||
*/
|
||||
@Service
|
||||
public class MarketIndicatorService {
|
||||
|
||||
/** Przecietne miesieczne wynagrodzenie brutto w Polsce (GUS). */
|
||||
public static final String AVERAGE_WAGE = "average-wage-gross";
|
||||
/** Stopa rynku pienieznego 3M dla Polski - odpowiednik WIBOR 3M (Eurostat). */
|
||||
public static final String MONEY_MARKET_3M = "money-market-3m";
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(MarketIndicatorService.class);
|
||||
|
||||
private final MarketIndicatorRepository repository;
|
||||
private final GusBdlClient gusClient;
|
||||
private final EurostatRateClient eurostatClient;
|
||||
|
||||
public MarketIndicatorService(MarketIndicatorRepository repository, GusBdlClient gusClient,
|
||||
EurostatRateClient eurostatClient) {
|
||||
this.repository = repository;
|
||||
this.gusClient = gusClient;
|
||||
this.eurostatClient = eurostatClient;
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<MarketIndicator> all() {
|
||||
return repository.findAll();
|
||||
}
|
||||
|
||||
@Async
|
||||
@EventListener(ApplicationReadyEvent.class)
|
||||
public void refreshOnStartupIfStale() {
|
||||
Instant weekAgo = Instant.now().minus(7, ChronoUnit.DAYS);
|
||||
if (isStale(AVERAGE_WAGE, weekAgo)) {
|
||||
refreshAverageWage();
|
||||
}
|
||||
if (isStale(MONEY_MARKET_3M, weekAgo)) {
|
||||
refreshMoneyMarketRate();
|
||||
}
|
||||
}
|
||||
|
||||
@Scheduled(cron = "0 25 4 * * MON", zone = "Europe/Warsaw")
|
||||
public void refreshWeekly() {
|
||||
refreshAverageWage();
|
||||
refreshMoneyMarketRate();
|
||||
}
|
||||
|
||||
public boolean refreshAverageWage() {
|
||||
try {
|
||||
GusBdlClient.AnnualValue wage = gusClient.latestAverageWage();
|
||||
save(AVERAGE_WAGE, wage.value(), String.valueOf(wage.year()), "GUS, Bank Danych Lokalnych");
|
||||
log.info("Wskazniki: przecietne wynagrodzenie {} zl za {}", wage.value(), wage.year());
|
||||
return true;
|
||||
} catch (IOException | RuntimeException ex) {
|
||||
log.warn("Wskazniki: nie udalo sie pobrac wynagrodzenia z GUS ({}) - zostaje poprzednia wartosc",
|
||||
ex.getMessage());
|
||||
return false;
|
||||
} catch (InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean refreshMoneyMarketRate() {
|
||||
try {
|
||||
EurostatRateClient.Rate rate = eurostatClient.latestThreeMonthRate();
|
||||
save(MONEY_MARKET_3M, rate.percent(), rate.period(), "Eurostat, stopy rynku pieniężnego (irt_st_m)");
|
||||
log.info("Wskazniki: stopa rynku pienieznego 3M {}% za {}", rate.percent(), rate.period());
|
||||
return true;
|
||||
} catch (IOException | RuntimeException ex) {
|
||||
log.warn("Wskazniki: nie udalo sie pobrac stopy z Eurostatu ({}) - zostaje poprzednia wartosc",
|
||||
ex.getMessage());
|
||||
return false;
|
||||
} catch (InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isStale(String key, Instant threshold) {
|
||||
return repository.findByKey(key).map(indicator -> indicator.getFetchedAt().isBefore(threshold)).orElse(true);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
protected void save(String key, BigDecimal value, String asOf, String source) {
|
||||
Optional<MarketIndicator> existing = repository.findByKey(key);
|
||||
Instant now = Instant.now();
|
||||
if (existing.isPresent()) {
|
||||
MarketIndicator indicator = existing.get();
|
||||
indicator.setValue(value);
|
||||
indicator.setAsOf(asOf);
|
||||
indicator.setSource(source);
|
||||
indicator.setFetchedAt(now);
|
||||
repository.save(indicator);
|
||||
} else {
|
||||
repository.save(new MarketIndicator(key, value, asOf, source, now));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,6 +49,35 @@ public class GusBdlClient {
|
||||
return matchCityUnit(results, city);
|
||||
}
|
||||
|
||||
/** Przecietne miesieczne wynagrodzenie brutto w Polsce (temat P2497, zmienna 64428, dane roczne). */
|
||||
static final long WAGE_VARIABLE_ID = 64428;
|
||||
|
||||
public record AnnualValue(int year, java.math.BigDecimal value) {
|
||||
}
|
||||
|
||||
/** Najnowszy rok z wartoscia przecietnego wynagrodzenia brutto dla calej Polski. */
|
||||
public AnnualValue latestAverageWage() throws IOException, InterruptedException {
|
||||
JsonNode response = get("/data/by-variable/" + WAGE_VARIABLE_ID + "?format=json&unit-level=0&page-size=100");
|
||||
return parseLatestAnnualValue(response);
|
||||
}
|
||||
|
||||
static AnnualValue parseLatestAnnualValue(JsonNode response) throws IOException {
|
||||
AnnualValue latest = null;
|
||||
for (JsonNode result : response.path("results")) {
|
||||
for (JsonNode value : result.path("values")) {
|
||||
int year = value.path("year").asInt(0);
|
||||
java.math.BigDecimal amount = value.path("val").decimalValue();
|
||||
if (year > 0 && amount.signum() > 0 && (latest == null || year > latest.year())) {
|
||||
latest = new AnnualValue(year, amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (latest == null) {
|
||||
throw new IOException("GUS BDL: brak wartosci przecietnego wynagrodzenia");
|
||||
}
|
||||
return latest;
|
||||
}
|
||||
|
||||
public List<Variable> variables() throws IOException, InterruptedException {
|
||||
return parseVariables(get("/variables?subject-id=" + SUBJECT + "&format=json&page-size=100").path("results"));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package pl.polskalokalnie.market;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import java.io.IOException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Parsowanie odpowiedzi JSON-stat z Eurostatu - ksztalt jak w zbiorze irt_st_m. */
|
||||
class EurostatRateClientTest {
|
||||
|
||||
private final ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
private String response(String values, String periods) {
|
||||
return "{\"value\":" + values + ",\"dimension\":{\"time\":{\"category\":{\"index\":" + periods + "}}}}";
|
||||
}
|
||||
|
||||
@Test
|
||||
void bierzeNajpozniejszyMiesiacZWartoscia() throws Exception {
|
||||
String json = response("{\"0\":3.85,\"1\":3.82,\"2\":3.83}",
|
||||
"{\"2026-06\":0,\"2026-07\":1,\"2026-08\":2}");
|
||||
EurostatRateClient.Rate rate = EurostatRateClient.parseLatest(mapper.readTree(json));
|
||||
assertThat(rate.period()).isEqualTo("2026-08");
|
||||
assertThat(rate.percent()).isEqualByComparingTo("3.83");
|
||||
}
|
||||
|
||||
@Test
|
||||
void pomijaMiesiaceBezWartosci() throws Exception {
|
||||
// Ostatni okres bywa jeszcze pusty - wtedy bierzemy poprzedni, a nie zglaszamy bledu.
|
||||
String json = response("{\"0\":3.85,\"1\":3.82}",
|
||||
"{\"2026-06\":0,\"2026-07\":1,\"2026-08\":2}");
|
||||
EurostatRateClient.Rate rate = EurostatRateClient.parseLatest(mapper.readTree(json));
|
||||
assertThat(rate.period()).isEqualTo("2026-07");
|
||||
assertThat(rate.percent()).isEqualByComparingTo("3.82");
|
||||
}
|
||||
|
||||
@Test
|
||||
void odrzucaOdpowiedzBezDanych() throws Exception {
|
||||
assertThatThrownBy(() -> EurostatRateClient.parseLatest(mapper.readTree("{}")))
|
||||
.isInstanceOf(IOException.class);
|
||||
assertThatThrownBy(() -> EurostatRateClient.parseLatest(
|
||||
mapper.readTree(response("{}", "{\"2026-08\":0}"))))
|
||||
.isInstanceOf(IOException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void odrzucaNieprawidlowaStope() throws Exception {
|
||||
String json = response("{\"0\":0}", "{\"2026-08\":0}");
|
||||
assertThatThrownBy(() -> EurostatRateClient.parseLatest(mapper.readTree(json)))
|
||||
.isInstanceOf(IOException.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package pl.polskalokalnie.pricehistory;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import java.io.IOException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Parsowanie rocznych wartosci z BDL - przecietne wynagrodzenie brutto dla calej Polski. */
|
||||
class GusWageParsingTest {
|
||||
|
||||
private final ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
@Test
|
||||
void bierzeNajnowszyRok() throws Exception {
|
||||
String json = "{\"results\":[{\"id\":\"000000000000\",\"name\":\"POLSKA\",\"values\":["
|
||||
+ "{\"year\":\"2023\",\"val\":7595.30},{\"year\":\"2025\",\"val\":9371.11},"
|
||||
+ "{\"year\":\"2024\",\"val\":8630.27}]}]}";
|
||||
GusBdlClient.AnnualValue wage = GusBdlClient.parseLatestAnnualValue(mapper.readTree(json));
|
||||
assertThat(wage.year()).isEqualTo(2025);
|
||||
assertThat(wage.value()).isEqualByComparingTo("9371.11");
|
||||
}
|
||||
|
||||
@Test
|
||||
void pomijaLataBezWartosci() throws Exception {
|
||||
String json = "{\"results\":[{\"values\":[{\"year\":\"2024\",\"val\":8630.27},{\"year\":\"2025\",\"val\":0}]}]}";
|
||||
GusBdlClient.AnnualValue wage = GusBdlClient.parseLatestAnnualValue(mapper.readTree(json));
|
||||
assertThat(wage.year()).isEqualTo(2024);
|
||||
}
|
||||
|
||||
@Test
|
||||
void odrzucaPustaOdpowiedz() {
|
||||
assertThatThrownBy(() -> GusBdlClient.parseLatestAnnualValue(mapper.readTree("{\"results\":[]}")))
|
||||
.isInstanceOf(IOException.class);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user