C# WPF desktop app for creating eBay UK listings with AI-powered photo analysis. Features: multi-photo vision analysis via OpenRouter (Claude), local listing save/export, saved listings browser, single item listing form, bulk import from CSV/Excel, and eBay OAuth authentication. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
101 lines
3.3 KiB
C#
101 lines
3.3 KiB
C#
using System.Globalization;
|
|
using ClosedXML.Excel;
|
|
using CsvHelper;
|
|
using CsvHelper.Configuration;
|
|
using EbayListingTool.Models;
|
|
|
|
namespace EbayListingTool.Services;
|
|
|
|
public class BulkImportService
|
|
{
|
|
public List<BulkImportRow> ImportFile(string filePath)
|
|
{
|
|
var ext = Path.GetExtension(filePath).ToLower();
|
|
return ext switch
|
|
{
|
|
".csv" => ImportCsv(filePath),
|
|
".xlsx" or ".xls" => ImportExcel(filePath),
|
|
_ => throw new NotSupportedException($"File type '{ext}' is not supported. Use .csv or .xlsx")
|
|
};
|
|
}
|
|
|
|
private List<BulkImportRow> ImportCsv(string filePath)
|
|
{
|
|
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
|
|
{
|
|
HasHeaderRecord = true,
|
|
MissingFieldFound = null,
|
|
HeaderValidated = null
|
|
};
|
|
|
|
using var reader = new StreamReader(filePath);
|
|
using var csv = new CsvReader(reader, config);
|
|
|
|
var rows = new List<BulkImportRow>();
|
|
csv.Read();
|
|
csv.ReadHeader();
|
|
|
|
while (csv.Read())
|
|
{
|
|
rows.Add(new BulkImportRow
|
|
{
|
|
Title = csv.TryGetField("Title", out string? t) ? t ?? "" : "",
|
|
Description = csv.TryGetField("Description", out string? d) ? d ?? "" : "",
|
|
Price = csv.TryGetField("Price", out string? p) ? p ?? "" : "",
|
|
Condition = csv.TryGetField("Condition", out string? c) ? c ?? "Used" : "Used",
|
|
CategoryKeyword = csv.TryGetField("CategoryKeyword", out string? k) ? k ?? "" : "",
|
|
Quantity = csv.TryGetField("Quantity", out string? q) ? q ?? "1" : "1",
|
|
PhotoPaths = csv.TryGetField("PhotoPaths", out string? ph) ? ph ?? "" : ""
|
|
});
|
|
}
|
|
|
|
return rows;
|
|
}
|
|
|
|
private List<BulkImportRow> ImportExcel(string filePath)
|
|
{
|
|
var rows = new List<BulkImportRow>();
|
|
|
|
using var workbook = new XLWorkbook(filePath);
|
|
var ws = workbook.Worksheets.First();
|
|
|
|
// Find header row (row 1)
|
|
var headers = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
|
var headerRow = ws.Row(1);
|
|
foreach (var cell in headerRow.CellsUsed())
|
|
headers[cell.GetString()] = cell.Address.ColumnNumber;
|
|
|
|
string GetValue(IXLRow row, string colName)
|
|
{
|
|
if (!headers.TryGetValue(colName, out var col)) return "";
|
|
return row.Cell(col).GetString().Trim();
|
|
}
|
|
|
|
int lastRow = ws.LastRowUsed()?.RowNumber() ?? 1;
|
|
for (int i = 2; i <= lastRow; i++)
|
|
{
|
|
var row = ws.Row(i);
|
|
if (row.IsEmpty()) continue;
|
|
|
|
rows.Add(new BulkImportRow
|
|
{
|
|
Title = GetValue(row, "Title"),
|
|
Description = GetValue(row, "Description"),
|
|
Price = GetValue(row, "Price"),
|
|
Condition = GetValue(row, "Condition").OrDefault("Used"),
|
|
CategoryKeyword = GetValue(row, "CategoryKeyword"),
|
|
Quantity = GetValue(row, "Quantity").OrDefault("1"),
|
|
PhotoPaths = GetValue(row, "PhotoPaths")
|
|
});
|
|
}
|
|
|
|
return rows;
|
|
}
|
|
}
|
|
|
|
internal static class StringExtensions
|
|
{
|
|
public static string OrDefault(this string value, string defaultValue)
|
|
=> string.IsNullOrWhiteSpace(value) ? defaultValue : value;
|
|
}
|