Feature: Human-Readable Text Format Product Import
Implemented a new text-based import format for bulk product imports that is easier to read, write, and version control compared to CSV format. ## New Features ### Import Service (ProductImportService.cs) - Added `ImportFromHumanTextAsync()` - Main text format parser - Added `GenerateTemplateAsHumanText()` - Template generator - Parser supports: - Product blocks starting with `#` - Descriptions between `<text>` tags (optional) - Key-value properties (category, price, weight, unit, stock) - Variants (lines starting with `-`) - Multi-buy offers (lines starting with `+`) - Variant collections (optional, after product name) ### Admin UI - New controller actions: - `ImportText()` - GET: Show import form - `ImportText(textContent, file)` - POST: Process import - `DownloadTextTemplate()` - Download .txt template - New view: `ImportText.cshtml` - Textarea for pasting text - File upload for .txt files - Format documentation sidebar - Links to CSV import and template downloads - Updated `Index.cshtml` with dropdown menu for import options ### Template & Documentation - Created `docs/ProductImportTemplate.txt` with 7 example products - Demonstrates all format features: - Products with/without descriptions - Variants with stock levels - Multi-buy pricing tiers - Multiple weight units ## Text Format Specification ``` # Product Name; OptionalVariantCollection <text> Multi-line description (optional) </text> category: CategoryName price: 10.00 weight: 100 unit: Grams stock: 50 - Variant1; 8.00; 50 - Variant2; 12.00; 30 + Multi-buy1; 2; 19.00 + Multi-buy2; 3; 25.00 ``` ## Benefits - ✅ Git-friendly (easy to diff and version) - ✅ Human-readable and editable - ✅ Supports all product features - ✅ Multi-line descriptions - ✅ Clear structure with # delimiters - ✅ Optional fields (description, variants, multi-buys) - ✅ Comprehensive error reporting 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -244,6 +244,58 @@ public class ProductsController : Controller
|
||||
return File(Encoding.UTF8.GetBytes(templateContent), "text/csv", fileName);
|
||||
}
|
||||
|
||||
// Human-Readable Text Format Import
|
||||
public IActionResult ImportText()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> ImportText(string textContent, IFormFile? file)
|
||||
{
|
||||
string importText = textContent;
|
||||
|
||||
// If file uploaded, use file content instead of textarea
|
||||
if (file != null && file.Length > 0)
|
||||
{
|
||||
if (!file.FileName.EndsWith(".txt", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
ModelState.AddModelError("", "Only .txt files are supported for text format import");
|
||||
return View();
|
||||
}
|
||||
|
||||
using var reader = new StreamReader(file.OpenReadStream());
|
||||
importText = await reader.ReadToEndAsync();
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(importText))
|
||||
{
|
||||
ModelState.AddModelError("", "Please provide text content or upload a .txt file");
|
||||
return View();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var result = await _importService.ImportFromHumanTextAsync(importText);
|
||||
ViewData["ImportResult"] = result;
|
||||
return View("ImportResult", result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ModelState.AddModelError("", $"Import failed: {ex.Message}");
|
||||
return View();
|
||||
}
|
||||
}
|
||||
|
||||
public IActionResult DownloadTextTemplate()
|
||||
{
|
||||
var templateContent = _importService.GenerateTemplateAsHumanText();
|
||||
var fileName = "product_import_template.txt";
|
||||
|
||||
return File(Encoding.UTF8.GetBytes(templateContent), "text/plain", fileName);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetVariantCollection(Guid id)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user