push only for upload attachment and project code but not working the autocomplete yet

This commit is contained in:
rowell_m_soriano 2026-02-13 15:56:56 +08:00
parent 0612679648
commit 6e0551707e
26 changed files with 755 additions and 6975 deletions

View File

@ -22,6 +22,8 @@ namespace CPRNIMS.Domain.Contracts.Items
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<List<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

@ -268,7 +268,7 @@ namespace CPRNIMS.Domain.Services.Items
else else
{ {
existing.OrigFileName = attach.OrigFileName; existing.OrigFileName = attach.OrigFileName;
existing.FileName = Guid.NewGuid().ToString(); existing.FileName = attach.FileName;
} }
await _dbContext.SaveChangesAsync(); await _dbContext.SaveChangesAsync();
} }
@ -316,5 +316,19 @@ namespace CPRNIMS.Domain.Services.Items
return allItems ?? new List<NotifUserKey>(); return allItems ?? new List<NotifUserKey>();
} }
public async Task<List<ProjectCodes>> GetProjectCode()
{
return await _dbContext.ProjectCodes
.AsNoTracking()
.ToListAsync();
}
public async Task<List<ProjectCodes>> GetProjectCodeByTerm(string? term)
{
return await _dbContext.ProjectCodes
.AsNoTracking()
.Where(p => EF.Functions.Like(p.ProjectCode, $"%{term}%"))
.ToListAsync();
}
} }
} }

View File

@ -21,6 +21,7 @@ namespace CPRNIMS.Domain.UIContracts.Items
Task<List<ItemVM>> GetItemUOM(User user, ItemVM viewModel); Task<List<ItemVM>> GetItemUOM(User user, ItemVM viewModel);
Task<List<ItemVM>> GetDepartment(User user, ItemVM viewModel); Task<List<ItemVM>> GetDepartment(User user, ItemVM viewModel);
Task<List<ItemVM>> GetItemCart(User user, ItemVM viewModel); Task<List<ItemVM>> GetItemCart(User user, ItemVM viewModel);
Task<List<ItemVM>?> GetProjectCode(User user, ItemVM viewModels);
Task<ItemVM> PostPurchRequest(User user, ItemVM viewModel); Task<ItemVM> PostPurchRequest(User user, ItemVM viewModel);
Task<ItemVM> PostPutItem(User user, ItemVM viewModel); Task<ItemVM> PostPutItem(User user, ItemVM viewModel);
Task<ItemVM> PutItemDetail(User user, ItemVM viewModel); Task<ItemVM> PutItemDetail(User user, ItemVM viewModel);

View File

@ -40,6 +40,7 @@ namespace CPRNIMS.Domain.UIContracts.PR
Task<PRVM> PRItemRemoval(User user, PRVM viewModel); Task<PRVM> PRItemRemoval(User user, PRVM viewModel);
Task<PRVM> ApprovedSelectedPRItem(User user, PRVM viewModel); Task<PRVM> ApprovedSelectedPRItem(User user, PRVM viewModel);
Task<PRVM> PostPutProjectCode(User user, PRVM viewModel); Task<PRVM> PostPutProjectCode(User user, PRVM viewModel);
Task<PRVM> PostPutAttachment(User user, PRVM prVM);
#endregion #endregion
} }
} }

View File

@ -129,6 +129,11 @@ namespace CPRNIMS.Domain.UIServices.Items
} }
#endregion #endregion
#region Get Method #region Get Method
public async Task<List<ItemVM>> GetProjectCode(Infrastructure.Models.Account.User user, ItemVM viewModel)
{
return await SendGetApiRequest(user, viewModel,
_configuration["LLI:NonInvent:ItemMgmt:GetProjectCode"]);
}
public async Task<List<ItemVM>> GetItemDetail(Infrastructure.Models.Account.User user, public async Task<List<ItemVM>> GetItemDetail(Infrastructure.Models.Account.User user,
ItemVM viewModel) ItemVM viewModel)
{ {

View File

@ -264,6 +264,12 @@ namespace CPRNIMS.Domain.UIServices.PR
return await SendPostApiRequest(user, viewModel, return await SendPostApiRequest(user, viewModel,
_configuration["LLI:NonInvent:PRMgmt:PostPutProjectCode"]); _configuration["LLI:NonInvent:PRMgmt:PostPutProjectCode"]);
} }
public async Task<PRVM> PostPutAttachment(User user, PRVM prVM)
{
return await SendPostApiRequest(user, prVM,
_configuration["LLI:NonInvent:PRMgmt:PostPutAttachment"]);
}
#endregion #endregion
} }
} }

View File

@ -12,6 +12,7 @@ namespace CPRNIMS.Infrastructure.Entities.Purchasing
{ {
[Key] [Key]
public long PRDetailsId { get; set; } public long PRDetailsId { get; set; }
public long PRId { get; set; }
public long ItemCodeId { get; set; } public long ItemCodeId { get; set; }
public short ItemClassId { get; set; } public short ItemClassId { get; set; }
public string? Department { get; set; } public string? Department { get; set; }
@ -38,5 +39,7 @@ namespace CPRNIMS.Infrastructure.Entities.Purchasing
public string? AttestedBy { get; set; } public string? AttestedBy { get; set; }
public string? ApprovedBy { get; set; } public string? ApprovedBy { get; set; }
public string? ProjectCode { get; set; } public string? ProjectCode { get; set; }
public string? FileName { get; set; }
public string? OrigFileName { get; set; }
} }
} }

View File

@ -32,9 +32,9 @@ namespace CPRNIMS.Infrastructure.Entities.Purchasing
public string? UOMName { get; set; } public string? UOMName { get; set; }
public string? ItemColorName { get; set; } public string? ItemColorName { get; set; }
public long PRNo { get; set; } public long PRNo { get; set; }
public long PRId { get; set; }
public string? Remarks { get; set; } public string? Remarks { get; set; }
public DateTime DateNeeded { get; set; } public DateTime DateNeeded { get; set; }
//public bool Queue { get; set; }
public string? AggreItemName { get; set; } public string? AggreItemName { get; set; }
} }
} }

View File

