Project code maintenance and pr item attachment

This commit is contained in:
rowell_m_soriano 2026-02-12 10:41:44 +08:00
parent 33b839741f
commit 0612679648
69 changed files with 8366 additions and 680 deletions

View File

@ -2,6 +2,7 @@
using CPRNIMS.Infrastructure.Entities.Account;
using CPRNIMS.Infrastructure.Entities.Items;
using CPRNIMS.Infrastructure.Entities.Purchasing;
using CPRNIMS.Infrastructure.Models.Common;
using System;
using System.Collections.Generic;
using System.Linq;
@ -21,11 +22,12 @@ namespace CPRNIMS.Domain.Contracts.Items
Task<List<ItemColor>> GetItemColor(ItemDto itemDto);
Task<List<UnitOfMessure>> GetItemUOM(ItemDto itemDto);
Task<List<NotifUserKey>> GetNotifUserKey(ItemDto itemDto);
Task<long> GetPRNo();
Task<ItemCart> PostPurchRequest(ItemDto itemDto);
Task<(long, long)> GetPRNo();
Task<ResponseObject> PostPurchRequest(ItemDto itemDto);
Task<ItemCodeDto> PostPutItem(ItemCodeDto itemDto);
Task<Item> PutItemDetail(ItemDto itemDto);
Task<ItemCart> PostPutItemCart(ItemDto itemDto);
Task<ItemCart> PostPutItemPath(ItemDto itemDto);
Task PostPutAttachment(AttachmentRequest attach);
}
}

View File

@ -2,6 +2,7 @@
using CPRNIMS.Infrastructure.Entities.Common;
using CPRNIMS.Infrastructure.Entities.Purchasing;
using CPRNIMS.Infrastructure.Entities.SMTP;
using CPRNIMS.Infrastructure.Models.Common;
using System;
using System.Collections.Generic;
using System.Linq;
@ -28,6 +29,7 @@ namespace CPRNIMS.Domain.Contracts.PR
Task<List<AlternativeOfferDetails>> GetSupplierAlterOfferDetails(PRDto PRDto);
Task<List<NotificationById>> GetNotificationById(PRDto PRDto);
Task<List<PRDto>> GetApproverName(PRDto PRDto);
Task<List<ProjectCodes>> GetProjectCodes(PRDto pRDto);
Task<MessageResponse> PRItemRemoval(PRDto pRDto);
Task<PRDetails> PostPRApproveReject(PRDto PRDto);
Task<PRDetails> PostPutReceiving(PRDto PRDto);
@ -35,5 +37,6 @@ namespace CPRNIMS.Domain.Contracts.PR
Task<PRDetails> PutItemDetail(PRDto PRDto);
Task<PRDetails> PostPutDeniedItem(PRDto PRDto);
Task<AlternativeOfferDetails> PutSupplierAlterOffer(PRDto pRDto);
Task<ResponseObject> PostPutProjectCode(PRDto prDto);
}
}

View File

@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Domain.Services
{
public static class ContentTypeHelper
{
public static string GetContentType(string fileName)
{
var extension = Path.GetExtension(fileName).ToLowerInvariant();
return extension switch
{
".pdf" => "application/pdf",
".doc" => "application/msword",
".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
".pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation",
".xls" => "application/vnd.ms-excel",
".xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
".png" => "image/png",
".jpg" or ".jpeg" => "image/jpeg",
".gif" => "image/gif",
".txt" => "text/plain",
_ => "application/octet-stream"
};
}
public static string ValidateFile(string filePath, string uploadsPath)
{
var message = "";
// Security: Prevent directory traversal attacks
var fullPath = Path.GetFullPath(filePath);
if (!fullPath.StartsWith(Path.GetFullPath(uploadsPath)))
{
message = "Invalid file path";
}
if (!System.IO.File.Exists(filePath))
{
message = "File not found";
}
return message;
}
}
}

View File

@ -1,16 +1,13 @@
using CPRNIMS.Domain.Contracts.Account;
using CPRNIMS.Domain.Contracts.Items;
using CPRNIMS.Domain.Contracts.Items;
using CPRNIMS.Infrastructure.Database;
using CPRNIMS.Infrastructure.Dto.Canvass;
using CPRNIMS.Infrastructure.Dto.Items;
using CPRNIMS.Infrastructure.Entities.Account;
using CPRNIMS.Infrastructure.Entities.Canvass;
using CPRNIMS.Infrastructure.Entities.Items;
using CPRNIMS.Infrastructure.Entities.Purchasing;
using CPRNIMS.Infrastructure.Models.Common;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
@ -26,344 +23,275 @@ namespace CPRNIMS.Domain.Services.Items
}
public async Task<ItemCodeDto> PostPutItem(ItemCodeDto itemDto)
{
try
var messCodeParam = new SqlParameter("@MessCode", SqlDbType.TinyInt)
{
var messCodeParam = new SqlParameter("@MessCode", SqlDbType.TinyInt)
{
Direction = ParameterDirection.Output
};
var messageParam = new SqlParameter("@Message", SqlDbType.VarChar, 500)
{
Direction = ParameterDirection.Output
};
var itemCodeParam = new SqlParameter("@ItemCode", SqlDbType.BigInt)
{
Direction = ParameterDirection.Output
};
await _dbContext.Database.ExecuteSqlRawAsync(
"EXEC PostPutItem @ItemCodeId, @ItemName, @ItemDescription, @ItemCategoryId, @Status, @UserId, " +
"@ItemCode OUTPUT, @MessCode OUTPUT, @Message OUTPUT",
new SqlParameter("@ItemCodeId", itemDto.ItemCodeId != null ? itemDto.ItemCodeId : 0L),
new SqlParameter("@ItemName", itemDto.ItemName ?? (object)DBNull.Value),
new SqlParameter("@ItemDescription", itemDto.ItemDescription ?? (object)DBNull.Value),
new SqlParameter("@ItemCategoryId", itemDto.ItemCategoryId),
new SqlParameter("@Status", itemDto.Status != null ? itemDto.Status : 4),
new SqlParameter("@UserId", itemDto.UserId ?? (object)DBNull.Value),
itemCodeParam,
messCodeParam,
messageParam
);
var messCode = (byte)messCodeParam.Value;
var message = messageParam.Value?.ToString();
var itemCode = itemCodeParam.Value != DBNull.Value ? (long?)itemCodeParam.Value : null;
return new ItemCodeDto
{
ItemCodeId = Convert.ToInt64(itemCode),
ItemName = itemDto.ItemName,
ItemDescription = itemDto.ItemDescription,
ItemCategoryId = itemDto.ItemCategoryId,
Status = itemDto.Status,
UserId = itemDto.UserId
};
}
catch (Exception ex)
Direction = ParameterDirection.Output
};
var messageParam = new SqlParameter("@Message", SqlDbType.VarChar, 500)
{
// You could log ex.Message or rethrow with a custom message
throw new Exception("An error occurred while executing PostPutItem.", ex);
}
Direction = ParameterDirection.Output
};
var itemCodeParam = new SqlParameter("@ItemCode", SqlDbType.BigInt)
{
Direction = ParameterDirection.Output
};
await _dbContext.Database.ExecuteSqlRawAsync(
"EXEC PostPutItem @ItemCodeId, @ItemName, @ItemDescription, @ItemCategoryId, @Status, @UserId, " +
"@ItemCode OUTPUT, @MessCode OUTPUT, @Message OUTPUT",
new SqlParameter("@ItemCodeId", itemDto.ItemCodeId != null ? itemDto.ItemCodeId : 0L),
new SqlParameter("@ItemName", itemDto.ItemName ?? (object)DBNull.Value),
new SqlParameter("@ItemDescription", itemDto.ItemDescription ?? (object)DBNull.Value),
new SqlParameter("@ItemCategoryId", itemDto.ItemCategoryId),
new SqlParameter("@Status", itemDto.Status != null ? itemDto.Status : 4),
new SqlParameter("@UserId", itemDto.UserId ?? (object)DBNull.Value),
itemCodeParam,
messCodeParam,
messageParam
);
var messCode = (byte)messCodeParam.Value;
var message = messageParam.Value?.ToString();
var itemCode = itemCodeParam.Value != DBNull.Value ? (long?)itemCodeParam.Value : null;
return new ItemCodeDto
{
ItemCodeId = Convert.ToInt64(itemCode),
ItemName = itemDto.ItemName,
ItemDescription = itemDto.ItemDescription,
ItemCategoryId = itemDto.ItemCategoryId,
Status = itemDto.Status,
UserId = itemDto.UserId
};
}
public async Task<Infrastructure.Entities.Items.Item> PutItemDetail(ItemDto itemDto)
{
try
{
await _dbContext.Database
.ExecuteSqlRawAsync($"EXEC PutItemDetail @ItemCodeId,@ItemLocalId,@ItemTypeId,@UOMId,@ItemColorId,@IsActive," +
$"@UserId,@ItemNo,@PRTypeId,@PackagingTypeId,@Qty,@ItemAttachId,@ItemAttachPath,@IsCommon,@ItemCategoryId," +
$"@RequestTypeId,@ItemName,@ItemDescription,@IsMDLD",
new SqlParameter("@ItemCodeId", itemDto.ItemCodeId != null ? itemDto.ItemCodeId : 0L),
new SqlParameter("@ItemLocalId", itemDto.ItemLocalId),
new SqlParameter("@ItemTypeId", itemDto.ItemTypeId),
new SqlParameter("@UOMId", itemDto.UOMId),
new SqlParameter("@ItemColorId", itemDto.ItemColorId),
new SqlParameter("@IsActive", itemDto.IsActive),
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@ItemNo", itemDto.ItemNo),
new SqlParameter("@PRTypeId", itemDto.PRTypeId),
new SqlParameter("@PackagingTypeId", itemDto.PackagingTypeId),
new SqlParameter("@Qty", itemDto.Qty),
new SqlParameter("@ItemAttachId", itemDto.ItemAttachId != null ? itemDto.ItemAttachId : 0L),
new SqlParameter("@ItemAttachPath", itemDto.ItemAttachPath ?? "N/A"),
new SqlParameter("@IsCommon", itemDto.IsCommon),
new SqlParameter("@ItemCategoryId", itemDto.ItemCategoryId),
new SqlParameter("@RequestTypeId", itemDto.RequestTypeId),
new SqlParameter("@ItemName", itemDto.ItemName),
new SqlParameter("@ItemDescription", itemDto.ItemDescription),
new SqlParameter("@IsMDLD", itemDto.IsMDLD));
await _dbContext.Database
.ExecuteSqlRawAsync($"EXEC PutItemDetail @ItemCodeId,@ItemLocalId,@ItemTypeId,@UOMId,@ItemColorId,@IsActive," +
$"@UserId,@ItemNo,@PRTypeId,@PackagingTypeId,@Qty,@ItemAttachId,@ItemAttachPath,@IsCommon,@ItemCategoryId," +
$"@RequestTypeId,@ItemName,@ItemDescription,@IsMDLD",
new SqlParameter("@ItemCodeId", itemDto.ItemCodeId != null ? itemDto.ItemCodeId : 0L),
new SqlParameter("@ItemLocalId", itemDto.ItemLocalId),
new SqlParameter("@ItemTypeId", itemDto.ItemTypeId),
new SqlParameter("@UOMId", itemDto.UOMId),
new SqlParameter("@ItemColorId", itemDto.ItemColorId),
new SqlParameter("@IsActive", itemDto.IsActive),
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@ItemNo", itemDto.ItemNo),
new SqlParameter("@PRTypeId", itemDto.PRTypeId),
new SqlParameter("@PackagingTypeId", itemDto.PackagingTypeId),
new SqlParameter("@Qty", itemDto.Qty),
new SqlParameter("@ItemAttachId", itemDto.ItemAttachId != null ? itemDto.ItemAttachId : 0L),
new SqlParameter("@ItemAttachPath", itemDto.ItemAttachPath ?? "N/A"),
new SqlParameter("@IsCommon", itemDto.IsCommon),
new SqlParameter("@ItemCategoryId", itemDto.ItemCategoryId),
new SqlParameter("@RequestTypeId", itemDto.RequestTypeId),
new SqlParameter("@ItemName", itemDto.ItemName),
new SqlParameter("@ItemDescription", itemDto.ItemDescription),
new SqlParameter("@IsMDLD", itemDto.IsMDLD));
return new Infrastructure.Entities.Items.Item();
}
catch (Exception ex)
{
ex.ToString();
throw;
}
return new Infrastructure.Entities.Items.Item();
}
public async Task<List<ItemLocalization>> GetItemLocalization(ItemDto itemDto)
{
try
{
var localizations = await _dbContext.ItemLocalizations
.Where(ic => ic.IsActive == true &&
EF.Functions.Like(ic.ItemLocalName, $"%{itemDto.ItemLocalName}%"))
.Take(15)
.ToListAsync();
var localizations = await _dbContext.ItemLocalizations
.Where(ic => ic.IsActive == true &&
EF.Functions.Like(ic.ItemLocalName, $"%{itemDto.ItemLocalName}%"))
.Take(15)
.ToListAsync();
return localizations ?? new List<ItemLocalization>();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
return localizations ?? new List<ItemLocalization>();
}
public async Task<List<ItemCategory>> GetItemCateg(ItemDto itemDto)
{
try
if (itemDto.ItemCategoryId == 0 || itemDto.ItemCategoryId == null)
{
if(itemDto.ItemCategoryId ==0 || itemDto.ItemCategoryId == null)
{
var categories = await _dbContext.ItemCategories
.Where(ic => ic.IsActive == true)
.ToListAsync();
return categories ?? new List<ItemCategory>();
}
else
{
var categories = await _dbContext.ItemCategories
.Where(ic => ic.IsActive == true && ic.ItemCategoryId == itemDto.ItemCategoryId)
.ToListAsync();
return categories ?? new List<ItemCategory>();
}
var categories = await _dbContext.ItemCategories
.Where(ic => ic.IsActive == true)
.ToListAsync();
return categories ?? new List<ItemCategory>();
}
catch (SqlException ex)
else
{
ex.ToString();
throw;
var categories = await _dbContext.ItemCategories
.Where(ic => ic.IsActive == true && ic.ItemCategoryId == itemDto.ItemCategoryId)
.ToListAsync();
return categories ?? new List<ItemCategory>();
}
}
public async Task<List<Infrastructure.Entities.Items.Item>> GetItemDetail(ItemDto itemDto)
{
try
{
var allItems = await _dbContext.Items
.FromSqlRaw($"EXEC GetItemDetail @ItemCodeId,@UserId",
new SqlParameter("@ItemCodeId", itemDto.ItemCodeId),
new SqlParameter("@UserId", itemDto.UserId))
.ToListAsync();
var allItems = await _dbContext.Items
.FromSqlRaw($"EXEC GetItemDetail @ItemCodeId,@UserId",
new SqlParameter("@ItemCodeId", itemDto.ItemCodeId),
new SqlParameter("@UserId", itemDto.UserId))
.ToListAsync();
return allItems ?? new List<Infrastructure.Entities.Items.Item>();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
return allItems ?? new List<Infrastructure.Entities.Items.Item>();
}
public async Task<List<ItemList>> GetItemList(ItemCodeDto itemCode)
{
try
{
var allItems = await _dbContext.ItemList
.FromSqlRaw($"EXEC GetItemList @UserId = '{itemCode.UserId}'")
.ToListAsync();
var allItems = await _dbContext.ItemList
.FromSqlRaw($"EXEC GetItemList @UserId = '{itemCode.UserId}'")
.ToListAsync();
return allItems ?? new List<ItemList>();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
return allItems ?? new List<ItemList>();
}
public async Task<List<ItemColor>> GetItemColor(ItemDto itemDto)
{
try
{
var colors = await _dbContext.ItemColors
.Where(ic => EF.Functions.Like(ic.ItemColorName, $"%{itemDto.ItemColorName}%"))
.Take(5)
.ToListAsync();
var colors = await _dbContext.ItemColors
.Where(ic => EF.Functions.Like(ic.ItemColorName, $"%{itemDto.ItemColorName}%"))
.Take(5)
.ToListAsync();
return colors ?? new List<ItemColor>();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
return colors ?? new List<ItemColor>();
}
public async Task<List<UnitOfMessure>> GetItemUOM(ItemDto itemDto)
{
try
{
var uoms = await _dbContext.UnitOfMessures
.Where(ic => ic.IsActive == true &&
EF.Functions.Like(ic.UOMName, $"%{itemDto.UOMName}%"))
.Take(150)
.ToListAsync();
var uoms = await _dbContext.UnitOfMessures
.Where(ic => ic.IsActive == true &&
EF.Functions.Like(ic.UOMName, $"%{itemDto.UOMName}%"))
.Take(150)
.ToListAsync();
return uoms ?? new List<UnitOfMessure>();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
return uoms ?? new List<UnitOfMessure>();
}
public async Task<ItemAttachement> PostPutItemPath(ItemDto itemDto)
{
try
{
var isExist = await _dbContext.ItemAttachements
var isExist = await _dbContext.ItemAttachements
.FirstOrDefaultAsync(ia => ia.IsActive == true
&& ia.ItemNo == itemDto.ItemNo);
if(isExist != null)
{
isExist.ItemAttachPath = itemDto.ItemAttachPath;
await _dbContext.SaveChangesAsync();
return new ItemAttachement();
}
else
{
return new ItemAttachement();
}
}
catch (SqlException ex)
if (isExist != null)
{
ex.ToString();
throw;
isExist.ItemAttachPath = itemDto.ItemAttachPath;
await _dbContext.SaveChangesAsync();
return new ItemAttachement();
}
else
{
return new ItemAttachement();
}
}
public async Task<ItemCart> PostPutItemCart(ItemDto itemDto)
{
try
{
await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PostPutItemCart @ItemCartId,@ItemNo,@UserId,@UOMId,@ItemColorId,@ItemCategoryId,@PackagingTypeId,@ItemAttachId,@ItemLocalId",
new SqlParameter("@ItemCartId", itemDto.ItemCartId != null ? itemDto.ItemCartId : 0L),
new SqlParameter("@ItemNo", itemDto.ItemNo != null ? itemDto.ItemNo : 0L),
new SqlParameter("@UOMId", itemDto.UOMId),
new SqlParameter("@ItemColorId", itemDto.ItemColorId),
new SqlParameter("@ItemCategoryId", itemDto.ItemCategoryId),
new SqlParameter("@PackagingTypeId", itemDto.PackagingTypeId),
new SqlParameter("@ItemAttachId", itemDto.ItemAttachId),
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@ItemLocalId", itemDto.ItemLocalId));
return new ItemCart();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PostPutItemCart @ItemCartId,@ItemNo,@UserId,@UOMId,@ItemColorId,@ItemCategoryId,@PackagingTypeId,@ItemAttachId,@ItemLocalId",
new SqlParameter("@ItemCartId", itemDto.ItemCartId != null ? itemDto.ItemCartId : 0L),
new SqlParameter("@ItemNo", itemDto.ItemNo != null ? itemDto.ItemNo : 0L),
new SqlParameter("@UOMId", itemDto.UOMId),
new SqlParameter("@ItemColorId", itemDto.ItemColorId),
new SqlParameter("@ItemCategoryId", itemDto.ItemCategoryId),
new SqlParameter("@PackagingTypeId", itemDto.PackagingTypeId),
new SqlParameter("@ItemAttachId", itemDto.ItemAttachId),
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@ItemLocalId", itemDto.ItemLocalId));
return new ItemCart();
}
public async Task<List<ItemCart>> GetItemCart(ItemDto itemDto)
{
try
{
var allItems = await _dbContext.ItemCarts
.FromSqlRaw($"EXEC GetItemCart @UserId,@RequestTypeId,@IsCount",
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@RequestTypeId", itemDto.RequestTypeId),
new SqlParameter("@IsCount", itemDto.IsCount))
.ToListAsync();
var allItems = await _dbContext.ItemCarts
.FromSqlRaw($"EXEC GetItemCart @UserId,@RequestTypeId,@IsCount",
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@RequestTypeId", itemDto.RequestTypeId),
new SqlParameter("@IsCount", itemDto.IsCount))
.ToListAsync();
return allItems ?? new List<ItemCart>();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
return allItems ?? new List<ItemCart>();
}
public async Task<ItemCart> PostPurchRequest(ItemDto itemDto)
public async Task<ResponseObject> PostPurchRequest(ItemDto itemDto)
{
var (messCode, message) = OutputParamMessage.CreateOutputParams();
if (itemDto.RequestTypeId == 1)//Internal
{
itemDto.Status = 2;
itemDto.IsApproved = 2;
await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PostPutReqItems @UserId, @RequestItemId, @ItemNo, @QtyRequest,@Status,@IsApproved,@QtyReceived,@LotId," +
"@MessCode OUTPUT, @Message OUTPUT",
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@ItemNo", itemDto.ItemNo),
new SqlParameter("@RequestItemId", itemDto.RequestItemId != null ? itemDto.RequestItemId : 0L),
new SqlParameter("@QtyRequest", itemDto.Qty),
new SqlParameter("@Status", itemDto.Status),
new SqlParameter("@IsApproved", itemDto.IsApproved),
new SqlParameter("@QtyReceived", itemDto.QtyReceived),
new SqlParameter("@LotId", itemDto.LotId),
messCode,message);
}
else
{
await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PostPurchRequest @ItemCartId, @IsActive, @UserId,@ItemCount," +
"@PRNo,@DateNeeded,@Qty,@ChargeTo,@Remarks,@ProjectCodeId,@MessCode OUTPUT, @Message OUTPUT",
new SqlParameter("@ItemCartId", itemDto.ItemCartId != null ? itemDto.ItemCartId : 0L),
new SqlParameter("@IsActive", 1),
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@ItemCount", itemDto.ItemCount),
new SqlParameter("@PRNo", itemDto.PRNo),
new SqlParameter("@DateNeeded", itemDto.DateNeeded),
new SqlParameter("@Qty", itemDto.Qty),
new SqlParameter("@ChargeTo", itemDto.ChargeTo),
new SqlParameter("@Remarks", itemDto.Remarks ?? "N/A"),
new SqlParameter("@ProjectCodeId", itemDto.ProjectCodeId),
messCode, message);
}
return new ResponseObject() {
messCode= (byte)messCode.Value,
message= message.Value.ToString()
};
}
public async Task PostPutAttachment(AttachmentRequest attach)
{
var existing = await _dbContext.PRAttachments
.FirstOrDefaultAsync(a => a.PRId == attach.PRId);
if (existing == null)
{
var attchmnt = new PRAttachments()
{
FileName = attach.FileName,
OrigFileName = attach.OrigFileName,
PRId = attach.PRId
};
await _dbContext.PRAttachments.AddAsync(attchmnt);
}
else
{
existing.OrigFileName = attach.OrigFileName;
existing.FileName = Guid.NewGuid().ToString();
}
await _dbContext.SaveChangesAsync();
}
public async Task<(long,long)> GetPRNo()
{
try
{
if(itemDto.RequestTypeId == 1)//Internal
{
itemDto.Status = 2;
itemDto.IsApproved = 2;
await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PostPutReqItems @UserId, @RequestItemId, @ItemNo, @QtyRequest,@Status,@IsApproved,@QtyReceived,@LotId",
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@ItemNo", itemDto.ItemNo),
new SqlParameter("@RequestItemId", itemDto.RequestItemId != null ? itemDto.RequestItemId : 0L),
new SqlParameter("@QtyRequest", itemDto.Qty),
new SqlParameter("@Status", itemDto.Status),
new SqlParameter("@IsApproved", itemDto.IsApproved),
new SqlParameter("@QtyReceived", itemDto.QtyReceived),
new SqlParameter("@LotId", itemDto.LotId));
}
else
{
await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PostPurchRequest @ItemCartId, @IsActive, @UserId,@ItemCount,@PRNo,@DateNeeded,@Qty,@ChargeTo,@Remarks",
new SqlParameter("@ItemCartId", itemDto.ItemCartId != null ? itemDto.ItemCartId : 0L),
new SqlParameter("@IsActive", 1),
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@ItemCount", itemDto.ItemCount),
new SqlParameter("@PRNo", itemDto.PRNo),
new SqlParameter("@DateNeeded", itemDto.DateNeeded),
new SqlParameter("@Qty", itemDto.Qty),
new SqlParameter("@ChargeTo", itemDto.ChargeTo),
new SqlParameter("@Remarks", itemDto.Remarks));
}
return new ItemCart();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
}
public async Task<long> GetPRNo()
{
try
{
// Query the PRs table
var latestPR = await _dbContext.PRs
.OrderByDescending(ic => ic.PRNo) // Sort by PRNo in descending order
.FirstOrDefaultAsync(); // Retrieve the first record
.Where(ic => ic.PRNo != null)
.OrderByDescending(ic => ic.PRNo)
.FirstOrDefaultAsync();
if (latestPR != null)
{
return latestPR.PRNo;
}
return (latestPR.PRNo + 1,latestPR.PRId + 1);
else
{
return 0; // Example: Return 0 if no records found
}
return (0,0);
}
catch (SqlException ex)
catch (Exception ex)
{
// Handle the exception (log, rethrow, etc.)
ex.ToString();
throw;
}
}
Task<ItemCart> IItem.PostPutItemPath(ItemDto itemDto)
{
@ -372,38 +300,21 @@ namespace CPRNIMS.Domain.Services.Items
public async Task <List<Departments>> GetDepartment(ItemCodeDto itemCode)
{
try
{
var departments = await _dbContext.Departments
.Where(d => d.IsActive == true)
.ToListAsync();
return departments;
}
catch (Exception ex)
{
// Log the exception or handle it as needed
throw;
}
return await _dbContext.Departments
.Where(d => d.IsActive == true)
.ToListAsync();
}
public async Task<List<NotifUserKey>> GetNotifUserKey(ItemDto itemDto)
{
try
{
var allItems = await _dbContext.NotifUserKeys
.FromSqlRaw($"EXEC GetNotifUserKey @UserId,@Status,@PRDetailsId,@PRNo",
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@Status", itemDto.Status),
new SqlParameter("@PRDetailsId", itemDto.PRDetailsId),
new SqlParameter("@PRNo", itemDto.PRNo))
.ToListAsync();
var allItems = await _dbContext.NotifUserKeys
.FromSqlRaw($"EXEC GetNotifUserKey @UserId,@Status,@PRDetailsId,@PRNo",
new SqlParameter("@UserId", itemDto.UserId),
new SqlParameter("@Status", itemDto.Status),
new SqlParameter("@PRDetailsId", itemDto.PRDetailsId),
new SqlParameter("@PRNo", itemDto.PRNo))
.ToListAsync();
return allItems ?? new List<NotifUserKey>();
}
catch (SqlException ex)
{
ex.ToString();
throw;
}
return allItems ?? new List<NotifUserKey>();
}
}
}

View File

@ -2,7 +2,6 @@
using CPRNIMS.Infrastructure.Database;
using CPRNIMS.Infrastructure.Dto.PR;
using CPRNIMS.Infrastructure.Entities.Common;
using CPRNIMS.Infrastructure.Entities.PO;
using CPRNIMS.Infrastructure.Entities.Purchasing;
using CPRNIMS.Infrastructure.Entities.SMTP;
using Microsoft.Data.SqlClient;
@ -14,6 +13,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using CPRNIMS.Infrastructure.Models.Common;
namespace CPRNIMS.Domain.Services.PR
{
@ -297,7 +297,10 @@ namespace CPRNIMS.Domain.Services.PR
return allItems ?? new List<NotificationById>();
}
public async Task<List<ProjectCodes>> GetProjectCodes(PRDto pRDto)
{
return await _dbContext.ProjectCodes.ToListAsync();
}
public async Task<MessageResponse> PRItemRemoval(PRDto prDto)
{
var (messCode, message) = CreateOutputParams();
@ -318,6 +321,74 @@ namespace CPRNIMS.Domain.Services.PR
};
return response;
}
public async Task<ResponseObject> PostPutProjectCode(PRDto prDto)
{
if (prDto == null) throw new ArgumentNullException(nameof(prDto));
var existing = await _dbContext.ProjectCodes
.FirstOrDefaultAsync(p => p.ProjectCodeId == prDto.ProjectCodeId);
if (existing == null)
{
var project = new ProjectCodes
{
ProjectCode = prDto.ProjectCode,
ProjectName = prDto.ProjectName,
DeliveryAddress = prDto.DeliveryAddress,
MaxDays = prDto.MaxDays,
IsActive = prDto.IsActive
};
await _dbContext.ProjectCodes.AddAsync(project);
}
else
{
if (await IsUsingAsync(prDto.ProjectCodeId))
{
return new ResponseObject()
{
message = "Cannot update this project code because it is already being used in a Purchase Order (PO).",
messCode = 0,
success = false,
};
}
else
{
existing.ProjectCode = prDto.ProjectCode;
existing.ProjectName = prDto.ProjectName;
existing.DeliveryAddress = prDto.DeliveryAddress;
existing.MaxDays = prDto.MaxDays;
existing.IsActive = prDto.IsActive;
}
}
await _dbContext.SaveChangesAsync();
return new ResponseObject()
{
message = "Project code detail successfully updated",
messCode = 1,
success = true
};
}
private async Task<bool> IsUsingAsync(int projectCodeId)
{
try
{
return await (from pr in _dbContext.PRs
join pod in _dbContext.PODetails on pr.PRNo equals pod.PRNo
where pr.ProjectCodeId == projectCodeId
&& !pod.IsRemoved
&& pr.IsActive
select pr).AnyAsync();
}
catch (Exception ex)
{
ex.ToString();
throw;
}
}
#endregion
}
}

View File

@ -1,6 +1,4 @@
using CPRNIMS.Infrastructure.Dto.Items;
using CPRNIMS.Infrastructure.Models.Account;
using CPRNIMS.Infrastructure.ViewModel.Items;
using CPRNIMS.Infrastructure.Models.Account;
using CPRNIMS.Infrastructure.ViewModel.PR;
using System;
using System.Collections.Generic;
@ -12,6 +10,7 @@ namespace CPRNIMS.Domain.UIContracts.PR
{
public interface IPRequest
{
#region Get
Task<List<PRVM>?> GetApproverName(User user, PRVM viewModels);
Task<List<PRVM>> GetForReceiving(User user, PRVM viewModel);
Task<List<PRVM>> GetItemDetailForReceiving(User user, PRVM viewModel);
@ -27,6 +26,9 @@ namespace CPRNIMS.Domain.UIContracts.PR
Task<List<PRVM>?> GetDetailedPRTracking(User user, PRVM viewModel);
Task<List<PRVM>?> GetSupplierAlternativeOffer(User user, PRVM viewModel);
Task<List<PRVM>?> GetSupplierAlterOfferDetails(User user, PRVM viewModel);
Task<List<PRVM>?> GetProjectCodes(User user, PRVM viewModels);
#endregion
#region Post Put
Task<PRVM> PostPRApproveReject(User user, PRVM viewModel);
Task<PRVM> PostPutItemReceiving(User user, PRVM viewModel);
Task<PRVM> PutItemDetail(User user, PRVM viewModel);
@ -37,5 +39,7 @@ namespace CPRNIMS.Domain.UIContracts.PR
Task<PRVM> PutSupplierAlterOffer(User user, PRVM viewModel);
Task<PRVM> PRItemRemoval(User user, PRVM viewModel);
Task<PRVM> ApprovedSelectedPRItem(User user, PRVM viewModel);
Task<PRVM> PostPutProjectCode(User user, PRVM viewModel);
#endregion
}
}

View File

@ -116,6 +116,11 @@ namespace CPRNIMS.Domain.UIServices.PR
}
#endregion
#region Get
public async Task<List<PRVM>?> GetProjectCodes(User user, PRVM viewModel)
{
return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:PRMgmt:GetProjectCodes"]);
}
public async Task<List<PRVM>?> GetApproverName(User user, PRVM viewModel)
{
return await SendGetApiRequest(user, viewModel,
@ -253,6 +258,12 @@ namespace CPRNIMS.Domain.UIServices.PR
return await SendPostApiRequest(user, viewModel,
_configuration["LLI:NonInvent:PRMgmt:ApprovedSelectedPRItem"]);
}
public async Task<PRVM> PostPutProjectCode(User user, PRVM viewModel)
{
return await SendPostApiRequest(user, viewModel,
_configuration["LLI:NonInvent:PRMgmt:PostPutProjectCode"]);
}
#endregion
}
}

View File

@ -47,6 +47,8 @@ namespace CPRNIMS.Infrastructure.Database
public virtual DbSet<SMTPCredential> SMTPCredentials { get; set; }
public virtual DbSet<PRDetails> PRDetails { get; set; }
public virtual DbSet<PRItemList> PRItemLists { get; set; }
public DbSet<PRAttachments> PRAttachments { get; set; }
public DbSet<ProjectCodes> ProjectCodes { get; set; }
public virtual DbSet<NotificationById> NotificationByIds { get; set; }
public virtual DbSet<AlternativeOffer> AlternativeOffers { get; set; }
public virtual DbSet<AlternativeOfferDetails> AlternativeOfferDetails { get; set; }
@ -84,6 +86,7 @@ namespace CPRNIMS.Infrastructure.Database
public virtual DbSet<ApprovedPO> ApprovedPOs { get; set; }
public virtual DbSet<PurchaseOrder> PurchaseOrders { get; set; }
public virtual DbSet<PO> POs { get; set; }
public DbSet<PODetails> PODetails { get; set; }
public virtual DbSet<PRPOSummaryCount> PRPOSummaryCounts { get; set; }
public virtual DbSet<PRPOSummaryItem> PRPOSummaryItems { get; set; }
public virtual DbSet<POItemDetail> POItemDetails { get; set; }
@ -117,6 +120,7 @@ namespace CPRNIMS.Infrastructure.Database
#region Automation Part
public virtual DbSet<AllForCanvass> AllForCanvasses { get; set; }
public DbSet<ErrorLog> ErrorLogs { get; set; }
#endregion
protected override void OnModelCreating(ModelBuilder modelBuilder)
{

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Items
{
public class AttachmentRequest
{
public long PRId { get; set; }
public string? FileName { get; set; }
public string? OrigFileName { get; set; }
}
}

View File

@ -8,7 +8,8 @@ namespace CPRNIMS.Infrastructure.Dto.Items
{
public class ItemCartDto
{
public List<long>? ItemCartIds { get; set; }
public List<int>? Qty { get; set; }
public long ItemCartId { get; set; }
public long ItemNo { get; set; }
public decimal Qty { get; set; }
}
}

View File

@ -20,6 +20,7 @@ namespace CPRNIMS.Infrastructure.Dto.Items
public string? ItemName { get; set; }
public string? ItemDescription { get; set; }
public string? UserId { get; set; }
public string? FileName { get; set; }
public short Status { get; set; }
public bool IsActive { get; set; }
}

View File

@ -115,5 +115,9 @@ namespace CPRNIMS.Infrastructure.Dto.Items
public DateTime DateFrom { get; set; }
public DateTime DateTo { get; set; }
public bool IsSorting { get; set; }=false;
public int ProjectCodeId { get; set; }
public long PRId { get; set; }
public string? FileName { get; set; }
public string? OrigFileName { get; set; }
}
}

View File

@ -125,5 +125,14 @@ namespace CPRNIMS.Infrastructure.Dto.PR
public bool IsApproved { get; set; }=false;
public int AlternativeOfferId { get; set; }
public byte AppsModuleId { get; set; }
public int ProjectCodeId { get; set; }
public string? ProjectCode { get; set; }
public string? ProjectName { get; set; }
public int MaxDays { get; set; }
public string? DeliveryAddress { get; set; }
public int PRAttachmentId { get; set; }
public long PRId { get; set; }
public string? FileName { get; set; }
public string? OrigFileName { get; set; }
}
}

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Entities.Common
{
public class ErrorLog
{
public Guid Id { get; set; }
public string Path { get; set; } = default!;
public string HttpMethod { get; set; } = default!;
public string? QueryString { get; set; }
public int StatusCode { get; set; }
public string ExceptionType { get; set; } = default!;
public string Message { get; set; } = default!;
public string? StackTrace { get; set; }
public string? UserId { get; set; }
public string? IpAddress { get; set; }
public DateTime CreatedAt { get; set; }
}
}

View File

@ -0,0 +1,20 @@
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.PO
{
[Table("PODetails")]
public class PODetails
{
[Key]
public long PODetailId { get; set; }
public long POId { get; set; }
public long PRNo { get; set; }
public bool IsRemoved { get; set; }
}
}

View File

@ -17,10 +17,9 @@ namespace CPRNIMS.Infrastructure.Entities.Purchasing
public long PRId { get; set; }
public long PRNo { get; set; }
public string? NewPRNo { get; set; }
//public long ItemCodeId { get; set; }
public int ProjectCodeId { get; set; }
public long ItemCartId { get; set; }
public string? UserId { get; set; }
public int ItemCount { get; set; }
public bool IsActive { get; set; }
}
}

View File

@ -0,0 +1,20 @@
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
{
[Table("PRAttachments")]
public class PRAttachments
{
[Key]
public int PRAttachmentId { get; set; }
public long PRId { get; set; }
public string? FileName { get; set; }
public string? OrigFileName { get; set; }
}
}

View File

@ -37,5 +37,6 @@ namespace CPRNIMS.Infrastructure.Entities.Purchasing
public bool Queue { get; set; }
public string? AttestedBy { get; set; }
public string? ApprovedBy { get; set; }
public string? ProjectCode { get; set; }
}
}

View File

@ -0,0 +1,22 @@
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
{
[Table("ProjectCodes")]
public class ProjectCodes
{
[Key]
public int ProjectCodeId { get; set; }
public string? ProjectCode { get; set; }
public string? ProjectName { get; set; }
public int MaxDays { get; set; }
public string? DeliveryAddress { get; set; }
public bool IsActive { get; set; }
}
}

View File

@ -44,6 +44,7 @@ namespace CPRNIMS.Infrastructure.ViewModel.Items
public string? ItemAttachPath { get; set; }
public int CartItemCount { get; set; }
public int ItemCartId { get; set; }
public string? ItemCartIds { get; set; }
public long ItemAttachId { get; set; }
public decimal QtyRequest { get; set; }
public byte IsApproved { get; set; }
@ -54,5 +55,10 @@ namespace CPRNIMS.Infrastructure.ViewModel.Items
public bool IsMDLD { get; set; } = false;
public bool CheckBox { get; set; }
public bool IsCount { get; set; }
public int ProjectCodeId { get; set; }
public string? FileName { get; set; }
public long PRId { get; set; }
public string? ProjectCode { get; set; }
public string? OrigFileName { get; set; }
}
}

View File

@ -123,6 +123,15 @@ namespace CPRNIMS.Infrastructure.ViewModel.PR
public string? Description { get; set; }
public int AlternativeOfferId { get; set; }
public string? AggreDescription { get; set; }
public string? ProjectCode { get; set; }
public int ProjectCodeId { get; set; }
public string? ProjectName { get; set; }
public int MaxDays { get; set; }
public string? DeliveryAddress { get; set; }
public int PRAttachmentId { get; set; }
public long PRId { get; set; }
public string? FileName { get; set; }
public string? OrigFileName { get; set; }
public ItemReceivingList? ItemList { get; set; }
public PRList? PRList { get; set; }
}

View File

@ -146,4 +146,9 @@
</Content>
</ItemGroup>
<ItemGroup>
<Folder Include="Helper\" />
<Folder Include="wwwroot\Content\Uploads\PRAttachment\" />
</ItemGroup>
</Project>

View File

