PR Tabbed for Approved but no PO, Deleted items are working properly

This commit is contained in:
rowell_m_soriano 2026-02-17 17:05:52 +08:00
parent 99be1e9c8b
commit 11646fec68
16 changed files with 554 additions and 37 deletions

View File

@ -39,5 +39,7 @@ namespace CPRNIMS.Domain.Contracts.PR
Task<PRDetails> PostPutDeniedItem(PRDto PRDto);
Task<AlternativeOfferDetails> PutSupplierAlterOffer(PRDto pRDto);
Task<ResponseObject> PostPutProjectCode(PRDto prDto);
Task<List<RemovedPR>> GetRemovedPR(PRDto pRDto);
Task<List<ApprovedPR>> GetApprovedPR(PRDto pRDto);
}
}

View File

@ -414,6 +414,24 @@ namespace CPRNIMS.Domain.Services.PR
}
}
public async Task<List<RemovedPR>> GetRemovedPR(PRDto pRDto)
{
var allItems = await _dbContext.RemovedPRs
.FromSqlRaw("EXEC GetRemovedPR @UserId",
new SqlParameter("@UserId", pRDto.UserId)).ToListAsync();
return allItems ?? new List<RemovedPR>();
}
public async Task<List<ApprovedPR>> GetApprovedPR(PRDto pRDto)
{
var allItems = await _dbContext.ApprovedPrs
.FromSqlRaw("EXEC GetApprovedPR @UserId",
new SqlParameter("@UserId", pRDto.UserId)).ToListAsync();
return allItems ?? new List<ApprovedPR>();
}
#endregion
}
}

View File

@ -11,6 +11,9 @@ namespace CPRNIMS.Domain.UIContracts.PR
public interface IPRequest
{
#region Get
Task<List<PRVM>> GetAllPR(User user, PRVM viewModel);
Task<List<PRVM>?> GetApprovedPR(User user, PRVM viewModels);
Task<List<PRVM>?> GetRemovedPR(User user, PRVM viewModels);
Task<List<PRVM>?> GetApproverName(User user, PRVM viewModels);
Task<List<PRVM>?> GetApproverNameByPRNo(User user, PRVM viewModels);
Task<List<PRVM>> GetForReceiving(User user, PRVM viewModel);
@ -19,7 +22,6 @@ namespace CPRNIMS.Domain.UIContracts.PR
Task<List<PRVM>> GetPRByRRId(User user, PRVM viewModel);
Task<List<PRVM>> GetRRDetailByPO(User user, PRVM viewModel);
Task<List<PRVM>> GetPRStatusById(User user, PRVM viewModel);
Task<List<PRVM>> GetAllPR(User user, PRVM viewModel);
Task<List<PRVM>> GetPRArchived(User user, PRVM viewModel);
Task<List<PRVM>> GetMyPR(User user, PRVM viewModel);
Task<List<PRVM>> GetPRDetailByPRNo(User user, PRVM viewModel);

View File

@ -201,6 +201,17 @@ namespace CPRNIMS.Domain.UIServices.PR
return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:PRMgmt:GetSupplierAlterOfferDetails"]);
}
public async Task<List<PRVM>?> GetApprovedPR(User user, PRVM viewModel)
{
return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:PRMgmt:GetApprovedPR"]);
}
public async Task<List<PRVM>?> GetRemovedPR(User user, PRVM viewModel)
{
return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:PRMgmt:GetRemovedPR"]);
}
#endregion
#region POST PUT
public async Task<PRVM> PostPRApproveReject(User user, PRVM viewModel)

View File

@ -44,6 +44,8 @@ namespace CPRNIMS.Infrastructure.Database
public virtual DbSet<ItemCart> ItemCarts { get; set; }
public virtual DbSet<PR> PRs { get; set; }
public virtual DbSet<Approved> Approved { get; set; }
public virtual DbSet<ApprovedPR> ApprovedPrs { get; set; }
public virtual DbSet<RemovedPR> RemovedPRs { get; set; }
public virtual DbSet<SMTPCredential> SMTPCredentials { get; set; }
public virtual DbSet<PRDetails> PRDetails { get; set; }
public virtual DbSet<PRItemList> PRItemLists { get; set; }

