Update QR Master

This commit is contained in:
Naz 2026-01-23 15:27:30 +08:00
parent 1485b8a160
commit fce9d7b6c7
5 changed files with 253 additions and 37 deletions

View File

@ -147,6 +147,24 @@
</div>
</div>
@* Inv Master Receive Item *@
<div v-if="itemlateststatus == 'On Delivery' && this.thisItem.lastUser == this.currentUser.id">
<h2 class="register-heading">Receive Item</h2>
<div class="col-sm-3"></div>
<div class="col-sm-6 offset-sm-3">
<form v-on:submit.prevent="receiveItemMovement" data-aos="fade-right">
<div class="row register-form">
<div style="display: flex; justify-content: center; margin-top: 20px;">
<button type="submit" class="btn btn-primary" style="width: 200px; padding: 10px; font-size: 16px;">
Receive Item
</button>
</div>
</div>
</form>
</div>
</div>
<div v-if="itemlateststatus == 'On Delivery' && this.thisItem.toUser == this.currentUser.id">
<h3 class="register-heading">Cancel Item Movement</h3>
<div class="col-sm-3"></div>
@ -208,6 +226,19 @@
</div>
</div>
@* Inv Master Return Item & Deploy to Station*@
<div v-if="itemlateststatus == 'Delivered' && thisItem.lastUser == currentUser.id">
<h2 class="text-center register-heading">Item Actions</h2>
<div class="col-sm-12 d-flex justify-content-center mt-3">
<button type="button" v-on:click="ReturnMessage" class="btn btn-warning m-2" style="width: 200px; padding: 10px;">
<i class="fas fa-undo me-2"></i>Return Item
</button>
<button type="button" v-on:click="StationMessage" class="btn btn-primary m-2" style="width: 200px; padding: 10px;">
<i class="fas fa-broadcast-tower me-2"></i>Deploy To Station
</button>
</div>
</div>
<div v-if="itemlateststatus == 'Return' && this.itemassignedtouser">
<h2 class="register-heading">Receive Item Return</h2>
<div class="col-sm-3"></div>
@ -571,6 +602,82 @@
</div>
</div>
</div>
@* Model Return Item *@
<div class="modal fade" id="returnMessageModal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Return Item</h5>
<button type="button" class="close closeModal" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<div class="modal-body">
<form v-on:submit.prevent="confirmReturnItem">
<div class="form-group row mb-3">
<label class="col-sm-4 col-form-label">Remark:</label>
<div class="col-sm-8">
<input type="text" class="form-control" v-model="remark" required />
</div>
</div>
<div class="form-group row mb-3">
<label class="col-sm-4 col-form-label">Consignment Note:</label>
<div class="col-sm-8">
<input type="file" class="form-control-file" v-on:change="handleFileUpload" accept="image/*, application/pdf" />
</div>
</div>
<div class="text-center">
<button type="submit" class="btn btn-primary">Submit Return</button>
</div>
</form>
</div>
</div>
</div>
</div>
@* Model Deploy to Station *@
<div class="modal fade" id="stationMessageModal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Deploy to Station</h5>
<button type="button" class="close closeModal" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<div class="modal-body">
<form v-on:submit.prevent="confirmDeployStation">
<div class="form-group row mb-3">
<label class="col-sm-4 col-form-label">Select Station:</label>
<div class="col-sm-8">
<select class="form-select" v-model="selectedStation" required>
<option value="" disabled>-- Select Station --</option>
<option v-for="station in stationlist" :key="station.stationId" :value="station.stationId">
{{ station.stationName }}
</option>
</select>
</div>
</div>
<div class="form-group row mb-3">
<label class="col-sm-4 col-form-label">Remark:</label>
<div class="col-sm-8">
<input type="text" class="form-control" v-model="remark" placeholder="Optional" />
</div>
</div>
<div class="form-group row mb-3">
<label class="col-sm-4 col-form-label">Consignment Note:</label>
<div class="col-sm-8">
<input type="file" class="form-control-file" v-on:change="handleFileUpload" accept="image/*, application/pdf" />
</div>
</div>
<div class="text-center">
<button type="submit" class="btn btn-success">Confirm Deployment</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@section Scripts {
@ -681,7 +788,7 @@
},
filteredDepartments() {
if (!this.selectedCompany) {
return []; // No company selected, return empty list
return [];
}
const company = this.companies.find(c => c.companyId === this.selectedCompany);
// this.selectedDepartment = '';
@ -689,7 +796,7 @@
},
showProduct() {
if (!this.selectedProduct) {
return []; // No company selected, return empty list
return [];
}
const product = this.products.find(c => c.productId === this.selectedProduct);
return product ? product : {};
@ -900,54 +1007,54 @@
},
async receiveItemMovement() {
const now = new Date();
console.log('currentuser'+this.currentUser.id);
console.log('lastuser'+this.thisItem.lastuser);
// Determine the status based on specific conditions
let statusToSave = "";
// 1. YOUR NEW LOGIC: If it's On Delivery and the current user is the target lastUser, set to Delivered
if (this.thisItem.toOther === "On Delivery" && this.thisItem.lastUser == this.currentUser.id) {
statusToSave = "Delivered";
}
// 2. KEEP EXISTING LOGIC: Calibration/Repair/Return/General Delivery goes to Ready to Deploy
else if (
this.thisItem.toOther === "Return" ||
this.thisItem.toOther === "Calibration" ||
this.thisItem.toOther === "Repair" ||
this.thisItem.toOther === "On Delivery"
) {
statusToSave = "Ready To Deploy";
}
// 3. KEEP EXISTING LOGIC: Store-to-Store delivery check
else if (this.itemlateststatus == 'On Delivery' && this.thisItem.lastStore == this.currentUser.store) {
statusToSave = "Delivered";
}
const formData = {
Id: this.thisItem.movementId,
ReceiveDate: new Date(now.getTime() + 8 * 60 * 60 * 1000).toISOString(),
Remark: this.thisItem.remark,
LastUser: this.thisItem.lastuser == null ? this.currentUser.id : this.thisItem.lastuser,
LatestStatus: this.thisItem.toOther === "Return" ? "Faulty" : (this.thisItem.toOther === "Calibration" || this.thisItem.toOther === "Repair" || this.thisItem.toOther === "On Delivery" ) ? "Ready To Deploy" : (this.itemlateststatus == 'On Delivery' && this.thisItem.lastStore == this.currentUser.store ? "Delivered" : "")
LatestStatus: statusToSave // Uses the prioritized status from above
};
try {
// Proceed to send the data to the API
const response = await fetch('/InvMainAPI/UpdateItemMovementMaster', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
// 'Authorization': `Bearer ${this.token}`
},
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData)
});
if (response.ok) {
// If the form submission was successful, display a success message
// alert('Success!', 'Item form has been successfully submitted.', 'success');
//const updatedItem = await response.json();
// this.items.push(updatedItem);
// console.log(updatedItem);
// Reset the form
if (response.ok) {
this.resetForm();
window.location.href = '/Inventory/InventoryMaster/ItemMovement';
} else {
throw new Error('Failed to submit form.');
}
} catch (error) {
console.error('Error:', error);
// Displaying error message
alert('Inventory PSTW Error', `An error occurred: ${error.message}`, 'error');
}
},
async fetchItem(itemid) {
try {
@ -1025,7 +1132,6 @@
},
async confirmCancelItemMovement() {
if (!window.confirm("Are you sure you want to cancel this item movement?")) {
return;
@ -1034,15 +1140,14 @@
const now = new Date();
try {
// --- REMOVED: First Movement: Cancellation Record (cancellationMovementData) ---
// Fetch the current item movement details to get the existing Remark
const originalMovementDetailsResponse = await fetch(`/InvMainAPI/GetItemMovementById?id=${this.thisItem.movementId}`); // Assuming you have an API endpoint to get a single item movement by ID
const originalMovementDetailsResponse = await fetch(`/InvMainAPI/GetItemMovementById?id=${this.thisItem.movementId}`);
if (!originalMovementDetailsResponse.ok) {
throw new Error('Failed to retrieve original item movement details.');
}
const originalMovementDetails = await originalMovementDetailsResponse.json();
const currentRemark = originalMovementDetails.remark || ''; // Get existing remark, default to empty string if null
const currentRemark = originalMovementDetails.remark || '';
// Second Movement: Re-registration/Re-stock Record
const registrationMovementData = {
@ -1052,7 +1157,7 @@
ToOther: null,
sendDate: null,
Action: 'Register',
Quantity: this.thisItem.movementQuantity, // Use the movement quantity, not item quantity
Quantity: this.thisItem.movementQuantity,
Remark: null,
ConsignmentNote: null,
LastUser: this.currentUser.id,
@ -1079,9 +1184,6 @@
throw new Error('Failed to update original movement as cancelled.');
}
// --- REMOVED: Send the first movement (cancellation) ---
// const response1 = await fetch('/InvMainAPI/AddItemMovement', { ... });
// Send the second movement (registration/re-stock)
const response2 = await fetch('/InvMainAPI/AddItemMovement', {
method: 'POST',
@ -1100,7 +1202,6 @@
body: JSON.stringify({
ItemId: this.thisItem.itemID,
MovementId: this.thisItem.movementId // Pass the movement ID to find the exact quantity
// Don't pass Quantity here - API will get it from the movement record
}),
});
@ -1118,8 +1219,6 @@
}
},
// FRONT END FUNCTIONS
//----------------------//
async fetchUser() {
try {
const response = await fetch(`/IdentityAPI/GetUserInformation/`, {
@ -1210,6 +1309,110 @@
console.error('Error fetching item:', error);
}
},
ReturnMessage() {
$("#returnMessageModal").modal("show");
},
async confirmReturnItem() {
if (!confirm("Are you sure you want to return this item to the Inventory Master?")) {
return;
}
const now = new Date();
const formData = {
ItemId: this.thisItem.itemID,
ToStore: this.thisItem.toStore,
ToUser: this.thisItem.toUser, // This will be handled by the API logic
ToOther: "Return",
SendDate: new Date(now.getTime() + 8 * 60 * 60 * 1000).toISOString(),
Action: "StockIn",
Quantity: this.thisItem.quantity || 1,
Remark: this.remark + " (Returned)",
ConsignmentNote: this.document, // The base64 string from handleFileUpload
Date: new Date(now.getTime() + 8 * 60 * 60 * 1000).toISOString(),
LastUser: this.currentUser.id,
LastStore: this.thisItem.toStore,
LatestStatus: null,
MovementComplete: false
};
try {
const response = await fetch('/InvMainAPI/ReturnItemMovementUser', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData)
});
if (response.ok) {
alert('Success! Item is now on delivery to be returned.');
$('#returnMessageModal').modal('hide');
this.resetScanner(); // Reset view back to scanner
window.location.href = '/Inventory/InventoryMaster/ItemMovement';
} else {
const errorText = await response.text();
throw new Error(errorText || 'Failed to return item.');
}
} catch (error) {
console.error('Error:', error);
alert('Error: ' + error.message);
}
},
// Show the Station Modal
StationMessage() {
this.selectedStation = "";
$("#stationMessageModal").modal("show");
},
async confirmDeployStation() {
if (!this.selectedStation) {
alert("Please select a station.");
return;
}
const now = new Date();
const formData = {
ItemId: this.thisItem.itemID,
ToStation: this.thisItem.ToStation,
ToStore: this.thisItem.toStore,
ToUser: this.currentUser.id,
ToOther: "Delivered",
SendDate: new Date(now.getTime() + 8 * 60 * 60 * 1000).toISOString(),
Action: "Assign",
Quantity: this.thisItem.quantity || 1,
Remark: this.remark || "Deployed to station",
ConsignmentNote: this.document, // Base64 from file upload
Date: new Date(now.getTime() + 8 * 60 * 60 * 1000).toISOString(),
LastUser: this.currentUser.id,
LastStore: this.thisItem.toStore,
LastStation: this.selectedStation, // The new station ID selected in modal
LatestStatus: "Delivered",
receiveDate: new Date(now.getTime() + 8 * 60 * 60 * 1000).toISOString(),
MovementComplete: true
};
try {
const response = await fetch('/InvMainAPI/StationItemMovementUser', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData)
});
if (response.ok) {
alert('Success! Item has been deployed to the station.');
$('#stationMessageModal').modal('hide');
this.resetScanner();
window.location.href = '/Inventory/InventoryMaster/ItemMovement';
} else {
const errorText = await response.text();
throw new Error(errorText || 'Failed to deploy station.');
}
} catch (error) {
console.error('Error:', error);
alert('Error: ' + error.message);
}
},
},
});

View File

@ -13,5 +13,9 @@ namespace PSTW_CentralSystem.Areas.Report.Controllers
{
return View();
}
public IActionResult InventoryReportManagement()
{
return View();
}
}
}

View File

@ -0,0 +1,4 @@
@{
ViewData["Title"] = "Dashboard";
Layout = "~/Views/Shared/_Layout.cshtml";
}

View File

@ -500,6 +500,11 @@
<i class="mdi mdi-view-dashboard"></i><span class="hide-menu">Inventory Report</span>
</a>
</li>
<li class="sidebar-item">
<a class="sidebar-link waves-effect waves-dark sidebar-link" asp-area="Report" asp-controller="Reporting" asp-action="InventoryReportManagement" aria-expanded="false">
<i class="mdi mdi-view-dashboard"></i><span class="hide-menu">Inventory Report ii</span>
</a>
</li>
<!--MMS-->
<li class="sidebar-item">
<a class="sidebar-link has-arrow waves-effect waves-dark"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB