Features for option to select currency for each PO during PO Creation

This commit is contained in:
rowell_m_soriano 2026-06-24 10:16:45 +08:00
parent fa03ef5a3d
commit 440cdfcdb7
78 changed files with 2992 additions and 1146 deletions

View File

@ -13,6 +13,6 @@ namespace CPRNIMS.Domain.Contracts.Finance
{ {
Task<List<ForPayment>> GetAllClosedPO(RRDetailsDto itemDto); Task<List<ForPayment>> GetAllClosedPO(RRDetailsDto itemDto);
Task<List<ReceivingDetail>> GetRRDetailByPO(RRDetailsDto itemDto); Task<List<ReceivingDetail>> GetRRDetailByPO(RRDetailsDto itemDto);
Task<RRDetail> PostPutPayment(RRDetailsDto itemDto); Task<RRDetailDto> PostPutPayment(RRDetailsDto itemDto);
} }
} }

View File

@ -21,7 +21,7 @@ namespace CPRNIMS.Domain.Contracts.Inventory
Task<PagedResult<InventoryResponse>> GetInventory(InventoryRequest request, CancellationToken ct); Task<PagedResult<InventoryResponse>> GetInventory(InventoryRequest request, CancellationToken ct);
Task<List<InventoryByIdResponse>> GetInventoryById(InventoryRequest itemDto, CancellationToken ct); Task<List<InventoryByIdResponse>> GetInventoryById(InventoryRequest itemDto, CancellationToken ct);
Task<TransactContextDto?> GetTransactContextAsync(int inventoryId, CancellationToken ct); Task<TransactContextDto?> GetTransactContextAsync(int inventoryId, CancellationToken ct);
Task<IEnumerable<DisciplineDto>> GetDisciplinesAsync(CancellationToken ct); Task<IReadOnlyList<DisciplineDto>> GetDisciplinesAsync(CancellationToken ct);
Task<Infrastructure.Entities.Inventory.Inventory> PostPutReqApproval(InventoryDto itemDto); Task<Infrastructure.Entities.Inventory.Inventory> PostPutReqApproval(InventoryDto itemDto);
Task<RequestItem> PostPutReqItems(InventoryDto itemDto); Task<RequestItem> PostPutReqItems(InventoryDto itemDto);
Task<Lot> PostPutLotNo(InventoryDto itemDto); Task<Lot> PostPutLotNo(InventoryDto itemDto);

View File

@ -12,6 +12,8 @@ namespace CPRNIMS.Domain.Contracts.Inventory
public interface IMRS public interface IMRS
{ {
Task<MRSPagedResult> GetPagedAsync(MRSFilterDto filter, CancellationToken ct,int? departmentId = null, string? userName = ""); Task<MRSPagedResult> GetPagedAsync(MRSFilterDto filter, CancellationToken ct,int? departmentId = null, string? userName = "");
Task<IReadOnlyList<RISSearchResultDto>> SearchRISForReturnAsync(string? risNoQuery, int? projectCodeId, CancellationToken ct);
Task<IReadOnlyList<ProjectCodeOptionDto>> GetProjectsWithOpenRISAsync(string? nameQuery, CancellationToken ct);
Task<MRS?> GetByIdAsync(long mrsId, CancellationToken ct); Task<MRS?> GetByIdAsync(long mrsId, CancellationToken ct);
Task<MRS> CreateAsync(CreateMRSRequest dto, string createdBy, CancellationToken ct); Task<MRS> CreateAsync(CreateMRSRequest dto, string createdBy, CancellationToken ct);
Task ApproveAsync(long mrsId, string approvedBy, CancellationToken ct); Task ApproveAsync(long mrsId, string approvedBy, CancellationToken ct);

View File

@ -16,14 +16,14 @@ namespace CPRNIMS.Domain.Contracts.Items
Task<List<Departments>> GetDepartment(ItemCodeDto itemCode); Task<List<Departments>> GetDepartment(ItemCodeDto itemCode);
Task<PagedResult<ItemList>> GetItemList(ItemCodeDto itemCode); Task<PagedResult<ItemList>> GetItemList(ItemCodeDto itemCode);
Task<List<ItemCart>> GetItemCart(ItemDto itemDto); Task<List<ItemCart>> GetItemCart(ItemDto itemDto);
Task<List<Item>> GetItemDetail(ItemDto itemDto); Task<List<ItemDtos>> GetItemDetail(ItemDto itemDto);
Task<List<ItemLocalization>> GetItemLocalization(ItemDto itemDto); Task<List<ItemLocalization>> GetItemLocalization(ItemDto itemDto);
Task<List<ItemCategory>> GetItemCateg(ItemDto itemDto); Task<List<ItemCategory>> GetItemCateg(ItemDto itemDto);
Task<List<ItemColor>> GetItemColor(ItemDto itemDto); Task<List<ItemColor>> GetItemColor(ItemDto itemDto);
Task<List<UnitOfMessure>> GetItemUOM(ItemDto itemDto); Task<List<UnitOfMessure>> GetItemUOM(ItemDto itemDto);
Task<List<NotifUserKey>> GetNotifUserKey(ItemDto itemDto); Task<List<NotifUserKey>> GetNotifUserKey(ItemDto itemDto);
Task<List<ProjectCodes>> GetProjectCode(); Task<IReadOnlyList<ProjectCodes>> GetProjectCode();
Task<List<ProjectCodes>> GetProjectCodeByTerm(string? fileName); Task<IReadOnlyList<ProjectCodes>> GetProjectCodeByTerm(string? fileName);
Task<(long, long)> GetPRNo(); Task<(long, long)> GetPRNo();
Task<ResponseObject> PostPurchRequest(ItemDto itemDto); Task<ResponseObject> PostPurchRequest(ItemDto itemDto);
Task<ItemCodeDto> PostPutItem(ItemCodeDto itemDto); Task<ItemCodeDto> PostPutItem(ItemCodeDto itemDto);

View File

@ -70,6 +70,7 @@ namespace CPRNIMS.Domain.Contracts.PO
Task<Incoterm> PostPutIncoterms(PODto pODto); Task<Incoterm> PostPutIncoterms(PODto pODto);
Task<bool> DeleteIncShip(PODto poDto); Task<bool> DeleteIncShip(PODto poDto);
Task<bool> PostIncShipFollowUp(PODto pODto); Task<bool> PostIncShipFollowUp(PODto pODto);
Task<IReadOnlyList<Currencies>> GetCurrencies(string currencyName, CancellationToken ct);
#endregion #endregion
} }
} }

View File

@ -12,7 +12,7 @@ namespace CPRNIMS.Domain.Contracts.Receiving
public interface IReceiving public interface IReceiving
{ {
Task<List<ReceivingDetail>> GetRRDetailByPO(ItemDto itemDto); Task<List<ReceivingDetail>> GetRRDetailByPO(ItemDto itemDto);
Task<List<RRDetail>> GetRRDetail(ItemDto itemDto); Task<List<RRDetailDto>> GetRRDetail(ItemDto itemDto);
Task<List<ForReceiving>> GetForReceiving(ItemDto itemDto); Task<List<ForReceiving>> GetForReceiving(ItemDto itemDto);
Task<List<RR>> GetRR(ItemDto itemDto); Task<List<RR>> GetRR(ItemDto itemDto);
Task<List<RRSeries>> GetLatestRRNo(ItemDto itemDto); Task<List<RRSeries>> GetLatestRRNo(ItemDto itemDto);

View File

@ -40,7 +40,7 @@ namespace CPRNIMS.Domain.Services.Finance
return allItems ?? new List<ReceivingDetail>(); return allItems ?? new List<ReceivingDetail>();
} }
public async Task<RRDetail> PostPutPayment(RRDetailsDto itemDto) public async Task<RRDetailDto> PostPutPayment(RRDetailsDto itemDto)
{ {
await _dbContext.Database await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PostPutPayment @UserId, @PONo, @POTypeId, @PRDetailsId", .ExecuteSqlRawAsync("EXEC PostPutPayment @UserId, @PONo, @POTypeId, @PRDetailsId",
@ -48,7 +48,7 @@ namespace CPRNIMS.Domain.Services.Finance
new SqlParameter("@PONo", itemDto.PONo), new SqlParameter("@PONo", itemDto.PONo),
new SqlParameter("@POTypeId", itemDto.POTypeId), new SqlParameter("@POTypeId", itemDto.POTypeId),
new SqlParameter("@PRDetailsId", itemDto.PRDetailsId)); new SqlParameter("@PRDetailsId", itemDto.PRDetailsId));
return new RRDetail(); return new RRDetailDto();
} }
} }
} }

View File