@ -31,13 +31,13 @@ namespace CPRNIMS.WebApi.Controllers.Account
private readonly UserClaimsManager _userClaimsManager;
private readonly RoleManager<IdentityRole> _roleManager;
public AccountController(ErrorMessageService errorMessageService,
IWebHostEnvironment webHostEnvironment, SMTPHelper sMTPHelper,
IWebHostEnvironment webHostEnvironment,
IConfiguration configuration,
IAttachment attachment, IAccount account, IDepartment department, IControllerAccess controllerAccess,
UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager,
UserClaimsManager userClaimsManager, RoleManager<IdentityRole> roleManager
) :
base(errorMessageService, webHostEnvironment, sMTPHelper, configuration)
base(errorMessageService, webHostEnvironment, configuration)
{
_errorMessageService = errorMessageService;
_attachment = attachment;

View File

@ -28,7 +28,7 @@ namespace CPRNIMS.WebApi.Controllers.Account
SignInManager<ApplicationUser> signInManager,
UserManager<ApplicationUser> userManager
)
: base(errorMessageService, webHostEnvironment, sMTPHelper, configuration)
: base(errorMessageService, webHostEnvironment, configuration)
{
_config = configuration;
_smtpHelper = sMTPHelper;

View File

@ -13,11 +13,11 @@ namespace CPRNIMS.WebApi.Controllers.Base
[ApiController]
public class BaseController : ControllerBase
{
private readonly IWebHostEnvironment _webHostEnvironment;
public readonly IWebHostEnvironment _webHostEnvironment;
public readonly ErrorMessageService ErrorMessageService;
public IConfiguration _configuration;
public BaseController(ErrorMessageService errorMessageService,
IWebHostEnvironment webHostEnvironment, Infrastructure.Helper.SMTPHelper sMTPHelper, IConfiguration configuration)
IWebHostEnvironment webHostEnvironment, IConfiguration configuration)
{
ErrorMessageService = errorMessageService;
_webHostEnvironment = webHostEnvironment;

View File

@ -21,7 +21,7 @@ namespace CPRNIMS.WebApi.Controllers.Canvass
public CanvassMgmtController(ErrorMessageService errorMessageService,
IWebHostEnvironment webHostEnvironment, SMTPHelper sMTPHelper,
IConfiguration configuration, ICanvass canvass) :
base(errorMessageService, webHostEnvironment, sMTPHelper, configuration)
base(errorMessageService, webHostEnvironment, configuration)
{
_canvass = canvass;
_config = configuration;

View File

@ -17,9 +17,9 @@ namespace CPRNIMS.WebApi.Controllers.Finance
private readonly IRR _rr;
public RRMgmtController(ErrorMessageService errorMessageService,
IWebHostEnvironment webHostEnvironment, SMTPHelper sMTPHelper,
IConfiguration configuration, SMTPHelper smptHelper, IRR rr) :
base(errorMessageService, webHostEnvironment, sMTPHelper, configuration)
IWebHostEnvironment webHostEnvironment,
IConfiguration configuration, IRR rr) :
base(errorMessageService, webHostEnvironment, configuration)
{
_rr = rr;
}

View File

@ -17,9 +17,9 @@ namespace CPRNIMS.WebApi.Controllers.Inventory
private readonly IInventory _inventory;
public InventoryMgmtController(ErrorMessageService errorMessageService,
IWebHostEnvironment webHostEnvironment, SMTPHelper sMTPHelper, IConfiguration configuration,
IWebHostEnvironment webHostEnvironment, IConfiguration configuration,
IInventory inventory) :
base(errorMessageService, webHostEnvironment, sMTPHelper, configuration)
base(errorMessageService, webHostEnvironment,configuration)
{
_inventory = inventory;
}

View File

@ -2,6 +2,7 @@
using CPRNIMS.Domain.Contracts.SMTP;
using CPRNIMS.Domain.Services;
using CPRNIMS.Infrastructure.Dto.Items;
using CPRNIMS.Infrastructure.Entities.Items;
using CPRNIMS.Infrastructure.Helper;
using CPRNIMS.Infrastructure.Models.Common;
using CPRNIMS.Infrastructure.ViewModel.Common;
@ -17,13 +18,15 @@ namespace CPRNIMS.WebApi.Controllers.Items
{
private readonly IItem _item;
private readonly IConfiguration _config;
private readonly SMTPHelper _smtpHelper;
public ItemMgmtController(ErrorMessageService errorMessageService,
IWebHostEnvironment webHostEnvironment, SMTPHelper sMTPHelper,
IWebHostEnvironment webHostEnvironment, SMTPHelper smtpHelper,
IConfiguration configuration, IItem item) :
base(errorMessageService, webHostEnvironment, sMTPHelper, configuration)
base(errorMessageService, webHostEnvironment, configuration)
{
_config = configuration;
_item= item;
_smtpHelper = smtpHelper;
}
[HttpPost("PostPutItemPath")]
@ -54,76 +57,91 @@ namespace CPRNIMS.WebApi.Controllers.Items
[HttpPost("PostPurchRequest")]
public async Task<IActionResult> PostPurchRequest([FromBody] ItemVM viewModel)
{
try
if (viewModel?.ItemCartVM == null)
return BadRequest("Invalid request.");
if (viewModel.ItemCartVM.ItemCartId.Count != viewModel.ItemCartVM.Qty.Count ||
viewModel.ItemCartVM.ItemCartId.Count != viewModel.ItemCartVM.ItemNo.Count)
{
// Check if ItemCartId, Qty, and ItemNo are null or not of the same length
if (viewModel.ItemCartVM.ItemCartId == null ||
viewModel.ItemCartVM.Qty == null ||
viewModel.ItemCartVM.ItemNo == null)
return BadRequest("ItemCartId, Qty, and ItemNo length mismatch.");
}
var result = await ProcessPurchaseRequest(viewModel);
return Ok(new { success = result });
}
private async Task<ItemDto> ProcessPurchaseRequest(ItemVM viewModel)
{
var (prNo,prId) = await _item.GetPRNo();
bool IsSuccess = false;
int itemCount = viewModel.ItemCartVM.ItemCartId.Count;
var dto = new ItemDto();
for (int i = 0; i < itemCount; i++)
{
dto = new ItemDto
{
throw new ArgumentNullException("One or more lists in ItemCartVM are null");
}
if (viewModel.ItemCartVM.ItemCartId.Count != viewModel.ItemCartVM.Qty.Count ||
viewModel.ItemCartVM.ItemCartId.Count != viewModel.ItemCartVM.ItemNo.Count)
{
throw new ArgumentException("The lengths of ItemCartId, Qty, and ItemNo must be the same");
}
viewModel.ItemCount = viewModel.ItemCartVM.ItemCartId.Count;
long prNo = await _item.GetPRNo();
var itemDto = new ItemDto();
// Process each item in the ItemCartVM
foreach (var itemCartId in viewModel.ItemCartVM.ItemCartId)
{
var index = viewModel.ItemCartVM.ItemCartId.IndexOf(itemCartId);
itemDto.ItemCartId = itemCartId;
itemDto.Qty = viewModel.ItemCartVM.Qty[index];
itemDto.ItemNo = viewModel.ItemCartVM.ItemNo[index];
itemDto.ItemCount = viewModel.ItemCount;
itemDto.RequestTypeId = viewModel.RequestTypeId;
itemDto.UserId = viewModel.UserId;
itemDto.PRNo = prNo + 1;
itemDto.DateNeeded = viewModel.DateNeeded;
itemDto.ChargeTo = viewModel.ChargeTo;
itemDto.Remarks = viewModel.Remarks;
await _item.PostPurchRequest(itemDto);
}
var getNotif = await _item.GetNotifUserKey(itemDto);
var baseTemplate = EMailTemplate("Content\\SMTPEmailContent", "NewPR.cshtml");
// Make a fresh copy of the template for each item
var message = new StringBuilder(baseTemplate);
message.Replace("@ViewBag.PRNo", itemDto.PRNo.ToString());
message.Replace("@ViewBag.Signature", getNotif[0].FullName);
var messageDetails = new EmailMessageDetailsVM
{
Recipient = getNotif[0].Email,
Bcc = getNotif[0].RequestorEmail,
CC = _config["SMTP:CC"] + getNotif[0].RequestorEmail,
Message = message.ToString(),
Subject = "Non-Inventory - New PR Created #: " + itemDto.PRNo.ToString(),
SenderEmail = _configuration["SMTP:SenderEmail"],
DisplayName = _configuration["SMTP:DisplayName"],
NewPassword = _configuration["SMTP:Password"],
OutGoingPort = 587,
Server = _configuration["SMTP:Server"],
UserName = _configuration["SMTP:UserName"],
ItemCartId = viewModel.ItemCartVM.ItemCartId[i],
Qty = viewModel.ItemCartVM.Qty[i],
ItemNo = viewModel.ItemCartVM.ItemNo[i],
ItemCount = itemCount,
RequestTypeId = viewModel.RequestTypeId,
UserId = viewModel.UserId,
PRNo = prNo,
DateNeeded = viewModel.DateNeeded,
ChargeTo = viewModel.ChargeTo,
Remarks = viewModel.Remarks,
ProjectCodeId = viewModel.ProjectCodeId,
FileName=viewModel.FileName,
OrigFileName = viewModel.OrigFileName,
PRId= viewModel.PRId != null ? prId : 0L
};
// await _smptHelper.SendEmailAsync(messageDetails);
return Ok(new { success = true });
var response = await _item.PostPurchRequest(dto);
if (response.messCode == 1)
IsSuccess = true;
}
catch (Exception ex)
if (IsSuccess)
{
var message = ex.InnerException?.ToString() ?? ex.Message;
await PostErrorMessage(message, "WebApi");
return StatusCode(500, new { success = false, message });
var attachment = new AttachmentRequest()
{
FileName = dto.FileName,
OrigFileName = dto.OrigFileName,
PRId = dto.PRId
};
await _item.PostPutAttachment(attachment);
// await SendNotificationEmail(dto);
}
return dto;
}
private async Task SendNotificationEmail(ItemDto itemDto)
{
var getNotif = await _item.GetNotifUserKey(itemDto);
var baseTemplate = EMailTemplate("Content\\SMTPEmailContent", "NewPR.cshtml");
// Make a fresh copy of the template for each item
var message = new StringBuilder(baseTemplate);
message.Replace("@ViewBag.PRNo", itemDto.PRNo.ToString());
message.Replace("@ViewBag.Signature", getNotif[0].FullName);
var messageDetails = new EmailMessageDetailsVM
{
Recipient = getNotif[0].Email,
Bcc = getNotif[0].RequestorEmail,
CC = _config["SMTP:CC"] + getNotif[0].RequestorEmail,
Message = message.ToString(),
Subject = "Non-Inventory - New PR Created #: " + itemDto.PRNo.ToString(),
SenderEmail = _configuration["SMTP:SenderEmail"],
DisplayName = _configuration["SMTP:DisplayName"],
NewPassword = _configuration["SMTP:Password"],
OutGoingPort = 587,
Server = _configuration["SMTP:Server"],
UserName = _configuration["SMTP:UserName"],
};
await _smtpHelper.SendEmailAsync(messageDetails);
}
[HttpPost("PostPutItem")]

View File

@ -24,7 +24,7 @@ namespace CPRNIMS.WebApi.Controllers.PO
public POMgmtController(ErrorMessageService errorMessageService,
IWebHostEnvironment webHostEnvironment, SMTPHelper sMTPHelper,
IConfiguration configuration, ISMTP sMTP, IPurchaseOrder purchaseOrder) :
base(errorMessageService, webHostEnvironment, sMTPHelper, configuration)
base(errorMessageService, webHostEnvironment, configuration)
{
_smtpHelper = sMTPHelper;
_sMTP= sMTP;

View File

@ -1,10 +1,16 @@
using CPRNIMS.Domain.Contracts.PR;
using CPRNIMS.Domain.Services;
using CPRNIMS.Infrastructure.Dto.PO;
using CPRNIMS.Infrastructure.Dto.PR;
using CPRNIMS.Infrastructure.Entities.PO;
using CPRNIMS.Infrastructure.Entities.Purchasing;
using CPRNIMS.Infrastructure.Helper;
using CPRNIMS.Infrastructure.Models.Common;
using CPRNIMS.Infrastructure.ViewModel.Common;
using CPRNIMS.Infrastructure.ViewModel.PR;
using CPRNIMS.WebApi.Controllers.Base;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;
using System.Text;
@ -21,7 +27,7 @@ namespace CPRNIMS.WebApi.Controllers.PR
public PRMgmtController(ErrorMessageService errorMessageService,
IWebHostEnvironment webHostEnvironment, SMTPHelper sMTPHelper,
IConfiguration configuration, IPRequest pRequest) :
base(errorMessageService, webHostEnvironment, sMTPHelper, configuration)
base(errorMessageService, webHostEnvironment, configuration)
{
_config = configuration;
_smptHelper = sMTPHelper;
@ -261,8 +267,23 @@ namespace CPRNIMS.WebApi.Controllers.PR
return Ok(new { success = false, messCode = 0, message = errorMessage });
}
}
[HttpPost("PostPutProjectCode")]
public async Task<IActionResult> PostPutProjectCode([FromBody] PRDto prDto)
{
var results = await _pRequest.PostPutProjectCode(prDto);
return Ok( new { data = results, message =results.message, messCode=results.messCode });
}
#endregion
#region Get
[HttpPost("GetProjectCodes")]
public async Task<IActionResult> GetProjectCodes(PRDto PRDto)
{
return await ExecuteWithErrorHandling(
() => _pRequest.GetProjectCodes(PRDto),
nameof(GetProjectCodes), false
);
}
[HttpPost("GetApproverName")]
public async Task<IActionResult> GetApproverName(PRDto PRDto)
{

View File

@ -6,6 +6,7 @@ using CPRNIMS.Infrastructure.Helper;
using CPRNIMS.Infrastructure.ViewModel.Receiving;
using CPRNIMS.WebApi.Controllers.Base;
using Microsoft.AspNetCore.Mvc;
using System.Runtime.InteropServices;
using System.Text;
namespace CPRNIMS.WebApi.Controllers.Receiving
@ -17,9 +18,9 @@ namespace CPRNIMS.WebApi.Controllers.Receiving
private readonly IItem _item;
public ReceivingController(ErrorMessageService errorMessageService,
IWebHostEnvironment webHostEnvironment, SMTPHelper sMTPHelper,
IWebHostEnvironment webHostEnvironment,
IConfiguration configuration, IReceiving receiving, IItem item) :
base(errorMessageService, webHostEnvironment, sMTPHelper, configuration)
base(errorMessageService, webHostEnvironment, configuration)
{
_receiving = receiving;
_item= item;
@ -68,7 +69,7 @@ namespace CPRNIMS.WebApi.Controllers.Receiving
{
try
{
long prNo = await _item.GetPRNo();
var (prNo,prId) = await _item.GetPRNo();
foreach (var items in viewModel.ItemList.PRDetailsId)
{
var index = viewModel.ItemList.PRDetailsId.IndexOf(items);

View File

@ -14,9 +14,9 @@ namespace CPRNIMS.WebApi.Controllers.SMTP
{
private readonly ISMTP _sMTP;
public SMTPMgmtController(ErrorMessageService errorMessageService,
IWebHostEnvironment webHostEnvironment, SMTPHelper sMTPHelper,
IWebHostEnvironment webHostEnvironment,
IConfiguration configuration, ISMTP sMTP) :
base(errorMessageService, webHostEnvironment, sMTPHelper, configuration)
base(errorMessageService, webHostEnvironment, configuration)
{
_sMTP = sMTP;
}

View File

@ -0,0 +1,13 @@
namespace CPRNIMS.WebApi.Exceptions
{
public class AppException : Exception
{
public int StatusCode { get; }
public AppException(string message, int statusCode = StatusCodes.Status400BadRequest)
: base(message)
{
StatusCode = statusCode;
}
}
}

View File

@ -0,0 +1,89 @@
using CPRNIMS.Infrastructure.Database;
using CPRNIMS.Infrastructure.Entities.Common;
using CPRNIMS.WebApi.Exceptions;
using System.Security.Claims;
using System.Text.Json;
namespace CPRNIMS.Middleware
{
public sealed class GlobalExceptionMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<GlobalExceptionMiddleware> _logger;
private readonly IWebHostEnvironment _env;
private readonly IServiceScopeFactory _scopeFactory;
public GlobalExceptionMiddleware(
RequestDelegate next,
ILogger<GlobalExceptionMiddleware> logger,
IWebHostEnvironment env,
IServiceScopeFactory scopeFactory)
{
_next = next;
_logger = logger;
_env = env;
_scopeFactory = scopeFactory;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
_logger.LogError(ex, "Unhandled exception");
await LogToDatabaseAsync(context, ex);
await HandleResponseAsync(context, ex);
}
}
private async Task LogToDatabaseAsync(HttpContext context, Exception ex)
{
using var scope = _scopeFactory.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<NonInventoryDbContext>();
var errorLog = new ErrorLog
{
Id = Guid.NewGuid(),
Path = context.Request.Path,
HttpMethod = context.Request.Method,
QueryString = context.Request.QueryString.Value,
StatusCode = context.Response.StatusCode,
ExceptionType = ex.GetType().FullName!,
Message = ex.Message,
StackTrace = ex.StackTrace,
UserId = context.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value,
IpAddress = context.Connection.RemoteIpAddress?.ToString(),
CreatedAt = DateTime.UtcNow
};
db.ErrorLogs.Add(errorLog);
await db.SaveChangesAsync();
}
private async Task HandleResponseAsync(HttpContext context, Exception ex)
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = ex switch
{
AppException app => app.StatusCode,
ArgumentException => StatusCodes.Status400BadRequest,
UnauthorizedAccessException => StatusCodes.Status401Unauthorized,
_ => StatusCodes.Status500InternalServerError
};
var response = new
{
success = false,
message = _env.IsDevelopment()
? ex.Message
: "An unexpected error occurred"
};
await context.Response.WriteAsync(JsonSerializer.Serialize(response));
}
}
}

View File

@ -1,3 +1,4 @@
using CPRNIMS.Middleware;
using CPRNIMS.WebApi.Common;
var builder = WebApplication.CreateBuilder(args);
@ -15,6 +16,7 @@ if (app.Environment.IsDevelopment())
c.SwaggerEndpoint("./v2/swagger.json", "LLOYD API V2"); //originally "./swagger/v1/swagger.json"
});
}
app.UseMiddleware<GlobalExceptionMiddleware>();
app.UseSwagger();
app.UseSwaggerUI(c =>
{

View File

@ -1,4 +1,22 @@
CREATE TABLE [dbo].[ControllerAccessDesc](
CREATE TABLE ProjectCodes(
ProjectCodeId INT PRIMARY KEY IDENTITY(1,1),
ProjectCode VARCHAR(50) NOT NULL,
ProjectName VARCHAR(200) NOT NULL,
MaxDays INT NOT NULL,
DeliveryAddress VARCHAR(300) NOT NULL,
IsActive BIT DEFAULT(1)
)
CREATE TABLE PRAttachments(
PRAttachmentId INT PRIMARY KEY IDENTITY(1,1),
PRId BIGINT,
OrigFileName VARCHAR(450),
FileName NVARCHAR(450),
FOREIGN KEY (PRId) REFERENCES PR (PRId)
);
ALTER TABLE PR
ADD ProjectCodeId INT DEFAULT 0;
CREATE TABLE [dbo].[ControllerAccessDesc](
[ContAccId] [int] IDENTITY(1,1) PRIMARY KEY NOT NULL,
[Action] [varchar](150) NOT NULL,
[Controller] [varchar](150) NOT NULL,

View File

@ -41,7 +41,7 @@
<Content Update="wwwroot\Content\Images\UserProfile\2e446d27-a03d-4024-832e-3f9c50f245f5.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\css\Item\cart.css">
<Content Update="wwwroot\css\Item\cartV2.css">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\GoogleSecurity\credentials.json">
@ -60,6 +60,7 @@
<Folder Include="Common\Helper\" />
<Folder Include="Properties\NewFolder\" />
<Folder Include="Views\Components\CanvassMgmt\" />
<Folder Include="wwwroot\Content\Uploads\PRAttachment\" />
</ItemGroup>
<ItemGroup>

View File

@ -13,7 +13,7 @@ namespace CPRNIMS.WebApps.Controllers.Account
List<UserRightsVM>? response;
public AccountController(IWebHostEnvironment webHostEnvironment,
IAccount account,ErrorLogHelper errorMessageService,TokenHelper tokenHelper
) : base(errorMessageService, webHostEnvironment,tokenHelper)
) : base(errorMessageService, webHostEnvironment,tokenHelper, account)
{
_account = account;
}

View File

@ -1,4 +1,5 @@
using CPRNIMS.Core.Facades;
using CPRNIMS.Domain.UIContracts.Account;
using CPRNIMS.Infrastructure.Constant;
using CPRNIMS.Infrastructure.Helper;
using CPRNIMS.Infrastructure.ViewModel;
@ -12,17 +13,19 @@ namespace CPRNIMS.WebApps.Controllers.Base
public abstract class BaseMethod : BaseProperties
{
protected readonly ErrorLogHelper ErrorMessageService;
protected readonly IWebHostEnvironment WebHostEnvironment;
public readonly IWebHostEnvironment _webHostEnvironment;
protected readonly Infrastructure.Helper.TokenHelper TokenHelper;
private readonly IAccount _account;
protected BaseMethod(
ErrorLogHelper errorMessageService,
IWebHostEnvironment webHostEnvironment,
Infrastructure.Helper.TokenHelper tokenHelper)
Infrastructure.Helper.TokenHelper tokenHelper,
IAccount account)
{
ErrorMessageService = errorMessageService;
WebHostEnvironment = webHostEnvironment;
_webHostEnvironment = webHostEnvironment;
TokenHelper = tokenHelper;
_account = account;
}
protected Infrastructure.Models.Account.User GetUser()
@ -74,9 +77,34 @@ namespace CPRNIMS.WebApps.Controllers.Base
return RedirectToAction("Index", "Home");
PopulateViewBagFromClaims();
if(!await PopulateSidebarAsync())
{
return RedirectToAction("Logout", "Home");
}
return View();
}
private async Task<bool> PopulateSidebarAsync()
{
try
{
if (!string.IsNullOrEmpty(ViewBag.UserRoles))
{
var myControllerAccess = await _account.GetLandingPageByUserId(GetUser());
// Group by menu name
ViewBag.TempDataElements = myControllerAccess
.GroupBy(e => e.ElementMenuName)
.ToList();
}
return true;
}
catch (Exception)
{
return false;
}
}
protected void PopulateViewBagFromClaims()
{
if (!User.Identity?.IsAuthenticated ?? true)
@ -90,7 +118,6 @@ namespace CPRNIMS.WebApps.Controllers.Base
User.FindAll(ClaimTypes.Role).Select(c => c.Value));
ViewBag.URLAttachment = User.FindFirst("URLAttachment")?.Value ?? "Content/Images/UserProfile/404userImage.jpg";
}
protected IActionResult GetResponse<T>(T response)
{
return Json(new
@ -142,12 +169,12 @@ namespace CPRNIMS.WebApps.Controllers.Base
var fileName = $"{Guid.NewGuid()}.{imageFormat.Name.ToLower()}";
var filePath = Path.Combine(
WebHostEnvironment.WebRootPath,
_webHostEnvironment.WebRootPath,
FileExtensionPath.GetExtensionPath(imageFormat.Name.ToLower()),
fileName);
var relativePath =
Path.GetRelativePath(WebHostEnvironment.WebRootPath, filePath);
Path.GetRelativePath(_webHostEnvironment.WebRootPath, filePath);
return facadeAttachment.SaveAttachment(
contentBytes,

View File

@ -1,4 +1,5 @@
using CPRNIMS.Domain.UIContracts.Canvass;
using CPRNIMS.Domain.UIContracts.Account;
using CPRNIMS.Domain.UIContracts.Canvass;
using CPRNIMS.Infrastructure.Helper;
using CPRNIMS.Infrastructure.ViewModel.Canvass;
using CPRNIMS.WebApps.Controllers.Base;
@ -12,9 +13,9 @@ namespace CPRNIMS.WebApps.Controllers.Canvass
private readonly ICanvass _canvass;
public CanvassMgmtController(TokenHelper tokenHelper, ErrorLogHelper errorMessageService,
IWebHostEnvironment webHostEnvironment
, ICanvass canvass
, ICanvass canvass,IAccount account
)
: base(errorMessageService, webHostEnvironment, tokenHelper)
: base(errorMessageService, webHostEnvironment, tokenHelper, account)
{
_canvass = canvass;
}

View File

@ -1,4 +1,5 @@
using CPRNIMS.Domain.UIContracts.Finance;
using CPRNIMS.Domain.UIContracts.Account;
using CPRNIMS.Domain.UIContracts.Finance;
using CPRNIMS.Infrastructure.Helper;
using CPRNIMS.Infrastructure.ViewModel.Finance;
using CPRNIMS.Infrastructure.ViewModel.PR;
@ -13,8 +14,8 @@ namespace CPRNIMS.WebApps.Controllers.Finance
private readonly IRR _rr;
public RRMgmtController(ErrorLogHelper errorMessageService,
IWebHostEnvironment webHostEnvironment, TokenHelper tokenHelper
, IRR pRequest)
: base(errorMessageService, webHostEnvironment, tokenHelper)
, IRR pRequest,IAccount account)
: base(errorMessageService, webHostEnvironment, tokenHelper, account)
{
_rr = pRequest;
}
@ -82,8 +83,7 @@ namespace CPRNIMS.WebApps.Controllers.Finance
#region Views
public async Task<IActionResult> Index()
{
await IsAuthenTicated();
return View();
return await IsAuthenTicated();
}
#endregion
}

View File

@ -29,7 +29,7 @@ namespace CPRNIMS.WebApps.Controllers
IWebHostEnvironment webHostEnvironment,
IAttachment attachment, IAccount account,
ICaptchaService captchaService) :
base(errorMessageService, webHostEnvironment,tokenHelper)
base(errorMessageService, webHostEnvironment,tokenHelper,account)
{
_account = account;
_attachment = attachment;

View File

@ -1,4 +1,5 @@
using CPRNIMS.Domain.UIContracts.Inventory;
using CPRNIMS.Domain.UIContracts.Account;
using CPRNIMS.Domain.UIContracts.Inventory;
using CPRNIMS.Infrastructure.Helper;
using CPRNIMS.Infrastructure.ViewModel.Account;
using CPRNIMS.Infrastructure.ViewModel.Finance;
@ -16,8 +17,8 @@ namespace CPRNIMS.WebApps.Controllers.Inventory
private readonly IInventory _inventory;
public InventoryMgmtController(ErrorLogHelper errorMessageService,
IWebHostEnvironment webHostEnvironment, TokenHelper tokenHelper
, IInventory inventory)
: base(errorMessageService, webHostEnvironment, tokenHelper)
, IInventory inventory,IAccount account)
: base(errorMessageService, webHostEnvironment, tokenHelper, account)
{
_inventory = inventory;
}
@ -180,18 +181,15 @@ namespace CPRNIMS.WebApps.Controllers.Inventory
#region Views
public async Task<IActionResult> Inventory()
{
await IsAuthenTicated();
return View();
return await IsAuthenTicated();
}
public async Task<IActionResult> Lot()
{
await IsAuthenTicated();
return View();
return await IsAuthenTicated();
}
public async Task<IActionResult> RequestItem()
{
await IsAuthenTicated();
return View();
return await IsAuthenTicated();
}
#endregion
}

View File

@ -1,21 +1,16 @@
using Azure;
using CPRNIMS.Domain.Services;
using CPRNIMS.Domain.UIContracts.Account;
using CPRNIMS.Domain.UIContracts.Items;
using CPRNIMS.Domain.UIServices.Updater;
using CPRNIMS.Infrastructure.Dto.Items;
using CPRNIMS.Infrastructure.Entities.Items;
using CPRNIMS.Infrastructure.Helper;
using CPRNIMS.Infrastructure.Models.Account;
using CPRNIMS.Infrastructure.ViewModel.Account;
using CPRNIMS.Infrastructure.ViewModel.Items;
using CPRNIMS.WebApps.Controllers.Base;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Drive.v3;
using Google.Apis.Drive.v3.Data;
using Google.Apis.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using System.Collections.Generic;
using System.Text.Json;
namespace CPRNIMS.WebApps.Controllers.Items
{
@ -28,8 +23,8 @@ namespace CPRNIMS.WebApps.Controllers.Items
private readonly IHubContext<CartHub> _hubContext;
public ItemMgmtController(ErrorLogHelper errorMessageService,
IWebHostEnvironment webHostEnvironment, IConfiguration config, TokenHelper tokenHelper,
IItem item, IHubContext<CartHub> hubContext)
: base(errorMessageService, webHostEnvironment,tokenHelper)
IItem item, IHubContext<CartHub> hubContext,IAccount account)
: base(errorMessageService, webHostEnvironment,tokenHelper, account)
{
_item = item;
_config = config;
@ -134,32 +129,127 @@ namespace CPRNIMS.WebApps.Controllers.Items
throw;
}
}
private async Task<string?> SaveAttachmentAsync(IFormFile? file, string? oldFileName)
{
var uploadsPath = Path.Combine(
_webHostEnvironment.WebRootPath,
"Content", "Uploads", "PRAttachment");
Directory.CreateDirectory(uploadsPath);
// If no new file uploaded, return old filename
if (file == null)
return oldFileName;
// Delete old file if exists
if (!string.IsNullOrWhiteSpace(oldFileName))
{
await DeleteAttachmentAsync(oldFileName);
}
// Validate file extension
var allowedExtensions = new[] { ".csv", ".xlsx", ".xls", ".pdf" };
var fileExtension = Path.GetExtension(file.FileName).ToLowerInvariant();
if (!allowedExtensions.Contains(fileExtension))
{
throw new InvalidOperationException("Invalid file type. Only CSV, Excel, and PDF files are allowed.");
}
// Validate file size (5MB max)
if (file.Length > 5 * 1024 * 1024)
{
throw new InvalidOperationException("File size exceeds 5MB limit.");
}
// Generate new unique filename with original extension
var newFileName = $"{Guid.NewGuid()}{fileExtension}";
var newFilePath = Path.Combine(uploadsPath, newFileName);
// Save new file
await using var stream = new FileStream(newFilePath, FileMode.Create);
await file.CopyToAsync(stream);
// Return only filename (NOT full path)
return newFileName;
}
private async Task DeleteAttachmentAsync(string fileName)
{
if (string.IsNullOrWhiteSpace(fileName))
return;
var uploadsPath = Path.Combine(
_webHostEnvironment.WebRootPath,
"Content", "Uploads", "PRAttachment");
var filePath = Path.Combine(uploadsPath, fileName);
if (System.IO.File.Exists(filePath))
{
await Task.Run(() => System.IO.File.Delete(filePath));
}
}
[HttpPost]
public async Task<IActionResult> PostPurchRequest(ItemVM viewModel,List<ItemCartVM> ItemCartIds)
public async Task<IActionResult> PostPurchRequest([FromForm] string ItemCartIds,
[FromForm] DateTime DateNeeded,
[FromForm] byte RequestTypeId,
[FromForm] int ChargeTo,
[FromForm] string? Remarks,
[FromForm] string? ProjectCode,
IFormFile? file)
{
try
{
viewModel.ItemCartVM = new ItemCartVM
{
ItemCartId = ItemCartIds.SelectMany(ic => ic.ItemCartId).ToList(),
Qty = ItemCartIds.SelectMany(ic => ic.Qty).ToList(),
ItemNo = ItemCartIds.SelectMany(ic => ic.ItemNo).ToList()
};
var postPutItem = await _item.PostPurchRequest(GetUser(), viewModel);
// Deserialize the ItemCartIds JSON string
var itemCartList = JsonSerializer.Deserialize<List<ItemCartDto>>(ItemCartIds);
if (postPutItem.statusResponse != "Error")
if (itemCartList == null || !itemCartList.Any())
{
return Json(new { success = true });
return Json(new { success = false, response = "No items selected" });
}
return Json(new { success = false, Response = postPutItem.message });
var viewModel = new ItemVM
{
DateNeeded = DateNeeded,
RequestTypeId = RequestTypeId,
ChargeTo = ChargeTo,
Remarks = Remarks,
ProjectCode = ProjectCode,
ItemCartVM = new ItemCartVM
{
ItemCartId = itemCartList.Select(ic => ic.ItemCartId).ToList(),
Qty = itemCartList.Select(ic => ic.Qty).ToList(),
ItemNo = itemCartList.Select(ic => ic.ItemNo).ToList()
}
};
// Save attachment if provided
string? savedFileName = await SaveAttachmentAsync(file, null);
viewModel.FileName = savedFileName;
viewModel.OrigFileName = file.FileName;
var postPutItem = await _item.PostPurchRequest(GetUser(), viewModel);
if (postPutItem.messCode != 0)
{
return Json(new { success = true, message = "Purchase request created successfully" });
}
// Delete uploaded file if request failed
if (!string.IsNullOrWhiteSpace(savedFileName))
{
await DeleteAttachmentAsync(savedFileName);
}
return Json(new { success = false, response = postPutItem.message });
}
catch (Exception ex)
{
var message = ex.InnerException?.ToString() ?? ex.Message.ToString();
throw;
var message = ex.InnerException?.Message ?? ex.Message;
return Json(new { success = false, response = "An error occurred while processing your request" });
}
}
#endregion
@ -349,17 +439,14 @@ namespace CPRNIMS.WebApps.Controllers.Items
public async Task<IActionResult> Index()
{
var viewModels = new ItemVM();
await IsAuthenTicated();
await UpdateCart(viewModels);
return View();
return await IsAuthenTicated();
}
public async Task<IActionResult> ItemCart(byte TypeOfRequest)
{
var viewModels = new ItemVM();
await IsAuthenTicated();
ViewBag.TypeOfRequest = TypeOfRequest;
return View();
return await IsAuthenTicated();
}
#endregion
#region Common

View File

@ -1,4 +1,5 @@
using CPRNIMS.Domain.UIContracts.PO;
using CPRNIMS.Domain.UIContracts.Account;
using CPRNIMS.Domain.UIContracts.PO;
using CPRNIMS.Infrastructure.Entities.PO;
using CPRNIMS.Infrastructure.Helper;
using CPRNIMS.Infrastructure.ViewModel.PO;
@ -16,8 +17,8 @@ namespace CPRNIMS.WebApps.Controllers.PO
private readonly IPurchaseOrder _purchaseOrder;
public POMgmtController(
ErrorLogHelper errorMessageService, IWebHostEnvironment webHostEnvironment
, IPurchaseOrder purchaseOrder, TokenHelper tokenHelper
) : base(errorMessageService, webHostEnvironment, tokenHelper)
, IPurchaseOrder purchaseOrder, TokenHelper tokenHelper,IAccount account
) : base(errorMessageService, webHostEnvironment, tokenHelper, account)
{
_purchaseOrder = purchaseOrder;
}

View File

@ -1,4 +1,6 @@
using CPRNIMS.Domain.UIContracts.PR;
using CPRNIMS.Domain.Services;
using CPRNIMS.Domain.UIContracts.Account;
using CPRNIMS.Domain.UIContracts.PR;
using CPRNIMS.Infrastructure.Dto.PR;
using CPRNIMS.Infrastructure.Helper;
using CPRNIMS.Infrastructure.ViewModel.PR;
@ -13,12 +15,43 @@ namespace CPRNIMS.WebApps.Controllers.PR
private readonly IPRequest _pRequest;
public PRMgmtController(TokenHelper tokenHelper, ErrorLogHelper errorMessageService,
IWebHostEnvironment webHostEnvironment
, IPRequest pRequest, IConfiguration configuration)
: base(errorMessageService, webHostEnvironment, tokenHelper)
, IPRequest pRequest, IConfiguration configuration,IAccount account)
: base(errorMessageService, webHostEnvironment, tokenHelper, account)
{
_pRequest = pRequest;
}
#region Get
private async Task<IActionResult> GetProductFile(string fileName)
{
try
{
// Validate filename
if (string.IsNullOrWhiteSpace(fileName) || fileName.Contains(".."))
{
return BadRequest("Invalid file name");
}
var uploadsPath = Path.Combine(_webHostEnvironment.WebRootPath, "Content/Uploads", "PRAttachment");
var filePath = Path.Combine(uploadsPath, fileName);
ContentTypeHelper.ValidateFile(filePath, uploadsPath);
// Stream the file instead of loading entirely into memory
var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
var contentType = ContentTypeHelper.GetContentType(fileName);
return File(fileStream, contentType, fileName, enableRangeProcessing: true);
}
catch (Exception ex)
{
return StatusCode(500, "Error retrieving file");
}
}
public async Task<IActionResult> GetProjectCodes(PRVM viewModels)
{
response = await _pRequest.GetProjectCodes(GetUser(), viewModels);
return GetResponse(response);
}
public async Task<IActionResult> GetApproverName(PRVM viewModels)
{
response = await _pRequest.GetApproverName(GetUser(), viewModels);
@ -117,6 +150,16 @@ namespace CPRNIMS.WebApps.Controllers.PR
}
#endregion
#region POST PUT
public async Task<IActionResult> PostPutProjectCode([FromBody] PRVM viewModel)
{
var postPutItem = await _pRequest.PostPutProjectCode(GetUser(), viewModel);
if (postPutItem.messCode != 0)
{
return Json(new { success = true, Response = postPutItem.Message });
}
return Json(new { success = false, Response = postPutItem.Message });
}
public async Task<IActionResult> ApprovedSelectedPRItem(PRVM viewModel,
List<PRList> PRList)
{
@ -223,6 +266,10 @@ namespace CPRNIMS.WebApps.Controllers.PR
{
return await IsAuthenTicated();
}
public async Task<IActionResult> ProjectCode()
{
return await IsAuthenTicated();
}
#endregion
}
}