View File

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Entities.Purchasing
{
public class ApprovedPR
{
[Key]
public long PRDetailsId { get; set; }
public long PRNo { get; set; }
public long PRId { get; set; }
public long ItemNo { get; set; }
public string? ItemName { get; set; }
public string? ItemDescription { get; set; }
public string? Department { get; set; }
public string? ItemCategoryName { get; set; }
public string? Remarks { get; set; }
public string? StatusName { get; set; }
public DateTime DateNeeded { get; set; }
public DateTime CreatedDate { get; set; }
public string? AttestedDate { get; set; }
public string? ApprovedDate { get; set; }
public string? UOMName { get; set; }
public decimal Qty { get; set; }
public string? ApprovedBy { get; set; }
public string? AttestedBy { get; set; }
public string? CreatedBy { get; set; }
public int RemainingDays { get; set; }
}
}

View File

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CPRNIMS.Infrastructure.Entities.Purchasing
{
public class RemovedPR
{
[Key]
public long PRDetailsId { get; set; }
public long PRNo { get; set; }
public long PRId { get; set; }
public long ItemNo { get; set; }
public string? ItemName { get; set; }
public string? ItemDescription { get; set; }
public string? Department { get; set; }
public string? ItemCategoryName { get; set; }
public string? Remarks { get; set; }
public string? StatusName { get; set; }
public DateTime DateNeeded { get; set; }
public DateTime CreatedDate { get; set; }
public string? AttestedDate { get; set; }
public string? ApprovedDate { get; set; }
public string? UOMName { get; set; }
public decimal Qty { get; set; }
public string? ApprovedBy { get; set; }
public string? AttestedBy { get; set; }
public string? CreatedBy { get; set; }
}
}

View File

@ -132,6 +132,9 @@ namespace CPRNIMS.Infrastructure.ViewModel.PR
public long PRId { get; set; }
public string? FileName { get; set; }
public string? OrigFileName { get; set; }
public string? AttestedDate { get; set; }
public string? ApprovedDate { get; set; }
public int RemainingDays { get; set; }
public ItemReceivingList? ItemList { get; set; }
public PRList? PRList { get; set; }
}

View File

@ -108,7 +108,7 @@ namespace CPRNIMS.WebApi.Controllers.Items
PRId = dto.PRId
};
await _item.PostPutAttachment(attachment);
// await SendNotificationEmail(dto);
await SendNotificationEmail(dto);
}
return dto;

View File

