diff --git a/CPRNIMS.Domain/CPRNIMS.Domain.csproj b/CPRNIMS.Domain/CPRNIMS.Domain.csproj index ae1b559..85e4f86 100644 --- a/CPRNIMS.Domain/CPRNIMS.Domain.csproj +++ b/CPRNIMS.Domain/CPRNIMS.Domain.csproj @@ -7,6 +7,7 @@ + diff --git a/CPRNIMS.Domain/Contracts/Canvass/ICanvass.cs b/CPRNIMS.Domain/Contracts/Canvass/ICanvass.cs index 8f940ef..3c5a9fb 100644 --- a/CPRNIMS.Domain/Contracts/Canvass/ICanvass.cs +++ b/CPRNIMS.Domain/Contracts/Canvass/ICanvass.cs @@ -1,4 +1,7 @@ -using CPRNIMS.Infrastructure.Dto.Canvass; +using CPRNIMS.Domain.Services.ICanvass; +using CPRNIMS.Infrastructure.Dto.Canvass; +using CPRNIMS.Infrastructure.Dto.Canvass.Request; +using CPRNIMS.Infrastructure.Dto.Canvass.Response; using CPRNIMS.Infrastructure.Entities.Canvass; using CPRNIMS.Infrastructure.Entities.Purchasing; using System; @@ -9,46 +12,46 @@ using System.Threading.Tasks; namespace CPRNIMS.Domain.Contracts.Canvass { - public interface ICanvass + public interface ICanvass : ISupplier { #region Post Put Task PostPerSupplierToken(CanvassDto CanvassDto); Task PutSupplierCanvass(long canvassSupplierId); - Task PostCanvass(CanvassDto CanvassDto); - Task PostPutSupplier(CanvassDto CanvassDto); - Task PostTaggingSupplier(CanvassDto CanvassDto); - Task PostApprovedSupp(CanvassDto CanvassDto); + Task PostCanvass(CanvassDto CanvassDto); + Task PostPutSupplier(CanvassDto CanvassDto); + Task PostTaggingSupplier(CanvassDto CanvassDto); + Task PostApprovedSupp(CanvassDto CanvassDto); Task PostSuggestedSupp(CanvassDto CanvassDto); Task PutSuppUnitPrice(CanvassDto CanvassDto); Task PutSuppBidDetails(CanvassDto canvassDto); - Task PostPutMySupplier(CanvassDto canvassDto); - Task PostPutItemTagging(CanvassDto canvassDto); + Task PostPutMySupplier(CanvassDto canvassDto); + Task PostPutItemTagging(CanvassDto canvassDto); Task UnlockFormLink(CanvassDto canvassDto); #endregion #region Get - Task> GetCanvassById(CanvassDto CanvassDto); + Task> GetCanvassById(CanvassDto CanvassDto); Task> GetCanvassWOResponse(CanvassDto CanvassDto); Task> GetWOResponseBySuppId(CanvassDto CanvassDto); - Task> GetSupplierById(CanvassDto CanvassDto); + Task> GetSupplierById(CanvassDto CanvassDto); Task> GetRFQ(CanvassDto CanvassDto); Task> GetSupplierBid(CanvassDto CanvassDto); Task> GetSupplierBidByItem(CanvassDto CanvassDto); Task> GetSupplierBidById(CanvassDto CanvassDto); Task> GetCanvassPerSupplier(CanvassDto CanvassDto); - Task> GetCanvassPerSupplierEmail(CanvassDto CanvassDto); - Task> GetCanvassPerSupplierId(CanvassDto itemCodeDto); + Task> GetCanvassPerSupplierEmail(CanvassDto CanvassDto); + Task> GetCanvassPerSupplierId(CanvassDto itemCodeDto); Task> GetItemSupplierWOEmail(CanvassDto CanvassDto); - Task> GetSupplierItemWOEmail(CanvassDto CanvassDto); - Task> GetCanvassByPRNo(CanvassDto CanvassDto); + Task> GetSupplierItemWOEmail(CanvassDto CanvassDto); + Task> GetCanvassByPRNo(CanvassDto CanvassDto); Task> GetCanvassGroupByPRNo(CanvassDto CanvassDto); - Task> GetCanvassByItemNo(CanvassDto CanvassDto); - Task> GetPRItemList(CanvassDto CanvassDto); - Task> GetPRItem(CanvassDto CanvassDto); + Task> GetCanvassByItemNo(CanvassDto CanvassDto); + Task> GetPRItemList(CanvassDto CanvassDto); + Task> GetPRItem(CanvassDto CanvassDto); Task> GetPRListByPRNo(CanvassDto canvassDto); Task> GetForCanvassPerItem(CanvassDto CanvassDto); Task GetCanvassNo(); Task> GetCanvassForFollowUp(CanvassDto itemDto); - Task> GetMySuppliers(CanvassDto CanvassDto); + Task> GetMySuppliers(CanvassDto CanvassDto); Task> GetMyPRWOCanvass(CanvassDto itemDto); Task> GetAlternativeOfferByPRDetailId(CanvassDto itemDto); Task> GetAllForCanvass(); diff --git a/CPRNIMS.Domain/Contracts/Canvass/ISupplier.cs b/CPRNIMS.Domain/Contracts/Canvass/ISupplier.cs new file mode 100644 index 0000000..5596abc --- /dev/null +++ b/CPRNIMS.Domain/Contracts/Canvass/ISupplier.cs @@ -0,0 +1,19 @@ +using CPRNIMS.Infrastructure.Dto.Canvass.Request; +using CPRNIMS.Infrastructure.Dto.Canvass.Response; +using CPRNIMS.Infrastructure.Entities.Purchasing; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CPRNIMS.Domain.Services.ICanvass +{ + public interface ISupplier + { + Task> GetItemWithoutSupplier(); + Task> PostSupplierAsync(SupplierRequest request, CancellationToken ct); + Task SendRFQ(SupplierEmailRequest supplierEmailRequest); + Task SearchingUpdate(long pRDetailsId); + } +} diff --git a/CPRNIMS.Domain/Contracts/PR/IPRequest.cs b/CPRNIMS.Domain/Contracts/PR/IPRequest.cs index 9d5fe47..03bc34a 100644 --- a/CPRNIMS.Domain/Contracts/PR/IPRequest.cs +++ b/CPRNIMS.Domain/Contracts/PR/IPRequest.cs @@ -1,5 +1,6 @@ using CPRNIMS.Infrastructure.Dto.Items; using CPRNIMS.Infrastructure.Dto.PR; +using CPRNIMS.Infrastructure.Dto.PR.Response; using CPRNIMS.Infrastructure.Entities.Common; using CPRNIMS.Infrastructure.Entities.Purchasing; using CPRNIMS.Infrastructure.Entities.SMTP; @@ -36,11 +37,11 @@ namespace CPRNIMS.Domain.Contracts.PR Task> GetDeletedPR(PRDto pRDto); Task> GetApprovedPR(PRDto pRDto); Task PRItemRemoval(PRDto pRDto); - Task PostPRApproveReject(PRDto PRDto); - Task PostPutReceiving(PRDto PRDto); - Task PutPOClose(PRDto PRDto); - Task PutItemDetail(PRDto PRDto); - Task PostPutDeniedItem(PRDto PRDto); + Task PostPRApproveReject(PRDto PRDto); + Task PostPutReceiving(PRDto PRDto); + Task PutPOClose(PRDto PRDto); + Task PutItemDetail(PRDto PRDto); + Task PostPutDeniedItem(PRDto PRDto); Task PutSupplierAlterOffer(PRDto pRDto); Task PostPutProjectCode(PRDto prDto); Task PostItemInPR(PRDto dto); diff --git a/CPRNIMS.Domain/Profile/Canvass/SupplierRequestProfile.cs b/CPRNIMS.Domain/Profile/Canvass/SupplierRequestProfile.cs new file mode 100644 index 0000000..0b9c035 --- /dev/null +++ b/CPRNIMS.Domain/Profile/Canvass/SupplierRequestProfile.cs @@ -0,0 +1,28 @@ +using CPRNIMS.Infrastructure.Dto.Canvass.Request; +using CPRNIMS.Infrastructure.Dto.Canvass.Response; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using AutoMapper; +using CPRNIMS.Infrastructure.ViewModel.Common; +using CPRNIMS.Infrastructure.Entities.Canvass; + +namespace CPRNIMS.Domain.Profile.Canvass +{ + public class SupplierRequestProfile : AutoMapper.Profile + { + public SupplierRequestProfile() + { + // 1. THIS IS THE MISSING LINK: Request -> Entity + CreateMap(); + + // 2. Entity -> Response + CreateMap(); + + // 3. Response <-> Request (Use ReverseMap to handle both directions automatically) + CreateMap().ReverseMap(); + } + } +} diff --git a/CPRNIMS.Domain/Services/Canvass/Canvass.cs b/CPRNIMS.Domain/Services/Canvass/Canvass.cs index 8397baa..27311be 100644 --- a/CPRNIMS.Domain/Services/Canvass/Canvass.cs +++ b/CPRNIMS.Domain/Services/Canvass/Canvass.cs @@ -1,41 +1,43 @@ -using CPRNIMS.Domain.Contracts.Canvass; +using AutoMapper; +using Azure.Core; +using CPRNIMS.Domain.Services.ICanvass; using CPRNIMS.Infrastructure.Database; using CPRNIMS.Infrastructure.Dto.Canvass; +using CPRNIMS.Infrastructure.Dto.Canvass.Request; +using CPRNIMS.Infrastructure.Dto.Canvass.Response; using CPRNIMS.Infrastructure.Entities.Canvass; using CPRNIMS.Infrastructure.Entities.Purchasing; +using CPRNIMS.Infrastructure.Helper; +using CPRNIMS.Infrastructure.ViewModel.Common; using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; using System.Data; -using static CPRNIMS.Domain.Services.OutputParamMessage; -using System.Linq; using System.Text; using System.Threading.Tasks; +using static CPRNIMS.Domain.Services.OutputParamMessage; namespace CPRNIMS.Domain.Services.Canvass { - public class Canvass : ICanvass + public class Canvass : Contracts.Canvass.ICanvass { private readonly NonInventoryDbContext _dbContext; - public Canvass(NonInventoryDbContext dbContext) + private readonly SMTPHelper _smptHelper; + private readonly IMapper _mapper; + public Canvass(NonInventoryDbContext dbContext, SMTPHelper smptHelper,IMapper mapper) { _dbContext = dbContext; + _smptHelper = smptHelper; + _mapper = mapper; } #region Get public async Task> GetItemSupplierWOEmail(CanvassDto CanvassDto) { - try - { - var allItems = await _dbContext.ItemListWOEmails - .FromSqlRaw($"EXEC GetItemSupplierWOEmail @PRNo = '{CanvassDto.PRNo}'") - .ToListAsync(); + var allItems = await _dbContext.ItemListWOEmails + .FromSqlRaw($"EXEC GetItemSupplierWOEmail @PRNo = '{CanvassDto.PRNo}'") + .ToListAsync(); - return allItems ?? new List(); - } - catch (SqlException ex) - { - ex.ToString(); - throw; - } + return allItems ?? new List(); } public async Task> GetSupplierBid(CanvassDto CanvassDto) { @@ -49,20 +51,12 @@ namespace CPRNIMS.Domain.Services.Canvass } public async Task> GetCanvassPerSupplier(CanvassDto CanvassDto) { - try - { - var allItems = await _dbContext.PerSuppliers + var allItems = await _dbContext.PerSuppliers .FromSqlRaw($"EXEC GetCanvassPerSupplier @UserId", new SqlParameter("@UserId", CanvassDto.UserId)) .ToListAsync(); - return allItems ?? new List(); - } - catch (SqlException ex) - { - ex.ToString(); - throw; - } + return allItems ?? new List(); } public async Task> GetSupplierBidByItem(CanvassDto CanvassDto) { @@ -78,34 +72,34 @@ namespace CPRNIMS.Domain.Services.Canvass return allItems ?? new List(); } - public async Task> GetCanvassById(CanvassDto CanvassDto) + public async Task> GetCanvassById(CanvassDto CanvassDto) { - var allItems = await _dbContext.PRDetails + var allItems = await _dbContext.PRCanvassDetails .FromSqlRaw("EXEC GetCanvassById @UserId", new SqlParameter("@UserId", CanvassDto.UserId)) .ToListAsync(); - return allItems ?? new List(); + return allItems ?? new List(); } - public async Task> GetCanvassByItemNo(CanvassDto CanvassDto) + public async Task> GetCanvassByItemNo(CanvassDto CanvassDto) { - var allItems = await _dbContext.PRDetails + var allItems = await _dbContext.PRCanvassDetails .FromSqlRaw($"EXEC GetCanvassByItemNo @UserId, @ItemNo", new SqlParameter("@UserId", CanvassDto.UserId), new SqlParameter("@ItemNo", CanvassDto.ItemNo)) .ToListAsync(); - return allItems ?? new List(); + return allItems ?? new List(); } - public async Task> GetCanvassByPRNo(CanvassDto CanvassDto) + public async Task> GetCanvassByPRNo(CanvassDto CanvassDto) { - var allItems = await _dbContext.PRDetails + var allItems = await _dbContext.PRCanvassDetails .FromSqlRaw("EXEC GetCanvassByPRNo @UserId, @PRNo", new SqlParameter("@UserId", CanvassDto.UserId), new SqlParameter("@PRNo", CanvassDto.PRNo)) .ToListAsync(); - return allItems ?? new List(); + return allItems ?? new List(); } public async Task> GetCanvassGroupByPRNo(CanvassDto CanvassDto) { @@ -119,215 +113,132 @@ namespace CPRNIMS.Domain.Services.Canvass return allItems ?? new List(); } - public async Task> GetSupplierItemWOEmail(CanvassDto CanvassDto) + public async Task> GetSupplierItemWOEmail(CanvassDto canvassDto) { - try - { - var allItems = await _dbContext.Suppliers - .FromSqlRaw($"EXEC GetSupplierItemWOEmail @ItemNo = '{CanvassDto.ItemNo}'") + // 1. Use Interpolated string to prevent SQL injection and pass the parameter safely + var suppliers = await _dbContext.Suppliers + .FromSqlInterpolated($"EXEC GetSupplierItemWOEmail @ItemNo = {canvassDto.ItemNo}") .ToListAsync(); - return allItems ?? new List(); - } - catch (SqlException ex) - { - ex.ToString(); - throw; - } + // 2. Map the List of entities to a List of Response objects + // AutoMapper handles collections automatically if the types are configured + return _mapper.Map>(suppliers); } - public async Task> GetSupplierById(CanvassDto CanvassDto) - { - try - { - var allItems = await _dbContext.Suppliers - .FromSqlRaw($"EXEC GetSupplierById @SupplierId", - new SqlParameter("@SupplierId", CanvassDto.SupplierId)) - .ToListAsync(); - return allItems ?? new List(); - } - catch (SqlException ex) - { - ex.ToString(); - throw; - } + public async Task> GetSupplierById(CanvassDto CanvassDto) + { + var item = await _dbContext.Suppliers + .FromSqlRaw($"EXEC GetSupplierById @SupplierId", + new SqlParameter("@SupplierId", CanvassDto.SupplierId)) + .ToListAsync(); + // 2. Map the List of entities to a List of Response objects + // AutoMapper handles collections automatically if the types are configured + return _mapper.Map>(item); } public async Task> GetRFQ(CanvassDto CanvassDto) { - try - { - var allItems = await _dbContext.RFQReferences - .FromSqlRaw($"EXEC GetRFQPerSupplier @SupplierId,@UserId", - new SqlParameter("@SupplierId", CanvassDto.SupplierId), - new SqlParameter("@UserId", CanvassDto.UserId)) - .ToListAsync(); + var allItems = await _dbContext.RFQReferences + .FromSqlRaw($"EXEC GetRFQPerSupplier @SupplierId,@UserId", + new SqlParameter("@SupplierId", CanvassDto.SupplierId), + new SqlParameter("@UserId", CanvassDto.UserId)) + .ToListAsync(); - return allItems ?? new List(); - } - catch (SqlException ex) - { - ex.ToString(); - throw; - } + return allItems ?? new List(); } - public async Task> GetPRItemList(CanvassDto CanvassDto) + public async Task> GetPRItemList(CanvassDto CanvassDto) { - try - { - var allItems = await _dbContext.PRDetails + var allItems = await _dbContext.PRCanvassDetails .FromSqlRaw($"EXEC GetPRItemList @UserId = '{CanvassDto.UserId}'") .ToListAsync(); - return allItems ?? new List(); - } - catch (SqlException ex) - { - ex.ToString(); - throw; - } + return allItems ?? new List(); } - public async Task> GetCanvassPerSupplierEmail(CanvassDto CanvassDto) + public async Task> GetCanvassPerSupplierEmail(CanvassDto CanvassDto) { - try - { - var allItems = await _dbContext.PRDetails - .FromSqlRaw($"EXEC GetCanvassPerSupplierEmail @UserId = '{CanvassDto.UserId}', @EmailAddress = '{CanvassDto.EmailAddress}'") - .ToListAsync(); + var allItems = await _dbContext.PRCanvassDetails + .FromSqlRaw($"EXEC GetCanvassPerSupplierEmail @UserId = '{CanvassDto.UserId}', @EmailAddress = '{CanvassDto.EmailAddress}'") + .ToListAsync(); - return allItems ?? new List(); - } - catch (SqlException ex) - { - ex.ToString(); - throw; - } + return allItems ?? new List(); } - public async Task> GetPRItem(CanvassDto CanvassDto) + public async Task> GetPRItem(CanvassDto CanvassDto) { - try - { - var allItems = await _dbContext.PRDetails - .FromSqlRaw($"EXEC GetPRItem @UserId = '{CanvassDto.UserId}', @ItemNo = {CanvassDto.ItemNo}") - .ToListAsync(); + var allItems = await _dbContext.PRCanvassDetails + .FromSqlRaw($"EXEC GetPRItem @UserId = '{CanvassDto.UserId}', @ItemNo = {CanvassDto.ItemNo}") + .ToListAsync(); - return allItems ?? new List(); - } - catch (SqlException ex) - { - ex.ToString(); - throw; - } + return allItems ?? new List(); } public async Task> GetCanvassWOResponse(CanvassDto CanvassDto) { - try - { - var allItems = await _dbContext.WOResponses - .FromSqlRaw($"EXEC GetCanvassWOResponse @UserId = '{CanvassDto.UserId}'") - .ToListAsync(); + var allItems = await _dbContext.WOResponses + .FromSqlRaw($"EXEC GetCanvassWOResponse @UserId = '{CanvassDto.UserId}'") + .ToListAsync(); - return allItems ?? new List(); - } - catch (SqlException ex) - { - ex.ToString(); - throw; - } + return allItems ?? new List(); } public async Task GetCanvassNo() { - try - { - var latestCanvassNo = await _dbContext.Canvasses - .OrderByDescending(ic => ic.CanvassNo) - .FirstOrDefaultAsync(); + var latestCanvassNo = await _dbContext.Canvasses + .OrderByDescending(ic => ic.CanvassNo) + .FirstOrDefaultAsync(); - if (latestCanvassNo != null) - { - return latestCanvassNo.CanvassNo; - } - else - { - return 0; - } - } - catch (SqlException ex) + if (latestCanvassNo != null) { - ex.ToString(); - throw; + return latestCanvassNo.CanvassNo; } + else + { + return 0; + } + } + public async Task> GetItemWithoutSupplier() + { + var allItems = await _dbContext.ItemWithoutSuppliers + .FromSqlRaw("EXEC GetItemWithoutSupplier") + .ToListAsync(); + + return allItems ?? new List(); } public async Task> GetWOResponseBySuppId(CanvassDto CanvassDto) { - try - { - var allItems = await _dbContext.WOResponseByIds - .FromSqlRaw($"EXEC GetWOResponseBySuppId @UserId = '{CanvassDto.UserId}',@SupplierId = '{CanvassDto.SupplierId}'") - .ToListAsync(); + var allItems = await _dbContext.WOResponseByIds + .FromSqlRaw($"EXEC GetWOResponseBySuppId @UserId = '{CanvassDto.UserId}',@SupplierId = '{CanvassDto.SupplierId}'") + .ToListAsync(); - return allItems ?? new List(); - } - catch (SqlException ex) - { - ex.ToString(); - throw; - } + return allItems ?? new List(); } public async Task PostPerSupplierToken(CanvassDto CanvassDto) { - try - { - await _dbContext.Database - .ExecuteSqlRawAsync("EXEC PostPerSupplierToken @UserId,@SupplierId,@PRNo,@ItemNo,@CanvassNo,@PRDetailsId", - new SqlParameter("@UserId", CanvassDto.UserId), - new SqlParameter("@SupplierId", CanvassDto.SupplierId), - new SqlParameter("@PRNo", CanvassDto.PRNo), - new SqlParameter("@ItemNo", CanvassDto.ItemNo), - new SqlParameter("@CanvassNo", CanvassDto.CanvassNo), - new SqlParameter("@PRDetailsId", CanvassDto.PRDetailsId)); + await _dbContext.Database + .ExecuteSqlRawAsync("EXEC PostPerSupplierToken @UserId,@SupplierId,@PRNo,@ItemNo,@CanvassNo,@PRDetailsId", + new SqlParameter("@UserId", CanvassDto.UserId), + new SqlParameter("@SupplierId", CanvassDto.SupplierId), + new SqlParameter("@PRNo", CanvassDto.PRNo), + new SqlParameter("@ItemNo", CanvassDto.ItemNo), + new SqlParameter("@CanvassNo", CanvassDto.CanvassNo), + new SqlParameter("@PRDetailsId", CanvassDto.PRDetailsId)); - return new RFQ(); - } - catch (SqlException ex) - { - ex.ToString(); - throw; - } + return new RFQ(); } public async Task> GetSupplierBidById(CanvassDto CanvassDto) { - try - { - var allItems = await _dbContext.SupplierBidByIds - .FromSqlRaw($"EXEC GetSupplierBidById @CanvassDetailId", - new SqlParameter("@CanvassDetailId", CanvassDto.CanvassDetailId)) - .ToListAsync(); + var allItems = await _dbContext.SupplierBidByIds + .FromSqlRaw($"EXEC GetSupplierBidById @CanvassDetailId", + new SqlParameter("@CanvassDetailId", CanvassDto.CanvassDetailId)) + .ToListAsync(); - return allItems ?? new List(); - } - catch (SqlException ex) - { - ex.ToString(); - throw; - } + return allItems ?? new List(); } - public async Task> GetMySuppliers(CanvassDto CanvassDto) + public async Task> GetMySuppliers(CanvassDto CanvassDto) { - try - { - var allItems = await _dbContext.Suppliers - .FromSqlRaw($"EXEC GetMySuppliers @UserId,@SupplierId", - new SqlParameter("@UserId", CanvassDto.UserId), - new SqlParameter("@SupplierId", CanvassDto.SupplierId)) - .ToListAsync(); + var items = await _dbContext.Suppliers + .FromSqlRaw($"EXEC GetMySuppliers @UserId,@SupplierId", + new SqlParameter("@UserId", CanvassDto.UserId), + new SqlParameter("@SupplierId", CanvassDto.SupplierId)) + .ToListAsync(); - return allItems ?? new List(); - } - catch (SqlException ex) - { - ex.ToString(); - throw; - } + return _mapper.Map>(items); } public async Task> GetMyPRWOCanvass(CanvassDto itemDto) { @@ -352,15 +263,15 @@ namespace CPRNIMS.Domain.Services.Canvass return allItems ?? new List(); } - public async Task> GetCanvassPerSupplierId(CanvassDto itemCodeDto) + public async Task> GetCanvassPerSupplierId(CanvassDto itemCodeDto) { - var allItems = await _dbContext.PRDetails + var allItems = await _dbContext.PRCanvassDetails .FromSqlRaw($"EXEC GetCanvassPerSupplierId @UserId,@SupplierId", new SqlParameter("@UserId", itemCodeDto.UserId), new SqlParameter("@SupplierId", itemCodeDto.SupplierId)) .ToListAsync(); - return allItems ?? new List(); + return allItems ?? new List(); } public async Task> @@ -400,225 +311,212 @@ namespace CPRNIMS.Domain.Services.Canvass } #endregion #region Post Put - public async Task PostApprovedSupp(CanvassDto CanvassDto) + public async Task> PostSupplierAsync(SupplierRequest request, CancellationToken ct) { - try - { - await _dbContext.Database - .ExecuteSqlRawAsync("EXEC PostApprovedSupp @UserId,@CanvassId,@ItemNo", - new SqlParameter("@UserId", CanvassDto.UserId), - new SqlParameter("@CanvassId", CanvassDto.CanvassId != null ? CanvassDto.CanvassId : 0L), - new SqlParameter("@ItemNo", CanvassDto.ItemNo != null ? CanvassDto.ItemNo : 0L)); + var strategy = _dbContext.Database.CreateExecutionStrategy(); - return new Suppliers(); - } - catch (SqlException ex) + return await strategy.ExecuteAsync(async () => { - throw; + await using var transaction = await _dbContext.Database.BeginTransactionAsync(ct); + + try + { + var supplier = await _dbContext.Suppliers + .FirstOrDefaultAsync(s => s.SupplierName == request.SupplierName, ct); + + if (supplier == null) + { + supplier = _mapper.Map(request); + await _dbContext.AddAsync(supplier, ct); + await _dbContext.SaveChangesAsync(ct); + } + + await PostSupplierItems(supplier.SupplierId, request.ItemNo, ct); + + await _dbContext.SaveChangesAsync(ct); + + await transaction.CommitAsync(ct); + + return Result.Success(_mapper.Map(supplier)); + } + catch (DbUpdateException ex) + { + await transaction.RollbackAsync(ct); + + // handle unique constraint violation here if needed + throw; + } + }); + } + private async Task PostSupplierItems(int supplierId, long itemNo, CancellationToken ct) + { + var exists = await _dbContext.SupplierItems.AnyAsync( + s => s.SupplierId == supplierId && s.ItemNo == itemNo && s.IsActive, + ct); + + if (!exists) + { + await _dbContext.SupplierItems.AddAsync(new SupplierItems + { + SupplierId = supplierId, + ItemNo = itemNo, + IsActive = true + }, ct); } } + public async Task PostApprovedSupp(CanvassDto CanvassDto) + { + await _dbContext.Database + .ExecuteSqlRawAsync("EXEC PostApprovedSupp @UserId,@CanvassId,@ItemNo", + new SqlParameter("@UserId", CanvassDto.UserId), + new SqlParameter("@CanvassId", CanvassDto.CanvassId != null ? CanvassDto.CanvassId : 0L), + new SqlParameter("@ItemNo", CanvassDto.ItemNo != null ? CanvassDto.ItemNo : 0L)); + + return new SupplierResponse(); + } public async Task PostSuggestedSupp(CanvassDto CanvassDto) { - try - { - await _dbContext.Database - .ExecuteSqlRawAsync("EXEC PostSuggestedSupp @UserId,@CanvassDetailId,@ItemNo,@SupplierId,@CanvassId", - new SqlParameter("@UserId", CanvassDto.UserId), - new SqlParameter("@CanvassDetailId", CanvassDto.CanvassDetailId), - new SqlParameter("@ItemNo", CanvassDto.ItemNo), - new SqlParameter("@SupplierId", CanvassDto.SupplierId), - new SqlParameter("@CanvassId", CanvassDto.CanvassId)); - return new CanvassDetail(); - } - catch (SqlException ex) - { - throw; - } + await _dbContext.Database + .ExecuteSqlRawAsync("EXEC PostSuggestedSupp @UserId,@CanvassDetailId,@ItemNo,@SupplierId,@CanvassId", + new SqlParameter("@UserId", CanvassDto.UserId), + new SqlParameter("@CanvassDetailId", CanvassDto.CanvassDetailId), + new SqlParameter("@ItemNo", CanvassDto.ItemNo), + new SqlParameter("@SupplierId", CanvassDto.SupplierId), + new SqlParameter("@CanvassId", CanvassDto.CanvassId)); + return new CanvassDetail(); } - public async Task PostCanvass(CanvassDto CanvassDto) + public async Task PostCanvass(CanvassDto CanvassDto) { - try - { - await _dbContext.Database - .ExecuteSqlRawAsync("EXEC PostCanvass @UserId, @SupplierId, @Status,@Remarks", - new SqlParameter("@SupplierId", CanvassDto.SupplierId != null ? CanvassDto.SupplierId : 0L), - new SqlParameter("@UserId", CanvassDto.UserId), - new SqlParameter("@Status", CanvassDto.Status), - new SqlParameter("@Remarks", CanvassDto.Remarks ?? "N/A")); - return new PRDetails(); - } - catch (SqlException ex) - { - ex.ToString(); - throw; - } + await _dbContext.Database + .ExecuteSqlRawAsync("EXEC PostCanvass @UserId, @SupplierId, @Status,@Remarks", + new SqlParameter("@SupplierId", CanvassDto.SupplierId != null ? CanvassDto.SupplierId : 0L), + new SqlParameter("@UserId", CanvassDto.UserId), + new SqlParameter("@Status", CanvassDto.Status), + new SqlParameter("@Remarks", CanvassDto.Remarks ?? "N/A")); + return new PRCanvassDetail(); } - public async Task PostTaggingSupplier(CanvassDto CanvassDto) + public async Task PostTaggingSupplier(CanvassDto CanvassDto) { - try - { - var (messCode, message) = CreateOutputParams(); + var (messCode, message) = CreateOutputParams(); - await _dbContext.Database - .ExecuteSqlRawAsync($"EXEC PostPutSupplier @SupplierId, @ItemNo, @IsActive, @UserId, @SupplierName, " + - "@EmailAddress, @Address, @ContactNo, @ContactPerson,@IsTagging, @MessCode OUTPUT, @Message OUTPUT", - new SqlParameter("@SupplierId", CanvassDto.SupplierId != null ? CanvassDto.SupplierId : 0L), - new SqlParameter("@ItemNo", CanvassDto.ItemNo), - new SqlParameter("@IsActive", CanvassDto.IsActive), - new SqlParameter("@UserId", CanvassDto.UserId), - new SqlParameter("@SupplierName", CanvassDto.SupplierName), - new SqlParameter("@EmailAddress", CanvassDto.EmailAddress), - new SqlParameter("@Address", CanvassDto.Address ?? "NONE"), - new SqlParameter("@ContactNo", CanvassDto.ContactNo ?? "NONE"), - new SqlParameter("@ContactPerson", CanvassDto.ContactPerson ?? "NONE"), - new SqlParameter("@IsTagging", CanvassDto.IsTagging), - messCode, - message); + await _dbContext.Database + .ExecuteSqlRawAsync($"EXEC PostPutSupplier @SupplierId, @ItemNo, @IsActive, @UserId, @SupplierName, " + + "@EmailAddress, @Address, @ContactNo, @ContactPerson,@IsTagging, @MessCode OUTPUT, @Message OUTPUT", + new SqlParameter("@SupplierId", CanvassDto.SupplierId != null ? CanvassDto.SupplierId : 0L), + new SqlParameter("@ItemNo", CanvassDto.ItemNo), + new SqlParameter("@IsActive", CanvassDto.IsActive), + new SqlParameter("@UserId", CanvassDto.UserId), + new SqlParameter("@SupplierName", CanvassDto.SupplierName), + new SqlParameter("@EmailAddress", CanvassDto.EmailAddress), + new SqlParameter("@Address", CanvassDto.Address ?? "NONE"), + new SqlParameter("@ContactNo", CanvassDto.ContactNo ?? "NONE"), + new SqlParameter("@ContactPerson", CanvassDto.ContactPerson ?? "NONE"), + new SqlParameter("@IsTagging", CanvassDto.IsTagging), + messCode, + message); - if ((byte)messCode.Value == 0) - { - throw new Exception(message.Value.ToString()); - } - return new Suppliers(); - } - catch (SqlException ex) + if ((byte)messCode.Value == 0) { - throw; + throw new Exception(message.Value.ToString()); } + return new SupplierResponse(); } - public async Task PostPutItemTagging(CanvassDto canvassDto) + public async Task PostPutItemTagging(CanvassDto canvassDto) { - try - { - var (messCode, message) = CreateOutputParams(); + var (messCode, message) = CreateOutputParams(); - await _dbContext.Database - .ExecuteSqlRawAsync($"EXEC PostPutItemTagging @SupplierId, @ItemNo, @IsActive, @UserId," + - "@MessCode OUTPUT, @Message OUTPUT", - new SqlParameter("@SupplierId", canvassDto.SupplierId != null ? canvassDto.SupplierId : 0L), - new SqlParameter("@ItemNo", canvassDto.ItemNo), - new SqlParameter("@IsActive", canvassDto.IsActive), - new SqlParameter("@UserId", canvassDto.UserId), - messCode, - message); + await _dbContext.Database + .ExecuteSqlRawAsync($"EXEC PostPutItemTagging @SupplierId, @ItemNo, @IsActive, @UserId," + + "@MessCode OUTPUT, @Message OUTPUT", + new SqlParameter("@SupplierId", canvassDto.SupplierId != null ? canvassDto.SupplierId : 0L), + new SqlParameter("@ItemNo", canvassDto.ItemNo), + new SqlParameter("@IsActive", canvassDto.IsActive), + new SqlParameter("@UserId", canvassDto.UserId), + messCode, + message); - if ((byte)messCode.Value == 0) - { - throw new Exception(message.Value.ToString()); - } - return new Suppliers(); - } - catch (SqlException ex) + if ((byte)messCode.Value == 0) { - throw; + throw new Exception(message.Value.ToString()); } + return new SupplierResponse(); } - public async Task PostPutSupplier(CanvassDto CanvassDto) + public async Task PostPutSupplier(CanvassDto CanvassDto) { - try + var messCode = new SqlParameter("@MessCode", SqlDbType.TinyInt) { Direction = ParameterDirection.Output }; + var message = new SqlParameter("@Message", SqlDbType.VarChar, 8000) { Direction = ParameterDirection.Output }; + + await _dbContext.Database + .ExecuteSqlRawAsync($"EXEC PostPutSupplier @SupplierId, @ItemNo, @IsActive, @UserId, @SupplierName, " + + "@EmailAddress, @Address, @ContactNo, @ContactPerson,@IsTagging, @MessCode OUTPUT, @Message OUTPUT", + new SqlParameter("@SupplierId", CanvassDto.SupplierId != null ? CanvassDto.SupplierId : 0L), + new SqlParameter("@ItemNo", CanvassDto.ItemNo), + new SqlParameter("@IsActive", CanvassDto.IsActive), + new SqlParameter("@UserId", CanvassDto.UserId), + new SqlParameter("@SupplierName", CanvassDto.SupplierName), + new SqlParameter("@EmailAddress", CanvassDto.EmailAddress), + new SqlParameter("@Address", CanvassDto.Address ?? "NONE"), + new SqlParameter("@ContactNo", CanvassDto.ContactNo ?? "NONE"), + new SqlParameter("@ContactPerson", CanvassDto.ContactPerson ?? "NONE"), + new SqlParameter("@IsTagging", CanvassDto.IsTagging), + messCode, + message); + + if ((byte)messCode.Value == 0) { - var messCode = new SqlParameter("@MessCode", SqlDbType.TinyInt) { Direction = ParameterDirection.Output }; - var message = new SqlParameter("@Message", SqlDbType.VarChar, 8000) { Direction = ParameterDirection.Output }; - - await _dbContext.Database - .ExecuteSqlRawAsync($"EXEC PostPutSupplier @SupplierId, @ItemNo, @IsActive, @UserId, @SupplierName, " + - "@EmailAddress, @Address, @ContactNo, @ContactPerson,@IsTagging, @MessCode OUTPUT, @Message OUTPUT", - new SqlParameter("@SupplierId", CanvassDto.SupplierId != null ? CanvassDto.SupplierId : 0L), - new SqlParameter("@ItemNo", CanvassDto.ItemNo), - new SqlParameter("@IsActive", CanvassDto.IsActive), - new SqlParameter("@UserId", CanvassDto.UserId), - new SqlParameter("@SupplierName", CanvassDto.SupplierName), - new SqlParameter("@EmailAddress", CanvassDto.EmailAddress), - new SqlParameter("@Address", CanvassDto.Address ?? "NONE"), - new SqlParameter("@ContactNo", CanvassDto.ContactNo ?? "NONE"), - new SqlParameter("@ContactPerson", CanvassDto.ContactPerson ?? "NONE"), - new SqlParameter("@IsTagging", CanvassDto.IsTagging), - messCode, - message); - - if ((byte)messCode.Value == 0) - { - throw new Exception(message.Value.ToString()); - } - - return new Suppliers(); - } - catch (SqlException ex) - { - throw; + throw new Exception(message.Value.ToString()); } + + return new SupplierResponse(); } - public async Task PostPutMySupplier(CanvassDto canvassDto) + public async Task PostPutMySupplier(CanvassDto canvassDto) { - try + var messCode = new SqlParameter("@MessCode", SqlDbType.TinyInt) { Direction = ParameterDirection.Output }; + var message = new SqlParameter("@Message", SqlDbType.VarChar, 8000) { Direction = ParameterDirection.Output }; + + await _dbContext.Database + .ExecuteSqlRawAsync($"EXEC PostPutMySupplier @SupplierId, @ItemNo, @IsActive, @UserId, @SupplierName," + + "@EmailAddress, @Address, @ContactNo, @ContactPerson,@TinNo,@LeadTime,@CurrencyId,@VatInc,@PaymentTermsId," + + "@MessCode OUTPUT, @Message OUTPUT", + new SqlParameter("@SupplierId", canvassDto.SupplierId != null ? canvassDto.SupplierId : 0L), + new SqlParameter("@ItemNo", canvassDto.ItemNo), + new SqlParameter("@IsActive", canvassDto.IsActive), + new SqlParameter("@UserId", canvassDto.UserId), + new SqlParameter("@SupplierName", canvassDto.SupplierName), + new SqlParameter("@EmailAddress", canvassDto.EmailAddress), + new SqlParameter("@Address", canvassDto.Address ?? "NONE"), + new SqlParameter("@ContactNo", canvassDto.ContactNo ?? "NONE"), + new SqlParameter("@ContactPerson", canvassDto.ContactPerson ?? "NONE"), + new SqlParameter("@TinNo", canvassDto.TinNo ?? "NONE"), + new SqlParameter("@LeadTime", canvassDto.LeadTime ?? "NONE"), + new SqlParameter("@CurrencyId", canvassDto.CurrencyId), + new SqlParameter("@VatInc", canvassDto.VatInc), + new SqlParameter("@PaymentTermsId", canvassDto.PaymentTermsId), + messCode, + message); + + if ((byte)messCode.Value == 0) { - var messCode = new SqlParameter("@MessCode", SqlDbType.TinyInt) { Direction = ParameterDirection.Output }; - var message = new SqlParameter("@Message", SqlDbType.VarChar, 8000) { Direction = ParameterDirection.Output }; - - await _dbContext.Database - .ExecuteSqlRawAsync($"EXEC PostPutMySupplier @SupplierId, @ItemNo, @IsActive, @UserId, @SupplierName," + - "@EmailAddress, @Address, @ContactNo, @ContactPerson,@TinNo,@LeadTime,@CurrencyId,@VatInc,@PaymentTermsId," + - "@MessCode OUTPUT, @Message OUTPUT", - new SqlParameter("@SupplierId", canvassDto.SupplierId != null ? canvassDto.SupplierId : 0L), - new SqlParameter("@ItemNo", canvassDto.ItemNo), - new SqlParameter("@IsActive", canvassDto.IsActive), - new SqlParameter("@UserId", canvassDto.UserId), - new SqlParameter("@SupplierName", canvassDto.SupplierName), - new SqlParameter("@EmailAddress", canvassDto.EmailAddress), - new SqlParameter("@Address", canvassDto.Address ?? "NONE"), - new SqlParameter("@ContactNo", canvassDto.ContactNo ?? "NONE"), - new SqlParameter("@ContactPerson", canvassDto.ContactPerson ?? "NONE"), - new SqlParameter("@TinNo", canvassDto.TinNo ?? "NONE"), - new SqlParameter("@LeadTime", canvassDto.LeadTime ?? "NONE"), - new SqlParameter("@CurrencyId", canvassDto.CurrencyId), - new SqlParameter("@VatInc", canvassDto.VatInc), - new SqlParameter("@PaymentTermsId", canvassDto.PaymentTermsId), - messCode, - message); - - if ((byte)messCode.Value == 0) - { - throw new Exception(message.Value.ToString()); - } - - return new Suppliers(); - } - catch (SqlException ex) - { - throw; + throw new Exception(message.Value.ToString()); } + + return new SupplierResponse(); } public async Task PutSuppUnitPrice(CanvassDto CanvassDto) { - try - { - await _dbContext.Database - .ExecuteSqlRawAsync($"EXEC PutSuppUnitPrice @UserId, @CanvassDetailId, @UnitPrice", - new SqlParameter("@CanvassDetailId", CanvassDto.CanvassDetailId != null ? CanvassDto.CanvassDetailId : 0L), - new SqlParameter("@UserId", CanvassDto.UserId), - new SqlParameter("@UnitPrice", CanvassDto.UnitPrice)); - return new CanvassDetail(); - } - catch (SqlException ex) - { - ex.ToString(); - throw; - } + await _dbContext.Database + .ExecuteSqlRawAsync($"EXEC PutSuppUnitPrice @UserId, @CanvassDetailId, @UnitPrice", + new SqlParameter("@CanvassDetailId", CanvassDto.CanvassDetailId != null ? CanvassDto.CanvassDetailId : 0L), + new SqlParameter("@UserId", CanvassDto.UserId), + new SqlParameter("@UnitPrice", CanvassDto.UnitPrice)); + return new CanvassDetail(); } public async Task PutSupplierCanvass(long canvassSupplierId) { - try - { - await _dbContext.Database - .ExecuteSqlRawAsync("EXEC PutCanvassForFollowUp @CanvassSupplierId", - new SqlParameter("@CanvassSupplierId", canvassSupplierId)); - return new ForCanvassFollowUp(); - } - catch (SqlException ex) - { - ex.ToString(); - throw; - } + await _dbContext.Database + .ExecuteSqlRawAsync("EXEC PutCanvassForFollowUp @CanvassSupplierId", + new SqlParameter("@CanvassSupplierId", canvassSupplierId)); + return new ForCanvassFollowUp(); } public async Task PutSuppBidDetails(CanvassDto canvassDto) { @@ -649,6 +547,61 @@ namespace CPRNIMS.Domain.Services.Canvass new SqlParameter("@CanvassSupplierId", canvassDto.CanvassSupplierId)); return new CanvassSupplier(); } + + public async Task SendRFQ(SupplierEmailRequest supplierEmailRequest) + { + var baseTemplate = EMailTemplate("Content\\SMTPEmailContent", "SendToSupplier.cshtml"); + + var message = new StringBuilder(baseTemplate); + + message.Replace("@ViewBag.FormLink", Convert.ToString(supplierEmailRequest.FormLink + supplierEmailRequest.Token)); + message.Replace("@ViewBag.Supplier", supplierEmailRequest.SupplierName); + message.Replace("@ViewBag.Signature", supplierEmailRequest.Purchaser); + + var messageDetails = new EmailMessageDetailsVM + { + Recipient = supplierEmailRequest.Recipient, + Message = message.ToString(), + Subject = supplierEmailRequest.Subject, + CC = supplierEmailRequest.CC, + IsSuccess = supplierEmailRequest.IsSuccess, + SenderEmail = supplierEmailRequest.UserName, + DisplayName = "llipurchasing.com", + NewPassword = supplierEmailRequest.Password, + OutGoingPort = supplierEmailRequest.OutGoingPort, + Server = supplierEmailRequest.Server, + UserName = supplierEmailRequest.UserName, + IsCanvass= supplierEmailRequest.IsCanvass, + AttachPath=supplierEmailRequest.AttachPath + }; + + await _smptHelper.SendEmailAsync(messageDetails); + } + public string EMailTemplate(string relativePath, string emailTemplate) + { + string basePath = AppContext.BaseDirectory; + string templateFolderPath = Path.Combine(basePath, relativePath); + string templateFilePath = Path.Combine(templateFolderPath, emailTemplate); + + if (System.IO.File.Exists(templateFilePath)) + { + return System.IO.File.ReadAllText(templateFilePath); + } + else + { + Console.WriteLine($"File not found: {templateFilePath}"); + return "Template file not found"; + } + } + + public async Task SearchingUpdate(long pRDetailsId) + { + var rowsAffected = await _dbContext.PRDetails + .Where(p => p.PRDetailsId == pRDetailsId) + .ExecuteUpdateAsync(s => s.SetProperty(p => p.IsSearched, true)); + + return rowsAffected > 0; + } #endregion } } diff --git a/CPRNIMS.Domain/Services/Canvass/SupplierSearchService.cs b/CPRNIMS.Domain/Services/Canvass/SupplierSearchService.cs new file mode 100644 index 0000000..5bbf3ba --- /dev/null +++ b/CPRNIMS.Domain/Services/Canvass/SupplierSearchService.cs @@ -0,0 +1,231 @@ +using CPRNIMS.Infrastructure.Dto.Canvass.Response; +using CPRNIMS.Infrastructure.Dto.Canvass.Result; +using Microsoft.Extensions.Configuration; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace CPRNIMS.Domain.Services.Canvass +{ + public class SupplierSearchService + { + private readonly HttpClient _httpClient; + private readonly IConfiguration _config; + + // Common contact page suffixes to try + private static readonly string[] ContactPaths = + { "/contact", "/contact-us", "/pages/contact-us", "/about/contact", "/about" }; + + public SupplierSearchService(HttpClient httpClient, IConfiguration config) + { + _httpClient = httpClient; + _config = config; + } + + public async Task> SearchAndFilterSuppliersAsync( + string itemName, string itemDescription) + { + // Step 1: Tavily — get supplier URLs + var (searchContent, supplierUrls) = await SearchTavilyAsync(itemName, itemDescription); + + // Step 2: Fetch contact pages from discovered URLs + var contactContent = await FetchContactPagesAsync(supplierUrls); + + // Step 3: Combine search + contact content, send to Groq + var combined = searchContent + " CONTACT_PAGES_DATA: " + contactContent; + var suppliers = await FilterWithGroqAsync(itemName, itemDescription, combined); + + return suppliers; + } + + // ── Tavily ────────────────────────────────────────────────────────────── + private async Task<(string content, List urls)> SearchTavilyAsync( + string itemName, string itemDescription) + { + var query = $"{itemName} {itemDescription} suppliers Philippines budget price contact email phone"; + + var payload = new + { + query, + max_results = 10, + search_depth = "advanced", + include_answer = false + }; + + var request = new HttpRequestMessage(HttpMethod.Post, _config["Tavily:SearchUrl"]); + request.Headers.Add("Authorization", $"Bearer {_config["Tavily:ApiKey"]}"); + request.Content = new StringContent( + JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json"); + + var response = await _httpClient.SendAsync(request); + response.EnsureSuccessStatusCode(); + + var body = await response.Content.ReadAsStringAsync(); + var result = JsonSerializer.Deserialize(body, + new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); + + var sb = new StringBuilder(); + var urls = new List(); + int i = 1; + + foreach (var r in result?.Results ?? new()) + { + // Clean text + var clean = Regex.Replace(r.Content ?? "", @"[^\x20-\x7E]", " "); + clean = Regex.Replace(clean, @"\s{3,}", " "); + if (clean.Length > 300) clean = clean[..300]; + sb.Append($"{i}. Title:{r.Title}|URL:{r.Url}|Content:{clean}|"); + + // Collect base domain URLs for contact page fetching + try + { + var uri = new Uri(r.Url); + var baseUrl = $"{uri.Scheme}://{uri.Host}"; + if (!urls.Contains(baseUrl)) urls.Add(baseUrl); + } + catch { } + i++; + } + + var fullText = sb.ToString(); + if (fullText.Length > 2000) fullText = fullText[..2000]; + + return (fullText, urls); + } + + // ── Fetch Contact Pages ────────────────────────────────────────────────── + private async Task FetchContactPagesAsync(List baseUrls) + { + var sb = new StringBuilder(); + // Limit to top 5 domains to avoid timeout + foreach (var baseUrl in baseUrls.Take(5)) + { + foreach (var path in ContactPaths) + { + try + { + var url = baseUrl + path; + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); + var resp = await _httpClient.GetAsync(url, cts.Token); + + if (!resp.IsSuccessStatusCode) continue; + + var html = await resp.Content.ReadAsStringAsync(); + + // Strip HTML tags + var text = Regex.Replace(html, @"<[^>]+>", " "); + text = Regex.Replace(text, @"[^\x20-\x7E]", " "); + text = Regex.Replace(text, @"\s{3,}", " "); + + // Extract only lines with contact signals + var contactLines = text.Split(' ', StringSplitOptions.RemoveEmptyEntries) + .Where(w => w.Contains("@") + || Regex.IsMatch(w, @"\+?[\d\-\(\)]{7,}") + || w.Contains("email") + || w.Contains("phone") + || w.Contains("contact") + || w.Contains("mobile") + || w.Contains("tel")) + .Take(50); + + var contactText = string.Join(" ", contactLines); + if (!string.IsNullOrWhiteSpace(contactText)) + { + sb.Append($"[{baseUrl}]: {contactText} | "); + break; // Found contact page for this domain, move to next + } + } + catch { /* timeout or unreachable — skip */ } + } + } + + return sb.Length > 2000 ? sb.ToString()[..2000] : sb.ToString(); + } + + // ── Groq ───────────────────────────────────────────────────────────────── + private async Task> FilterWithGroqAsync( + string itemName, string itemDescription, string searchContent) + { + var prompt = $"Extract top 10 unique suppliers for: {itemName} {itemDescription}. " + + "Prioritize Philippines suppliers first. " + + "IMPORTANT: Look carefully in CONTACT_PAGES_DATA section for real phone numbers and emails. " + + "Extract exact email addresses and phone numbers found. " + + "For domains without contact data found, infer email as sales@domain or info@domain. " + + "Prefer budget-friendly suppliers. No duplicates. " + + "Return ONLY a raw JSON array: company_name, country, phone_number, contact_email, website, estimated_price_usd, item_specifications. " + + $"Null for missing. JSON array only. Data: {searchContent}"; + + var payload = new + { + model = _config["Groq:Model"] ?? "llama-3.1-8b-instant", + stream = false, + max_tokens = 2048, + temperature = 0.1, + messages = new[] + { + new { role = "system", content = "You are a supplier data extractor. Extract real contact details from provided content. Return ONLY a valid JSON array, no markdown, no explanation." }, + new { role = "user", content = prompt } + } + }; + + var request = new HttpRequestMessage(HttpMethod.Post, _config["Groq:ApiUrl"]); + request.Headers.Add("Authorization", $"Bearer {_config["Groq:ApiKey"]}"); + request.Content = new StringContent( + JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json"); + + var response = await _httpClient.SendAsync(request); + response.EnsureSuccessStatusCode(); + + var body = await response.Content.ReadAsStringAsync(); + var groqResp = JsonSerializer.Deserialize(body, + new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); + + var rawText = groqResp?.Choices?[0]?.Message?.Content ?? string.Empty; + + var match = Regex.Match(rawText, @"\[[\s\S]*\]"); + if (!match.Success) return new List(); + + var groqList = JsonSerializer.Deserialize>(match.Value, + new JsonSerializerOptions { PropertyNameCaseInsensitive = true }) + ?? new List(); + + var seen = new HashSet(StringComparer.OrdinalIgnoreCase); + var suppliers = new List(); + + foreach (var s in groqList) + { + var key = (s.CompanyName ?? "").Trim().ToLower(); + if (string.IsNullOrEmpty(key) || seen.Contains(key)) continue; + seen.Add(key); + + if (string.IsNullOrEmpty(s.ContactEmail)) continue; + + suppliers.Add(new SupplierResponse + { + SupplierName = s.CompanyName, + EmailAddress = s.ContactEmail, + ContactNo = s.PhoneNumber ?? string.Empty, + Address = s.Country ?? string.Empty, + IsActive = true, + VatInc = false, + Currency = "PHP", + CurrencyId = 1, + PaymentTermsId = 1, + PaymentTerms = "30 Days", + LeadTime = "7-14 Days", + TinNo = string.Empty, + ContactPerson = string.Empty, + Website =s.Website ?? string.Empty, + }); + + if (suppliers.Count >= 10) break; + } + + return suppliers; + } + } +} diff --git a/CPRNIMS.Domain/Services/PR/PRequest.cs b/CPRNIMS.Domain/Services/PR/PRequest.cs index 4dc50eb..1278e83 100644 --- a/CPRNIMS.Domain/Services/PR/PRequest.cs +++ b/CPRNIMS.Domain/Services/PR/PRequest.cs @@ -2,6 +2,7 @@ using CPRNIMS.Infrastructure.Database; using CPRNIMS.Infrastructure.Dto.Items; using CPRNIMS.Infrastructure.Dto.PR; +using CPRNIMS.Infrastructure.Dto.PR.Response; using CPRNIMS.Infrastructure.Entities.Common; using CPRNIMS.Infrastructure.Entities.Purchasing; using CPRNIMS.Infrastructure.Entities.SMTP; @@ -309,7 +310,7 @@ namespace CPRNIMS.Domain.Services.PR PRNo = reader["PRNo"] as long? ?? 0, NewPRNo = reader["NewPRNo"]?.ToString(), AggreItemName = reader["AggreItemName"]?.ToString(), - CreatedDate = reader["NewPRNo"] as DateTime? ?? DateTime.UtcNow, + CreatedDate = reader["CreatedDate"] as DateTime? ?? DateTime.UtcNow, DateNeeded = reader["DateNeeded"] as DateTime? ?? DateTime.UtcNow, CreatedBy = reader["CreatedBy"]?.ToString(), Department = reader["Department"]?.ToString(), @@ -545,7 +546,7 @@ namespace CPRNIMS.Domain.Services.PR } #endregion #region Post Put - public async Task PostPRApproveReject(PRDto PRDto) + public async Task PostPRApproveReject(PRDto PRDto) { await _dbContext.Database .ExecuteSqlRawAsync("EXEC PostPRApproveReject @UserId, @ItemNo, @Status, @PRDetailsId, @Remarks", @@ -554,9 +555,9 @@ namespace CPRNIMS.Domain.Services.PR new SqlParameter("@Status", PRDto.Status), new SqlParameter("@PRDetailsId", PRDto.PRDetailsId), new SqlParameter("@Remarks", PRDto.Remarks ?? "N/A")); - return new PRDetails(); + return new PRResponse(); } - public async Task PutItemDetail(PRDto PRDto) + public async Task PutItemDetail(PRDto PRDto) { await _dbContext.Database .ExecuteSqlRawAsync($"EXEC PutPRItemDetail @UserId, @ItemLocalId, @UOMId, @ItemColorId," + @@ -571,18 +572,18 @@ namespace CPRNIMS.Domain.Services.PR new SqlParameter("@Remarks", PRDto.Remarks), new SqlParameter("@ItemName", PRDto.ItemName), new SqlParameter("@ItemDescription", PRDto.ItemDescription)); - return new PRDetails(); + return new PRResponse(); } - public async Task PostPutDeniedItem(PRDto PRDto) + public async Task PostPutDeniedItem(PRDto PRDto) { await _dbContext.Database .ExecuteSqlRawAsync("EXEC PostPutDeniedItem @UserId,@PRDetailsId,@Remarks", new SqlParameter("@UserId", PRDto.UserId), new SqlParameter("@PRDetailsId", PRDto.PRDetailsId), new SqlParameter("@Remarks", PRDto.Remarks ?? "N/A")); - return new PRDetails(); + return new PRResponse(); } - public async Task PostPutReceiving(PRDto PRDto) + public async Task PostPutReceiving(PRDto PRDto) { await _dbContext.Database .ExecuteSqlRawAsync($"EXEC PostPutReceiving @UserId, @PONo, @POTypeId, @EmailAddress, @DRNo, @DocTypeId, @QuantityReceived,@RRNo,@PRDetailsId,@Remarks,@ReceivedDate,@IsCompleted", @@ -598,9 +599,9 @@ namespace CPRNIMS.Domain.Services.PR new SqlParameter("@Remarks", PRDto.Remarks ?? "N/A"), new SqlParameter("@ReceivedDate", PRDto.ReceivedDate), new SqlParameter("@IsCompleted", PRDto.IsCompleted)); - return new PRDetails(); + return new PRResponse(); } - public async Task PutPOClose(PRDto PRDto) + public async Task PutPOClose(PRDto PRDto) { await _dbContext.Database .ExecuteSqlRawAsync("EXEC PutPOClose @UserId, @PONo, @POTypeId, @EmailAddress,@PRDetailsId,@DocTypeId,@PRNo,@Remarks", @@ -612,7 +613,7 @@ namespace CPRNIMS.Domain.Services.PR new SqlParameter("@PRDetailsId", PRDto.PRDetailsId), new SqlParameter("@PRNo", PRDto.PRNo), new SqlParameter("@Remarks", PRDto.Remarks ?? "N/A")); - return new PRDetails(); + return new PRResponse(); } public async Task PutSupplierAlterOffer(PRDto pRDto) { diff --git a/CPRNIMS.Domain/Services/Receiving/Receiving.cs b/CPRNIMS.Domain/Services/Receiving/Receiving.cs index d36c15c..37ed0c8 100644 --- a/CPRNIMS.Domain/Services/Receiving/Receiving.cs +++ b/CPRNIMS.Domain/Services/Receiving/Receiving.cs @@ -23,113 +23,65 @@ namespace CPRNIMS.Domain.Services.Receiving #region Get public async Task> GetRRReport(ItemDto itemDto) { - try + if (!itemDto.IsSorting) { - if (!itemDto.IsSorting) - { - itemDto.DateFrom = DateTime.Today; - itemDto.DateTo = DateTime.Today.AddDays(1).AddSeconds(-1); - } - - var allItems = await _dbContext.RRReports - .FromSqlRaw($"EXEC GetRRReport @DateFrom,@DateTo,@IsSorting", - new SqlParameter("@DateFrom", itemDto.DateFrom), - new SqlParameter("@DateTo", itemDto.DateTo), - new SqlParameter("@IsSorting", itemDto.IsSorting)) - .ToListAsync(); - - return allItems ?? new List(); - } - catch (SqlException ex) - { - ex.ToString(); - throw; + itemDto.DateFrom = DateTime.Today; + itemDto.DateTo = DateTime.Today.AddDays(1).AddSeconds(-1); } + + var allItems = await _dbContext.RRReports + .FromSqlRaw($"EXEC GetRRReport @DateFrom,@DateTo,@IsSorting", + new SqlParameter("@DateFrom", itemDto.DateFrom), + new SqlParameter("@DateTo", itemDto.DateTo), + new SqlParameter("@IsSorting", itemDto.IsSorting)) + .ToListAsync(); + + return allItems ?? new List(); } public async Task> GetForReceiving(ItemDto itemDto) { - try - { - var allItems = await _dbContext.ForReceivings - .FromSqlRaw($"EXEC GetForReceiving @UserId,@IsDenied", - new SqlParameter("@UserId", itemDto.UserId), - new SqlParameter("@IsDenied", itemDto.IsDenied)) - .ToListAsync(); + var allItems = await _dbContext.ForReceivings + .FromSqlRaw($"EXEC GetForReceiving @UserId,@IsDenied", + new SqlParameter("@UserId", itemDto.UserId), + new SqlParameter("@IsDenied", itemDto.IsDenied)) + .ToListAsync(); - return allItems ?? new List(); - } - catch (SqlException ex) - { - ex.ToString(); - throw; - } + return allItems ?? new List(); } public async Task> GetRR(ItemDto itemDto) { - try - { - var allItems = await _dbContext.RRs + var allItems = await _dbContext.RRs .FromSqlRaw($"EXEC GetRR @UserId", new SqlParameter("@UserId", itemDto.UserId)) .ToListAsync(); - return allItems ?? new List(); - } - catch (SqlException ex) - { - ex.ToString(); - throw; - } + return allItems ?? new List(); } public async Task> GetLatestRRNo(ItemDto itemDto) { - try - { - return await _dbContext.RRSeries.FromSqlRaw("EXEC GetLatestRRNo @UserId", - new SqlParameter("@UserId",itemDto.UserId)).ToListAsync(); - } - catch (Exception) - { - - throw; - } + return await _dbContext.RRSeries.FromSqlRaw("EXEC GetLatestRRNo @UserId", + new SqlParameter("@UserId", itemDto.UserId)).ToListAsync(); } public async Task> GetRRDetailByPO(ItemDto itemDto) { - try - { - var allItems = await _dbContext.ReceivingDetails - .FromSqlRaw($"EXEC GetRRDetailByPO @PONo,@POTypeId,@UserId", - new SqlParameter("@PONo", itemDto.PONo), - new SqlParameter("@POTypeId", itemDto.POTypeId), - new SqlParameter("@UserId", itemDto.UserId)) - .ToListAsync(); + var allItems = await _dbContext.ReceivingDetails + .FromSqlRaw($"EXEC GetRRDetailByPO @PONo,@POTypeId,@UserId", + new SqlParameter("@PONo", itemDto.PONo), + new SqlParameter("@POTypeId", itemDto.POTypeId), + new SqlParameter("@UserId", itemDto.UserId)) + .ToListAsync(); - return allItems ?? new List(); - } - catch (SqlException ex) - { - ex.ToString(); - throw; - } + return allItems ?? new List(); } public async Task> GetRRDetail(ItemDto itemDto) { - try - { - var allItems = await _dbContext.RRDetailss - .FromSqlRaw($"EXEC GetRRDetail @RRNo,@UserId", + var allItems = await _dbContext.RRDetailss + .FromSqlRaw("EXEC GetRRDetail @RRNo,@UserId", new SqlParameter("@RRNo", itemDto.RRNo), new SqlParameter("@UserId", itemDto.UserId)) .ToListAsync(); - return allItems ?? new List(); - } - catch (SqlException ex) - { - ex.ToString(); - throw; - } + return allItems ?? new List(); } #endregion #region Post Put diff --git a/CPRNIMS.Domain/Services/Result.cs b/CPRNIMS.Domain/Services/Result.cs new file mode 100644 index 0000000..3e510e4 --- /dev/null +++ b/CPRNIMS.Domain/Services/Result.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CPRNIMS.Domain.Services +{ + public class Result + { + public bool IsSuccess { get; set; } + public string? Error { get; set; } + public T? Value { get; set; } + private Result(bool isSuccess, T? value, string? error) + { + IsSuccess = isSuccess; + Error = error; + Value = value; + } + public static Result Success(T value) + => new Result(true, value, null); + public static Result Failure(string? error) + => new Result(false, default, error); + } +} diff --git a/CPRNIMS.Infrastructure/CPRNIMS.Infrastructure.csproj b/CPRNIMS.Infrastructure/CPRNIMS.Infrastructure.csproj index 4598bfa..f3e0c5a 100644 --- a/CPRNIMS.Infrastructure/CPRNIMS.Infrastructure.csproj +++ b/CPRNIMS.Infrastructure/CPRNIMS.Infrastructure.csproj @@ -23,4 +23,8 @@ + + + + diff --git a/CPRNIMS.Infrastructure/Database/NonInventoryDbContext.cs b/CPRNIMS.Infrastructure/Database/NonInventoryDbContext.cs index e9964bd..ebc2bdb 100644 --- a/CPRNIMS.Infrastructure/Database/NonInventoryDbContext.cs +++ b/CPRNIMS.Infrastructure/Database/NonInventoryDbContext.cs @@ -65,6 +65,7 @@ namespace CPRNIMS.Infrastructure.Database public virtual DbSet ForRRs { get; set; } public virtual DbSet RRs { get; set; } public virtual DbSet Canvasses { get; set; } + public DbSet SupplierItems { get; set; } public virtual DbSet ForCanvassFollowUps { get; set; } public virtual DbSet WOResponses { get; set; } public virtual DbSet WOResponseByIds { get; set; } @@ -78,6 +79,7 @@ namespace CPRNIMS.Infrastructure.Database public virtual DbSet CanvassSuppliers { get; set; } public virtual DbSet RFQReferences { get; set; } public virtual DbSet CanvassDetails { get; set; } + public virtual DbSet PRCanvassDetails { get; set; } public virtual DbSet CanvassGroupByPRNos { get; set; } public virtual DbSet ForCanvasses { get; set; } public virtual DbSet ForPOs { get; set; } @@ -122,6 +124,7 @@ namespace CPRNIMS.Infrastructure.Database #region Automation Part public virtual DbSet AllForCanvasses { get; set; } + public DbSet ItemWithoutSuppliers { get; set; } public DbSet ErrorLogs { get; set; } #endregion protected override void OnModelCreating(ModelBuilder modelBuilder) @@ -150,6 +153,11 @@ namespace CPRNIMS.Infrastructure.Database b.ToTable("PRPOSummaryItem"); b.HasNoKey(); }); + modelBuilder.Entity(b => + { + b.ToTable("RR"); + b.HasNoKey(); + }); modelBuilder.Entity(b => { b.ToTable("Users"); diff --git a/CPRNIMS.Infrastructure/Dto/Canvass/Request/SearchSupplierRequest.cs b/CPRNIMS.Infrastructure/Dto/Canvass/Request/SearchSupplierRequest.cs new file mode 100644 index 0000000..29ea1d1 --- /dev/null +++ b/CPRNIMS.Infrastructure/Dto/Canvass/Request/SearchSupplierRequest.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CPRNIMS.Infrastructure.Dto.Canvass.Request +{ + public class SearchSupplierRequest + { + public long PRDetailsId { get; set; } + public long PRNo { get; set; } + public long ItemNo { get; set; } + public string ItemName { get; set; } = string.Empty; + public string ItemDescription { get; set; } = string.Empty; + public string FullName { get; set; } = string.Empty; + } +} diff --git a/CPRNIMS.Infrastructure/Dto/Canvass/Request/SupplierEmailRequest.cs b/CPRNIMS.Infrastructure/Dto/Canvass/Request/SupplierEmailRequest.cs new file mode 100644 index 0000000..c047705 --- /dev/null +++ b/CPRNIMS.Infrastructure/Dto/Canvass/Request/SupplierEmailRequest.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CPRNIMS.Infrastructure.Dto.Canvass.Request +{ + public class SupplierEmailRequest + { + public string Subject { get; set; } = string.Empty; + public string SenderEmail { get; set; } = string.Empty; + public string Recipient { get; set; } = string.Empty; + public string DisplayName { get; set; } = string.Empty; + public int OutGoingPort { get; set; } = 587; + public string Password { get; set; } = string.Empty; + public string Token { get; set; } = string.Empty; + public string Server { get; set; } = string.Empty; + public string CC { get; set; } = string.Empty; + public bool IsCanvass { get; set; } + public string Purchaser { get; set; }=string.Empty; + public string UserName { get; set; } = string.Empty; + public string FormLink { get; set; } = string.Empty; + public string EmailAddress { get; set; } = string.Empty; + public string SupplierName { get; set; } = string.Empty; + public bool IsSuccess { get; set; } + public string AttachPath { get; set; } = string.Empty; + } +} diff --git a/CPRNIMS.Infrastructure/Dto/Canvass/Request/SupplierRequest.cs b/CPRNIMS.Infrastructure/Dto/Canvass/Request/SupplierRequest.cs new file mode 100644 index 0000000..eb477b4 --- /dev/null +++ b/CPRNIMS.Infrastructure/Dto/Canvass/Request/SupplierRequest.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CPRNIMS.Infrastructure.Dto.Canvass.Request +{ + public class SupplierRequest + { + public string SupplierName { get; set; } = string.Empty; + public string EmailAddress { get; set; } = string.Empty; + public bool IsActive { get; set; } = true; + public string ContactNo { get; set; } = string.Empty; + public string ContactPerson { get; set; } = string.Empty; + public string LeadTime { get; set; } = string.Empty; + public bool IsVatable { get; set; } = false; + public byte PaymentTermsId { get; set; } = 1; + public byte CurrencyId { get; set; } = 1; + public string TinNo { get; set; } = string.Empty; + public string Address { get; set; } = string.Empty; + public long ItemNo { get; set; } = 0; + public string Website { get; set; } = string.Empty; + } +} diff --git a/CPRNIMS.Infrastructure/Dto/Canvass/Response/SearchSupplierResponse.cs b/CPRNIMS.Infrastructure/Dto/Canvass/Response/SearchSupplierResponse.cs new file mode 100644 index 0000000..ee070a2 --- /dev/null +++ b/CPRNIMS.Infrastructure/Dto/Canvass/Response/SearchSupplierResponse.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CPRNIMS.Infrastructure.Dto.Canvass.Response +{ + public class SearchSupplierResponse + { + } +} diff --git a/CPRNIMS.Infrastructure/Dto/Canvass/Response/SupplierResponse.cs b/CPRNIMS.Infrastructure/Dto/Canvass/Response/SupplierResponse.cs new file mode 100644 index 0000000..b394a14 --- /dev/null +++ b/CPRNIMS.Infrastructure/Dto/Canvass/Response/SupplierResponse.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CPRNIMS.Infrastructure.Dto.Canvass.Response +{ + public class SupplierResponse + { + public int SupplierId { get; set; } + public string SupplierName { get; set; } = string.Empty; + public string EmailAddress { get; set; } = string.Empty; + public bool IsActive { get; set; } = true; + public string ContactNo { get; set; } = string.Empty; + public string ContactPerson { get; set; } = string.Empty; + public string LeadTime { get; set; } = string.Empty; + public bool VatInc { get; set; } = false; + public string Currency { get; set; } = string.Empty; + public string PaymentTerms { get; set; } = string.Empty; + public byte PaymentTermsId { get; set; } = 1; + public byte CurrencyId { get; set; } = 1; + public string TinNo { get; set; } = string.Empty; + public string Address { get; set; } = string.Empty; + public string Website { get; set; } = string.Empty; + } +} diff --git a/CPRNIMS.Infrastructure/Dto/Canvass/Result/GroqSupplierResult.cs b/CPRNIMS.Infrastructure/Dto/Canvass/Result/GroqSupplierResult.cs new file mode 100644 index 0000000..bda468b --- /dev/null +++ b/CPRNIMS.Infrastructure/Dto/Canvass/Result/GroqSupplierResult.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +namespace CPRNIMS.Infrastructure.Dto.Canvass.Result +{ + public class GroqSupplierResult + { + [JsonPropertyName("company_name")] + public string CompanyName { get; set; } = string.Empty; + + [JsonPropertyName("country")] + public string? Country { get; set; } + + [JsonPropertyName("phone_number")] + public string? PhoneNumber { get; set; } + + [JsonPropertyName("contact_email")] + public string? ContactEmail { get; set; } + + [JsonPropertyName("website")] + public string? Website { get; set; } + + [JsonPropertyName("source")] + public string? Source { get; set; } + + [JsonPropertyName("estimated_price_usd")] + public decimal? EstimatedPriceUsd { get; set; } + + [JsonPropertyName("item_specifications")] + public JsonElement? ItemSpecifications { get; set; } + } + public class TavilySearchResult + { + public List Results { get; set; } = new(); + } + + public class TavilyResult + { + public string Title { get; set; } = string.Empty; + public string Url { get; set; } = string.Empty; + public string Content { get; set; } = string.Empty; + public double Score { get; set; } + } + + public class GroqResponse + { + public List Choices { get; set; } = new(); + } + + public class GroqChoice + { + public GroqMessage Message { get; set; } = new(); + } + + public class GroqMessage + { + public string Content { get; set; } = string.Empty; + } +} diff --git a/CPRNIMS.Infrastructure/Dto/PR/Response/PRResponse.cs b/CPRNIMS.Infrastructure/Dto/PR/Response/PRResponse.cs new file mode 100644 index 0000000..a0e0f67 --- /dev/null +++ b/CPRNIMS.Infrastructure/Dto/PR/Response/PRResponse.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CPRNIMS.Infrastructure.Dto.PR.Response +{ + public class PRResponse + { + [Key] + public long PRDetailsId { get; set; } + public long ItemCodeId { get; set; } + public short ItemClassId { get; set; } + public string? Department { get; set; } + public string? ItemCategoryName { get; set; } + public string? UserId { get; set; } + public string? ItemName { get; set; } + public decimal TotalAmount { get; set; } + public string? ItemDescription { get; set; } + public short Status { get; set; } + public string? StatusName { get; set; } + public bool IsActive { get; set; } + public long ItemNo { get; set; } + public string? ItemLocalName { get; set; } + public decimal Qty { get; set; } + public string? NewPRNo { get; set; } + public string? ItemClassName { get; set; } + public string? UOMName { get; set; } + public string? ItemColorName { get; set; } + public string? ItemAttachPath { get; set; } + public long PRNo { get; set; } + public string? Remarks { get; set; } + public DateTime DateNeeded { get; set; } + } +} diff --git a/CPRNIMS.Infrastructure/Entities/Canvass/PRCanvassDetail.cs b/CPRNIMS.Infrastructure/Entities/Canvass/PRCanvassDetail.cs new file mode 100644 index 0000000..6cd9f04 --- /dev/null +++ b/CPRNIMS.Infrastructure/Entities/Canvass/PRCanvassDetail.cs @@ -0,0 +1,38 @@ +using CPRNIMS.Infrastructure.Entities.Common; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CPRNIMS.Infrastructure.Entities.Canvass +{ + public class PRCanvassDetail : CommonProperties + { + [Key] + public long PRDetailsId { get; set; } + public long ItemCodeId { get; set; } + public short ItemClassId { get; set; } + public string? Department { get; set; } + public string? ItemCategoryName { get; set; } + public string? UserId { get; set; } + public string? ItemName { get; set; } + public decimal TotalAmount { get; set; } + public string? ItemDescription { get; set; } + public short Status { get; set; } + public string? StatusName { get; set; } + public bool IsActive { get; set; } + public long ItemNo { get; set; } + public string? ItemLocalName { get; set; } + public decimal Qty { get; set; } + public string? NewPRNo { get; set; } + public string? ItemClassName { get; set; } + public string? UOMName { get; set; } + public string? ItemColorName { get; set; } + public string? ItemAttachPath { get; set; } + public long PRNo { get; set; } + public string? Remarks { get; set; } + public DateTime DateNeeded { get; set; } + } +} diff --git a/CPRNIMS.Infrastructure/Entities/Canvass/SupplierItems.cs b/CPRNIMS.Infrastructure/Entities/Canvass/SupplierItems.cs new file mode 100644 index 0000000..3822937 --- /dev/null +++ b/CPRNIMS.Infrastructure/Entities/Canvass/SupplierItems.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CPRNIMS.Infrastructure.Entities.Canvass +{ + [Table("SupplierItems")] + public class SupplierItems + { + [Key] + public long SupplierItemId { get; set; } + public int SupplierId { get; set; } + public long ItemNo { get; set; } + public bool IsActive { get; set; } + + } +} diff --git a/CPRNIMS.Infrastructure/Entities/Canvass/Suppliers.cs b/CPRNIMS.Infrastructure/Entities/Canvass/Suppliers.cs index 3e3f0da..3ce01f9 100644 --- a/CPRNIMS.Infrastructure/Entities/Canvass/Suppliers.cs +++ b/CPRNIMS.Infrastructure/Entities/Canvass/Suppliers.cs @@ -13,18 +13,17 @@ namespace CPRNIMS.Infrastructure.Entities.Canvass { [Key] public int SupplierId { get; set; } - public string? SupplierName { get; set; } - public string? EmailAddress { get; set; } - public bool IsActive { get; set; } - public string? ContactNo { get; set; } - public string? ContactPerson { get; set; } - public string? LeadTime { get; set; } - public bool VatInc { get; set; } - public string? Currency { get; set; } - public string? PaymentTerms { get; set; } - public byte PaymentTermsId { get; set; } - public byte CurrencyId { get; set; } - public string? TinNo { get; set; } - public string? Address { get; set; } + public string SupplierName { get; set; } = string.Empty; + public string EmailAddress { get; set; } = string.Empty; + public bool IsActive { get; set; } = true; + public string ContactNo { get; set; } = string.Empty; + public string ContactPerson { get; set; } = string.Empty; + public string LeadTime { get; set; } = string.Empty; + public bool IsVatable { get; set; }=false; + public byte PaymentTermsId { get; set; } = 1; + public byte CurrencyId { get; set; } = 1; + public string TinNo { get; set; } = string.Empty; + public string Address { get; set; } = string.Empty; + public string Website { get; set; } = string.Empty; } } diff --git a/CPRNIMS.Infrastructure/Entities/Purchasing/ItemWithoutSupplier.cs b/CPRNIMS.Infrastructure/Entities/Purchasing/ItemWithoutSupplier.cs new file mode 100644 index 0000000..fc8982f --- /dev/null +++ b/CPRNIMS.Infrastructure/Entities/Purchasing/ItemWithoutSupplier.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CPRNIMS.Infrastructure.Entities.Purchasing +{ + public class ItemWithoutSupplier + { + [Key] + public long PRDetailsId { get; set; } + public long PRNo { get; set; } + public long ItemNo { get; set; } + public string UserId { get; set; } = string.Empty; + public string ItemName { get; set; }=string.Empty; + public string ItemDescription { get; set; } = string.Empty; + public string FullName { get; set; } = string.Empty; + } +} diff --git a/CPRNIMS.Infrastructure/Entities/Purchasing/PRDetails.cs b/CPRNIMS.Infrastructure/Entities/Purchasing/PRDetails.cs index 5d4a88a..ba03ae7 100644 --- a/CPRNIMS.Infrastructure/Entities/Purchasing/PRDetails.cs +++ b/CPRNIMS.Infrastructure/Entities/Purchasing/PRDetails.cs @@ -3,38 +3,24 @@ using CPRNIMS.Infrastructure.ViewModel.Items; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using System.Text; using System.Threading.Tasks; namespace CPRNIMS.Infrastructure.Entities.Purchasing { - public class PRDetails : CommonProperties + [Table("PRDetails")] + public class PRDetails { [Key] public long PRDetailsId { get; set; } - public long ItemCodeId { get; set; } - public short ItemClassId { get; set; } - public string? Department { get; set; } - public string? ItemCategoryName { get; set; } - public string? UserId { get; set; } - public string? ItemName { get; set; } - public decimal TotalAmount { get; set; } - public string? ItemDescription { get; set; } + public string ItemName { get; set; }=string.Empty; + public string ItemDescription { get; set; } = string.Empty; public short Status { get; set; } - public string? StatusName { get; set; } public bool IsActive { get; set; } public long ItemNo { get; set; } - public string? ItemLocalName { get; set; } public decimal Qty { get; set; } - public string? NewPRNo { get; set; } - public string? ItemClassName { get; set; } - public string? UOMName { get; set; } - public string? ItemColorName { get; set; } - public string? ItemAttachPath { get; set; } - public long PRNo { get; set; } - public string? Remarks { get; set; } - public DateTime DateNeeded { get; set; } - public bool Queue { get; set; } + public bool IsSearched { get; set; } } } diff --git a/CPRNIMS.Infrastructure/Entities/Purchasing/RR.cs b/CPRNIMS.Infrastructure/Entities/Purchasing/RR.cs index cd50ca7..cacf63a 100644 --- a/CPRNIMS.Infrastructure/Entities/Purchasing/RR.cs +++ b/CPRNIMS.Infrastructure/Entities/Purchasing/RR.cs @@ -1,4 +1,5 @@ -using System; +using Microsoft.EntityFrameworkCore; +using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; @@ -7,9 +8,10 @@ using System.Threading.Tasks; namespace CPRNIMS.Infrastructure.Entities.Purchasing { + [Keyless] public class RR { - [Key] + public long RRId { get; set; } public long RRNo { get; set; } public long POId { get; set; } public string? PONo { get; set; } diff --git a/CPRNIMS.Infrastructure/Helper/SMTPHelper.cs b/CPRNIMS.Infrastructure/Helper/SMTPHelper.cs index a2170cc..a1d6c23 100644 --- a/CPRNIMS.Infrastructure/Helper/SMTPHelper.cs +++ b/CPRNIMS.Infrastructure/Helper/SMTPHelper.cs @@ -44,123 +44,113 @@ namespace CPRNIMS.Infrastructure.Helper } public async Task SendEmailAsync(EmailMessageDetailsVM emailMessageBody) { - try + if (string.IsNullOrWhiteSpace(emailMessageBody?.Recipient)) { - if (string.IsNullOrWhiteSpace(emailMessageBody?.Recipient)) + Console.WriteLine("Email address is null or empty. Cannot send email."); + return false; + } + + // Reads live from appsettings.json every time — picks up changes without restart + var excludedEmails = new HashSet( + _configuration.GetSection("Canvass:EmailSettings:ExcludedEmails") + .Get>() ?? new List(), + StringComparer.OrdinalIgnoreCase + ); + + using (MailMessage myMessage = new MailMessage()) + { + var recipientList = emailMessageBody.Recipient + .Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries) + .Select(r => r.Trim()) + .Where(r => !string.IsNullOrWhiteSpace(r)) + .Where(r => + { + if (excludedEmails.Contains(r)) + { + Console.WriteLine($"[Excluded] Skipping: {r}"); + return false; + } + return true; + }); + + // Validate remaining recipients concurrently + var validationResults = await _emailValidator.ValidateBatchAsync(recipientList); + + foreach (var result in validationResults) { - Console.WriteLine("Email address is null or empty. Cannot send email."); + if (result.IsValid) + myMessage.To.Add(result.Email); + else + Console.WriteLine($"[Skipped] {result.Reason}: {result.Email}"); + } + + if (myMessage.To.Count == 0) + { + Console.WriteLine("No valid recipients after exclusion/validation. Aborting."); return false; } - // 👇 Reads live from appsettings.json every time — picks up changes without restart - var excludedEmails = new HashSet( - _configuration.GetSection("Canvass:EmailSettings:ExcludedEmails") - .Get>() ?? new List(), - StringComparer.OrdinalIgnoreCase - ); + myMessage.Sender = new MailAddress(emailMessageBody.SenderEmail); + myMessage.From = new MailAddress(emailMessageBody.SenderEmail, emailMessageBody.DisplayName); - using (MailMessage myMessage = new MailMessage()) + // CC with exclusion too + if (!string.IsNullOrWhiteSpace(emailMessageBody.CC)) { - var recipientList = emailMessageBody.Recipient + var ccList = emailMessageBody.CC .Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries) - .Select(r => r.Trim()) - .Where(r => !string.IsNullOrWhiteSpace(r)) - .Where(r => + .Select(c => c.Trim()) + .Where(c => !string.IsNullOrWhiteSpace(c)) + .Where(c => { - if (excludedEmails.Contains(r)) + if (excludedEmails.Contains(c)) { - Console.WriteLine($"[Excluded] Skipping: {r}"); + Console.WriteLine($"[Excluded CC] Skipping: {c}"); return false; } return true; }); - // Validate remaining recipients concurrently - var validationResults = await _emailValidator.ValidateBatchAsync(recipientList); - - foreach (var result in validationResults) + var ccValidationResults = await _emailValidator.ValidateBatchAsync(ccList); + foreach (var result in ccValidationResults) { if (result.IsValid) - myMessage.To.Add(result.Email); + myMessage.CC.Add(result.Email); else - Console.WriteLine($"[Skipped] {result.Reason}: {result.Email}"); - } - - if (myMessage.To.Count == 0) - { - Console.WriteLine("No valid recipients after exclusion/validation. Aborting."); - return false; - } - - myMessage.Sender = new MailAddress(emailMessageBody.SenderEmail); - myMessage.From = new MailAddress(emailMessageBody.SenderEmail, emailMessageBody.DisplayName); - - // CC with exclusion too - if (!string.IsNullOrWhiteSpace(emailMessageBody.CC)) - { - var ccList = emailMessageBody.CC - .Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries) - .Select(c => c.Trim()) - .Where(c => !string.IsNullOrWhiteSpace(c)) - .Where(c => - { - if (excludedEmails.Contains(c)) - { - Console.WriteLine($"[Excluded CC] Skipping: {c}"); - return false; - } - return true; - }); - - var ccValidationResults = await _emailValidator.ValidateBatchAsync(ccList); - foreach (var result in ccValidationResults) - { - if (result.IsValid) - myMessage.CC.Add(result.Email); - else - Console.WriteLine($"[Skipped CC] {result.Reason}: {result.Email}"); - } - } - - myMessage.Subject = emailMessageBody.Subject; - myMessage.Body = emailMessageBody.Message; - myMessage.IsBodyHtml = true; - - if (emailMessageBody.IsCanvass && File.Exists(emailMessageBody.AttachPath)) - { - Attachment pdfAttachment = new Attachment(emailMessageBody.AttachPath); - pdfAttachment.Name = Path.GetFileName(emailMessageBody.AttachPath); - myMessage.Attachments.Add(pdfAttachment); - } - - using (SmtpClient smtp = new SmtpClient(emailMessageBody.Server)) - { - smtp.Port = emailMessageBody.OutGoingPort; - smtp.UseDefaultCredentials = emailMessageBody.IsSuccess; - smtp.Credentials = new NetworkCredential(emailMessageBody.UserName, emailMessageBody.NewPassword); - smtp.EnableSsl = true; - - try - { - await smtp.SendMailAsync(myMessage); - Console.WriteLine($"Email sent successfully to {myMessage.To.Count} recipient(s)."); - return true; - } - catch (Exception ex) - { - var message = ex.InnerException?.ToString() ?? ex.Message; - Console.WriteLine($"Error sending email: {message}"); - return false; - } + Console.WriteLine($"[Skipped CC] {result.Reason}: {result.Email}"); + } + } + + myMessage.Subject = emailMessageBody.Subject; + myMessage.Body = emailMessageBody.Message; + myMessage.IsBodyHtml = true; + + if (emailMessageBody.IsCanvass && File.Exists(emailMessageBody.AttachPath)) + { + Attachment pdfAttachment = new Attachment(emailMessageBody.AttachPath); + pdfAttachment.Name = Path.GetFileName(emailMessageBody.AttachPath); + myMessage.Attachments.Add(pdfAttachment); + } + + using (SmtpClient smtp = new SmtpClient(emailMessageBody.Server)) + { + smtp.Port = emailMessageBody.OutGoingPort; + smtp.UseDefaultCredentials = emailMessageBody.IsSuccess; + smtp.Credentials = new NetworkCredential(emailMessageBody.UserName, emailMessageBody.NewPassword); + smtp.EnableSsl = true; + + try + { + await smtp.SendMailAsync(myMessage); + Console.WriteLine($"Email sent successfully to {myMessage.To.Count} recipient(s)."); + return true; + } + catch (Exception ex) + { + var message = ex.InnerException?.ToString() ?? ex.Message; + Console.WriteLine($"Error sending email: {message}"); + return false; } } - } - catch (Exception ex) - { - IsAuthError = true; - var message = ex.InnerException?.ToString() ?? ex.Message; - Console.WriteLine($"Error in SendEmailAsync: {message}"); - return false; } } } diff --git a/CPRNIMS.WebApi/Common/ServiceExtensions.cs b/CPRNIMS.WebApi/Common/ServiceExtensions.cs index bc83ebd..f3e9468 100644 --- a/CPRNIMS.WebApi/Common/ServiceExtensions.cs +++ b/CPRNIMS.WebApi/Common/ServiceExtensions.cs @@ -1,28 +1,29 @@ -using CPRNIMS.Infrastructure.Database; +using CPRNIMS.Domain.Contracts.Account; +using CPRNIMS.Domain.Contracts.Canvass; +using CPRNIMS.Domain.Contracts.Finance; +using CPRNIMS.Domain.Contracts.Inventory; +using CPRNIMS.Domain.Contracts.Items; +using CPRNIMS.Domain.Contracts.PO; +using CPRNIMS.Domain.Contracts.PR; +using CPRNIMS.Domain.Contracts.Receiving; +using CPRNIMS.Domain.Contracts.SMTP; +using CPRNIMS.Domain.Services; +using CPRNIMS.Domain.Services.Account; +using CPRNIMS.Domain.Services.Canvass; +using CPRNIMS.Domain.Services.Finance; +using CPRNIMS.Domain.Services.Inventory; +using CPRNIMS.Domain.Services.PO; +using CPRNIMS.Domain.Services.Receiving; +using CPRNIMS.Domain.Services.SMTP; +using CPRNIMS.Infrastructure.Database; using CPRNIMS.Infrastructure.Entities.Account; +using CPRNIMS.Infrastructure.Helper; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; -using Microsoft.OpenApi.Models; -using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; +using Microsoft.OpenApi.Models; using System.Text; -using CPRNIMS.Domain.Services.Account; -using CPRNIMS.Domain.Contracts.Account; -using CPRNIMS.Domain.Services; -using CPRNIMS.Domain.Contracts.Items; -using CPRNIMS.Domain.Contracts.PR; -using CPRNIMS.Domain.Contracts.Canvass; -using CPRNIMS.Domain.Contracts.SMTP; -using CPRNIMS.Domain.Services.SMTP; -using CPRNIMS.Infrastructure.Helper; -using CPRNIMS.Domain.Contracts.PO; -using CPRNIMS.Domain.Services.PO; -using CPRNIMS.Domain.Contracts.Finance; -using CPRNIMS.Domain.Services.Finance; -using CPRNIMS.Domain.Contracts.Inventory; -using CPRNIMS.Domain.Services.Inventory; -using CPRNIMS.Domain.Contracts.Receiving; -using CPRNIMS.Domain.Services.Receiving; namespace CPRNIMS.WebApi.Common @@ -150,7 +151,12 @@ namespace CPRNIMS.WebApi.Common services.AddScoped(); services.AddScoped(); services.AddScoped(); - services.AddScoped(); + services.AddScoped(); + + #region Automation using LLM + services.AddHttpClient(); + #endregion + services.AddScoped(); services.AddScoped(); services.AddScoped (); diff --git a/CPRNIMS.WebApi/Controllers/Base/BaseController.cs b/CPRNIMS.WebApi/Controllers/Base/BaseController.cs index 8557666..8c0c26a 100644 --- a/CPRNIMS.WebApi/Controllers/Base/BaseController.cs +++ b/CPRNIMS.WebApi/Controllers/Base/BaseController.cs @@ -56,15 +56,8 @@ namespace CPRNIMS.WebApi.Controllers.Base [HttpPost("{GetRelativePath}")] public string GetRelativePath(string relativePath) { - try - { - string templateFolderPath = Path.Combine(_webHostEnvironment.ContentRootPath, relativePath); - return templateFolderPath; - } - catch (Exception) - { - throw; - } + string templateFolderPath = Path.Combine(_webHostEnvironment.ContentRootPath, relativePath); + return templateFolderPath; } [NonAction] [HttpPost("{ErrMessage}")] diff --git a/CPRNIMS.WebApi/Controllers/Canvass/CanvassMgmtController.cs b/CPRNIMS.WebApi/Controllers/Canvass/CanvassMgmtController.cs index b735893..50db716 100644 --- a/CPRNIMS.WebApi/Controllers/Canvass/CanvassMgmtController.cs +++ b/CPRNIMS.WebApi/Controllers/Canvass/CanvassMgmtController.cs @@ -1,8 +1,10 @@ -using CPRNIMS.Domain.Contracts.Canvass; -using CPRNIMS.Domain.Contracts.SMTP; +using AutoMapper; +using CPRNIMS.Domain.Contracts.Canvass; using CPRNIMS.Domain.Services; +using CPRNIMS.Domain.Services.Canvass; using CPRNIMS.Infrastructure.Dto.Canvass; -using CPRNIMS.Infrastructure.Entities.Canvass; +using CPRNIMS.Infrastructure.Dto.Canvass.Request; +using CPRNIMS.Infrastructure.Dto.Canvass.Response; using CPRNIMS.Infrastructure.Helper; using CPRNIMS.Infrastructure.ViewModel.Canvass; using CPRNIMS.Infrastructure.ViewModel.Common; @@ -17,15 +19,19 @@ namespace CPRNIMS.WebApi.Controllers.Canvass private readonly SMTPHelper _smtpHelper; private readonly ICanvass _canvass; private readonly IConfiguration _config; - + private readonly SupplierSearchService _supplierSearchService; + private readonly IMapper _mapper; public CanvassMgmtController(ErrorMessageService errorMessageService, IWebHostEnvironment webHostEnvironment, SMTPHelper sMTPHelper, - IConfiguration configuration, ICanvass canvass) : + IConfiguration configuration, ICanvass canvass, SupplierSearchService supplierSearchService, + IMapper mapper) : base(errorMessageService, webHostEnvironment, configuration) { _canvass = canvass; _config = configuration; _smtpHelper = sMTPHelper; + _supplierSearchService= supplierSearchService; + _mapper = mapper; } #region Get @@ -350,142 +356,295 @@ namespace CPRNIMS.WebApi.Controllers.Canvass [HttpPost("PostTaggingSupplier")] public async Task PostTaggingSupplier([FromBody] CanvassVM canvassVM) { - try + var supplier = new SupplierResponse(); + foreach (var items in canvassVM.SupplierList.SupplierId) { - var supplier = new Suppliers(); - foreach (var items in canvassVM.SupplierList.SupplierId) + var index = canvassVM.SupplierList.SupplierId.IndexOf(items); + + var CanvassDto = new CanvassDto { - var index = canvassVM.SupplierList.SupplierId.IndexOf(items); + SupplierId = canvassVM.SupplierList.SupplierId[index], + ItemNo = canvassVM.ItemNo, + IsActive = true, + UserId = canvassVM.UserId, + SupplierName = "N/A", + EmailAddress = "N/A", + Address = "N/A", + ContactNo = "N/A", + ContactPerson = "N/A", + IsTagging = true + }; - var CanvassDto = new CanvassDto - { - SupplierId = canvassVM.SupplierList.SupplierId[index], - ItemNo = canvassVM.ItemNo, - IsActive = true, - UserId = canvassVM.UserId, - SupplierName = "N/A", - EmailAddress = "N/A", - Address = "N/A", - ContactNo = "N/A", - ContactPerson = "N/A", - IsTagging = true - }; - - supplier = await _canvass.PostTaggingSupplier(CanvassDto); - } - return Ok(supplier); - } - catch (Exception ex) - { - var message = ex.InnerException?.Message ?? ex.Message; - return BadRequest(new { ErrMessage = message, ErrCode = 0 }); + supplier = await _canvass.PostTaggingSupplier(CanvassDto); } + return Ok(supplier); } [HttpPost("PostPutItemTagging")] public async Task PostPutItemTagging([FromBody] CanvassVM canvassVM) { - try + var supplier = new SupplierResponse(); + foreach (var items in canvassVM.ItemList.ItemNo) { - var supplier = new Suppliers(); - foreach (var items in canvassVM.ItemList.ItemNo) + var index = canvassVM.ItemList.ItemNo.IndexOf(items); + + var CanvassDto = new CanvassDto { - var index = canvassVM.ItemList.ItemNo.IndexOf(items); + ItemNo = canvassVM.ItemList.ItemNo[index], + SupplierId = canvassVM.SupplierId, + IsActive = canvassVM.IsActive, + UserId = canvassVM.UserId, + }; - var CanvassDto = new CanvassDto - { - ItemNo = canvassVM.ItemList.ItemNo[index], - SupplierId = canvassVM.SupplierId, - IsActive = canvassVM.IsActive, - UserId = canvassVM.UserId, - }; - - supplier = await _canvass.PostPutItemTagging(CanvassDto); - } - return Ok(supplier); - } - catch (Exception ex) - { - var message = ex.InnerException?.Message ?? ex.Message; - return BadRequest(new { ErrMessage = message, ErrCode = 0 }); + supplier = await _canvass.PostPutItemTagging(CanvassDto); } + return Ok(supplier); } [HttpPost("PostCanvass")] public async Task PostCanvass([FromBody] CanvassVM canvassVM) { - try + var baseTemplate = EMailTemplate("Content\\SMTPEmailContent", "SendToSupplier.cshtml"); + + var CanvassDto = new CanvassDto(); + int canvassNo = await _canvass.GetCanvassNo(); + foreach (var itemCartId in canvassVM.CanvassList.PRDetailsId) { - var baseTemplate = "n/a"; + var index = canvassVM.CanvassList.PRDetailsId.IndexOf(itemCartId); - baseTemplate = EMailTemplate("Content\\SMTPEmailContent", "SendToSupplier.cshtml"); - - var CanvassDto = new CanvassDto(); - int canvassNo = await _canvass.GetCanvassNo(); - foreach (var itemCartId in canvassVM.CanvassList.PRDetailsId) + CanvassDto = new CanvassDto { - var index = canvassVM.CanvassList.PRDetailsId.IndexOf(itemCartId); - - CanvassDto = new CanvassDto - { - PRDetailsId = canvassVM.CanvassList.PRDetailsId[index], - PRNo = canvassVM.CanvassList.PRNo[index], - ItemNo = canvassVM.CanvassList.ItemNo[index], - SupplierId = canvassVM.SupplierId, - UserId = canvassVM.UserId, - FullName = canvassVM.FullName, - CanvassNo = canvassNo + 1, - }; - await _canvass.PostPerSupplierToken(CanvassDto); - } - var rfq = await _canvass.GetRFQ(CanvassDto); - - var message = new StringBuilder(baseTemplate); - message.Replace("@ViewBag.FormLink", Convert.ToString(_configuration["WebEndPoint:SupplierForm"] + rfq[0].Token)); - message.Replace("@ViewBag.Supplier", rfq[0].SupplierName); - message.Replace("@ViewBag.Signature", CanvassDto.FullName); - - var messageDetails = new EmailMessageDetailsVM(); - messageDetails.AttachPath = GetRelativePath(@"Content\Documents\Pdf\Offer_Submission_Procedure.pdf"); - - messageDetails.Recipient = rfq[0].EmailAddress; - messageDetails.Message = message.ToString(); - messageDetails.Subject = "CLMS - Request For Quotation #PRNo: " + rfq[0].AggrePRNo; - messageDetails.CC = Convert.ToString(_configuration["Canvass:CC"]); - messageDetails.SenderEmail = _config["SMTP:SenderEmail"]; - messageDetails.DisplayName = "lloydlabinc.com"; - messageDetails.NewPassword = _config["SMTP:Password"]; - messageDetails.OutGoingPort = 587; - messageDetails.Server = _config["SMTP:Server"]; - messageDetails.UserName = _config["SMTP:UserName"]; - messageDetails.IsSuccess = false; - messageDetails.IsCanvass = true; - await _smtpHelper.SendEmailAsync(messageDetails); - - var pR = await _canvass.PostCanvass(CanvassDto); - - return Ok(pR); - } - catch (Exception ex) - { - var errorMessage = ex.InnerException?.ToString() ?? ex.Message.ToString(); - await PostErrorMessage(errorMessage + " PostCanvass", "WebApi"); - throw; + PRDetailsId = canvassVM.CanvassList.PRDetailsId[index], + PRNo = canvassVM.CanvassList.PRNo[index], + ItemNo = canvassVM.CanvassList.ItemNo[index], + SupplierId = canvassVM.SupplierId, + UserId = canvassVM.UserId, + FullName = canvassVM.FullName, + CanvassNo = canvassNo + 1, + }; + await _canvass.PostPerSupplierToken(CanvassDto); } + var rfq = await _canvass.GetRFQ(CanvassDto); + + var message = new StringBuilder(baseTemplate); + message.Replace("@ViewBag.FormLink", Convert.ToString(_configuration["WebEndPoint:SupplierForm"] + rfq[0].Token)); + message.Replace("@ViewBag.Supplier", rfq[0].SupplierName); + message.Replace("@ViewBag.Signature", CanvassDto.FullName); + + var messageDetails = new EmailMessageDetailsVM(); + messageDetails.AttachPath = GetRelativePath(@"Content\Documents\Pdf\Offer_Submission_Procedure.pdf"); + + messageDetails.Recipient = rfq[0].EmailAddress; + messageDetails.Message = message.ToString(); + messageDetails.Subject = "CLMS - Request For Quotation #PRNo: " + rfq[0].AggrePRNo; + messageDetails.CC = Convert.ToString(_configuration["Canvass:CC"]); + messageDetails.SenderEmail = _config["SMTP:SenderEmail"]; + messageDetails.DisplayName = "lloydlabinc.com"; + messageDetails.NewPassword = _config["SMTP:Password"]; + messageDetails.OutGoingPort = 587; + messageDetails.Server = _config["SMTP:Server"]; + messageDetails.UserName = _config["SMTP:UserName"]; + messageDetails.IsSuccess = false; + messageDetails.IsCanvass = true; + await _smtpHelper.SendEmailAsync(messageDetails); + + var pR = await _canvass.PostCanvass(CanvassDto); + + return Ok(pR); } + [HttpPost("PostSearchSupplierAndSend")] + public async Task PostSearchSupplierAndSend(CancellationToken ct) + { + // #1 Get top 10 items without suppliers — must process all + var response = await _canvass.GetItemWithoutSupplier(); + if (response == null || !response.Any()) return BadRequest("No items found."); + + var supplierResults = new List(); + + foreach (var item in response) // ✅ FIX #1: use loop variable, not response[0] + { + // #2 Search Tavily + Filter with Groq + var suppliers = await _supplierSearchService + .SearchAndFilterSuppliersAsync(item.ItemName, item.ItemDescription); + + if (!suppliers.Any()) + { + await _canvass.SearchingUpdate(item.PRDetailsId); + continue; + } + + // #3 & #4 Loop each found supplier + foreach (var supplier in suppliers) + { + int canvassNo = await _canvass.GetCanvassNo(); + + var supplierRequest = _mapper.Map(supplier); + supplierRequest.ItemNo = item.ItemNo; + + var result = await _canvass.PostSupplierAsync(supplierRequest, ct); + if (result?.Value == null) continue; + + var canvassDto = new CanvassDto + { + PRDetailsId = item.PRDetailsId, + PRNo = item.PRNo, + ItemNo = item.ItemNo, + SupplierId = result.Value.SupplierId, + UserId = item.UserId, + FullName = item.FullName, + CanvassNo = ++canvassNo, + }; + + await _canvass.PostPerSupplierToken(canvassDto); + + var rfq = await _canvass.GetRFQ(canvassDto); + if (rfq == null || !rfq.Any()) continue; + + var supplierEmailRequest = new SupplierEmailRequest + { + AttachPath = GetRelativePath(@"Content\\Documents\\Pdf\\Offer_Submission_Procedure.pdf"), + Recipient = "rmsoriano@lloydlab.com",//rfq[0].EmailAddress, // this will be implemented later + Subject = $"CLMS - Request For Quotation #PRNo: {rfq[0].AggrePRNo}", + CC = Convert.ToString(_configuration["Canvass:CC"] ?? ""), + SenderEmail = _config["SMTP:SenderEmail"], + DisplayName = "lloydlabinc.com", + Password = _config["SMTP:Password"], + OutGoingPort = 587, + Server = _config["SMTP:Server"], + UserName = _config["SMTP:UserName"], + FormLink = Convert.ToString(_configuration["WebEndPoint:SupplierForm"] ?? ""), + Token = rfq[0].Token, + SupplierName = result.Value.SupplierName, + Purchaser = item.FullName, + IsSuccess = false, + IsCanvass = true, + }; + + await _canvass.SearchingUpdate(item.PRDetailsId); + await _canvass.SendRFQ(supplierEmailRequest); + + supplierResults.Add(new + { + item = item.ItemName, + supplier = supplier.SupplierName, + email = supplier.EmailAddress, + canvassNo = canvassDto.CanvassNo + }); + } + } + + return Ok(new + { + totalProcessed = supplierResults.Count, + suppliers = supplierResults + }); + } + /* [HttpPost("PostSearchSupplierAndSend")] + public async Task PostSearchSupplierAndSend(CancellationToken ct) + { + // #1 Get top 10 item without suppliers must be process all + var response = await _canvass.GetItemWithoutSupplier(); + if (response == null || !response.Any()) return BadRequest("No items found."); + + var supplierResults = new List(); + + foreach (var supplierList in response) + { + + var item = response[0]; + + // #2 Search Tavily + Filter with Groq + var suppliers = await _supplierSearchService + .SearchAndFilterSuppliersAsync(item.ItemName, item.ItemDescription); + + if (!suppliers.Any()) + { + await _canvass.SearchingUpdate(supplierList.PRDetailsId); + continue; + } + + var results = new List(); + + // #3 & #4 Loop each found supplier + foreach (var supplier in suppliers) + { + int canvassNo = await _canvass.GetCanvassNo(); + + // Map SupplierResponse → SupplierRequest before saving + var supplierRequest = _mapper.Map(supplier); + + supplierRequest.ItemNo=item.ItemNo; + + var result = await _canvass.PostSupplierAsync(supplierRequest, ct); + + if (result?.Value == null) continue; + + var canvassDto = new CanvassDto + { + PRDetailsId = item.PRDetailsId, + PRNo = item.PRNo, + ItemNo = item.ItemNo, + SupplierId = result.Value.SupplierId, + UserId = item.UserId, + FullName = item.FullName, + CanvassNo = ++canvassNo, + }; + + // Generate token for supplier form link + await _canvass.PostPerSupplierToken(canvassDto); + + // Get RFQ details + var rfq = await _canvass.GetRFQ(canvassDto); + + if (rfq == null || !rfq.Any()) continue; + + // Send RFQ email + var email = rfq[0].EmailAddress; + var supplierEmailRequest = new SupplierEmailRequest + { + AttachPath = GetRelativePath(@"Content\\Documents\\Pdf\\Offer_Submission_Procedure.pdf"), + Recipient = "rmsoriano@lloydlab.com",//rfq[0].EmailAddress, // this will be implemented later + Subject = $"CLMS - Request For Quotation #PRNo: {rfq[0].AggrePRNo}", + CC = Convert.ToString(_configuration["Canvass:CC"] ?? ""), + SenderEmail = _config["SMTP:SenderEmail"], + DisplayName = "lloydlabinc.com", + Password = _config["SMTP:Password"], + OutGoingPort = 587, + Server = _config["SMTP:Server"], + UserName = _config["SMTP:UserName"], + FormLink= Convert.ToString(_configuration["WebEndPoint:SupplierForm"] ?? ""), + Token = rfq[0].Token, + SupplierName= result.Value.SupplierName, + Purchaser= item.FullName, + IsSuccess = false, + IsCanvass = true, + }; + await _canvass.SearchingUpdate(supplierList.PRDetailsId); + + await _canvass.SendRFQ(supplierEmailRequest); + + results.Add(new + { + supplier = supplier.SupplierName, + email = supplier.EmailAddress, + canvassNo = canvassDto.CanvassNo + }); + } + + return Ok(new + { + item = item.ItemName, + processed = results.Count, + suppliers = results + }); + } + return Ok(); + }*/ + [HttpPost("PostSuggestedSupp")] public async Task PostSuggestedSupp(CanvassDto CanvassDto) { - try - { - var pR = await _canvass.PostSuggestedSupp(CanvassDto); + var pR = await _canvass.PostSuggestedSupp(CanvassDto); - return Ok(pR); - } - catch (Exception ex) - { - var message = ex.InnerException?.ToString() ?? ex.Message.ToString(); - await PostErrorMessage(message + " PostSuggestedSupp", "WebApi"); - throw; - } + return Ok(pR); } [HttpPost("PostApprovedSupp")] public async Task PostApprovedSupp(CanvassDto CanvassDto) diff --git a/CPRNIMS.WebApi/Controllers/Receiving/ReceivingController.cs b/CPRNIMS.WebApi/Controllers/Receiving/ReceivingController.cs index e104547..1809a6c 100644 --- a/CPRNIMS.WebApi/Controllers/Receiving/ReceivingController.cs +++ b/CPRNIMS.WebApi/Controllers/Receiving/ReceivingController.cs @@ -124,82 +124,37 @@ namespace CPRNIMS.WebApi.Controllers.Receiving [HttpPost("GetForReceiving")] public async Task GetForReceiving(ItemDto itemDto) { - try - { - var myPR = await _receiving.GetForReceiving(itemDto); + var myPR = await _receiving.GetForReceiving(itemDto); - return Ok(myPR); - } - catch (Exception ex) - { - var message = ex.InnerException?.ToString() ?? ex.Message.ToString(); - await PostErrorMessage(message, "WebApi"); - throw; - } + return Ok(myPR); } [HttpPost("GetRR")] public async Task GetRR(ItemDto itemDto) { - try - { - var myPR = await _receiving.GetRR(itemDto); + var myPR = await _receiving.GetRR(itemDto); - return Ok(myPR); - } - catch (Exception ex) - { - var message = ex.InnerException?.ToString() ?? ex.Message.ToString(); - await PostErrorMessage(message, "WebApi"); - throw; - } + return Ok(myPR); } [HttpPost("GetRRDetailByPO")] public async Task GetRRDetailByPO(ItemDto itemDto) { - try - { - var myPR = await _receiving.GetRRDetailByPO(itemDto); + var myPR = await _receiving.GetRRDetailByPO(itemDto); - return Ok(myPR); - } - catch (Exception ex) - { - var message = ex.InnerException?.ToString() ?? ex.Message.ToString(); - await PostErrorMessage(message + "GetPRByRRId", "WebApi"); - throw; - } + return Ok(myPR); } [HttpPost("GetRRDetail")] public async Task GetRRDetail(ItemDto itemDto) { - try - { - var myPR = await _receiving.GetRRDetail(itemDto); + var myPR = await _receiving.GetRRDetail(itemDto); - return Ok(myPR); - } - catch (Exception ex) - { - var message = ex.InnerException?.ToString() ?? ex.Message.ToString(); - await PostErrorMessage(message + "GetRRDetail", "WebApi"); - throw; - } + return Ok(myPR); } [HttpPost("GetLatestRRNo")] public async Task GetLatestRRNo(ItemDto itemDto) { - try - { - var myPR = await _receiving.GetLatestRRNo(itemDto); + var myPR = await _receiving.GetLatestRRNo(itemDto); - return Ok(myPR); - } - catch (Exception ex) - { - var message = ex.InnerException?.ToString() ?? ex.Message.ToString(); - await PostErrorMessage(message + "GetLatestRRNo", "WebApi"); - throw; - } + return Ok(myPR); } #endregion } diff --git a/CPRNIMS.WebApi/Program.cs b/CPRNIMS.WebApi/Program.cs index 656b101..b804e42 100644 --- a/CPRNIMS.WebApi/Program.cs +++ b/CPRNIMS.WebApi/Program.cs @@ -1,3 +1,4 @@ +using CPRNIMS.Domain.Profile.Canvass; using CPRNIMS.Middleware; using CPRNIMS.WebApi.Common; @@ -5,6 +6,8 @@ var builder = WebApplication.CreateBuilder(args); builder.Services.AddApplicationServices(builder); +builder.Services.AddAutoMapper(cfg => { }, typeof(SupplierRequestProfile)); + var app = builder.Build(); // Configure the HTTP request pipeline. diff --git a/CPRNIMS.WebApps/Views/Components/Receiving/RRPrinting/DR.cshtml b/CPRNIMS.WebApps/Views/Components/Receiving/RRPrinting/DR.cshtml index 885cfc0..d86cf5a 100644 --- a/CPRNIMS.WebApps/Views/Components/Receiving/RRPrinting/DR.cshtml +++ b/CPRNIMS.WebApps/Views/Components/Receiving/RRPrinting/DR.cshtml @@ -8,7 +8,7 @@
- LLOD LABORATORIES INC. + LLOYD LABORATORIES INC.