@ -3,7 +3,9 @@ using CPRNIMS.Infrastructure.Database;
using CPRNIMS.Infrastructure.Dto.Inventory; using CPRNIMS.Infrastructure.Dto.Inventory;
using CPRNIMS.Infrastructure.Dto.Inventory.Request; using CPRNIMS.Infrastructure.Dto.Inventory.Request;
using CPRNIMS.Infrastructure.Dto.Inventory.Response; using CPRNIMS.Infrastructure.Dto.Inventory.Response;
using CPRNIMS.Infrastructure.Entities.Account;
using CPRNIMS.Infrastructure.Entities.Inventory; using CPRNIMS.Infrastructure.Entities.Inventory;
using Microsoft.AspNetCore.Identity;
using Microsoft.Data.SqlClient; using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System; using System;
@ -17,9 +19,11 @@ namespace CPRNIMS.Domain.Services.Inventory
public class Inventory : IInventory public class Inventory : IInventory
{ {
private readonly NonInventoryDbContext _dbContext; private readonly NonInventoryDbContext _dbContext;
public Inventory(NonInventoryDbContext dbContext) private readonly UserManager<ApplicationUser> _userManager;
public Inventory(NonInventoryDbContext dbContext, UserManager<ApplicationUser> userManager)
{ {
_dbContext = dbContext; _dbContext = dbContext;
_userManager = userManager;
} }
public async Task<TransactContextDto?> GetTransactContextAsync(int inventoryId, CancellationToken ct) public async Task<TransactContextDto?> GetTransactContextAsync(int inventoryId, CancellationToken ct)
{ {
@ -79,7 +83,7 @@ namespace CPRNIMS.Domain.Services.Inventory
.ToListAsync(ct); .ToListAsync(ct);
var disciplines = await GetDisciplinesAsync(ct); var disciplines = await GetDisciplinesAsync(ct);
var projectCodes = await GetProjectCodesAsync(ct);
return new TransactContextDto return new TransactContextDto
{ {
InventoryId = inv.InventoryId, InventoryId = inv.InventoryId,
@ -91,13 +95,15 @@ namespace CPRNIMS.Domain.Services.Inventory
QtyOnHand = inv.QtyOnHand, QtyOnHand = inv.QtyOnHand,
QtyIn = inv.QtyIn, QtyIn = inv.QtyIn,
QtyOut = inv.QtyOut, QtyOut = inv.QtyOut,
ProjectCodes = projectCodes,
Disciplines = disciplines, Disciplines = disciplines,
OpenRISList = openRIS OpenRISList = openRIS
}; };
} }
public async Task<IEnumerable<DisciplineDto>> GetDisciplinesAsync(CancellationToken ct) public async Task<IReadOnlyList<DisciplineDto>> GetDisciplinesAsync(CancellationToken ct)
{ {
return await _dbContext.Disciplines return await _dbContext.Disciplines
.AsNoTracking()
.OrderBy(d => d.DisciplineName) .OrderBy(d => d.DisciplineName)
.Select(d => new DisciplineDto .Select(d => new DisciplineDto
{ {
@ -106,6 +112,19 @@ namespace CPRNIMS.Domain.Services.Inventory
}) })
.ToListAsync(ct); .ToListAsync(ct);
} }
public async Task<IReadOnlyList<ProjectCodeDto>> GetProjectCodesAsync(CancellationToken ct)
{
return await _dbContext.ProjectCodes
.Where(p => p.StatusName != "Completed" && p.IsActive)
.OrderBy(d => d.ProjectName)
.Select(d => new ProjectCodeDto
{
ProjectCodeId = d.ProjectCodeId,
ProjectCode = d.ProjectCode ?? "N/A",
ProjectName = d.ProjectName ?? "N/A"
})
.ToListAsync(ct);
}
public async Task<List<ItemDetail>> GetInventoryById(InventoryDto itemDto) public async Task<List<ItemDetail>> GetInventoryById(InventoryDto itemDto)
{ {
var allItems = await _dbContext.ItemDetails var allItems = await _dbContext.ItemDetails

View File

@ -1,6 +1,7 @@
using CPRNIMS.Domain.Contracts.Inventory; using CPRNIMS.Domain.Contracts.Inventory;
using CPRNIMS.Infrastructure.Database; using CPRNIMS.Infrastructure.Database;
using CPRNIMS.Infrastructure.Dto.Inventory.Reports; using CPRNIMS.Infrastructure.Dto.Inventory.Reports;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace CPRNIMS.Domain.Services.Inventory namespace CPRNIMS.Domain.Services.Inventory
@ -43,7 +44,7 @@ namespace CPRNIMS.Domain.Services.Inventory
ItemName = r.PRDetail != null ? r.PRDetail.ItemName : "—", ItemName = r.PRDetail != null ? r.PRDetail.ItemName : "—",
ItemNo = r.Inventory.ItemNo, ItemNo = r.Inventory.ItemNo,
DisciplineName = r.Discipline.DisciplineName, DisciplineName = r.Discipline.DisciplineName,
IssuedTo = r.IssuedTo, ProjectName = r.ProjectCodes.ProjectName,
QtyIssued = r.QtyIssued, QtyIssued = r.QtyIssued,
TotalReturned = r.MaterialReturns TotalReturned = r.MaterialReturns
.Where(m => m.Status != 2) .Where(m => m.Status != 2)
@ -79,7 +80,7 @@ namespace CPRNIMS.Domain.Services.Inventory
.ToList(); .ToList();
var topRecipients = rows var topRecipients = rows
.GroupBy(r => r.IssuedTo) .GroupBy(r => r.ProjectName)
.Select(g => new TopRecipient .Select(g => new TopRecipient
{ {
IssuedTo = g.Key, IssuedTo = g.Key,
@ -187,108 +188,104 @@ namespace CPRNIMS.Domain.Services.Inventory
public async Task<InventoryReportDto> GetInventoryReportAsync(DateTime dateFrom, DateTime dateTo, CancellationToken ct, public async Task<InventoryReportDto> GetInventoryReportAsync(DateTime dateFrom, DateTime dateTo, CancellationToken ct,
int? departmentId = null, string? userName = "") int? departmentId = null, string? userName = "")
{ {
var endDate = dateTo.Date.AddDays(1);
var allowedAllDeptUsers = new[] { "LSKRISUR24", "LSCYNDIZ25", "LSJONTAN25", "LHRIOCAS24" }; var allowedAllDeptUsers = new[] { "LSKRISUR24", "LSCYNDIZ25", "LSJONTAN25", "LHRIOCAS24" };
bool seeAllDepartments = !string.IsNullOrWhiteSpace(userName) bool seeAllDepartments = !string.IsNullOrWhiteSpace(userName)
&& allowedAllDeptUsers.Contains(userName, StringComparer.OrdinalIgnoreCase); && allowedAllDeptUsers.Contains(userName, StringComparer.OrdinalIgnoreCase);
var query = _db.InventTransDetails var dto = new InventoryReportDto
.Where(itd =>
itd.IsActive &&
itd.InventTrans.IsActive &&
itd.InventTrans.Inventory.IsActive &&
itd.CreatedDate >= dateFrom &&
itd.CreatedDate < endDate);
if (departmentId.HasValue && !seeAllDepartments)
{
query = query.Where(itd =>
itd.InventTrans.Inventory.User.DepartmentId == departmentId.Value);
}
var rawRows = await query
.Select(itd => new
{
itd.InventTrans.Inventory.InventoryId,
itd.InventTrans.Inventory.ItemNo,
itd.InventTrans.Inventory.QtyIn,
itd.InventTrans.Inventory.QtyOut,
itd.InventTrans.Inventory.QtyOnHand,
LotNo = itd.InventTrans.Inventory.Lot != null
? itd.InventTrans.Inventory.Lot.LotName
: null,
ItemName = itd.InventTrans.Inventory.Item.ItemCode.ItemName ?? "None",
ItemCategoryName =
itd.InventTrans.Inventory.Item.ItemCode.ItemCategory.ItemCategoryName ?? "None",
itd.CreatedDate
})
.ToListAsync(ct);
// De-duplicate: one row per Inventory (latest trans detail wins for the date shown)
var rows = rawRows
.GroupBy(r => r.InventoryId)
.Select(g =>
{
var inv = g.OrderByDescending(x => x.CreatedDate).First();
return new InventoryReportRow
{
ItemName = inv.ItemName,
ItemNo = inv.ItemNo,
ItemCategoryName = inv.ItemCategoryName,
LotNo = inv.LotNo,
QtyIn = inv.QtyIn,
QtyOut = inv.QtyOut,
QtyOnHand = inv.QtyOnHand,
StockPct = inv.QtyIn > 0
? (int)Math.Round(Math.Max(0, Math.Min(100, (inv.QtyOnHand / inv.QtyIn) * 100)))
: 0
};
})
.OrderBy(r => r.ItemName)
.ToList();
var summary = new InventoryReportSummary
{
TotalSKUs = rows.Count,
TotalOnHand = rows.Sum(r => r.QtyOnHand),
TotalQtyIn = rows.Sum(r => r.QtyIn),
TotalQtyOut = rows.Sum(r => r.QtyOut),
LowStockCount = rows.Count(r => r.StockPct < 20 && r.QtyOnHand > 0),
OutOfStockCount = rows.Count(r => r.QtyOnHand <= 0)
};
var byCategory = rows
.GroupBy(r => r.ItemCategoryName)
.Select(g => new CategoryStockLevel
{
CategoryName = g.Key,
AvgStockPct = (int)Math.Round(g.Average(r => r.StockPct))
})
.OrderByDescending(c => c.AvgStockPct)
.ToList();
var alerts = rows
.Where(r => r.StockPct < 20)
.OrderBy(r => r.StockPct)
.Take(10)
.Select(r => new InventoryAlert
{
ItemName = r.ItemName,
QtyOnHand = r.QtyOnHand,
Severity = r.QtyOnHand <= 0 ? "Critical" : "Low"
})
.ToList();
return new InventoryReportDto
{ {
ReportNo = $"RPT-INV-{DateTime.Now:yyyyMM}-{Random.Shared.Next(1, 999):D3}", ReportNo = $"RPT-INV-{DateTime.Now:yyyyMM}-{Random.Shared.Next(1, 999):D3}",
AsOf = dateTo.Date, // reflect the requested period end, not always today AsOf = dateTo.Date,
Summary = summary, Rows = new List<InventoryReportRow>(),
Rows = rows, ByCategory = new List<CategoryStockLevel>(),
ByCategory = byCategory, Alerts = new List<InventoryAlert>(),
Alerts = alerts Summary = new InventoryReportSummary()
};
var conn = _db.Database.GetDbConnection();
await using var cmd = conn.CreateCommand();
cmd.CommandText = "dbo.GetInventoryReport";
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("@DateFrom", dateFrom));
cmd.Parameters.Add(new SqlParameter("@DateTo", dateTo));
cmd.Parameters.Add(new SqlParameter("@DepartmentId", (object?)departmentId ?? DBNull.Value));
cmd.Parameters.Add(new SqlParameter("@SeeAllDepartments", seeAllDepartments ? 1 : 0));
if (conn.State != System.Data.ConnectionState.Open)
await conn.OpenAsync(ct);
try
{
await using var reader = await cmd.ExecuteReaderAsync(ct);
// 1: detail rows
while (await reader.ReadAsync(ct))
{
dto.Rows.Add(new InventoryReportRow
{
ItemName = reader.GetString(reader.GetOrdinal("ItemName")),
ItemNo = reader.GetInt64(reader.GetOrdinal("ItemNo")),
ItemCategoryName = reader.GetString(reader.GetOrdinal("ItemCategoryName")),
LotNo = reader.IsDBNull(reader.GetOrdinal("LotNo"))
? null : reader.GetString(reader.GetOrdinal("LotNo")),
QtyIn = reader.GetDecimal(reader.GetOrdinal("QtyIn")),
QtyOut = reader.GetDecimal(reader.GetOrdinal("QtyOut")),
QtyOnHand = reader.GetDecimal(reader.GetOrdinal("QtyOnHand")),
UnitPrice = reader.GetDecimal(reader.GetOrdinal("UnitPrice")),
StockPct = reader.GetInt32(reader.GetOrdinal("StockPct"))
});
}
// 2: summary
if (await reader.NextResultAsync(ct) && await reader.ReadAsync(ct))
{
dto.Summary = new InventoryReportSummary
{
TotalSKUs = reader.GetInt32(reader.GetOrdinal("TotalSKUs")),
TotalOnHand = reader.GetDecimal(reader.GetOrdinal("TotalOnHand")),
TotalQtyIn = reader.GetDecimal(reader.GetOrdinal("TotalQtyIn")),
TotalQtyOut = reader.GetDecimal(reader.GetOrdinal("TotalQtyOut")),
TotalValue = reader.GetDecimal(reader.GetOrdinal("TotalValue")),
LowStockCount = reader.GetInt32(reader.GetOrdinal("LowStockCount")),
OutOfStockCount = reader.GetInt32(reader.GetOrdinal("OutOfStockCount"))
}; };
} }
// 3: by category
if (await reader.NextResultAsync(ct))
{
while (await reader.ReadAsync(ct))
{
dto.ByCategory.Add(new CategoryStockLevel
{
CategoryName = reader.GetString(reader.GetOrdinal("CategoryName")),
AvgStockPct = reader.GetInt32(reader.GetOrdinal("AvgStockPct"))
});
}
}
// 4: alerts
if (await reader.NextResultAsync(ct))
{
while (await reader.ReadAsync(ct))
{
dto.Alerts.Add(new InventoryAlert
{
ItemName = reader.GetString(reader.GetOrdinal("ItemName")),
QtyOnHand = reader.GetDecimal(reader.GetOrdinal("QtyOnHand")),
Severity = reader.GetString(reader.GetOrdinal("Severity"))
});
}
}
}
finally
{
if (conn.State == System.Data.ConnectionState.Open)
await conn.CloseAsync();
}
return dto;
}
} }
} }

View File

@ -19,6 +19,17 @@ namespace CPRNIMS.Domain.Services.Inventory
} }
public async Task ApproveAsync(long mrsId, string approvedBy, CancellationToken ct) public async Task ApproveAsync(long mrsId, string approvedBy, CancellationToken ct)
{ {
//var user = await _userManager.FindByNameAsync(approvedBy);
//if (user != null)
//{
// bool isApprover2 = await _userManager.IsInRoleAsync(user, "APPROVER2");
// if (!isApprover2)
// {
// throw new Exception("You have no permission to approve this item.");
// }
//}
var rms = await _db.MRS.FindAsync(mrsId) var rms = await _db.MRS.FindAsync(mrsId)
?? throw new InvalidOperationException("MRS not found."); ?? throw new InvalidOperationException("MRS not found.");
@ -34,6 +45,17 @@ namespace CPRNIMS.Domain.Services.Inventory
public async Task CancelAsync(CancelMRSRequest request,string canceledBy, CancellationToken ct) public async Task CancelAsync(CancelMRSRequest request,string canceledBy, CancellationToken ct)
{ {
//var user = await _userManager.FindByNameAsync(canceledBy);
//if (user != null)
//{
// bool isApprover2 = await _userManager.IsInRoleAsync(user, "APPROVER2");
// if (!isApprover2)
// {
// throw new Exception("You have no permission to cancel this item.");
// }
//}
await _transactionFacade.ExecuteAsync(async () => await _transactionFacade.ExecuteAsync(async () =>
{ {
var mrs = await _db.MRS var mrs = await _db.MRS
@ -78,7 +100,7 @@ namespace CPRNIMS.Domain.Services.Inventory
QtyReturned = dto.QtyReturned, QtyReturned = dto.QtyReturned,
Condition = dto.Condition, Condition = dto.Condition,
Remarks = dto.Remarks, Remarks = dto.Remarks,
Status = 0, Status = 1,//Matic Approve for now
CreatedBy = createdBy, CreatedBy = createdBy,
CreatedDate = DateTime.Now CreatedDate = DateTime.Now
}; };
@ -177,7 +199,6 @@ namespace CPRNIMS.Domain.Services.Inventory
return new MRSPagedResult { Data = data, RecordsTotal = total }; return new MRSPagedResult { Data = data, RecordsTotal = total };
} }
private async Task<string> GenerateMRSNoAsync() private async Task<string> GenerateMRSNoAsync()
{ {
var year = DateTime.Now.Year; var year = DateTime.Now.Year;
@ -185,5 +206,55 @@ namespace CPRNIMS.Domain.Services.Inventory
var count = await _db.MRS.CountAsync(m => m.CreatedDate.Year == year) + 1; var count = await _db.MRS.CountAsync(m => m.CreatedDate.Year == year) + 1;
return $"MRS-{year}{month}-{count:D4}"; return $"MRS-{year}{month}-{count:D4}";
} }
public async Task<IReadOnlyList<RISSearchResultDto>> SearchRISForReturnAsync(string? risNoQuery, int? projectCodeId, CancellationToken ct)
{
var query = _db.RIS
.Where(r => r.Status == 1);
if (projectCodeId.HasValue)
query = query.Where(r => r.ProjectCodeId == projectCodeId.Value);
if (!string.IsNullOrWhiteSpace(risNoQuery))
query = query.Where(r => r.RISNo.Contains(risNoQuery));
return await query
.Select(r => new RISSearchResultDto
{
RISId = r.RISId,
RISNo = r.RISNo,
ProjectCodeId = r.ProjectCodeId,
ProjectCode = r.ProjectCodes.ProjectCode ?? "N/A",
ProjectName = r.ProjectCodes.ProjectName ?? "N/A",
DisciplineName = r.Discipline.DisciplineName,
QtyAvailableToReturn = r.QtyIssued - r.MaterialReturns.Sum(m => m.QtyReturned)
})
.Where(r => r.QtyAvailableToReturn > 0)
.OrderByDescending(r => r.RISId)
.Take(20)
.ToListAsync(ct);
}
public async Task<IReadOnlyList<ProjectCodeOptionDto>> GetProjectsWithOpenRISAsync(string? nameQuery, CancellationToken ct)
{
var query = _db.RIS
.Where(r => r.Status == 1 && r.QtyIssued > r.MaterialReturns.Sum(m => m.QtyReturned));
if (!string.IsNullOrWhiteSpace(nameQuery))
query = query.Where(r =>
r.ProjectCodes.ProjectName.Contains(nameQuery) ||
r.ProjectCodes.ProjectCode.Contains(nameQuery));
return await query
.Select(r => new ProjectCodeOptionDto
{
ProjectCodeId = r.ProjectCodeId,
ProjectCode = r.ProjectCodes.ProjectCode ?? "N/A",
ProjectName = r.ProjectCodes.ProjectName ?? "N/A"
})
.Distinct()
.OrderBy(p => p.ProjectName)
.Take(20)
.ToListAsync(ct);
}
} }
} }

View File

@ -42,11 +42,11 @@ namespace CPRNIMS.Domain.Services.Inventory
RISNo = risNo, RISNo = risNo,
InventoryId = dto.InventoryId, InventoryId = dto.InventoryId,
PRDetailId = dto.PRDetailId, PRDetailId = dto.PRDetailId,
IssuedTo = dto.IssuedTo, ProjectCodeId = dto.ProjectCodeId,
DisciplineId = dto.DisciplineId, DisciplineId = dto.DisciplineId,
QtyIssued = dto.QtyIssued, QtyIssued = dto.QtyIssued,
Remarks = dto.Remarks, Remarks = dto.Remarks,
Status = 0, Status = 1,//Approved alredy 0 is Draft
CreatedBy = createdBy, CreatedBy = createdBy,
CreatedDate = DateTime.Now CreatedDate = DateTime.Now
}; };
@ -78,6 +78,17 @@ namespace CPRNIMS.Domain.Services.Inventory
public async Task ApproveAsync(ApproveRISRequest request, string approvedBy, CancellationToken ct) public async Task ApproveAsync(ApproveRISRequest request, string approvedBy, CancellationToken ct)
{ {
//var user = await _userManager.FindByNameAsync(approvedBy);
//if (user != null)
//{
// bool isApprover2 = await _userManager.IsInRoleAsync(user, "APPROVER2");
// if (!isApprover2)
// {
// throw new Exception("You have no permission to approved this item.");
// }
//}
var ris = await _db.RIS.FindAsync(request.RISId, ct) var ris = await _db.RIS.FindAsync(request.RISId, ct)
?? throw new InvalidOperationException("RIS not found."); ?? throw new InvalidOperationException("RIS not found.");
@ -93,6 +104,17 @@ namespace CPRNIMS.Domain.Services.Inventory
public async Task CancelAsync(CancelRISRequest request,string canceledBy, CancellationToken ct) public async Task CancelAsync(CancelRISRequest request,string canceledBy, CancellationToken ct)
{ {
//var user = await _userManager.FindByNameAsync(canceledBy);
//if (user != null)
//{
// bool isApprover2 = await _userManager.IsInRoleAsync(user, "APPROVER2");
// if (!isApprover2)
// {
// throw new Exception("You have no permission to cancel this item.");
// }
//}
await _transactionFacade.ExecuteAsync(async () => await _transactionFacade.ExecuteAsync(async () =>
{ {
var ris = await _db.RIS var ris = await _db.RIS
@ -189,9 +211,10 @@ namespace CPRNIMS.Domain.Services.Inventory
.Any(d => d.PRDetails != null && .Any(d => d.PRDetails != null &&
d.PRDetails.ItemName.Contains(filter.SearchItemName))); d.PRDetails.ItemName.Contains(filter.SearchItemName)));
// Issued To // Issued To is Project code/name
if (!string.IsNullOrWhiteSpace(filter.SearchIssuedTo)) if (!string.IsNullOrWhiteSpace(filter.SearchIssuedTo))
q = q.Where(r => r.IssuedTo.Contains(filter.SearchIssuedTo)); q = q.Where(r => r.ProjectCodes.ProjectCode.Contains(filter.SearchIssuedTo)
|| r.ProjectCodes.ProjectName.Contains(filter.SearchIssuedTo));
// Discipline // Discipline
if (!string.IsNullOrWhiteSpace(filter.Discipline)) if (!string.IsNullOrWhiteSpace(filter.Discipline))
@ -220,7 +243,8 @@ namespace CPRNIMS.Domain.Services.Inventory
.FirstOrDefault() ?? "—", .FirstOrDefault() ?? "—",
ItemNo = r.Inventory.ItemNo, ItemNo = r.Inventory.ItemNo,
LotNo = r.Inventory.Lot != null ? r.Inventory.Lot.LotName : null, LotNo = r.Inventory.Lot != null ? r.Inventory.Lot.LotName : null,
IssuedTo = r.IssuedTo, ProjectName = r.ProjectCodes.ProjectName,
ProjectCode = r.ProjectCodes.ProjectCode,
DisciplineName = r.Discipline.DisciplineName, DisciplineName = r.Discipline.DisciplineName,
DisciplineId = r.DisciplineId, DisciplineId = r.DisciplineId,
QtyIssued = r.QtyIssued, QtyIssued = r.QtyIssued,
@ -253,7 +277,7 @@ namespace CPRNIMS.Domain.Services.Inventory
DisciplineList = disciplines DisciplineList = disciplines
}; };
} }
public async Task<IEnumerable<DisciplineDto>> GetDisciplinesAsync(CancellationToken ct) public async Task<IReadOnlyList<DisciplineDto>> GetDisciplinesAsync(CancellationToken ct)
{ {
return await _db.Disciplines return await _db.Disciplines
.OrderBy(d => d.DisciplineName) .OrderBy(d => d.DisciplineName)
@ -264,6 +288,19 @@ namespace CPRNIMS.Domain.Services.Inventory
}) })
.ToListAsync(ct); .ToListAsync(ct);
} }
public async Task<IReadOnlyList<ProjectCodeDto>> GetProjectCodesAsync(CancellationToken ct)
{
return await _db.ProjectCodes
.Where(p=>p.StatusName !="Completed")
.OrderBy(d => d.ProjectName)
.Select(d => new ProjectCodeDto
{
ProjectCodeId= d.ProjectCodeId,
ProjectCode = d.ProjectCode ?? "N/A",
ProjectName = d.ProjectName ?? "N/A"
})
.ToListAsync(ct);
}
public async Task<RISResponse?> GetByIdAsync(long risId, CancellationToken ct) public async Task<RISResponse?> GetByIdAsync(long risId, CancellationToken ct)
{ {
return await _db.RIS return await _db.RIS
@ -273,7 +310,7 @@ namespace CPRNIMS.Domain.Services.Inventory
RISId = r.RISId, RISId = r.RISId,
RISNo = r.RISNo, RISNo = r.RISNo,
InventoryId = r.InventoryId, InventoryId = r.InventoryId,
IssuedTo = r.IssuedTo, ProjectCodeId = r.ProjectCodeId,
DisciplineName = r.Discipline.DisciplineName, DisciplineName = r.Discipline.DisciplineName,
DisciplineId = r.DisciplineId, DisciplineId = r.DisciplineId,
QtyIssued = r.QtyIssued, QtyIssued = r.QtyIssued,

View File

@ -63,7 +63,6 @@ namespace CPRNIMS.Domain.Services.Items
UserId = itemDto.UserId UserId = itemDto.UserId
}; };
} }
public async Task<Infrastructure.Entities.Items.Item> PutItemDetail(ItemDto itemDto) public async Task<Infrastructure.Entities.Items.Item> PutItemDetail(ItemDto itemDto)
{ {
await _dbContext.Database await _dbContext.Database
@ -92,6 +91,139 @@ namespace CPRNIMS.Domain.Services.Items
return new Infrastructure.Entities.Items.Item(); return new Infrastructure.Entities.Items.Item();
} }
public async Task<ItemAttachement> PostPutItemPath(ItemDto itemDto)
{
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();
}
}
public async Task<ItemCart> PostPutItemCart(ItemDto itemDto)
{
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<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 = attach.FileName;
}
await _dbContext.SaveChangesAsync();
}
Task<ItemCart> IItem.PostPutItemPath(ItemDto itemDto)
{
throw new NotImplementedException();
}
public async Task<List<ItemCart>> GetItemCart(ItemDto itemDto)
{
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>();
}
public async Task<(long, long)> GetPRNo()
{
try
{
var latestPR = await _dbContext.PRs
.Where(ic => ic.PRNo != null)
.OrderByDescending(ic => ic.PRNo)
.FirstOrDefaultAsync();
if (latestPR != null)
return (latestPR.PRNo + 1, latestPR.PRId + 1);
else
return (0, 0);
}
catch (Exception ex)
{
throw;
}
}
public async Task<List<ItemLocalization>> GetItemLocalization(ItemDto itemDto) public async Task<List<ItemLocalization>> GetItemLocalization(ItemDto itemDto)
{ {
var localizations = await _dbContext.ItemLocalizations var localizations = await _dbContext.ItemLocalizations
@ -119,18 +251,16 @@ namespace CPRNIMS.Domain.Services.Items
return categories ?? new List<ItemCategory>(); return categories ?? new List<ItemCategory>();
} }
} }
public async Task<List<ItemDtos>> GetItemDetail(ItemDto itemDto)
public async Task<List<Infrastructure.Entities.Items.Item>> GetItemDetail(ItemDto itemDto)
{ {
var allItems = await _dbContext.Items var allItems = await _dbContext.ItemDtos
.FromSqlRaw($"EXEC GetItemDetail @ItemCodeId,@UserId", .FromSqlRaw($"EXEC GetItemDetail @ItemCodeId,@UserId",
new SqlParameter("@ItemCodeId", itemDto.ItemCodeId), new SqlParameter("@ItemCodeId", itemDto.ItemCodeId),
new SqlParameter("@UserId", itemDto.UserId)) new SqlParameter("@UserId", itemDto.UserId))
.ToListAsync(); .ToListAsync();
return allItems ?? new List<Infrastructure.Entities.Items.Item>(); return allItems ?? new List<ItemDtos>();
} }
public async Task<PagedResult<ItemList>> GetItemList(ItemCodeDto dto) public async Task<PagedResult<ItemList>> GetItemList(ItemCodeDto dto)
{ {
var parameters = new[] var parameters = new[]
@ -200,7 +330,6 @@ namespace CPRNIMS.Domain.Services.Items
return colors ?? new List<ItemColor>(); return colors ?? new List<ItemColor>();
} }
public async Task<List<UnitOfMessure>> GetItemUOM(ItemDto itemDto) public async Task<List<UnitOfMessure>> GetItemUOM(ItemDto itemDto)
{ {
var uoms = await _dbContext.UnitOfMessures var uoms = await _dbContext.UnitOfMessures
@ -211,143 +340,6 @@ namespace CPRNIMS.Domain.Services.Items
return uoms ?? new List<UnitOfMessure>(); return uoms ?? new List<UnitOfMessure>();
} }
public async Task<ItemAttachement> PostPutItemPath(ItemDto itemDto)
{
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();
}
}
public async Task<ItemCart> PostPutItemCart(ItemDto itemDto)
{
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)
{
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>();
}
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 = attach.FileName;
}
await _dbContext.SaveChangesAsync();
}
public async Task<(long,long)> GetPRNo()
{
try
{
var latestPR = await _dbContext.PRs
.Where(ic => ic.PRNo != null)
.OrderByDescending(ic => ic.PRNo)
.FirstOrDefaultAsync();
if (latestPR != null)
return (latestPR.PRNo + 1,latestPR.PRId + 1);
else
return (0,0);
}
catch (Exception ex)
{
throw;
}
}
Task<ItemCart> IItem.PostPutItemPath(ItemDto itemDto)
{
throw new NotImplementedException();
}
public async Task <List<Departments>> GetDepartment(ItemCodeDto itemCode) public async Task <List<Departments>> GetDepartment(ItemCodeDto itemCode)
{ {
return await _dbContext.Departments return await _dbContext.Departments
@ -366,18 +358,18 @@ namespace CPRNIMS.Domain.Services.Items
return allItems ?? new List<NotifUserKey>(); return allItems ?? new List<NotifUserKey>();
} }
public async Task<IReadOnlyList<ProjectCodes>> GetProjectCode()
public async Task<List<ProjectCodes>> GetProjectCode()
{ {
return await _dbContext.ProjectCodes return await _dbContext.ProjectCodes
.AsNoTracking() .AsNoTracking()
.ToListAsync(); .ToListAsync();
} }
public async Task<List<ProjectCodes>> GetProjectCodeByTerm(string? term) public async Task<IReadOnlyList<ProjectCodes>> GetProjectCodeByTerm(string? term)
{ {
return await _dbContext.ProjectCodes return await _dbContext.ProjectCodes
.AsNoTracking() .AsNoTracking()
.Where(p => EF.Functions.Like(p.ProjectCode, $"%{term}%")) .Where(p => p.StatusName != "Completed" && p.IsActive
&& EF.Functions.Like(p.ProjectCode, $"%{term}%"))
.ToListAsync(); .ToListAsync();
} }
} }

View File

@ -30,6 +30,14 @@ namespace CPRNIMS.Domain.Services.PO
_smptHelper = smptHelper; _smptHelper = smptHelper;
} }
#region Get #region Get
public async Task<IReadOnlyList<Currencies>> GetCurrencies(string currencyName, CancellationToken ct)
{
return await _dbContext.Currencies.AsNoTracking()
.Where(c => c.IsActive==true &&
(string.IsNullOrEmpty(currencyName) || c.CurrencyName.Contains(currencyName)))
.ToListAsync(ct);
}
public async Task<POFormData> GetPOFormDataAsync(long? poId) public async Task<POFormData> GetPOFormDataAsync(long? poId)
{ {
// Reuse the connection from your existing DbContext // Reuse the connection from your existing DbContext
@ -493,7 +501,7 @@ namespace CPRNIMS.Domain.Services.PO
await _dbContext.Database await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PostPutCustomPO @UserId,@POTypeId,@PONumber,@PRDetailsId,@Specification,@PRNo,@PORemarks,@IncoTermsId," + .ExecuteSqlRawAsync("EXEC PostPutCustomPO @UserId,@POTypeId,@PONumber,@PRDetailsId,@Specification,@PRNo,@PORemarks,@IncoTermsId," +
$"@PODId,@ProfInvoiceNo,@ProfInvoiceDate,@PaymentTermsId,@ShippingInstructionId,@SupplierId,@DeliveryDate,@Discount,@Amount," + $"@PODId,@ProfInvoiceNo,@ProfInvoiceDate,@PaymentTermsId,@ShippingInstructionId,@SupplierId,@DeliveryDate,@Discount,@Amount," +
$"@UnitPrice,@Quantity,@DeliverTo,@CountryOrigin, @MessCode OUTPUT, @Message OUTPUT", $"@UnitPrice,@Quantity,@DeliverTo,@CountryOrigin,@CurrencyId, @MessCode OUTPUT, @Message OUTPUT",
new SqlParameter("@UserId", pODto.UserId), new SqlParameter("@UserId", pODto.UserId),
new SqlParameter("@POTypeId", pODto.POTypeId), new SqlParameter("@POTypeId", pODto.POTypeId),
new SqlParameter("@PONumber", formattedPONumber), new SqlParameter("@PONumber", formattedPONumber),
@ -516,6 +524,7 @@ namespace CPRNIMS.Domain.Services.PO
new SqlParameter("@Quantity", pODto.Quantity), new SqlParameter("@Quantity", pODto.Quantity),
new SqlParameter("@DeliverTo", pODto.DeliverTo), new SqlParameter("@DeliverTo", pODto.DeliverTo),
new SqlParameter("@CountryOrigin", pODto.CountryOrigin ?? "N/A"), new SqlParameter("@CountryOrigin", pODto.CountryOrigin ?? "N/A"),
new SqlParameter("@CurrencyId", pODto.CurrencyId),
messCode, messCode,
message); message);
@ -544,7 +553,7 @@ namespace CPRNIMS.Domain.Services.PO
await _dbContext.Database await _dbContext.Database
.ExecuteSqlRawAsync("EXEC PutExistingPO @UserId,@POTypeId,@PONumber,@PRDetailsId,@Specification,@PRNo,@PORemarks,@IncoTermsId," + .ExecuteSqlRawAsync("EXEC PutExistingPO @UserId,@POTypeId,@PONumber,@PRDetailsId,@Specification,@PRNo,@PORemarks,@IncoTermsId," +
$"@PODId,@ProfInvoiceNo,@ProfInvoiceDate,@PaymentTermsId,@ShippingInstructionId,@SupplierId,@DeliveryDate,@Discount,@Amount," + $"@PODId,@ProfInvoiceNo,@ProfInvoiceDate,@PaymentTermsId,@ShippingInstructionId,@SupplierId,@DeliveryDate,@Discount,@Amount," +
$"@UnitPrice,@Quantity,@DeliverTo,@IsRemoved,@CountryOrigin, @MessCode OUTPUT, @Message OUTPUT", $"@UnitPrice,@Quantity,@DeliverTo,@IsRemoved,@CountryOrigin,@CurrencyId, @MessCode OUTPUT, @Message OUTPUT",
new SqlParameter("@UserId", pODto.UserId), new SqlParameter("@UserId", pODto.UserId),
new SqlParameter("@POTypeId", pODto.POTypeId), new SqlParameter("@POTypeId", pODto.POTypeId),
new SqlParameter("@PONumber", pODto.PONo), new SqlParameter("@PONumber", pODto.PONo),
@ -568,6 +577,7 @@ namespace CPRNIMS.Domain.Services.PO
new SqlParameter("@DeliverTo", pODto.DeliverTo), new SqlParameter("@DeliverTo", pODto.DeliverTo),
new SqlParameter("@IsRemoved", isRemoved), new SqlParameter("@IsRemoved", isRemoved),
new SqlParameter("@CountryOrigin", pODto.CountryOrigin ?? "N/A"), new SqlParameter("@CountryOrigin", pODto.CountryOrigin ?? "N/A"),
new SqlParameter("@CurrencyId", pODto.CurrencyId),
messCode, messCode,
message); message);
@ -635,7 +645,8 @@ namespace CPRNIMS.Domain.Services.PO
DeliverTo = PODto.DeliverTo ?? "N/A", DeliverTo = PODto.DeliverTo ?? "N/A",
Specification = specification, Specification = specification,
IsUpdate = PODto.IsUpdate, IsUpdate = PODto.IsUpdate,
CountryOrigin=PODto.CountryOrigin CountryOrigin=PODto.CountryOrigin,
CurrencyId=PODto.CurrencyId
}; };
} }
public async Task<DocRequired> PostSuppDocRequirements(PODto poDto) public async Task<DocRequired> PostSuppDocRequirements(PODto poDto)

View File

@ -633,6 +633,17 @@ namespace CPRNIMS.Domain.Services.PR
&& pr.IsActive && pr.IsActive
select pr).AnyAsync(); select pr).AnyAsync();
} }
private async Task<bool> ProjectStatusChanges(int projectCodeId,string? status)
{
var project = await _dbContext.ProjectCodes.FirstOrDefaultAsync(pc=>pc.ProjectCodeId==projectCodeId);
if (project == null)
return false;
if (project.StatusName == status)
return false;
else
return true;
}
public async Task<MessageResponse> PRItemRemoval(PRDto prDto) public async Task<MessageResponse> PRItemRemoval(PRDto prDto)
{ {
var (messCode, message) = CreateOutputParams(); var (messCode, message) = CreateOutputParams();
@ -653,7 +664,6 @@ namespace CPRNIMS.Domain.Services.PR
}; };
return response; return response;
} }
public async Task<ResponseObject> PostPutProjectCode(PRDto prDto) public async Task<ResponseObject> PostPutProjectCode(PRDto prDto)
{ {
if (prDto == null) throw new ArgumentNullException(nameof(prDto)); if (prDto == null) throw new ArgumentNullException(nameof(prDto));
@ -669,13 +679,14 @@ namespace CPRNIMS.Domain.Services.PR
ProjectName = prDto.ProjectName, ProjectName = prDto.ProjectName,
DeliveryAddress = prDto.DeliveryAddress, DeliveryAddress = prDto.DeliveryAddress,
MaxDays = prDto.MaxDays, MaxDays = prDto.MaxDays,
StatusName = prDto.StatusName,
IsActive = prDto.IsActive IsActive = prDto.IsActive
}; };
await _dbContext.ProjectCodes.AddAsync(project); await _dbContext.ProjectCodes.AddAsync(project);
} }
else else
{ {
if (await IsUsingAsync(prDto.ProjectCodeId)) if (await IsUsingAsync(prDto.ProjectCodeId) && await ProjectStatusChanges(prDto.ProjectCodeId,prDto.StatusName) == false)
{ {
return new ResponseObject() return new ResponseObject()
{ {
@ -684,12 +695,17 @@ namespace CPRNIMS.Domain.Services.PR
success = false, success = false,
}; };
} }
if (await IsUsingAsync(prDto.ProjectCodeId))
{
existing.StatusName = prDto.StatusName;
}
else else
{ {
existing.ProjectCode = prDto.ProjectCode; existing.ProjectCode = prDto.ProjectCode;
existing.ProjectName = prDto.ProjectName; existing.ProjectName = prDto.ProjectName;
existing.DeliveryAddress = prDto.DeliveryAddress; existing.DeliveryAddress = prDto.DeliveryAddress;
existing.MaxDays = prDto.MaxDays; existing.MaxDays = prDto.MaxDays;
existing.StatusName = prDto.StatusName;
existing.IsActive = prDto.IsActive; existing.IsActive = prDto.IsActive;
} }
} }

