[CLAUDE] Supplier: Excel-import Phase B (upload NCC preview/confirm) + Mig 63
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 5m25s
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 5m25s
Import Excel 'Database NCC': upload→preview classify (New/Update/Skip/Error)→confirm all-or-nothing upsert-by-Code (OrdinalIgnoreCase dedup, fill-nulls-safe). Mig 63 +SourceUpdatedAt/By (2 nullable). Parser layout-locked header-fingerprint NFC-normalized + absolute-cell-index + #REF!-null + NAS-backslash-raw. Type-lạ→NhaCungCap. FE dialog fe-admin+fe-user byte-identical. 10 test SupplierExcelImportServiceTests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using SolutionErp.Application.Common.Models;
|
||||
using SolutionErp.Application.Master.Suppliers.Commands.CreateSupplier;
|
||||
using SolutionErp.Application.Master.Suppliers.Commands.DeleteSupplier;
|
||||
using SolutionErp.Application.Master.Suppliers.Commands.ImportSuppliers;
|
||||
using SolutionErp.Application.Master.Suppliers.Commands.UpdateSupplier;
|
||||
using SolutionErp.Application.Master.Suppliers.Dtos;
|
||||
using SolutionErp.Application.Master.Suppliers.Queries.GetSupplier;
|
||||
@ -57,4 +58,25 @@ public class SuppliersController(IMediator mediator) : ControllerBase
|
||||
await mediator.Send(new DeleteSupplierCommand(id), ct);
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
// ========== Import Excel "Database NCC" (Supplier Phase B, Approach A — layout-locked) ==========
|
||||
// Preview: parse + phân loại từng hàng (KHÔNG ghi DB). Header sai layout → LayoutValid=false.
|
||||
[Authorize(Roles = "Admin,CatalogManager")]
|
||||
[HttpPost("import/preview")]
|
||||
[RequestSizeLimit(25_000_000)]
|
||||
public async Task<ActionResult<SupplierImportPreviewDto>> ImportPreview(IFormFile file, CancellationToken ct)
|
||||
{
|
||||
if (file is null || file.Length == 0)
|
||||
return BadRequest(new { detail = "Chưa chọn file." });
|
||||
await using var stream = file.OpenReadStream();
|
||||
return Ok(await mediator.Send(new SupplierImportPreviewCommand(stream), ct));
|
||||
}
|
||||
|
||||
// Confirm: ALL-OR-NOTHING upsert (New → insert; existing case-insensitive-Code → fill-nulls).
|
||||
// Body JSON = { "rows": [ ... ] } (mảng SupplierImportRowDto round-trip từ preview).
|
||||
[Authorize(Roles = "Admin,CatalogManager")]
|
||||
[HttpPost("import/confirm")]
|
||||
public async Task<ActionResult<SupplierImportResultDto>> ImportConfirm(
|
||||
[FromBody] SupplierImportConfirmCommand cmd, CancellationToken ct)
|
||||
=> Ok(await mediator.Send(cmd, ct));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user