@ -348,6 +348,22 @@ namespace CPRNIMS.WebApi.Controllers.PR
nameof(GetAllPR), false
);
}
[HttpPost("GetApprovedPR")]
public async Task<IActionResult> GetApprovedPR(PRDto PRDto)
{
return await ExecuteWithErrorHandling(
() => _pRequest.GetApprovedPR(PRDto),
nameof(GetApprovedPR), false
);
}
[HttpPost("GetRemovedPR")]
public async Task<IActionResult> GetRemovedPR(PRDto PRDto)
{
return await ExecuteWithErrorHandling(
() => _pRequest.GetRemovedPR(PRDto),
nameof(GetRemovedPR), false
);
}
[HttpPost("GetMyPR")]
public async Task<IActionResult> GetMyPR(PRDto PRDto)
{

View File

@ -20,7 +20,22 @@ namespace CPRNIMS.WebApps.Controllers.PR
{
_pRequest = pRequest;
}
#region Get
#region Get
public async Task<IActionResult> GetAllPR(PRVM viewModels)
{
response = await _pRequest.GetAllPR(GetUser(), viewModels);
return GetResponse(response);
}
public async Task<IActionResult> GetApprovedPR(PRVM viewModels)
{
response = await _pRequest.GetApprovedPR(GetUser(), viewModels);
return GetResponse(response);
}
public async Task<IActionResult> GetRemovedPR(PRVM viewModels)
{
response = await _pRequest.GetRemovedPR(GetUser(), viewModels);
return GetResponse(response);
}
[HttpGet]
public async Task<IActionResult> GetPRAttachment(string fileName)
{
@ -51,7 +66,6 @@ namespace CPRNIMS.WebApps.Controllers.PR
return StatusCode(500, "Error retrieving file");
}
}
public async Task<IActionResult> GetProjectCodes(PRVM viewModels)
{
response = await _pRequest.GetProjectCodes(GetUser(), viewModels);
@ -67,11 +81,6 @@ namespace CPRNIMS.WebApps.Controllers.PR
response = await _pRequest.GetApproverName(GetUser(), viewModels);
return GetResponse(response);
}
public async Task<IActionResult> GetAllPR(PRVM viewModels)
{
response = await _pRequest.GetAllPR(GetUser(), viewModels);
return GetResponse(response);
}
public async Task<IActionResult> GetPRDetailByPRNo(PRVM viewModels)
{
response = await _pRequest.GetPRDetailByPRNo(GetUser(), viewModels);
@ -135,9 +144,7 @@ namespace CPRNIMS.WebApps.Controllers.PR
}
public async Task<IActionResult> GetDashBoard()
{
var viewModel = new PRVM();
response = await _pRequest.GetDashBoard(GetUser(), viewModel);
response = await _pRequest.GetDashBoard(GetUser(), new PRVM());
return GetResponse(response);
}
@ -325,6 +332,10 @@ namespace CPRNIMS.WebApps.Controllers.PR
{
return ViewComponent("Dashboard", new { dashboardId = DashboardId });
}
public IActionResult GetTabbedById(int TableId)
{
return ViewComponent("PRTabbed", new { tableId = TableId });
}
public async Task<IActionResult> DashBoard()
{
return await IsAuthenTicated();

View File

@ -0,0 +1,18 @@
using Microsoft.AspNetCore.Mvc;
namespace CPRNIMS.WebApps.ViewComponents.PR
{
public class PRTabbedViewComponent : ViewComponent
{
public IViewComponentResult Invoke(int tableId)
{
string viewName = tableId switch
{
1 => "~/Views/Components/PRMgmt/PRTabbedTable/AllPR.cshtml",
2 => "~/Views/Components/PRMgmt/PRTabbedTable/ApprovedPR.cshtml",
_ => "~/Views/Components/PRMgmt/PRTabbedTable/RemovedPR.cshtml"
};
return View(viewName);
}
}
}

View File

@ -0,0 +1,58 @@
<!-- AllPR.cshtml - Example View Component -->
<div class="tab-content-wrapper">
<table id="PRTable" class="row-border" cellspacing="0" width="100%">
<thead >
<tr>
<th style="width:7%">PRNo</th>
<th style="width:7%">New PRNo</th>
<th style="width:50%">ItemName's</th>
<th style="width:9%">Req. Date</th>
<th style="width:14%">Req. By</th>
<th style="width:8%">DateNeeded</th>
<th style="width:7%">ChargeTo</th>
<th style="width:7%">Action</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<script>
$(document).ready(function () {
loader = $('#overlay, #loader');
UserRights = document.getElementById("roleRights").value;
prTable = $('#PRTable').DataTable({
ajax: {
url: '/PRMgmt/GetAllPR',
type: 'GET',
beforeSend: function () {
loader.show();
},
complete: function () {
loader.hide();
},
error: function (xhr, error, thrown) {
loader.hide();
console.error('Error loading data:', error);
if (typeof toastr !== 'undefined') {
toastr.error('Failed to load data. Please try again.');
}
}
},
initComplete: initCompleteCallback,
columns: colOnPRTable,
order: [[3, 'asc']],
rowCallback: rowStatusColorCallback,
responsive: true,
language: {
emptyTable: "No record available",
loadingRecords: "Loading data...",
processing: "Processing..."
},
error: errorHandler
});
});
</script>

View File

@ -0,0 +1,160 @@
<div class="tab-content-wrapper">
<table id="ApprovedPRTable" class="row-border" cellspacing="0" width="100%">
<thead>
<tr>
<th>Status</th>
<th>Remaining Days</th>
<th>PRNo</th>
<th>ItemNo</th>
<th>ItemName</th>
<th>Qty</th>
<th>PR By</th>
<th>PR Date</th>
<th>Attested By</th>
<th>Attested Date</th>
<th>Approved By</th>
<th>Approved Date</th>
<th>Charge To</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<script>
$(document).ready(function() {
// Initialize DataTable for Approved PR
var approvedPRTable = $('#ApprovedPRTable').DataTable({
ajax: {
url: '/PRMgmt/GetApprovedPR',
type: 'GET',
beforeSend: function () {
loader.show();
},
complete: function () {
loader.hide();
},
error: function (xhr, error, thrown) {
loader.hide();
console.error('Error loading data:', error);
if (typeof toastr !== 'undefined') {
toastr.error('Failed to load data. Please try again.');
}
}
},
initComplete: function () {
initializeColumnSearch({
tableId: '#ApprovedPRTable',
dataTable: approvedPRTable,
searchableColumns: [
{
columnIndex: 0,
columnName: 'Status',
placeholder: 'Select Status...',
searchType: 'select',
searchMode: 'exact',
width: '150px'
},
{
columnIndex: 2,
columnName: 'PR No',
placeholder: 'Enter PR Number...',
searchType: 'text',
searchMode: 'exact',
width: '150px'
},
{
columnIndex: 3,
columnName: 'Item No',
placeholder: 'Enter Item Number...',
searchType: 'text',
searchMode: 'exact',
width: '150px'
},
{
columnIndex: 4,
columnName: 'Item Name',
placeholder: 'Enter Item Name...',
searchType: 'text',
searchMode: 'contains',
width: '200px'
},
{
columnIndex: 12,
columnName: 'Department',
placeholder: 'Select Department...',
searchType: 'select',
searchMode: 'exact',
width: '150px'
}
]
});
const uniqueSearchClass = 'column-search-input-ApprovedPRTable';
populateSelectOptions(approvedPRTable, 0, '.' + uniqueSearchClass + '[data-column="0"]');
populateSelectOptions(approvedPRTable, 12, '.' + uniqueSearchClass + '[data-column="12"]');
restoreSearchFromURL(uniqueSearchClass, '#ApprovedPRTable');
},
columns: [
{ data: 'statusName' },
{ data: 'remainingDays', searchable: false },
{ data: 'prNo' },
{ data: 'itemNo' },
{ data: 'itemName' },
{
searchable: false,
data: 'qty',
render: function (data) {
return numberWithCommas(data);
}
},
{ data: 'createdBy' },
{
searchable: false,
data: 'createdDate',
render: function (data) {
return formatDateTime(data);
}
},
{ data: 'attestedBy' },
{
searchable: false,
data: 'attestedDate',
render: function (data) {
return formatStrDateTime(data);
}
},
{ data: 'approvedBy' },
{
searchable: false,
data: 'approvedDate',
render: function (data) {
return formatStrDateTime(data);
}
},
{ data: 'department' }
],
order: [[11, 'asc']],
responsive: true,
language: {
emptyTable: "No approved records available"
}
});
});
function formatStrDateTime(dateString) {
if (!dateString || dateString === "None") return "None";
let date = new Date(dateString);
let month = ('0' + (date.getMonth() + 1)).slice(-2);
let day = ('0' + date.getDate()).slice(-2);
let year = date.getFullYear();
let hours = ('0' + date.getHours()).slice(-2);
let minutes = ('0' + date.getMinutes()).slice(-2);
let seconds = ('0' + date.getSeconds()).slice(-2);
return `${month}/${day}/${year} ${hours}:${minutes}:${seconds}`;
}
</script>

View File

@ -0,0 +1,149 @@
<div class="tab-content-wrapper">
<table id="RemovedPRTable" class="row-border" cellspacing="0" width="100%">
<thead>
<tr>
<th>PRNo</th>
<th>ItemNo</th>
<th>ItemName</th>
<th>Qty</th>
<th>PR By</th>
<th>PR Date</th>
<th>Attested By</th>
<th>Attested Date</th>
<th>Approved By</th>
<th>Approved Date</th>
<th>Charge To</th>
<th>Remarks</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<script>
$(document).ready(function() {
// Initialize DataTable for Approved PR
var removedPRTable = $('#RemovedPRTable').DataTable({
ajax: {
url: '/PRMgmt/GetApprovedPR',
type: 'GET',
beforeSend: function () {
loader.show();
},
complete: function () {
loader.hide();
},
error: function (xhr, error, thrown) {
loader.hide();
console.error('Error loading data:', error);
if (typeof toastr !== 'undefined') {
toastr.error('Failed to load data. Please try again.');
}
}
},
initComplete: function () {
initializeColumnSearch({
tableId: '#RemovedPRTable',
dataTable: removedPRTable,
searchableColumns: [
{
columnIndex: 0,
columnName: 'PR No',
placeholder: 'Enter PR Number...',
searchType: 'text',
searchMode: 'exact',
width: '150px'
},
{
columnIndex: 1,
columnName: 'Item No',
placeholder: 'Enter Item Number...',
searchType: 'text',
searchMode: 'exact',
width: '150px'
},
{
columnIndex: 2,
columnName: 'Item Name',
placeholder: 'Enter Item Name...',
searchType: 'text',
searchMode: 'contains',
width: '200px'
},
{
columnIndex: 10,
columnName: 'Department',
placeholder: 'Select Department...',
searchType: 'select',
searchMode: 'exact',
width: '150px'
}
]
});
const uniqueSearchClass = 'column-search-input-RemovedPRTable';
populateSelectOptions(removedPRTable, 10, '.' + uniqueSearchClass + '[data-column="10"]');
restoreSearchFromURL(uniqueSearchClass, '#RemovedPRTable');
},
columns: [
{ data: 'prNo' },
{ data: 'itemNo' },
{ data: 'itemName' },
{
searchable: false,
data: 'qty',
render: function (data) {
return numberWithCommas(data);
}
},
{ data: 'createdBy' },
{
searchable: false,
data: 'createdDate',
render: function (data) {
return formatDateTime(data);
}
},
{ data: 'attestedBy' },
{
searchable: false,
data: 'attestedDate',
render: function (data) {
return formatStrDateTime(data);
}
},
{ data: 'approvedBy' },
{
searchable: false,
data: 'approvedDate',
render: function (data) {
return formatStrDateTime(data);
}
},
{ data: 'department' },
{ data: 'remarks' }
],
order: [[9, 'asc']],
responsive: true,
language: {
emptyTable: "No approved records available"
}
});
});
function formatStrDateTime(dateString) {
if (!dateString || dateString === "None") return "None";
let date = new Date(dateString);
let month = ('0' + (date.getMonth() + 1)).slice(-2);
let day = ('0' + date.getDate()).slice(-2);
let year = date.getFullYear();
let hours = ('0' + date.getHours()).slice(-2);
let minutes = ('0' + date.getMinutes()).slice(-2);
let seconds = ('0' + date.getSeconds()).slice(-2);
return `${month}/${day}/${year} ${hours}:${minutes}:${seconds}`;
}
</script>

View File

@ -1,37 +1,35 @@
<body>
<div class="container-fluid">
<div class="table-container shadow-lg p-3 mb-5 bg-white rounded">
<div class="header-container">
<h2 style="display: flex; flex-direction: column; align-items: center;">PR List</h2>
<!-- Tab Navigation - Above Everything -->
<div class="pr-tabs-header">
<div class="pr-tabs-nav">
<button class="pr-tab-btn active" data-tab="pr-list" data-endpoint="/PRMgmt/GetAllPR">
All PR
</button>
<button class="pr-tab-btn" data-tab="pr-approved" data-endpoint="/PRMgmt/GetApprovedPR">
Approved PR
</button>
<button class="pr-tab-btn" data-tab="pr-removed" data-endpoint="/PRMgmt/GetRemovedPR">
Removed PR
</button>
</div>
</div>
<!-- Page Heading - Left Aligned Below Tabs -->
<div class="page-header-section">
<h2 id="pageTitle" class="page-heading">All Purchase Requests</h2>
</div>
<div id="TabbedContainer">
</div>
<br />
<br />
<table id="PRTable" class="row-border" cellspacing="0" width="100%">
<thead>
<tr>
<th style="width:7%">PRNo</th>
<th style ="width:7%">New PRNo</th>
<th style="width:50%">ItemName's</th>
<th style="width:9%">Req. Date</th>
<th style="width:14%">Req. By</th>
<th style="width:8%">DateNeeded</th>
<th style="width:7%">ChargeTo</th>
<th style="width:7%">Action</th>
<th hidden></th>
<th hidden></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<!-- Modal addRemarksUpdate -->
<div class="modal fade custom-modal-backdrop" id="addRemarksUpdate"
tabindex="-1" aria-labelledby="approveLabel" aria-hidden="true" data-bs-backdrop="static">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 id="approveLabel" class="modal-title">
Put remarks before to proceed
</h5>
@ -49,13 +47,13 @@
</div>
</div>
</div>
<!-- Modal viewItemRemovalRemarks -->
<div class="modal fade custom-modal-backdrop" id="viewItemRemovalRemarks"
tabindex="-1" aria-labelledby="approveLabel" aria-hidden="true" data-bs-backdrop="static">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 id="approveLabel" class="modal-title">
Put remarks before to remove
</h5>
@ -63,7 +61,7 @@
<div class="modal-body">
<label id="labelremarks" for="remove-remarks" style="margin-bottom: 5px;">Remarks</label>
<textarea type="text" id="remove-remarks" name="remove-remarks" rows="4" cols="50"
class="form-control" placeholder="Input here..."></textarea>
class="form-control" placeholder="Input here..."></textarea>
</div>
<div class="modal-footer">
@ -76,7 +74,9 @@
</div>
<link href="~/css/pr/TrackingV3.css" rel="stylesheet" />
<link href="~/css/pr/ButtonStyleV2.css" rel="stylesheet" />
<link href="~/css/pr/PRTabs.css" rel="stylesheet" />
@await Html.PartialAsync("PagesView/PR/_PRTracking")
<script src="~/JsFunctions/PR/PRV7.js"></script>
<script src="~/JsFunctions/PR/PRTabs.js"></script>
@await Html.PartialAsync("PagesView/PR/_PRScripts")
</body>