View File

@ -73,7 +73,7 @@ namespace CPRNIMS.Domain.Services.Receiving
return allItems ?? new List<ReceivingDetail>(); return allItems ?? new List<ReceivingDetail>();
} }
public async Task<List<RRDetail>> GetRRDetail(ItemDto itemDto) public async Task<List<RRDetailDto>> GetRRDetail(ItemDto itemDto)
{ {
var allItems = await _dbContext.RRDetailss var allItems = await _dbContext.RRDetailss
.FromSqlRaw("EXEC GetRRDetail @RRNo,@UserId", .FromSqlRaw("EXEC GetRRDetail @RRNo,@UserId",
@ -81,7 +81,7 @@ namespace CPRNIMS.Domain.Services.Receiving
new SqlParameter("@UserId", itemDto.UserId)) new SqlParameter("@UserId", itemDto.UserId))
.ToListAsync(); .ToListAsync();
return allItems ?? new List<RRDetail>(); return allItems ?? new List<RRDetailDto>();
} }
#endregion #endregion
#region Post Put #region Post Put

View File

@ -16,5 +16,7 @@ namespace CPRNIMS.Domain.UIContracts.Inventory
Task<ApiResponse<object>> CreateMRS(CreateMRSRequest request, CancellationToken ct); Task<ApiResponse<object>> CreateMRS(CreateMRSRequest request, CancellationToken ct);
Task<ApiResponse<object>> ApproveMRS(ApproveMRSRequest request, CancellationToken ct); Task<ApiResponse<object>> ApproveMRS(ApproveMRSRequest request, CancellationToken ct);
Task<ApiResponse<object>> CancelMRS(CancelMRSRequest request, CancellationToken ct); Task<ApiResponse<object>> CancelMRS(CancelMRSRequest request, CancellationToken ct);
Task<ApiResponse<List<SearchRISProjectCodeResponse>>> SearchRIS(SearchRISProjectCodeRequest request, CancellationToken ct);
Task<ApiResponse<List<ProjectCodeOptionResponse>>> SearchProjects(SearchRISProjectCodeRequest request, CancellationToken ct);
} }
} }

View File

@ -11,6 +11,7 @@ namespace CPRNIMS.Domain.UIContracts.PO
public interface IPurchaseOrder public interface IPurchaseOrder
{ {
#region Get #region Get
Task<List<POVM>> GetCurrencies(User user, POVM viewModels);
Task<List<POVM>> GetSupplierBidById(User user, POVM viewModel); Task<List<POVM>> GetSupplierBidById(User user, POVM viewModel);
Task<List<POVM>> GetSupplierBidByItem(User user, POVM viewModel); Task<List<POVM>> GetSupplierBidByItem(User user, POVM viewModel);
Task<List<POVM>> GetSupplierBid(User user, POVM viewModel); Task<List<POVM>> GetSupplierBid(User user, POVM viewModel);

View File

@ -1,4 +1,5 @@
using CPRNIMS.Domain.Services; using Azure.Core;
using CPRNIMS.Domain.Services;
using CPRNIMS.Domain.UIContracts.Common; using CPRNIMS.Domain.UIContracts.Common;
using CPRNIMS.Domain.UIContracts.Inventory; using CPRNIMS.Domain.UIContracts.Inventory;
using CPRNIMS.Infrastructure.Dto.Common; using CPRNIMS.Infrastructure.Dto.Common;
@ -141,5 +142,56 @@ namespace CPRNIMS.Domain.UIServices.Inventory
return result; return result;
} }
public async Task<ApiResponse<List<SearchRISProjectCodeResponse>>> SearchRIS(SearchRISProjectCodeRequest request, CancellationToken ct)
{
var token = await _tokenHelper.GetValidTokenAsync();
if (string.IsNullOrEmpty(token))
throw new InvalidOperationException("Token has been expired.");
var baseEndpoint = _configuration["LLI:NonInvent:InventoryMgmt:SearchRIS"]
?? throw new InvalidOperationException("GetMRS endpoint is not configured.");
var qs = new StringBuilder(baseEndpoint).Append('?');
if (!string.IsNullOrWhiteSpace(request.SearchRISNo))
qs.Append($"&searchRISNo={Uri.EscapeDataString(request.SearchRISNo)}");
if (!string.IsNullOrWhiteSpace(request.SearchRISNo))
qs.Append($"&projectCodeId= {request.SearchProjectCodeId}");
using var http = _apiConfigurationService.CreateHttpClientWithDefaultHeaders(token);
var response = await http.GetAsync(qs.ToString(), ct);
var json = await response.Content.ReadAsStringAsync(ct);
if (!response.IsSuccessStatusCode)
return new ApiResponse<List<SearchRISProjectCodeResponse>>{ };
var result = JsonSerializer.Deserialize<ApiResponse<List<SearchRISProjectCodeResponse>>>(json, _mrsJsonOpts);
return result ?? new ApiResponse<List<SearchRISProjectCodeResponse>>();
}
public async Task<ApiResponse<List<ProjectCodeOptionResponse>>> SearchProjects(SearchRISProjectCodeRequest request, CancellationToken ct)
{
var token = await _tokenHelper.GetValidTokenAsync();
if (string.IsNullOrEmpty(token))
throw new InvalidOperationException("Token has expired.");
var baseEndpoint = _configuration["LLI:NonInvent:InventoryMgmt:SearchProjects"]
?? throw new InvalidOperationException("SearchProjects endpoint is not configured.");
var qs = new StringBuilder(baseEndpoint);
if (!string.IsNullOrWhiteSpace(request.SearchProjectCode))
qs.Append('?').Append("searchProjectCode=").Append(Uri.EscapeDataString(request.SearchProjectCode));
using var http = _apiConfigurationService.CreateHttpClientWithDefaultHeaders(token);
var response = await http.GetAsync(qs.ToString(), ct);
var json = await response.Content.ReadAsStringAsync(ct);
if (!response.IsSuccessStatusCode)
return new ApiResponse<List<ProjectCodeOptionResponse>>();
var result = JsonSerializer.Deserialize<ApiResponse<List<ProjectCodeOptionResponse>>>(json, _mrsJsonOpts);
return result ?? new ApiResponse<List<ProjectCodeOptionResponse>>();
}
} }
} }

View File

@ -284,6 +284,11 @@ namespace CPRNIMS.Domain.UIServices.PO
return await SendGetApiRequest(user, viewModel, return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:POMgmt:GetPortOfDischarge"]); _configuration["LLI:NonInvent:POMgmt:GetPortOfDischarge"]);
} }
public async Task<List<POVM>> GetCurrencies(User user, POVM viewModel)
{
return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:POMgmt:GetCurrencies"]);
}
#endregion #endregion
#region Post Put #region Post Put
public async Task<POVM> PostApprovedSupplier(User user, POVM viewModel) public async Task<POVM> PostApprovedSupplier(User user, POVM viewModel)

View File

@ -40,6 +40,7 @@ namespace CPRNIMS.Infrastructure.Database
public virtual DbSet<ItemCode> ItemCodes { get; set; } public virtual DbSet<ItemCode> ItemCodes { get; set; }
public virtual DbSet<ItemList> ItemList { get; set; } public virtual DbSet<ItemList> ItemList { get; set; }
public virtual DbSet<Item> Items { get; set; } public virtual DbSet<Item> Items { get; set; }
public DbSet<ItemDtos> ItemDtos { get; set; }
public DbSet<Attachment> Attachments { get; set; } public DbSet<Attachment> Attachments { get; set; }
public virtual DbSet<AttachmentExtension> AttachmentExtensions { get; set; } public virtual DbSet<AttachmentExtension> AttachmentExtensions { get; set; }
public virtual DbSet<AttachmentFileType> AttachmentFileTypes { get; set; } public virtual DbSet<AttachmentFileType> AttachmentFileTypes { get; set; }
@ -127,6 +128,7 @@ namespace CPRNIMS.Infrastructure.Database
public virtual DbSet<PaymentTerm> PaymentTerms { get; set; } public virtual DbSet<PaymentTerm> PaymentTerms { get; set; }
public virtual DbSet<Incoterm> Incoterms { get; set; } public virtual DbSet<Incoterm> Incoterms { get; set; }
public virtual DbSet<CentralPONo> CentralPONos { get; set; } public virtual DbSet<CentralPONo> CentralPONos { get; set; }
public DbSet<Currencies> Currencies { get; set; }
#endregion #endregion
#region Inventory #region Inventory
@ -148,10 +150,11 @@ namespace CPRNIMS.Infrastructure.Database
public virtual DbSet<ForReceiving> ForReceivings { get; set; } public virtual DbSet<ForReceiving> ForReceivings { get; set; }
public virtual DbSet<Infrastructure.Entities.Receiving.RRReport> RRReports { get; set; } public virtual DbSet<Infrastructure.Entities.Receiving.RRReport> RRReports { get; set; }
public virtual DbSet<ReceivingDetail> ReceivingDetails { get; set; } public virtual DbSet<ReceivingDetail> ReceivingDetails { get; set; }
public virtual DbSet<RRDetail> RRDetails { get; set; } public virtual DbSet<RRDetailDto> RRDetailDtos { get; set; }
public virtual DbSet<ForRR> ForRRs { get; set; } public virtual DbSet<ForRR> ForRRs { get; set; }
public virtual DbSet<RR> RRs { get; set; } public virtual DbSet<RR> RRs { get; set; }
public virtual DbSet<Entities.Receiving.RRDetail> RRDetailss { get; set; } public virtual DbSet<Entities.Receiving.RRDetailDto> RRDetailss { get; set; }
public virtual DbSet<Entities.Receiving.RRDetails> RRDetails { get; set; }
public virtual DbSet<RRSeries> RRSeries { get; set; } public virtual DbSet<RRSeries> RRSeries { get; set; }
#endregion #endregion
@ -294,7 +297,15 @@ namespace CPRNIMS.Infrastructure.Database
.WithMany() .WithMany()
.HasForeignKey(t => t.PRDetailId) .HasForeignKey(t => t.PRDetailId)
.OnDelete(DeleteBehavior.Restrict); .OnDelete(DeleteBehavior.Restrict);
e.HasOne(r => r.RRDetails)
.WithMany()
.HasForeignKey(r => r.RRDetailId)
.IsRequired(false)
.HasForeignKey(r => r.RRDetailId)
.OnDelete(DeleteBehavior.Restrict);
}); });
modelBuilder.Entity<PRDetails>(e => modelBuilder.Entity<PRDetails>(e =>
{ {
e.HasOne(i => i.PRs) e.HasOne(i => i.PRs)
@ -312,6 +323,10 @@ namespace CPRNIMS.Infrastructure.Database
e.HasOne(r => r.Discipline) e.HasOne(r => r.Discipline)
.WithMany() .WithMany()
.HasForeignKey(r => r.DisciplineId); .HasForeignKey(r => r.DisciplineId);
e.HasOne(r => r.ProjectCodes)
.WithMany()
.HasForeignKey(r => r.ProjectCodeId);
}); });
modelBuilder.Entity<MRS>(e => { modelBuilder.Entity<MRS>(e => {

View File

@ -11,4 +11,10 @@ namespace CPRNIMS.Infrastructure.Dto.Inventory
public byte DisciplineId { get; set; } public byte DisciplineId { get; set; }
public string DisciplineName { get; set; } = string.Empty; public string DisciplineName { get; set; } = string.Empty;
} }
public class ProjectCodeDto
{
public string ProjectCode { get; set; } = string.Empty;
public string ProjectName { get; set; } = string.Empty;
public int ProjectCodeId { get; set; }
}
} }

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory
{
public class RISSearchResultDto
{
public long RISId { get; set; }
public string RISNo { get; set; } = string.Empty;
public int ProjectCodeId { get; set; }
public string ProjectCode { get; set; } = string.Empty;
public string ProjectName { get; set; } = string.Empty;
public string DisciplineName { get; set; } = string.Empty;
public decimal QtyAvailableToReturn { get; set; }
}
public class ProjectCodeOptionDto
{
public int ProjectCodeId { get; set; }
public string ProjectCode { get; set; } = string.Empty;
public string ProjectName { get; set; } = string.Empty;
}
}

View File

@ -39,7 +39,7 @@ namespace CPRNIMS.Infrastructure.Dto.Inventory.Reports
public string ItemName { get; set; } = string.Empty; public string ItemName { get; set; } = string.Empty;
public long ItemNo { get; set; } public long ItemNo { get; set; }
public string DisciplineName { get; set; } = string.Empty; public string DisciplineName { get; set; } = string.Empty;
public string IssuedTo { get; set; } = string.Empty; public string ProjectName { get; set; } = string.Empty;
public decimal QtyIssued { get; set; } public decimal QtyIssued { get; set; }
public decimal TotalReturned { get; set; } public decimal TotalReturned { get; set; }
public decimal NetIssued { get; set; } public decimal NetIssued { get; set; }
@ -121,6 +121,7 @@ namespace CPRNIMS.Infrastructure.Dto.Inventory.Reports
public decimal TotalOnHand { get; set; } public decimal TotalOnHand { get; set; }
public decimal TotalQtyIn { get; set; } public decimal TotalQtyIn { get; set; }
public decimal TotalQtyOut { get; set; } public decimal TotalQtyOut { get; set; }
public decimal TotalValue { get; set; }
public int LowStockCount { get; set; } public int LowStockCount { get; set; }
public int OutOfStockCount { get; set; } public int OutOfStockCount { get; set; }
} }
@ -134,6 +135,7 @@ namespace CPRNIMS.Infrastructure.Dto.Inventory.Reports
public decimal QtyIn { get; set; } public decimal QtyIn { get; set; }
public decimal QtyOut { get; set; } public decimal QtyOut { get; set; }
public decimal QtyOnHand { get; set; } public decimal QtyOnHand { get; set; }
public decimal UnitPrice { get; set; }
public int StockPct { get; set; } public int StockPct { get; set; }
} }

View File

@ -10,7 +10,7 @@ namespace CPRNIMS.Infrastructure.Dto.Inventory.Request
{ {
public int InventoryId { get; set; } public int InventoryId { get; set; }
public long PRDetailId { get; set; } public long PRDetailId { get; set; }
public string IssuedTo { get; set; } = string.Empty; public int ProjectCodeId { get; set; }
public byte DisciplineId { get; set; } public byte DisciplineId { get; set; }
public decimal QtyIssued { get; set; } public decimal QtyIssued { get; set; }
public string? Remarks { get; set; } public string? Remarks { get; set; }

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.Inventory.Request
{
public class SearchRISProjectCodeRequest
{
public int? SearchProjectCodeId { get; set; }
public string? SearchRISNo { get; set; }
public string? SearchProjectCode { get; set; }
}
}

View File

@ -27,7 +27,9 @@ namespace CPRNIMS.Infrastructure.Dto.Inventory.Response
public long ItemNo { get; set; } public long ItemNo { get; set; }
public string? IssuedTo { get; set; } public string? ProjectCode { get; set; }
public string? ProjectName { get; set; }
public string? DisciplineName { get; set; } public string? DisciplineName { get; set; }

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.Inventory.Response
{
public class RISProjectCodeResponse
{
public string ProjectCode { get; set; }=string.Empty;
public string ProjectName { get; set; } = string.Empty;
}
}

View File

@ -14,7 +14,7 @@ namespace CPRNIMS.Infrastructure.Dto.Inventory.Response
public string ItemName { get; set; } = string.Empty; public string ItemName { get; set; } = string.Empty;
public long ItemNo { get; set; } public long ItemNo { get; set; }
public string? LotNo { get; set; } public string? LotNo { get; set; }
public string IssuedTo { get; set; } = string.Empty; public int ProjectCodeId { get; set; }
public string DisciplineName { get; set; } = string.Empty; public string DisciplineName { get; set; } = string.Empty;
public string? Message { get; set; } public string? Message { get; set; }
public byte DisciplineId { get; set; } public byte DisciplineId { get; set; }
@ -28,5 +28,7 @@ namespace CPRNIMS.Infrastructure.Dto.Inventory.Response
public DateTime? ApprovedDate { get; set; } public DateTime? ApprovedDate { get; set; }
public decimal MRSCount { get; set; } public decimal MRSCount { get; set; }
public decimal TotalReturned { get; set; } public decimal TotalReturned { get; set; }
public string? ProjectName { get; set; }
public string? ProjectCode { get; set; }
} }
} }

View File

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Dto.Inventory.Response
{
public class SearchApiResponse<T>
{
public bool Success { get; set; }
public List<T> data { get; set; } = new List<T>();
}
public class SearchRISProjectCodeResponse
{
public long RISId { get; set; }
public string RISNo { get; set; } = string.Empty;
public int ProjectCodeId { get; set; }
public string ProjectCode { get; set; } = string.Empty;
public string ProjectName { get; set; } = string.Empty;
public string DisciplineName { get; set; } = string.Empty;
public decimal QtyAvailableToReturn { get; set; }
}
public class ProjectCodeOptionResponse
{
public int ProjectCodeId { get; set; }
public string ProjectCode { get; set; } = string.Empty;
public string ProjectName { get; set; } = string.Empty;
}
}

View File

@ -17,6 +17,7 @@ namespace CPRNIMS.Infrastructure.Dto.Inventory
public decimal QtyOnHand { get; set; } public decimal QtyOnHand { get; set; }
public decimal QtyIn { get; set; } public decimal QtyIn { get; set; }
public decimal QtyOut { get; set; } public decimal QtyOut { get; set; }
public IEnumerable<ProjectCodeDto> ProjectCodes { get; set; } = [];
public IEnumerable<DisciplineDto> Disciplines { get; set; } = []; public IEnumerable<DisciplineDto> Disciplines { get; set; } = [];
public IEnumerable<RISReferenceDto> OpenRISList { get; set; } = []; public IEnumerable<RISReferenceDto> OpenRISList { get; set; } = [];
} }

View File

@ -23,7 +23,7 @@ namespace CPRNIMS.Infrastructure.Dto.PO
public string? SupplierName { get; set; } public string? SupplierName { get; set; }
public string? Manufacturer { get; set; } public string? Manufacturer { get; set; }
public int ItemCount { get; set; } public int ItemCount { get; set; }
public short CurrencyId { get; set; } public byte CurrencyId { get; set; }
public string? Department { get; set; } public string? Department { get; set; }
public string? ItemCategoryName { get; set; } public string? ItemCategoryName { get; set; }
public DateTime CommitmentDate { get; set; } public DateTime CommitmentDate { get; set; }

View File

@ -23,6 +23,7 @@ namespace CPRNIMS.Infrastructure.Entities.Account
public DateTime UpdatedDate { get; set; } public DateTime UpdatedDate { get; set; }
public string? ProfilePicture { get; set; } public string? ProfilePicture { get; set; }
public string? Address { get; set; } public string? Address { get; set; }
public bool? IsActive { get; set; }
public Attachment? Attachment { get; set; } public Attachment? Attachment { get; set; }
} }
} }

View File

@ -8,7 +8,7 @@ using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Entities.Finance namespace CPRNIMS.Infrastructure.Entities.Finance
{ {
public class RRDetail : CommonProperties public class RRDetailDto : CommonProperties
{ {
[Key] [Key]
public long RRDetailId { get; set; } public long RRDetailId { get; set; }

View File

@ -18,7 +18,6 @@ namespace CPRNIMS.Infrastructure.Entities.Inventory
public string CreatedBy { get; set; }=string.Empty; public string CreatedBy { get; set; }=string.Empty;
public bool IsActive { get; set; } public bool IsActive { get; set; }
public Inventory? Inventory { get; set; } public Inventory? Inventory { get; set; }
// public InventTransDetail? InventTransDetail { get; set; }
public ICollection<InventTransDetail> InventTransDetails { get; set; } = []; public ICollection<InventTransDetail> InventTransDetails { get; set; } = [];
} }
} }

View File

@ -1,5 +1,6 @@
using CPRNIMS.Infrastructure.Entities.Items; using CPRNIMS.Infrastructure.Entities.Items;
using CPRNIMS.Infrastructure.Entities.Purchasing; using CPRNIMS.Infrastructure.Entities.Purchasing;
using CPRNIMS.Infrastructure.Entities.Receiving;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
@ -17,15 +18,15 @@ namespace CPRNIMS.Infrastructure.Entities.Inventory
public long InventTransDetailId { get; set; } public long InventTransDetailId { get; set; }
public int InventTransId { get; set; } public int InventTransId { get; set; }
public byte TransTypeId { get; set; } public byte TransTypeId { get; set; }
public long RRDetailId { get; set; }
public decimal QtyIn { get; set; } public decimal QtyIn { get; set; }
public decimal QtyOut { get; set; } public decimal QtyOut { get; set; }
public DateTime CreatedDate { get; set; } public DateTime CreatedDate { get; set; }
public string? Remarks { get; set; } public string? Remarks { get; set; }
public bool IsActive { get; set; } public bool IsActive { get; set; }
public long PRDetailId { get; set; } public long PRDetailId { get; set; }
public long? RRDetailId { get; set; }
public PRDetails? PRDetails { get; set; } public PRDetails? PRDetails { get; set; }
public ItemCategory? ItemCategory { get; set; } public RRDetails? RRDetails { get; set; }
public InventTrans? InventTrans { get; set; } public InventTrans? InventTrans { get; set; }
} }
} }

View File

@ -20,10 +20,6 @@ namespace CPRNIMS.Infrastructure.Entities.Inventory
public int InventoryId { get; set; } public int InventoryId { get; set; }
public long PRDetailId { get; set; } public long PRDetailId { get; set; }
[Required, MaxLength(450)]
public string IssuedTo { get; set; } = string.Empty;
public byte DisciplineId { get; set; } public byte DisciplineId { get; set; }
public decimal QtyIssued { get; set; } public decimal QtyIssued { get; set; }
@ -40,6 +36,8 @@ namespace CPRNIMS.Infrastructure.Entities.Inventory
public string? CanceledBy { get; set; } public string? CanceledBy { get; set; }
public DateTime? CanceledDate { get; set; } public DateTime? CanceledDate { get; set; }
public string? Reason { get; set; } public string? Reason { get; set; }
public int ProjectCodeId { get; set; }
public ProjectCodes ProjectCodes { get; set; } = null!;
public Inventory Inventory { get; set; } = null!; public Inventory Inventory { get; set; } = null!;
public PRDetails PRDetail { get; set; } = null!; public PRDetails PRDetail { get; set; } = null!;
public Discipline Discipline { get; set; } = null!; public Discipline Discipline { get; set; } = null!;

View File

@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Entities.Items
{
public class ItemDtos
{
[Key]
public long ItemNo { get; set; }
public long ItemCodeId { get; set; }
public string? Department { get; set; }
public string? ItemCategoryName { get; set; }
public string? UserId { get; set; }
public string? ItemName { get; set; }
public string? ItemDescription { get; set; }
public string? StatusName { get; set; }
public bool IsActive { get; set; }
public bool IsCommon { get; set; }
public byte RequestTypeId { get; set; }
public string? ItemLocalName { get; set; }
public string? ItemTypeName { get; set; }
public string? PRTypeName { get; set; }
public decimal Qty { get; set; }
public int ItemColorId { get; set; }
public short ItemLocalId { get; set; }
public int UOMId { get; set; }
public short ItemCategoryId { get; set; }
public string? PackagingTypeName { get; set; }
public short ItemClassId { get; set; }
public string? UOMName { get; set; }
public string? ItemColorName { get; set; }
public long ItemAttachId { get; set; }
public string? ItemAttachPath { get; set; }
public bool IsMDLD { get; set; }
public bool CheckBox { 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.PO
{
[Table("Currencies")]
public class Currencies
{
[Key]
public byte CurrencyId { get; set; }
public string CurrencyName { get; set; }=string.Empty;
public decimal VatRate { get; set; }
public decimal CER { get; set; }
public string? AmountWords { get; set; }
public bool? IsActive { get; set; }
}
}

View File

@ -34,6 +34,7 @@ namespace CPRNIMS.Infrastructure.Entities.PO
public byte PODId { get; set; } public byte PODId { get; set; }
public byte POTypeId { get; set; } public byte POTypeId { get; set; }
public byte IncoTermsId { get; set; } public byte IncoTermsId { get; set; }
public byte CurrencyId { get; set; }
public string? IncotermsName { get; set; } public string? IncotermsName { get; set; }
public string? CountryOrigin { get; set; } public string? CountryOrigin { get; set; }
} }

View File

@ -17,6 +17,7 @@ namespace CPRNIMS.Infrastructure.Entities.Purchasing
public string? ProjectName { get; set; } public string? ProjectName { get; set; }
public int MaxDays { get; set; } public int MaxDays { get; set; }
public string? DeliveryAddress { get; set; } public string? DeliveryAddress { get; set; }
public string? StatusName { get; set; }
public bool IsActive { get; set; } public bool IsActive { get; set; }
} }
} }

View File

@ -8,7 +8,7 @@ using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Entities.Receiving namespace CPRNIMS.Infrastructure.Entities.Receiving
{ {
public class RRDetail public class RRDetailDto
{ {
[Key] [Key]
public long PRDetailsId { get; set; } public long PRDetailsId { get; set; }

View File

@ -0,0 +1,25 @@
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.Receiving
{
[Table("RRDetails")]
public class RRDetails
{
[Key]
public long RRDetailId { get; set; }
public long PRDetailId { get; set; }
public long RRId { get; set; }
public long PODetailId { get; set; }
public decimal Quantity { get; set; }
public decimal QuantityReceived { get; set; }
public decimal QtyRemaining { get; set; }
public decimal UnitPrice { get; set; }
public bool IsActive { get; set; }
}
}

View File

@ -23,5 +23,6 @@ namespace CPRNIMS.Infrastructure.Models.Account
public string? Token { get; set; } public string? Token { get; set; }
public string? Company { get; set; } public string? Company { get; set; }
public string? MyAccess { get; set; } public string? MyAccess { get; set; }
public int DepartmentId { get; set; }
} }
} }

View File

@ -24,7 +24,7 @@ namespace CPRNIMS.Infrastructure.ViewModel.PO
public string? ContactPerson { get; set; } public string? ContactPerson { get; set; }
public string? Manufacturer { get; set; } public string? Manufacturer { get; set; }
public int ItemCount { get; set; } public int ItemCount { get; set; }
public short CurrencyId { get; set; } public byte CurrencyId { get; set; }
public string? Department { get; set; } public string? Department { get; set; }
public string? ItemCategoryName { get; set; } public string? ItemCategoryName { get; set; }
public DateTime CommitmentDate { get; set; } public DateTime CommitmentDate { get; set; }

View File

@ -29,9 +29,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="FastReport.OpenSource" Version="2026.2.3" />
<PackageReference Include="FastReport.OpenSource.Export.PdfSimple" Version="2026.2.3" />
<PackageReference Include="FastReport.OpenSource.Web" Version="2026.2.3" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.0" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup> </ItemGroup>

View File

@ -23,7 +23,20 @@ namespace CPRNIMS.WebApi.Controllers.Inventory
var result = await _mrs.GetPagedAsync(filter, ct, currentUser.DepartmentId, currentUser.UserName); var result = await _mrs.GetPagedAsync(filter, ct, currentUser.DepartmentId, currentUser.UserName);
return Ok(result); return Ok(result);
} }
[HttpPost()] [HttpGet("SearchRIS")]
public async Task<IActionResult> SearchRIS([FromQuery] string? searchRISNo, int? projectCodeId, CancellationToken ct)
{
var results = await _mrs.SearchRISForReturnAsync(searchRISNo, projectCodeId, ct);
return Ok(new { success = true, data = results });
}
[HttpGet("SearchProjects")]
public async Task<IActionResult> SearchProjects([FromQuery] string? searchProjectCode, CancellationToken ct)
{
var results = await _mrs.GetProjectsWithOpenRISAsync(searchProjectCode, ct);
return Ok(new { success = true, data = results });
}
[HttpPost]
public async Task<IActionResult> CreateMRS([FromBody] CreateMRSRequest request, CancellationToken ct) public async Task<IActionResult> CreateMRS([FromBody] CreateMRSRequest request, CancellationToken ct)
{ {
var currentUser = User.ToUserClaims(); var currentUser = User.ToUserClaims();

View File

@ -284,6 +284,12 @@ namespace CPRNIMS.WebApi.Controllers.PO
} }
#endregion #endregion
#region Get #region Get
[HttpPost("GetCurrencies")]
public async Task<IActionResult> GetCurrencies(Currencies request, CancellationToken ct)
{
var data = await _purchaseOrder.GetCurrencies(request.CurrencyName,ct);
return Ok(data);
}
[HttpGet("GetPOFormData")] [HttpGet("GetPOFormData")]
public async Task<IActionResult> GetPOFormData(int? poId = null) public async Task<IActionResult> GetPOFormData(int? poId = null)
{ {

View File

@ -17,14 +17,14 @@ if (app.Environment.IsDevelopment())
app.UseSwagger(); app.UseSwagger();
app.UseSwaggerUI(c => app.UseSwaggerUI(c =>
{ {
c.SwaggerEndpoint("./v2/swagger.json", "LLOYD API V2"); //originally "./swagger/v1/swagger.json" c.SwaggerEndpoint("./v2/swagger.json", "LLOYD API V2");
}); });
} }
app.UseMiddleware<GlobalExceptionMiddleware>(); app.UseMiddleware<GlobalExceptionMiddleware>();
app.UseSwagger(); app.UseSwagger();
app.UseSwaggerUI(c => app.UseSwaggerUI(c =>
{ {
c.SwaggerEndpoint("./v2/swagger.json", "LLOYD API V2"); //originally "./swagger/v1/swagger.json" c.SwaggerEndpoint("./v2/swagger.json", "LLOYD API V2");
}); });
app.UseCors("AllowAnyOrigin"); app.UseCors("AllowAnyOrigin");

View File

@ -16,7 +16,7 @@ CREATE TABLE [dbo].[RIS] (
[RISNo] VARCHAR(50) NOT NULL, -- generated slip number [RISNo] VARCHAR(50) NOT NULL, -- generated slip number
[InventoryId] INT NOT NULL, [InventoryId] INT NOT NULL,
[PRDetailId] BIGINT NOT NULL, [PRDetailId] BIGINT NOT NULL,
[IssuedTo] VARCHAR(450) NOT NULL, -- UserId receiving items [ProjectCodeId] INT NOT NULL, -- UserId receiving items
[DisciplineId] TINYINT NOT NULL, -- Trade/Matrix/Structural/Architectural [DisciplineId] TINYINT NOT NULL, -- Trade/Matrix/Structural/Architectural
[QtyIssued] DECIMAL(14,2) NOT NULL, [QtyIssued] DECIMAL(14,2) NOT NULL,
[Remarks] VARCHAR(500) NULL, [Remarks] VARCHAR(500) NULL,
@ -30,7 +30,8 @@ CREATE TABLE [dbo].[RIS] (
Reason VARCHAR(150) NULL, Reason VARCHAR(150) NULL,
FOREIGN KEY ([InventoryId]) REFERENCES [Inventory]([InventoryId]), FOREIGN KEY ([InventoryId]) REFERENCES [Inventory]([InventoryId]),
FOREIGN KEY ([PRDetailId]) REFERENCES [PRDetails]([PRDetailsId]), FOREIGN KEY ([PRDetailId]) REFERENCES [PRDetails]([PRDetailsId]),
FOREIGN KEY ([DisciplineId]) REFERENCES [Disciplines]([DisciplineId]) FOREIGN KEY ([DisciplineId]) REFERENCES [Disciplines]([DisciplineId]),
FOREIGN KEY ([ProjectCodeId]) REFERENCES ProjectCodes([ProjectCodeId])
); );
-- ── MRS: Material Return Slip ───────────────────────────────────── -- ── MRS: Material Return Slip ─────────────────────────────────────

View File

@ -43,6 +43,7 @@ namespace CPRNIMS.WebApps.Controllers.Base
UserName = User.Identity?.Name, UserName = User.Identity?.Name,
FullName = User.FindFirst("FullName")?.Value, FullName = User.FindFirst("FullName")?.Value,
Company = User.FindFirst("Company")?.Value, Company = User.FindFirst("Company")?.Value,
DepartmentId = Convert.ToInt32(User.FindFirst("DepartmentId")?.Value),
MyAccess = UserRoles, MyAccess = UserRoles,
URLAttachment = User.FindFirst("URLAttachment")?.Value URLAttachment = User.FindFirst("URLAttachment")?.Value
}; };

View File

@ -5,6 +5,7 @@ using CPRNIMS.Infrastructure.Helper;
using CPRNIMS.Infrastructure.ViewModel.Inventory; using CPRNIMS.Infrastructure.ViewModel.Inventory;
using CPRNIMS.WebApps.Controllers.Base; using CPRNIMS.WebApps.Controllers.Base;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
namespace CPRNIMS.WebApps.Controllers.Inventory namespace CPRNIMS.WebApps.Controllers.Inventory
@ -133,7 +134,10 @@ namespace CPRNIMS.WebApps.Controllers.Inventory
#region Views #region Views
public IActionResult GetInventoryTabPage(int id) public IActionResult GetInventoryTabPage(int id)
{ {
return ViewComponent("InventoryTabPage", new { inventoryTabPageId = id }); var currentDepartment = GetUser();
bool isFinance = currentDepartment.DepartmentId is 6 or 9;
return ViewComponent("InventoryTabPage", new { inventoryTabPageId = id, isFinance });
} }
public async Task<IActionResult> Inventory() public async Task<IActionResult> Inventory()
{ {

View File

@ -40,7 +40,25 @@ namespace CPRNIMS.WebApps.Controllers.Inventory
return Json(new { data = result.Data, recordsTotal = result.RecordsTotal}); return Json(new { data = result.Data, recordsTotal = result.RecordsTotal});
} }
[HttpGet]
public async Task<IActionResult> SearchRIS([FromQuery] int? searchProjectCodeId, string? searchRISNo , CancellationToken ct = default)
{
var result = await _mrs.SearchRIS(new SearchRISProjectCodeRequest
{
SearchRISNo = searchRISNo,
SearchProjectCodeId = searchProjectCodeId,
}, ct);
return Json(new { data = result.data, success = result.success, message = result.message });
}
[HttpGet]
public async Task<IActionResult> SearchProjects([FromQuery] string? searchProjectCode, CancellationToken ct = default)
{
var result = await _mrs.SearchProjects(new SearchRISProjectCodeRequest
{ SearchProjectCode = searchProjectCode,}, ct);
return Json(new { data = result.data, success = result.success, message = result.message });
}
[HttpPost] [HttpPost]
public async Task<IActionResult> CreateMRS([FromBody] CreateMRSRequest request,CancellationToken ct) public async Task<IActionResult> CreateMRS([FromBody] CreateMRSRequest request,CancellationToken ct)
{ {

View File

@ -418,6 +418,26 @@ namespace CPRNIMS.WebApps.Controllers.PO
response = await _purchaseOrder.GetOtherCharges(GetUser(), viewModels); response = await _purchaseOrder.GetOtherCharges(GetUser(), viewModels);
return GetResponse(response); return GetResponse(response);
} }
[HttpGet]
public async Task<IActionResult> GetCurrencies([FromQuery] string query)
{
var viewModels = new POVM();
viewModels.CurrencyName = query;
var responseQuery = await _purchaseOrder.GetCurrencies(GetUser(), viewModels);
if (responseQuery == null)
{
responseQuery = new List<POVM>();
}
var formattedData = responseQuery.Select(item => new
{
label = item.CurrencyName,
value = item.CurrencyId,
value2 = item.Currency
});
return Json(new { success = true, data = formattedData });
}
public async Task<IActionResult> GetSuppliers(string query) public async Task<IActionResult> GetSuppliers(string query)
{ {
var viewModels = new POVM(); var viewModels = new POVM();
@ -435,6 +455,7 @@ namespace CPRNIMS.WebApps.Controllers.PO
value2 = item.Currency, value2 = item.Currency,
value3 = item.PaymentTerms, value3 = item.PaymentTerms,
value4 = item.PaymentTermsId, value4 = item.PaymentTermsId,
value5 = item.CurrencyId
}); });
return Json(new { success = true, data = formattedData }); return Json(new { success = true, data = formattedData });

View File

@ -17,10 +17,6 @@ if (!app.Environment.IsDevelopment())
app.UseHsts(); app.UseHsts();
} }
//var provider = new FileExtensionContentTypeProvider();
//provider.Mappings[".js"] = "text/javascript";
//provider.Mappings[".css"] = "text/css";
app.UseHttpsRedirection(); app.UseHttpsRedirection();
app.UseStaticFiles(); app.UseStaticFiles();
app.UseRouting(); app.UseRouting();

View File