@ -1,13 +1,12 @@
using CPRNIMS.Domain.Contracts.Items; using CPRNIMS.Domain.Contracts.Items;
using CPRNIMS.Domain.Contracts.SMTP;
using CPRNIMS.Domain.Services; using CPRNIMS.Domain.Services;
using CPRNIMS.Infrastructure.Dto.Items; using CPRNIMS.Infrastructure.Dto.Items;
using CPRNIMS.Infrastructure.Entities.Items;
using CPRNIMS.Infrastructure.Helper; using CPRNIMS.Infrastructure.Helper;
using CPRNIMS.Infrastructure.Models.Common; using CPRNIMS.Infrastructure.Models.Common;
using CPRNIMS.Infrastructure.ViewModel.Common; using CPRNIMS.Infrastructure.ViewModel.Common;
using CPRNIMS.Infrastructure.ViewModel.Items; using CPRNIMS.Infrastructure.ViewModel.Items;
using CPRNIMS.WebApi.Controllers.Base; using CPRNIMS.WebApi.Controllers.Base;
using Google.Apis.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System.Text; using System.Text;
@ -172,6 +171,12 @@ namespace CPRNIMS.WebApi.Controllers.Items
}); });
} }
} }
[HttpPost("GetProjectCode")]
public async Task<IActionResult> GetProjectCode(ItemCodeDto itemDto)
{
var results = await _item.GetProjectCodeByTerm(itemDto.FileName);
return Ok( new {message="success", messCode=1, data= results });
}
[HttpPost("GetDepartment")] [HttpPost("GetDepartment")]
public async Task<IActionResult> GetDepartment(ItemCodeDto itemDto) public async Task<IActionResult> GetDepartment(ItemCodeDto itemDto)

View File

