push only for upload attachment and project code but not working the autocomplete yet
This commit is contained in:
parent
0612679648
commit
6e0551707e
@ -22,6 +22,8 @@ namespace CPRNIMS.Domain.Contracts.Items
|
||||
Task<List<ItemColor>> GetItemColor(ItemDto itemDto);
|
||||
Task<List<UnitOfMessure>> GetItemUOM(ItemDto itemDto);
|
||||
Task<List<NotifUserKey>> GetNotifUserKey(ItemDto itemDto);
|
||||
Task<List<ProjectCodes>> GetProjectCode();
|
||||
Task<List<ProjectCodes>> GetProjectCodeByTerm(string? fileName);
|
||||
Task<(long, long)> GetPRNo();
|
||||
Task<ResponseObject> PostPurchRequest(ItemDto itemDto);
|
||||
Task<ItemCodeDto> PostPutItem(ItemCodeDto itemDto);
|
||||
|
||||
@ -268,7 +268,7 @@ namespace CPRNIMS.Domain.Services.Items
|
||||
else
|
||||
{
|
||||
existing.OrigFileName = attach.OrigFileName;
|
||||
existing.FileName = Guid.NewGuid().ToString();
|
||||
existing.FileName = attach.FileName;
|
||||
}
|
||||
await _dbContext.SaveChangesAsync();
|
||||
}
|
||||
@ -316,5 +316,19 @@ namespace CPRNIMS.Domain.Services.Items
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,6 +21,7 @@ namespace CPRNIMS.Domain.UIContracts.Items
|
||||
Task<List<ItemVM>> GetItemUOM(User user, ItemVM viewModel);
|
||||
Task<List<ItemVM>> GetDepartment(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> PostPutItem(User user, ItemVM viewModel);
|
||||
Task<ItemVM> PutItemDetail(User user, ItemVM viewModel);
|
||||
|
||||
@ -40,6 +40,7 @@ namespace CPRNIMS.Domain.UIContracts.PR
|
||||
Task<PRVM> PRItemRemoval(User user, PRVM viewModel);
|
||||
Task<PRVM> ApprovedSelectedPRItem(User user, PRVM viewModel);
|
||||
Task<PRVM> PostPutProjectCode(User user, PRVM viewModel);
|
||||
Task<PRVM> PostPutAttachment(User user, PRVM prVM);
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,6 +129,11 @@ namespace CPRNIMS.Domain.UIServices.Items
|
||||
}
|
||||
#endregion
|
||||
#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,
|
||||
ItemVM viewModel)
|
||||
{
|
||||
|
||||
@ -264,6 +264,12 @@ namespace CPRNIMS.Domain.UIServices.PR
|
||||
return await SendPostApiRequest(user, viewModel,
|
||||
_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
|
||||
}
|
||||
}
|
||||
@ -12,6 +12,7 @@ namespace CPRNIMS.Infrastructure.Entities.Purchasing
|
||||
{
|
||||
[Key]
|
||||
public long PRDetailsId { get; set; }
|
||||
public long PRId { get; set; }
|
||||
public long ItemCodeId { get; set; }
|
||||
public short ItemClassId { get; set; }
|
||||
public string? Department { get; set; }
|
||||
@ -38,5 +39,7 @@ namespace CPRNIMS.Infrastructure.Entities.Purchasing
|
||||
public string? AttestedBy { get; set; }
|
||||
public string? ApprovedBy { get; set; }
|
||||
public string? ProjectCode { get; set; }
|
||||
public string? FileName { get; set; }
|
||||
public string? OrigFileName { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,9 +32,9 @@ namespace CPRNIMS.Infrastructure.Entities.Purchasing
|
||||
public string? UOMName { get; set; }
|
||||
public string? ItemColorName { get; set; }
|
||||
public long PRNo { get; set; }
|
||||
public long PRId { get; set; }
|
||||
public string? Remarks { get; set; }
|
||||
public DateTime DateNeeded { get; set; }
|
||||
//public bool Queue { get; set; }
|
||||
public string? AggreItemName { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
using CPRNIMS.Domain.Contracts.Items;
|
||||
using CPRNIMS.Domain.Contracts.SMTP;
|
||||
using CPRNIMS.Domain.Services;
|
||||
using CPRNIMS.Infrastructure.Dto.Items;
|
||||
using CPRNIMS.Infrastructure.Entities.Items;
|
||||
using CPRNIMS.Infrastructure.Helper;
|
||||
using CPRNIMS.Infrastructure.Models.Common;
|
||||
using CPRNIMS.Infrastructure.ViewModel.Common;
|
||||
using CPRNIMS.Infrastructure.ViewModel.Items;
|
||||
using CPRNIMS.WebApi.Controllers.Base;
|
||||
using Google.Apis.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
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")]
|
||||
public async Task<IActionResult> GetDepartment(ItemCodeDto itemDto)
|
||||
|
||||
@ -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.Infrastructure.Dto.Items;
|
||||
using CPRNIMS.Infrastructure.Dto.PO;
|
||||
using CPRNIMS.Infrastructure.Dto.PR;
|
||||
using CPRNIMS.Infrastructure.Entities.PO;
|
||||
@ -12,6 +14,7 @@ using CPRNIMS.WebApi.Controllers.Base;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.HttpResults;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
using System.Text;
|
||||
|
||||
|
||||
@ -23,17 +26,30 @@ namespace CPRNIMS.WebApi.Controllers.PR
|
||||
private readonly IPRequest _pRequest;
|
||||
private readonly SMTPHelper _smptHelper;
|
||||
private readonly IConfiguration _config;
|
||||
|
||||
private readonly IItem _item;
|
||||
public PRMgmtController(ErrorMessageService errorMessageService,
|
||||
IWebHostEnvironment webHostEnvironment, SMTPHelper sMTPHelper,
|
||||
IConfiguration configuration, IPRequest pRequest) :
|
||||
IConfiguration configuration, IPRequest pRequest, IItem item) :
|
||||
base(errorMessageService, webHostEnvironment, configuration)
|
||||
{
|
||||
_config = configuration;
|
||||
_smptHelper = sMTPHelper;
|
||||
_pRequest = pRequest;
|
||||
_item = item;
|
||||
}
|
||||
#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")]
|
||||
public async Task<IActionResult> ApprovedSelectedPRItem([FromBody] PRVM PRDto)
|
||||
{
|
||||
|
||||
@ -255,6 +255,13 @@ namespace CPRNIMS.WebApps.Controllers.Items
|
||||
#endregion
|
||||
|
||||
#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()
|
||||
{
|
||||
try
|
||||
|
||||
@ -21,24 +21,28 @@ namespace CPRNIMS.WebApps.Controllers.PR
|
||||
_pRequest = pRequest;
|
||||
}
|
||||
#region Get
|
||||
private async Task<IActionResult> GetProductFile(string fileName)
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetPRAttachment(string fileName)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Validate filename
|
||||
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 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 contentType = ContentTypeHelper.GetContentType(fileName);
|
||||
var contentType = "application/octet-stream"; // Or use a provider to get actual type
|
||||
|
||||
return File(fileStream, contentType, fileName, enableRangeProcessing: true);
|
||||
}
|
||||
@ -47,6 +51,7 @@ namespace CPRNIMS.WebApps.Controllers.PR
|
||||
return StatusCode(500, "Error retrieving file");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IActionResult> GetProjectCodes(PRVM viewModels)
|
||||
{
|
||||
response = await _pRequest.GetProjectCodes(GetUser(), viewModels);
|
||||
@ -150,6 +155,79 @@ namespace CPRNIMS.WebApps.Controllers.PR
|
||||
}
|
||||
#endregion
|
||||
#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)
|
||||
{
|
||||
var postPutItem = await _pRequest.PostPutProjectCode(GetUser(), viewModel);
|
||||
|
||||
@ -113,7 +113,7 @@
|
||||
rows="4"
|
||||
placeholder="Add any additional notes or comments here..."></textarea>
|
||||
<div class="form-text">
|
||||
<span id="charCount">0</span>/500 characters
|
||||
<span id="charCount">0</span>/100 characters
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -74,8 +74,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<link href="~/css/pr/TrackingV2.css" rel="stylesheet" />
|
||||
<link href="~/css/pr/buttonstyle.css" rel="stylesheet" />
|
||||
<link href="~/css/pr/TrackingV3.css" rel="stylesheet" />
|
||||
<link href="~/css/pr/ButtonStyleV2.css" rel="stylesheet" />
|
||||
@await Html.PartialAsync("PagesView/PR/_PRTracking")
|
||||
<script src="~/JsFunctions/PR/PRV6.js"></script>
|
||||
@await Html.PartialAsync("PagesView/PR/_PRScripts")
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
</div>
|
||||
<input hidden id="roleRights" value="@ViewBag.UserRoles" />
|
||||
<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" />
|
||||
<script src="~/JsFunctions/Canvass/canvassColumnV9.js"></script>
|
||||
<script src="~/JsFunctions/Canvass/canvassVarV3.js"></script>
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
<div id="loader" class="loader"></div>
|
||||
</div>
|
||||
<link href="~/css/common/rowhighlighter.css" rel="stylesheet" />
|
||||
|
||||
<script src="~/jsfunctions/pr/PRColumnV7.js"></script>
|
||||
<script src="~/jsfunctions/pr/PRViewV5.js"></script>
|
||||
<script src="~/jsfunctions/pr/PRPutPost.js"></script>
|
||||
|
||||
@ -337,60 +337,112 @@
|
||||
</div>
|
||||
<div id="printableRelatedItem">
|
||||
<div class="modal-body">
|
||||
<!-- PR Info Section -->
|
||||
<div class="p-2 mb-3 rounded border shadow-sm bg-light pr-info-section">
|
||||
<div class="row mb-2">
|
||||
<!-- PR No -->
|
||||
<div class="col-md-5">
|
||||
<small class="text-muted">P.R. No</small>
|
||||
<div id="label-pr-prNo" class="fw-bold text-dark"></div>
|
||||
</div>
|
||||
<!-- PR By -->
|
||||
<div class="col-md-5">
|
||||
<small class="text-muted">P.R. By</small>
|
||||
<div id="label-prby" class="fw-bold text-dark"></div>
|
||||
</div>
|
||||
<!-- Department -->
|
||||
<div class="col-md-5">
|
||||
<small class="text-muted">Department</small>
|
||||
<div id="label-pr-Department" class="fw-bold text-dark"></div>
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<small class="text-muted">Project Code</small>
|
||||
<div id="label-pr-ProjectCode" class="fw-bold text-dark"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- PR SUMMARY CARD -->
|
||||
<div class="card border-0 shadow-sm mb-4 pr-info-section">
|
||||
<div class="card-body">
|
||||
|
||||
<div class="row mb-2">
|
||||
<!-- Attested By -->
|
||||
<div class="col-md-4">
|
||||
<small class="text-muted">Attested By</small>
|
||||
<div id="label-pr-attestedBy" class="fw-bold text-dark"></div>
|
||||
</div>
|
||||
<!-- Approved By -->
|
||||
<div class="col-md-4">
|
||||
<small class="text-muted">Approved By</small>
|
||||
<div id="label-pr-approvedBy" class="fw-bold text-dark"></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 class="row g-3">
|
||||
|
||||
<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 class="col-md-3">
|
||||
<div class="text-muted small">Date Needed</div>
|
||||
<div id="label-pr-dateNeeded" class="fw-semibold text-danger"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-md-3">
|
||||
<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>
|
||||
|
||||
<!-- 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 />
|
||||
|
||||
<!-- SELECTION SUMMARY -->
|
||||
<div class="d-flex align-items-center mb-3 gap-2">
|
||||
<div>
|
||||
<span class="fw-semibold">Selected Items:</span>
|
||||
<span id="totalSelected" class="badge bg-danger ms-2">0</span>
|
||||
</div>
|
||||
<div>
|
||||
<button id="btnDownloadAttachment"
|
||||
class="btn btn-sm btn-outline-teal d-none"
|
||||
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>
|
||||
</div>
|
||||
|
||||
<table id="PRdataTable"
|
||||
class="row-border" style="width: 100%;">
|
||||
<colgroup>
|
||||
@ -422,15 +474,31 @@
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary" onclick="resetIsApproval()" data-bs-dismiss="modal">Back</button>
|
||||
<button type="button" id="btnPrintPR" onclick="printPRItem();" class="btn btn-warning">Print</button>
|
||||
<button id="btnSubmitItem" type="button"
|
||||
class="btn btn-success" onclick="approvedSelectedPRItem();">
|
||||
Submit
|
||||
<div class="modal-footer pr-modal-footer">
|
||||
<button type="button"
|
||||
class="btn btn-outline-secondary"
|
||||
onclick="resetIsApproval()"
|
||||
data-bs-dismiss="modal">
|
||||
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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<input hidden id="roleRights" value="@ViewBag.UserRoles" />
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -247,6 +247,17 @@ document.getElementById('fileAttachment').addEventListener('change', function (e
|
||||
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() {
|
||||
document.getElementById('dateNeeded').value = '';
|
||||
document.getElementById('projectCode').value = '';
|
||||
@ -256,14 +267,10 @@ function clearFormData() {
|
||||
clearFileAttachment();
|
||||
document.getElementById('charCount').textContent = '0';
|
||||
}
|
||||
function clearFileAttachment() {
|
||||
document.getElementById('fileAttachment').value = '';
|
||||
document.getElementById('filePreview').classList.add('d-none');
|
||||
}
|
||||
document.getElementById('requestorRemarks').addEventListener('input', function (e) {
|
||||
const charCount = document.getElementById('charCount');
|
||||
const currentLength = e.target.value.length;
|
||||
const maxLength = 500;
|
||||
const maxLength = 100;
|
||||
|
||||
charCount.textContent = currentLength;
|
||||
|
||||
@ -279,10 +286,4 @@ document.getElementById('requestorRemarks').addEventListener('input', function (
|
||||
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];
|
||||
}
|
||||
|
||||
|
||||
@ -1,32 +1,50 @@
|
||||
async function setupProjectCodeAutocomplete() {
|
||||
const input = document.getElementById('projectCode');
|
||||
let debounceTimer;
|
||||
function populateGetProjectCode() {
|
||||
$("#projectCode").autocomplete({
|
||||
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) {
|
||||
clearTimeout(debounceTimer);
|
||||
const searchTerm = e.target.value;
|
||||
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() : '',
|
||||
value3: item.value3 !== undefined && item.value3 !== null ? item.value3.toString() : '',
|
||||
value4: item.value4 !== undefined && item.value4 !== null ? item.value4.toString() : ''
|
||||
}));
|
||||
response(formattedData);
|
||||
} else {
|
||||
console.error('Invalid data format received:', result);
|
||||
response([]);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
minLength: 2,
|
||||
select: function (event, ui) {
|
||||
$('#projectCodeList').val(ui.item.label);
|
||||
$('#supplierId').val(ui.item.value);
|
||||
|
||||
if (searchTerm.length < 2) return;
|
||||
|
||||
debounceTimer = setTimeout(async () => {
|
||||
try {
|
||||
// Replace with your actual API endpoint
|
||||
const response = await fetch(`/api/projects/search?term=${encodeURIComponent(searchTerm)}`);
|
||||
const projects = await response.json();
|
||||
|
||||
const datalist = document.getElementById('projectCodeList');
|
||||
datalist.innerHTML = '';
|
||||
|
||||
projects.forEach(project => {
|
||||
const option = document.createElement('option');
|
||||
option.value = project.code;
|
||||
option.textContent = `${project.code} - ${project.name}`;
|
||||
datalist.appendChild(option);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error fetching project codes:', error);
|
||||
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');
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
});
|
||||
}
|
||||
function populateItemCategSelect() {
|
||||
@ -420,6 +438,7 @@ function inputItemPopulation() {
|
||||
}
|
||||
function showModal() {
|
||||
popltDeprtmntChargeTo();
|
||||
populateGetProjectCode();
|
||||
$('#addDateNeeded').modal('show');
|
||||
$('#addDateNeeded').css('z-index', 1060);
|
||||
}
|
||||
|
||||
@ -19,8 +19,6 @@
|
||||
};
|
||||
});
|
||||
|
||||
console.log(requestData);
|
||||
|
||||
var DateNeeded = document.getElementById('dateNeeded').value;
|
||||
|
||||
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) {
|
||||
var loader = $('#overlay, #loader');
|
||||
var ItemNo = $('#itemNo').val();
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -55,7 +55,6 @@
|
||||
|
||||
modal.modal('show');
|
||||
}
|
||||
|
||||
function getApproverName(prDetailsId) {
|
||||
PRDetailsId = prDetailsId;
|
||||
$.ajax({
|
||||
@ -90,106 +89,111 @@ function printPRItem() {
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
const doc = iframe.contentWindow.document;
|
||||
|
||||
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"]');
|
||||
stylesheets.forEach(sheet => {
|
||||
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(`
|
||||
<style>
|
||||
@media print {
|
||||
.pr-info-section .row {
|
||||
display: flex !important;
|
||||
flex-wrap: nowrap !important;
|
||||
}
|
||||
.pr-info-section .col-md-4 {
|
||||
flex: 0 0 33.33% !important;
|
||||
max-width: 33.33% !important;
|
||||
/* Reduce overall print font */
|
||||
body {
|
||||
font-size: 10px !important;
|
||||
}
|
||||
|
||||
/* Reduce PR Info Section font */
|
||||
.pr-info-section {
|
||||
font-size: 10px !important;
|
||||
margin-bottom: 5px !important;
|
||||
page-break-inside: avoid !important;
|
||||
}
|
||||
|
||||
/* Make PR info labels slightly smaller */
|
||||
.pr-info-section small,
|
||||
.pr-info-section .text-muted {
|
||||
font-size: 9px !important;
|
||||
}
|
||||
|
||||
/* Reduce table body font */
|
||||
table {
|
||||
table-layout: fixed !important;
|
||||
width: 125% !important;
|
||||
font-size: 9px !important;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
/* Keep header slightly larger for readability */
|
||||
th {
|
||||
font-size: 11px !important;
|
||||
}
|
||||
|
||||
.page-break {
|
||||
page-break-before: always;
|
||||
/* Reduce table padding */
|
||||
th, td {
|
||||
padding: 3px 4px !important;
|
||||
border: 1px #ddd;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: Roman, sans-serif;
|
||||
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;
|
||||
}
|
||||
/* Ensure Bootstrap grid works in print */
|
||||
.row {
|
||||
display: flex !important;
|
||||
flex-wrap: wrap !important;
|
||||
margin-right: -10px !important;
|
||||
margin-left: -10px !important;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
.col-md-3 {
|
||||
flex: 0 0 25% !important;
|
||||
max-width: 25% !important;
|
||||
padding-right: 10px !important;
|
||||
padding-left: 10px !important;
|
||||
}
|
||||
|
||||
.pr-info-section {
|
||||
font-size: 10px !important;
|
||||
background: #f8f9fa !important;
|
||||
border: 1px solid #dee2e6 !important;
|
||||
padding: 8px !important;
|
||||
margin-bottom: 10px !important;
|
||||
}
|
||||
.card {
|
||||
border: 1px #ddd !important;
|
||||
}
|
||||
|
||||
.pr-info-section label,
|
||||
.pr-info-section strong,
|
||||
.pr-info-section .fw-bold {
|
||||
font-size: 10px !important;
|
||||
font-weight: bold !important;
|
||||
}
|
||||
.card-body {
|
||||
padding: 5px !important;
|
||||
}
|
||||
|
||||
.pr-info-section .text-muted {
|
||||
font-size: 9px !important;
|
||||
color: #666 !important;
|
||||
}
|
||||
|
||||
/* Hide DataTables controls */
|
||||
.dataTables_length,
|
||||
.dataTables_filter,
|
||||
.dataTables_info,
|
||||
.dataTables_paginate {
|
||||
display: none !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>
|
||||
`);
|
||||
@ -197,13 +201,14 @@ function printPRItem() {
|
||||
doc.write('</head><body>');
|
||||
|
||||
// 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');
|
||||
let prInfoHTML = '';
|
||||
if (prInfoSection) {
|
||||
prInfoHTML = prInfoSection.outerHTML;
|
||||
const clonedPrInfo = prInfoSection.cloneNode(true);
|
||||
prInfoHTML = clonedPrInfo.outerHTML;
|
||||
}
|
||||
|
||||
// Clone the printable content
|
||||
@ -220,19 +225,48 @@ function printPRItem() {
|
||||
// Get the table
|
||||
const table = printContent.querySelector('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 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 : '';
|
||||
|
||||
// Split into pages
|
||||
for (let i = 0; i < rows.length; i += rowsPerPage) {
|
||||
// Add page break for pages after the first
|
||||
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
|
||||
@ -242,20 +276,8 @@ function printPRItem() {
|
||||
const currentPageRows = rows.slice(i, i + rowsPerPage);
|
||||
|
||||
// Create table for current page
|
||||
doc.write('<table class="row-border" style="width: 100%;">');
|
||||
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('<table>');
|
||||
doc.write(tableHeaderHTML);
|
||||
|
||||
// Add table body with current page rows
|
||||
doc.write('<tbody>');
|
||||
currentPageRows.forEach(row => {
|
||||
doc.write(row.outerHTML);
|
||||
@ -264,7 +286,7 @@ function printPRItem() {
|
||||
doc.write('</table>');
|
||||
}
|
||||
} else {
|
||||
// Fallback: just add PR info and content
|
||||
// Fallback
|
||||
doc.write(prInfoHTML);
|
||||
doc.write(printContent.innerHTML);
|
||||
}
|
||||
@ -275,16 +297,17 @@ function printPRItem() {
|
||||
|
||||
// Wait for the iframe to load before printing
|
||||
iframe.onload = function () {
|
||||
// Print the iframe content
|
||||
iframe.contentWindow.print();
|
||||
|
||||
// Remove the iframe after printing
|
||||
// Small delay to ensure styles are loaded
|
||||
setTimeout(function () {
|
||||
document.body.removeChild(iframe);
|
||||
}, 1000);
|
||||
iframe.contentWindow.print();
|
||||
|
||||
// Remove the iframe after printing
|
||||
setTimeout(function () {
|
||||
document.body.removeChild(iframe);
|
||||
}, 1000);
|
||||
}, 500);
|
||||
};
|
||||
}
|
||||
|
||||
function viewItemRemovalRemarks(data) {
|
||||
PRDetailsId = data.prDetailsId;
|
||||
ItemName = data.itemName;
|
||||
@ -696,7 +719,8 @@ function viewPRDetails(data) {
|
||||
document.getElementById('label-pr-approvedBy').innerHTML = data.approvedBy;
|
||||
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);
|
||||
|
||||
@ -712,6 +736,27 @@ function viewPRDetails(data) {
|
||||
emptyTable: "No record available"
|
||||
},
|
||||
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({
|
||||
tableName: tableName,
|
||||
dataTable: prDataTable,
|
||||
@ -727,11 +772,43 @@ function viewPRDetails(data) {
|
||||
});
|
||||
},
|
||||
columns: colItemList,
|
||||
// responsive: true,
|
||||
pageLength: 5,
|
||||
lengthMenu: [[5, 10, 25, 50, 100, -1], [5, 10, 25, 50, 100, "All"]],
|
||||
rowCallback: rowStatusColorCallback,
|
||||
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() {
|
||||
if (UserRights == 'LLISCMAdmin' || UserRights == 'LTReceiver') {
|
||||
document.getElementById('docTypeId').value = "";
|
||||
|
||||
@ -18,3 +18,26 @@
|
||||
outline: none;
|
||||
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;
|
||||
}
|
||||
@ -133,6 +133,14 @@ textarea {
|
||||
.modal-footer .btn {
|
||||
min-width: 80px;
|
||||
}
|
||||
.pr-table-header {
|
||||
background-color: #0f766e;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.pr-table-header th {
|
||||
border-color: #0f766e;
|
||||
}
|
||||
|
||||
.form-row .col {
|
||||
padding-left: 0;
|
||||
@ -170,3 +178,53 @@ textarea {
|
||||
transform: scale(1.05);
|
||||
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);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user