Add Columbia Coatings API client, DTOs, and sync settings
Phase 1b of the Columbia Coatings integration: the typed read client and its configuration, ahead of the sync/mapper service. - ColumbiaProductDtos: wire-shape models for GET /products. tiered_pricing is captured as JsonElement because the API returns it as an object on simple products but an empty array on variable ones — binding it raw avoids a deserialization throw; the mapper interprets it. - IColumbiaCoatingsApiClient / ColumbiaCoatingsApiClient: pages the catalog via GET /products (NOT the export download_url, which is Cloudflare-blocked for server clients). Sends X-API-Key from config, honors 429/Retry-After, and THROWS on any page failure so a partial pull can never be mistaken for the full catalog (protects the later discontinuation sweep). - ColumbiaIntegrationConstants: single home for config keys, setting keys, and the derived Source/manufacturer/category values. - Config: Columbia:ApiKey (blank — secret supplied per environment) and Columbia:BaseUrl in appsettings. - SeedColumbiaSyncSettings migration: seeds SuperAdmin-managed platform settings ColumbiaSyncEnabled (off by default), ColumbiaSyncIntervalDays (7), and last-sync tracking, under a new "Integrations" group. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
using PowderCoating.Application.DTOs.Columbia;
|
||||
|
||||
namespace PowderCoating.Application.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Typed client for the Columbia Coatings product catalog API (<c>/wp-json/cca/v1</c>).
|
||||
/// Read-only: lists products via the paged <c>GET /products</c> endpoint.
|
||||
/// <para>
|
||||
/// We deliberately page <c>/products</c> rather than using the bulk <c>export.json</c> download:
|
||||
/// the export returns a temporary <c>download_url</c> to a static file under <c>/wp-content/uploads</c>,
|
||||
/// which sits behind Cloudflare bot protection and 403s for non-browser clients. The
|
||||
/// <c>/wp-json</c> API routes are allowlisted via the API key, so paging is the only path that
|
||||
/// works reliably from a server.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public interface IColumbiaCoatingsApiClient
|
||||
{
|
||||
/// <summary>
|
||||
/// True when an API key is configured (<c>Columbia:ApiKey</c>). When false, callers should
|
||||
/// skip the sync entirely rather than issue unauthenticated requests.
|
||||
/// </summary>
|
||||
bool IsConfigured { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a single page of products. <paramref name="perPage"/> is capped at 100 by the API.
|
||||
/// </summary>
|
||||
Task<ColumbiaProductsResponse> GetProductsPageAsync(int page, int perPage, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Pages through the entire catalog and returns every product. Honors rate limiting
|
||||
/// (429 / Retry-After). THROWS if any page fails after retries — callers must treat an
|
||||
/// exception as "incomplete pull" and NOT run discontinuation logic against a partial set.
|
||||
/// </summary>
|
||||
Task<IReadOnlyList<ColumbiaProduct>> GetAllProductsAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
Reference in New Issue
Block a user