@ -1,5 +1,7 @@
using CPRNIMS.Domain.Contracts.PR; using CPRNIMS.Domain.Contracts.Items;
using CPRNIMS.Domain.Contracts.PR;
using CPRNIMS.Domain.Services; using CPRNIMS.Domain.Services;
using CPRNIMS.Infrastructure.Dto.Items;
using CPRNIMS.Infrastructure.Dto.PO; using CPRNIMS.Infrastructure.Dto.PO;
using CPRNIMS.Infrastructure.Dto.PR; using CPRNIMS.Infrastructure.Dto.PR;
using CPRNIMS.Infrastructure.Entities.PO; using CPRNIMS.Infrastructure.Entities.PO;
@ -12,6 +14,7 @@ using CPRNIMS.WebApi.Controllers.Base;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System.Reflection.Metadata.Ecma335;
using System.Text; using System.Text;
@ -23,17 +26,30 @@ namespace CPRNIMS.WebApi.Controllers.PR
private readonly IPRequest _pRequest; private readonly IPRequest _pRequest;
private readonly SMTPHelper _smptHelper; private readonly SMTPHelper _smptHelper;
private readonly IConfiguration _config; private readonly IConfiguration _config;
private readonly IItem _item;
public PRMgmtController(ErrorMessageService errorMessageService, public PRMgmtController(ErrorMessageService errorMessageService,
IWebHostEnvironment webHostEnvironment, SMTPHelper sMTPHelper, IWebHostEnvironment webHostEnvironment, SMTPHelper sMTPHelper,
IConfiguration configuration, IPRequest pRequest) : IConfiguration configuration, IPRequest pRequest, IItem item) :
base(errorMessageService, webHostEnvironment, configuration) base(errorMessageService, webHostEnvironment, configuration)
{ {
_config = configuration; _config = configuration;
_smptHelper = sMTPHelper; _smptHelper = sMTPHelper;
_pRequest = pRequest; _pRequest = pRequest;
_item = item;
} }
#region POST PUT #region POST PUT
[HttpPost("PostPutAttachment")]
public async Task<IActionResult> PostPutAttachment([FromBody] PRVM PRDto)
{
var item = new AttachmentRequest()
{
PRId=PRDto.PRId,
FileName=PRDto.FileName,
OrigFileName=PRDto.OrigFileName,
};
await _item.PostPutAttachment(item);
return Ok(new { messCode = 1, message = "success"});
}
[HttpPost("ApprovedSelectedPRItem")] [HttpPost("ApprovedSelectedPRItem")]
public async Task<IActionResult> ApprovedSelectedPRItem([FromBody] PRVM PRDto) public async Task<IActionResult> ApprovedSelectedPRItem([FromBody] PRVM PRDto)
{ {

View File

@ -255,6 +255,13 @@ namespace CPRNIMS.WebApps.Controllers.Items
#endregion #endregion
#region Get #region Get
public async Task<IActionResult> GetProjectCode(string term)
{
var item = new ItemVM();
item.FileName = term;
response = await _item.GetProjectCode(GetUser(), item);
return GetResponse(response);
}
public async Task<IActionResult> GetImageFileIds() public async Task<IActionResult> GetImageFileIds()
{ {
try try

View File

@ -21,24 +21,28 @@ namespace CPRNIMS.WebApps.Controllers.PR
_pRequest = pRequest; _pRequest = pRequest;
} }
#region Get #region Get
private async Task<IActionResult> GetProductFile(string fileName) [HttpGet]
public async Task<IActionResult> GetPRAttachment(string fileName)
{ {
try try
{ {
// Validate filename
if (string.IsNullOrWhiteSpace(fileName) || fileName.Contains("..")) if (string.IsNullOrWhiteSpace(fileName) || fileName.Contains(".."))
{ {
return BadRequest("Invalid file name"); // Return a 400 Bad Request so the frontend 'catch' or '!response.ok' triggers
return BadRequest(new { success = false, message = "File does not exist!" });
} }
var uploadsPath = Path.Combine(_webHostEnvironment.WebRootPath, "Content/Uploads", "PRAttachment"); var uploadsPath = Path.Combine(_webHostEnvironment.WebRootPath, "Content/Uploads", "PRAttachment");
var filePath = Path.Combine(uploadsPath, fileName); var filePath = Path.Combine(uploadsPath, fileName);
ContentTypeHelper.ValidateFile(filePath, uploadsPath); if (!System.IO.File.Exists(filePath))
{
return NotFound(new { success = false, message = "File not found on server." });
}
// Stream the file instead of loading entirely into memory // Stream the file for better performance
var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
var contentType = ContentTypeHelper.GetContentType(fileName); var contentType = "application/octet-stream"; // Or use a provider to get actual type
return File(fileStream, contentType, fileName, enableRangeProcessing: true); return File(fileStream, contentType, fileName, enableRangeProcessing: true);
} }
@ -47,6 +51,7 @@ namespace CPRNIMS.WebApps.Controllers.PR
return StatusCode(500, "Error retrieving file"); return StatusCode(500, "Error retrieving file");
} }
} }
public async Task<IActionResult> GetProjectCodes(PRVM viewModels) public async Task<IActionResult> GetProjectCodes(PRVM viewModels)
{ {
response = await _pRequest.GetProjectCodes(GetUser(), viewModels); response = await _pRequest.GetProjectCodes(GetUser(), viewModels);
@ -150,6 +155,79 @@ namespace CPRNIMS.WebApps.Controllers.PR
} }
#endregion #endregion
#region POST PUT #region POST PUT
public async Task<IActionResult?> UploadAttachment(IFormFile? file, [FromForm] string? oldFileName,
[FromForm] long prId)
{
var uploadsPath = Path.Combine(
_webHostEnvironment.WebRootPath,
"Content", "Uploads", "PRAttachment");
Directory.CreateDirectory(uploadsPath);
// If no new file uploaded, return old filename
if (file == null)
return BadRequest(new { success = false, message = "File does not exist!" });
// Delete old file if exists
if (!string.IsNullOrWhiteSpace(oldFileName))
{
await DeleteAttachmentAsync(oldFileName);
}
// Validate file extension
var allowedExtensions = new[] { ".csv", ".xlsx", ".xls", ".pdf" };
var fileExtension = Path.GetExtension(file.FileName).ToLowerInvariant();
if (!allowedExtensions.Contains(fileExtension))
{
throw new InvalidOperationException("Invalid file type. Only CSV, Excel, and PDF files are allowed.");
}
// Validate file size (5MB max)
if (file.Length > 5 * 1024 * 1024)
{
throw new InvalidOperationException("File size exceeds 5MB limit.");
}
// Generate new unique filename with original extension
var newFileName = $"{Guid.NewGuid()}{fileExtension}";
var newFilePath = Path.Combine(uploadsPath, newFileName);
// Save new file
await using var stream = new FileStream(newFilePath, FileMode.Create);
await file.CopyToAsync(stream);
var prVM = new PRVM()
{
FileName = newFileName,
OrigFileName = file.FileName,
PRId = prId
};
var prResponse = await _pRequest.PostPutAttachment(GetUser(),prVM);
if (prResponse.messCode == 0) {
return BadRequest(new { success = false, message = "File does not exist!"});
}
// Return only filename (NOT full path)
return Json(new { success = true, message = "Attachment successfully uploaded!", newFileName = newFileName });
}
private async Task DeleteAttachmentAsync(string fileName)
{
if (string.IsNullOrWhiteSpace(fileName))
return;
var uploadsPath = Path.Combine(
_webHostEnvironment.WebRootPath,
"Content", "Uploads", "PRAttachment");
var filePath = Path.Combine(uploadsPath, fileName);
if (System.IO.File.Exists(filePath))
{
await Task.Run(() => System.IO.File.Delete(filePath));
}
}
public async Task<IActionResult> PostPutProjectCode([FromBody] PRVM viewModel) public async Task<IActionResult> PostPutProjectCode([FromBody] PRVM viewModel)
{ {
var postPutItem = await _pRequest.PostPutProjectCode(GetUser(), viewModel); var postPutItem = await _pRequest.PostPutProjectCode(GetUser(), viewModel);

View File

@ -113,7 +113,7 @@
rows="4" rows="4"
placeholder="Add any additional notes or comments here..."></textarea> placeholder="Add any additional notes or comments here..."></textarea>
<div class="form-text"> <div class="form-text">
<span id="charCount">0</span>/500 characters <span id="charCount">0</span>/100 characters
</div> </div>
</div> </div>

View File

@ -74,8 +74,8 @@
</div> </div>
</div> </div>
</div> </div>
<link href="~/css/pr/TrackingV2.css" rel="stylesheet" /> <link href="~/css/pr/TrackingV3.css" rel="stylesheet" />
<link href="~/css/pr/buttonstyle.css" rel="stylesheet" /> <link href="~/css/pr/ButtonStyleV2.css" rel="stylesheet" />
@await Html.PartialAsync("PagesView/PR/_PRTracking") @await Html.PartialAsync("PagesView/PR/_PRTracking")
<script src="~/JsFunctions/PR/PRV6.js"></script> <script src="~/JsFunctions/PR/PRV6.js"></script>
@await Html.PartialAsync("PagesView/PR/_PRScripts") @await Html.PartialAsync("PagesView/PR/_PRScripts")

View File

@ -5,7 +5,7 @@
</div> </div>
<input hidden id="roleRights" value="@ViewBag.UserRoles" /> <input hidden id="roleRights" value="@ViewBag.UserRoles" />
<link href="~/css/canvass/itemfortagging.css" rel="stylesheet" /> <link href="~/css/canvass/itemfortagging.css" rel="stylesheet" />
<link href="~/css/pr/buttonstyle.css" rel="stylesheet" /> <link href="~/css/pr/ButtonStyleV2.css" rel="stylesheet" />
<link href="~/css/common/rowhighlighter.css" rel="stylesheet" /> <link href="~/css/common/rowhighlighter.css" rel="stylesheet" />
<script src="~/JsFunctions/Canvass/canvassColumnV9.js"></script> <script src="~/JsFunctions/Canvass/canvassColumnV9.js"></script>
<script src="~/JsFunctions/Canvass/canvassVarV3.js"></script> <script src="~/JsFunctions/Canvass/canvassVarV3.js"></script>

View File

@ -2,6 +2,7 @@
<div id="loader" class="loader"></div> <div id="loader" class="loader"></div>
</div> </div>
<link href="~/css/common/rowhighlighter.css" rel="stylesheet" /> <link href="~/css/common/rowhighlighter.css" rel="stylesheet" />
<script src="~/jsfunctions/pr/PRColumnV7.js"></script> <script src="~/jsfunctions/pr/PRColumnV7.js"></script>
<script src="~/jsfunctions/pr/PRViewV5.js"></script> <script src="~/jsfunctions/pr/PRViewV5.js"></script>
<script src="~/jsfunctions/pr/PRPutPost.js"></script> <script src="~/jsfunctions/pr/PRPutPost.js"></script>

View File

@ -337,60 +337,112 @@
</div> </div>
<div id="printableRelatedItem"> <div id="printableRelatedItem">
<div class="modal-body"> <div class="modal-body">
<!-- PR Info Section --> <!-- PR SUMMARY CARD -->
<div class="p-2 mb-3 rounded border shadow-sm bg-light pr-info-section"> <div class="card border-0 shadow-sm mb-4 pr-info-section">
<div class="row mb-2"> <div class="card-body">
<!-- PR No -->
<div class="col-md-5"> <div class="row g-3">
<small class="text-muted">P.R. No</small>
<div id="label-pr-prNo" class="fw-bold text-dark"></div> <div class="col-md-3">
<div class="text-muted small">P.R. No</div>
<div id="label-pr-prNo" class="fw-bold fs-6"></div>
</div> </div>
<!-- PR By -->
<div class="col-md-5"> <div class="col-md-3">
<small class="text-muted">P.R. By</small> <div class="text-muted small">Date Needed</div>
<div id="label-prby" class="fw-bold text-dark"></div> <div id="label-pr-dateNeeded" class="fw-semibold text-danger"></div>
</div> </div>
<!-- Department -->
<div class="col-md-5">
<small class="text-muted">Department</small> <div class="col-md-3">
<div id="label-pr-Department" class="fw-bold text-dark"></div> <div class="text-muted small">Department</div>
<div id="label-pr-Department" class="fw-semibold"></div>
</div>
<div class="col-md-3">
<div class="text-muted small">Project Code</div>
<div id="label-pr-ProjectCode" class="fw-semibold"></div>
</div>
<div class="col-md-3">
<div class="text-muted small">Requested By</div>
<div id="label-prby" class="fw-semibold"></div>
</div>
<div class="col-md-3">
<div class="text-muted small">Attested By</div>
<div id="label-pr-attestedBy" class="fw-semibold"></div>
</div>
<div class="col-md-3">
<div class="text-muted small">Approved By</div>
<div id="label-pr-approvedBy" class="fw-semibold"></div>
</div>
<div class="col-md-3">
<div class="text-muted small">Remarks</div>
<div id="label-pr-remarks"
class="bg-light rounded p-2 small"></div>
</div>
</div> </div>
<div class="col-md-5">
<small class="text-muted">Project Code</small>
<div id="label-pr-ProjectCode" class="fw-bold text-dark"></div>
</div> </div>
</div> </div>
<div class="row mb-2"> <!-- SELECTION SUMMARY -->
<!-- Attested By --> <div class="d-flex align-items-center mb-3 gap-2">
<div class="col-md-4"> <div>
<small class="text-muted">Attested By</small> <span class="fw-semibold">Selected Items:</span>
<div id="label-pr-attestedBy" class="fw-bold text-dark"></div> <span id="totalSelected" class="badge bg-danger ms-2">0</span>
</div> </div>
<!-- Approved By --> <div>
<div class="col-md-4"> <button id="btnDownloadAttachment"
<small class="text-muted">Approved By</small> class="btn btn-sm btn-outline-teal d-none"
<div id="label-pr-approvedBy" class="fw-bold text-dark"></div> onclick="downloadPRAttachment()">
📎Export
</button>
<input hidden id="fileName" />
<input hidden id="origFileName" />
<input hidden id="prId" />
</div>
<!-- File Attachment Section -->
<div class="d-flex align-items-center gap-2 flex-grow-1">
<!-- File Input -->
<div class="file-upload-wrapper position-relative">
<input type="file"
class="form-control"
id="fileAttachment"
name="fileAttachment"
accept=".csv,.xlsx,.xls,.pdf"
style="max-width: 300px;" />
</div>
<!-- File Info Badge (shows when file selected) -->
<div id="fileInfoBadge" class="d-none">
<span class="badge bg-success-subtle text-success border border-success px-3 py-2">
<i class="bi bi-file-earmark-check me-1"></i>
<span id="fileNameDisplay" class="me-2"></span>
<small class="text-muted">(<span id="fileSizeDisplay"></span>)</small>
<button type="button"
class="btn-close btn-close-sm ms-2"
onclick="clearFileAttachment()"
style="font-size: 0.7rem; vertical-align: middle;"
title="Remove file"></button>
</span>
</div>
<!-- Upload/Update Button (shows when file selected) -->
<div id="btnUploadContainer" class="d-none ms-auto">
<button type="button"
class="btn btn-success btn-sm"
onclick="uploadAttachment()">
<i class="bi bi-cloud-upload me-1"></i>
<span id="btnUploadText">Upload Attachment</span>
</button>
</div> </div>
<!-- Date Needed -->
<div class="col-md-4">
<small class="text-muted">Date Needed</small>
<div id="label-pr-dateNeeded" class="fw-bold text-dark"></div>
</div> </div>
</div> </div>
<!-- Requestor Remarks -->
<div class="row">
<div class="col-md-12">
<small class="text-muted">Remarks</small>
<div id="label-pr-remarks" class="fw-bold text-dark"></div>
</div>
</div>
</div>
<label for="totalSelected" style="font-size:medium;">Total Selected : </label>
<label id="totalSelected"
style="margin-bottom:20px; width:50px; font-weight:bold; color:red;"></label>
<br />
<table id="PRdataTable" <table id="PRdataTable"
class="row-border" style="width: 100%;"> class="row-border" style="width: 100%;">
<colgroup> <colgroup>
@ -422,15 +474,31 @@
</table> </table>
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer pr-modal-footer">
<button type="button" class="btn btn-primary" onclick="resetIsApproval()" data-bs-dismiss="modal">Back</button> <button type="button"
<button type="button" id="btnPrintPR" onclick="printPRItem();" class="btn btn-warning">Print</button> class="btn btn-outline-secondary"
<button id="btnSubmitItem" type="button" onclick="resetIsApproval()"
class="btn btn-success" onclick="approvedSelectedPRItem();"> data-bs-dismiss="modal">
Submit Back
</button>
<button type="button"
id="btnPrintPR"
onclick="printPRItem();"
class="btn btn-teal-warning">
🖨 Print
</button>
<button id="btnSubmitItem"
type="button"
class="btn btn-teal-primary"
onclick="approvedSelectedPRItem();">
✔ Approve Selected
</button> </button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<input hidden id="roleRights" value="@ViewBag.UserRoles" /> <input hidden id="roleRights" value="@ViewBag.UserRoles" />

View File

@ -247,6 +247,17 @@ document.getElementById('fileAttachment').addEventListener('change', function (e
filePreview.classList.remove('d-none'); filePreview.classList.remove('d-none');
} }
}); });
function formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i];
}
function clearFileAttachment() {
document.getElementById('fileAttachment').value = '';
document.getElementById('filePreview').classList.add('d-none');
}
function clearFormData() { function clearFormData() {
document.getElementById('dateNeeded').value = ''; document.getElementById('dateNeeded').value = '';
document.getElementById('projectCode').value = ''; document.getElementById('projectCode').value = '';
@ -256,14 +267,10 @@ function clearFormData() {
clearFileAttachment(); clearFileAttachment();
document.getElementById('charCount').textContent = '0'; document.getElementById('charCount').textContent = '0';
} }
function clearFileAttachment() {
document.getElementById('fileAttachment').value = '';
document.getElementById('filePreview').classList.add('d-none');
}
document.getElementById('requestorRemarks').addEventListener('input', function (e) { document.getElementById('requestorRemarks').addEventListener('input', function (e) {
const charCount = document.getElementById('charCount'); const charCount = document.getElementById('charCount');
const currentLength = e.target.value.length; const currentLength = e.target.value.length;
const maxLength = 500; const maxLength = 100;
charCount.textContent = currentLength; charCount.textContent = currentLength;
@ -279,10 +286,4 @@ document.getElementById('requestorRemarks').addEventListener('input', function (
charCount.classList.remove('text-danger'); charCount.classList.remove('text-danger');
} }
}); });
function formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i];
}

