Refine Columbia sync after first live run
Fixes from reviewing the first full sync of the real catalog:
- Exclude non-powder / size-variant listings: physical swatch cards (-SW /
"SWATCH"), 4 oz testers (-04 / "Tester"), and 5 lb sample bags ("Sample (").
These are not standalone powder colors. Filtered before mapping, and a
cleanup step deletes any already synced (so they're removed, not flagged
discontinued). Sample detection keys off the "Sample (" name, not the bare
-S suffix, to avoid catching a real SKU ending in S (verified 0 collisions).
- Tighten RequiresClearCoat: was flagging ~53% of the catalog on any casual
"clear coat" mention. Now only genuine signals (partial-cure schedules, the
Illusion line, explicit "requires a clear" phrasing) trip it.
- Fix literal "—" in the sync success banner (TempData is HTML-encoded).
Tests cover the exclusion patterns and the tightened clear-coat detection.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -57,7 +57,9 @@ public class ColumbiaCatalogSyncService : IColumbiaCatalogSyncService
|
||||
result.TotalFetched = products.Count;
|
||||
|
||||
// Map and de-duplicate by (VendorName, SKU) in case the feed repeats a SKU.
|
||||
// Exclude swatch cards and tester/sample size-variants — not standalone powder colors.
|
||||
var mapped = products
|
||||
.Where(p => !ColumbiaCatalogMapper.IsExcludedProduct(p))
|
||||
.Select(ColumbiaCatalogMapper.Map)
|
||||
.Where(m => !string.IsNullOrWhiteSpace(m.Sku))
|
||||
.GroupBy(m => $"{m.VendorName}|{m.Sku}", StringComparer.OrdinalIgnoreCase)
|
||||
@@ -70,6 +72,10 @@ public class ColumbiaCatalogSyncService : IColumbiaCatalogSyncService
|
||||
result.Unchanged = upsertResult.Unchanged;
|
||||
result.Skipped = upsertResult.Skipped;
|
||||
|
||||
// Remove any excluded records (swatches) that were synced before the exclusion existed,
|
||||
// so they're deleted outright rather than lingering as "discontinued" powders.
|
||||
await RemoveExcludedRecordsAsync();
|
||||
|
||||
// Complete pull succeeded — safe to reconcile discontinuations.
|
||||
var incomingKeys = mapped
|
||||
.Select(m => $"{m.VendorName}|{m.Sku}")
|
||||
@@ -136,6 +142,32 @@ public class ColumbiaCatalogSyncService : IColumbiaCatalogSyncService
|
||||
return (discontinued, reactivated);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes Columbia-sourced catalog rows that should not be in the catalog (swatch cards and
|
||||
/// tester/sample size-variants). Mirrors <see cref="ColumbiaCatalogMapper.IsExcludedProduct"/>
|
||||
/// on the stored columns. A no-op once the catalog is clean; guards against records synced
|
||||
/// before the exclusion rule and ensures excluded items are removed, not flagged discontinued.
|
||||
/// </summary>
|
||||
private async Task RemoveExcludedRecordsAsync()
|
||||
{
|
||||
var excluded = (await _unitOfWork.PowderCatalog.FindAsync(p =>
|
||||
p.Source == ColumbiaIntegrationConstants.SourceName
|
||||
&& (p.Sku.EndsWith("-SW")
|
||||
|| p.Sku.EndsWith("-04")
|
||||
|| p.ColorName.Contains("SWATCH")
|
||||
|| p.ColorName.Contains("Tester")
|
||||
|| p.ColorName.Contains("Sample (")))).ToList();
|
||||
|
||||
if (excluded.Count == 0)
|
||||
return;
|
||||
|
||||
foreach (var e in excluded)
|
||||
await _unitOfWork.PowderCatalog.DeleteAsync(e);
|
||||
await _unitOfWork.CompleteAsync();
|
||||
|
||||
_logger.LogInformation("Columbia sync: removed {Count} excluded record(s) (swatch/tester/sample) from the catalog.", excluded.Count);
|
||||
}
|
||||
|
||||
/// <summary>Persists the run outcome to the last-synced / last-result platform settings.</summary>
|
||||
private async Task RecordResultAsync(ColumbiaSyncResult result)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user