Enhance: Replace All now clears orders + Auto-creates categories

- Replace All option now deletes ALL sales data (orders, payments, customers, messages)
- Auto-create missing categories in text import (same as CSV import)
- Deletes in proper order: sales data → products → categories
- Ensures clean slate for complete catalog replacement
- Add formatted product import file with variant collections

Changes:
- ImportFromTextAsync: Delete sales + products when replaceAll=true
- ImportFromHumanTextAsync: Auto-create categories + delete sales data
- Regex parsing to extract category names before import
- Enhanced logging for deletion operations
This commit is contained in:
2025-10-08 16:01:21 +01:00
parent 4f591418df
commit daa59e3271
2 changed files with 218 additions and 7 deletions

View File

@@ -53,9 +53,15 @@ public class ProductImportService : IProductImportService
// Replace all existing data if requested
if (replaceAll)
{
_logger.LogWarning("REPLACE ALL: Deleting all existing products, variants, and categories");
var deletedCount = await DeleteAllProductsAndCategoriesAsync();
_logger.LogInformation("Deleted {Count} existing records", deletedCount);
_logger.LogWarning("REPLACE ALL: Deleting all existing orders, sales data, products, and categories");
// Delete orders and sales data first
var salesDeleted = await DeleteAllOrdersAndSalesDataAsync();
_logger.LogInformation("Deleted {Count} sales records", salesDeleted);
// Then delete products and categories
var productDeleted = await DeleteAllProductsAndCategoriesAsync();
_logger.LogInformation("Deleted {Count} product records", productDeleted);
}
var lines = csvText.Split('\n', StringSplitOptions.RemoveEmptyEntries);
@@ -381,9 +387,15 @@ public class ProductImportService : IProductImportService
// Replace all existing data if requested
if (replaceAll)
{
_logger.LogWarning("REPLACE ALL: Deleting all existing products, variants, and categories");
var deletedCount = await DeleteAllProductsAndCategoriesAsync();
_logger.LogInformation("Deleted {Count} existing records", deletedCount);
_logger.LogWarning("REPLACE ALL: Deleting all existing orders, sales data, products, and categories");
// Delete orders and sales data first
var salesDeleted = await DeleteAllOrdersAndSalesDataAsync();
_logger.LogInformation("Deleted {Count} sales records", salesDeleted);
// Then delete products and categories
var productDeleted = await DeleteAllProductsAndCategoriesAsync();
_logger.LogInformation("Deleted {Count} product records", productDeleted);
}
if (string.IsNullOrWhiteSpace(textContent))
@@ -406,8 +418,39 @@ public class ProductImportService : IProductImportService
.ToListAsync();
var variantCollections = variantCollectionsList.ToDictionary(vc => vc.Name, vc => vc.Id, StringComparer.OrdinalIgnoreCase);
// Split into product blocks (each starting with #)
// Auto-create categories from text blocks if they don't exist
var productBlocks = SplitIntoProductBlocks(textContent);
var uniqueCategoryNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var block in productBlocks)
{
var categoryMatch = System.Text.RegularExpressions.Regex.Match(block, @"category:\s*(.+)", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
if (categoryMatch.Success)
{
var categoryName = categoryMatch.Groups[1].Value.Trim();
if (!string.IsNullOrEmpty(categoryName))
{
uniqueCategoryNames.Add(categoryName);
}
}
}
// Create missing categories
foreach (var categoryName in uniqueCategoryNames)
{
if (!categoryLookup.ContainsKey(categoryName))
{
var createCategoryDto = new CreateCategoryDto
{
Name = categoryName,
Description = $"Auto-created category for {categoryName} products"
};
var newCategory = await _categoryService.CreateCategoryAsync(createCategoryDto);
categoryLookup[categoryName] = newCategory.Id;
_logger.LogInformation("Auto-created category: {CategoryName}", categoryName);
}
}
// Split into product blocks (each starting with #)
result.TotalRows = productBlocks.Count;
for (int i = 0; i < productBlocks.Count; i++)