View File

@ -1,32 +1,50 @@
async function setupProjectCodeAutocomplete() { function populateGetProjectCode() {
const input = document.getElementById('projectCode'); $("#projectCode").autocomplete({
let debounceTimer; source: function (request, response) {
$.ajax({
url:'/ItemMgmt/GetProjectCode',
data: { query: request.term },
success: function (result) {
if (result && result.success && Array.isArray(result.data)) {
input.addEventListener('input', function (e) { var formattedData = result.data.map(item => ({
clearTimeout(debounceTimer); label: item.label || '',
const searchTerm = e.target.value; value: item.value !== undefined && item.value !== null ? item.value.toString() : '',
value2: item.value2 !== undefined && item.value2 !== null ? item.value2.toString() : '',
if (searchTerm.length < 2) return; value3: item.value3 !== undefined && item.value3 !== null ? item.value3.toString() : '',
value4: item.value4 !== undefined && item.value4 !== null ? item.value4.toString() : ''
debounceTimer = setTimeout(async () => { }));
try { response(formattedData);
// Replace with your actual API endpoint } else {
const response = await fetch(`/api/projects/search?term=${encodeURIComponent(searchTerm)}`); console.error('Invalid data format received:', result);
const projects = await response.json(); response([]);
}
const datalist = document.getElementById('projectCodeList'); }
datalist.innerHTML = ''; });
},
projects.forEach(project => { minLength: 2,
const option = document.createElement('option'); select: function (event, ui) {
option.value = project.code; $('#projectCodeList').val(ui.item.label);
option.textContent = `${project.code} - ${project.name}`; $('#supplierId').val(ui.item.value);
datalist.appendChild(option);
}); return false;
} catch (error) { },
console.error('Error fetching project codes:', error); 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');
}
} }
}, 300);
}); });
} }
function populateItemCategSelect() { function populateItemCategSelect() {
@ -420,6 +438,7 @@ function inputItemPopulation() {
} }
function showModal() { function showModal() {
popltDeprtmntChargeTo(); popltDeprtmntChargeTo();
populateGetProjectCode();
$('#addDateNeeded').modal('show'); $('#addDateNeeded').modal('show');
$('#addDateNeeded').css('z-index', 1060); $('#addDateNeeded').css('z-index', 1060);
} }

View File

@ -19,8 +19,6 @@
}; };
}); });
console.log(requestData);
var DateNeeded = document.getElementById('dateNeeded').value; var DateNeeded = document.getElementById('dateNeeded').value;
if (!DateNeeded) { if (!DateNeeded) {
@ -234,91 +232,6 @@ function sendUpdateRequest(data, loader) {
} }
}); });
} }
//function postPutPurchase() {
// loader = $('#overlay, #loader').css('z-index', 1060);
// isValid = true;
// var Remarks = document.getElementById('requestorRemarks').value;
// var selectedCheckboxes = $('.selectedItem-checkbox:checked');
// var requestData = [];
// selectedCheckboxes.each(function () {
// var $row = $(this).closest('tr');
// var rowIndex = itemTable.row($row).index();
// var rowData = itemTable.row(rowIndex).data();
// var itemCartId = rowData.itemCartId;
// var itemNo = rowData.itemNo;
// var qty = $row.find('.editable-qty').val() || rowData.qty;
// if (parseFloat(qty) === 0 || isNaN(parseFloat(qty))) {
// isValid = false;
// showToast('warning', "Please input a valid qty for ItemNo# " + itemNo + "!", ' warning', 4000);
// $(modalId).modal('hide');
// return false;
// }
// var itemData = {
// itemCartId: itemCartId,
// ItemNo: itemNo,
// qty: qty
// };
// requestData.push(itemData);
// });
// if (selectedCheckboxes.length <= 0) {
// showToast('warning', 'No selected item!', 'Item cart failed', 4000);
// return;
// } else {
// var DateNeeded = document.getElementById('dateNeeded').value;
// if (!DateNeeded) {
// showToast('warning', 'Please choose date needed!', 'P.R. submission failed', 4000);
// confirmUpdateListener = false;
// return;
// }
// if (RequestTypeId == 3) {
// updateDepartmentId();
// var ChargeTo = document.getElementById('departmentId').value;
// if (!ChargeTo) {
// showToast('warning', 'Please choose a department to be in charge of!', 'P.R. submission failed', 4000);
// confirmUpdateListener = false;
// return;
// }
// }
// }
// showConfirmation({
// title: 'Purchasing Requisition',
// message: 'Are you sure you want to proceed? This action cannot be undone.',
// type: 'warning',
// confirmText: 'Yes',
// cancelText: 'No'
// }).then((confirmed) => {
// if (confirmed) {
// $.ajax({
// url: '/ItemMgmt/PostPurchRequest',
// type: 'POST',
// data: { ItemCartIds: requestData, DateNeeded: DateNeeded, RequestTypeId: RequestTypeId, ChargeTo: ChargeTo, Remarks: Remarks },
// success: function (response) {
// if (response.success) {
// itemTable.ajax.reload();
// $('#addDateNeeded').modal('hide');
// showToast('success', 'P.R. Successfully Created!', 'Success', 4000);
// var totalSelectedLabel = $('#totalSelected');
// totalSelectedLabel.text('');
// } else {
// itemTable.ajax.reload();
// showToast('error', response.response, title + ' failed', 4000);
// }
// },
// beforeSend: function () {
// loader.show();
// },
// complete: function () {
// loader.hide();
// }
// });
// }
// });
//}
function AddToCart(isUpdated) { function AddToCart(isUpdated) {
var loader = $('#overlay, #loader'); var loader = $('#overlay, #loader');
var ItemNo = $('#itemNo').val(); var ItemNo = $('#itemNo').val();

View File

@ -122,3 +122,151 @@ function submitItem() {
}); });
} }
} }
const fileInput = document.getElementById('fileAttachment');
const fileInfoBadge = document.getElementById('fileInfoBadge');
const fileNameDisplay = document.getElementById('fileNameDisplay');
const fileSizeDisplay = document.getElementById('fileSizeDisplay');
const btnUploadContainer = document.getElementById('btnUploadContainer');
const btnUploadText = document.getElementById('btnUploadText');
let selectedFile = null;
let existingAttachment = false; // Set this to true if there's already an attachment
// File input change event
fileInput.addEventListener('change', function (e) {
const file = e.target.files[0];
if (file) {
// Validate file size (5MB max)
const maxSize = 5 * 1024 * 1024; // 5MB in bytes
if (file.size > maxSize) {
showToast('warning', 'File size exceeds 5MB. Please choose a smaller file.', 'File Upload', 4000);
e.target.value = '';
return;
}
// Validate file type
const allowedExtensions = ['csv', 'xlsx', 'xls', 'pdf'];
const fileExtension = file.name.split('.').pop().toLowerCase();
if (!allowedExtensions.includes(fileExtension)) {
showToast('warning', 'Invalid file type. Please upload CSV, Excel, or PDF files only.', 'File Upload', 4000);
e.target.value = '';
return;
}
// Store the selected file
selectedFile = file;
// Show file info and upload button
showFileInfo(file);
showUploadButton();
}
});
// Show file information
function showFileInfo(file) {
fileNameDisplay.textContent = truncateFileName(file.name, 30);
fileSizeDisplay.textContent = formatFileSize(file.size);
fileInfoBadge.classList.remove('d-none');
}
// Show upload button
function showUploadButton() {
// Change button text based on whether there's an existing attachment
if (existingAttachment) {
btnUploadText.innerHTML = '<i class="bi bi-arrow-repeat me-1"></i>Update Attachment';
} else {
btnUploadText.innerHTML = '<i class="bi bi-cloud-upload me-1"></i>Upload Attachment';
}
btnUploadContainer.classList.remove('d-none');
}
// Clear file attachment
function clearFileAttachment() {
fileInput.value = '';
selectedFile = null;
fileInfoBadge.classList.add('d-none');
btnUploadContainer.classList.add('d-none');
}
// Upload attachment function
function uploadAttachment() {
if (!selectedFile) {
showToast('warning', 'Please select a file first.', 'File Upload', 3000);
return;
}
const formData = new FormData();
formData.append('file', selectedFile);
formData.append('prId', $('#prId').val());
formData.append('oldFileName', $('#fileName').val());
// Show loading state
btnUploadText.innerHTML = '<span class="spinner-border spinner-border-sm me-1"></span>Uploading...';
document.querySelector('#btnUploadContainer button').disabled = true;
fetch('/PRMgmt/UploadAttachment', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
showToast('success', 'Attachment uploaded successfully!', 'File Upload', 3000);
existingAttachment = true;
$('#fileName').val(data.newFileName)
// Update the download button if needed
document.getElementById('btnDownloadAttachment').classList.remove('d-none');
clearFileAttachment();
} else {
showToast('error', data.message || 'Upload failed. Please try again.', 'File Upload', 4000);
}
})
.catch(error => {
console.error('Upload error:', error);
showToast('error', 'An error occurred during upload.', 'File Upload', 4000);
})
.finally(() => {
// Reset button state
document.querySelector('#btnUploadContainer button').disabled = false;
showUploadButton(); // Restore button text
});
}
// Truncate long file names
function truncateFileName(fileName, maxLength) {
if (fileName.length <= maxLength) return fileName;
const extension = fileName.split('.').pop();
const nameWithoutExt = fileName.substring(0, fileName.lastIndexOf('.'));
const truncatedName = nameWithoutExt.substring(0, maxLength - extension.length - 4) + '...';
return truncatedName + '.' + extension;
}
// Format file size
function formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i];
}
// Initialize: Check if there's an existing attachment on page load
function checkExistingAttachment() {
// Replace with your logic to check if attachment exists
// For example, check if there's a filename in your hidden input
const existingFileName = document.getElementById('fileName').value;
if (existingFileName) {
existingAttachment = true;
document.getElementById('btnDownloadAttachment').classList.remove('d-none');
} else {
existingAttachment = false;
}
}

View File

@ -55,7 +55,6 @@
modal.modal('show'); modal.modal('show');
} }
function getApproverName(prDetailsId) { function getApproverName(prDetailsId) {
PRDetailsId = prDetailsId; PRDetailsId = prDetailsId;
$.ajax({ $.ajax({
@ -90,106 +89,111 @@ function printPRItem() {
document.body.appendChild(iframe); document.body.appendChild(iframe);
const doc = iframe.contentWindow.document; const doc = iframe.contentWindow.document;
doc.open(); doc.open();
doc.write('<html><head><title>Print</title>'); doc.write('<!DOCTYPE html><html><head>');
doc.write('<meta charset="UTF-8">');
// Copy all stylesheets INCLUDING Bootstrap
const stylesheets = document.querySelectorAll('link[rel="stylesheet"]'); const stylesheets = document.querySelectorAll('link[rel="stylesheet"]');
stylesheets.forEach(sheet => { stylesheets.forEach(sheet => {
doc.write(sheet.outerHTML); doc.write(sheet.outerHTML);
}); });
// Copy all inline styles
const styles = document.querySelectorAll('style');
styles.forEach(style => {
doc.write(style.outerHTML);
});
// Add additional print styles
doc.write(` doc.write(`
<style> <style>
@media print { @media print {
.pr-info-section .row { /* Reduce overall print font */
display: flex !important;
flex-wrap: nowrap !important;
}
.pr-info-section .col-md-4 {
flex: 0 0 33.33% !important;
max-width: 33.33% !important;
}
table {
table-layout: fixed !important;
width: 125% !important;
}
/* Hide the 5th and 6th columns */
/* Hide the 5th and 6th columns */
table th:nth-child(5),
table th:nth-child(6),
table td:nth-child(5),
table td:nth-child(6) {
display: none !important;
}
table th:not(:nth-child(5)):not(:nth-child(6)),
table td:not(:nth-child(5)):not(:nth-child(6)) {
width: auto !important;
}
.page-break {
page-break-before: always;
}
}
body { body {
font-family: Roman, sans-serif; font-size: 10px !important;
font-size: 12px;
margin: 0;
padding: 10px;
}
.header {
font-family: Roman, sans-serif;
font-size: 14px;
font-weight: bold;
text-align: center;
margin-bottom: 5px;
padding: 5px 0;
}
/* Reduce vertical padding inside table rows */
table {
border-collapse: collapse;
font-size: 12px;
font-family: Roman, sans-serif;
}
table th,
table td {
padding: 2px 2px;
line-height: 1.2;
vertical-align: top;
border: .5px solid #808080 !important;
} }
/* Reduce PR Info Section font */
.pr-info-section { .pr-info-section {
font-size: 10px !important; font-size: 10px !important;
background: #f8f9fa !important; margin-bottom: 5px !important;
border: 1px solid #dee2e6 !important; page-break-inside: avoid !important;
padding: 8px !important;
margin-bottom: 10px !important;
}
.pr-info-section label,
.pr-info-section strong,
.pr-info-section .fw-bold {
font-size: 10px !important;
font-weight: bold !important;
} }
/* Make PR info labels slightly smaller */
.pr-info-section small,
.pr-info-section .text-muted { .pr-info-section .text-muted {
font-size: 9px !important; font-size: 9px !important;
color: #666 !important;
} }
/* Hide DataTables controls */ /* Reduce table body font */
.dataTables_length, table {
.dataTables_filter, font-size: 9px !important;
.dataTables_info, border-collapse: collapse;
.dataTables_paginate { }
display: none !important;
/* Keep header slightly larger for readability */
th {
font-size: 11px !important;
}
/* Reduce table padding */
th, td {
padding: 3px 4px !important;
border: 1px #ddd;
text-align: left;
}
/* Ensure Bootstrap grid works in print */
.row {
display: flex !important;
flex-wrap: wrap !important;
margin-right: -10px !important;
margin-left: -10px !important;
}
.col-md-3 {
flex: 0 0 25% !important;
max-width: 25% !important;
padding-right: 10px !important;
padding-left: 10px !important;
}
.card {
border: 1px #ddd !important;
}
.card-body {
padding: 5px !important;
}
th {
background-color: #444 !important;
color: white !important;
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
tbody tr:nth-child(even) {
background-color: #666 !important;
color: white !important;
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
tbody tr:nth-child(odd) {
background-color: #f9f9f9 !important;
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
@page {
margin: 0.5in;
}
} }
</style> </style>
`); `);
@ -197,13 +201,14 @@ function printPRItem() {
doc.write('</head><body>'); doc.write('</head><body>');
// Add the main header // Add the main header
doc.write('<div class="header">Purchase Requisition Details</div>'); doc.write('<div style="text-align: center; margin-bottom: 20px;"><h5>Purchase Requisition Details</h5></div>');
// Get the PR info section HTML // Get the PR info section HTML and preserve its exact structure
const prInfoSection = document.querySelector('.pr-info-section'); const prInfoSection = document.querySelector('.pr-info-section');
let prInfoHTML = ''; let prInfoHTML = '';
if (prInfoSection) { if (prInfoSection) {
prInfoHTML = prInfoSection.outerHTML; const clonedPrInfo = prInfoSection.cloneNode(true);
prInfoHTML = clonedPrInfo.outerHTML;
} }
// Clone the printable content // Clone the printable content
@ -220,19 +225,48 @@ function printPRItem() {
// Get the table // Get the table
const table = printContent.querySelector('table'); const table = printContent.querySelector('table');
if (table) { if (table) {
const tbody = table.querySelector('tbody');
const rows = Array.from(tbody.querySelectorAll('tr'));
const rowsPerPage = 50; // Reduced to accommodate PR info section
// Create table header HTML
const thead = table.querySelector('thead'); const thead = table.querySelector('thead');
const tbody = table.querySelector('tbody');
// Remove unwanted columns from header
if (thead) {
const headerRows = thead.querySelectorAll('tr');
headerRows.forEach(row => {
const cells = Array.from(row.querySelectorAll('th'));
// Count total cells
const totalCells = cells.length;
// Remove Action column (last)
if (cells[totalCells - 1]) cells[totalCells - 1].remove();
// Remove Status column (second to last)
if (cells[totalCells - 2]) cells[totalCells - 2].remove();
// Remove checkbox column (first)
if (cells[0]) cells[0].remove();
});
}
// Remove unwanted columns from body rows
const rows = Array.from(tbody.querySelectorAll('tr'));
rows.forEach(row => {
const cells = Array.from(row.querySelectorAll('td'));
const totalCells = cells.length;
// Remove Action column (last)
if (cells[totalCells - 1]) cells[totalCells - 1].remove();
// Remove Status column (second to last)
if (cells[totalCells - 2]) cells[totalCells - 2].remove();
// Remove checkbox column (first)
if (cells[0]) cells[0].remove();
});
const rowsPerPage = 50;
const tableHeaderHTML = thead ? thead.outerHTML : ''; const tableHeaderHTML = thead ? thead.outerHTML : '';
// Split into pages // Split into pages
for (let i = 0; i < rows.length; i += rowsPerPage) { for (let i = 0; i < rows.length; i += rowsPerPage) {
// Add page break for pages after the first // Add page break for pages after the first
if (i > 0) { if (i > 0) {
doc.write('<div class="page-break"></div>'); doc.write('<div style="page-break-before: always;"></div>');
} }
// Add PR info section to every page // Add PR info section to every page
@ -242,20 +276,8 @@ function printPRItem() {
const currentPageRows = rows.slice(i, i + rowsPerPage); const currentPageRows = rows.slice(i, i + rowsPerPage);
// Create table for current page // Create table for current page
doc.write('<table class="row-border" style="width: 100%;">'); doc.write('<table>');
doc.write('<colgroup>');
doc.write('<col style="width:8%" />');
doc.write('<col style="width:30%" />');
doc.write('<col style="width:34%" />');
doc.write('<col style="width:8%" />');
doc.write('<col style="width:8%" />');
doc.write('<col style="width:12%" />');
doc.write('</colgroup>');
// Add table header
doc.write(tableHeaderHTML); doc.write(tableHeaderHTML);
// Add table body with current page rows
doc.write('<tbody>'); doc.write('<tbody>');
currentPageRows.forEach(row => { currentPageRows.forEach(row => {
doc.write(row.outerHTML); doc.write(row.outerHTML);
@ -264,7 +286,7 @@ function printPRItem() {
doc.write('</table>'); doc.write('</table>');
} }
} else { } else {
// Fallback: just add PR info and content // Fallback
doc.write(prInfoHTML); doc.write(prInfoHTML);
doc.write(printContent.innerHTML); doc.write(printContent.innerHTML);
} }
@ -275,16 +297,17 @@ function printPRItem() {
// Wait for the iframe to load before printing // Wait for the iframe to load before printing
iframe.onload = function () { iframe.onload = function () {
// Print the iframe content // Small delay to ensure styles are loaded
setTimeout(function () {
iframe.contentWindow.print(); iframe.contentWindow.print();
// Remove the iframe after printing // Remove the iframe after printing
setTimeout(function () { setTimeout(function () {
document.body.removeChild(iframe); document.body.removeChild(iframe);
}, 1000); }, 1000);
}, 500);
}; };
} }
function viewItemRemovalRemarks(data) { function viewItemRemovalRemarks(data) {
PRDetailsId = data.prDetailsId; PRDetailsId = data.prDetailsId;
ItemName = data.itemName; ItemName = data.itemName;
@ -696,7 +719,8 @@ function viewPRDetails(data) {
document.getElementById('label-pr-approvedBy').innerHTML = data.approvedBy; document.getElementById('label-pr-approvedBy').innerHTML = data.approvedBy;
document.getElementById('label-pr-ProjectCode').innerHTML = data.projectCode; document.getElementById('label-pr-ProjectCode').innerHTML = data.projectCode;
console.log('data.projectCode', data.projectCode); $('#prId').val(data.prId);
console.log('data.prId', data.prId);
document.getElementById('label-pr-dateNeeded').innerHTML = formatDate(data.dateNeeded); document.getElementById('label-pr-dateNeeded').innerHTML = formatDate(data.dateNeeded);
@ -712,6 +736,27 @@ function viewPRDetails(data) {
emptyTable: "No record available" emptyTable: "No record available"
}, },
initComplete: function () { initComplete: function () {
var api = this.api();
var response = api.ajax.json();
// 1. Find the first row that actually has a fileName
const rowWithFile = response?.data?.find(
row => row.fileName && row.fileName.trim() !== ''
);
// 2. If a file exists, update the hidden inputs and show the button
if (rowWithFile) {
$('#fileName').val(rowWithFile.fileName);
$('#origFileName').val(rowWithFile.origFileName || ''); // Use empty string if null
$('#btnDownloadAttachment').removeClass('d-none');
} else {
// Clear values and hide button if no attachment is found
$('#fileName').val('');
$('#origFileName').val('');
$('#btnDownloadAttachment').addClass('d-none');
}
// Keep your selection initialization
initializeTableSelection({ initializeTableSelection({
tableName: tableName, tableName: tableName,
dataTable: prDataTable, dataTable: prDataTable,
@ -727,11 +772,43 @@ function viewPRDetails(data) {
}); });
}, },
columns: colItemList, columns: colItemList,
// responsive: true, pageLength: 5,
lengthMenu: [[5, 10, 25, 50, 100, -1], [5, 10, 25, 50, 100, "All"]],
rowCallback: rowStatusColorCallback, rowCallback: rowStatusColorCallback,
error: errorHandler error: errorHandler
}); });
} }
function downloadPRAttachment() {
let fileName = $('#fileName').val();
// Append parameters to URL for GET requests
const params = new URLSearchParams({ fileName: fileName });
const url = `/PRMgmt/GetPRAttachment?${params.toString()}`;
fetch(url, { method: 'GET' })
.then(response => {
if (!response.ok) {
// If backend returns 500 or 400, it won't be a blob
throw new Error("Failed to download file");
}
return response.blob();
})
.then(blob => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = fileName;
document.body.appendChild(a);
a.click();
a.remove();
window.URL.revokeObjectURL(url);
})
.catch(error => {
console.error("Error downloading attachment:", error);
alert("Error downloading attachment. Please check if the file exists.");
});
}
function clearTextModal() { function clearTextModal() {
if (UserRights == 'LLISCMAdmin' || UserRights == 'LTReceiver') { if (UserRights == 'LLISCMAdmin' || UserRights == 'LTReceiver') {
document.getElementById('docTypeId').value = ""; document.getElementById('docTypeId').value = "";

View File

@ -18,3 +18,26 @@
outline: none; outline: none;
box-shadow: 0 0 4px rgba(0, 0, 0, 0.3); box-shadow: 0 0 4px rgba(0, 0, 0, 0.3);
} }
.pr-modal-footer {
background: #f1f5f9;
border-top: 1px solid #e2e8f0;
}
/* Teal primary button */
.btn-teal-primary {
background-color: #0f766e;
border-color: #0f766e;
color: #fff;
}
.btn-teal-primary:hover {
background-color: #115e59;
border-color: #115e59;
}
/* Soft warning */
.btn-teal-warning {
background-color: #f59e0b;
border-color: #f59e0b;
color: #fff;
}

View File

@ -133,6 +133,14 @@ textarea {
.modal-footer .btn { .modal-footer .btn {
min-width: 80px; min-width: 80px;
} }
.pr-table-header {
background-color: #0f766e;
color: #fff;
}
.pr-table-header th {
border-color: #0f766e;
}
.form-row .col { .form-row .col {
padding-left: 0; padding-left: 0;
@ -170,3 +178,53 @@ textarea {
transform: scale(1.05); transform: scale(1.05);
box-shadow: 0 4px 10px rgba(0,0,0,0.2) box-shadow: 0 4px 10px rgba(0,0,0,0.2)
} }
.btn-outline-teal {
color: #0f766e;
border: 1px solid #0f766e;
background: transparent;
}
.btn-outline-teal:hover {
background-color: #0f766e;
color: #fff;
}
/* File upload styling */
.file-upload-wrapper {
position: relative;
}
#fileAttachment {
cursor: pointer;
}
#fileInfoBadge .badge {
font-size: 0.875rem;
font-weight: 400;
}
#fileInfoBadge .btn-close {
padding: 0;
opacity: 0.5;
}
#fileInfoBadge .btn-close:hover {
opacity: 1;
}
/* Smooth transitions */
#fileInfoBadge, #btnUploadContainer {
animation: fadeInRight 0.3s ease;
}
@keyframes fadeInRight {
from {
opacity: 0;
transform: translateX(-10px);
}
to {
opacity: 1;
transform: translateX(0);
}
}