using System.Text.Json.Serialization; namespace PrismaticSync.Models; /// /// On-disk scrape output. Shape matches the app's catalog import (a top-level "results" array of /// snake_case product records), so the JSON drops straight into the import endpoint. "errors" tracks /// failed URLs for resumable re-runs. /// public class ScrapeOutput { [JsonPropertyName("results")] public List Results { get; set; } = new(); [JsonPropertyName("errors")] public List Errors { get; set; } = new(); } /// One scraped product, in the import's expected field shape. public class ProductRecord { [JsonPropertyName("sku")] public string Sku { get; set; } = ""; [JsonPropertyName("color_name")] public string ColorName { get; set; } = ""; [JsonPropertyName("description")] public string Description { get; set; } = ""; [JsonPropertyName("price_tiers")] public List PriceTiers { get; set; } = new(); [JsonPropertyName("safety_data_sheet_url")] public string SafetyDataSheetUrl { get; set; } = ""; [JsonPropertyName("technical_data_sheet_url")] public string TechnicalDataSheetUrl { get; set; } = ""; [JsonPropertyName("application_guide_url")] public string ApplicationGuideUrl { get; set; } = ""; [JsonPropertyName("sample_image_url")] public string SampleImageUrl { get; set; } = ""; [JsonPropertyName("product_url")] public string ProductUrl { get; set; } = ""; [JsonPropertyName("scraped_at")] public DateTime ScrapedAt { get; set; } } /// A quantity-break price tier — {min, max, price}. max is null for an open-ended top tier. public class PriceTier { [JsonPropertyName("min")] public int? Min { get; set; } [JsonPropertyName("max")] public int? Max { get; set; } [JsonPropertyName("price")] public decimal Price { get; set; } } /// A URL that failed to scrape, kept so resumable runs can skip or retry it. public class ScrapeError { [JsonPropertyName("product_url")] public string ProductUrl { get; set; } = ""; [JsonPropertyName("error")] public string Error { get; set; } = ""; [JsonPropertyName("scraped_at")] public DateTime ScrapedAt { get; set; } }