View File

@ -1,4 +1,5 @@
using CPRNIMS.Domain.UIContracts.Receiving;
using CPRNIMS.Domain.UIContracts.Account;
using CPRNIMS.Domain.UIContracts.Receiving;
using CPRNIMS.Infrastructure.Helper;
using CPRNIMS.Infrastructure.ViewModel.PR;
using CPRNIMS.Infrastructure.ViewModel.Receiving;
@ -14,8 +15,8 @@ namespace CPRNIMS.WebApps.Controllers.Receiving
private readonly IConfiguration _configuration;
public ReceivingController(ErrorLogHelper errorMessageService,
IWebHostEnvironment webHostEnvironment,TokenHelper tokenHelper
, IReceiving receiving, IConfiguration configuration)
: base(errorMessageService, webHostEnvironment,tokenHelper)
, IReceiving receiving, IConfiguration configuration,IAccount account)
: base(errorMessageService, webHostEnvironment,tokenHelper, account)
{
_receiving = receiving;
_configuration = configuration;

View File

@ -1,4 +1,5 @@
using Azure;
using CPRNIMS.Domain.UIContracts.Account;
using CPRNIMS.Domain.UIContracts.SMTP;
using CPRNIMS.Infrastructure.Entities.Items;
using CPRNIMS.Infrastructure.Helper;
@ -17,16 +18,15 @@ namespace CPRNIMS.WebApps.Controllers.SMTP
private readonly ISMTP _sMTP;
public SMTPMgmtController(ErrorLogHelper errorMessageService,
IWebHostEnvironment webHostEnvironment, TokenHelper tokenHelper
, ISMTP sMTP
, ISMTP sMTP,IAccount account
)
: base(errorMessageService, webHostEnvironment,tokenHelper)
: base(errorMessageService, webHostEnvironment,tokenHelper, account)
{
_sMTP = sMTP;
}
public async Task<IActionResult> Index()
{
await IsAuthenTicated();
return View();
return await IsAuthenTicated();
}
#region Get
public async Task<IActionResult> GetAllSmtp()

View File

@ -2,7 +2,7 @@
<div class="container-fluid">
<div class="table-container shadow-lg p-3 mb-5 bg-white rounded">
<div class="header-container">
<h2 style="display: flex; flex-direction: column; align-items: center;">Requestor Page</h2>
<h2 style="display: flex; flex-direction: column; align-items: center;">Item Management</h2>
</div>
<br />
<button id="btnAddNewLayout" type="button" class="btn btn-success"
@ -237,7 +237,7 @@
</div>
</div>
</div>
<script src="~/JsFunctions/Items/ItemManagementV6.js"></script>
<script src="~/JsFunctions/Items/ItemManagementV7.js"></script>
@await Html.PartialAsync("PagesView/Item/_Scripts")
</div>

View File

@ -15,9 +15,10 @@
<table id="ItemCartTable" class="row-border" cellspacing="0" width="100%">
<thead>
<tr>
<th>
<th style="text-align:left;width:4%;">
All
<input id="selectAllHeaderCheckbox" type="checkbox" class="selectAllCheckbox" style="margin-left:10px;" />
<input id="selectAllCheckboxItem" type="checkbox"
class="selectAllCheckboxItem" />
</th>
<th>ItemNo</th>
<th>ItemName</th>
@ -25,64 +26,122 @@
<th>PRTypeId</th>
<th>Qty</th>
<th>Action</th>
<th hidden></th>
<th hidden></th>
<th hidden></th>
<th hidden></th>
<th hidden></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div style="margin-top:20px;" class="d-flex justify-content-end">
<a class="btn btn-primary" asp-area="" asp-controller="ItemMgmt" asp-action="Index" style="margin-bottom:20px; margin-right:10px;">
Back
<a class="btn btn-outline-secondary px-4" asp-area="" asp-controller="ItemMgmt" asp-action="Index" style="margin-bottom:20px; margin-right:10px;">
<i class="bi bi-x-circle me-2"></i>Back
</a>
<button id="btnSubmitItem" type="button" class="btn btn-success" onclick="showModal();" style="margin-bottom:20px; margin-right:10px;">
Submit
<i class="bi bi-check-circle me-2"></i> Submit
</button>
</div>
</div>
<!-- Modal addDateNeeded -->
<!-- Modal -->
<div class="modal fade custom-modal-backdrop" id="addDateNeeded"
tabindex="-1" aria-labelledby="addDateNeededLabel" aria-hidden="true" data-bs-backdrop="static">
<div class="modal-dialog">
<div class="modal-content">
tabindex="-1" aria-labelledby="addDateNeededLabel" aria-hidden="true" data-bs-backdrop="static">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content border-0 shadow-lg">
<div class="modal-header">
<h5 id="addDateNeededLabel" class="modal-title">
Fill all fields below, before to proceed
<h5 id="addDateNeededLabel" class="modal-title fw-semibold">
<i class="bi bi-clipboard-check me-2"></i>Purchase Request Details
</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="form-group">
<label id="labelDateNeeded" for="dateNeeded" style="margin-bottom: 5px;">Date Needed</label>
<input type="date" class="form-control"
style="width: 100%;margin-bottom:10px;" id="dateNeeded" name="dateNeeded" />
<div class="modal-body p-4">
<!-- Date Needed -->
<div class="mb-3">
<label id="labelDateNeeded" for="dateNeeded" class="form-label fw-light">
Date Needed <span class="text-danger">*</span>
</label>
<input type="date" class="form-control form-control"
id="dateNeeded" name="dateNeeded" required />
</div>
<div class="form-group">
<label for="requestorRemarks">Remarks</label>
<!-- Project Code Autocomplete -->
<div class="mb-3">
<label for="projectCode" class="form-label fw-semibold">
Project Code <small class="text-muted">(Optional)</small>
</label>
<input type="text" class="form-control form-control"
id="projectCode" name="projectCode"
placeholder="Start typing here..."
autocomplete="off"
list="projectCodeList" />
<datalist id="projectCodeList">
<!-- Options will be populated dynamically via JavaScript -->
</datalist>
<div class="form-text">
<i class="bi bi-info-circle me-1"></i>Search and select the appropriate project code
</div>
</div>
<!-- File Attachment -->
<div class="mb-3">
<label for="fileAttachment" class="form-label fw-semibold">
Attachment <small class="text-muted">(Optional)</small>
</label>
<input type="file" class="form-control"
id="fileAttachment" name="fileAttachment"
accept=".csv,.xlsx,.xls,.pdf" />
<div class="form-text">
<i class="bi bi-paperclip me-1"></i>Accepted formats: CSV, Excel (.xlsx, .xls), PDF (Max 5MB)
</div>
<!-- File preview area -->
<div id="filePreview" class="mt-2 d-none">
<div class="alert alert-success alert-dismissible fade show py-2" role="alert">
<i class="bi bi-file-earmark-check me-2"></i>
<span id="fileName"></span>
<small class="text-muted ms-2">(<span id="fileSize"></span>)</small>
<button type="button" class="btn-close py-2" onclick="clearFileAttachment()"></button>
</div>
</div>
</div>
<!-- Remarks -->
<div class="mb-3">
<label for="requestorRemarks" class="form-label fw-semibold">
Remarks <small class="text-muted">(Optional)</small>
</label>
<textarea id="requestorRemarks" class="form-control"
style="width: 100%; height: 100px;margin-bottom:10px;"></textarea>
rows="4"
placeholder="Add any additional notes or comments here..."></textarea>
<div class="form-text">
<span id="charCount">0</span>/500 characters
</div>
</div>
<div class="form-group">
<label id="labelChargeTo" for="chargeTo">Charge To</label>
<select id="chargeTo" class="form-control" style="margin-bottom:10px;" name="chargeTo">
<!-- Charge To -->
<div class="mb-3">
<label id="labelChargeTo" for="chargeTo" class="form-label fw-semibold">
Charge To <span class="text-danger">*</span>
</label>
<select id="chargeTo" class="form-select form-select-lg" name="chargeTo" required>
<option value="" selected disabled>-- Select Department --</option>
<!-- Options populated dynamically -->
</select>
<input type="hidden" id="departmentId" name="departmentId" />
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-warning" data-bs-dismiss="modal">Cancel</button>
<button type="button" id="btnConfirmUpdate" onclick="postPutPurchase()" class="btn btn-success">Submit</button>
<div class="modal-footer bg-light border-0 p-3">
<button type="button" class="btn btn-outline-secondary px-4" data-bs-dismiss="modal">
<i class="bi bi-x-circle me-2"></i>Cancel
</button>
<button type="button" id="btnConfirmUpdate" onclick="postPutPurchase()" class="btn btn-success px-4">
<i class="bi bi-check-circle me-2"></i>Submit Request
</button>
</div>
</div>
</div>
</div>
</div>
<link href="~/css/item/cartv2.css" rel="stylesheet" />
@await Html.PartialAsync("PagesView/Item/_Scripts")
<script src="~/JsFunctions/Items/ItemCartV2.js"></script>
<script src="~/JsFunctions/Items/ItemCartV3.js"></script>
</body>

View File

@ -0,0 +1,105 @@
<body>
<div class="container-fluid">
<div class="table-container shadow-lg p-3 mb-5 bg-white rounded">
<div class="header-container">
<h2>Project Code Management</h2>
</div>
<br />
<button id="btnAddNew" type="button" class="btn btn-success" data-mode="add"
onclick="showProjectCode({},true)" style="margin-bottom:20px;margin-left:10px;">
Add new
</button>
<br />
<table id="ProjectCodeTable" class="row-border" cellspacing="0" width="100%">
<thead>
<tr>
<th style="width:15%">ProjectCode</th>
<th style="width:25%">ProjectName</th>
<th style="width:32%">DeliveryAddress</th>
<th style="width:10%">MaxDays</th>
<th style="width:11%">Status</th>
<th style="width:7%">Action</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
<!-- Modal addNewItem -->
<div class="modal fade custom-modal-backdrop" id="showProjectCode" tabindex="-1"
aria-labelledby="ModalLabel" aria-hidden="true" data-bs-backdrop="static">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" style="text-align: center; margin-left: auto; margin-right: auto;"
id="headerNew">
Add new item
</h5>
<h5 class="modal-title" style="text-align: center; margin-left: auto; margin-right: auto;"
id="headerUpdate">
Update item
</h5>
</div>
<br />
<div class="modal-body">
<form id="itemPostPutForm">
<div class="form-floating mb-3">
<input id="projectCodeId" hidden />
<input id="projectCode" class="form-control"
placeholder=" Describe proejct code...">
<label for="projectCode">Project Code</label>
</div>
<div class="form-floating mb-3">
<textarea id="projectName" class="form-control"
placeholder=" Describe projectName..."></textarea>
<label for="projectName">Project Name</label>
</div>
<div class="form-floating mb-3">
<textarea id="deliveryAddress" class="form-control"
placeholder=" Describe deliveryAddress..."></textarea>
<label for="deliveryAddress">Delivery Address</label>
</div>
<div class="row g-3 mb-3">
<div class="col-md-6">
<div class="form-floating">
<input id="maxDays"
type="number"
min="1"
class="form-control"
placeholder="Max days">
<label for="maxDays">Max Days</label>
</div>
</div>
<div class="col-md-6 d-flex align-items-center">
<div class="form-check form-switch">
<input class="form-check-input"
type="checkbox"
id="statusSwitch"
checked>
<label class="form-check-label" for="statusSwitch">
Active
</label>
</div>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-cancel" data-bs-dismiss="modal">Cancel</button>
<button type="button" id="btnAddUpdate" onclick="postPutProjectCode(1);" class="btn btn-success"></button>
</div>
</div>
</div>
</div>
<script src="~/JsFunctions/PR/ProjectCode.js"></script>
@await Html.PartialAsync("PagesView/PR/_PRScripts")
</body>

View File

@ -5,8 +5,11 @@
<link href="~/lib/bootstrap/dist/fonts/boostrap-icons.css" rel="stylesheet" />
<link href="~/css/common/rowhighlighter.css" rel="stylesheet" />
<script src="~/jsfunctions/items/itemvar.js"></script>
<script src="~/jsfunctions/items/ItemViewV5.js"></script>
<script src="~/jsfunctions/items/PostPutItemV2.js"></script>
<script src="~/jsfunctions/items/ItemViewV6.js"></script>
<script src="~/jsfunctions/items/PostPutItemV3.js"></script>
<script src="~/microsoft-signalr/signalr.min.js"></script>
<script src="~/jsfunctions/updater/CartUpdater.js"></script>
<script src="~/jsfunctions/utilities/NewStyle.js"></script>
<script src="~/jsfunctions/utilities/utilsV3.js"></script>
<script src="~/jsfunctions/utilities/StylesV3.js"></script>

View File

@ -2,12 +2,12 @@
<div id="loader" class="loader"></div>
</div>
<link href="~/css/common/rowhighlighter.css" rel="stylesheet" />
<script src="~/jsfunctions/pr/PRColumnV6.js"></script>
<script src="~/jsfunctions/pr/PRViewV4.js"></script>
<script src="~/jsfunctions/pr/PRPutPostV9.js"></script>
<script src="~/jsfunctions/pr/PRButtonv2.js"></script>
<script src="~/jsfunctions/pr/PRColumnV7.js"></script>
<script src="~/jsfunctions/pr/PRViewV5.js"></script>
<script src="~/jsfunctions/pr/PRPutPost.js"></script>
<script src="~/jsfunctions/pr/PRButtonv3.js"></script>
<script src="~/jsfunctions/pr/PRVarV3.js"></script>
<script src="~/jsfunctions/pr/Configv4.js"></script>
<script src="~/jsfunctions/pr/Configv5.js"></script>
<script src="~/jsfunctions/pr/populatedropdown.js"></script>
<script src="~/jsfunctions/pr/prRowCallbackV3.js"></script>
<script src="~/jsfunctions/utilities/columnstyle.js"></script>

View File

@ -341,20 +341,24 @@
<div class="p-2 mb-3 rounded border shadow-sm bg-light pr-info-section">
<div class="row mb-2">
<!-- PR No -->
<div class="col-md-4">
<div class="col-md-5">
<small class="text-muted">P.R. No</small>
<div id="label-pr-prNo" class="fw-bold text-dark"></div>
</div>
<!-- PR By -->
<div class="col-md-4">
<div class="col-md-5">
<small class="text-muted">P.R. By</small>
<div id="label-prby" class="fw-bold text-dark"></div>
</div>
<!-- Department -->
<div class="col-md-4">
<div class="col-md-5">
<small class="text-muted">Department</small>
<div id="label-pr-Department" class="fw-bold text-dark"></div>
</div>
<div class="col-md-5">
<small class="text-muted">Project Code</small>
<div id="label-pr-ProjectCode" class="fw-bold text-dark"></div>
</div>
</div>
<div class="row mb-2">

View File

@ -1,32 +1,7 @@
@using CPRNIMS.Infrastructure.ViewModel;
@using CPRNIMS.Infrastructure.ViewModel.Account;
@using CPRNIMS.Infrastructure.ViewModel.Common;
@inject CPRNIMS.Domain.UIContracts.Account.IAccount _account;
@model CPRNIMS.Infrastructure.Dto.Attachement.AttachResponseDto
@{
if (!String.IsNullOrEmpty(ViewBag.UserRoles))
{
try
{
string allowedRoles = ViewBag.UserRoles;
var userCred = new CPRNIMS.Infrastructure.Models.Account.User();
userCred.UserName = ViewBag.UserName;
userCred.UserId = ViewBag.UserId;
var myControllerAccess = await _account.GetLandingPageByUserId(userCred);
var groupedElements = myControllerAccess.GroupBy(e => e.ElementMenuName).ToList();
ViewBag.TempDataElements = groupedElements;
}
catch (Exception)
{
// Console.WriteLine(ex.Message.ToString() ?? ex.InnerException?.ToString());
throw;
}
}
}
<div class="sidebar">
<div class="logo-details">
<i class="bx bxl-c-plus-plus icon"></i>
@ -68,6 +43,3 @@
@await Html.PartialAsync("PartialView/MenuNav/UserProfile/_UpdateUserProfile")
</ul>
</div>

View File

@ -50,7 +50,7 @@
</div>
</div>
<link href="~/css/item/cart.css" rel="stylesheet" />
<link href="~/css/item/cartV2.css" rel="stylesheet" />
}
</header>

