item mng with sync
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Distribution.Features.Sync;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/sync")]
|
||||
[Authorize(Policy = "items.create")]
|
||||
public class SyncController(SyncService service) : ControllerBase
|
||||
{
|
||||
[HttpPost("uoms")]
|
||||
public async Task<IActionResult> SyncUoms(SyncUomsPayload payload, CancellationToken ct) =>
|
||||
Ok(await service.SyncUomsAsync(payload, ct));
|
||||
|
||||
[HttpPost("categories")]
|
||||
public async Task<IActionResult> SyncCategories(SyncCategoriesPayload payload, CancellationToken ct) =>
|
||||
Ok(await service.SyncCategoriesAsync(payload, ct));
|
||||
|
||||
[HttpPost("brands")]
|
||||
public async Task<IActionResult> SyncBrands(SyncBrandsPayload payload, CancellationToken ct) =>
|
||||
Ok(await service.SyncBrandsAsync(payload, ct));
|
||||
|
||||
[HttpPost("items")]
|
||||
public async Task<IActionResult> SyncItems(SyncItemsPayload payload, CancellationToken ct) =>
|
||||
Ok(await service.SyncItemsAsync(payload, ct));
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
namespace Distribution.Features.Sync;
|
||||
|
||||
public record SyncUomRequest(int ErpId, string Name);
|
||||
public record SyncUomsPayload(List<SyncUomRequest> Items);
|
||||
|
||||
public record SyncSubCategoryRequest(int ErpId, string Name, int ParentErpId);
|
||||
public record SyncCategoryRequest(int ErpId, string Name, List<SyncSubCategoryRequest> SubCategories);
|
||||
public record SyncCategoriesPayload(List<SyncCategoryRequest> Items);
|
||||
|
||||
public record SyncBrandRequest(int ErpId, string Name);
|
||||
public record SyncBrandsPayload(List<SyncBrandRequest> Items);
|
||||
|
||||
public record SyncItemRequest(
|
||||
int ErpId,
|
||||
string Sku,
|
||||
string Name,
|
||||
string? Description,
|
||||
int CategoryErpId,
|
||||
int? SubCategoryErpId,
|
||||
int? BrandErpId,
|
||||
int BaseUomErpId,
|
||||
decimal? SalePrice,
|
||||
bool IsActive);
|
||||
public record SyncItemsPayload(List<SyncItemRequest> Items);
|
||||
|
||||
public record SyncResult(int Inserted, int Updated, int Skipped);
|
||||
@@ -0,0 +1,186 @@
|
||||
using Distribution.Features.Brand;
|
||||
using Distribution.Features.Category;
|
||||
using Distribution.Features.Uom;
|
||||
using Distribution.Features.Item;
|
||||
using Distribution.Infra.UoW;
|
||||
|
||||
namespace Distribution.Features.Sync;
|
||||
|
||||
public class SyncService(
|
||||
ICategoryRepository categoryRepo,
|
||||
ISubCategoryRepository subCategoryRepo,
|
||||
IBrandRepository brandRepo,
|
||||
IUomRepository uomRepo,
|
||||
IItemRepository itemRepo,
|
||||
IUnitOfWork uow)
|
||||
{
|
||||
public async Task<SyncResult> SyncUomsAsync(SyncUomsPayload payload, CancellationToken ct = default)
|
||||
{
|
||||
int inserted = 0, updated = 0;
|
||||
await uow.BeginAsync(ct);
|
||||
try
|
||||
{
|
||||
foreach (var u in payload.Items)
|
||||
{
|
||||
var existing = await uomRepo.GetByExternalErpIdAsync(u.ErpId);
|
||||
if (existing is null)
|
||||
{
|
||||
await uomRepo.AddAsync(new Models.Uom { Name = u.Name, ExternalErpId = u.ErpId });
|
||||
inserted++;
|
||||
}
|
||||
else
|
||||
{
|
||||
existing.Name = u.Name;
|
||||
uomRepo.Update(existing);
|
||||
updated++;
|
||||
}
|
||||
}
|
||||
await uow.CommitAsync(ct);
|
||||
}
|
||||
catch { await uow.RollbackAsync(ct); throw; }
|
||||
return new SyncResult(inserted, updated, 0);
|
||||
}
|
||||
|
||||
public async Task<SyncResult> SyncCategoriesAsync(SyncCategoriesPayload payload, CancellationToken ct = default)
|
||||
{
|
||||
int inserted = 0, updated = 0;
|
||||
await uow.BeginAsync(ct);
|
||||
try
|
||||
{
|
||||
foreach (var c in payload.Items)
|
||||
{
|
||||
var existingCat = await categoryRepo.GetByExternalErpIdAsync(c.ErpId);
|
||||
Guid categoryId;
|
||||
if (existingCat is null)
|
||||
{
|
||||
var newCat = new Models.Category { Name = c.Name, ExternalErpId = c.ErpId };
|
||||
await categoryRepo.AddAsync(newCat);
|
||||
categoryId = newCat.Id;
|
||||
inserted++;
|
||||
}
|
||||
else
|
||||
{
|
||||
existingCat.Name = c.Name;
|
||||
categoryRepo.Update(existingCat);
|
||||
categoryId = existingCat.Id;
|
||||
updated++;
|
||||
}
|
||||
|
||||
foreach (var s in c.SubCategories)
|
||||
{
|
||||
var existingSub = await subCategoryRepo.GetByExternalErpIdAsync(s.ErpId);
|
||||
if (existingSub is null)
|
||||
{
|
||||
await subCategoryRepo.AddAsync(new Models.SubCategory
|
||||
{
|
||||
Name = s.Name,
|
||||
FK_CategoryId = categoryId,
|
||||
ExternalErpId = s.ErpId
|
||||
});
|
||||
inserted++;
|
||||
}
|
||||
else
|
||||
{
|
||||
existingSub.Name = s.Name;
|
||||
existingSub.FK_CategoryId = categoryId;
|
||||
subCategoryRepo.Update(existingSub);
|
||||
updated++;
|
||||
}
|
||||
}
|
||||
}
|
||||
await uow.CommitAsync(ct);
|
||||
}
|
||||
catch { await uow.RollbackAsync(ct); throw; }
|
||||
return new SyncResult(inserted, updated, 0);
|
||||
}
|
||||
|
||||
public async Task<SyncResult> SyncBrandsAsync(SyncBrandsPayload payload, CancellationToken ct = default)
|
||||
{
|
||||
int inserted = 0, updated = 0;
|
||||
await uow.BeginAsync(ct);
|
||||
try
|
||||
{
|
||||
foreach (var b in payload.Items)
|
||||
{
|
||||
var existing = await brandRepo.GetByExternalErpIdAsync(b.ErpId);
|
||||
if (existing is null)
|
||||
{
|
||||
await brandRepo.AddAsync(new Models.Brand { Name = b.Name, ExternalErpId = b.ErpId });
|
||||
inserted++;
|
||||
}
|
||||
else
|
||||
{
|
||||
existing.Name = b.Name;
|
||||
brandRepo.Update(existing);
|
||||
updated++;
|
||||
}
|
||||
}
|
||||
await uow.CommitAsync(ct);
|
||||
}
|
||||
catch { await uow.RollbackAsync(ct); throw; }
|
||||
return new SyncResult(inserted, updated, 0);
|
||||
}
|
||||
|
||||
public async Task<SyncResult> SyncItemsAsync(SyncItemsPayload payload, CancellationToken ct = default)
|
||||
{
|
||||
int inserted = 0, updated = 0, skipped = 0;
|
||||
await uow.BeginAsync(ct);
|
||||
try
|
||||
{
|
||||
foreach (var i in payload.Items)
|
||||
{
|
||||
var category = await categoryRepo.GetByExternalErpIdAsync(i.CategoryErpId);
|
||||
var baseUom = await uomRepo.GetByExternalErpIdAsync(i.BaseUomErpId);
|
||||
|
||||
if (category is null || baseUom is null) { skipped++; continue; }
|
||||
|
||||
Models.SubCategory? subCategory = null;
|
||||
if (i.SubCategoryErpId.HasValue)
|
||||
subCategory = await subCategoryRepo.GetByExternalErpIdAsync(i.SubCategoryErpId.Value);
|
||||
|
||||
Models.Brand? brand = null;
|
||||
if (i.BrandErpId.HasValue)
|
||||
brand = await brandRepo.GetByExternalErpIdAsync(i.BrandErpId.Value);
|
||||
|
||||
var existing = await itemRepo.GetByExternalErpItemIdAsync(i.ErpId);
|
||||
if (existing is null)
|
||||
{
|
||||
await itemRepo.AddAsync(new Models.Item
|
||||
{
|
||||
Sku = i.Sku,
|
||||
Name = i.Name,
|
||||
Description = i.Description,
|
||||
FK_CategoryId = category.Id,
|
||||
FK_SubCategoryId = subCategory?.Id,
|
||||
FK_BrandId = brand?.Id,
|
||||
FK_BaseUomId = baseUom.Id,
|
||||
SalePrice = i.SalePrice,
|
||||
IsActive = i.IsActive,
|
||||
SyncSource = Models.SyncSource.Erp,
|
||||
ExternalErpItemId = i.ErpId,
|
||||
LastSyncedAt = DateTime.UtcNow
|
||||
});
|
||||
inserted++;
|
||||
}
|
||||
else
|
||||
{
|
||||
existing.Sku = i.Sku;
|
||||
existing.Name = i.Name;
|
||||
existing.Description = i.Description;
|
||||
existing.FK_CategoryId = category.Id;
|
||||
existing.FK_SubCategoryId = subCategory?.Id;
|
||||
existing.FK_BrandId = brand?.Id;
|
||||
existing.FK_BaseUomId = baseUom.Id;
|
||||
existing.SalePrice = i.SalePrice;
|
||||
existing.IsActive = i.IsActive;
|
||||
existing.LastSyncedAt = DateTime.UtcNow;
|
||||
itemRepo.Update(existing);
|
||||
updated++;
|
||||
}
|
||||
}
|
||||
await uow.CommitAsync(ct);
|
||||
}
|
||||
catch { await uow.RollbackAsync(ct); throw; }
|
||||
return new SyncResult(inserted, updated, skipped);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user