@ -4,14 +4,17 @@ namespace CPRNIMS.WebApps.ViewComponents.Inventory
{ {
public class InventoryTabPageViewComponent : ViewComponent public class InventoryTabPageViewComponent : ViewComponent
{ {
public IViewComponentResult Invoke(int InventoryTabPageId) public IViewComponentResult Invoke(int InventoryTabPageId,bool isFinance)
{ {
var report = isFinance ? "~/Views/Components/Inventory/TabPage/Reports/InventorySummaryReportFinance.cshtml"
: "~/Views/Components/Inventory/TabPage/Reports/InventorySummaryReport.cshtml";
string viewName = InventoryTabPageId switch string viewName = InventoryTabPageId switch
{ {
1 => "~/Views/Components/Inventory/TabPage/Inventory.cshtml", 1 => "~/Views/Components/Inventory/TabPage/Inventory.cshtml",
2 => "~/Views/Components/Inventory/TabPage/RIS.cshtml", 2 => "~/Views/Components/Inventory/TabPage/RIS.cshtml",
3 => "~/Views/Components/Inventory/TabPage/MRS.cshtml", 3 => "~/Views/Components/Inventory/TabPage/MRS.cshtml",
4 => "~/Views/Components/Inventory/TabPage/Reports/InventorySummaryReport.cshtml", 4 => report,
5 => "~/Views/Components/Inventory/TabPage/Reports/RISReport.cshtml", 5 => "~/Views/Components/Inventory/TabPage/Reports/RISReport.cshtml",
_ => "~/Views/Components/Inventory/TabPage/Reports/MRSReport.cshtml" _ => "~/Views/Components/Inventory/TabPage/Reports/MRSReport.cshtml"
}; };

View File

@ -1,8 +1,3 @@
@* ── Tab: Return Issuance Slip — For Approval ───────────────────────────────
Returned by GetInventoryTabPage?id=2 (or whichever tab id you assign)
Depends on: _InventoryStyles, _InventoryHelpers, window.InventoryHelpers
────────────────────────────────────────────────────────────────────────────── *@
@* ── FILTER BAR ── *@ @* ── FILTER BAR ── *@
<div class="inv-filters"> <div class="inv-filters">
<div class="inv-search-box"> <div class="inv-search-box">

View File

@ -126,39 +126,40 @@
<!-- BODY --> <!-- BODY -->
<div style="padding:16px 18px;display:flex;flex-direction:column;gap:14px"> <div style="padding:16px 18px;display:flex;flex-direction:column;gap:14px">
<!-- Project code/name search -->
<div class="tm-form-group" style="position:relative">
<label class="tm-label">
<i class="fas fa-qrcode"></i> Project code/name <span class="tm-req">*</span>
</label>
<input id="mrs-project-code-name-search" class="tm-input"
type="text" placeholder="Type project code/name to search…"
autocomplete="off">
<input type="hidden" id="mrs-project-code-name">
<div id="mrs-project-code-name-results" class="tm-search-dropdown"></div>
</div>
<!-- RIS reference search --> <!-- RIS reference search -->
<div class="tm-form-group"> <div class="tm-form-group" style="position:relative">
<label class="tm-label"> <label class="tm-label">
<i class="fas fa-receipt"></i> RIS Reference <span class="tm-req">*</span> <i class="fas fa-receipt"></i> RIS Reference <span class="tm-req">*</span>
</label> </label>
<div style="position:relative">
<input id="mrs-ris-search" class="tm-input" <input id="mrs-ris-search" class="tm-input"
type="text" placeholder="Type RIS number to search…" type="text" placeholder="Type RIS number to search…"
autocomplete="off"> autocomplete="off">
<div id="mrs-ris-results" style=" <input type="hidden" id="tm-mrs-ris">
display:none;position:absolute;top:100%;left:0;right:0;z-index:10; <div id="mrs-ris-results" class="tm-search-dropdown"></div>
background:#fff;border:1.5px solid var(--teal-mid,#0e7c86);
border-top:none;border-radius:0 0 8px 8px;
max-height:200px;overflow-y:auto;
box-shadow:0 8px 20px rgba(0,0,0,.12)">
</div>
</div>
</div> </div>
<!-- Selected RIS detail badge --> <!-- Selected RIS detail badge -->
<div id="mrs-selected-ris-badge" style="display:none; <div id="mrs-selected-ris-badge" style="display:none;
background:var(--teal-pale,#e6f7f8);border:1px solid var(--border,#d6eaec); background:var(--teal-pale,#e6f7f8);border:1px solid var(--border,#d6eaec);
border-radius:10px;padding:12px 14px; border-radius:10px;padding:12px 14px;
display:none;flex-direction:column;gap:8px"> flex-direction:column;gap:8px">
<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px"> <div style="display:grid;grid-template-columns:1fr 1fr;gap:8px">
<div class="am-field"> <div class="am-field">
<span class="am-lbl"><i class="fas fa-hashtag"></i> RIS No</span> <span class="am-lbl"><i class="fas fa-hashtag"></i> RIS No</span>
<span class="am-val" id="mrs-sel-risno">—</span> <span class="am-val" id="mrs-sel-risno">—</span>
</div> </div>
<div class="am-field">
<span class="am-lbl"><i class="fas fa-cubes"></i> Qty Issued</span>
<span class="am-val" id="mrs-sel-qtyissued">—</span>
</div>
<div class="am-field"> <div class="am-field">
<span class="am-lbl"><i class="fas fa-undo"></i> Max Return</span> <span class="am-lbl"><i class="fas fa-undo"></i> Max Return</span>
<span class="am-val" id="mrs-sel-maxreturn" <span class="am-val" id="mrs-sel-maxreturn"
@ -167,8 +168,8 @@
</div> </div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px"> <div style="display:grid;grid-template-columns:1fr 1fr;gap:8px">
<div class="am-field"> <div class="am-field">
<span class="am-lbl"><i class="fas fa-box"></i> Item</span> <span class="am-lbl"><i class="fas fa-diagram-project"></i> Project</span>
<span class="am-val" id="mrs-sel-itemname">—</span> <span class="am-val" id="mrs-sel-project">—</span>
</div> </div>
<div class="am-field"> <div class="am-field">
<span class="am-lbl"><i class="fas fa-tools"></i> Discipline</span> <span class="am-lbl"><i class="fas fa-tools"></i> Discipline</span>
@ -207,7 +208,7 @@
<i class="fas fa-user"></i> Returned By <span class="tm-req">*</span> <i class="fas fa-user"></i> Returned By <span class="tm-req">*</span>
</label> </label>
<input id="mrs-create-returnedby" class="tm-input" <input id="mrs-create-returnedby" class="tm-input"
type="text" placeholder="Name or user ID…"> type="text" placeholder="Name…">
</div> </div>
<div class="tm-form-group"> <div class="tm-form-group">
@ -255,7 +256,9 @@
<div> <div>
<div style="font-size:14px;font-weight:600;color:#fff">Approve MRS</div> <div style="font-size:14px;font-weight:600;color:#fff">Approve MRS</div>
<div id="mrs-approve-subtitle" <div id="mrs-approve-subtitle"
style="font-size:11px;color:rgba(255,255,255,.65);margin-top:2px">—</div> style="font-size:11px;color:rgba(255,255,255,.65);margin-top:2px">
</div>
</div> </div>
</div> </div>
<div style="padding:20px 18px"> <div style="padding:20px 18px">
@ -303,7 +306,9 @@
<div> <div>
<div style="font-size:14px;font-weight:600;color:#fff">Cancel MRS</div> <div style="font-size:14px;font-weight:600;color:#fff">Cancel MRS</div>
<div id="mrs-cancel-subtitle" <div id="mrs-cancel-subtitle"
style="font-size:11px;color:rgba(255,255,255,.65);margin-top:2px">—</div> style="font-size:11px;color:rgba(255,255,255,.65);margin-top:2px">
</div>
</div> </div>
</div> </div>
<div style="padding:20px 18px"> <div style="padding:20px 18px">
@ -353,9 +358,17 @@
gap: 16px; gap: 16px;
min-height: 220px; min-height: 220px;
} }
@@media (max-width: 768px) { .mrs-grid { grid-template-columns: 1fr; } }
@@media (max-width: 768px) {
.mrs-grid {
grid-template-columns: 1fr;
}
}
@@media (min-width: 769px) and (max-width: 1100px) { @@media (min-width: 769px) and (max-width: 1100px) {
.mrs-grid { grid-template-columns: repeat(2, 1fr); } .mrs-grid {
grid-template-columns: repeat(2, 1fr);
}
} }
/* ── MRS card ── */ /* ── MRS card ── */
@ -369,7 +382,11 @@
flex-direction: column; flex-direction: column;
transition: box-shadow .25s, transform .25s; transition: box-shadow .25s, transform .25s;
} }
.mrs-card:hover { box-shadow: var(--shadow-hover); transform: translateY(-2px); }
.mrs-card:hover {
box-shadow: var(--shadow-hover);
transform: translateY(-2px);
}
/* ── Card header — blue theme for MRS ── */ /* ── Card header — blue theme for MRS ── */
.mrs-card-hd { .mrs-card-hd {
@ -377,6 +394,7 @@
padding: 14px 16px 12px; padding: 14px 16px 12px;
position: relative; position: relative;
} }
.mrs-card-no { .mrs-card-no {
font-size: .7rem; font-size: .7rem;
color: rgba(255,255,255,.6); color: rgba(255,255,255,.6);
@ -385,6 +403,7 @@
text-transform: uppercase; text-transform: uppercase;
margin-bottom: 3px; margin-bottom: 3px;
} }
.mrs-card-title { .mrs-card-title {
font-family: 'Space Grotesk', sans-serif; font-family: 'Space Grotesk', sans-serif;
font-size: 1rem; font-size: 1rem;
@ -394,6 +413,7 @@
word-break: break-word; word-break: break-word;
margin-bottom: 6px; margin-bottom: 6px;
} }
.mrs-card-meta { .mrs-card-meta {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
@ -401,19 +421,40 @@
font-size: 11px; font-size: 11px;
color: rgba(255,255,255,.65); color: rgba(255,255,255,.65);
} }
.mrs-card-meta span { display: flex; align-items: center; gap: 4px; }
.mrs-card-meta span {
display: flex;
align-items: center;
gap: 4px;
}
/* ── Status badge ── */ /* ── Status badge ── */
.mrs-status-badge { .mrs-status-badge {
position: absolute; position: absolute;
top: 12px; right: 14px; top: 12px;
font-size: 10px; font-weight: 700; right: 14px;
padding: 3px 10px; border-radius: 50px; font-size: 10px;
letter-spacing: .05em; text-transform: uppercase; font-weight: 700;
padding: 3px 10px;
border-radius: 50px;
letter-spacing: .05em;
text-transform: uppercase;
}
.mrs-status-draft {
background: rgba(255,255,255,.18);
color: #fff;
}
.mrs-status-approved {
background: #dcfce7;
color: #166534;
}
.mrs-status-cancelled {
background: #fee2e2;
color: #991b1b;
} }
.mrs-status-draft { background: rgba(255,255,255,.18); color: #fff; }
.mrs-status-approved { background: #dcfce7; color: #166534; }
.mrs-status-cancelled { background: #fee2e2; color: #991b1b; }
/* ── RIS reference strip ── */ /* ── RIS reference strip ── */
.mrs-ris-ref { .mrs-ris-ref {
@ -426,8 +467,15 @@
font-size: 12px; font-size: 12px;
color: #0C447C; color: #0C447C;
} }
.mrs-ris-ref i { font-size: 12px; flex-shrink: 0; }
.mrs-ris-ref strong { font-weight: 700; } .mrs-ris-ref i {
font-size: 12px;
flex-shrink: 0;
}
.mrs-ris-ref strong {
font-weight: 700;
}
/* ── Stats row ── */ /* ── Stats row ── */
.mrs-stats-row { .mrs-stats-row {
@ -437,118 +485,276 @@
background: var(--border, #d6eaec); background: var(--border, #d6eaec);
border-bottom: 1px solid var(--border, #d6eaec); border-bottom: 1px solid var(--border, #d6eaec);
} }
.mrs-stat { .mrs-stat {
background: var(--card-bg, #fff); background: var(--card-bg, #fff);
padding: 10px 12px; padding: 10px 12px;
display: flex; flex-direction: column; gap: 2px; display: flex;
flex-direction: column;
gap: 2px;
} }
.mrs-stat-lbl { .mrs-stat-lbl {
font-size: 10px; font-weight: 700; font-size: 10px;
text-transform: uppercase; letter-spacing: .05em; font-weight: 700;
text-transform: uppercase;
letter-spacing: .05em;
color: var(--text-muted, #6b8890); color: var(--text-muted, #6b8890);
display: flex; align-items: center; gap: 4px; display: flex;
align-items: center;
gap: 4px;
} }
.mrs-stat-lbl i { font-size: 11px; }
.mrs-stat-lbl i {
font-size: 11px;
}
.mrs-stat-val { .mrs-stat-val {
font-size: 18px; font-weight: 700; font-size: 18px;
color: var(--text-dark, #1a2e35); line-height: 1.2; font-weight: 700;
color: var(--text-dark, #1a2e35);
line-height: 1.2;
}
.mrs-stat-val.blue {
color: #185FA5;
}
.mrs-stat-val.green {
color: #166534;
}
.mrs-stat-val.amber {
color: #92400e;
} }
.mrs-stat-val.blue { color: #185FA5; }
.mrs-stat-val.green { color: #166534; }
.mrs-stat-val.amber { color: #92400e; }
/* ── Condition badge ── */ /* ── Condition badge ── */
.mrs-condition-badge { .mrs-condition-badge {
display: inline-flex; align-items: center; gap: 5px; display: inline-flex;
padding: 3px 10px; border-radius: 50px; align-items: center;
font-size: 11px; font-weight: 600; gap: 5px;
padding: 3px 10px;
border-radius: 50px;
font-size: 11px;
font-weight: 600;
}
.mrs-cond-good {
background: #dcfce7;
color: #166534;
}
.mrs-cond-damaged {
background: #fee2e2;
color: #991b1b;
}
.mrs-cond-partial {
background: #fef3c7;
color: #92400e;
} }
.mrs-cond-good { background: #dcfce7; color: #166534; }
.mrs-cond-damaged { background: #fee2e2; color: #991b1b; }
.mrs-cond-partial { background: #fef3c7; color: #92400e; }
/* ── Card body ── */ /* ── Card body ── */
.mrs-card-body { .mrs-card-body {
padding: 12px 16px; flex: 1; padding: 12px 16px;
display: flex; flex-direction: column; gap: 8px; flex: 1;
display: flex;
flex-direction: column;
gap: 8px;
} }
.mrs-field-row { .mrs-field-row {
display: flex; align-items: flex-start; display: flex;
gap: 8px; font-size: 12px; align-items: flex-start;
gap: 8px;
font-size: 12px;
} }
.mrs-field-lbl { .mrs-field-lbl {
min-width: 84px; font-size: 10px; font-weight: 700; min-width: 84px;
text-transform: uppercase; letter-spacing: .05em; font-size: 10px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: .05em;
color: var(--text-muted, #6b8890); color: var(--text-muted, #6b8890);
padding-top: 1px; display: flex; align-items: center; padding-top: 1px;
gap: 4px; flex-shrink: 0; display: flex;
align-items: center;
gap: 4px;
flex-shrink: 0;
} }
.mrs-field-lbl i { font-size: 11px; }
.mrs-field-lbl i {
font-size: 11px;
}
.mrs-field-val { .mrs-field-val {
color: var(--text-dark, #1a2e35); color: var(--text-dark, #1a2e35);
line-height: 1.5; word-break: break-word; line-height: 1.5;
word-break: break-word;
} }
/* ── Footer ── */ /* ── Footer ── */
.mrs-card-ft { .mrs-card-ft {
padding: 10px 16px 14px; padding: 10px 16px 14px;
display: flex; gap: 8px; display: flex;
gap: 8px;
border-top: 1px solid var(--border, #d6eaec); border-top: 1px solid var(--border, #d6eaec);
} }
.mrs-btn { .mrs-btn {
flex: 1; padding: 8px 12px; flex: 1;
padding: 8px 12px;
border-radius: var(--radius-sm, 8px); border-radius: var(--radius-sm, 8px);
border: none; cursor: pointer; border: none;
cursor: pointer;
font-family: 'DM Sans', sans-serif; font-family: 'DM Sans', sans-serif;
font-size: .82rem; font-weight: 600; font-size: .82rem;
display: flex; align-items: center; font-weight: 600;
justify-content: center; gap: 6px; display: flex;
align-items: center;
justify-content: center;
gap: 6px;
transition: all .2s; transition: all .2s;
} }
.mrs-btn-approve { background: #0e7c86; color: #fff; }
.mrs-btn-approve:hover { background: #0d5c63; } .mrs-btn-approve {
.mrs-btn-approve:disabled { opacity: .4; cursor: default; } background: #0e7c86;
color: #fff;
}
.mrs-btn-approve:hover {
background: #0d5c63;
}
.mrs-btn-approve:disabled {
opacity: .4;
cursor: default;
}
.mrs-btn-cancel { .mrs-btn-cancel {
background: transparent; color: #dc2626; background: transparent;
color: #dc2626;
border: 1.5px solid #fca5a5; border: 1.5px solid #fca5a5;
} }
.mrs-btn-cancel:hover { background: #fef2f2; border-color: #dc2626; }
.mrs-btn-cancel:disabled { opacity: .4; cursor: default; } .mrs-btn-cancel:hover {
background: #fef2f2;
border-color: #dc2626;
}
.mrs-btn-cancel:disabled {
opacity: .4;
cursor: default;
}
/* ── Create button (top of page) ── */ /* ── Create button (top of page) ── */
.mrs-create-fab { .mrs-create-fab {
display: inline-flex; align-items: center; gap: 8px; display: inline-flex;
padding: 9px 18px; border-radius: 8px; border: none; align-items: center;
background: #185FA5; color: #fff; gap: 8px;
padding: 9px 18px;
border-radius: 8px;
border: none;
background: #185FA5;
color: #fff;
font-family: 'DM Sans', sans-serif; font-family: 'DM Sans', sans-serif;
font-size: .875rem; font-weight: 600; font-size: .875rem;
cursor: pointer; transition: background .18s; font-weight: 600;
cursor: pointer;
transition: background .18s;
margin-bottom: 14px; margin-bottom: 14px;
} }
.mrs-create-fab:hover { background: #0c3d6b; }
/* ── RIS search result items ── */ .mrs-create-fab:hover {
.mrs-ris-result-item { background: #0c3d6b;
padding: 10px 14px; cursor: pointer; }
border-bottom: 1px solid var(--border, #d6eaec);
font-size: 13px; transition: background .12s; /* ── Searchable dropdown panel (project / RIS) ── */
display: flex; flex-direction: column; gap: 3px; .tm-search-dropdown {
position: absolute;
top: 100%;
left: 0;
right: 0;
z-index: 1090;
margin-top: 4px;
max-height: 220px;
overflow-y: auto;
background: #fff;
border: 1.5px solid var(--border, #d6eaec);
border-radius: 8px;
box-shadow: 0 8px 24px rgba(0,0,0,.12);
display: none;
}
.tm-search-dropdown.open {
display: block;
}
/* ── RIS / Project search result items ── */
.mrs-ris-result-item {
padding: 10px 14px;
cursor: pointer;
border-bottom: 1px solid var(--border, #d6eaec);
font-size: 13px;
transition: background .12s;
display: flex;
flex-direction: column;
gap: 3px;
}
.mrs-ris-result-item:last-child {
border-bottom: none;
}
.mrs-ris-result-item:hover,
.mrs-ris-result-item.active {
background: var(--teal-pale, #e6f7f8);
}
.mrs-ris-result-no {
font-weight: 700;
color: var(--teal-dark, #0d5c63);
}
.mrs-ris-result-meta {
font-size: 11px;
color: var(--text-muted, #6b8890);
}
.mrs-ris-result-empty {
padding: 10px 14px;
font-size: 12px;
color: var(--text-muted, #6b8890);
} }
.mrs-ris-result-item:last-child { border-bottom: none; }
.mrs-ris-result-item:hover { background: var(--teal-pale, #e6f7f8); }
.mrs-ris-result-no { font-weight: 700; color: var(--teal-dark, #0d5c63); }
.mrs-ris-result-meta { font-size: 11px; color: var(--text-muted, #6b8890); }
/* ── am-field reuse ── */ /* ── am-field reuse ── */
.am-field { display: flex; flex-direction: column; gap: 3px; } .am-field {
.am-lbl { display: flex;
font-size: 10px; font-weight: 700; text-transform: uppercase; flex-direction: column;
letter-spacing: .05em; color: var(--text-muted, #6b8890); gap: 3px;
display: flex; align-items: center; gap: 4px; }
.am-lbl {
font-size: 10px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: .05em;
color: var(--text-muted, #6b8890);
display: flex;
align-items: center;
gap: 4px;
}
.am-lbl i {
font-size: 11px;
}
.am-val {
font-size: 13px;
font-weight: 600;
color: var(--teal-dark, #0d5c63);
} }
.am-lbl i { font-size: 11px; }
.am-val { font-size: 13px; font-weight: 600; color: var(--teal-dark, #0d5c63); }
</style> </style>
<script> <script>
@ -564,8 +770,11 @@
timer: null timer: null
}; };
// ── Selected RIS for create form ─────────────────────────────────────── // ── Selected values for the create form ──────────────────────────────
let _selectedRIS = null; let _selectedRIS = null; // { risId, risNo, discipline, maxReturn }
let _activeProjectCodeId = ""; // "" = no project filter active
let _projectSearchTimer = null;
let _risSearchTimer = null;
// ── Elements ─────────────────────────────────────────────────────────── // ── Elements ───────────────────────────────────────────────────────────
const grid = document.getElementById("mrs-grid"); const grid = document.getElementById("mrs-grid");
@ -601,7 +810,7 @@
allIcon: "fas fa-th-large", itemIcon: "fas fa-tag" }); allIcon: "fas fa-th-large", itemIcon: "fas fa-tag" });
condDropdown.setItems(["Good", "Damaged", "Partial"]); condDropdown.setItems(["Good", "Damaged", "Partial"]);
// ── Search inputs ────────────────────────────────────────────────────── // ── Search inputs (list filter bar) ────────────────────────────────────
[inMRSNo, inRISNo, inItem, inRby].forEach(el => { [inMRSNo, inRISNo, inItem, inRby].forEach(el => {
if (!el) return; if (!el) return;
el.addEventListener("input", () => { el.addEventListener("input", () => {
@ -652,7 +861,6 @@
if (!res.ok) throw new Error(`HTTP ${res.status}`); if (!res.ok) throw new Error(`HTTP ${res.status}`);
const json = await res.json(); const json = await res.json();
const data = json.data ?? json;
s.totalCount = json.recordsTotal ?? 0; s.totalCount = json.recordsTotal ?? 0;
renderCards(json.data ?? []); renderCards(json.data ?? []);
@ -708,7 +916,6 @@
const mrsId = item.mrsId ?? item.MRSId ?? 0; const mrsId = item.mrsId ?? item.MRSId ?? 0;
const mrsNo = item.mrsNo ?? item.MRSNo ?? "—"; const mrsNo = item.mrsNo ?? item.MRSNo ?? "—";
const risNo = item.risNo ?? item.RISNo ?? "—"; const risNo = item.risNo ?? item.RISNo ?? "—";
const risId = item.risId ?? item.RISId ?? 0;
const itemName = item.itemName ?? item.ItemName ?? "—"; const itemName = item.itemName ?? item.ItemName ?? "—";
const returnedBy = item.returnedBy ?? item.ReturnedBy ?? "—"; const returnedBy = item.returnedBy ?? item.ReturnedBy ?? "—";
const qtyReturned = item.qtyReturned ?? item.QtyReturned ?? 0; const qtyReturned = item.qtyReturned ?? item.QtyReturned ?? 0;
@ -824,64 +1031,75 @@
</div>` : ""} </div>` : ""}
</div> </div>
<!-- FOOTER --> <!-- FOOTER here-->
<div class="mrs-card-ft">
${isDraft ? `
<button class="mrs-btn mrs-btn-approve btn-mrs-approve"
data-mrsid="${mrsId}"
data-mrsno="${H.escAttr(mrsNo)}"
data-itemname="${H.escAttr(itemName)}"
data-returnedby="${H.escAttr(returnedBy)}"
data-qtyreturned="${qtyReturned}"
data-condition="${H.escAttr(condition)}">
<i class="fas fa-check-circle"></i> Approve
</button>
<button class="mrs-btn mrs-btn-cancel btn-mrs-cancel"
data-mrsid="${mrsId}"
data-mrsno="${H.escAttr(mrsNo)}"
data-itemname="${H.escAttr(itemName)}"
data-returnedby="${H.escAttr(returnedBy)}"
data-qtyreturned="${qtyReturned}">
<i class="fas fa-ban"></i> Cancel
</button>` : `
<button class="mrs-btn mrs-btn-cancel btn-mrs-cancel"
${isCancelled ? "disabled" : ""}
data-mrsid="${mrsId}"
data-mrsno="${H.escAttr(mrsNo)}"
data-itemname="${H.escAttr(itemName)}"
data-returnedby="${H.escAttr(returnedBy)}"
data-qtyreturned="${qtyReturned}"
style="flex:1">
<i class="fas fa-ban"></i>
${isCancelled ? "Cancelled" : "Cancel"}
</button>`}
</div>
</div>`; </div>`;
} }
// <!-- FOOTER once the is approval it must be added-->
// <div class="mrs-card-ft">
// ${isDraft ? `
// <button class="mrs-btn mrs-btn-approve btn-mrs-approve"
// data-mrsid="${mrsId}"
// data-mrsno="${H.escAttr(mrsNo)}"
// data-itemname="${H.escAttr(itemName)}"
// data-returnedby="${H.escAttr(returnedBy)}"
// data-qtyreturned="${qtyReturned}"
// data-condition="${H.escAttr(condition)}">
// <i class="fas fa-check-circle"></i> Approve
// </button>
// <button class="mrs-btn mrs-btn-cancel btn-mrs-cancel"
// data-mrsid="${mrsId}"
// data-mrsno="${H.escAttr(mrsNo)}"
// data-itemname="${H.escAttr(itemName)}"
// data-returnedby="${H.escAttr(returnedBy)}"
// data-qtyreturned="${qtyReturned}">
// <i class="fas fa-ban"></i> Cancel
// </button>` : `
// <button class="mrs-btn mrs-btn-cancel btn-mrs-cancel"
// ${isCancelled ? "disabled" : ""}
// data-mrsid="${mrsId}"
// data-mrsno="${H.escAttr(mrsNo)}"
// data-itemname="${H.escAttr(itemName)}"
// data-returnedby="${H.escAttr(returnedBy)}"
// data-qtyreturned="${qtyReturned}"
// style="flex:1">
// <i class="fas fa-ban"></i>
// ${isCancelled ? "Cancelled" : "Cancel"}
// </button>`
// }
// </div>
// ══════════════════════════════════════════════════════════════════════ // ══════════════════════════════════════════════════════════════════════
// CREATE MRS MODAL // CREATE MRS MODAL
// ══════════════════════════════════════════════════════════════════════ // ══════════════════════════════════════════════════════════════════════
function openCreateModal() { function openCreateModal() {
_selectedRIS = null; _selectedRIS = null;
_activeProjectCodeId = "";
const overlay = document.getElementById("mrs-create-overlay"); const overlay = document.getElementById("mrs-create-overlay");
// Reset form // Reset form
document.getElementById("mrs-project-code-name-search").value = "";
document.getElementById("mrs-project-code-name").value = "";
document.getElementById("mrs-ris-search").value = ""; document.getElementById("mrs-ris-search").value = "";
document.getElementById("tm-mrs-ris").value = "";
document.getElementById("mrs-create-qty").value = ""; document.getElementById("mrs-create-qty").value = "";
document.getElementById("mrs-create-qty").disabled = true; document.getElementById("mrs-create-qty").disabled = true;
document.getElementById("mrs-create-returnedby").value = ""; document.getElementById("mrs-create-returnedby").value = "";
document.getElementById("mrs-create-remarks").value = ""; document.getElementById("mrs-create-remarks").value = "";
document.getElementById("mrs-create-condition").value = "Good"; document.getElementById("mrs-create-condition").value = "Good";
document.getElementById("mrs-selected-ris-badge").style.display = "none"; document.getElementById("mrs-selected-ris-badge").style.display = "none";
document.getElementById("mrs-ris-results").style.display = "none"; document.getElementById("mrs-ris-results").classList.remove("open");
document.getElementById("mrs-project-code-name-results").classList.remove("open");
document.getElementById("mrs-create-qty-warn").style.display = "none"; document.getElementById("mrs-create-qty-warn").style.display = "none";
document.getElementById("mrs-create-qty-hint").style.display = "none"; document.getElementById("mrs-create-qty-hint").style.display = "none";
document.getElementById("mrs-create-submit-btn").disabled = true; document.getElementById("mrs-create-submit-btn").disabled = true;
document.getElementById("mrs-create-subtitle").textContent =
"Select an approved RIS to return against";
overlay.style.display = "flex"; overlay.style.display = "flex";
document.getElementById("mrs-ris-search").focus(); document.getElementById("mrs-project-code-name-search").focus();
// Wire close // Wire close
const closeModal = () => { overlay.style.display = "none"; }; const closeModal = () => { overlay.style.display = "none"; };
@ -889,12 +1107,27 @@
document.getElementById("mrs-create-cancel-btn").onclick = closeModal; document.getElementById("mrs-create-cancel-btn").onclick = closeModal;
overlay.onclick = e => { if (e.target === overlay) closeModal(); }; overlay.onclick = e => { if (e.target === overlay) closeModal(); };
// RIS search input with debounce // Close dropdowns when clicking outside them
let risSearchTimer; document.addEventListener("click", _onOutsideClickForSearchPanels);
document.getElementById("mrs-ris-search").oninput = () => {
clearTimeout(risSearchTimer); // Project search input with debounce
risSearchTimer = setTimeout(_searchRIS, 300); document.getElementById("mrs-project-code-name-search").oninput = () => {
document.getElementById("mrs-project-code-name").value = "";
_activeProjectCodeId = "";
clearTimeout(_projectSearchTimer);
_projectSearchTimer = setTimeout(_searchProjects, 300);
// Project text cleared -> RIS pool should widen back to unfiltered
clearTimeout(_risSearchTimer);
_risSearchTimer = setTimeout(_searchRIS, 300);
}; };
document.getElementById("mrs-project-code-name-search").onfocus = _searchProjects;
// RIS search input with debounce
document.getElementById("mrs-ris-search").oninput = () => {
clearTimeout(_risSearchTimer);
_risSearchTimer = setTimeout(_searchRIS, 300);
};
document.getElementById("mrs-ris-search").onfocus = _searchRIS;
// Qty validation // Qty validation
document.getElementById("mrs-create-qty").oninput = _validateCreateQty; document.getElementById("mrs-create-qty").oninput = _validateCreateQty;
@ -906,56 +1139,155 @@
newSubmit.addEventListener("click", _handleCreateSubmit); newSubmit.addEventListener("click", _handleCreateSubmit);
} }
// RIS live search function _onOutsideClickForSearchPanels(e) {
const projSearch = document.getElementById("mrs-project-code-name-search");
const projResults = document.getElementById("mrs-project-code-name-results");
const risSearch = document.getElementById("mrs-ris-search");
const risResults = document.getElementById("mrs-ris-results");
if (projSearch && projResults &&
!projSearch.contains(e.target) && !projResults.contains(e.target)) {
projResults.classList.remove("open");
}
if (risSearch && risResults &&
!risSearch.contains(e.target) && !risResults.contains(e.target)) {
risResults.classList.remove("open");
}
}
// ── Project live search ────────────────────────────────────────────────
// Endpoint: GET /MRSMgmt/SearchProjects?searchProjectCode={text}
async function _searchProjects() {
const q = document.getElementById("mrs-project-code-name-search").value.trim();
const results = document.getElementById("mrs-project-code-name-results");
results.classList.add("open");
results.innerHTML = `<div class="mrs-ris-result-empty">
<i class="fas fa-spinner fa-spin"></i> Searching…</div>`;
try {
const params = new URLSearchParams();
if (q) params.set("searchProjectCode", q);
const res = await fetch(`/MRSMgmt/SearchProjects?${params.toString()}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const json = await res.json();
const list = json.data ?? [];
if (!list.length) {
results.innerHTML = `<div class="mrs-ris-result-empty">No matching projects.</div>`;
return;
}
results.innerHTML = list.map(p => {
const id = p.projectCodeId ?? p.ProjectCodeId;
const code = p.projectCode ?? p.ProjectCode ?? "N/A";
const name = p.projectName ?? p.ProjectName ?? "N/A";
return `
<div class="mrs-ris-result-item"
data-projectcodeid="${id}"
data-projectcode="${H.escAttr(code)}"
data-projectname="${H.escAttr(name)}">
<span class="mrs-ris-result-no">${H.escHtml(name)}</span>
<span class="mrs-ris-result-meta">${H.escHtml(code)}</span>
</div>`;
}).join("");
results.querySelectorAll(".mrs-ris-result-item").forEach(el =>
el.addEventListener("click", () => _selectProject(el.dataset))
);
} catch (err) {
console.error("SearchProjects error:", err);
results.innerHTML = `<div class="mrs-ris-result-empty" style="color:#dc2626">
Search failed.</div>`;
}
}
function _selectProject(dataset) {
_activeProjectCodeId = dataset.projectcodeid;
document.getElementById("mrs-project-code-name").value = dataset.projectcodeid;
document.getElementById("mrs-project-code-name-search").value =
`${dataset.projectcode} — ${dataset.projectname}`;
document.getElementById("mrs-project-code-name-results").classList.remove("open");
// Selecting a project narrows the RIS pool; clear any previously chosen RIS
_selectedRIS = null;
document.getElementById("mrs-ris-search").value = "";
document.getElementById("tm-mrs-ris").value = "";
document.getElementById("mrs-selected-ris-badge").style.display = "none";
document.getElementById("mrs-create-qty").value = "";
document.getElementById("mrs-create-qty").disabled = true;
document.getElementById("mrs-create-qty-hint").style.display = "none";
document.getElementById("mrs-create-qty-warn").style.display = "none";
document.getElementById("mrs-create-submit-btn").disabled = true;
document.getElementById("mrs-create-subtitle").textContent =
"Select an approved RIS to return against";
_searchRIS(); // re-query, now scoped to this project
}
// ── RIS live search ────────────────────────────────────────────────────
// Endpoint: GET /MRSMgmt/SearchRIS?searchRISNo={text}&searchProjectCodeId={id}
// Per requirement: typing in the RIS box always searches ALL RIS; the
// project filter (if active) narrows the pool, it does not restrict typed text.
async function _searchRIS() { async function _searchRIS() {
const q = document.getElementById("mrs-ris-search").value.trim(); const q = document.getElementById("mrs-ris-search").value.trim();
const results = document.getElementById("mrs-ris-results"); const results = document.getElementById("mrs-ris-results");
if (!q) { results.style.display = "none"; return; } results.classList.add("open");
results.innerHTML = `<div class="mrs-ris-result-empty">
results.style.display = "block";
results.innerHTML = `<div style="padding:10px 14px;font-size:12px;
color:var(--text-muted,#6b8890)">
<i class="fas fa-spinner fa-spin"></i> Searching…</div>`; <i class="fas fa-spinner fa-spin"></i> Searching…</div>`;
try { try {
const res = await fetch( const params = new URLSearchParams();
`/RISMgmt/GetRIS?searchRISNo=${encodeURIComponent(q)}&status=1&pageSize=10` if (q) params.set("searchRISNo", q);
); if (_activeProjectCodeId) params.set("searchProjectCodeId", _activeProjectCodeId);
// const res = await fetch(`/RISMgmt/GetRIS?q=${encodeURIComponent(q)}`);
const res = await fetch(`/MRSMgmt/SearchRIS?${params.toString()}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const json = await res.json(); const json = await res.json();
const list = (json.data ?? json).data ?? json.data ?? []; const list = json.data ?? [];
if (!list.length) { if (!list.length) {
results.innerHTML = `<div style="padding:10px 14px;font-size:12px; results.innerHTML = `<div class="mrs-ris-result-empty">No approved RIS found.</div>`;
color:var(--text-muted,#6b8890)">No approved RIS found.</div>`;
return; return;
} }
results.innerHTML = list.map(r => ` results.innerHTML = list.map(r => {
const risId = r.risId ?? r.RISId;
const risNo = r.risNo ?? r.RISNo ?? "—";
const projectCodeId = r.projectCodeId ?? r.ProjectCodeId ?? "";
const projectCode = r.projectCode ?? r.ProjectCode ?? "N/A";
const projectName = r.projectName ?? r.ProjectName ?? "N/A";
const discipline = r.disciplineName ?? r.DisciplineName ?? "—";
const maxReturn = r.qtyAvailableToReturn ?? r.QtyAvailableToReturn ?? 0;
return `
<div class="mrs-ris-result-item" <div class="mrs-ris-result-item"
data-risid="${r.risId ?? r.RISId}" data-risid="${risId}"
data-risno="${H.escAttr(r.risNo ?? r.RISNo ?? '')}" data-risno="${H.escAttr(risNo)}"
data-itemname="${H.escAttr(r.itemName ?? r.ItemName ?? '')}" data-projectcodeid="${projectCodeId}"
data-discipline="${H.escAttr(r.disciplineName ?? r.DisciplineName ?? '')}" data-projectcode="${H.escAttr(projectCode)}"
data-qtyissued="${r.qtyIssued ?? r.QtyIssued ?? 0}" data-projectname="${H.escAttr(projectName)}"
data-maxreturn="${r.qtyAvailableToReturn ?? (r.qtyIssued - r.totalReturned) ?? 0}"> data-discipline="${H.escAttr(discipline)}"
<span class="mrs-ris-result-no"> data-maxreturn="${maxReturn}">
${H.escHtml(r.risNo ?? r.RISNo ?? '—')} <span class="mrs-ris-result-no">${H.escHtml(risNo)}</span>
</span>
<span class="mrs-ris-result-meta"> <span class="mrs-ris-result-meta">
${H.escHtml(r.itemName ?? r.ItemName ?? '—')} · ${H.escHtml(projectCode)} · ${H.escHtml(discipline)} ·
${H.escHtml(r.disciplineName ?? r.DisciplineName ?? '—')} · <strong>${maxReturn} pcs available</strong>
<strong>${r.qtyAvailableToReturn ?? 0} pcs available</strong>
</span> </span>
</div>`).join(""); </div>`;
}).join("");
results.querySelectorAll(".mrs-ris-result-item").forEach(el => results.querySelectorAll(".mrs-ris-result-item").forEach(el =>
el.addEventListener("click", () => _selectRIS(el.dataset)) el.addEventListener("click", () => _selectRIS(el.dataset))
); );
} catch (err) { } catch (err) {
results.innerHTML = `<div style="padding:10px 14px;font-size:12px;color:#dc2626"> console.error("SearchRIS error:", err);
results.innerHTML = `<div class="mrs-ris-result-empty" style="color:#dc2626">
Search failed.</div>`; Search failed.</div>`;
} }
} }
@ -964,20 +1296,26 @@
_selectedRIS = { _selectedRIS = {
risId: parseInt(dataset.risid, 10), risId: parseInt(dataset.risid, 10),
risNo: dataset.risno, risNo: dataset.risno,
itemName: dataset.itemname,
discipline: dataset.discipline, discipline: dataset.discipline,
qtyIssued: parseInt(dataset.qtyissued, 10),
maxReturn: parseInt(dataset.maxreturn, 10) maxReturn: parseInt(dataset.maxreturn, 10)
}; };
document.getElementById("tm-mrs-ris").value = _selectedRIS.risId;
document.getElementById("mrs-ris-search").value = _selectedRIS.risNo; document.getElementById("mrs-ris-search").value = _selectedRIS.risNo;
document.getElementById("mrs-ris-results").style.display = "none"; document.getElementById("mrs-ris-results").classList.remove("open");
// Backfill project box for clarity if RIS picked without a project pre-selected
if (!_activeProjectCodeId && dataset.projectcodeid) {
document.getElementById("mrs-project-code-name").value = dataset.projectcodeid;
document.getElementById("mrs-project-code-name-search").value =
`${dataset.projectcode} — ${dataset.projectname}`;
}
// Populate badge // Populate badge
document.getElementById("mrs-sel-risno").textContent = _selectedRIS.risNo; document.getElementById("mrs-sel-risno").textContent = _selectedRIS.risNo;
document.getElementById("mrs-sel-qtyissued").textContent = _selectedRIS.qtyIssued + " pcs";
document.getElementById("mrs-sel-maxreturn").textContent = _selectedRIS.maxReturn + " pcs"; document.getElementById("mrs-sel-maxreturn").textContent = _selectedRIS.maxReturn + " pcs";
document.getElementById("mrs-sel-itemname").textContent = _selectedRIS.itemName; document.getElementById("mrs-sel-project").textContent =
`${dataset.projectcode} — ${dataset.projectname}`;
document.getElementById("mrs-sel-discipline").textContent = _selectedRIS.discipline; document.getElementById("mrs-sel-discipline").textContent = _selectedRIS.discipline;
const badge = document.getElementById("mrs-selected-ris-badge"); const badge = document.getElementById("mrs-selected-ris-badge");
@ -994,8 +1332,7 @@
hint.textContent = `Max returnable: ${_selectedRIS.maxReturn} pcs`; hint.textContent = `Max returnable: ${_selectedRIS.maxReturn} pcs`;
document.getElementById("mrs-create-submit-btn").disabled = false; document.getElementById("mrs-create-submit-btn").disabled = false;
document.getElementById("mrs-create-subtitle").textContent = document.getElementById("mrs-create-subtitle").textContent = _selectedRIS.risNo;
`${_selectedRIS.risNo} — ${_selectedRIS.itemName}`;
} }
function _validateCreateQty() { function _validateCreateQty() {
@ -1066,6 +1403,7 @@
showToast("success", d.message ?? "MRS created successfully.", "Done!", 3500); showToast("success", d.message ?? "MRS created successfully.", "Done!", 3500);
document.getElementById("mrs-create-overlay").style.display = "none"; document.getElementById("mrs-create-overlay").style.display = "none";
document.removeEventListener("click", _onOutsideClickForSearchPanels);
fetchData(); fetchData();
} catch (err) { } catch (err) {

View File

@ -10,7 +10,7 @@
</div> </div>
<div class="inv-search-box"> <div class="inv-search-box">
<i class="fas fa-user"></i> <i class="fas fa-user"></i>
<input type="text" id="ris-srchIssuedTo" placeholder="Issued To..." /> <input type="text" id="ris-srchIssuedTo" placeholder="Project Name..." />
</div> </div>
@* ── Discipline dropdown ── *@ @* ── Discipline dropdown ── *@
@ -18,18 +18,18 @@
<div class="inv-dep-trigger"> <div class="inv-dep-trigger">
<span class="inv-dep-left"> <span class="inv-dep-left">
<i class="fas fa-tools"></i> <i class="fas fa-tools"></i>
<span class="inv-dep-lbl">All Disciplines</span> <span class="inv-dep-lbl">All Trades</span>
</span> </span>
<i class="fas fa-chevron-down inv-dep-caret"></i> <i class="fas fa-chevron-down inv-dep-caret"></i>
</div> </div>
<div class="inv-dep-dropdown"> <div class="inv-dep-dropdown">
<div class="inv-dep-searchbox"> <div class="inv-dep-searchbox">
<i class="fas fa-search"></i> <i class="fas fa-search"></i>
<input type="text" placeholder="Search discipline..." autocomplete="off" /> <input type="text" placeholder="Search trades..." autocomplete="off" />
</div> </div>
<div class="inv-dep-list"> <div class="inv-dep-list">
<div class="inv-dep-opt active" data-value=""> <div class="inv-dep-opt active" data-value="">
<i class="fas fa-th-large"></i> All Disciplines <i class="fas fa-th-large"></i> All Trades
</div> </div>
</div> </div>
</div> </div>
@ -505,7 +505,7 @@
fetchData(); fetchData();
}, { }, {
cssPrefix: "inv-dep", cssPrefix: "inv-dep",
allLabel: "All Disciplines", allLabel: "All Trades",
allIcon: "fas fa-th-large", allIcon: "fas fa-th-large",
itemIcon: "fas fa-tools" itemIcon: "fas fa-tools"
}); });
@ -642,7 +642,7 @@
const risNo = item.risNo ?? item.RISNo ?? "—"; const risNo = item.risNo ?? item.RISNo ?? "—";
const itemName = item.itemName ?? item.ItemName ?? "—"; const itemName = item.itemName ?? item.ItemName ?? "—";
const itemNo = item.itemNo ?? item.ItemNo ?? "—"; const itemNo = item.itemNo ?? item.ItemNo ?? "—";
const issuedTo = item.issuedTo ?? item.IssuedTo ?? "—"; const issuedTo = item.projectCode ?? item.projectName ?? "—";
const discipline = item.disciplineName ?? item.DisciplineName ?? "—"; const discipline = item.disciplineName ?? item.DisciplineName ?? "—";
const qtyIssued = item.qtyIssued ?? item.QtyIssued ?? 0; const qtyIssued = item.qtyIssued ?? item.QtyIssued ?? 0;
const totalReturned= item.totalReturned ?? item.TotalReturned ?? 0; const totalReturned= item.totalReturned ?? item.TotalReturned ?? 0;
@ -713,7 +713,7 @@
<div class="ris-card-body"> <div class="ris-card-body">
<div class="ris-field-row"> <div class="ris-field-row">
<span class="ris-field-lbl"> <span class="ris-field-lbl">
<i class="fas fa-tools"></i> Discipline <i class="fas fa-tools"></i> Trade
</span> </span>
<span class="ris-field-val"> <span class="ris-field-val">
<span class="ris-discipline-chip"> <span class="ris-discipline-chip">

View File

@ -0,0 +1,726 @@
<style>
body {
font-family: 'DM Sans', Arial, sans-serif;
background: #fff;
color: #1a2e35;
padding: 24px;
}
@@media print {
body { padding: 0; margin: 0; background: #fff;}
body * { visibility: hidden;}
#inv-rpt-page, #inv-rpt-page * {
visibility: visible;
}
#inv-rpt-page {
position: absolute;
left: 0;
top: 0;
width: 100%;
box-shadow: none !important;
border: none !important;
border-radius: 0 !important;
}
.no-print {
display: none !important;
}
.rpt-table tr {
page-break-inside: avoid;
}
thead {
display: table-header-group;
}
}
.rpt-page {
width: 100%;
margin: 0;
background: #fff;
border: 1px solid var(--border, #d6eaec);
border-radius: var(--radius-lg, 14px);
overflow: hidden;
}
.rpt-header {
padding: 20px 24px 16px;
border-bottom: 1px solid #d6eaec;
}
/* ── FILTER BUTTONS (blended with shared theme) ── */
.rpt-date-group {
display: flex;
align-items: center;
gap: 8px;
border: 1.5px solid var(--border, #d6eaec);
border-radius: var(--radius-sm, 8px);
padding: 0 12px;
background: #fff;
}
.rpt-date-lbl {
display: flex;
align-items: center;
gap: 6px;
font-size: .8rem;
font-weight: 600;
color: var(--text-muted, #6b8890);
white-space: nowrap;
}
.rpt-date-input {
border: none;
outline: none;
background: transparent;
padding: 9px 0;
font-family: 'DM Sans', sans-serif;
font-size: .875rem;
color: var(--text-dark, #1a2e35);
}
.rpt-btn {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 9px 18px;
border-radius: var(--radius-sm, 8px);
border: none;
font-family: 'DM Sans', sans-serif;
font-size: .84rem;
font-weight: 600;
cursor: pointer;
transition: all .2s ease;
white-space: nowrap;
}
.rpt-btn-primary {
background: var(--teal-mid, #0e7c86);
color: #fff;
box-shadow: 0 2px 8px rgba(14,124,134,.3);
}
.rpt-btn-primary:hover {
background: var(--teal-dark, #0d5c63);
transform: translateY(-1px);
box-shadow: 0 4px 14px rgba(14,124,134,.35);
}
.rpt-btn-outline {
background: #fff;
color: var(--teal-dark, #0d5c63);
border: 1.5px solid var(--teal-mid, #0e7c86);
}
.rpt-btn-outline:hover {
background: var(--teal-pale, #e6f7f8);
border-color: var(--teal-dark, #0d5c63);
}
.rpt-header-top {
display: flex;
align-items: flex-start;
justify-content: space-between;
margin-bottom: 14px;
}
.rpt-company {
font-size: 11px;
font-weight: 600;
color: #6b8890;
text-transform: uppercase;
letter-spacing: .08em;
margin-bottom: 4px;
}
.rpt-title {
font-size: 20px;
font-weight: 700;
color: #1a2e35;
margin-bottom: 2px;
}
.rpt-subtitle {
font-size: 12px;
color: #6b8890;
}
.rpt-logo {
width: 40px;
height: 40px;
border-radius: 8px;
background: #EAF3DE;
display: flex;
align-items: center;
justify-content: center;
}
.rpt-logo i {
font-size: 20px;
color: #3B6D11;
}
.rpt-meta {
display: flex;
gap: 24px;
flex-wrap: wrap;
}
.rpt-meta-item {
display: flex;
flex-direction: column;
gap: 2px;
}
.rpt-meta-lbl {
font-size: 10px;
font-weight: 600;
color: #6b8890;
text-transform: uppercase;
letter-spacing: .07em;
}
.rpt-meta-val {
font-size: 12px;
font-weight: 600;
color: #1a2e35;
}
.kpi-strip {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 0;
border-bottom: 1px solid #d6eaec;
}
.kpi-cell {
padding: 14px 18px;
border-right: 1px solid #d6eaec;
}
.kpi-cell:last-child {
border-right: none;
}
.kpi-lbl {
font-size: 10px;
font-weight: 600;
color: #6b8890;
text-transform: uppercase;
letter-spacing: .07em;
margin-bottom: 4px;
}
.kpi-val {
font-size: 22px;
font-weight: 700;
color: #1a2e35;
}
.rpt-section {
padding: 16px 24px;
}
.rpt-section + .rpt-section {
border-top: 1px solid #d6eaec;
}
.rpt-section-title {
font-size: 11px;
font-weight: 600;
color: #6b8890;
text-transform: uppercase;
letter-spacing: .08em;
margin-bottom: 12px;
}
.rpt-table {
width: 100%;
border-collapse: collapse;
font-size: 12px;
}
.rpt-table thead tr {
background: linear-gradient(135deg, #1a3a4a, #1e5468);
}
.rpt-table th {
text-align: left;
font-size: 10px;
font-weight: 700;
color: rgba(255,255,255,.85);
text-transform: uppercase;
letter-spacing: .06em;
padding: 9px 12px;
white-space: nowrap;
}
.rpt-table td {
padding: 9px 12px;
border-bottom: 1px solid #d6eaec;
vertical-align: middle;
}
.rpt-table tr:last-child td {
border-bottom: none;
}
.rpt-table .num {
text-align: right;
}
.rpt-table .total-row td {
font-weight: 700;
background: #f0f6f7;
}
.pill {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 2px 9px;
border-radius: 50px;
font-size: 10px;
font-weight: 600;
}
.mini-bar-track {
flex: 1;
height: 5px;
border-radius: 3px;
background: #d6eaec;
overflow: hidden;
}
.mini-bar-fill {
height: 100%;
border-radius: 3px;
}
.fill-teal {
background: #1D9E75;
}
.fill-blue {
background: #378ADD;
}
.fill-amber {
background: #EF9F27;
}
.fill-coral {
background: #D85A30;
}
.two-col {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0;
border-top: 1px solid #d6eaec;
}
.col-left {
padding: 16px 24px;
border-right: 1px solid #d6eaec;
}
.col-right {
padding: 16px 24px;
}
.sig-block {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
}
.sig-item {
border-top: 1px solid #d6eaec;
padding-top: 8px;
}
.sig-role {
font-size: 10px;
color: #6b8890;
text-transform: uppercase;
letter-spacing: .07em;
margin-bottom: 16px;
}
.sig-name {
font-size: 11px;
font-weight: 600;
color: #1a2e35;
}
.rpt-footer {
padding: 10px 24px;
border-top: 1px solid #d6eaec;
display: flex;
align-items: center;
justify-content: space-between;
background: #f0f6f7;
}
.rpt-footer-lbl {
font-size: 10px;
color: #6b8890;
}
.loading-state {
text-align: center;
padding: 80px 20px;
color: #6b8890;
}
</style>
@await Html.PartialAsync("PagesView/Inventory/_InventoryReportHelper")
<script>
(function () {
"use strict";
const fromEl = document.getElementById("inv-rpt-from");
const toEl = document.getElementById("inv-rpt-to");
const genBtn = document.getElementById("inv-rpt-generate");
const csvBtn = document.getElementById("inv-rpt-csv");
const xlsxBtn = document.getElementById("inv-rpt-excel");
const container = document.getElementById("inv-rpt-container");
if (!fromEl || !toEl || !container) {
console.error("Inventory report subtab init failed — missing elements.");
return;
}
// default: first day of current month -> today
const today = new Date();
const first = new Date(today.getFullYear(), today.getMonth(), 1);
toEl.value = today.toISOString().slice(0, 10);
fromEl.value = first.toISOString().slice(0, 10);
let lastData = null; // cache for export
function buildParams() {
return new URLSearchParams({ dateFrom: fromEl.value, dateTo: toEl.value });
}
csvBtn.addEventListener("click", exportCsv);
genBtn.addEventListener("click", fetchAndRender);
async function fetchAndRender() {
container.innerHTML = `<div class="inv-tab-loading">
<div class="inv-spinner"></div><span>Loading report…</span></div>`;
try {
const res = await fetch(`/InventoryReports/GetInventoryReport?${buildParams()}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const json = await res.json();
lastData = json.data ?? json;
renderReport(lastData);
} catch (err) {
console.error("Inventory report fetch error:", err);
container.innerHTML = `
<div class="inv-placeholder">
<i class="fas fa-exclamation-triangle" style="color:#ff5c5c"></i>
<h3>Failed to load report</h3>
<p>Please try again.</p>
</div>`;
}
}
// ── CSV export (client-side, no backend needed) ──
function exportCsv() {
if (!lastData) return;
const rows = lastData.rows ?? [];
const byCat = lastData.byCategory ?? [];
const alerts = lastData.alerts ?? [];
const summary = lastData.summary ?? {};
const headers = ["Item Name","Item No.","Category","Unit Price","Qty In","Qty Out","On Hand","Stock %"];
const csvLines = [
`Inventory Summary Report`,
`Company,${csvCell(lastData.companyName)}`,
`Report No,${csvCell(lastData.reportNo)}`,
`Period,${csvCell(fromEl.value)} to ${csvCell(toEl.value)}`,
``,
// ── Inventory detail ──
headers.map(csvCell).join(","),
...rows.map(r => [
r.itemName, r.itemNo, r.itemCategoryName, r.unitPrice,
r.qtyIn, r.qtyOut, r.qtyOnHand, r.stockPct
].map(csvCell).join(",")),
["Total","","","", summary.totalQtyIn ?? 0, summary.totalQtyOut ?? 0, summary.totalOnHand ?? 0, ""].map(csvCell).join(","),
``,
// ── Stock level by category ──
`Stock Level by Category`,
["Category","Avg Stock %"].map(csvCell).join(","),
...byCat.map(c => [c.categoryName, c.avgStockPct].map(csvCell).join(",")),
``,
// ── Items requiring attention ──
`Items Requiring Attention`,
["Item","On Hand","Alert"].map(csvCell).join(","),
...alerts.map(a => [a.itemName, a.qtyOnHand, a.severity].map(csvCell).join(","))
];
downloadBlob(
"\uFEFF" + csvLines.join("\r\n"),
`Inventory_Report_${fromEl.value}_to_${toEl.value}.csv`,
"text/csv;charset=utf-8;"
);
}
function csvCell(v) {
const s = String(v ?? "");
return /[",\r\n]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
}
function downloadBlob(content, filename, mime) {
const blob = new Blob([content], { type: mime });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url; a.download = filename;
document.body.appendChild(a); a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
function renderReport(data) {
const summary = data.summary ?? {};
const rows = data.rows ?? [];
const byCat = data.byCategory ?? [];
const alerts = data.alerts ?? [];
const catFillColors = ["fill-teal", "fill-blue", "fill-amber", "fill-coral"];
const maxCatPct = Math.max(1, ...byCat.map(c => c.avgStockPct));
container.innerHTML = `
<div class="rpt-page" id="inv-rpt-page">
<div class="rpt-header">
<div class="rpt-header-top">
<div>
<div class="rpt-company">${_esc(data.companyName ?? "")}</div>
<div class="rpt-title">Inventory summary Report</div>
<div class="rpt-subtitle">As of ${_fmtDate(data.asOf)} · All departments · All categories</div>
</div>
<div class="rpt-logo" style="background:#EAF3DE">
<i class="fas fa-boxes" style="color:#3B6D11"></i>
</div>
</div>
<div class="rpt-meta">
<div class="rpt-meta-item">
<span class="rpt-meta-lbl">Prepared by</span>
<span class="rpt-meta-val">${_esc(data.preparedBy ?? "Finance Department")}</span>
</div>
<div class="rpt-meta-item">
<span class="rpt-meta-lbl">Print date</span>
<span class="rpt-meta-val">${_fmtDate(new Date().toISOString())}</span>
</div>
<div class="rpt-meta-item">
<span class="rpt-meta-lbl">Report no.</span>
<span class="rpt-meta-val">${_esc(data.reportNo ?? "")}</span>
</div>
</div>
</div>
<div class="kpi-strip" style="grid-template-columns:repeat(5,1fr)">
<div class="kpi-cell">
<div class="kpi-lbl"><i class="fas fa-box"></i> Total SKUs</div>
<div class="kpi-val">${summary.totalSKUs ?? 0}</div>
</div>
<div class="kpi-cell">
<div class="kpi-lbl"><i class="fas fa-layer-group"></i> Total on hand</div>
<div class="kpi-val">${(summary.totalOnHand ?? 0).toLocaleString()}</div>
</div>
<div class="kpi-cell">
<div class="kpi-lbl"><i class="fas fa-coins"></i> Total value</div>
<div class="kpi-val">${_money(summary.totalValue ?? 0)}</div>
</div>
<div class="kpi-cell">
<div class="kpi-lbl"><i class="fas fa-exclamation-triangle"></i> Low stock</div>
<div class="kpi-val" style="color:#A32D2D">${summary.lowStockCount ?? 0}</div>
</div>
<div class="kpi-cell">
<div class="kpi-lbl"><i class="fas fa-ban"></i> Out of stock</div>
<div class="kpi-val" style="color:#A32D2D">${summary.outOfStockCount ?? 0}</div>
</div>
</div>
<div class="rpt-section">
<div class="rpt-section-title"><i class="fas fa-list"></i> Inventory detail by item</div>
<table class="rpt-table">
<thead>
<tr>
<th>Item Name</th><th>Item No.</th><th>Category</th>
<th class="num">Unit Price</th>
<th class="num">Qty In</th><th class="num">Qty Out</th>
<th class="num">On Hand</th>
<th class="num">Total Value</th>
<th>Stock Level</th>
</tr>
</thead>
<tbody>
${rows.map(r => `
<tr>
<td style="font-weight:600">${_esc(r.itemName)}</td>
<td style="color:var(--text-muted,#6b8890)">#${_esc(r.itemNo)}</td>
<td>${_esc(r.itemCategoryName)}</td>
<td class="num">${_money(r.unitPrice)}</td>
<td class="num">${r.qtyIn}</td>
<td class="num">${r.qtyOut}</td>
<td class="num" style="font-weight:600">${r.qtyOnHand}</td>
<td class="num">${_money(r.qtyOnHand * r.unitPrice)}</td>
<td>${_stockBar(r.stockPct)}</td>
</tr>`).join("")}
<tr class="total-row">
<td colspan="4">Total</td>
<td class="num">${summary.totalQtyIn ?? 0}</td>
<td class="num">${summary.totalQtyOut ?? 0}</td>
<td class="num">${summary.totalOnHand ?? 0}</td>
<td class="num">${_money(summary.totalValue ?? 0)}</td>
<td></td>
</tr>
</tbody>
</table>
</div>
<div class="two-col">
<div class="col-left">
<div class="rpt-section-title"><i class="fas fa-chart-bar"></i> Stock level by category</div>
<div style="display:flex;flex-direction:column;gap:8px">
${byCat.map((c, i) => `
<div>
<div style="display:flex;justify-content:space-between;font-size:12px;margin-bottom:4px">
<span>${_esc(c.categoryName)}</span>
<span style="font-weight:600">${c.avgStockPct}% avg</span>
</div>
<div class="mini-bar-track">
<div class="mini-bar-fill ${catFillColors[i % catFillColors.length]}"
style="width:${c.avgStockPct}%"></div>
</div>
</div>`).join("")}
</div>
</div>
<div class="col-right">
<div class="rpt-section-title"><i class="fas fa-exclamation-triangle"></i> Items requiring attention</div>
<table class="rpt-table">
<thead><tr><th>Item</th><th class="num">On Hand</th><th>Alert</th></tr></thead>
<tbody>
${alerts.map(a => `
<tr>
<td>${_esc(a.itemName)}</td>
<td class="num" style="color:#A32D2D">${a.qtyOnHand}</td>
<td>${_alertPill(a.severity)}</td>
</tr>`).join("")}
</tbody>
</table>
</div>
</div>
<div class="rpt-section">
<div class="sig-block">
<div class="sig-item"><div class="sig-role">Prepared by</div><div class="sig-name">Finance Officer</div></div>
<div class="sig-item"><div class="sig-role">Reviewed by</div><div class="sig-name">Finance Manager</div></div>
<div class="sig-item"><div class="sig-role">Approved by</div><div class="sig-name">Finance Director</div></div>
</div>
</div>
<div class="rpt-footer">
<span class="rpt-footer-lbl">${_esc(data.companyName ?? "")} — Confidential — For internal use only</span>
</div>
</div>`;
}
function _money(v) {
const n = Number(v) || 0;
return n.toLocaleString("en-PH", {
style: "currency",
currency: "PHP",
minimumFractionDigits: 2
});
}
function _stockBar(pct) {
const cls = pct < 20 ? "fill-coral" : pct < 50 ? "fill-amber" : "fill-teal";
const color = pct < 20 ? "#A32D2D" : pct < 50 ? "#854F0B" : "inherit";
return `<div style="display:flex;flex-direction:column;gap:3px">
<div class="mini-bar-track"><div class="mini-bar-fill ${cls}" style="width:${pct}%"></div></div>
<span style="font-size:10px;color:${color};text-align:right">${pct}%${pct < 20 ? " ⚠" : ""}</span>
</div>`;
}
function _alertPill(severity) {
const map = {
"Critical": { bg: "#FCEBEB", fg: "#A32D2D" },
"Low": { bg: "#FAEEDA", fg: "#854F0B" }
};
const c = map[severity] ?? map["Low"];
return `<span class="pill" style="background:${c.bg};color:${c.fg}">${_esc(severity)}</span>`;
}
// ── Excel export (client-side, HTML-table .xls — Excel opens natively) ──
function exportExcel() {
if (!lastData) return;
const rows = lastData.rows ?? [];
const byCat = lastData.byCategory ?? [];
const alerts = lastData.alerts ?? [];
const summary = lastData.summary ?? {};
const headerCells = ["Item Name","Item No.","Category","Unit Price","Qty In","Qty Out","On Hand","Stock %"]
.map(h => `<th>${_esc(h)}</th>`).join("");
const bodyRows = rows.map(r => `
<tr>
<td>${_esc(r.itemName)}</td>
<td>${_esc(r.itemNo)}</td>
<td>${_esc(r.itemCategoryName)}</td>
<td>${_esc(r.unitPrice)}</td>
<td>${r.qtyIn}</td>
<td>${r.qtyOut}</td>
<td>${r.qtyOnHand}</td>
<td>${r.stockPct}</td>
</tr>`).join("");
const catRows = byCat.map(c => `
<tr><td>${_esc(c.categoryName)}</td><td>${c.avgStockPct}</td></tr>`).join("");
const alertRows = alerts.map(a => `
<tr><td>${_esc(a.itemName)}</td><td>${a.qtyOnHand}</td><td>${_esc(a.severity)}</td></tr>`).join("");
const html = `
<html xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns="http://www.w3.org/TR/REC-html40">
<head><meta charset="utf-8"></head>
<body>
<table border="1">
<tr><td colspan="8"><b>Inventory Summary Report</b></td></tr>
<tr><td>Company</td><td colspan="7">${_esc(lastData.companyName)}</td></tr>
<tr><td>Report No</td><td colspan="7">${_esc(lastData.reportNo)}</td></tr>
<tr><td>Period</td><td colspan="7">${_esc(fromEl.value)} to ${_esc(toEl.value)}</td></tr>
<tr></tr>
<tr>${headerCells}</tr>
${bodyRows}
<tr><td colspan="4"><b>Total</b></td><td>${summary.totalQtyIn ?? 0}</td><td>${summary.totalQtyOut ?? 0}</td><td>${summary.totalOnHand ?? 0}</td><td></td></tr>
</table>
<br/>
<table border="1">
<tr><td colspan="2"><b>Stock Level by Category</b></td></tr>
<tr><th>Category</th><th>Avg Stock %</th></tr>
${catRows}
</table>
<br/>
<table border="1">
<tr><td colspan="3"><b>Items Requiring Attention</b></td></tr>
<tr><th>Item</th><th>On Hand</th><th>Alert</th></tr>
${alertRows}
</table>
</body></html>`;
downloadBlob(html, `Inventory_Report_${fromEl.value}_to_${toEl.value}.xls`,
"application/vnd.ms-excel");
}
xlsxBtn.addEventListener("click", exportExcel);
fetchAndRender();
})();
</script>

View File

@ -19,7 +19,8 @@
<div class="col-3"> <div class="col-3">
<div class="form-group"> <div class="form-group">
<label for="currency">Currency</label> <label for="currency">Currency</label>
<input disabled id="currency" value="PESO" class="form-control" /> <input type="search" name="currency" id="currency" class="form-control" style="margin-bottom:5px;">
<input type="hidden" id="currencyId" name="currencyId" />
</div> </div>
</div> </div>

View File

@ -528,7 +528,8 @@
<label class="lbl">Currency / CER</label> <label class="lbl">Currency / CER</label>
<div class="cur-pair"> <div class="cur-pair">
<span class="cur-badge">USD</span> <span class="cur-badge">USD</span>
<input type="hidden" id="currency" value="USD" /> <input type="search" name="currency" id="currency" class="form-control" style="margin-bottom:5px;">
<input type="hidden" id="currencyId" name="currencyId" />
<input type="number" id="currencyCER" name="currencyCER" value="59.00" class="fc" step="0.01"> <input type="number" id="currencyCER" name="currencyCER" value="59.00" class="fc" step="0.01">
</div> </div>
</div> </div>
@ -673,3 +674,59 @@
<input hidden id="dr-ImportPoNo" /> <input hidden id="dr-ImportPoNo" />
<input hidden id="si-ImportPoNo" /> <input hidden id="si-ImportPoNo" />
@await Html.PartialAsync("PagesView/PO/_DocRequired") @await Html.PartialAsync("PagesView/PO/_DocRequired")
<script>
$(function() {
$("#currency").autocomplete({
source: function (request, response) {
console.log('Autocomplete source called with:', request.term);
$.ajax({
url: endpoint.GetCurrencies,
data: { query: request.term },
success: function (result) {
console.log('AJAX success:', result);
if (result && result.success && Array.isArray(result.data)) {
var formattedData = result.data.map(item => ({
label: item.label || '',
value: item.value !== undefined && item.value !== null ? item.value.toString() : '',
value2: item.value2 !== undefined && item.value2 !== null ? item.value2.toString() : ''
}));
response(formattedData);
} else {
console.error('Invalid data format received:', result);
response([]);
}
},
error: function(xhr, status, error) {
console.error('AJAX error:', status, error);
console.log('Response:', xhr.responseText);
response([]);
}
});
},
minLength: 2,
select: function (event, ui) {
$('#currency').val(ui.item.label);
$('#currencyId').val(ui.item.value);
return false;
},
focus: function (event, ui) {
event.preventDefault();
},
open: function () {
var dropdown = $(".ui-autocomplete");
dropdown.css({
"max-height": "200px",
"overflow-y": "auto"
});
},
messages: {
noResults: '',
results: function (count) {
return count + (count > 1 ? ' results' : ' result');
}
}
});
});
</script>

View File

@ -21,7 +21,8 @@
<div class="col-3"> <div class="col-3">
<div class="form-group"> <div class="form-group">
<label for="currency">Currency</label> <label for="currency">Currency</label>
<input disabled id="currency" value="PESO" class="form-control" /> <input type="search" name="currency" id="currency" class="form-control" style="margin-bottom:5px;">
<input type="hidden" id="currencyId" name="currencyId" />
</div> </div>
</div> </div>
<div class="col-3"> <div class="col-3">

View File

@ -11,7 +11,7 @@
<!-- PO No --> <!-- PO No -->
<div class="col-md-2"> <div class="col-md-2">
<div class="form-group">
<label for="poNo"> <label for="poNo">
PO No. PO No.
<i class="bx bx-pencil" <i class="bx bx-pencil"
@ -25,20 +25,20 @@
id="poId" id="poId"
class="form-control" class="form-control"
name="poId" /> name="poId" />
</div>
</div> </div>
<!-- Final PO No --> <!-- Final PO No -->
<div class="col-md-2"> <div class="col-md-2">
<div class="form-group">
<label for="poNoFinal">Final PO No.</label> <label for="poNoFinal">Final PO No.</label>
<input readonly id="poNoFinal" class="form-control"> <input readonly id="poNoFinal" class="form-control">
</div>
</div> </div>
<!-- PO Type --> <!-- PO Type -->
<div class="col-md-2"> <div class="col-md-2">
<div class="form-group">
<label for="poType">PO Type</label> <label for="poType">PO Type</label>
<select class="form-control" <select class="form-control"
@ -54,7 +54,7 @@
<option value="2">DR</option> <option value="2">DR</option>
<option value="3">Import</option> <option value="3">Import</option>
</select> </select>
</div>
</div> </div>
<!-- Supplier (Wider) --> <!-- Supplier (Wider) -->
@ -197,7 +197,7 @@
<input hidden id="poTypeId"/> <input hidden id="poTypeId"/>
<link href="~/css/po/CustomPOV3.css" rel="stylesheet" /> <link href="~/css/po/CustomPOV3.css" rel="stylesheet" />
<script src="~/JsFunctions/PO/CustomPOV9.js"></script> <script src="~/JsFunctions/PO/CustomPO.js"></script>
@await Html.PartialAsync("PagesView/PR/_PRWOCanvass") @await Html.PartialAsync("PagesView/PR/_PRWOCanvass")
@await Html.PartialAsync("PagesView/PO/_POScripts") @await Html.PartialAsync("PagesView/PO/_POScripts")
</body> </body>

View File

@ -17,7 +17,8 @@
<th style="width:25%">ProjectName</th> <th style="width:25%">ProjectName</th>
<th style="width:32%">DeliveryAddress</th> <th style="width:32%">DeliveryAddress</th>
<th style="width:10%">MaxDays</th> <th style="width:10%">MaxDays</th>
<th style="width:11%">Status</th> <th style="width:11%">PorjectStatus</th>
<th style="width:11%">Availability</th>
<th style="width:7%">Action</th> <th style="width:7%">Action</th>
</tr> </tr>
</thead> </thead>
@ -63,7 +64,16 @@
placeholder=" Describe deliveryAddress..."></textarea> placeholder=" Describe deliveryAddress..."></textarea>
<label for="deliveryAddress">Delivery Address</label> <label for="deliveryAddress">Delivery Address</label>
</div> </div>
<div class="form-floating mb-3">
<select id="projectStatus" class="form-control">
<option value="">-- Select Status --</option>
<option value="Pending">Pending</option>
<option value="Ongoing">Ongoing</option>
<option value="Completed">Completed</option>
<option value="Cancelled">Cancelled</option>
</select>
<label for="projectStatus">Project Status</label>
</div>
<div class="row g-3 mb-3"> <div class="row g-3 mb-3">
<div class="col-md-6"> <div class="col-md-6">
<div class="form-floating"> <div class="form-floating">

View File

@ -179,6 +179,46 @@
opacity: .5; opacity: .5;
cursor: default; cursor: default;
} }
.tm-search-dropdown {
position: absolute;
top: 100%;
left: 0;
right: 0;
z-index: 1090;
margin-top: 4px;
max-height: 220px;
overflow-y: auto;
background: #fff;
border: 1.5px solid var(--border, #d6eaec);
border-radius: 8px;
box-shadow: 0 8px 24px rgba(0,0,0,.12);
display: none;
}
.tm-search-dropdown.open {
display: block;
}
.tm-search-item {
padding: 8px 10px;
font-size: 13px;
color: var(--text-dark, #1a2e35);
cursor: pointer;
}
.tm-search-item:hover,
.tm-search-item.active {
background: var(--teal-pale, #e6f7f8);
color: var(--teal-dark, #0d5c63);
}
.tm-search-empty {
padding: 10px;
font-size: 12px;
color: var(--text-muted, #6b8890);
text-align: center;
}
</style> </style>
<script> <script>
window.TransactModal = (function () { window.TransactModal = (function () {
@ -196,7 +236,7 @@ window.TransactModal = (function () {
let optRIS, optMRS, formRIS, formMRS; let optRIS, optMRS, formRIS, formMRS;
// ── RIS fields ──────────────────────────────────────────────────────────── // ── RIS fields ────────────────────────────────────────────────────────────
let risItemBadge, risOnHand, risDiscipline, risIssuedTo, risQty, let risItemBadge, risOnHand, risDiscipline, risQty,
risPRRef, risRemarks, risQtyWarn; risPRRef, risRemarks, risQtyWarn;
// ── MRS fields ──────────────────────────────────────────────────────────── // ── MRS fields ────────────────────────────────────────────────────────────
@ -263,7 +303,7 @@ window.TransactModal = (function () {
<div style="width:38px;height:38px;border-radius:10px; <div style="width:38px;height:38px;border-radius:10px;
background:rgba(255,255,255,.15); background:rgba(255,255,255,.15);
display:flex;align-items:center;justify-content:center"> display:flex;align-items:center;justify-content:center">
<i class="fas fa-transfer-alt" style="color:#fff;font-size:16px"></i> <i class="fa-solid fa-arrow-right-arrow-left" style="color:#fff;font-size:16px"></i>
</div> </div>
<div> <div>
<div style="font-size:14px;font-weight:600;color:#fff"> <div style="font-size:14px;font-weight:600;color:#fff">
@ -328,18 +368,20 @@ window.TransactModal = (function () {
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px"> <div style="display:grid;grid-template-columns:1fr 1fr;gap:10px">
<div class="tm-form-group"> <div class="tm-form-group">
<label class="tm-label"> <label class="tm-label">
<i class="fas fa-tools"></i> Discipline <span class="tm-req">*</span> <i class="fas fa-tools"></i> TRADE <span class="tm-req">*</span>
</label> </label>
<select id="tm-ris-discipline" class="tm-input"> <select id="tm-ris-discipline" class="tm-input">
<option value="">Select discipline…</option> <option value="">Select trade…</option>
</select> </select>
</div> </div>
<div class="tm-form-group"> <div class="tm-form-group" style="position:relative">
<label class="tm-label"> <label class="tm-label">
<i class="fas fa-user"></i> Issued to <span class="tm-req">*</span> <i class="fas fa-diagram-project"></i> Project Name <span class="tm-req">*</span>
</label> </label>
<input id="tm-ris-issuedto" class="tm-input" <input id="tm-ris-project-code-name-search" class="tm-input"
type="text" placeholder="Name or user ID…"> type="text" placeholder="Search project name…" autocomplete="off">
<input type="hidden" id="tm-ris-project-code-name">
<div id="tm-ris-project-code-name-list" class="tm-search-dropdown"></div>
</div> </div>
</div> </div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px"> <div style="display:grid;grid-template-columns:1fr 1fr;gap:10px">
@ -359,7 +401,7 @@ window.TransactModal = (function () {
<i class="fas fa-file-alt"></i> PR reference <i class="fas fa-file-alt"></i> PR reference
</label> </label>
<input id="tm-ris-prref" class="tm-input" <input id="tm-ris-prref" class="tm-input"
type="text" placeholder="PR-2026-XXXX"> type="text" readOnly placeholder="PR-2026-XXXX">
</div> </div>
</div> </div>
<div class="tm-form-group"> <div class="tm-form-group">
@ -454,7 +496,12 @@ window.TransactModal = (function () {
// RIS fields // RIS fields
risItemBadge = document.getElementById("tm-ris-stock-badge"); risItemBadge = document.getElementById("tm-ris-stock-badge");
risDiscipline = document.getElementById("tm-ris-discipline"); risDiscipline = document.getElementById("tm-ris-discipline");
risIssuedTo = document.getElementById("tm-ris-issuedto"); risProjectCode = document.getElementById("tm-ris-project-code-name");
risProjectCodeSearch = document.getElementById("tm-ris-project-code-name-search");
risProjectCodeList = document.getElementById("tm-ris-project-code-name-list");
_bindProjectCodeSearch();
risQty = document.getElementById("tm-ris-qty"); risQty = document.getElementById("tm-ris-qty");
risPRRef = document.getElementById("tm-ris-prref"); risPRRef = document.getElementById("tm-ris-prref");
risRemarks = document.getElementById("tm-ris-remarks"); risRemarks = document.getElementById("tm-ris-remarks");
@ -509,7 +556,7 @@ window.TransactModal = (function () {
// Discipline dropdown // Discipline dropdown
risDiscipline.innerHTML = ` risDiscipline.innerHTML = `
<option value="">Select discipline…</option>` + <option value="">Select trade…</option>` +
(_ctx.disciplines || []).map(d => (_ctx.disciplines || []).map(d =>
` `
<option value="${d.disciplineId}">${H.escHtml(d.disciplineName)}</option>` <option value="${d.disciplineId}">${H.escHtml(d.disciplineName)}</option>`
@ -530,6 +577,11 @@ window.TransactModal = (function () {
.join("") .join("")
: ""); : "");
//Project name
_setProjectCodeOptions(_ctx.projectCodes);
risProjectCodeSearch.value = "";
risProjectCode.value = "";
if (!hasRIS) { if (!hasRIS) {
optMRS.style.opacity = ".45"; optMRS.style.opacity = ".45";
optMRS.style.cursor = "not-allowed"; optMRS.style.cursor = "not-allowed";
@ -605,9 +657,11 @@ window.TransactModal = (function () {
} }
function _clearErrors() { function _clearErrors() {
[risQty, risIssuedTo, risDiscipline, mrsRISSelect, mrsQty].forEach(el => { [risQty, risDiscipline, risProjectCode, mrsRISSelect, mrsQty].forEach(el => {
if (el) el.classList.remove("error"); if (el) el.classList.remove("error");
}); });
risProjectCodeSearch?.classList.remove("error");
[risQtyWarn, mrsQtyWarn].forEach(el => { [risQtyWarn, mrsQtyWarn].forEach(el => {
if (el) el.style.display = "none"; if (el) el.style.display = "none";
}); });
@ -618,11 +672,15 @@ window.TransactModal = (function () {
if (_activeType === "ris") { if (_activeType === "ris") {
if (!risDiscipline.value) { risDiscipline.classList.add("error"); valid = false; } if (!risDiscipline.value) { risDiscipline.classList.add("error"); valid = false; }
if (!risIssuedTo.value.trim()) { risIssuedTo.classList.add("error"); valid = false; }
const qty = parseInt(risQty.value, 10); const qty = parseInt(risQty.value, 10);
if (isNaN(qty) || qty < 1 || qty > _ctx.qtyOnHand) { if (isNaN(qty) || qty < 1 || qty > _ctx.qtyOnHand) {
risQty.classList.add("error"); valid = false; risQty.classList.add("error"); valid = false;
} }
if (!risProjectCode.value) {
risProjectCode.classList.add("error");
risProjectCodeSearch.classList.add("error");
valid = false;
}
} else { } else {
if (!mrsRISSelect.value) { mrsRISSelect.classList.add("error"); valid = false; } if (!mrsRISSelect.value) { mrsRISSelect.classList.add("error"); valid = false; }
const qty = parseInt(mrsQty.value, 10); const qty = parseInt(mrsQty.value, 10);
@ -636,6 +694,117 @@ window.TransactModal = (function () {
return valid; return valid;
} }
// ── Searchable dropdown refs ────────────────────────────────────────────────
let risProjectCode, risProjectCodeSearch, risProjectCodeList;
let _projectCodeOptions = [];
let _projectCodeActiveIndex = -1;
function _bindIssuedToSearch() {
risIssuedToSearch = document.getElementById("tm-ris-issuedto-search");
risIssuedToList = document.getElementById("tm-ris-issuedto-list");
risIssuedToSearch.addEventListener("input", _onIssuedToInput);
risIssuedToSearch.addEventListener("focus", () => _renderIssuedToList(risIssuedToSearch.value));
risIssuedToSearch.addEventListener("keydown", _onIssuedToKeydown);
document.addEventListener("click", (e) => {
if (!risIssuedToSearch.contains(e.target) && !risIssuedToList.contains(e.target)) {
_closeIssuedToList();
}
});
}
function _bindProjectCodeSearch() {
risProjectCodeSearch.addEventListener("input", _onProjectCodeInput);
risProjectCodeSearch.addEventListener("focus", () => _renderProjectCodeList(risProjectCodeSearch.value));
risProjectCodeSearch.addEventListener("keydown", _onProjectCodeKeydown);
document.addEventListener("click", (e) => {
if (!risProjectCodeSearch.contains(e.target) && !risProjectCodeList.contains(e.target)) {
_closeProjectCodeList();
}
});
}
function _setProjectCodeOptions(projectCodes) {
_projectCodeOptions = (projectCodes || []).map(p => ({
value: p.projectCodeId,
code: p.projectCode,
name: p.projectName,
label: `${p.projectCode} — ${p.projectName}`
}));
}
function _onProjectCodeInput() {
risProjectCode.value = ""; // invalidate committed selection until re-picked
_renderProjectCodeList(risProjectCodeSearch.value);
}
function _renderProjectCodeList(query) {
const q = (query || "").trim().toLowerCase();
const filtered = q
? _projectCodeOptions.filter(o =>
o.name.toLowerCase().includes(q) || o.code.toLowerCase().includes(q))
: _projectCodeOptions;
_projectCodeActiveIndex = -1;
risProjectCodeList.innerHTML = filtered.length
? filtered.map((o, i) =>
`<div class="tm-search-item" data-index="${i}" data-value="${o.value}">
<div>${H.escHtml(o.name)}</div>
<div style="font-size:11px;color:var(--text-muted,#6b8890)">${H.escHtml(o.code)}</div>
</div>`).join("")
: `<div class="tm-search-empty">No matching projects</div>`;
risProjectCodeList.querySelectorAll(".tm-search-item").forEach(item => {
item.addEventListener("click", () => {
const opt = _projectCodeOptions[parseInt(item.dataset.index, 10)];
_selectProjectCode(opt);
});
});
risProjectCodeList.classList.add("open");
}
function _selectProjectCode(opt) {
risProjectCode.value = opt.value; // ProjectCodeId — this is what gets posted
risProjectCodeSearch.value = opt.label; // visible text
_closeProjectCodeList();
risProjectCode.classList.remove("error");
risProjectCodeSearch.classList.remove("error");
}
function _closeProjectCodeList() {
risProjectCodeList.classList.remove("open");
_projectCodeActiveIndex = -1;
}
function _onProjectCodeKeydown(e) {
const items = risProjectCodeList.querySelectorAll(".tm-search-item");
if (!items.length) return;
if (e.key === "ArrowDown") {
e.preventDefault();
_projectCodeActiveIndex = Math.min(_projectCodeActiveIndex + 1, items.length - 1);
_highlightProjectCode(items);
} else if (e.key === "ArrowUp") {
e.preventDefault();
_projectCodeActiveIndex = Math.max(_projectCodeActiveIndex - 1, 0);
_highlightProjectCode(items);
} else if (e.key === "Enter") {
e.preventDefault();
const idx = _projectCodeActiveIndex >= 0 ? _projectCodeActiveIndex : 0;
const item = items[idx];
if (item) _selectProjectCode(_projectCodeOptions[parseInt(item.dataset.index, 10)]);
} else if (e.key === "Escape") {
_closeProjectCodeList();
}
}
function _highlightProjectCode(items) {
items.forEach((el, i) => el.classList.toggle("active", i === _projectCodeActiveIndex));
items[_projectCodeActiveIndex]?.scrollIntoView({ block: "nearest" });
}
// ════════════════════════════════════════════════════════════════════════ // ════════════════════════════════════════════════════════════════════════
// SUBMIT // SUBMIT
// ════════════════════════════════════════════════════════════════════════ // ════════════════════════════════════════════════════════════════════════
@ -665,7 +834,7 @@ window.TransactModal = (function () {
? { ? {
InventoryId: _ctx.inventoryId, InventoryId: _ctx.inventoryId,
PRDetailId: parseInt(risPRRef.value, 10) || 0, PRDetailId: parseInt(risPRRef.value, 10) || 0,
IssuedTo: risIssuedTo.value.trim(), ProjectCodeId: parseInt(risProjectCode.value, 10),
DisciplineId: parseInt(risDiscipline.value, 10), DisciplineId: parseInt(risDiscipline.value, 10),
QtyIssued: parseInt(risQty.value, 10), QtyIssued: parseInt(risQty.value, 10),
Remarks: risRemarks.value.trim() || null Remarks: risRemarks.value.trim() || null

View File

@ -23,3 +23,59 @@
</div> </div>
</div> </div>
</div> </div>
<script>
$(function() {
$("#currency").autocomplete({
source: function (request, response) {
console.log('Autocomplete source called with:', request.term);
$.ajax({
url: endpoint.GetCurrencies,
data: { query: request.term },
success: function (result) {
console.log('AJAX success:', result);
if (result && result.success && Array.isArray(result.data)) {
var formattedData = result.data.map(item => ({
label: item.label || '',
value: item.value !== undefined && item.value !== null ? item.value.toString() : '',
value2: item.value2 !== undefined && item.value2 !== null ? item.value2.toString() : ''
}));
response(formattedData);
} else {
console.error('Invalid data format received:', result);
response([]);
}
},
error: function(xhr, status, error) {
console.error('AJAX error:', status, error);
console.log('Response:', xhr.responseText);
response([]);
}
});
},
minLength: 2,
select: function (event, ui) {
$('#currency').val(ui.item.label);
$('#currencyId').val(ui.item.value);
return false;
},
focus: function (event, ui) {
event.preventDefault();
},
open: function () {
var dropdown = $(".ui-autocomplete");
dropdown.css({
"max-height": "200px",
"overflow-y": "auto"
});
},
messages: {
noResults: '',
results: function (count) {
return count + (count > 1 ? ' results' : ' result');
}
}
});
});
</script>

View File

@ -12,18 +12,18 @@
<script src="~/jsfunctions/common/ColumnCommonV2.js"></script> <script src="~/jsfunctions/common/ColumnCommonV2.js"></script>
<script src="~/jsfunctions/common/genericcrud.js"></script> <script src="~/jsfunctions/common/genericcrud.js"></script>
<script src="~/jsfunctions/common/ParamConfigV3.js"></script> <script src="~/jsfunctions/common/ParamConfigV3.js"></script>
<script src="~/jsfunctions/common/PostPutV3.js"></script> <script src="~/jsfunctions/common/PostPutV4.js"></script>
<script src="~/jsfunctions/common/PRWOCanvassV2.js"></script> <script src="~/jsfunctions/common/PRWOCanvassV2.js"></script>
<script src="~/jsfunctions/po/POButton.js"></script> <script src="~/jsfunctions/po/POButton.js"></script>
<script src="~/jsfunctions/po/PrintingV2.js"></script> <script src="~/jsfunctions/po/PrintingV2.js"></script>
<script src="~/JsFunctions/PO/POColumn.js"></script> <script src="~/JsFunctions/PO/POColumn.js"></script>
<script src="~/jsfunctions/po/ApiV5.js"></script> <script src="~/jsfunctions/po/ApiV6.js"></script>
<script src="~/jsfunctions/po/populatetable.js"></script> <script src="~/jsfunctions/po/populatetable.js"></script>
<script src="~/jsfunctions/po/POVarV6.js"></script> <script src="~/jsfunctions/po/POVarV6.js"></script>
<script src="~/jsfunctions/po/POViewV5.js"></script> <script src="~/jsfunctions/po/POViewV5.js"></script>
<script src="~/jsfunctions/po/PopulateDopdownV4.js"></script> <script src="~/jsfunctions/po/PopulateDopdownV5.js"></script>
<script src="~/jsfunctions/po/POPutPostV6.js"></script> <script src="~/jsfunctions/po/POPutPostV7.js"></script>
<script src="~/jsfunctions/po/rowCallBackV6.js"></script> <script src="~/jsfunctions/po/rowCallBackV6.js"></script>
<script src="~/jsfunctions/utilities/NewStyle.js"></script> <script src="~/jsfunctions/utilities/NewStyle.js"></script>

View File

@ -4,9 +4,9 @@
<link href="~/css/item/item.css" rel="stylesheet" /> <link href="~/css/item/item.css" rel="stylesheet" />
<link href="~/css/common/rowhighlighter.css" rel="stylesheet" /> <link href="~/css/common/rowhighlighter.css" rel="stylesheet" />
<script src="~/jsfunctions/pr/PRColumn.js"></script> <script src="~/jsfunctions/pr/PRColumnV2.js"></script>
<script src="~/jsfunctions/pr/PRView.js"></script> <script src="~/jsfunctions/pr/PRView.js"></script>
<script src="~/jsfunctions/pr/PRPostPut.js"></script> <script src="~/jsfunctions/pr/PRPostPutV2.js"></script>
<script src="~/jsfunctions/pr/PRButtonv3.js"></script> <script src="~/jsfunctions/pr/PRButtonv3.js"></script>
<script src="~/jsfunctions/pr/PRVarV3.js"></script> <script src="~/jsfunctions/pr/PRVarV3.js"></script>
<script src="~/jsfunctions/pr/ConfigV7.js"></script> <script src="~/jsfunctions/pr/ConfigV7.js"></script>

View File

@ -6,7 +6,7 @@
<script src="~/js/sidebar.js"></script> <script src="~/js/sidebar.js"></script>
<script src="~/Datatables/DataTables-1.13.6/js/jquery.dataTables.min.js"></script> <script src="~/Datatables/DataTables-1.13.6/js/jquery.dataTables.min.js"></script>
<script src="~/datatables/responsive-2.5.0/js/datatables.responsive.min.js"></script> <script src="~/datatables/responsive-2.5.0/js/datatables.responsive.min.js"></script>
<script src="~/jsfunctions/account/sessionTimeoutV4.js"></script> <script src="~/jsfunctions/account/sessionTimeoutV5.js"></script>
<script src="~/lib/jquery-ui-1132custom/jquery-ui.min.js"></script> <script src="~/lib/jquery-ui-1132custom/jquery-ui.min.js"></script>
<!-- DataTables Buttons and Export JS --> <!-- DataTables Buttons and Export JS -->

View File

@ -160,7 +160,8 @@
"GetIndexCard": "api/POMgmt/GetIndexCard/", "GetIndexCard": "api/POMgmt/GetIndexCard/",
"GetIncotermsByName": "api/POMgmt/GetIncotermsByName/", "GetIncotermsByName": "api/POMgmt/GetIncotermsByName/",
"GetPortOfDischarge": "api/POMgmt/GetPortOfDischarge/", "GetPortOfDischarge": "api/POMgmt/GetPortOfDischarge/",
"GetIncomingShipment": "api/POMgmt/GetIncomingShipment/" "GetIncomingShipment": "api/POMgmt/GetIncomingShipment/",
"GetCurrencies": "api/POMgmt/GetCurrencies/"
}, },
"SMTPMgmt": { "SMTPMgmt": {
"PostPutSmtp": "api/SMTPMgmt/PostPutSmtp/", "PostPutSmtp": "api/SMTPMgmt/PostPutSmtp/",
@ -199,7 +200,17 @@
"ApproveRIS": "api/RISMgmt/ApproveRIS/", "ApproveRIS": "api/RISMgmt/ApproveRIS/",
"CancelRIS": "api/RISMgmt/CancelRIS/", "CancelRIS": "api/RISMgmt/CancelRIS/",
"CreateRIS": "api/RISMgmt/", "CreateRIS": "api/RISMgmt/",
"GetRIS": "api/RISMgmt/GetRIS/" "GetRIS": "api/RISMgmt/GetRIS/",
"GetMRS": "api/MRSMgmt/",
"SearchRIS": "api/MRSMgmt/SearchRIS/",
"SearchProjects": "api/MRSMgmt/SearchProjects/",
"ApproveMRS": "api/MRSMgmt/Approve/",
"CancelMRS": "api/MRSMgmt/Cancel/",
"CreateMRS": "api/MRSMgmt/",
"RISReportData": "api/InventoryReports/GetRISData/",
"GetRISReport": "api/InventoryReports/GetRISReport/",
"GetMRSReport": "api/InventoryReports/GetMRSReport/",
"GetInventoryReport": "api/InventoryReports/GetInventoryReport/"
}, },
"ImageUploadSettings": { "ImageUploadSettings": {
"UploadPath": "C:\\WebApps\\wwwroot\\Content\\Images" "UploadPath": "C:\\WebApps\\wwwroot\\Content\\Images"

View File

@ -132,7 +132,7 @@ function handleStayLoggedIn() {
updateLastActivity(); updateLastActivity();
} }
console.log('User chose to stay logged in - session extended'); // console.log('User chose to stay logged in - session extended');
} }
/** /**
@ -145,7 +145,7 @@ function handleLogout() {
countdownInterval = null; countdownInterval = null;
} }
console.log('Session timeout - logging out...'); //console.log('Session timeout - logging out...');
// Perform logout // Perform logout
performLogout(); performLogout();
@ -167,7 +167,7 @@ function handleLogout() {
try { try {
const timestamp = Date.now(); const timestamp = Date.now();
sessionStorage.setItem(CONFIG.storageKey, timestamp.toString()); sessionStorage.setItem(CONFIG.storageKey, timestamp.toString());
console.log('Activity updated:', new Date(timestamp).toLocaleTimeString()); //console.log('Activity updated:', new Date(timestamp).toLocaleTimeString());
warningShown = false; // Reset warning flag on activity warningShown = false; // Reset warning flag on activity
} catch (e) { } catch (e) {
console.error('Failed to update last activity:', e); console.error('Failed to update last activity:', e);
@ -204,7 +204,7 @@ function handleLogout() {
const inactiveTime = now - lastActivity; const inactiveTime = now - lastActivity;
const inactiveMinutes = Math.floor(inactiveTime / 60000); const inactiveMinutes = Math.floor(inactiveTime / 60000);
console.log(`Session check - Inactive for: ${inactiveMinutes} minutes`); //console.log(`Session check - Inactive for: ${inactiveMinutes} minutes`);
// Check if session has expired // Check if session has expired
if (inactiveTime >= sessionTimeout) { if (inactiveTime >= sessionTimeout) {

View File

@ -67,6 +67,7 @@ function poValidateParameters(poTypeId, method, isItem) {
updateSharedVariables(inputs, customPOConfig); updateSharedVariables(inputs, customPOConfig);
} }
poDTO(customPOConfig); poDTO(customPOConfig);
return isValid; return isValid;
} }
function parameters(method) { function parameters(method) {
@ -85,6 +86,7 @@ function parameters(method) {
supplierId: document.getElementById('supplierId'), supplierId: document.getElementById('supplierId'),
deliveryDate: document.getElementById('deliveryDate'), deliveryDate: document.getElementById('deliveryDate'),
paymentTermsId: document.getElementById('C-paymentTermsId'), paymentTermsId: document.getElementById('C-paymentTermsId'),
currencyId: document.getElementById('currencyId')
}; };
} }
return paramValue; return paramValue;
@ -97,6 +99,7 @@ function clearCustomPOParam() {
profInvoiceDate: new Date().toISOString().split('T')[0], profInvoiceDate: new Date().toISOString().split('T')[0],
shippingInstructionId: 0, shippingInstructionId: 0,
podId: 0, podId: 0,
currencyId: 0,
paymentTermsId: 0, paymentTermsId: 0,
supplierId: 0, supplierId: 0,
supplierName: '', supplierName: '',
@ -104,6 +107,7 @@ function clearCustomPOParam() {
deliveryDate: new Date().toISOString().split('T')[0], deliveryDate: new Date().toISOString().split('T')[0],
deliverTo: '' deliverTo: ''
}; };
$('#poNo').val(''); $('#poNo').val('');
$('#poType').val(0); $('#poType').val(0);
$('#supplierName').val(''); $('#supplierName').val('');
@ -115,6 +119,7 @@ function clearCustomPOParam() {
$('#finalAmount').val(0.00); $('#finalAmount').val(0.00);
$('#docRequiredId').val(''); $('#docRequiredId').val('');
$('#discount').val(''); $('#discount').val('');
$('#currency').val('');
$('#grossAmountPHP').val(0.00); $('#grossAmountPHP').val(0.00);
$('#finalAmountPHP').val(0.00); $('#finalAmountPHP').val(0.00);
@ -142,4 +147,5 @@ function poDTO(config) {
Qty = config.qty; Qty = config.qty;
UOMName = config.uomName; UOMName = config.uomName;
UOMId = config.uomId; UOMId = config.uomId;
CurrencyId = config.currencyId;
} }

View File

@ -17,6 +17,7 @@
GetPortOfDischarge: "/POMgmt/GetPortOfDischarge", GetPortOfDischarge: "/POMgmt/GetPortOfDischarge",
GetPOListByTerm: "/POMgmt/GetPOListByTerm", GetPOListByTerm: "/POMgmt/GetPOListByTerm",
GetIncotermsByName: "/POMgmt/GetIncotermsByName", GetIncotermsByName: "/POMgmt/GetIncotermsByName",
GetCurrencies: "/POMgmt/GetCurrencies",
PutPOCancel: "/POMgmt/PutPOCancel", PutPOCancel: "/POMgmt/PutPOCancel",
PutPOItemDetail: "/POMgmt/PutPOItemDetail", PutPOItemDetail: "/POMgmt/PutPOItemDetail",

View File

@ -62,7 +62,10 @@ async function fetchAndPopulatePOFormData(poType, poId = null) {
$('#countryOrigin').val(d.header.countryOrigin || ''); $('#countryOrigin').val(d.header.countryOrigin || '');
$('#currencyCER').val(d.header.currencyCER || '59.00'); $('#currencyCER').val(d.header.currencyCER || '59.00');
$('#podId').val(d.header.podId || 0); $('#podId').val(d.header.podId || 0);
console.log('shipping Instruction', d.header.shippingInstructionId);
$('#currency').val(d.header.currencyName || '');
$('#currencyId').val(d.header.currencyId || 1);
$('#shippingInstructionId').val(d.header.shippingInstructionId); $('#shippingInstructionId').val(d.header.shippingInstructionId);
$('#discount').val(d.header.discount || 0); $('#discount').val(d.header.discount || 0);

View File

@ -252,7 +252,7 @@ function postPutCustomPO() {
data: { data: {
DocRequiredList, OtherChargesList, PRItemList, CountryOrigin, DocRequiredList, OtherChargesList, PRItemList, CountryOrigin,
POTypeId, PONo, IncotermsId, ProfInvoiceNo, ProfInvoiceDate, POTypeId, PONo, IncotermsId, ProfInvoiceNo, ProfInvoiceDate,
ShippingInstructionId, PodId, PaymentTermsId, ShippingInstructionId, PodId, PaymentTermsId,CurrencyId,
PoRemarks, Discount, SupplierId, DeliveryDate, DeliverTo PoRemarks, Discount, SupplierId, DeliveryDate, DeliverTo
}, },
success: function (response) { success: function (response) {
@ -306,7 +306,7 @@ function updateExistingPO() {
data: { data: {
DocRequiredList, OtherChargesList, PRItemList, CountryOrigin, DocRequiredList, OtherChargesList, PRItemList, CountryOrigin,
POTypeId, PONo, IncotermsId, ProfInvoiceNo, ProfInvoiceDate, POTypeId, PONo, IncotermsId, ProfInvoiceNo, ProfInvoiceDate,
ShippingInstructionId, PodId, PaymentTermsId, ShippingInstructionId, PodId, PaymentTermsId,CurrencyId,
PoRemarks, Discount, SupplierId, DeliveryDate, DeliverTo, IsUpdate PoRemarks, Discount, SupplierId, DeliveryDate, DeliverTo, IsUpdate
}, },
success: function (response) { success: function (response) {
@ -700,7 +700,6 @@ function AddItem() {
toggleSubmitButton(); toggleSubmitButton();
} }
function AddDocRequired() { function AddDocRequired() {
var selectedCheckboxes = $('.select-DocRequired-checkbox:checked'); var selectedCheckboxes = $('.select-DocRequired-checkbox:checked');
var DocRequiredList = []; var DocRequiredList = [];
@ -796,7 +795,6 @@ function AddDiscount() {
calculateFinalUsdAmount(); calculateFinalUsdAmount();
lessDiscount(); lessDiscount();
} }
function removeRowMain(rowData) { function removeRowMain(rowData) {
var poDataTable = $('#PODataTable').DataTable(); var poDataTable = $('#PODataTable').DataTable();

View File

@ -308,7 +308,8 @@ function populateSupplier() {
value: item.value !== undefined && item.value !== null ? item.value.toString() : '', value: item.value !== undefined && item.value !== null ? item.value.toString() : '',
value2: item.value2 !== undefined && item.value2 !== null ? item.value2.toString() : '', value2: item.value2 !== undefined && item.value2 !== null ? item.value2.toString() : '',
value3: item.value3 !== undefined && item.value3 !== null ? item.value3.toString() : '', value3: item.value3 !== undefined && item.value3 !== null ? item.value3.toString() : '',
value4: item.value4 !== undefined && item.value4 !== null ? item.value4.toString() : '' value4: item.value4 !== undefined && item.value4 !== null ? item.value4.toString() : '',
value5: item.value5 !== undefined && item.value5 !== null ? item.value5.toString() : ''
})); }));
response(formattedData); response(formattedData);
} else { } else {
@ -325,6 +326,7 @@ function populateSupplier() {
$('#currency').val(ui.item.value2); $('#currency').val(ui.item.value2);
$('#C-paymentTerms').val(ui.item.value3); $('#C-paymentTerms').val(ui.item.value3);
$('#C-paymentTermsId').val(ui.item.value4); $('#C-paymentTermsId').val(ui.item.value4);
$('#currencyId').val(ui.item.value5);
return false; return false;
}, },

View File

@ -255,6 +255,7 @@ var colOnProjectCode = [
{ data: 'projectName' }, { data: 'projectName' },
{ data: 'deliveryAddress' }, { data: 'deliveryAddress' },
{ data: 'maxDays' }, { data: 'maxDays' },
{ data: 'statusName' },
{ {
data: 'isActive', data: 'isActive',
render: function (data) { render: function (data) {

View File

@ -71,6 +71,7 @@ function postPutProjectCode() {
ProjectCodeId: Number($('#projectCodeId').val()) || 0, ProjectCodeId: Number($('#projectCodeId').val()) || 0,
ProjectCode: $('#projectCode').val().trim(), ProjectCode: $('#projectCode').val().trim(),
ProjectName: $('#projectName').val().trim(), ProjectName: $('#projectName').val().trim(),
StatusName: $('#projectStatus').val().trim(),
DeliveryAddress: $('#deliveryAddress').val().trim(), DeliveryAddress: $('#deliveryAddress').val().trim(),
MaxDays: parseInt($('#maxDays').val(), 10), MaxDays: parseInt($('#maxDays').val(), 10),
IsActive: $('#statusSwitch').is(':checked') IsActive: $('#statusSwitch').is(':checked')