From e92c68ec93a259ba719e39cc45245bdb05dd0968 Mon Sep 17 00:00:00 2001 From: Przemek Zatorski Date: Tue, 22 Sep 2026 13:56:26 +0200 Subject: [PATCH] Historia cen na prawdziwych danych: ogloszenia, NBP i GUS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Strona /historia-cen pokazywala pusty wykres (wczesniej zmyslony). Teraz: Ceny ofertowe z ogloszen: - Tabela price_snapshots: codzienny zapis srednich cen za m2 z opublikowanych ogloszen per miasto i dzielnica, typ (mieszkanie/dom) i rynek. Zapis co noc (02:30) i przy starcie, gdy brakuje dzisiejszego. Historii sprzed pierwszego zapisu nie odtwarzamy. Ceny transakcyjne ze zrodel publicznych (porownanie, cale miasto, mieszkania): - NBP: plik ceny_mieszkan.xlsx (baza BaRN) - 17 miast, rynek pierwotny i wtorny, od III kw. 2006. Odczyt XLSX bez nowych zaleznosci. - GUS: API Banku Danych Lokalnych (temat P3794) - miasta na prawach powiatu, kwartalnie od 2010, z opoznieniem ok. roku. - Import raz w tygodniu i przy starcie, gdy dane sa starsze niz tydzien; blad zrodla nie kasuje poprzednich danych. - GET /api/price-history (publiczny): historia, biezaca srednia z ogloszen, od kiedy zbieramy dane oraz serie NBP i GUS. Frontend: - Okresy "Ostatnie 5 lat" (domyslny), "Od 2006 (NBP)", "2026 do dzis"; trzy serie z legenda, dymek ze wszystkimi zrodlami, statystyki i wnioski z prawdziwych liczb, porownanie cen ofertowych z NBP i GUS oraz roznica i srednia, gdy zrodla sie roznia. Ceny w "Porownaj lokalizacje". - Poprawione dopasowanie lokalizacji ("Warszawa" otwierala "Warszawa, Mokotów"), usuniete resztki zmyslonych cen i opcja "Lokal uzytkowy". Co-Authored-By: Claude Opus 5 (1M context) --- .../polskalokalnie/auth/SecurityConfig.java | 2 + .../ExternalPriceImportService.java | 166 +++++ .../pricehistory/ExternalQuarterPrice.java | 97 +++ .../ExternalQuarterPriceRepository.java | 26 + .../pricehistory/GusBdlClient.java | 134 ++++ .../pricehistory/NbpXlsxParser.java | 256 +++++++ .../pricehistory/PriceHistoryController.java | 81 +++ .../pricehistory/PriceSnapshot.java | 94 +++ .../pricehistory/PriceSnapshotRepository.java | 26 + .../pricehistory/PriceSnapshotService.java | 160 +++++ .../pricehistory/GusBdlClientTest.java | 49 ++ .../pricehistory/NbpXlsxParserTest.java | 41 ++ .../PriceSnapshotServiceTest.java | 94 +++ .../src/test/resources/nbp/ceny_mieszkan.xlsx | Bin 0 -> 193059 bytes frontend/src/App.tsx | 647 ++++++++++++------ frontend/src/styles.css | 61 ++ 16 files changed, 1722 insertions(+), 212 deletions(-) create mode 100644 backend/src/main/java/pl/polskalokalnie/pricehistory/ExternalPriceImportService.java create mode 100644 backend/src/main/java/pl/polskalokalnie/pricehistory/ExternalQuarterPrice.java create mode 100644 backend/src/main/java/pl/polskalokalnie/pricehistory/ExternalQuarterPriceRepository.java create mode 100644 backend/src/main/java/pl/polskalokalnie/pricehistory/GusBdlClient.java create mode 100644 backend/src/main/java/pl/polskalokalnie/pricehistory/NbpXlsxParser.java create mode 100644 backend/src/main/java/pl/polskalokalnie/pricehistory/PriceHistoryController.java create mode 100644 backend/src/main/java/pl/polskalokalnie/pricehistory/PriceSnapshot.java create mode 100644 backend/src/main/java/pl/polskalokalnie/pricehistory/PriceSnapshotRepository.java create mode 100644 backend/src/main/java/pl/polskalokalnie/pricehistory/PriceSnapshotService.java create mode 100644 backend/src/test/java/pl/polskalokalnie/pricehistory/GusBdlClientTest.java create mode 100644 backend/src/test/java/pl/polskalokalnie/pricehistory/NbpXlsxParserTest.java create mode 100644 backend/src/test/java/pl/polskalokalnie/pricehistory/PriceSnapshotServiceTest.java create mode 100644 backend/src/test/resources/nbp/ceny_mieszkan.xlsx diff --git a/backend/src/main/java/pl/polskalokalnie/auth/SecurityConfig.java b/backend/src/main/java/pl/polskalokalnie/auth/SecurityConfig.java index cb23376..0cb382e 100644 --- a/backend/src/main/java/pl/polskalokalnie/auth/SecurityConfig.java +++ b/backend/src/main/java/pl/polskalokalnie/auth/SecurityConfig.java @@ -49,6 +49,8 @@ public class SecurityConfig { .requestMatchers(HttpMethod.GET, "/api/listings", "/api/listings/**").permitAll() // Podglad ogloszenia dla crawlerow social media (Open Graph) - publiczny, tylko GET. .requestMatchers(HttpMethod.GET, "/api/og/**").permitAll() + // Historia srednich cen z ogloszen - publiczna, jak same ogloszenia. + .requestMatchers(HttpMethod.GET, "/api/price-history").permitAll() .requestMatchers(HttpMethod.GET, "/api/articles", "/api/articles/**").permitAll() .requestMatchers(HttpMethod.POST, "/api/articles").authenticated() .requestMatchers(HttpMethod.GET, "/api/banners").permitAll() diff --git a/backend/src/main/java/pl/polskalokalnie/pricehistory/ExternalPriceImportService.java b/backend/src/main/java/pl/polskalokalnie/pricehistory/ExternalPriceImportService.java new file mode 100644 index 0000000..1c9e648 --- /dev/null +++ b/backend/src/main/java/pl/polskalokalnie/pricehistory/ExternalPriceImportService.java @@ -0,0 +1,166 @@ +package pl.polskalokalnie.pricehistory; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +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.support.TransactionTemplate; +import pl.polskalokalnie.listing.ListingRepository; +import pl.polskalokalnie.listing.ListingStatus; +import pl.polskalokalnie.listing.PropertyListing; +import pl.polskalokalnie.pricehistory.ExternalQuarterPrice.Source; + +/** + * Import cen transakcyjnych z NBP (plik XLSX) i GUS (API BDL) - zrodla porownawcze dla historii cen. + * Raz w tygodniu oraz przy starcie, gdy dane sa starsze niz tydzien. Blad zrodla nie rusza starych danych. + */ +@Service +public class ExternalPriceImportService { + + static final String NBP_URL = "https://static.nbp.pl/dane/rynek-nieruchomosci/ceny_mieszkan.xlsx"; + private static final long MAX_DOWNLOAD_BYTES = 20L * 1024 * 1024; + private static final int GUS_FROM_YEAR = 2010; + private static final Logger log = LoggerFactory.getLogger(ExternalPriceImportService.class); + + private final ExternalQuarterPriceRepository repository; + private final ListingRepository listingRepository; + private final GusBdlClient gusClient; + private final TransactionTemplate transaction; + private final HttpClient http = HttpClient.newBuilder() + .connectTimeout(Duration.ofSeconds(15)) + .followRedirects(HttpClient.Redirect.NORMAL) + .build(); + + public ExternalPriceImportService(ExternalQuarterPriceRepository repository, ListingRepository listingRepository, + GusBdlClient gusClient, TransactionTemplate transaction) { + this.repository = repository; + this.listingRepository = listingRepository; + this.gusClient = gusClient; + this.transaction = transaction; + } + + @Async + @EventListener(ApplicationReadyEvent.class) + public void importOnStartupIfStale() { + Instant weekAgo = Instant.now().minus(7, ChronoUnit.DAYS); + if (repository.findLastImport(Source.NBP).map(last -> last.isBefore(weekAgo)).orElse(true)) { + importNbp(); + } + if (repository.findLastImport(Source.GUS).map(last -> last.isBefore(weekAgo)).orElse(true)) { + importGus(); + } + } + + @Scheduled(cron = "0 10 4 * * MON", zone = "Europe/Warsaw") + public void importWeekly() { + importNbp(); + importGus(); + } + + public int importNbp() { + try { + List rows; + try (InputStream xlsx = download(NBP_URL)) { + rows = NbpXlsxParser.parse(xlsx); + } + if (rows.isEmpty()) { + log.warn("NBP: w pliku nie znaleziono cen transakcyjnych - zostawiam poprzednie dane"); + return 0; + } + Instant now = Instant.now(); + transaction.executeWithoutResult(status -> { + repository.deleteBySource(Source.NBP); + repository.saveAll(rows.stream() + .map(row -> new ExternalQuarterPrice(Source.NBP, row.year(), row.quarter(), row.market(), + row.city(), row.pricePerM2(), now)) + .toList()); + }); + log.info("NBP: zaimportowano {} cen kwartalnych", rows.size()); + return rows.size(); + } catch (IOException | RuntimeException ex) { + log.warn("NBP: import nieudany ({}) - zostawiam poprzednie dane", ex.getMessage()); + return 0; + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + return 0; + } + } + + /** GUS dla miast z ogloszen i miast z danych NBP - tylko miasta na prawach powiatu maja wlasne dane. */ + public int importGus() { + int imported = 0; + try { + List variables = gusClient.variables(); + int toYear = PriceSnapshotService.today().getYear(); + for (String city : citiesToTrack()) { + try { + String unitId = gusClient.cityUnitId(city); + if (unitId != null) { + List values = gusClient.quarterlyPrices(unitId, variables, GUS_FROM_YEAR, toYear); + if (!values.isEmpty()) { + Instant now = Instant.now(); + transaction.executeWithoutResult(status -> { + repository.deleteBySourceAndCityKey(Source.GUS, PriceSnapshotService.key(city)); + repository.saveAll(values.stream() + .map(value -> new ExternalQuarterPrice(Source.GUS, value.year(), value.quarter(), + value.market(), city, value.pricePerM2(), now)) + .toList()); + }); + imported += values.size(); + } + } + // Publiczne API bez klucza ma limity zapytan - nie spieszymy sie. + Thread.sleep(700); + } catch (IOException | RuntimeException ex) { + log.warn("GUS: nie udalo sie pobrac danych dla {} ({})", city, ex.getMessage()); + } + } + log.info("GUS: zaimportowano {} cen kwartalnych", imported); + } catch (IOException | RuntimeException ex) { + log.warn("GUS: import nieudany ({}) - zostawiam poprzednie dane", ex.getMessage()); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + return imported; + } + + private List citiesToTrack() { + Map cities = new LinkedHashMap<>(); + repository.findAll().stream() + .filter(price -> price.getSource() == Source.NBP) + .forEach(price -> cities.putIfAbsent(price.getCityKey(), price.getCity())); + listingRepository.findAll().stream() + .filter(listing -> listing.getStatus() == ListingStatus.APPROVED) + .map(PropertyListing::getCity) + .filter(city -> city != null && !city.isBlank()) + .forEach(city -> cities.putIfAbsent(PriceSnapshotService.key(city), city.trim())); + return List.copyOf(cities.values()); + } + + private InputStream download(String url) throws IOException, InterruptedException { + HttpRequest request = HttpRequest.newBuilder(URI.create(url)).timeout(Duration.ofSeconds(60)).GET().build(); + HttpResponse response = http.send(request, HttpResponse.BodyHandlers.ofByteArray()); + if (response.statusCode() != 200) { + throw new IOException("serwer odpowiedzial " + response.statusCode()); + } + if (response.body().length > MAX_DOWNLOAD_BYTES) { + throw new IOException("plik jest za duzy"); + } + return new java.io.ByteArrayInputStream(response.body()); + } +} diff --git a/backend/src/main/java/pl/polskalokalnie/pricehistory/ExternalQuarterPrice.java b/backend/src/main/java/pl/polskalokalnie/pricehistory/ExternalQuarterPrice.java new file mode 100644 index 0000000..282d11d --- /dev/null +++ b/backend/src/main/java/pl/polskalokalnie/pricehistory/ExternalQuarterPrice.java @@ -0,0 +1,97 @@ +package pl.polskalokalnie.pricehistory; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; +import java.time.Instant; + +/** + * Kwartalna srednia cena transakcyjna za m2 mieszkan z zewnetrznego zrodla: + * NBP (baza BaRN, 16 miast wojewodzkich i Gdynia) albo GUS (Bank Danych Lokalnych, miasta na prawach powiatu). + * Rynek: "Pierwotny", "Wtórny" albo "" (oba razem - tylko GUS). + */ +@Entity +@Table(name = "external_quarter_prices", + uniqueConstraints = @UniqueConstraint(columnNames = {"source", "year", "quarter", "market", "cityKey"})) +public class ExternalQuarterPrice { + + public enum Source { NBP, GUS } + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Enumerated(EnumType.STRING) + @Column(nullable = false, length = 8) + private Source source; + + @Column(nullable = false) + private int year; + + @Column(nullable = false) + private int quarter; + + @Column(nullable = false, length = 32) + private String market; + + @Column(nullable = false, length = 120) + private String cityKey; + + @Column(nullable = false, length = 120) + private String city; + + @Column(nullable = false) + private long pricePerM2; + + @Column(nullable = false) + private Instant importedAt; + + protected ExternalQuarterPrice() { + } + + public ExternalQuarterPrice(Source source, int year, int quarter, String market, String city, long pricePerM2, + Instant importedAt) { + this.source = source; + this.year = year; + this.quarter = quarter; + this.market = market; + this.city = city; + this.cityKey = PriceSnapshotService.key(city); + this.pricePerM2 = pricePerM2; + this.importedAt = importedAt; + } + + public Source getSource() { + return source; + } + + public int getYear() { + return year; + } + + public int getQuarter() { + return quarter; + } + + public String getMarket() { + return market; + } + + public String getCity() { + return city; + } + + public String getCityKey() { + return cityKey; + } + + public long getPricePerM2() { + return pricePerM2; + } +} diff --git a/backend/src/main/java/pl/polskalokalnie/pricehistory/ExternalQuarterPriceRepository.java b/backend/src/main/java/pl/polskalokalnie/pricehistory/ExternalQuarterPriceRepository.java new file mode 100644 index 0000000..db214df --- /dev/null +++ b/backend/src/main/java/pl/polskalokalnie/pricehistory/ExternalQuarterPriceRepository.java @@ -0,0 +1,26 @@ +package pl.polskalokalnie.pricehistory; + +import java.time.Instant; +import java.util.List; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import pl.polskalokalnie.pricehistory.ExternalQuarterPrice.Source; + +public interface ExternalQuarterPriceRepository extends JpaRepository { + + List findByCityKeyAndMarketOrderByYearAscQuarterAsc(String cityKey, String market); + + @Query("select max(p.importedAt) from ExternalQuarterPrice p where p.source = :source") + Optional findLastImport(@Param("source") Source source); + + @Modifying + @Query("delete from ExternalQuarterPrice p where p.source = :source") + void deleteBySource(@Param("source") Source source); + + @Modifying + @Query("delete from ExternalQuarterPrice p where p.source = :source and p.cityKey = :cityKey") + void deleteBySourceAndCityKey(@Param("source") Source source, @Param("cityKey") String cityKey); +} diff --git a/backend/src/main/java/pl/polskalokalnie/pricehistory/GusBdlClient.java b/backend/src/main/java/pl/polskalokalnie/pricehistory/GusBdlClient.java new file mode 100644 index 0000000..f769260 --- /dev/null +++ b/backend/src/main/java/pl/polskalokalnie/pricehistory/GusBdlClient.java @@ -0,0 +1,134 @@ +package pl.polskalokalnie.pricehistory; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.net.URI; +import java.net.URLEncoder; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.text.Normalizer; +import java.time.Duration; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.springframework.stereotype.Component; + +/** + * Publiczne API GUS - Bank Danych Lokalnych (bdl.stat.gov.pl, bez klucza). + * Temat P3794: srednia cena za 1 m2 lokali mieszkalnych sprzedanych w ramach transakcji rynkowych + * (dane kwartalne), poziom powiatu - miasta na prawach powiatu maja wlasne dane. + */ +@Component +public class GusBdlClient { + + static final String SUBJECT = "P3794"; + private static final String API = "https://bdl.stat.gov.pl/api/v1"; + private static final Pattern QUARTER = Pattern.compile("^(\\d)\\s*kwarta"); + + /** Zmienna BDL: kwartal i rynek ("" = oba rynki razem). */ + public record Variable(long id, int quarter, String market) { + } + + public record QuarterValue(int year, int quarter, String market, long pricePerM2) { + } + + private final HttpClient http = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(15)).build(); + private final ObjectMapper mapper = new ObjectMapper(); + + /** Id jednostki "Powiat m. " / "Powiat m.st. " albo null, gdy miasto nie jest na prawach powiatu. */ + public String cityUnitId(String city) throws IOException, InterruptedException { + JsonNode results = get("/units/search?level=5&format=json&page-size=20&name=" + + URLEncoder.encode(city, StandardCharsets.UTF_8)).path("results"); + return matchCityUnit(results, city); + } + + public List variables() throws IOException, InterruptedException { + return parseVariables(get("/variables?subject-id=" + SUBJECT + "&format=json&page-size=100").path("results")); + } + + public List quarterlyPrices(String unitId, List variables, int fromYear, int toYear) + throws IOException, InterruptedException { + StringBuilder query = new StringBuilder("/data/by-unit/").append(unitId).append("?format=json"); + variables.forEach(variable -> query.append("&var-id=").append(variable.id())); + for (int year = fromYear; year <= toYear; year++) { + query.append("&year=").append(year); + } + return parseUnitData(get(query.toString()), variables); + } + + static String matchCityUnit(JsonNode results, String city) { + String wanted = normalize(city); + for (JsonNode unit : results) { + String name = normalize(unit.path("name").asText()); + // "Powiat m. Kraków", "Powiat m. st. Warszawa" - bez powiatow ziemskich wokol miasta. + if (name.equals("powiat m. " + wanted) || name.equals("powiat m. st. " + wanted) + || name.equals("powiat m.st. " + wanted)) { + return unit.path("id").asText(); + } + } + return null; + } + + // Tylko "ogolem" wg powierzchni lokalu - dla kazdego kwartalu i rynku jedna wartosc. + static List parseVariables(JsonNode results) { + List variables = new ArrayList<>(); + for (JsonNode variable : results) { + Matcher quarter = QUARTER.matcher(variable.path("n1").asText()); + String market = switch (normalize(variable.path("n2").asText())) { + case "ogółem" -> ""; + case "rynek pierwotny" -> "Pierwotny"; + case "rynek wtórny" -> "Wtórny"; + default -> null; + }; + if (quarter.find() && market != null && "ogółem".equals(normalize(variable.path("n3").asText()))) { + variables.add(new Variable(variable.path("id").asLong(), Integer.parseInt(quarter.group(1)), market)); + } + } + return variables; + } + + static List parseUnitData(JsonNode response, List variables) { + Map byId = new LinkedHashMap<>(); + variables.forEach(variable -> byId.put(variable.id(), variable)); + List values = new ArrayList<>(); + for (JsonNode result : response.path("results")) { + Variable variable = byId.get(result.path("id").asLong()); + if (variable == null) { + continue; + } + for (JsonNode value : result.path("values")) { + double price = value.path("val").asDouble(0); + int year = value.path("year").asInt(0); + if (price > 0 && year > 0) { + values.add(new QuarterValue(year, variable.quarter(), variable.market(), Math.round(price))); + } + } + } + return values; + } + + private JsonNode get(String path) throws IOException, InterruptedException { + HttpRequest request = HttpRequest.newBuilder(URI.create(API + path)) + .timeout(Duration.ofSeconds(30)) + .header("Accept", "application/json") + .GET() + .build(); + HttpResponse response = http.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + if (response.statusCode() != 200) { + throw new IOException("GUS BDL odpowiedzial " + response.statusCode() + " dla " + path); + } + return mapper.readTree(response.body()); + } + + private static String normalize(String value) { + return Normalizer.normalize(value == null ? "" : value.trim(), Normalizer.Form.NFC) + .toLowerCase(Locale.ROOT).replaceAll("\\s+", " "); + } +} diff --git a/backend/src/main/java/pl/polskalokalnie/pricehistory/NbpXlsxParser.java b/backend/src/main/java/pl/polskalokalnie/pricehistory/NbpXlsxParser.java new file mode 100644 index 0000000..02acff9 --- /dev/null +++ b/backend/src/main/java/pl/polskalokalnie/pricehistory/NbpXlsxParser.java @@ -0,0 +1,256 @@ +package pl.polskalokalnie.pricehistory; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +/** + * Odczyt cen transakcyjnych z pliku NBP ceny_mieszkan.xlsx bez zewnetrznych bibliotek (XLSX to ZIP z XML). + * Z arkuszy "Rynek pierwotny" i "Rynek wtórny" bierze blok "Ceny transakcyjne": kolumne kwartalu + * ("II 2026") i kolumny miast; pomija srednie zbiorcze ("7 miast") oraz indeksy cen. + */ +public final class NbpXlsxParser { + + public record Row(int year, int quarter, String market, String city, long pricePerM2) { + } + + private static final long MAX_ENTRY_BYTES = 20L * 1024 * 1024; + private static final Pattern QUARTER = Pattern.compile("^(IV|III|II|I)\\s+(\\d{4})$"); + private static final Pattern CELL_REF = Pattern.compile("^([A-Z]+)\\d+$"); + private static final Map SHEET_MARKETS = Map.of( + "Rynek pierwotny", "Pierwotny", + "Rynek wtórny", "Wtórny"); + + private NbpXlsxParser() { + } + + public static List parse(InputStream xlsx) throws IOException { + Map entries = unzip(xlsx); + try { + List sharedStrings = sharedStrings(entries.get("xl/sharedStrings.xml")); + Map sheetFiles = sheetFiles(entries); + List rows = new ArrayList<>(); + for (Map.Entry sheet : SHEET_MARKETS.entrySet()) { + String file = sheetFiles.get(sheet.getKey()); + if (file != null && entries.containsKey(file)) { + rows.addAll(transactionPrices(read(entries.get(file)), sharedStrings, sheet.getValue())); + } + } + return rows; + } catch (IOException ex) { + throw ex; + } catch (Exception ex) { + throw new IOException("Nie udało się odczytać pliku NBP: " + ex.getMessage(), ex); + } + } + + private static List transactionPrices(Document sheet, List shared, String market) { + List> table = new ArrayList<>(); + NodeList rowNodes = sheet.getElementsByTagName("row"); + for (int i = 0; i < rowNodes.getLength(); i++) { + Map cells = new LinkedHashMap<>(); + NodeList cellNodes = ((Element) rowNodes.item(i)).getElementsByTagName("c"); + for (int j = 0; j < cellNodes.getLength(); j++) { + Element cell = (Element) cellNodes.item(j); + Matcher ref = CELL_REF.matcher(cell.getAttribute("r")); + String value = cellValue(cell, shared); + if (ref.matches() && value != null && !value.isBlank()) { + cells.put(ref.group(1), value.trim()); + } + } + table.add(cells); + } + + String transactionColumn = findColumn(table, "Ceny transakcyjne"); + Map header = table.stream() + .filter(row -> row.values().stream().filter("Kwartał"::equals).count() >= 2) + .findFirst() + .orElse(null); + if (transactionColumn == null || header == null) { + return List.of(); + } + // Kolumna kwartalu bloku transakcyjnego: ostatnia "Kwartał" nie dalej niz naglowek bloku. + String quarterColumn = null; + for (Map.Entry cell : header.entrySet()) { + if ("Kwartał".equals(cell.getValue()) && columnIndex(cell.getKey()) <= columnIndex(transactionColumn)) { + quarterColumn = cell.getKey(); + } + } + if (quarterColumn == null) { + return List.of(); + } + Map cityColumns = new LinkedHashMap<>(); + for (int index = columnIndex(quarterColumn) + 1; ; index++) { + String name = header.get(columnName(index)); + if (name == null || name.toLowerCase().contains("miast")) { + break; + } + cityColumns.put(columnName(index), name.replace("*", "").trim()); + } + + List result = new ArrayList<>(); + for (Map row : table) { + Matcher quarter = QUARTER.matcher(row.getOrDefault(quarterColumn, "")); + if (!quarter.matches()) { + continue; + } + int quarterNumber = switch (quarter.group(1)) { + case "I" -> 1; + case "II" -> 2; + case "III" -> 3; + default -> 4; + }; + int year = Integer.parseInt(quarter.group(2)); + cityColumns.forEach((column, city) -> { + Double price = number(row.get(column)); + if (price != null && price > 0) { + result.add(new Row(year, quarterNumber, market, city, Math.round(price))); + } + }); + } + return result; + } + + private static String findColumn(List> table, String text) { + for (Map row : table) { + for (Map.Entry cell : row.entrySet()) { + if (text.equals(cell.getValue())) { + return cell.getKey(); + } + } + } + return null; + } + + private static String cellValue(Element cell, List shared) { + String type = cell.getAttribute("t"); + if ("inlineStr".equals(type)) { + return textOf(cell); + } + NodeList values = cell.getElementsByTagName("v"); + if (values.getLength() == 0) { + return null; + } + String raw = values.item(0).getTextContent(); + if ("s".equals(type)) { + int index = Integer.parseInt(raw.trim()); + return index < shared.size() ? shared.get(index) : null; + } + return raw; + } + + private static List sharedStrings(byte[] xml) throws Exception { + List strings = new ArrayList<>(); + if (xml == null) { + return strings; + } + NodeList items = read(xml).getElementsByTagName("si"); + for (int i = 0; i < items.getLength(); i++) { + strings.add(textOf((Element) items.item(i))); + } + return strings; + } + + private static String textOf(Element element) { + StringBuilder text = new StringBuilder(); + NodeList parts = element.getElementsByTagName("t"); + for (int i = 0; i < parts.getLength(); i++) { + text.append(parts.item(i).getTextContent()); + } + return text.toString(); + } + + // Nazwa arkusza -> sciezka pliku w ZIP (workbook.xml + relacje). + private static Map sheetFiles(Map entries) throws Exception { + Map targets = new HashMap<>(); + NodeList relations = read(entries.get("xl/_rels/workbook.xml.rels")).getElementsByTagName("Relationship"); + for (int i = 0; i < relations.getLength(); i++) { + Element relation = (Element) relations.item(i); + String target = relation.getAttribute("Target"); + targets.put(relation.getAttribute("Id"), target.startsWith("/") ? target.substring(1) : "xl/" + target); + } + Map files = new HashMap<>(); + NodeList sheets = read(entries.get("xl/workbook.xml")).getElementsByTagName("sheet"); + for (int i = 0; i < sheets.getLength(); i++) { + Element sheet = (Element) sheets.item(i); + files.put(sheet.getAttribute("name").trim(), targets.get(sheet.getAttribute("r:id"))); + } + return files; + } + + private static Map unzip(InputStream input) throws IOException { + Map entries = new HashMap<>(); + try (ZipInputStream zip = new ZipInputStream(input)) { + ZipEntry entry; + while ((entry = zip.getNextEntry()) != null) { + if (entry.isDirectory()) { + continue; + } + byte[] data = zip.readNBytes((int) MAX_ENTRY_BYTES + 1); + if (data.length > MAX_ENTRY_BYTES) { + throw new IOException("Plik NBP ma nieoczekiwanie duzy element: " + entry.getName()); + } + entries.put(entry.getName(), data); + } + } + if (!entries.containsKey("xl/workbook.xml")) { + throw new IOException("To nie jest plik XLSX"); + } + return entries; + } + + private static Document read(byte[] xml) throws Exception { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + // Plik z zewnatrz - bez encji zewnetrznych i DTD (ochrona przed XXE). + factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); + factory.setExpandEntityReferences(false); + DocumentBuilder builder = factory.newDocumentBuilder(); + return builder.parse(new ByteArrayInputStream(xml)); + } + + private static Double number(String value) { + if (value == null) { + return null; + } + try { + return Double.parseDouble(value.replace(',', '.')); + } catch (NumberFormatException ex) { + return null; + } + } + + private static int columnIndex(String column) { + int index = 0; + for (char letter : column.toCharArray()) { + index = index * 26 + (letter - 'A' + 1); + } + return index; + } + + private static String columnName(int index) { + StringBuilder name = new StringBuilder(); + while (index > 0) { + int remainder = (index - 1) % 26; + name.insert(0, (char) ('A' + remainder)); + index = (index - 1) / 26; + } + return name.toString(); + } +} diff --git a/backend/src/main/java/pl/polskalokalnie/pricehistory/PriceHistoryController.java b/backend/src/main/java/pl/polskalokalnie/pricehistory/PriceHistoryController.java new file mode 100644 index 0000000..cc24fa0 --- /dev/null +++ b/backend/src/main/java/pl/polskalokalnie/pricehistory/PriceHistoryController.java @@ -0,0 +1,81 @@ +package pl.polskalokalnie.pricehistory; + +import java.time.LocalDate; +import java.util.List; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import pl.polskalokalnie.listing.OfferType; +import pl.polskalokalnie.listing.PropertyType; + +/** Publiczna historia srednich cen ofertowych za m2 dla miasta lub dzielnicy. */ +@RestController +@RequestMapping("/api/price-history") +public class PriceHistoryController { + + private final PriceSnapshotRepository snapshotRepository; + private final PriceSnapshotService snapshotService; + private final ExternalQuarterPriceRepository externalRepository; + + public PriceHistoryController(PriceSnapshotRepository snapshotRepository, PriceSnapshotService snapshotService, + ExternalQuarterPriceRepository externalRepository) { + this.snapshotRepository = snapshotRepository; + this.snapshotService = snapshotService; + this.externalRepository = externalRepository; + } + + public record PricePoint(LocalDate date, long avgPricePerM2, int listingsCount) { + } + + public record QuarterPoint(int year, int quarter, long pricePerM2) { + } + + /** + * points - dzienne zapisy od "from"; current - srednia z ogloszen w tej chwili (null, gdy brak); + * trackedSince - od kiedy serwis w ogole zbiera historie (null, gdy jeszcze nic nie zapisano); + * nbp / gus - kwartalne ceny transakcyjne mieszkan dla calego miasta (puste, gdy zrodlo go nie obejmuje); + * nbpMarket - rynek, ktorego dotyczy nbp (NBP nie podaje obu rynkow razem - wtedy wtorny). + */ + public record PriceHistoryResponse(List points, PricePoint current, LocalDate trackedSince, + List nbp, List gus, String nbpMarket) { + } + + @GetMapping + public PriceHistoryResponse history( + @RequestParam String city, + @RequestParam(required = false, defaultValue = "") String district, + @RequestParam(required = false, defaultValue = "SALE") OfferType offerType, + @RequestParam(required = false, defaultValue = "APARTMENT") PropertyType propertyType, + @RequestParam(required = false, defaultValue = "") String market, + @RequestParam(required = false) LocalDate from + ) { + LocalDate since = from != null ? from : PriceSnapshotService.today().minusYears(1); + String wantedMarket = market.trim(); + List points = snapshotRepository + .findByCityKeyAndDistrictKeyAndOfferTypeAndPropertyTypeAndMarketAndSnapshotDateGreaterThanEqualOrderBySnapshotDateAsc( + PriceSnapshotService.key(city), PriceSnapshotService.key(district), offerType, propertyType, + wantedMarket, since) + .stream() + .map(snapshot -> new PricePoint(snapshot.getSnapshotDate(), snapshot.getAvgPricePerM2(), snapshot.getListingsCount())) + .toList(); + PriceSnapshotService.Average now = snapshotService.currentAverage(offerType, propertyType, wantedMarket, city, district); + PricePoint current = now == null ? null + : new PricePoint(PriceSnapshotService.today(), now.avgPricePerM2(), now.listingsCount()); + // NBP i GUS podaja ceny transakcyjne mieszkan - dla domow i najmu nie ma porownania. + boolean comparable = offerType == OfferType.SALE && propertyType == PropertyType.APARTMENT; + String nbpMarket = wantedMarket.isEmpty() ? "Wtórny" : wantedMarket; + String cityKey = PriceSnapshotService.key(city); + List nbp = comparable ? quarters(cityKey, nbpMarket, ExternalQuarterPrice.Source.NBP) : List.of(); + List gus = comparable ? quarters(cityKey, wantedMarket, ExternalQuarterPrice.Source.GUS) : List.of(); + return new PriceHistoryResponse(points, current, snapshotRepository.findFirstSnapshotDate().orElse(null), + nbp, gus, nbpMarket); + } + + private List quarters(String cityKey, String market, ExternalQuarterPrice.Source source) { + return externalRepository.findByCityKeyAndMarketOrderByYearAscQuarterAsc(cityKey, market).stream() + .filter(price -> price.getSource() == source) + .map(price -> new QuarterPoint(price.getYear(), price.getQuarter(), price.getPricePerM2())) + .toList(); + } +} diff --git a/backend/src/main/java/pl/polskalokalnie/pricehistory/PriceSnapshot.java b/backend/src/main/java/pl/polskalokalnie/pricehistory/PriceSnapshot.java new file mode 100644 index 0000000..8d00730 --- /dev/null +++ b/backend/src/main/java/pl/polskalokalnie/pricehistory/PriceSnapshot.java @@ -0,0 +1,94 @@ +package pl.polskalokalnie.pricehistory; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Index; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; +import java.time.LocalDate; +import pl.polskalokalnie.listing.OfferType; +import pl.polskalokalnie.listing.PropertyType; + +/** + * Dzienny zapis sredniej ceny ofertowej za m2 z opublikowanych ogloszen - zrodlo historii cen. + * Jeden wiersz na (dzien, typ oferty, typ nieruchomosci, rynek, miasto, dzielnica). + * Pusta dzielnica = cale miasto, pusty rynek = wtorny i pierwotny razem. + * Klucze (cityKey, districtKey) sa znormalizowane, zeby "Kraków" i " kraków" trafialy w to samo. + */ +@Entity +@Table(name = "price_snapshots", + uniqueConstraints = @UniqueConstraint(columnNames = { + "snapshotDate", "offerType", "propertyType", "market", "cityKey", "districtKey"}), + indexes = @Index(columnList = "cityKey, districtKey, offerType, propertyType, market, snapshotDate")) +public class PriceSnapshot { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false) + private LocalDate snapshotDate; + + @Enumerated(EnumType.STRING) + @Column(nullable = false, length = 16) + private OfferType offerType; + + @Enumerated(EnumType.STRING) + @Column(nullable = false, length = 16) + private PropertyType propertyType; + + @Column(nullable = false, length = 32) + private String market; + + @Column(nullable = false, length = 120) + private String cityKey; + + @Column(nullable = false, length = 120) + private String districtKey; + + @Column(nullable = false, length = 120) + private String city; + + @Column(nullable = false, length = 120) + private String district; + + @Column(nullable = false) + private int listingsCount; + + @Column(nullable = false) + private long avgPricePerM2; + + protected PriceSnapshot() { + } + + public PriceSnapshot(LocalDate snapshotDate, OfferType offerType, PropertyType propertyType, String market, + String city, String district, int listingsCount, long avgPricePerM2) { + this.snapshotDate = snapshotDate; + this.offerType = offerType; + this.propertyType = propertyType; + this.market = market; + this.city = city; + this.district = district; + this.cityKey = PriceSnapshotService.key(city); + this.districtKey = PriceSnapshotService.key(district); + this.listingsCount = listingsCount; + this.avgPricePerM2 = avgPricePerM2; + } + + public LocalDate getSnapshotDate() { + return snapshotDate; + } + + public int getListingsCount() { + return listingsCount; + } + + public long getAvgPricePerM2() { + return avgPricePerM2; + } +} diff --git a/backend/src/main/java/pl/polskalokalnie/pricehistory/PriceSnapshotRepository.java b/backend/src/main/java/pl/polskalokalnie/pricehistory/PriceSnapshotRepository.java new file mode 100644 index 0000000..2def3d7 --- /dev/null +++ b/backend/src/main/java/pl/polskalokalnie/pricehistory/PriceSnapshotRepository.java @@ -0,0 +1,26 @@ +package pl.polskalokalnie.pricehistory; + +import java.time.LocalDate; +import java.util.List; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import pl.polskalokalnie.listing.OfferType; +import pl.polskalokalnie.listing.PropertyType; + +public interface PriceSnapshotRepository extends JpaRepository { + + boolean existsBySnapshotDate(LocalDate snapshotDate); + + @Modifying + @Query("delete from PriceSnapshot s where s.snapshotDate = :date") + void deleteBySnapshotDate(@Param("date") LocalDate date); + + List findByCityKeyAndDistrictKeyAndOfferTypeAndPropertyTypeAndMarketAndSnapshotDateGreaterThanEqualOrderBySnapshotDateAsc( + String cityKey, String districtKey, OfferType offerType, PropertyType propertyType, String market, LocalDate from); + + @Query("select min(s.snapshotDate) from PriceSnapshot s") + Optional findFirstSnapshotDate(); +} diff --git a/backend/src/main/java/pl/polskalokalnie/pricehistory/PriceSnapshotService.java b/backend/src/main/java/pl/polskalokalnie/pricehistory/PriceSnapshotService.java new file mode 100644 index 0000000..64aa67e --- /dev/null +++ b/backend/src/main/java/pl/polskalokalnie/pricehistory/PriceSnapshotService.java @@ -0,0 +1,160 @@ +package pl.polskalokalnie.pricehistory; + +import java.text.Normalizer; +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +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.Scheduled; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import pl.polskalokalnie.listing.ListingRepository; +import pl.polskalokalnie.listing.ListingStatus; +import pl.polskalokalnie.listing.OfferType; +import pl.polskalokalnie.listing.PropertyListing; +import pl.polskalokalnie.listing.PropertyType; + +/** + * Historia cen: codzienny zapis srednich cen ofertowych za m2 z opublikowanych ogloszen. + * Danych sprzed pierwszego zapisu nie odtwarzamy - historia rosnie z kazdym dniem. + */ +@Service +public class PriceSnapshotService { + + public static final ZoneId ZONE = ZoneId.of("Europe/Warsaw"); + /** Wartosc rynku oznaczajaca "wtorny i pierwotny razem". */ + public static final String ALL_MARKETS = ""; + + private static final Logger log = LoggerFactory.getLogger(PriceSnapshotService.class); + + private final ListingRepository listingRepository; + private final PriceSnapshotRepository snapshotRepository; + + public PriceSnapshotService(ListingRepository listingRepository, PriceSnapshotRepository snapshotRepository) { + this.listingRepository = listingRepository; + this.snapshotRepository = snapshotRepository; + } + + /** Srednia na dany moment - ta sama grupa, co w zapisie dziennym. */ + public record Average(long avgPricePerM2, int listingsCount) { + } + + private record GroupKey(OfferType offerType, PropertyType propertyType, String market, String city, String district) { + } + + // Co noc zapisujemy stan z konca dnia; przy starcie uzupelniamy dzisiejszy zapis, jesli go brakuje. + // Transakcja na tych metodach, bo wywolanie recordToday() z wnetrza klasy omija proxy Springa. + @Scheduled(cron = "0 30 2 * * *", zone = "Europe/Warsaw") + @Transactional + public void recordDaily() { + recordToday(); + } + + @EventListener(ApplicationReadyEvent.class) + @Transactional + public void recordOnStartupIfMissing() { + if (!snapshotRepository.existsBySnapshotDate(today())) { + recordToday(); + } + } + + /** Zapis dzisiejszych srednich; ponowne wywolanie w tym samym dniu nadpisuje dzisiejsze wiersze. */ + @Transactional + public int recordToday() { + LocalDate date = today(); + snapshotRepository.deleteBySnapshotDate(date); + Map> groups = group(pricedListings()); + List rows = new ArrayList<>(); + groups.forEach((key, prices) -> rows.add(new PriceSnapshot(date, key.offerType(), key.propertyType(), key.market(), + key.city(), key.district(), prices.size(), Math.round(average(prices))))); + snapshotRepository.saveAll(rows); + log.info("Historia cen: zapisano {} srednich za {}", rows.size(), date); + return rows.size(); + } + + /** Aktualna srednia liczona wprost z ogloszen - "dzisiaj" na wykresie jest zawsze swieze. */ + public Average currentAverage(OfferType offerType, PropertyType propertyType, String market, String city, String district) { + String wantedCity = key(city); + String wantedDistrict = key(district); + List prices = pricedListings().stream() + .filter(listing -> listing.getOfferType() == offerType && listing.getPropertyType() == propertyType) + .filter(listing -> key(listing.getCity()).equals(wantedCity)) + .filter(listing -> wantedDistrict.isEmpty() || key(listing.getDistrict()).equals(wantedDistrict)) + .filter(listing -> market.isEmpty() || market.equalsIgnoreCase(trim(listing.getMarket()))) + .map(PriceSnapshotService::pricePerM2) + .toList(); + return prices.isEmpty() ? null : new Average(Math.round(average(prices)), prices.size()); + } + + private List pricedListings() { + return listingRepository.findAll().stream() + .filter(listing -> listing.getStatus() == ListingStatus.APPROVED) + .filter(listing -> listing.getOfferType() != null && listing.getPropertyType() != null) + .filter(listing -> listing.getPrice() != null && listing.getPrice().doubleValue() > 0) + .filter(listing -> listing.getArea() != null && listing.getArea() > 0) + .filter(listing -> !trim(listing.getCity()).isEmpty()) + .toList(); + } + + // Kazde ogloszenie liczy sie do miasta i (jesli ma) do dzielnicy - dla wszystkich rynkow i dla swojego rynku. + private static Map> group(List listings) { + Map> groups = new LinkedHashMap<>(); + for (PropertyListing listing : listings) { + double price = pricePerM2(listing); + String city = trim(listing.getCity()); + String district = trim(listing.getDistrict()); + String market = trim(listing.getMarket()); + List markets = market.isEmpty() ? List.of(ALL_MARKETS) : List.of(ALL_MARKETS, market); + List districts = district.isEmpty() ? List.of("") : List.of("", district); + for (String groupMarket : markets) { + for (String groupDistrict : districts) { + GroupKey key = new GroupKey(listing.getOfferType(), listing.getPropertyType(), groupMarket, + city, groupDistrict); + groups.computeIfAbsent(canonical(groups, key), ignored -> new ArrayList<>()).add(price); + } + } + } + return groups; + } + + // Ta sama grupa niezaleznie od wielkosci liter i spacji - pierwsza napotkana pisownia zostaje nazwa. + private static GroupKey canonical(Map> groups, GroupKey candidate) { + for (GroupKey existing : groups.keySet()) { + if (existing.offerType() == candidate.offerType() && existing.propertyType() == candidate.propertyType() + && existing.market().equalsIgnoreCase(candidate.market()) + && key(existing.city()).equals(key(candidate.city())) + && key(existing.district()).equals(key(candidate.district()))) { + return existing; + } + } + return candidate; + } + + public static LocalDate today() { + return LocalDate.now(ZONE); + } + + /** Klucz porownania nazw: male litery, bez nadmiarowych spacji (polskie znaki zostaja). */ + public static String key(String value) { + return Normalizer.normalize(trim(value), Normalizer.Form.NFC).toLowerCase(Locale.ROOT).replaceAll("\\s+", " "); + } + + private static String trim(String value) { + return value == null ? "" : value.trim(); + } + + private static double pricePerM2(PropertyListing listing) { + return listing.getPrice().doubleValue() / listing.getArea(); + } + + private static double average(List values) { + return values.stream().mapToDouble(Double::doubleValue).average().orElse(0); + } +} diff --git a/backend/src/test/java/pl/polskalokalnie/pricehistory/GusBdlClientTest.java b/backend/src/test/java/pl/polskalokalnie/pricehistory/GusBdlClientTest.java new file mode 100644 index 0000000..4c23aab --- /dev/null +++ b/backend/src/test/java/pl/polskalokalnie/pricehistory/GusBdlClientTest.java @@ -0,0 +1,49 @@ +package pl.polskalokalnie.pricehistory; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.List; +import org.junit.jupiter.api.Test; + +// Probki w formacie odpowiedzi bdl.stat.gov.pl/api/v1 (sprawdzonym 2026-09-22). +class GusBdlClientTest { + + private final ObjectMapper mapper = new ObjectMapper(); + + @Test + void matchesOnlyCityWithPowiatRights() throws Exception { + var units = mapper.readTree(""" + [{"id":"071412865000","name":"Powiat m. st. Warszawa"}, + {"id":"011212106000","name":"Powiat krakowski"}, + {"id":"011212161000","name":"Powiat m. Kraków"}]"""); + + assertThat(GusBdlClient.matchCityUnit(units, "Warszawa")).isEqualTo("071412865000"); + assertThat(GusBdlClient.matchCityUnit(units, "kraków")).isEqualTo("011212161000"); + assertThat(GusBdlClient.matchCityUnit(units, "Zabierzów")).isNull(); + } + + @Test + void readsQuarterlyTotalsPerMarket() throws Exception { + var variables = GusBdlClient.parseVariables(mapper.readTree(""" + [{"id":634007,"n1":"1 kwartał","n2":"ogółem","n3":"ogółem"}, + {"id":634008,"n1":"1 kwartał","n2":"ogółem","n3":"do 40 m2"}, + {"id":634012,"n1":"1 kwartał","n2":"rynek pierwotny","n3":"ogółem"}, + {"id":634032,"n1":"2 kwartał","n2":"rynek wtórny","n3":"ogółem"}]""")); + + assertThat(variables).containsExactly( + new GusBdlClient.Variable(634007, 1, ""), + new GusBdlClient.Variable(634012, 1, "Pierwotny"), + new GusBdlClient.Variable(634032, 2, "Wtórny")); + + List values = GusBdlClient.parseUnitData(mapper.readTree(""" + {"results":[ + {"id":634007,"values":[{"year":"2024","val":13210.4},{"year":"2025","val":0}]}, + {"id":634032,"values":[{"year":"2024","val":14135}]}, + {"id":999999,"values":[{"year":"2024","val":1}]}]}"""), variables); + + assertThat(values).containsExactly( + new GusBdlClient.QuarterValue(2024, 1, "", 13210), + new GusBdlClient.QuarterValue(2024, 2, "Wtórny", 14135)); + } +} diff --git a/backend/src/test/java/pl/polskalokalnie/pricehistory/NbpXlsxParserTest.java b/backend/src/test/java/pl/polskalokalnie/pricehistory/NbpXlsxParserTest.java new file mode 100644 index 0000000..73a2772 --- /dev/null +++ b/backend/src/test/java/pl/polskalokalnie/pricehistory/NbpXlsxParserTest.java @@ -0,0 +1,41 @@ +package pl.polskalokalnie.pricehistory; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.InputStream; +import java.util.List; +import org.junit.jupiter.api.Test; + +class NbpXlsxParserTest { + + // Plik NBP (ceny_mieszkan.xlsx) pobrany 2026-09-22 - prawdziwy uklad arkuszy. + private List parseFixture() throws Exception { + try (InputStream xlsx = getClass().getResourceAsStream("/nbp/ceny_mieszkan.xlsx")) { + return NbpXlsxParser.parse(xlsx); + } + } + + @Test + void readsTransactionPricesPerCityAndMarket() throws Exception { + List rows = parseFixture(); + + // Wartosci z arkusza "Rynek pierwotny", blok "Ceny transakcyjne", III kw. 2006. + assertThat(rows).contains( + new NbpXlsxParser.Row(2006, 3, "Pierwotny", "Kraków", 6816), + new NbpXlsxParser.Row(2006, 3, "Pierwotny", "Białystok", 3008)); + // Oba rynki, "Gdynia**" bez gwiazdek, najnowszy kwartal w pliku. + assertThat(rows).anyMatch(row -> row.market().equals("Wtórny") && row.city().equals("Warszawa") + && row.year() == 2026 && row.quarter() == 2); + assertThat(rows).anyMatch(row -> row.city().equals("Gdynia")); + } + + @Test + void skipsAggregatesAndOfferPrices() throws Exception { + List rows = parseFixture(); + + assertThat(rows).noneMatch(row -> row.city().contains("miast")); + // Cena ofertowa Krakowa na rynku pierwotnym w III kw. 2006 to 6021 - nie moze trafic do transakcyjnych. + assertThat(rows).doesNotContain(new NbpXlsxParser.Row(2006, 3, "Pierwotny", "Kraków", 6021)); + assertThat(rows.stream().map(NbpXlsxParser.Row::city).distinct()).hasSize(17); + } +} diff --git a/backend/src/test/java/pl/polskalokalnie/pricehistory/PriceSnapshotServiceTest.java b/backend/src/test/java/pl/polskalokalnie/pricehistory/PriceSnapshotServiceTest.java new file mode 100644 index 0000000..a79024f --- /dev/null +++ b/backend/src/test/java/pl/polskalokalnie/pricehistory/PriceSnapshotServiceTest.java @@ -0,0 +1,94 @@ +package pl.polskalokalnie.pricehistory; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.math.BigDecimal; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import pl.polskalokalnie.listing.ListingRepository; +import pl.polskalokalnie.listing.ListingStatus; +import pl.polskalokalnie.listing.OfferType; +import pl.polskalokalnie.listing.PropertyListing; +import pl.polskalokalnie.listing.PropertyType; + +class PriceSnapshotServiceTest { + + private final ListingRepository listings = mock(ListingRepository.class); + private final PriceSnapshotRepository snapshots = mock(PriceSnapshotRepository.class); + private final PriceSnapshotService service = new PriceSnapshotService(listings, snapshots); + + @Test + @SuppressWarnings("unchecked") + void recordsCityDistrictAndMarketAverages() { + when(listings.findAll()).thenReturn(List.of( + listing("Kraków", "Podgórze", "Wtórny", 1_000_000, 100, ListingStatus.APPROVED), // 10 000 zl/m2 + listing(" kraków ", "podgórze", "Pierwotny", 600_000, 50, ListingStatus.APPROVED), // 12 000 zl/m2 + listing("Kraków", null, null, 800_000, 100, ListingStatus.APPROVED), // 8 000 zl/m2 + listing("Kraków", "Podgórze", "Wtórny", 9_000_000, 10, ListingStatus.PENDING))); // nieopublikowane + + service.recordToday(); + + ArgumentCaptor> saved = ArgumentCaptor.forClass(List.class); + verify(snapshots).saveAll(saved.capture()); + List rows = saved.getValue(); + + // Cale miasto, wszystkie rynki: (10 000 + 12 000 + 8 000) / 3. + assertThat(find(rows, "", "")).extracting(PriceSnapshot::getAvgPricePerM2, PriceSnapshot::getListingsCount) + .containsExactly(10_000L, 3); + // Dzielnica bez wzgledu na wielkosc liter: (10 000 + 12 000) / 2. + assertThat(find(rows, "podgórze", "")).extracting(PriceSnapshot::getAvgPricePerM2, PriceSnapshot::getListingsCount) + .containsExactly(11_000L, 2); + // Tylko rynek wtorny w miescie. + assertThat(find(rows, "", "Wtórny")).extracting(PriceSnapshot::getAvgPricePerM2, PriceSnapshot::getListingsCount) + .containsExactly(10_000L, 1); + } + + @Test + void currentAverageUsesOnlyMatchingPublishedListings() { + when(listings.findAll()).thenReturn(List.of( + listing("Kraków", "Podgórze", "Wtórny", 1_000_000, 100, ListingStatus.APPROVED), + listing("Kraków", "Podgórze", "Wtórny", 9_000_000, 10, ListingStatus.PAUSED), + listing("Warszawa", "Mokotów", "Wtórny", 2_000_000, 100, ListingStatus.APPROVED))); + + PriceSnapshotService.Average average = service.currentAverage( + OfferType.SALE, PropertyType.APARTMENT, "", "KRAKÓW", ""); + + assertThat(average).isEqualTo(new PriceSnapshotService.Average(10_000L, 1)); + assertThat(service.currentAverage(OfferType.SALE, PropertyType.APARTMENT, "", "Gdańsk", "")).isNull(); + } + + private static PriceSnapshot find(List rows, String districtKey, String market) { + return rows.stream() + .filter(row -> readField(row, "districtKey").equals(districtKey) && readField(row, "market").equals(market)) + .findFirst() + .orElseThrow(() -> new AssertionError("brak wiersza " + districtKey + "/" + market)); + } + + private static String readField(PriceSnapshot row, String name) { + try { + var field = PriceSnapshot.class.getDeclaredField(name); + field.setAccessible(true); + return (String) field.get(row); + } catch (ReflectiveOperationException ex) { + throw new IllegalStateException(ex); + } + } + + private static PropertyListing listing(String city, String district, String market, int price, double area, + ListingStatus status) { + PropertyListing listing = new PropertyListing(); + listing.setOfferType(OfferType.SALE); + listing.setPropertyType(PropertyType.APARTMENT); + listing.setCity(city); + listing.setDistrict(district); + listing.setMarket(market); + listing.setPrice(BigDecimal.valueOf(price)); + listing.setArea(area); + listing.setStatus(status); + return listing; + } +} diff --git a/backend/src/test/resources/nbp/ceny_mieszkan.xlsx b/backend/src/test/resources/nbp/ceny_mieszkan.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..6e2ea8e03b639b2709cee901062a3d416c625f2f GIT binary patch literal 193059 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
O=dicsu7z);)924XI9s3_(hO`f}Cr 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 literal 0 HcmV?d00001 diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index fa39f8e..8f7f9d2 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -20938,204 +20938,208 @@ function MegaSearch({ filters, onOpenMap, onSearch, mode = 'buy' }: { type HistoryPropertyType = 'Mieszkanie' | 'Dom' | 'Lokal użytkowy'; type HistoryMarketType = 'Wtórny i pierwotny' | 'Wtórny' | 'Pierwotny'; -type HistoryPeriod = '2026'; +type HistoryPeriod = '2026' | '5y' | 'all'; type PriceHistoryMarket = { key: string; label: string; city: string; region: string; - apartmentM2: number; - trend24: number; - volatility: number; aliases?: string[]; }; const HISTORY_PRICE_MARKETS: PriceHistoryMarket[] = [ - { key: 'warszawa-mokotow', label: 'Warszawa, Mokotów', city: 'Warszawa', region: 'mazowieckie', apartmentM2: 16842, trend24: 0.086, volatility: 0.032, aliases: ['mokotów'] }, - { key: 'warszawa-srodmiescie', label: 'Warszawa, Śródmieście', city: 'Warszawa', region: 'mazowieckie', apartmentM2: 18932, trend24: 0.094, volatility: 0.036, aliases: ['śródmieście warszawa'] }, - { key: 'warszawa-wola', label: 'Warszawa, Wola', city: 'Warszawa', region: 'mazowieckie', apartmentM2: 16123, trend24: 0.083, volatility: 0.031, aliases: ['wola'] }, - { key: 'warszawa-praga-poludnie', label: 'Warszawa, Praga-Południe', city: 'Warszawa', region: 'mazowieckie', apartmentM2: 13254, trend24: 0.071, volatility: 0.029, aliases: ['praga południe', 'praga-poludnie'] }, - { key: 'warszawa-bielany', label: 'Warszawa, Bielany', city: 'Warszawa', region: 'mazowieckie', apartmentM2: 12876, trend24: 0.067, volatility: 0.027, aliases: ['bielany'] }, - { key: 'krakow-zablocie', label: 'Kraków, Zabłocie', city: 'Kraków', region: 'małopolskie', apartmentM2: 15840, trend24: 0.091, volatility: 0.034, aliases: ['zabłocie'] }, - { key: 'krakow-stare-miasto', label: 'Kraków, Stare Miasto', city: 'Kraków', region: 'małopolskie', apartmentM2: 17490, trend24: 0.088, volatility: 0.037 }, - { key: 'krakow-krowodrza', label: 'Kraków, Krowodrza', city: 'Kraków', region: 'małopolskie', apartmentM2: 14320, trend24: 0.079, volatility: 0.031 }, - { key: 'wroclaw-krzyki', label: 'Wrocław, Krzyki', city: 'Wrocław', region: 'dolnośląskie', apartmentM2: 13480, trend24: 0.082, volatility: 0.032, aliases: ['krzyki'] }, - { key: 'wroclaw-stare-miasto', label: 'Wrocław, Stare Miasto', city: 'Wrocław', region: 'dolnośląskie', apartmentM2: 14750, trend24: 0.084, volatility: 0.034 }, - { key: 'gdansk-wrzeszcz', label: 'Gdańsk, Wrzeszcz', city: 'Gdańsk', region: 'pomorskie', apartmentM2: 14320, trend24: 0.087, volatility: 0.036, aliases: ['wrzeszcz'] }, - { key: 'gdansk-srodmiescie', label: 'Gdańsk, Śródmieście', city: 'Gdańsk', region: 'pomorskie', apartmentM2: 16080, trend24: 0.089, volatility: 0.039 }, - { key: 'gdynia-redlowo', label: 'Gdynia, Redłowo', city: 'Gdynia', region: 'pomorskie', apartmentM2: 13960, trend24: 0.075, volatility: 0.034 }, - { key: 'sopot-centrum', label: 'Sopot, Centrum', city: 'Sopot', region: 'pomorskie', apartmentM2: 18850, trend24: 0.079, volatility: 0.043 }, - { key: 'poznan-jezyce', label: 'Poznań, Jeżyce', city: 'Poznań', region: 'wielkopolskie', apartmentM2: 11980, trend24: 0.064, volatility: 0.028, aliases: ['jeżyce'] }, - { key: 'poznan-grunwald', label: 'Poznań, Grunwald', city: 'Poznań', region: 'wielkopolskie', apartmentM2: 11150, trend24: 0.058, volatility: 0.026 }, - { key: 'lodz-srodmiescie', label: 'Łódź, Śródmieście', city: 'Łódź', region: 'łódzkie', apartmentM2: 9350, trend24: 0.054, volatility: 0.028 }, - { key: 'lodz-widzew', label: 'Łódź, Widzew', city: 'Łódź', region: 'łódzkie', apartmentM2: 8420, trend24: 0.047, volatility: 0.026 }, - { key: 'katowice-koszutka', label: 'Katowice, Koszutka', city: 'Katowice', region: 'śląskie', apartmentM2: 10320, trend24: 0.059, volatility: 0.029 }, - { key: 'rzeszow-centrum', label: 'Rzeszów, Centrum', city: 'Rzeszów', region: 'podkarpackie', apartmentM2: 10380, trend24: 0.069, volatility: 0.031 }, - { key: 'lublin-centrum', label: 'Lublin, Centrum', city: 'Lublin', region: 'lubelskie', apartmentM2: 10120, trend24: 0.061, volatility: 0.028 }, - { key: 'bialystok-centrum', label: 'Białystok, Centrum', city: 'Białystok', region: 'podlaskie', apartmentM2: 9580, trend24: 0.053, volatility: 0.025 }, - { key: 'szczecin-centrum', label: 'Szczecin, Centrum', city: 'Szczecin', region: 'zachodniopomorskie', apartmentM2: 9840, trend24: 0.056, volatility: 0.027 }, - { key: 'bydgoszcz-srodmiescie', label: 'Bydgoszcz, Śródmieście', city: 'Bydgoszcz', region: 'kujawsko-pomorskie', apartmentM2: 8230, trend24: 0.044, volatility: 0.025 }, - { key: 'torun-centrum', label: 'Toruń, Centrum', city: 'Toruń', region: 'kujawsko-pomorskie', apartmentM2: 9140, trend24: 0.049, volatility: 0.026 }, - { key: 'olsztyn-centrum', label: 'Olsztyn, Centrum', city: 'Olsztyn', region: 'warmińsko-mazurskie', apartmentM2: 9120, trend24: 0.05, volatility: 0.026 }, - { key: 'opole-centrum', label: 'Opole, Centrum', city: 'Opole', region: 'opolskie', apartmentM2: 8840, trend24: 0.047, volatility: 0.025 }, - { key: 'kielce-centrum', label: 'Kielce, Centrum', city: 'Kielce', region: 'świętokrzyskie', apartmentM2: 8060, trend24: 0.042, volatility: 0.024 }, - { key: 'zielona-gora-centrum', label: 'Zielona Góra, Centrum', city: 'Zielona Góra', region: 'lubuskie', apartmentM2: 8120, trend24: 0.043, volatility: 0.025 }, - { key: 'zakopane-centrum', label: 'Zakopane, Centrum', city: 'Zakopane', region: 'małopolskie', apartmentM2: 17200, trend24: 0.081, volatility: 0.045 }, + { key: 'warszawa-mokotow', label: 'Warszawa, Mokotów', city: 'Warszawa', region: 'mazowieckie', aliases: ['mokotów'] }, + { key: 'warszawa-srodmiescie', label: 'Warszawa, Śródmieście', city: 'Warszawa', region: 'mazowieckie', aliases: ['śródmieście warszawa'] }, + { key: 'warszawa-wola', label: 'Warszawa, Wola', city: 'Warszawa', region: 'mazowieckie', aliases: ['wola'] }, + { key: 'warszawa-praga-poludnie', label: 'Warszawa, Praga-Południe', city: 'Warszawa', region: 'mazowieckie', aliases: ['praga południe', 'praga-poludnie'] }, + { key: 'warszawa-bielany', label: 'Warszawa, Bielany', city: 'Warszawa', region: 'mazowieckie', aliases: ['bielany'] }, + { key: 'krakow-zablocie', label: 'Kraków, Zabłocie', city: 'Kraków', region: 'małopolskie', aliases: ['zabłocie'] }, + { key: 'krakow-stare-miasto', label: 'Kraków, Stare Miasto', city: 'Kraków', region: 'małopolskie' }, + { key: 'krakow-krowodrza', label: 'Kraków, Krowodrza', city: 'Kraków', region: 'małopolskie' }, + { key: 'wroclaw-krzyki', label: 'Wrocław, Krzyki', city: 'Wrocław', region: 'dolnośląskie', aliases: ['krzyki'] }, + { key: 'wroclaw-stare-miasto', label: 'Wrocław, Stare Miasto', city: 'Wrocław', region: 'dolnośląskie' }, + { key: 'gdansk-wrzeszcz', label: 'Gdańsk, Wrzeszcz', city: 'Gdańsk', region: 'pomorskie', aliases: ['wrzeszcz'] }, + { key: 'gdansk-srodmiescie', label: 'Gdańsk, Śródmieście', city: 'Gdańsk', region: 'pomorskie' }, + { key: 'gdynia-redlowo', label: 'Gdynia, Redłowo', city: 'Gdynia', region: 'pomorskie' }, + { key: 'sopot-centrum', label: 'Sopot, Centrum', city: 'Sopot', region: 'pomorskie' }, + { key: 'poznan-jezyce', label: 'Poznań, Jeżyce', city: 'Poznań', region: 'wielkopolskie', aliases: ['jeżyce'] }, + { key: 'poznan-grunwald', label: 'Poznań, Grunwald', city: 'Poznań', region: 'wielkopolskie' }, + { key: 'lodz-srodmiescie', label: 'Łódź, Śródmieście', city: 'Łódź', region: 'łódzkie' }, + { key: 'lodz-widzew', label: 'Łódź, Widzew', city: 'Łódź', region: 'łódzkie' }, + { key: 'katowice-koszutka', label: 'Katowice, Koszutka', city: 'Katowice', region: 'śląskie' }, + { key: 'rzeszow-centrum', label: 'Rzeszów, Centrum', city: 'Rzeszów', region: 'podkarpackie' }, + { key: 'lublin-centrum', label: 'Lublin, Centrum', city: 'Lublin', region: 'lubelskie' }, + { key: 'bialystok-centrum', label: 'Białystok, Centrum', city: 'Białystok', region: 'podlaskie' }, + { key: 'szczecin-centrum', label: 'Szczecin, Centrum', city: 'Szczecin', region: 'zachodniopomorskie' }, + { key: 'bydgoszcz-srodmiescie', label: 'Bydgoszcz, Śródmieście', city: 'Bydgoszcz', region: 'kujawsko-pomorskie' }, + { key: 'torun-centrum', label: 'Toruń, Centrum', city: 'Toruń', region: 'kujawsko-pomorskie' }, + { key: 'olsztyn-centrum', label: 'Olsztyn, Centrum', city: 'Olsztyn', region: 'warmińsko-mazurskie' }, + { key: 'opole-centrum', label: 'Opole, Centrum', city: 'Opole', region: 'opolskie' }, + { key: 'kielce-centrum', label: 'Kielce, Centrum', city: 'Kielce', region: 'świętokrzyskie' }, + { key: 'zielona-gora-centrum', label: 'Zielona Góra, Centrum', city: 'Zielona Góra', region: 'lubuskie' }, + { key: 'zakopane-centrum', label: 'Zakopane, Centrum', city: 'Zakopane', region: 'małopolskie' }, ]; -const HISTORY_CITY_BASE_PRICES: Record = { - Warszawa: 16000, Kraków: 14500, Wrocław: 12600, Gdańsk: 13600, Gdynia: 12700, Sopot: 17800, - Poznań: 10800, Łódź: 8500, Katowice: 9700, Rzeszów: 9800, Lublin: 9300, Białystok: 8900, - Szczecin: 9200, Bydgoszcz: 7600, Toruń: 8500, Kielce: 7400, Olsztyn: 8500, Opole: 8200, - Zielona: 7800, 'Zielona Góra': 7800, Częstochowa: 6900, Radom: 6700, Gliwice: 7800, - Zabrze: 6100, Rybnik: 6200, Tychy: 7600, Bielsko: 8600, 'Bielsko-Biała': 8600, - Płock: 7100, Tarnów: 7200, Koszalin: 7900, Kalisz: 7100, Legnica: 7300, Słupsk: 7400, - Nowy: 7600, 'Nowy Sącz': 7600, Jelenia: 7400, 'Jelenia Góra': 7400, Piaseczno: 11200, - Pruszków: 10400, Legionowo: 9400, Wieliczka: 9300, Zakopane: 16000, Kołobrzeg: 12200, -}; - const HISTORY_POPULAR_MARKETS = ['Warszawa, Mokotów', 'Kraków, Zabłocie', 'Wrocław, Krzyki', 'Gdańsk, Wrzeszcz', 'Poznań, Jeżyce']; -const HISTORY_PROPERTY_MULTIPLIERS: Record = { Mieszkanie: 1, Dom: 0.78, 'Lokal użytkowy': 1.12 }; -const HISTORY_MARKET_MULTIPLIERS: Record = { 'Wtórny i pierwotny': 1, Wtórny: 0.97, Pierwotny: 1.08 }; -const HISTORY_LOCATION_TYPE_MULTIPLIERS: Record = { - dzielnica: 1, - miasto: 0.96, - town: 0.86, - miejscowość: 0.78, - gmina: 0.76, - powiat: 0.74, - wieś: 0.62, - przysiółek: 0.56, + +// Historia cen z API (/api/price-history) - dzienne srednie ceny ofertowe z ogloszen serwisu. +type ApiPricePoint = { date: string; avgPricePerM2: number; listingsCount: number }; +type ApiQuarterPoint = { year: number; quarter: number; pricePerM2: number }; +// nbp / gus - kwartalne ceny transakcyjne mieszkan dla calego miasta; nbpMarket - rynek serii NBP. +type ApiPriceHistory = { + points: ApiPricePoint[]; + current: ApiPricePoint | null; + trackedSince: string | null; + nbp: ApiQuarterPoint[]; + gus: ApiQuarterPoint[]; + nbpMarket: string; }; + +// Ogloszenia serwisu to mieszkania i domy - lokali uzytkowych nie ma z czego liczyc. +const HISTORY_PROPERTY_API: Record = { + Mieszkanie: 'APARTMENT', + Dom: 'HOUSE', + 'Lokal użytkowy': null, +}; +// Pusty rynek = wtorny i pierwotny razem (tak zapisuje backend). +const HISTORY_MARKET_API: Record = { + 'Wtórny i pierwotny': '', + Wtórny: 'Wtórny', + Pierwotny: 'Pierwotny', +}; + +// "Warszawa, Mokotów" -> miasto Warszawa, dzielnica Mokotów; sama nazwa miasta -> cale miasto. +function priceHistoryApiPath(market: PriceHistoryMarket, propertyType: HistoryPropertyType, + marketType: HistoryMarketType, from: string): string { + // Dzielnica to druga czesc etykiety, o ile nie jest nazwa regionu (lokalizacje zapamietane + // przez starsza wersje mialy np. "Kraków, małopolskie"). + const district = market.label.split(',').map((part) => part.trim()).slice(1) + .find((part) => part && !isHistoryRegionName(part) && normalizeHistoryText(part) !== normalizeHistoryText(market.region)) ?? ''; + const params = new URLSearchParams({ + city: market.city, + district, + propertyType: HISTORY_PROPERTY_API[propertyType] ?? 'APARTMENT', + market: HISTORY_MARKET_API[marketType], + from, + }); + return `/price-history?${params.toString()}`; +} + const HISTORY_YEAR = 2026; const HISTORY_YEAR_MONTHS = ['sty', 'lut', 'mar', 'kwi', 'maj', 'cze', 'lip', 'sie', 'wrz', 'paź', 'lis', 'gru']; +// "od maja", "od września" - odmiana do opisu zmiany ceny. +const HISTORY_MONTHS_GENITIVE = ['stycznia', 'lutego', 'marca', 'kwietnia', 'maja', 'czerwca', 'lipca', 'sierpnia', 'września', 'października', 'listopada', 'grudnia']; const HISTORY_PERIOD_OPTIONS: { value: HistoryPeriod; label: string }[] = [ + { value: '5y', label: 'Ostatnie 5 lat' }, + { value: 'all', label: 'Od 2006 (NBP)' }, { value: '2026', label: '2026 do dziś' }, ]; +// Pierwszy kwartal w danych NBP (baza BaRN). +const HISTORY_NBP_FIRST_YEAR = 2006; +const HISTORY_NBP_FIRST_QUARTER = 3; +const HISTORY_ROMAN_QUARTERS = ['I', 'II', 'III', 'IV']; + +// Przedzial na osi wykresu: miesiac (okres 2026) albo kwartal (dluzsze okresy). +type HistorySlot = { axisLabel: string; label: string; sinceLabel: string; year: number; month: number | null; quarter: number }; + +function buildHistorySlots(period: HistoryPeriod): HistorySlot[] { + if (period === '2026') { + return historyMonthLabels().map((label, month) => ({ + axisLabel: label, + label: `${label} ${HISTORY_YEAR}`, + sinceLabel: HISTORY_MONTHS_GENITIVE[month], + year: HISTORY_YEAR, + month, + quarter: Math.floor(month / 3) + 1, + })); + } + const now = new Date(); + const currentYear = now.getFullYear(); + const currentQuarter = Math.floor(now.getMonth() / 3) + 1; + const startYear = period === '5y' ? currentYear - 4 : HISTORY_NBP_FIRST_YEAR; + const slots: HistorySlot[] = []; + for (let year = startYear; year <= currentYear; year += 1) { + for (let quarter = 1; quarter <= 4; quarter += 1) { + if (year === currentYear && quarter > currentQuarter) { + break; + } + if (period === 'all' && year === HISTORY_NBP_FIRST_YEAR && quarter < HISTORY_NBP_FIRST_QUARTER) { + continue; + } + const label = `${HISTORY_ROMAN_QUARTERS[quarter - 1]} kw. ${year}`; + // Podpis roku przy pierwszym kwartale; przy 20 latach co drugi rok, zeby sie nie zlewaly. + const showYear = (quarter === 1 || slots.length === 0) && (period === '5y' || year % 2 === 0); + slots.push({ axisLabel: showYear ? String(year) : '', label, sinceLabel: label, year, month: null, quarter }); + } + } + return slots; +} + +function historySlotContains(slot: HistorySlot, date: string): boolean { + const year = Number(date.slice(0, 4)); + const month = Number(date.slice(5, 7)) - 1; + return year === slot.year && (slot.month != null ? month === slot.month : Math.floor(month / 3) + 1 === slot.quarter); +} + +// Wartosc kwartalna na osi: w widoku kwartalnym wprost, w miesiecznym w srodkowym miesiacu kwartalu. +function historyQuarterValue(points: ApiQuarterPoint[], slot: HistorySlot): number | null { + if (slot.month != null && slot.month % 3 !== 1) { + return null; + } + return points.find((point) => point.year === slot.year && point.quarter === slot.quarter)?.pricePerM2 ?? null; +} + +// Poczatek okresu dla zapytania o historie. +function historyFromDate(slots: HistorySlot[]): string { + const first = slots[0]; + if (!first) { + return `${HISTORY_YEAR}-01-01`; + } + const month = first.month != null ? first.month + 1 : (first.quarter - 1) * 3 + 1; + return `${first.year}-${String(month).padStart(2, '0')}-01`; +} function normalizeHistoryText(value: string) { return value.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '').replace(/ł/g, 'l').replace(/[^a-z0-9]+/g, ' ').trim(); } -function historyLocationTypeFromText(value: string, city?: string | null) { - const normalized = normalizeHistoryText(value); - if (normalized.includes('dzielnica') || normalized.includes('osiedle')) { - return 'dzielnica'; - } - if (normalized.includes('wies') || normalized.includes('przysiolek') || normalized.includes('hamlet') || normalized.includes('osada')) { - return normalized.includes('przysiolek') || normalized.includes('hamlet') ? 'przysiółek' : 'wieś'; - } - if (normalized.includes('powiat')) { - return 'powiat'; - } - if (normalized.includes('gmina')) { - return 'gmina'; - } - if (normalized.includes('miejscowosc')) { - return 'miejscowość'; - } - if (normalized.includes('miasto') || city) { - return 'miasto'; - } - return 'miejscowość'; -} - -function historyFindValuationCity(value: string) { - const normalized = normalizeHistoryText(value); - return Object.keys(VALUATION_PRICE_PER_SQM_BY_CITY).find((city) => { - const normalizedCity = normalizeHistoryText(city); - return normalized === normalizedCity || normalized.includes(normalizedCity) || normalizedCity.includes(normalized); - }) ?? null; -} - -function historyFindKnownCity(value: string) { - const normalized = normalizeHistoryText(value); - return POLISH_CITIES.find((city) => { - const normalizedCity = normalizeHistoryText(city); - return normalized === normalizedCity || normalized.includes(normalizedCity) || normalizedCity.includes(normalized); - }) ?? null; -} - -function historyFindRegion(value: string) { - const normalized = normalizeHistoryText(value); - return Object.keys(VALUATION_PRICE_PER_SQM_BY_REGION).find((region) => normalized.includes(normalizeHistoryText(region))) ?? null; -} - -function estimateHistoryLocationPrice(label: string, sublabel = '') { - const locationText = [label, sublabel].filter(Boolean).join(', '); - const normalized = normalizeHistoryText(locationText); - const valuationCity = historyFindValuationCity(locationText); - const knownCity = valuationCity ?? historyFindKnownCity(locationText); - const region = historyFindRegion(locationText); - const locationType = historyLocationTypeFromText(locationText, knownCity); - const locationMultiplier = HISTORY_LOCATION_TYPE_MULTIPLIERS[locationType] ?? 0.78; - const seededAdjustment = 0.96 + (normalized.split('').reduce((sum, char) => sum + char.charCodeAt(0), 0) % 9) / 100; - - if (valuationCity) { - const exactPrice = VALUATION_PRICE_PER_SQM_BY_CITY[valuationCity]; - const cityMultiplier = locationType === 'dzielnica' ? 1 : locationType === 'miasto' ? 1 : locationMultiplier; - return { - price: Math.round((exactPrice * cityMultiplier * seededAdjustment) / 50) * 50, - region: region ?? 'Polska', - locationType, - }; - } - - const cityIndex = knownCity ? POLISH_CITIES.findIndex((city) => normalizeHistoryText(city) === normalizeHistoryText(knownCity)) : -1; - if (cityIndex >= 0) { - const regionalBase = region ? VALUATION_PRICE_PER_SQM_BY_REGION[region] : VALUATION_NATIONAL_BASE_PER_SQM; - const cityTierMultiplier = cityIndex < 8 ? 1.24 : cityIndex < 30 ? 1.12 : cityIndex < 80 ? 1.02 : 0.92; - return { - price: Math.round((regionalBase * cityTierMultiplier * seededAdjustment) / 50) * 50, - region: region ?? 'Polska', - locationType: 'miasto', - }; - } - - if (region) { - return { - price: Math.round((VALUATION_PRICE_PER_SQM_BY_REGION[region] * locationMultiplier * seededAdjustment) / 50) * 50, - region, - locationType, - }; - } - - const cityExact = Object.entries(HISTORY_CITY_BASE_PRICES).find(([city]) => normalizeHistoryText(city) === normalized || normalized.startsWith(`${normalizeHistoryText(city)} `)); - if (cityExact) { - return { price: cityExact[1], region: 'Polska', locationType: 'miasto' }; - } - - return { - price: Math.round((VALUATION_NATIONAL_BASE_PER_SQM * locationMultiplier * seededAdjustment) / 50) * 50, - region: 'Polska', - locationType, - }; -} - +// Tylko dokladna nazwa lub alias ze slownika. Dopasowanie po samym miescie wybieralo pierwsza +// z brzegu dzielnice ("Warszawa" -> "Warszawa, Mokotów"), a historia cen jest liczona per dzielnica. function findHistoryMarket(label: string) { const normalized = normalizeHistoryText(label); - return HISTORY_PRICE_MARKETS.find((market) => { - const names = [market.label, market.city, ...(market.aliases ?? [])].map(normalizeHistoryText); - return names.some((name) => normalized === name || normalized.includes(name) || name.includes(normalized)); - }); + return HISTORY_PRICE_MARKETS.find((market) => ( + [market.label, ...(market.aliases ?? [])].some((name) => normalizeHistoryText(name) === normalized) + )); } +const HISTORY_VOIVODESHIPS = [ + 'dolnośląskie', 'kujawsko-pomorskie', 'lubelskie', 'lubuskie', 'łódzkie', 'małopolskie', 'mazowieckie', 'opolskie', + 'podkarpackie', 'podlaskie', 'pomorskie', 'śląskie', 'świętokrzyskie', 'warmińsko-mazurskie', 'wielkopolskie', + 'zachodniopomorskie', +].map(normalizeHistoryText); + +function isHistoryRegionName(value: string) { + const normalized = normalizeHistoryText(value.replace(/^województwo\s+/i, '')); + return normalized === 'polska' || HISTORY_VOIVODESHIPS.includes(normalized); +} + +// Lokalizacja spoza slownika (wpisana albo z podpowiedzi mapy). Ceny liczy backend z ogloszen - tu tylko nazwy: +// "Kraków, Podgórze" -> dzielnica Podgórze w Krakowie; "Kraków" (+ województwo w opisie) -> cale miasto. function createHistoryMarketFromPlace(label: string, sublabel = 'Polska'): PriceHistoryMarket { - const city = label.split(',')[0].trim() || label; - const estimate = estimateHistoryLocationPrice(label, sublabel); - const normalized = normalizeHistoryText(`${label}-${sublabel}`) || 'polska'; - const seed = normalized.split('').reduce((sum, char) => sum + char.charCodeAt(0), 0); - const sublabelParts = sublabel.split(','); - const sublabelTail = sublabelParts[sublabelParts.length - 1]?.trim(); + const labelParts = label.split(',').map((part) => part.trim()).filter(Boolean); + const city = labelParts[0] || label.trim(); + const district = labelParts.slice(1).find((part) => !isHistoryRegionName(part)) ?? ''; + const regionFromPlace = sublabel.split(',').map((part) => part.trim()).find(isHistoryRegionName); + const knownRegion = HISTORY_PRICE_MARKETS.find((market) => normalizeHistoryText(market.city) === normalizeHistoryText(city))?.region; + const region = knownRegion + ?? (regionFromPlace && normalizeHistoryText(regionFromPlace) !== 'polska' ? regionFromPlace.replace(/^województwo\s+/i, '') : 'Polska'); + const normalized = normalizeHistoryText([city, district].filter(Boolean).join('-')) || 'polska'; return { key: `custom-${normalized.replace(/\s+/g, '-')}`, - label: [label, sublabel.includes('województwo') ? '' : sublabelTail].filter(Boolean).join(', '), + label: [city, district].filter(Boolean).join(', '), city, - region: estimate.region, - apartmentM2: Math.round(estimate.price * (0.98 + (seed % 5) / 100)), - trend24: 0.035 + (seed % 52) / 1000, - volatility: 0.02 + (seed % 22) / 1000, + region, }; } @@ -21221,7 +21225,7 @@ function PriceHistoryPage({ user }: { user: AuthUser | null }) { const [selectedMarket, setSelectedMarket] = useState(null); const [propertyType, setPropertyType] = useState('Mieszkanie'); const [marketType, setMarketType] = useState('Wtórny i pierwotny'); - const [period, setPeriod] = useState('2026'); + const [period, setPeriod] = useState('5y'); const [createAlertFeedback, setCreateAlertFeedback] = useState(null); const [cityAlertSubscriptions, setCityAlertSubscriptions] = useState([]); const [suggestions, setSuggestions] = useState([]); @@ -21244,15 +21248,65 @@ function PriceHistoryPage({ user }: { user: AuthUser | null }) { const hasSelectedMarket = selectedMarket != null; const activeLocationLabel = selectedMarket?.label ?? 'wybranej lokalizacji'; const todayLabel = historyTodayLabel(); - const monthLabels = historyMonthLabels(); - // Historia cen nie ma jeszcze zrodla danych - wykres i statystyki zostaja puste do czasu podpiecia API. - const priceHistoryPoints = Array.from({ length: monthLabels.length }, () => 0); - const hasHistoryData = priceHistoryPoints.some((price) => price > 0); - const minPrice = Math.min(...priceHistoryPoints); - const maxPrice = Math.max(...priceHistoryPoints); - const tickValues = historyTicks(minPrice, maxPrice); - const chartValues = priceHistoryPoints; - const chartTicks = tickValues; + const historySlots = useMemo(() => buildHistorySlots(period), [period]); + // Historia z /api/price-history: dzienne zapisy srednich cen ofertowych z ogloszen serwisu + // oraz kwartalne ceny transakcyjne NBP i GUS dla calego miasta. + const [history, setHistory] = useState(null); + const [historyLoading, setHistoryLoading] = useState(false); + // Aktualna srednia dla lokalizacji z porownania (klucz lokalizacji -> cena za m2 albo null). + const [comparisonPrices, setComparisonPrices] = useState>({}); + const historyPropertyAvailable = HISTORY_PROPERTY_API[propertyType] != null; + // Nasza srednia w przedziale (miesiac albo kwartal); ostatni przedzial to swieza srednia z ogloszen. + // Przedzial bez zapisow zostaje pusty - niczego nie dopowiadamy. + const offerPrices: (number | null)[] = historySlots.map((slot, slotIndex) => { + if (!history) { + return null; + } + if (slotIndex === historySlots.length - 1 && history.current) { + return history.current.avgPricePerM2; + } + const inSlot = history.points.filter((point) => historySlotContains(slot, point.date)); + return inSlot.length > 0 + ? Math.round(inSlot.reduce((sum, point) => sum + point.avgPricePerM2, 0) / inSlot.length) + : null; + }); + const nbpPrices = historySlots.map((slot) => historyQuarterValue(history?.nbp ?? [], slot)); + const gusPrices = historySlots.map((slot) => historyQuarterValue(history?.gus ?? [], slot)); + const knownPrices = offerPrices + .map((price, slotIndex) => ({ price, slotIndex })) + .filter((entry): entry is { price: number; slotIndex: number } => entry.price != null); + const hasOfferData = knownPrices.length > 0; + const hasNbpData = nbpPrices.some((price) => price != null); + const hasGusData = gusPrices.some((price) => price != null); + const hasHistoryData = hasOfferData || hasNbpData || hasGusData; + const firstKnown = knownPrices[0] ?? null; + const latestKnown = knownPrices[knownPrices.length - 1] ?? null; + const lowestKnown = knownPrices.reduce<{ price: number; slotIndex: number } | null>((lowest, entry) => (!lowest || entry.price < lowest.price ? entry : lowest), null); + const highestKnown = knownPrices.reduce<{ price: number; slotIndex: number } | null>((highest, entry) => (!highest || entry.price > highest.price ? entry : highest), null); + const averageKnown = hasOfferData ? Math.round(knownPrices.reduce((sum, entry) => sum + entry.price, 0) / knownPrices.length) : null; + // Zmiana ma sens dopiero przy dwoch roznych przedzialach z danymi. + const changePercent = firstKnown && latestKnown && knownPrices.length > 1 && firstKnown.price > 0 + ? ((latestKnown.price - firstKnown.price) / firstKnown.price) * 100 + : null; + // Ostatnie wartosci zrodel zewnetrznych (tez spoza wybranego okresu) - do porownania z ogloszeniami. + const latestNbp = history?.nbp?.[history.nbp.length - 1] ?? null; + const latestGus = history?.gus?.[history.gus.length - 1] ?? null; + const nbpMarketLabel = (history?.nbpMarket ?? 'Wtórny').toLowerCase(); + // GUS podaje tez oba rynki razem - wtedy porownanie z NBP (jeden rynek) jest tylko orientacyjne. + const gusMarketLabel = marketType === 'Wtórny i pierwotny' ? 'oba rynki' : `rynek ${marketType.toLowerCase()}`; + // Najnowszy kwartal, dla ktorego sa oba zrodla - tam porownujemy NBP z GUS. + const commonExternalQuarter = [...(history?.nbp ?? [])].reverse() + .map((nbp) => ({ nbp, gus: history?.gus.find((gus) => gus.year === nbp.year && gus.quarter === nbp.quarter) })) + .find((pair): pair is { nbp: ApiQuarterPoint; gus: ApiQuarterPoint } => pair.gus != null) ?? null; + const quarterName = (point: ApiQuarterPoint) => `${HISTORY_ROMAN_QUARTERS[point.quarter - 1]} kw. ${point.year}`; + const percentDiff = (value: number, reference: number) => { + const diff = ((value - reference) / reference) * 100; + return `${diff >= 0 ? '+' : ''}${diff.toFixed(1).replace('.', ',')}%`; + }; + const allValues = [...offerPrices, ...nbpPrices, ...gusPrices].filter((price): price is number => price != null); + const minPrice = allValues.length ? Math.min(...allValues) : 0; + const maxPrice = allValues.length ? Math.max(...allValues) : 0; + const chartTicks = historyTicks(minPrice, maxPrice); const chartAxisMin = minPrice; const chartAxisMax = maxPrice; // Tabela porownania to ostatnie sprawdzone lokalizacje tego konta - bez podpowiedzi z listy. @@ -21260,41 +21314,103 @@ function PriceHistoryPage({ user }: { user: AuthUser | null }) { const chartWidth = 920; const chartHeight = 250; const chartPaddingTop = 86; - const chartPaddingRight = 22; const chartPaddingBottom = 28; - const chartPaddingLeft = 52; - const chartInnerWidth = chartWidth - chartPaddingLeft - chartPaddingRight; const chartInnerHeight = chartHeight - chartPaddingTop - chartPaddingBottom; - const pointCoords = chartValues.map((price, index) => { - const x = chartPaddingLeft + (index / (chartValues.length - 1)) * chartInnerWidth; + // Srodek kolumny przedzialu - w tym samym miejscu co podpis pod wykresem. + const slotX = (slotIndex: number) => ((slotIndex + 0.5) / historySlots.length) * chartWidth; + const priceY = (price: number) => { const range = chartAxisMax - chartAxisMin || 1; - const y = chartPaddingTop + (1 - (price - chartAxisMin) / range) * chartInnerHeight; - return { x, y, price, sourcePrice: priceHistoryPoints[index] }; - }); - const linePath = pointCoords.map((point, index) => `${index === 0 ? 'M' : 'L'} ${point.x.toFixed(1)} ${point.y.toFixed(1)}`).join(' '); + return chartAxisMax === chartAxisMin + ? chartPaddingTop + chartInnerHeight / 2 + : chartPaddingTop + (1 - (price - chartAxisMin) / range) * chartInnerHeight; + }; + const seriesCoords = (prices: (number | null)[]) => prices + .map((price, slotIndex) => (price == null ? null : { x: slotX(slotIndex), y: priceY(price), price, slotIndex })) + .filter((point): point is { x: number; y: number; price: number; slotIndex: number } => point != null); + const seriesPath = (coords: { x: number; y: number }[]) => coords + .map((point, index) => `${index === 0 ? 'M' : 'L'} ${point.x.toFixed(1)} ${point.y.toFixed(1)}`).join(' '); + const pointCoords = seriesCoords(offerPrices); + const nbpCoords = seriesCoords(nbpPrices); + const gusCoords = seriesCoords(gusPrices); + const linePath = seriesPath(pointCoords); + const nbpPath = seriesPath(nbpCoords); + const gusPath = seriesPath(gusCoords); const chartBaseY = chartHeight - chartPaddingBottom; - const areaPath = `${linePath} L ${pointCoords[pointCoords.length - 1].x.toFixed(1)} ${chartBaseY} L ${chartPaddingLeft} ${chartBaseY} Z`; - const hoveredPoint = hoveredHistoryIndex != null ? pointCoords[hoveredHistoryIndex] : null; - const hoveredDate = hoveredHistoryIndex != null ? `${monthLabels[hoveredHistoryIndex]} ${HISTORY_YEAR}${hoveredHistoryIndex === monthLabels.length - 1 ? ` (do ${todayLabel})` : ''}` : ''; - const tooltipWidth = 132; - const tooltipHeight = 54; + const areaPath = pointCoords.length > 1 + ? `${linePath} L ${pointCoords[pointCoords.length - 1].x.toFixed(1)} ${chartBaseY} L ${pointCoords[0].x.toFixed(1)} ${chartBaseY} Z` + : ''; + // Dymek: wszystkie zrodla dla przedzialu pod kursorem. + const hoveredSlot = hoveredHistoryIndex != null ? historySlots[hoveredHistoryIndex] ?? null : null; + const hoveredValues = hoveredHistoryIndex == null ? [] : [ + { label: 'Ogłoszenia', price: offerPrices[hoveredHistoryIndex] }, + { label: `NBP (${nbpMarketLabel})`, price: nbpPrices[hoveredHistoryIndex] }, + { label: `GUS (${gusMarketLabel})`, price: gusPrices[hoveredHistoryIndex] }, + ].filter((entry): entry is { label: string; price: number } => entry.price != null); + const hoveredPoint = hoveredSlot && hoveredValues.length > 0 + ? { x: slotX(hoveredHistoryIndex!), y: priceY(Math.max(...hoveredValues.map((entry) => entry.price))) } + : null; + const hoveredDate = hoveredSlot + ? `${hoveredSlot.label}${hoveredHistoryIndex === historySlots.length - 1 ? ` (do ${todayLabel})` : ''}` + : ''; + const tooltipWidth = 190; + const tooltipHeight = 30 + hoveredValues.length * 20; const tooltipX = hoveredPoint ? Math.min(chartWidth - tooltipWidth - 8, Math.max(8, hoveredPoint.x - tooltipWidth / 2)) : 0; const tooltipY = hoveredPoint ? Math.max(8, hoveredPoint.y - tooltipHeight - 14) : 0; const selectedMarketAlreadyAlerted = selectedMarket ? cityAlertSubscriptions.some((item) => item.key === selectedMarket.key) : false; + // Dymek przy najblizszym punkcie z danymi. const handleHistoryChartMouseMove = (event: ReactMouseEvent) => { - if (!hasSelectedMarket) { + const slotsWithData = historySlots + .map((_, slotIndex) => slotIndex) + .filter((slotIndex) => offerPrices[slotIndex] != null || nbpPrices[slotIndex] != null || gusPrices[slotIndex] != null); + if (!hasSelectedMarket || slotsWithData.length === 0) { return; } const bounds = event.currentTarget.getBoundingClientRect(); const svgX = ((event.clientX - bounds.left) / bounds.width) * chartWidth; - const rawIndex = Math.round(((svgX - chartPaddingLeft) / chartInnerWidth) * (pointCoords.length - 1)); - const nextIndex = Math.min(pointCoords.length - 1, Math.max(0, rawIndex)); - setHoveredHistoryIndex(nextIndex); + const nearest = slotsWithData.reduce((best, slotIndex) => ( + Math.abs(slotX(slotIndex) - svgX) < Math.abs(slotX(best) - svgX) ? slotIndex : best + ), slotsWithData[0]); + setHoveredHistoryIndex(nearest); }; + useEffect(() => { + if (!selectedMarket || !historyPropertyAvailable) { + setHistory(null); + return; + } + let cancelled = false; + setHistoryLoading(true); + setHoveredHistoryIndex(null); + apiFetch(priceHistoryApiPath(selectedMarket, propertyType, marketType, historyFromDate(historySlots))) + .then((data) => { if (!cancelled) setHistory(data); }) + .catch(() => { if (!cancelled) setHistory(null); }) + .finally(() => { if (!cancelled) setHistoryLoading(false); }); + return () => { cancelled = true; }; + }, [selectedMarket, propertyType, marketType, historyPropertyAvailable, historySlots]); + + // Porownanie: aktualna srednia dla kazdej zapamietanej lokalizacji (te same filtry co wykres). + useEffect(() => { + if (!historyPropertyAvailable || recentMarkets.length === 0) { + setComparisonPrices({}); + return; + } + let cancelled = false; + const today = new Date().toISOString().slice(0, 10); + Promise.all(recentMarkets.map((market) => ( + apiFetch(priceHistoryApiPath(market, propertyType, marketType, today)) + .then((data) => [market.key, data.current?.avgPricePerM2 ?? null] as const) + .catch(() => [market.key, null] as const) + ))).then((entries) => { + if (!cancelled) { + setComparisonPrices(Object.fromEntries(entries)); + } + }); + return () => { cancelled = true; }; + }, [recentMarkets, propertyType, marketType, historyPropertyAvailable]); + useEffect(() => { if (!createAlertFeedback) { return; @@ -21384,11 +21500,11 @@ function PriceHistoryPage({ user }: { user: AuthUser | null }) { return; } const typeParam = historyParams.get('typ'); - if (typeParam && typeParam in HISTORY_PROPERTY_MULTIPLIERS) { + if (typeParam && typeParam in HISTORY_PROPERTY_API) { setPropertyType(typeParam as HistoryPropertyType); } const marketParam = historyParams.get('rynek'); - if (marketParam && marketParam in HISTORY_MARKET_MULTIPLIERS) { + if (marketParam && marketParam in HISTORY_MARKET_API) { setMarketType(marketParam as HistoryMarketType); } applyMarket(resolveHistoryMarket(label)); @@ -21421,7 +21537,7 @@ function PriceHistoryPage({ user }: { user: AuthUser | null }) { setSuggestOpen(false); setPropertyType('Mieszkanie'); setMarketType('Wtórny i pierwotny'); - setPeriod('2026'); + setPeriod('5y'); }; const createCityAlert = () => { @@ -21529,7 +21645,7 @@ function PriceHistoryPage({ user }: { user: AuthUser | null }) {

setHoveredHistoryIndex(null)} > @@ -21584,27 +21709,58 @@ function PriceHistoryPage({ user }: { user: AuthUser | null }) { const labelY = Math.max(13, Math.min(chartHeight - 10, y - 7)); return {formatPricePerArea(tick)}; })} - - - {pointCoords.map((point, index) => )} + {nbpCoords.length > 1 && } + {gusCoords.length > 1 && } + {areaPath && } + {pointCoords.length > 1 && } + {pointCoords.map((point) => )} + {/* Pojedynczy punkt zrodla zewnetrznego (np. okres 2026) - bez linii nie bylby widoczny. */} + {nbpCoords.length === 1 && } + {gusCoords.length === 1 && } )} {hasSelectedMarket && hoveredPoint && } {hasSelectedMarket && hoveredPoint && ( -
{hoveredDate}{formatPricePerArea(hoveredPoint.sourcePrice)}
+
+ {hoveredDate} + {hoveredValues.map((entry) => ( + {entry.label}: {formatPricePerArea(entry.price)} + ))} +
)} -
Brak danychHistoria cen będzie dostępna wkrótce.
-
{monthLabels.map((month, index) => {month})}
+ {!hasHistoryData && ( +
+ {!hasSelectedMarket ? ( + <>Wybierz lokalizacjęPokażemy średnie ceny ofertowe z ogłoszeń w wybranym mieście lub dzielnicy. + ) : historyLoading ? ( + <>Wczytywanie…Pobieramy historię cen. + ) : ( + <>Brak danychW tej lokalizacji nie ma jeszcze ogłoszeń spełniających wybrane filtry. + )} +
+ )} +
{historySlots.map((slot) => {slot.axisLabel})}
+ {(hasNbpData || hasGusData) && ( +
+ {hasOfferData && Ceny ofertowe z ogłoszeń (Polska Lokalnie)} + {hasNbpData && Ceny transakcyjne NBP, rynek {nbpMarketLabel} - całe miasto} + {hasGusData && Ceny transakcyjne GUS, {gusMarketLabel} - całe miasto} +
+ )}
-
Najniższa cena—
-
Najwyższa cena—
-
Zmiana od stycznia—
-
Średnia cena—
+
Najniższa cena{lowestKnown ? formatPricePerArea(lowestKnown.price) : '—'}{lowestKnown && {historySlots[lowestKnown.slotIndex].label}}
+
Najwyższa cena{highestKnown ? formatPricePerArea(highestKnown.price) : '—'}{highestKnown && {historySlots[highestKnown.slotIndex].label}}
+
= 0 ? 'positive' : 'negative'}> + Zmiana w okresie + {changePercent == null ? '—' : `${changePercent >= 0 ? '+' : ''}${changePercent.toFixed(1).replace('.', ',')}%`} + {changePercent != null && firstKnown && latestKnown && {formatPricePerArea(latestKnown.price - firstKnown.price)}} +
+
Średnia cena{averageKnown != null ? formatPricePerArea(averageKnown) : '—'}
@@ -21626,7 +21782,74 @@ function PriceHistoryPage({ user }: { user: AuthUser | null }) {

Wnioski z analizy

-

Brak danych do analizy.

+ {!latestKnown && !latestNbp && !latestGus ? ( +

+ {hasSelectedMarket ? 'Brak danych do analizy w tej lokalizacji.' : 'Wybierz lokalizację, aby zobaczyć wnioski.'} +

+ ) : ( +
+ {latestKnown ? ( + <> +
+ +

+ Aktualna cena ofertowa + + {propertyType} ({marketType.toLowerCase()}) w lokalizacji {activeLocationLabel}: {formatPricePerArea(latestKnown.price)} + {history?.current ? `, liczona z ${history.current.listingsCount} ${history.current.listingsCount === 1 ? 'ogłoszenia' : 'ogłoszeń'}` : ''}. + +

+
+
+ +

+ {changePercent == null ? 'Trend' : changePercent > 0 ? 'Ceny rosną' : changePercent < 0 ? 'Ceny spadają' : 'Ceny bez zmian'} + + {changePercent == null + ? `Za mało danych z ogłoszeń, aby ocenić trend${history?.trackedSince ? ` - zbieramy je od ${formatArticleDate(history.trackedSince)}` : ''}.` + : `Od ${historySlots[firstKnown!.slotIndex].sinceLabel} średnia zmieniła się o ${changePercent.toFixed(1).replace('.', ',')}%.`} + +

+
+ + ) : ( +
+ +

+ Brak ogłoszeń + W tej lokalizacji nie ma teraz ogłoszeń spełniających filtry - poniżej ceny transakcyjne z danych publicznych. +

+
+ )} + {(latestNbp || latestGus) && ( +
+ +

+ Porównanie źródeł (ceny transakcyjne, całe miasto) + {latestNbp && ( + + NBP, rynek {nbpMarketLabel}, {quarterName(latestNbp)}: {formatPricePerArea(latestNbp.pricePerM2)} + {latestKnown ? ` - ceny w ogłoszeniach ${percentDiff(latestKnown.price, latestNbp.pricePerM2)}` : ''}. + + )} + {latestGus && ( + + GUS, {gusMarketLabel}, {quarterName(latestGus)}: {formatPricePerArea(latestGus.pricePerM2)} + {latestKnown ? ` - ceny w ogłoszeniach ${percentDiff(latestKnown.price, latestGus.pricePerM2)}` : ''}. + + )} + {commonExternalQuarter && commonExternalQuarter.nbp.pricePerM2 !== commonExternalQuarter.gus.pricePerM2 && ( + + W {quarterName(commonExternalQuarter.nbp)} źródła się różnią: NBP ({nbpMarketLabel}) {formatPricePerArea(commonExternalQuarter.nbp.pricePerM2)}, + GUS ({gusMarketLabel}) {formatPricePerArea(commonExternalQuarter.gus.pricePerM2)} ({percentDiff(commonExternalQuarter.nbp.pricePerM2, commonExternalQuarter.gus.pricePerM2)}). + Średnia z obu: {formatPricePerArea(Math.round((commonExternalQuarter.nbp.pricePerM2 + commonExternalQuarter.gus.pricePerM2) / 2))}. + + )} +

+
+ )} +
+ )}
@@ -21643,7 +21866,7 @@ function PriceHistoryPage({ user }: { user: AuthUser | null }) { onClick={() => applyMarket(market)} > {historyShortMarketLabel(market)} - — + {comparisonPrices[market.key] != null ? formatPricePerArea(comparisonPrices[market.key] as number) : '—'}