update & fix request
This commit is contained in:
parent
9214a081d3
commit
0f2b065c66
@ -8,13 +8,13 @@ namespace PSTW_CentralSystem.Areas.Inventory.Models
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
public int ItemId { get; set; }
|
||||
public int? ItemId { get; set; }
|
||||
public int? ToStation { get; set; }
|
||||
public int? ToStore { get; set; }
|
||||
public int? ToUser { get; set; }
|
||||
[Comment("Repair, Calibration, Faulty, Ready To Deploy, On Delivery")]
|
||||
public string? ToOther { get; set; }
|
||||
public DateTime sendDate { get; set; }
|
||||
public DateTime? sendDate { get; set; }
|
||||
[Comment("Register, StockIn, Stock Out")]
|
||||
public string? Action { get; set; }
|
||||
public int? Quantity { get; set; }
|
||||
@ -26,7 +26,7 @@ namespace PSTW_CentralSystem.Areas.Inventory.Models
|
||||
public int? LastStation{ get; set; }
|
||||
[Comment("Repair, Calibration, Faulty, Ready To Deploy, On Delivery")]
|
||||
public string? LatestStatus { get; set; }
|
||||
public DateTime receiveDate { get; set; }
|
||||
public DateTime? receiveDate { get; set; }
|
||||
public bool MovementComplete { get; set; } = false;
|
||||
//public virtual ItemModel? Item { get; set; }
|
||||
//[ForeignKey("ToStore")]
|
||||
|
||||
@ -23,9 +23,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row card">
|
||||
<div class="card-header">
|
||||
<h2>Pending Request</h2>
|
||||
<button id="addRequestBtn" class="btn btn-success col-md-3 col-lg-3 m-1 col-12"><i class="fa fa-plus"></i> Add Request</button>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@ -36,6 +36,21 @@
|
||||
</div> *@
|
||||
<table class="table table-bordered table-hover table-striped no-wrap" id="requestDatatable" style=" width:100%;border-style: solid; border-width: 1px"></table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="row card">
|
||||
<div class="card-header">
|
||||
<h2>Complete Request</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@* <div v-if="loading">
|
||||
<div class="spinner-border text-info" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
</div> *@
|
||||
<table class="table table-bordered table-hover table-striped no-wrap" id="settledrequestDatatable" style=" width:100%;border-style: solid; border-width: 1px"></table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="modal fade" id="requestModal" tabindex="-1" role="dialog" aria-labelledby="addRequestModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered modal-xl" role="document">
|
||||
@ -118,7 +133,7 @@
|
||||
<div class="form-group row d-flex align-items-center">
|
||||
<label class="col-sm-4 col-form-label">Document/Picture:</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="file" class="form-control-file" v-on:change="handleFileUpload" />
|
||||
<input type="file" id="document" name="document" class="form-control-file" v-on:change="handleFileUpload" accept="image/png, image/jpeg, application/pdf" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -210,19 +225,23 @@
|
||||
methods: {
|
||||
handleFileUpload(event) {
|
||||
const file = event.target.files[0];
|
||||
|
||||
if (file) {
|
||||
this.document = file.name;
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
this.document = e.target.result.split(',')[1]; // Get Base64 string (remove metadata)
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
} else {
|
||||
this.document = null; // Ensure null if no file selected
|
||||
this.document = null;
|
||||
}
|
||||
},
|
||||
|
||||
async addRequest() {
|
||||
try {
|
||||
const requiredFields = ['stationId', 'productId', 'quantity', 'productCategory'];
|
||||
|
||||
this.userId = this.currentUser.id;
|
||||
this.status = "Request";
|
||||
this.status = "Requested";
|
||||
this.requestDate = new Date().toISOString();
|
||||
|
||||
// Loop through required fields and check if any are null or empty
|
||||
@ -244,7 +263,7 @@
|
||||
status: this.status,
|
||||
requestDate: this.requestDate,
|
||||
approvalDate: this.approvalDate ? this.approvalDate : null,
|
||||
document: this.document // ✅ Store only the file name/path
|
||||
document: this.document
|
||||
};
|
||||
|
||||
$('.modal').modal('hide');
|
||||
@ -255,7 +274,7 @@
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(requestData) // ✅ Send JSON (No file upload)
|
||||
body: JSON.stringify(requestData)
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
@ -278,7 +297,95 @@
|
||||
initiateTable() {
|
||||
self = this;
|
||||
this.requestDatatable = $('#requestDatatable').DataTable({
|
||||
"data": this.request,
|
||||
"data": this.request.filter(request => request.status == "Requested"),
|
||||
"columns": [
|
||||
{
|
||||
"title": "Request ID",
|
||||
"data": "requestId",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
// Assign a unique ID to the <td> element
|
||||
$(td).attr('id', `qr${cellData}`);
|
||||
},
|
||||
},
|
||||
{
|
||||
"title": "Product Id",
|
||||
"data": "productId",
|
||||
},
|
||||
{
|
||||
"title": "Product Category",
|
||||
"data": "productCategory",
|
||||
},
|
||||
{
|
||||
"title": "Request Quantity",
|
||||
"data": "requestQuantity",
|
||||
},
|
||||
|
||||
{
|
||||
"title": "Document / Picture",
|
||||
"data": "document",
|
||||
"render": function (data, type, full, meta) {
|
||||
if (!data) {
|
||||
return "No Document";
|
||||
}
|
||||
|
||||
// Check if the document is an image based on file extension
|
||||
var isImage = /\.(jpeg|jpg|png|gif)$/i.test(data);
|
||||
var isPdf = /\.pdf$/i.test(data);
|
||||
|
||||
if (isImage) {
|
||||
return `<a href="${data}" target="_blank" data-lightbox="image-1">
|
||||
<img src="${data}" alt="Image" class="img-thumbnail" style="width: 100px; height: 100px;" />
|
||||
</a>`;
|
||||
}
|
||||
else if (isPdf) {
|
||||
return `<a href="${data}" target="_blank">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/8/87/PDF_file_icon.svg"
|
||||
alt="PDF Document" class="img-thumbnail"
|
||||
style="width: 50px; height: 50px;" />
|
||||
<br>View PDF
|
||||
</a>`;
|
||||
} else {
|
||||
return `<a href="${data}" target="_blank">Download File</a>`;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"title": "Remark",
|
||||
"data": "remarkUser",
|
||||
},
|
||||
{
|
||||
"title": "Request Date",
|
||||
"data": "requestDate",
|
||||
},
|
||||
{
|
||||
"title": "Status",
|
||||
"data": "status",
|
||||
},
|
||||
{
|
||||
"title": "Delete",
|
||||
"data": "requestId",
|
||||
"render": function (data) {
|
||||
var deleteButton = `<button type="button" class="btn btn-danger delete-btn" data-id="${data}">Delete</button>`;
|
||||
return deleteButton;
|
||||
},
|
||||
"className": "align-middle",
|
||||
// "title": "Delete",
|
||||
// "data": "requestId",
|
||||
// "render": function (data, type, row) {
|
||||
// if (row.status === "Approved" || row.status === "Rejected") {
|
||||
// return `<button type="button" class="btn btn-danger delete-btn" data-id="${data}" disabled>Delete</button>`;
|
||||
// } else {
|
||||
// return `<button type="button" class="btn btn-danger delete-btn" data-id="${data}">Delete</button>`;
|
||||
// }
|
||||
// },
|
||||
// "className": "align-middle",
|
||||
}
|
||||
|
||||
],
|
||||
responsive: true,
|
||||
});
|
||||
this.requestDatatable = $('#settledrequestDatatable').DataTable({
|
||||
"data": this.request.filter(request => request.status !== "Requested"),
|
||||
"columns": [
|
||||
{
|
||||
"title": "Request ID",
|
||||
@ -303,15 +410,38 @@
|
||||
{
|
||||
"title": "Document / Picture",
|
||||
"data": "document",
|
||||
},
|
||||
"render": function (data, type, full, meta) {
|
||||
if (!data) {
|
||||
return "No Document";
|
||||
}
|
||||
|
||||
// Check if the document is an image based on file extension
|
||||
var isImage = /\.(jpeg|jpg|png|gif)$/i.test(data);
|
||||
var isPdf = /\.pdf$/i.test(data);
|
||||
|
||||
if (isImage) {
|
||||
return `<a href="${data}" target="_blank" data-lightbox="image-1">
|
||||
<img src="${data}" alt="Image" class="img-thumbnail" style="width: 100px; height: 100px;" />
|
||||
</a>`;
|
||||
} else if (isPdf) {
|
||||
return `<a href="${data}" target="_blank">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/8/87/PDF_file_icon.svg"
|
||||
alt="PDF Document" class="img-thumbnail"
|
||||
style="width: 50px; height: 50px;" />
|
||||
<br>View PDF
|
||||
</a>`;
|
||||
} else {
|
||||
return `<a href="${data}" target="_blank">Download File</a>`;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"title": "Remark",
|
||||
"data": "remark",
|
||||
"data": "remarkUser",
|
||||
},
|
||||
{
|
||||
"title": "Status",
|
||||
"data": "status",
|
||||
"title": "Remark (Master)",
|
||||
"data": "remarkMasterInv",
|
||||
},
|
||||
{
|
||||
"title": "Request Date",
|
||||
@ -322,21 +452,13 @@
|
||||
"data": "approvalDate",
|
||||
},
|
||||
{
|
||||
"title": "Delete",
|
||||
"data": "requestId",
|
||||
"render": function (data, type, row) {
|
||||
if (row.status === "Approved" || row.status === "Rejected") {
|
||||
return `<button type="button" class="btn btn-danger delete-btn" data-id="${data}" disabled>Delete</button>`;
|
||||
} else {
|
||||
return `<button type="button" class="btn btn-danger delete-btn" data-id="${data}">Delete</button>`;
|
||||
}
|
||||
},
|
||||
"className": "align-middle",
|
||||
"title": "Status",
|
||||
"data": "status",
|
||||
}
|
||||
|
||||
],
|
||||
responsive: true,
|
||||
})
|
||||
});
|
||||
|
||||
$('#requestDatatable tbody').off('click', '.delete-btn');
|
||||
|
||||
@ -368,6 +490,9 @@
|
||||
if ($.fn.dataTable.isDataTable('#requestDatatable')) {
|
||||
$('#requestDatatable').DataTable().clear().destroy();
|
||||
}
|
||||
if ($.fn.dataTable.isDataTable('#settledrequestDatatable')) {
|
||||
$('#settledrequestDatatable').DataTable().clear().destroy();
|
||||
}
|
||||
|
||||
this.initiateTable();
|
||||
}
|
||||
|
||||
@ -38,6 +38,17 @@
|
||||
<div v-if="displayStatus != null" style="display: flex; justify-content: center; align-items: center;">
|
||||
|
||||
<div class="col-lg-7 col-11 border rounded p-3 shadow-sm">
|
||||
<div class="row m-3 d-flex align-items-center justify-content-center">
|
||||
<div class="col-lg-7 col-11 border rounded p-3 shadow-sm">
|
||||
<div class="col-12 text-center">
|
||||
<img :src="thisItem.imageProduct" alt="Product Image" class="img-fluid rounded" data-toggle="modal" data-target="#imageModal" style="max-height: 300px;" />
|
||||
</div>
|
||||
<div class="col-12 text-center mt-3">
|
||||
<p class="h4 fw-bold text-primary">{{ thisItem.uniqueID }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Item Name -->
|
||||
<div class="col-12 mb-3">
|
||||
<p class="h5 fw-bold">
|
||||
@ -114,7 +125,7 @@
|
||||
|
||||
</div>
|
||||
|
||||
<form v-on:submit="updateItemMovement" v-if="displayStatus === 'arrived'" data-aos="fade-right">
|
||||
<form v-on:submit.prevent="updateItemMovement" v-if="displayStatus === 'arrived'" data-aos="fade-right">
|
||||
<div class=" register" data-aos="fade-right">
|
||||
<div class="row" data-aos="fade-right">
|
||||
|
||||
@ -156,6 +167,51 @@
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form v-on:submit.prevent="returnItemMovement" v-if="displayStatus === 'return'" data-aos="fade-right">
|
||||
<div class=" register" data-aos="fade-right">
|
||||
<div class="row" data-aos="fade-right">
|
||||
|
||||
@*Right Side*@
|
||||
<div class="col-md-12">
|
||||
<div class="tab-content" id="myTabContent">
|
||||
<div class="tab-pane fade show active" id="home" role="tabpanel" aria-labelledby="home-tab">
|
||||
<br><br>
|
||||
<h3 style="text-align: center; margin: 20px 0; padding: 20px;" class="register-heading" style="margin: auto">Station Deploy :</h3>
|
||||
<div class="row register-form">
|
||||
<div class="col-md-3"></div>
|
||||
<div class="col-md-6">
|
||||
|
||||
<!-- Remark Input -->
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label">Remark : </label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" class="form-control col-md-10" v-model="remark" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Consignment Note input -->
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label">Consignment Note : </label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" class="form-control col-md-10" v-model="consignmentNote" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Submit and Reset Buttons *@
|
||||
<div class="form-group row">
|
||||
<div class="col-sm-8 offset-sm-3">
|
||||
<button type="button" v-on:click="resetForm" class="btn btn-secondary m-1">Return</button>
|
||||
<button type="submit" class="btn btn-primary m-1">Receive</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@ -199,13 +255,14 @@
|
||||
}
|
||||
|
||||
try {
|
||||
// Disable button
|
||||
|
||||
const formData = {
|
||||
Id: this.thisItem.movementId,
|
||||
LastStation: this.selectedStation,
|
||||
receiveDate: new Date().toISOString(),
|
||||
LatestStatus: "Delivered",
|
||||
MovementComplete: true,
|
||||
ReceiveDate: new Date().toISOString(),
|
||||
MovementComplete: true
|
||||
};
|
||||
|
||||
const response = await fetch('/InvMainAPI/UpdateItemMovementUser', {
|
||||
@ -218,8 +275,46 @@
|
||||
|
||||
if (response.ok) {
|
||||
alert('Success! Item movement has been successfully submitted.');
|
||||
// this.displayStatus = "return";
|
||||
// this.resetForm();
|
||||
this.thisItem = await response.json();
|
||||
this.displayStatus = "return";
|
||||
this.resetForm();
|
||||
} else {
|
||||
throw new Error('Failed to submit form.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
alert('Inventory PSTW Error: An error occurred.');
|
||||
}
|
||||
},
|
||||
async returnItemMovement() {
|
||||
if (!confirm("Are you sure you already receive this item?")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// Disable button
|
||||
|
||||
const formData = {
|
||||
Id: this.thisItem.movementId,
|
||||
LastStation: this.selectedStation,
|
||||
LatestStatus: "Delivered",
|
||||
ReceiveDate: new Date().toISOString(),
|
||||
MovementComplete: true
|
||||
};
|
||||
|
||||
const response = await fetch('/InvMainAPI/UpdateItemMovementUser', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(formData)
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
alert('Success! Item movement has been successfully submitted.');
|
||||
this.thisItem = await response.json();
|
||||
this.displayStatus = "return";
|
||||
this.resetForm();
|
||||
} else {
|
||||
throw new Error('Failed to submit form.');
|
||||
}
|
||||
|
||||
@ -745,6 +745,31 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
||||
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrEmpty(request.Document))
|
||||
{
|
||||
var bytes = Convert.FromBase64String(request.Document);
|
||||
string filePath = "";
|
||||
|
||||
string uniqueName = $"{request.ProductId}_{Guid.NewGuid()}";
|
||||
|
||||
if (IsImage(bytes))
|
||||
{
|
||||
filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/media/inventory/request", uniqueName + request.UserId + "_Request.jpg");
|
||||
request.Document = "/media/inventory/request/" + uniqueName + request.UserId + "_Request.jpg";
|
||||
}
|
||||
else if (IsPdf(bytes))
|
||||
{
|
||||
filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/media/inventory/request", uniqueName + request.UserId + "_Request.pdf");
|
||||
request.Document = "/media/inventory/request/" + uniqueName + request.UserId + "_Request.pdf";
|
||||
}
|
||||
else
|
||||
{
|
||||
return BadRequest("Unsupported file format.");
|
||||
}
|
||||
|
||||
await System.IO.File.WriteAllBytesAsync(filePath, bytes);
|
||||
}
|
||||
|
||||
_centralDbContext.Requests.Add(request);
|
||||
await _centralDbContext.SaveChangesAsync();
|
||||
|
||||
@ -759,6 +784,28 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
||||
return BadRequest(ex.Message);
|
||||
}
|
||||
}
|
||||
private bool IsImage(byte[] bytes)
|
||||
{
|
||||
// JPEG file signature: FF D8 FF
|
||||
if (bytes.Length > 2 && bytes[0] == 0xFF && bytes[1] == 0xD8 && bytes[2] == 0xFF)
|
||||
return true;
|
||||
|
||||
// PNG file signature: 89 50 4E 47 0D 0A 1A 0A
|
||||
if (bytes.Length > 7 && bytes[0] == 0x89 && bytes[1] == 0x50 && bytes[2] == 0x4E && bytes[3] == 0x47)
|
||||
return true;
|
||||
|
||||
// GIF file signature: GIF87a or GIF89a
|
||||
if (bytes.Length > 5 && bytes[0] == 0x47 && bytes[1] == 0x49 && bytes[2] == 0x46)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool IsPdf(byte[] bytes)
|
||||
{
|
||||
// PDF file signature: 25 50 44 46 (ASCII for "%PDF")
|
||||
return bytes.Length > 3 && bytes[0] == 0x25 && bytes[1] == 0x50 && bytes[2] == 0x44 && bytes[3] == 0x46;
|
||||
}
|
||||
|
||||
[HttpGet("ItemRequestListEachUser/{userId}")]
|
||||
public async Task<IActionResult> ItemRequestListEachUser(int userId)
|
||||
@ -999,10 +1046,6 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
||||
[HttpPost("UpdateItemMovementUser")]
|
||||
public async Task<IActionResult> UpdateItemMovementUser([FromBody] ItemMovementModel receiveMovement)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
|
Before Width: | Height: | Size: 130 KiB After Width: | Height: | Size: 130 KiB |
BIN
wwwroot/Media/Inventory/request/2 Request.jpg
Normal file
BIN
wwwroot/Media/Inventory/request/2 Request.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 84 KiB |
Loading…
Reference in New Issue
Block a user