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 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 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 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 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); } }