View File

@ -54,18 +54,27 @@ function showHideLabelButtons() {
$(document).ready(function () {
loader = $('#overlay, #loader');
var submitButton = $('#btnSubmitItem');
var totalSelectedLabel = $('#totalSelected');
tableName = '#ItemCartTable';
totalSelectedLabel = $('#totalSelected');
clearTableSelection(tableName, selectedProductsMap, () => {
totalSelectedLabel.text(0);
}, 'selected-row', '.select-all-item-checkbox');
tableElement = $(tableName);
tableDestroy(tableElement);
UserRights = document.getElementById("roleRights").value;
RequestTypeId = document.getElementById("requestTypeId").value;
showHideLabelButtons();
itemTable = $('#ItemCartTable').DataTable({
itemTable = $(tableName).DataTable({
ajax: {
url: '/ItemMgmt/GetItemCart',
type: 'GET',
data: { RequestTypeId },
beforeSend: function () {
// Show the loader before making the AJAX request
loader.show();
},
complete: function () {
@ -73,6 +82,19 @@ $(document).ready(function () {
}
},
initComplete: function () {
initializeTableSelection({
tableName: tableName,
dataTable: itemTable,
selectedItemsMap: selectedProductsMap,
idKey: 'itemCartId',
idKey2: 'itemNo',
checkboxClass: '.select-item-checkbox',
selectAllClass: '.select-all-item-checkbox',
selectedRowClass: 'selected-row',
updateCountCallback: function () {
totalSelectedLabel.text(getSelectedCount(selectedProductsMap));
}
});
var api = this.api();
var data = api.ajax.json();
@ -85,9 +107,12 @@ $(document).ready(function () {
columns: [
{
data: 'itemCartId',
title: '<input type="checkbox" class="select-all-item-checkbox" />',
render: function () {
return '<input type="checkbox" class="selectedItem-checkbox" />';
}
return '<input type="checkbox" class="select-item-checkbox"/>';
},
orderable: false,
searchable: false
},
{ data: 'itemNo' },
{ data: 'itemName' },
@ -99,12 +124,7 @@ $(document).ready(function () {
render: function (data, type, row) {
return renderItembtns(data, row);
}
},
{ data: 'isActive', visible: false },
{ data: 'itemCartId', visible: false },
{ data: 'cartItemCount', visible: false },
{ data: 'createdDate', visible: false },
{ data: 'requestTypeId', visible: false },
}
],
"columnDefs": [
@ -139,7 +159,7 @@ $(document).ready(function () {
}
},
//responsive: true,
order: [[10, 'desc']],
order: [[0, 'desc']],
language: {
emptyTable: "No record available"
},
@ -157,37 +177,6 @@ $(document).ready(function () {
// Toggle the visibility of the submit button based on whether the table is empty or not
submitButton.toggle(!isEmpty);
}
// Event handler for individual checkbox change
$('#ItemCartTable').on('change', '.selectedItem-checkbox', function () {
var row = $(this).closest('tr'); // Get the closest row for the checkbox
if ($(this).prop('checked')) {
row.addClass('selected-row'); // Add highlight class if checked
} else {
row.removeClass('selected-row'); // Remove highlight class if unchecked
}
updateTotalSelectedCount(); // Update the total selected count
});
// Event handler for "Select All" checkbox change in the header
$('#selectAllHeaderCheckbox').on('change', function () {
var isChecked = $(this).prop('checked'); // Check if "Select All" checkbox is checked
// Check or uncheck all checkboxes in the table based on the state of "Select All" checkbox
$('.selectedItem-checkbox').prop('checked', isChecked);
// Highlight or unhighlight all rows based on "Select All" checkbox state
if (isChecked) {
$('#ItemCartTable tbody tr').addClass('selected-row');
} else {
$('#ItemCartTable tbody tr').removeClass('selected-row');
}
updateTotalSelectedCount(); // Update the total selected count
});
function updateTotalSelectedCount() {
var totalSelected = $('.selectedItem-checkbox:checked').length; // Count the checked checkboxes
totalSelectedLabel.text(totalSelected); // Update the label with the count
}
})
function deleteCartItemById(data) {
loader = $('#overlay, #loader');
@ -228,3 +217,72 @@ function deleteCartItemById(data) {
}
});
}
document.getElementById('fileAttachment').addEventListener('change', function (e) {
const file = e.target.files[0];
const filePreview = document.getElementById('filePreview');
const fileName = document.getElementById('fileName');
const fileSize = document.getElementById('fileSize');
if (file) {
// Validate file size (5MB max)
const maxSize = 5 * 1024 * 1024; // 5MB in bytes
if (file.size > maxSize) {
showToast('warning', 'File size exceeds 5MB. Please choose a smaller file.', 'File Upload', 4000);
e.target.value = '';
return;
}
// Validate file type
const allowedExtensions = ['csv', 'xlsx', 'xls', 'pdf'];
const fileExtension = file.name.split('.').pop().toLowerCase();
if (!allowedExtensions.includes(fileExtension)) {
showToast('warning', 'Invalid file type. Please upload CSV, Excel, or PDF files only.', 'File Upload', 4000);
e.target.value = '';
return;
}
// Show file preview
fileName.textContent = file.name;
fileSize.textContent = formatFileSize(file.size);
filePreview.classList.remove('d-none');
}
});
function clearFormData() {
document.getElementById('dateNeeded').value = '';
document.getElementById('projectCode').value = '';
document.getElementById('requestorRemarks').value = '';
document.getElementById('fileAttachment').value = '';
document.getElementById('chargeTo').value = '';
clearFileAttachment();
document.getElementById('charCount').textContent = '0';
}
function clearFileAttachment() {
document.getElementById('fileAttachment').value = '';
document.getElementById('filePreview').classList.add('d-none');
}
document.getElementById('requestorRemarks').addEventListener('input', function (e) {
const charCount = document.getElementById('charCount');
const currentLength = e.target.value.length;
const maxLength = 500;
charCount.textContent = currentLength;
if (currentLength > maxLength) {
e.target.value = e.target.value.substring(0, maxLength);
charCount.textContent = maxLength;
}
// Change color when approaching limit
if (currentLength > maxLength * 0.9) {
charCount.classList.add('text-danger');
} else {
charCount.classList.remove('text-danger');
}
});
function formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i];
}

View File

@ -40,11 +40,10 @@ function isFullFilled() {
}
$(document).ready(function () {
var loader = $('#overlay, #loader');
loader = $('#overlay, #loader');
let fetchedData = [];
let hasFetched = false; // ensures only one fetch per page load
let fetchInProgress = false; // prevents multiple calls before first finishes
let itemTable;
let cartItemCount = $('#cartItemCount').val();
$('#cartCount').text(cartItemCount);

View File

@ -1,4 +1,35 @@
function populateItemCategSelect() {
async function setupProjectCodeAutocomplete() {
const input = document.getElementById('projectCode');
let debounceTimer;
input.addEventListener('input', function (e) {
clearTimeout(debounceTimer);
const searchTerm = e.target.value;
if (searchTerm.length < 2) return;
debounceTimer = setTimeout(async () => {
try {
// Replace with your actual API endpoint
const response = await fetch(`/api/projects/search?term=${encodeURIComponent(searchTerm)}`);
const projects = await response.json();
const datalist = document.getElementById('projectCodeList');
datalist.innerHTML = '';
projects.forEach(project => {
const option = document.createElement('option');
option.value = project.code;
option.textContent = `${project.code} - ${project.name}`;
datalist.appendChild(option);
});
} catch (error) {
console.error('Error fetching project codes:', error);
}
}, 300);
});
}
function populateItemCategSelect() {
$.ajax({
url: "/ItemMgmt/GetItemCateg",
success: function (response) {

View File

@ -1,4 +1,106 @@
function putItemDetails() {
function postPutPurchase() {
loader = $('#overlay, #loader').css('z-index', 1060);
isValid = true;
var Remarks = document.getElementById('requestorRemarks').value;
var ProjectCode = document.getElementById('projectCode').value;
const selectedItems = Object.values(selectedProductsMap);
if (selectedItems.length === 0) {
showToast('warning', 'Please select items first!', 'Approval failed', 4000);
return;
}
const requestData = selectedItems.map(item => {
return {
ItemCartId: item.itemCartId,
ItemNo: item.itemNo,
Qty: item.qty
};
});
console.log(requestData);
var DateNeeded = document.getElementById('dateNeeded').value;
if (!DateNeeded) {
showToast('warning', 'Please choose date needed!', 'P.R. submission failed', 4000);
confirmUpdateListener = false;
return;
}
if (RequestTypeId == 3) {
updateDepartmentId();
var ChargeTo = document.getElementById('departmentId').value;
if (!ChargeTo) {
showToast('warning', 'Please choose a department to be in charge of!', 'P.R. submission failed', 4000);
confirmUpdateListener = false;
return;
}
}
showConfirmation({
title: 'Purchasing Requisition',
message: 'Are you sure you want to proceed? This action cannot be undone.',
type: 'warning',
confirmText: 'Yes',
cancelText: 'No'
}).then((confirmed) => {
if (confirmed) {
// Create FormData to handle file upload
var formData = new FormData();
// Append file if exists
var fileInput = document.getElementById('fileAttachment');
if (fileInput.files.length > 0) {
formData.append('file', fileInput.files[0]);
}
// Append other data
formData.append('DateNeeded', DateNeeded);
formData.append('RequestTypeId', RequestTypeId);
formData.append('ChargeTo', ChargeTo || '');
formData.append('Remarks', Remarks || '');
formData.append('ProjectCode', ProjectCode || '');
// Append array data - serialize as JSON
formData.append('ItemCartIds', JSON.stringify(requestData));
$.ajax({
url: '/ItemMgmt/PostPurchRequest',
type: 'POST',
data: formData,
processData: false, // Important: Don't process the data
contentType: false, // Important: Don't set content type
success: function (response) {
if (response.success) {
itemTable.ajax.reload();
$('#addDateNeeded').modal('hide');
showToast('success', 'P.R. Successfully Created!', 'Success', 4000);
var totalSelectedLabel = $('#totalSelected');
totalSelectedLabel.text('');
// Clear form after successful submission
clearFormData();
} else {
itemTable.ajax.reload();
showToast('error', response.response, 'P.R. submission failed', 4000);
}
},
error: errorHandler,
beforeSend: function () {
loader.show();
},
complete: function () {
loader.hide();
}
});
}
});
}
function putItemDetails() {
loader = $('#overlay, #loader');
const itemPictureImageInput = document.getElementById("itemPictureImageInput");
@ -132,91 +234,91 @@ function sendUpdateRequest(data, loader) {
}
});
}
function postPutPurchase() {
loader = $('#overlay, #loader').css('z-index', 1060);
isValid = true;
var Remarks = document.getElementById('requestorRemarks').value;
var selectedCheckboxes = $('.selectedItem-checkbox:checked');
var requestData = [];
selectedCheckboxes.each(function () {
var $row = $(this).closest('tr');
var rowIndex = itemTable.row($row).index();
var rowData = itemTable.row(rowIndex).data();
//function postPutPurchase() {
// loader = $('#overlay, #loader').css('z-index', 1060);
// isValid = true;
// var Remarks = document.getElementById('requestorRemarks').value;
// var selectedCheckboxes = $('.selectedItem-checkbox:checked');
// var requestData = [];
// selectedCheckboxes.each(function () {
// var $row = $(this).closest('tr');
// var rowIndex = itemTable.row($row).index();
// var rowData = itemTable.row(rowIndex).data();
var itemCartId = rowData.itemCartId;
var itemNo = rowData.itemNo;
var qty = $row.find('.editable-qty').val() || rowData.qty;
// var itemCartId = rowData.itemCartId;
// var itemNo = rowData.itemNo;
// var qty = $row.find('.editable-qty').val() || rowData.qty;
if (parseFloat(qty) === 0 || isNaN(parseFloat(qty))) {
isValid = false;
showToast('warning', "Please input a valid qty for ItemNo# " + itemNo + "!", ' warning', 4000);
$(modalId).modal('hide');
return false;
}
// if (parseFloat(qty) === 0 || isNaN(parseFloat(qty))) {
// isValid = false;
// showToast('warning', "Please input a valid qty for ItemNo# " + itemNo + "!", ' warning', 4000);
// $(modalId).modal('hide');
// return false;
// }
var itemData = {
itemCartId: itemCartId,
ItemNo: itemNo,
qty: qty
};
requestData.push(itemData);
});
// var itemData = {
// itemCartId: itemCartId,
// ItemNo: itemNo,
// qty: qty
// };
// requestData.push(itemData);
// });
if (selectedCheckboxes.length <= 0) {
showToast('warning', 'No selected item!', 'Item cart failed', 4000);
return;
} else {
var DateNeeded = document.getElementById('dateNeeded').value;
// if (selectedCheckboxes.length <= 0) {
// showToast('warning', 'No selected item!', 'Item cart failed', 4000);
// return;
// } else {
// var DateNeeded = document.getElementById('dateNeeded').value;
if (!DateNeeded) {
showToast('warning', 'Please choose date needed!', 'P.R. submission failed', 4000);
confirmUpdateListener = false;
return;
}
if (RequestTypeId == 3) {
updateDepartmentId();
var ChargeTo = document.getElementById('departmentId').value;
if (!ChargeTo) {
showToast('warning', 'Please choose a department to be in charge of!', 'P.R. submission failed', 4000);
confirmUpdateListener = false;
return;
}
}
}
showConfirmation({
title: 'Purchasing Requisition',
message: 'Are you sure you want to proceed? This action cannot be undone.',
type: 'warning',
confirmText: 'Yes',
cancelText: 'No'
}).then((confirmed) => {
if (confirmed) {
$.ajax({
url: '/ItemMgmt/PostPurchRequest',
type: 'POST',
data: { ItemCartIds: requestData, DateNeeded: DateNeeded, RequestTypeId: RequestTypeId, ChargeTo: ChargeTo, Remarks: Remarks },
success: function (response) {
if (response.success) {
itemTable.ajax.reload();
$('#addDateNeeded').modal('hide');
showToast('success', 'P.R. Successfully Created!', 'Success', 4000);
var totalSelectedLabel = $('#totalSelected');
totalSelectedLabel.text('');
} else {
itemTable.ajax.reload();
showToast('error', response.response, title + ' failed', 4000);
}
},
beforeSend: function () {
loader.show();
},
complete: function () {
loader.hide();
}
});
}
});
}
// if (!DateNeeded) {
// showToast('warning', 'Please choose date needed!', 'P.R. submission failed', 4000);
// confirmUpdateListener = false;
// return;
// }
// if (RequestTypeId == 3) {
// updateDepartmentId();
// var ChargeTo = document.getElementById('departmentId').value;
// if (!ChargeTo) {
// showToast('warning', 'Please choose a department to be in charge of!', 'P.R. submission failed', 4000);
// confirmUpdateListener = false;
// return;
// }
// }
// }
// showConfirmation({
// title: 'Purchasing Requisition',
// message: 'Are you sure you want to proceed? This action cannot be undone.',
// type: 'warning',
// confirmText: 'Yes',
// cancelText: 'No'
// }).then((confirmed) => {
// if (confirmed) {
// $.ajax({
// url: '/ItemMgmt/PostPurchRequest',
// type: 'POST',
// data: { ItemCartIds: requestData, DateNeeded: DateNeeded, RequestTypeId: RequestTypeId, ChargeTo: ChargeTo, Remarks: Remarks },
// success: function (response) {
// if (response.success) {
// itemTable.ajax.reload();
// $('#addDateNeeded').modal('hide');
// showToast('success', 'P.R. Successfully Created!', 'Success', 4000);
// var totalSelectedLabel = $('#totalSelected');
// totalSelectedLabel.text('');
// } else {
// itemTable.ajax.reload();
// showToast('error', response.response, title + ' failed', 4000);
// }
// },
// beforeSend: function () {
// loader.show();
// },
// complete: function () {
// loader.hide();
// }
// });
// }
// });
//}
function AddToCart(isUpdated) {
var loader = $('#overlay, #loader');
var ItemNo = $('#itemNo').val();

View File

@ -3,10 +3,13 @@
GetItemColor: '/ItemMgmt/GetItemColor',
GetItemLocalization: '/ItemMgmt/GetItemLocalization',
GetItemUOM: '/ItemMgmt/GetItemUOM',
GetProjectCodes: '/PRMgmt/GetProjectCodes',
GetSupplierAlternativeOffer: '/PRMgmt/GetSupplierAlternativeOffer',
GetSupplierAlterOfferDetails: '/PRMgmt/GetSupplierAlterOfferDetails',
PutSupplierAlterOffer: '/PRMgmt/PutSupplierAlterOffer',
PostPutProjectCode: '/PRMgmt/PostPutProjectCode',
PRItemRemoval: '/PRMgmt/PRItemRemoval',
PutItemDetail: '/PRMgmt/PutItemDetail',
ApprovedSelectedPRItem: '/PRMgmt/ApprovedSelectedPRItem',

View File

@ -30,3 +30,10 @@ function renderAlterOfferbtns(data, row) {
'</button > ';
return buttonsHtml;
}
function renderProjectCodebtns(data, row) {
var jsonData = JSON.stringify(row).replace(/"/g, "&quot;");
return '<button onclick="showProjectCode(' + jsonData + ',' + false + ')" class="btn btn-default">' +
'<i class="fa-solid fa-pen-to-square fa-xl" style="color: #FFA500;" aria-hidden="true"></i>' +
'</button > ';;
}

View File

@ -62,7 +62,6 @@ var colOnPRtracking = [
{ data: 'acknowledgeBy' },
{ data: 'acknowledgeDate' },
];
var colOnPRTable = [
{ data: 'prNo' },
{ data: 'newPRNo' },
@ -126,7 +125,6 @@ var colAlterOfferTable = [
},
{ data: 'description' },
];
var colRRFinance = [
{ data: 'prNo' },
{ data: 'itemNo' },
@ -161,7 +159,6 @@ var colRRFinance = [
{ data: 'emailAddress', visible: false },
{ data: 'supplierName', visible: false },
];
var colItemList = [
{
data: 'prDetailsId',
@ -184,3 +181,22 @@ var colItemList = [
}
}
];
var colOnProjectCode = [
{ data: 'projectCode' },
{ data: 'projectName' },
{ data: 'deliveryAddress' },
{ data: 'maxDays' },
{
data: 'isActive',
render: function (data) {
return data ? 'Active' : 'Inactive';
}
},
{
data: null,
render: function (data, type, row) {
return renderProjectCodebtns(data, row);
}
}
];

View File

@ -1,4 +1,64 @@
function approvedSelectedPRItem() {
function postPutProjectCode() {
loader = $('#overlay, #loader').css('z-index', 1070);
const modal = $('#showProjectCode');
const mode = modal.attr('data-mode');
const id = modal.attr('data-id');
const payload = {
ProjectCodeId: Number($('#projectCodeId').val()) || 0,
ProjectCode: $('#projectCode').val().trim(),
ProjectName: $('#projectName').val().trim(),
DeliveryAddress: $('#deliveryAddress').val().trim(),
MaxDays: parseInt($('#maxDays').val(), 10),
IsActive: $('#statusSwitch').is(':checked')
};
if (!payload.ProjectCode || !payload.ProjectName || !payload.DeliveryAddress
|| !Number.isInteger(payload.MaxDays) || payload.MaxDays <= 0) {
showToast('error', 'Please complete all required fields.', 'Submission failed', 4000);
return;
}
const isAdd = mode === 'add';
let message = isAdd
? 'Are you sure you want to add new project code? This action cannot be undone.'
: 'Are you sure you want to update this project code? This action cannot be undone.';
showConfirmation({
title: 'Project Code',
message: message,
type: 'warning',
confirmText: 'Yes',
cancelText: 'No'
}).then((confirmed) => {
if (confirmed) {
$.ajax({
url: endpoint.PostPutProjectCode,
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(payload),
...beforeComplete(loader),
success: function (response) {
if (response.success) {
// Refresh table
prTable.ajax.reload(null, false);
// Close modal
modal.modal('hide');
showToast('success', isAdd ? 'Project added successfully!' : 'Project updated successfully!', 'Success', 4000);
} else {
showToast('error', response.response, 'Approval failed', 4000);
}
},
error: errorHandler
});
}
});
}
function approvedSelectedPRItem() {
const loader = $('#overlay, #loader').css('z-index', 1070);
const selectedItems = Object.values(selectedProductsMap);

View File

@ -1,4 +1,62 @@
function getApproverName(prDetailsId) {
function showProjectCode(data = {}, isNew = true) {
const modal = $('#showProjectCode');
if (isNew) {
// Mode
modal.attr('data-mode', 'add');
modal.attr('data-id', '');
// Header & button
$('#headerNew').show();
$('#headerUpdate').hide();
$('#btnAddUpdate')
.text('Add Project')
.removeClass('btn-warning')
.addClass('btn-success');
// Clear fields
$('#itemPostPutForm')[0].reset();
$('#status').val('true');
} else {
modal.attr('data-mode', 'update');
modal.attr('data-id', data.id);
$('#headerNew').hide();
$('#headerUpdate').show();
$('#btnAddUpdate')
.text('Update Project')
.removeClass('btn-success')
.addClass('btn-warning');
// Fill fields
$('#projectCodeId').val(data.projectCodeId);
$('#projectCode').val(data.projectCode);
$('#projectName').val(data.projectName);
$('#deliveryAddress').val(data.deliveryAddress);
$('#maxDays').val(data.maxDays);
$('#statusSwitch').prop('checked', data.isActive);
$('label[for="statusSwitch"]').text(data.isActive ? 'Active' : 'Inactive');
}
$('#maxDays').on('input', function () {
const value = Number(this.value);
$('#btnAddUpdate').prop('disabled', value <= 0);
});
$('#statusSwitch').on('change', function () {
$('label[for="statusSwitch"]').text(
this.checked ? 'Active' : 'Inactive'
);
});
modal.modal('show');
}
function getApproverName(prDetailsId) {
PRDetailsId = prDetailsId;
$.ajax({
url: '/PRMgmt/GetApproverName',
@ -636,6 +694,9 @@ function viewPRDetails(data) {
document.getElementById('label-pr-remarks').innerHTML = data.remarks;
document.getElementById('label-pr-attestedBy').innerHTML = data.attestedBy;
document.getElementById('label-pr-approvedBy').innerHTML = data.approvedBy;
document.getElementById('label-pr-ProjectCode').innerHTML = data.projectCode;
console.log('data.projectCode', data.projectCode);
document.getElementById('label-pr-dateNeeded').innerHTML = formatDate(data.dateNeeded);

View File

@ -0,0 +1,22 @@
$(document).ready(function () {
loader = $('#overlay, #loader');
prTable = $('#ProjectCodeTable').DataTable({
ajax: {
url: endpoint.GetProjectCodes,
type: 'GET',
beforeSend: function () {
loader.show();
},
complete: function () {
loader.hide();
}
},
initComplete: initCompleteCallback,
columns: colOnProjectCode,
responsive: true,
language: {
emptyTable: "No record available"
},
error: errorHandler
});
})

View File

@ -29,3 +29,8 @@
align-self: flex-end;
margin-right: 20px;
}
#filePreview .alert {
border-left: 4px solid #198754;
}