Update Inv Master > Inv Master
This commit is contained in:
parent
81013fa710
commit
6535050179
@ -273,28 +273,36 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Inv Master Return Item & Deploy to Station*@
|
||||
@* Inv Master Return Item & Assign*@
|
||||
<div v-if="itemlateststatus == 'Delivered' && (this.thisItem.toUser == this.currentUser.id || this.thisItem.toStore == this.currentUser.store || this.isStationPIC )">
|
||||
<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;">
|
||||
@* <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>
|
||||
{{ (thisItem?.currentStationId || thisItem?.toStationId) ? "Change Station" : "Deploy To Station" }}
|
||||
</button>
|
||||
</button> *@
|
||||
</div>
|
||||
<h2 class="register-heading mt-3 text-center">Add Item Movement</h2>
|
||||
<div class="col-sm-6 offset-sm-3">
|
||||
<div class="dropdown">
|
||||
<select class="btn btn-primary dropdown-toggle col-md-10 " v-model="selectedAction" required>
|
||||
<option class="btn-light" value="" disabled selected>Select Action</option>
|
||||
<option class="btn-light" value="user">Assign to User</option>
|
||||
<option class="btn-light" value="station">Assign to Station</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="itemlateststatus == 'Return' && this.itemassignedtouser">
|
||||
<div v-if="itemlateststatus == 'Return' && thisItem.toStore == currentUser.store">
|
||||
<h2 class="register-heading">Receive Item Return</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
|
||||
@ -807,8 +815,8 @@
|
||||
storelist: null,
|
||||
supplierlist: null,
|
||||
selectedUser: "",
|
||||
selectedStation: "",
|
||||
selectedStationPIC: null,
|
||||
// selectedStation: "",
|
||||
// selectedStationPIC: null,
|
||||
selectedStore: "",
|
||||
selectedAction: "",
|
||||
assigndate: null,
|
||||
@ -863,33 +871,31 @@
|
||||
this.trackFunctionSelected.value = this.paintOutline;
|
||||
},
|
||||
watch: {
|
||||
selectedStation(newStationId) {
|
||||
|
||||
// Find the station object that matches the selectedStation id
|
||||
const selectedStationObj = this.stationlist.find(station => station.stationId === newStationId);
|
||||
// Set the selectedPIC based on the stationPIC
|
||||
this.selectedStationPIC = selectedStationObj ? selectedStationObj.stationPicID : "";
|
||||
// this.selectedStationPIC = selectedStationObj ? selectedStationObj : null;
|
||||
},
|
||||
// Watch for changes in `thisItem` to reset `quantity` when a new item is scanned
|
||||
thisItem: {
|
||||
handler(newItem) {
|
||||
if (newItem && newItem.category === 'Disposable') {
|
||||
this.quantity = 1; // Reset to 1 or default quantity when a disposable item is scanned
|
||||
this.maxQuantity = newItem.quantity; // Set maxQuantity for disposable items
|
||||
this.quantity = 1;
|
||||
|
||||
// 🌟 HIERARCHICAL FIX: Check if Owner or Borrower
|
||||
const isOwner = (newItem.departmentId === this.selectedDepartment);
|
||||
|
||||
// If Owner, use main table. If Borrower, use movement table!
|
||||
this.maxQuantity = isOwner ? newItem.quantity : (newItem.movementQuantity || 1);
|
||||
|
||||
} else {
|
||||
this.quantity = 1; // Ensure it's 1 for non-disposable items
|
||||
this.maxQuantity = null; // Clear maxQuantity for non-disposable items
|
||||
this.quantity = 1;
|
||||
this.maxQuantity = null;
|
||||
}
|
||||
},
|
||||
immediate: true // Run the handler immediately when the component is mounted
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
selectedStationPicName() {
|
||||
const selectedStationObj = this.stationlist.find(station => station.stationId === this.selectedStation);
|
||||
return selectedStationObj?.stationPic?.fullName || "";
|
||||
},
|
||||
// selectedStationPicName() {
|
||||
// const selectedStationObj = this.stationlist.find(station => station.stationId === this.selectedStation);
|
||||
// return selectedStationObj?.stationPic?.fullName || "";
|
||||
// },
|
||||
filteredDepartments() {
|
||||
if (!this.selectedCompany) {
|
||||
return [];
|
||||
@ -1107,14 +1113,14 @@
|
||||
}
|
||||
},
|
||||
async addItemMovement() {
|
||||
// Client-side validation for quantity
|
||||
if (this.thisItem && this.thisItem.category === "Disposable" && this.quantity > this.thisItem.quantity) {
|
||||
alert('Error!', `The quantity you entered (${this.quantity}) exceeds the available stock (${this.thisItem.quantity}). Please enter a quantity less than or equal to the available stock.`, 'error');
|
||||
// 🌟 HIERARCHICAL FIX: Validate against maxQuantity, not thisItem.quantity
|
||||
if (this.thisItem && this.thisItem.category === "Disposable" && this.quantity > this.maxQuantity) {
|
||||
alert('Error!', `The quantity you entered (${this.quantity}) exceeds your available stock (${this.maxQuantity}). Please enter a quantity less than or equal to the available stock.`, 'error');
|
||||
return; // Prevent form submission
|
||||
}
|
||||
|
||||
// Check if the item is disposable and set serial number accordingly
|
||||
let itemQuantityToSend = 1; // Default quantity for non-disposable
|
||||
let itemQuantityToSend = 1;
|
||||
if (this.thisItem && this.thisItem.category === "Disposable") {
|
||||
// Ensure serial number is null for disposable items
|
||||
this.thisItem.serialNumber = null;
|
||||
@ -1219,23 +1225,27 @@
|
||||
async receiveItemMovement() {
|
||||
const now = new Date();
|
||||
|
||||
// Determine the status based on specific conditions
|
||||
let statusToSave = "";
|
||||
let statusToSave = "Delivered";
|
||||
|
||||
// If it's On Delivery and the current user/store is the target toUser/toStore, set to Delivered
|
||||
if (this.thisItem.toOther === "On Delivery" &&
|
||||
(this.thisItem.toUser == this.currentUser.id || this.thisItem.toStore == this.currentUser.store || this.isStationPIC))
|
||||
{
|
||||
const isSameStore = String(this.thisItem.toStore) === String(this.currentUser.store);
|
||||
const isTargetUser = String(this.thisItem.toUser) === String(this.currentUser.id);
|
||||
|
||||
const isSameDepartment = String(this.thisItem.departmentId) === String(this.selectedDepartment);
|
||||
|
||||
if (this.thisItem.toOther === "On Delivery") {
|
||||
// Condition: On Delivery + Same Store -> Delivered
|
||||
if (isSameStore || isTargetUser || this.isStationPIC) {
|
||||
statusToSave = "Delivered";
|
||||
}
|
||||
// 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";
|
||||
}
|
||||
else if (this.thisItem.toOther === "Return") {
|
||||
// Condition: Return + Same Dept -> Ready To Deploy
|
||||
// Condition: Return + Different Dept -> Delivered
|
||||
statusToSave = isSameDepartment ? "Ready To Deploy" : "Delivered";
|
||||
}
|
||||
else if (this.thisItem.toOther === "Calibration" || this.thisItem.toOther === "Repair") {
|
||||
// Condition: Calibration/Repair + Same Store -> Ready To Deploy
|
||||
statusToSave = isSameStore ? "Ready To Deploy" : "Delivered";
|
||||
}
|
||||
|
||||
let receiveToUser = null;
|
||||
@ -1246,12 +1256,7 @@
|
||||
receiveToUser = null;
|
||||
receiveToStore = null;
|
||||
receiveToStation = this.thisItem.toStation;
|
||||
}
|
||||
else if (this.thisItem.toStore) {
|
||||
receiveToUser = this.currentUser.id;
|
||||
receiveToStore = this.currentUser.store;
|
||||
}
|
||||
else if (this.thisItem.toUser) {
|
||||
} else {
|
||||
receiveToUser = this.currentUser.id;
|
||||
receiveToStore = this.currentUser.store;
|
||||
}
|
||||
@ -1261,7 +1266,7 @@
|
||||
ReceiveDate: new Date(now.getTime() + 8 * 60 * 60 * 1000).toISOString(),
|
||||
Remark: this.thisItem.remark,
|
||||
LatestStatus: statusToSave,
|
||||
|
||||
Action: "Stock In",
|
||||
ToUser: receiveToUser,
|
||||
ToStore: receiveToStore,
|
||||
ToStation: receiveToStation,
|
||||
@ -1270,6 +1275,7 @@
|
||||
LastStore: this.thisItem.lastStore,
|
||||
LastStation: this.thisItem.lastStation
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch('/InvMainAPI/UpdateItemMovementMaster', {
|
||||
method: 'POST',
|
||||
@ -1278,14 +1284,15 @@
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
alert(`Success! Item received and set to: ${statusToSave}`);
|
||||
this.resetScanner();
|
||||
// window.location.href = '/Inventory/InventoryMaster/ItemMovement';
|
||||
window.location.reload();
|
||||
} else {
|
||||
throw new Error('Failed to submit form.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
alert('Inventory PSTW Error', `An error occurred: ${error.message}`, 'error');
|
||||
alert('Inventory PSTW Error: An error occurred.');
|
||||
}
|
||||
},
|
||||
async fetchItem(itemid) {
|
||||
@ -1296,10 +1303,14 @@
|
||||
|
||||
if (response.ok) {
|
||||
this.thisItem = await response.json();
|
||||
// If the item is disposable, set the quantity to 1 by default, or to its current quantity if available
|
||||
|
||||
// 🌟 HIERARCHICAL FIX: Set max quantity based on role
|
||||
if (this.thisItem.category === 'Disposable') {
|
||||
this.quantity = 1;
|
||||
this.maxQuantity = this.thisItem.quantity;
|
||||
|
||||
const isOwner = (this.thisItem.departmentId === this.selectedDepartment);
|
||||
this.maxQuantity = isOwner ? this.thisItem.quantity : (this.thisItem.movementQuantity || 1);
|
||||
|
||||
} else {
|
||||
this.quantity = 1;
|
||||
this.maxQuantity = null;
|
||||
@ -1372,117 +1383,117 @@
|
||||
},
|
||||
|
||||
async confirmCancelItemMovement() {
|
||||
if (!window.confirm("Are you sure you want to cancel this item movement?")) {
|
||||
return;
|
||||
}
|
||||
if (!window.confirm("Are you sure you want to cancel this item movement?")) {
|
||||
return;
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
const now = new Date();
|
||||
|
||||
try {
|
||||
try {
|
||||
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 || '';
|
||||
|
||||
// Fetch the current item movement details to get the existing Remark
|
||||
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 || '';
|
||||
const isSameDepartment = this.thisItem.departmentId === this.selectedDepartment;
|
||||
const targetLatestStatus = isSameDepartment ? 'Ready To Deploy' : 'Delivered';
|
||||
|
||||
// Second Movement: Re-registration/Re-stock Record
|
||||
const registrationMovementData = {
|
||||
ItemId: this.thisItem.itemID,
|
||||
LastStore: this.currentUser.store,
|
||||
LastUser: this.currentUser.id,
|
||||
ToOther: null,
|
||||
sendDate: null,
|
||||
Action: 'Register',
|
||||
Quantity: this.thisItem.movementQuantity,
|
||||
Remark: null,
|
||||
ConsignmentNote: null,
|
||||
ToUser: this.currentUser.id,
|
||||
ToStore: this.currentUser.store,
|
||||
LatestStatus: 'Ready To Deploy',
|
||||
receiveDate: null,
|
||||
MovementComplete: true,
|
||||
};
|
||||
|
||||
// Update the original movement to mark it as cancelled
|
||||
const updateOriginalResponse = await fetch('/InvMainAPI/UpdateItemMovementMaster', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
Id: this.thisItem.movementId,
|
||||
ToUser: originalMovementDetails.toUser,
|
||||
ToStore: originalMovementDetails.toStore,
|
||||
ToStation: originalMovementDetails.toStation,
|
||||
MovementComplete: true,
|
||||
LatestStatus: 'Cancelled',
|
||||
// Append the cancellation remark to the current remark
|
||||
Remark: `Current: ${currentRemark.trim()}${currentRemark.trim() ? ' / ' : ''}Movement cancelled: ${this.cancelRemark}`
|
||||
}),
|
||||
});
|
||||
|
||||
if (!updateOriginalResponse.ok) {
|
||||
throw new Error('Failed to update original movement as cancelled.');
|
||||
}
|
||||
|
||||
// Send the second movement (registration/re-stock)
|
||||
const response2 = await fetch('/InvMainAPI/AddItemMovement', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(registrationMovementData),
|
||||
});
|
||||
|
||||
if (!response2.ok) {
|
||||
throw new Error('Failed to record re-registration movement.');
|
||||
}
|
||||
|
||||
// Update the item's quantity by adding back the assigned quantity
|
||||
const updateItemResponse = await fetch('/InvMainAPI/UpdateItemQuantity', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
const registrationMovementData = {
|
||||
ItemId: this.thisItem.itemID,
|
||||
MovementId: this.thisItem.movementId // Pass the movement ID to find the exact quantity
|
||||
}),
|
||||
});
|
||||
|
||||
if (!updateItemResponse.ok) {
|
||||
throw new Error('Failed to update item quantity.');
|
||||
}
|
||||
LastStore: originalMovementDetails.toStore,
|
||||
LastUser: originalMovementDetails.toUser,
|
||||
LastStation: originalMovementDetails.toStation,
|
||||
|
||||
alert('Success!', 'Item movement cancelled and quantity returned successfully.', 'success');
|
||||
this.resetForm();
|
||||
window.location.href = '/Inventory/InventoryMaster/ItemMovement';
|
||||
ToOther: null,
|
||||
sendDate: null,
|
||||
Action: 'Stock In',
|
||||
Quantity: this.thisItem.movementQuantity,
|
||||
Remark: null,
|
||||
ConsignmentNote: null,
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error during cancellation process:', error);
|
||||
alert('Error', `An error occurred during cancellation: ${error.message}`, 'error');
|
||||
}
|
||||
},
|
||||
ToUser: this.currentUser.id,
|
||||
ToStore: this.currentUser.store,
|
||||
|
||||
LatestStatus: targetLatestStatus,
|
||||
receiveDate: null,
|
||||
MovementComplete: true,
|
||||
};
|
||||
|
||||
const updateOriginalResponse = await fetch('/InvMainAPI/UpdateItemMovementMaster', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
Id: this.thisItem.movementId,
|
||||
ToUser: originalMovementDetails.toUser,
|
||||
ToStore: originalMovementDetails.toStore,
|
||||
ToStation: originalMovementDetails.toStation,
|
||||
MovementComplete: true,
|
||||
LatestStatus: 'Cancelled',
|
||||
Remark: `Current: ${currentRemark.trim()}${currentRemark.trim() ? ' / ' : ''}Movement cancelled: ${this.cancelRemark}`
|
||||
}),
|
||||
});
|
||||
|
||||
if (!updateOriginalResponse.ok) {
|
||||
throw new Error('Failed to update original movement as cancelled.');
|
||||
}
|
||||
|
||||
const response2 = await fetch('/InvMainAPI/AddItemMovement', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(registrationMovementData),
|
||||
});
|
||||
|
||||
if (!response2.ok) {
|
||||
throw new Error('Failed to record re-registration movement.');
|
||||
}
|
||||
|
||||
const updateItemResponse = await fetch('/InvMainAPI/UpdateItemQuantity', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
ItemId: this.thisItem.itemID,
|
||||
MovementId: this.thisItem.movementId
|
||||
}),
|
||||
});
|
||||
|
||||
if (!updateItemResponse.ok) {
|
||||
throw new Error('Failed to update item quantity.');
|
||||
}
|
||||
|
||||
alert('Success!', 'Item movement cancelled and quantity returned successfully.', 'success');
|
||||
this.resetForm();
|
||||
window.location.href = '/Inventory/InventoryMaster/ItemMovement';
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error during cancellation process:', error);
|
||||
alert('Error', `An error occurred during cancellation: ${error.message}`, 'error');
|
||||
}
|
||||
},
|
||||
async fetchUser() {
|
||||
try {
|
||||
const response = await fetch(`/IdentityAPI/GetUserInformation/`, {
|
||||
method: 'POST',
|
||||
});
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
this.currentUser = data?.userInfo || null;
|
||||
const companyDeptData = await this.currentUser.department;
|
||||
this.currentUserCompanyDept = companyDeptData;
|
||||
this.selectedCompany = companyDeptData?.companyId || "";
|
||||
this.selectedDepartment = companyDeptData?.departmentId || "";
|
||||
});
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
this.currentUser = data?.userInfo || null;
|
||||
const companyDeptData = await this.currentUser.department;
|
||||
this.currentUserCompanyDept = companyDeptData;
|
||||
this.selectedCompany = companyDeptData?.companyId || "";
|
||||
this.selectedDepartment = companyDeptData?.departmentId || "";
|
||||
|
||||
|
||||
}
|
||||
else {
|
||||
console.error(`Failed to fetch user: ${response.statusText}`);
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.error('There was a problem with the fetch operation:', error);
|
||||
else {
|
||||
console.error(`Failed to fetch user: ${response.statusText}`);
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.error('There was a problem with the fetch operation:', error);
|
||||
}
|
||||
},
|
||||
async fetchUsers() {
|
||||
try {
|
||||
@ -1575,7 +1586,7 @@
|
||||
|
||||
ToOther: "Return",
|
||||
SendDate: new Date(now.getTime() + 8 * 60 * 60 * 1000).toISOString(),
|
||||
Action: "StockIn",
|
||||
Action: "Stock Out",
|
||||
Quantity: this.thisItem.movementQuantity || 1,
|
||||
Remark: this.remark,
|
||||
ConsignmentNote: this.document,
|
||||
@ -1608,10 +1619,10 @@
|
||||
}
|
||||
},
|
||||
|
||||
StationMessage() {
|
||||
this.selectedStation = "";
|
||||
$("#stationMessageModal").modal("show");
|
||||
},
|
||||
// StationMessage() {
|
||||
// this.selectedStation = "";
|
||||
// $("#stationMessageModal").modal("show");
|
||||
// },
|
||||
|
||||
async confirmDeployStation() {
|
||||
if (!this.selectedStation) {
|
||||
|
||||
@ -277,7 +277,7 @@
|
||||
<label class="col-sm-4 col-form-label">Deploy Station : </label>
|
||||
<div class="col-sm-8">
|
||||
<select class="btn btn-primary dropdown-toggle col-md-10" v-model="selectedStation">
|
||||
<option class="btn-light" value="" disabled selected>Select Station</option>
|
||||
<option class="btn-light" value="" disabled selected>-- Select Station --</option>
|
||||
<option v-if="stationList.length === 0" class="btn-light" disabled>No Station Assigned to You</option>
|
||||
<option class="btn-light" v-for="(station, index) in stationList" :key="index" :value="station.stationId">{{ station.stationName}}</option>
|
||||
</select>
|
||||
@ -619,7 +619,7 @@
|
||||
}
|
||||
|
||||
try {
|
||||
// 1. LOGIC: Identify the Origin (Last location)
|
||||
|
||||
let returnLastUser = null;
|
||||
let returnLastStore = null;
|
||||
let returnLastStation = null;
|
||||
@ -631,19 +631,16 @@
|
||||
} else if (this.thisItem.toUser) {
|
||||
returnLastUser = this.thisItem.toUser;
|
||||
} else {
|
||||
returnLastUser = this.currentUserId; // Fallback to current user if not found
|
||||
returnLastUser = this.currentUserId;
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
const formData = {
|
||||
ItemId: this.thisItem.itemID,
|
||||
|
||||
// ORIGINS: Where the item is currently sitting
|
||||
LastUser: returnLastUser,
|
||||
LastStore: returnLastStore,
|
||||
LastStation: returnLastStation,
|
||||
|
||||
// DESTINATIONS: Set to null (the C# API logic overrides this)
|
||||
ToUser: null,
|
||||
ToStore: null,
|
||||
ToStation: null,
|
||||
@ -655,32 +652,29 @@
|
||||
ConsignmentNote: this.consignmentNote,
|
||||
SendDate: new Date(now.getTime() + 8 * 60 * 60 * 1000).toISOString(),
|
||||
Date: new Date(now.getTime() + 8 * 60 * 60 * 1000).toISOString(),
|
||||
LatestStatus: null,
|
||||
ReceiveDate: null,
|
||||
MovementComplete: false,
|
||||
};
|
||||
|
||||
const response = await fetch('/InvMainAPI/ReturnItemMovementUser', {
|
||||
const response = await fetch('/InvMainAPI/ReturnToStore', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(formData)
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
alert('Success! Item is on the delivery to return to Inventory Master.');
|
||||
alert('Success! Item is returning to the Store.');
|
||||
this.thisItem = await response.json();
|
||||
$('#returnModal').modal('hide');
|
||||
$('#returnMessage').modal('hide');
|
||||
this.displayStatus = "requestAgain";
|
||||
this.resetForm();
|
||||
} else {
|
||||
throw new Error('Failed to submit form.');
|
||||
const errorText = await response.text();
|
||||
throw new Error(errorText || 'Failed to submit form.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
alert('Inventory PSTW Error: An error occurred.');
|
||||
alert('Error: ' + error.message);
|
||||
}
|
||||
},
|
||||
async fetchItem(itemid) {
|
||||
|
||||
@ -677,8 +677,8 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
||||
try
|
||||
{
|
||||
var savedItem = await _centralDbContext.Items
|
||||
.Include(i => i.Product)
|
||||
.FirstOrDefaultAsync(i => i.ItemID == item.ItemID);
|
||||
.Include(i => i.Product)
|
||||
.FirstOrDefaultAsync(i => i.ItemID == item.ItemID);
|
||||
if (savedItem == null)
|
||||
{
|
||||
return NotFound(new { success = false, message = "Item not found" });
|
||||
@ -687,19 +687,15 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
||||
var oldProduct = savedItem.Product;
|
||||
var newProduct = await _centralDbContext.Products.FirstOrDefaultAsync(p => p.ProductId == item.ProductId) ?? throw new Exception("New Product not found");
|
||||
|
||||
// --- PREPARE DEPT CODES FOR JSON ---
|
||||
var oldDept = await GetDepartmentWithCompany(savedItem.CompanyId, savedItem.DepartmentId);
|
||||
var newDept = await GetDepartmentWithCompany(item.CompanyId, item.DepartmentId);
|
||||
string oldDeptCode = oldDept?.DepartmentCode ?? "UNKNOWN";
|
||||
string newDeptCode = newDept?.DepartmentCode ?? "UNKNOWN";
|
||||
|
||||
// Quantity adjustment logic based on category changes (JSON logic added inside each block)
|
||||
if (oldProduct?.Category == "Disposable" && newProduct.Category == "Disposable")
|
||||
{
|
||||
int quantityDifference = item.Quantity - savedItem.Quantity;
|
||||
newProduct.QuantityProduct += quantityDifference;
|
||||
|
||||
// If changing department but same product
|
||||
if (savedItem.DepartmentId != item.DepartmentId)
|
||||
{
|
||||
UpdateQuantityJson(newProduct, oldDeptCode, -savedItem.Quantity);
|
||||
@ -715,23 +711,23 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
||||
if (oldProduct != null && oldProduct.QuantityProduct > 0)
|
||||
{
|
||||
oldProduct.QuantityProduct = (oldProduct.QuantityProduct ?? 0) - 1;
|
||||
UpdateQuantityJson(oldProduct, oldDeptCode, -1); // <--- ADDED
|
||||
UpdateQuantityJson(oldProduct, oldDeptCode, -1);
|
||||
_centralDbContext.Products.Update(oldProduct);
|
||||
}
|
||||
newProduct.QuantityProduct += item.Quantity;
|
||||
UpdateQuantityJson(newProduct, newDeptCode, item.Quantity); // <--- ADDED
|
||||
UpdateQuantityJson(newProduct, newDeptCode, item.Quantity);
|
||||
}
|
||||
else if (oldProduct?.Category == "Disposable" && (newProduct.Category == "Asset" || newProduct.Category == "Part"))
|
||||
{
|
||||
if (oldProduct != null)
|
||||
{
|
||||
oldProduct.QuantityProduct = (oldProduct.QuantityProduct ?? 0) - savedItem.Quantity;
|
||||
UpdateQuantityJson(oldProduct, oldDeptCode, -savedItem.Quantity); // <--- ADDED
|
||||
UpdateQuantityJson(oldProduct, oldDeptCode, -savedItem.Quantity);
|
||||
if (oldProduct.QuantityProduct < 0) oldProduct.QuantityProduct = 0;
|
||||
_centralDbContext.Products.Update(oldProduct);
|
||||
}
|
||||
newProduct.QuantityProduct = (newProduct.QuantityProduct ?? 0) + 1;
|
||||
UpdateQuantityJson(newProduct, newDeptCode, 1); // <--- ADDED
|
||||
UpdateQuantityJson(newProduct, newDeptCode, 1);
|
||||
item.Quantity = 1;
|
||||
}
|
||||
else if ((oldProduct?.Category == "Asset" || oldProduct?.Category == "Part") && (newProduct.Category == "Asset" || newProduct.Category == "Part"))
|
||||
@ -741,22 +737,20 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
||||
if (oldProduct != null && oldProduct.QuantityProduct > 0)
|
||||
{
|
||||
oldProduct.QuantityProduct = (oldProduct.QuantityProduct ?? 0) - 1;
|
||||
UpdateQuantityJson(oldProduct, oldDeptCode, -1); // <--- ADDED
|
||||
UpdateQuantityJson(oldProduct, oldDeptCode, -1);
|
||||
_centralDbContext.Products.Update(oldProduct);
|
||||
}
|
||||
newProduct.QuantityProduct = (newProduct.QuantityProduct ?? 0) + 1;
|
||||
UpdateQuantityJson(newProduct, newDeptCode, 1); // <--- ADDED
|
||||
UpdateQuantityJson(newProduct, newDeptCode, 1);
|
||||
}
|
||||
item.Quantity = 1;
|
||||
}
|
||||
|
||||
// Handle serial number based on the new product's category
|
||||
if (newProduct.Category == "Disposable")
|
||||
{
|
||||
item.SerialNumber = null;
|
||||
}
|
||||
|
||||
// Update savedItem properties (Existing logic kept exactly as provided)
|
||||
savedItem.DefaultPrice = item.DefaultPrice;
|
||||
savedItem.CompanyId = item.CompanyId;
|
||||
savedItem.DepartmentId = item.DepartmentId;
|
||||
@ -777,15 +771,23 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
||||
savedItem.InvoiceNo = item.InvoiceNo;
|
||||
savedItem.InvoiceDate = item.InvoiceDate;
|
||||
savedItem.PartNumber = item.PartNumber;
|
||||
|
||||
savedItem.ModifiedDate = DateTime.Now;
|
||||
|
||||
var companyDepartment = await GetDepartmentWithCompany(savedItem.CompanyId, savedItem.DepartmentId);
|
||||
string? deptCode = companyDepartment!.DepartmentCode?.ToString();
|
||||
string? dCode = companyDepartment!.DepartmentCode?.ToString();
|
||||
char? initialCategory = newProduct!.Category.ToString().Substring(0, 1).ToUpper().FirstOrDefault();
|
||||
string? productId = newProduct!.ProductId.ToString("D3");
|
||||
string? itemIdString = savedItem.ItemID.ToString("D5");
|
||||
savedItem.UniqueID = $"{deptCode}{initialCategory}{productId}{itemIdString}".ToUpper();
|
||||
savedItem.UniqueID = $"{dCode}{initialCategory}{productId}{itemIdString}".ToUpper();
|
||||
|
||||
var regMovement = await _centralDbContext.ItemMovements
|
||||
.FirstOrDefaultAsync(m => m.ItemId == savedItem.ItemID && m.Action == "Register");
|
||||
|
||||
if (regMovement != null)
|
||||
{
|
||||
regMovement.Quantity = savedItem.Quantity;
|
||||
_centralDbContext.ItemMovements.Update(regMovement);
|
||||
}
|
||||
|
||||
_centralDbContext.Products.Update(newProduct);
|
||||
_centralDbContext.Items.Update(savedItem);
|
||||
@ -1064,29 +1066,12 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
||||
|
||||
try
|
||||
{
|
||||
//itemmovement.sendDate = DateTime.Now; // This ensures hours/minutes/seconds are captured
|
||||
//itemmovement.Date = DateTime.Now; // Set the general record date as well
|
||||
|
||||
//var inventoryMaster = await _centralDbContext.InventoryMasters.Include("User").FirstOrDefaultAsync(i => i.UserId == itemmovement.LastUser);
|
||||
//if (inventoryMaster != null)
|
||||
//{
|
||||
// itemmovement.LastStore = inventoryMaster.StoreId;
|
||||
//}
|
||||
|
||||
// 1. FIX DATE OVERRULE:
|
||||
// Use the date from the frontend (assigndate) if it exists.
|
||||
// Only set to DateTime.Now if the frontend sent null/empty.
|
||||
if (itemmovement.sendDate == default || itemmovement.sendDate == null)
|
||||
{
|
||||
itemmovement.sendDate = DateTime.Now;
|
||||
}
|
||||
itemmovement.Date = DateTime.Now; // Log the entry creation time
|
||||
itemmovement.Date = DateTime.Now;
|
||||
|
||||
// 2. FIX STORE/USER OVERRULE:
|
||||
// Only auto-fill LastStore if:
|
||||
// - The frontend didn't send one (null)
|
||||
// - We have a LastUser to look up
|
||||
// - AND it is NOT a "user" assignment (because for 'user', we want it to stay NULL)
|
||||
if (itemmovement.LastStore == null && itemmovement.LastUser != null && itemmovement.ToUser == null)
|
||||
{
|
||||
var inventoryMaster = await _centralDbContext.InventoryMasters
|
||||
@ -1124,51 +1109,48 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
||||
}
|
||||
|
||||
_centralDbContext.ItemMovements.Add(itemmovement);
|
||||
await _centralDbContext.SaveChangesAsync();
|
||||
|
||||
await _centralDbContext.SaveChangesAsync(); // This generates the auto-incremented ItemID
|
||||
|
||||
var updateItem = await _centralDbContext.Items.FindAsync(itemmovement.ItemId); //only access after it have its own itemmovent
|
||||
var updateItem = await _centralDbContext.Items.FindAsync(itemmovement.ItemId);
|
||||
|
||||
if (updateItem != null)
|
||||
{
|
||||
if (itemmovement.ToOther == "On Delivery")
|
||||
{
|
||||
updateItem.ItemStatus = 2;
|
||||
}
|
||||
else if (itemmovement.ToOther == "Repair" || itemmovement.ToOther == "Calibration")
|
||||
{
|
||||
updateItem.ItemStatus = 4;
|
||||
}
|
||||
else if (itemmovement.ToOther == "Faulty")
|
||||
{
|
||||
updateItem.ItemStatus = 8;
|
||||
}
|
||||
// Handle quantity update for disposable items here
|
||||
// This is crucial: if it's a disposable item, decrement the Item's Quantity
|
||||
// You'll need to fetch the Product to know if it's Disposable
|
||||
var product = await _centralDbContext.Products.FindAsync(updateItem.ProductId);
|
||||
// Update statuses unconditionally
|
||||
if (itemmovement.ToOther == "On Delivery") updateItem.ItemStatus = 2;
|
||||
else if (itemmovement.ToOther == "Repair" || itemmovement.ToOther == "Calibration") updateItem.ItemStatus = 4;
|
||||
else if (itemmovement.ToOther == "Faulty") updateItem.ItemStatus = 8;
|
||||
|
||||
if (product != null)
|
||||
// --- HIERARCHICAL CUSTODY CHECK ---
|
||||
// Verify if the sender (LastUser) belongs to the Owner Department.
|
||||
// *Note: Adjust 'DepartmentId' below to match your actual User/Item schema properties*
|
||||
var currentUserDept = await _centralDbContext.Users
|
||||
.Where(u => u.Id == itemmovement.LastUser)
|
||||
.Select(u => u.departmentId)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
bool isOwnerDepartment = (updateItem.DepartmentId == currentUserDept);
|
||||
|
||||
// ONLY affect the Items table quantity if the Owner is sending it
|
||||
if (isOwnerDepartment)
|
||||
{
|
||||
// Handle variable quantity for Disposables
|
||||
if (product.Category == "Disposable" && itemmovement.Quantity.HasValue)
|
||||
var product = await _centralDbContext.Products.FindAsync(updateItem.ProductId);
|
||||
if (product != null)
|
||||
{
|
||||
updateItem.Quantity -= itemmovement.Quantity.Value;
|
||||
if (updateItem.Quantity < 0) updateItem.Quantity = 0;
|
||||
}
|
||||
// Handle binary quantity for Parts and Assets
|
||||
else if (product.Category == "Part" || product.Category == "Asset")
|
||||
{
|
||||
updateItem.Quantity = 0; // The unique item is now unavailable
|
||||
if (product.Category == "Disposable" && itemmovement.Quantity.HasValue)
|
||||
{
|
||||
updateItem.Quantity -= itemmovement.Quantity.Value;
|
||||
if (updateItem.Quantity < 0) updateItem.Quantity = 0;
|
||||
}
|
||||
else if (product.Category == "Part" || product.Category == "Asset")
|
||||
{
|
||||
updateItem.Quantity = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
updateItem.MovementId = itemmovement.Id;
|
||||
_centralDbContext.Items.Update(updateItem);
|
||||
await _centralDbContext.SaveChangesAsync(); // save changes for table item - movementid
|
||||
|
||||
|
||||
await _centralDbContext.SaveChangesAsync();
|
||||
}
|
||||
return Json(new
|
||||
{
|
||||
@ -1207,21 +1189,19 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
||||
{
|
||||
var updatedList = await _centralDbContext.ItemMovements.FindAsync(receiveMovement.Id);
|
||||
|
||||
if (updatedList == null)
|
||||
{
|
||||
return NotFound("Item movement record not found.");
|
||||
}
|
||||
if (updatedList == null) return NotFound("Item movement record not found.");
|
||||
|
||||
updatedList.ToUser = receiveMovement.ToUser ?? updatedList.ToUser;
|
||||
updatedList.ToStore = receiveMovement.ToStore ?? updatedList.ToStore;
|
||||
updatedList.ToStation = receiveMovement.ToStation ?? updatedList.ToStation;
|
||||
//updatedList.ToUser = receiveMovement.ToUser;
|
||||
//updatedList.ToStore = receiveMovement.ToStore;
|
||||
updatedList.LatestStatus = receiveMovement.LatestStatus;
|
||||
updatedList.receiveDate = receiveMovement.receiveDate;
|
||||
updatedList.Remark = receiveMovement.Remark;
|
||||
updatedList.MovementComplete = true;
|
||||
|
||||
updatedList.Action = receiveMovement.Action;
|
||||
|
||||
|
||||
var item = await _centralDbContext.Items
|
||||
.Include(i => i.Product)
|
||||
.FirstOrDefaultAsync(i => i.ItemID == updatedList.ItemId);
|
||||
@ -1230,16 +1210,30 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
||||
{
|
||||
if (updatedList.ToOther == "Return" || receiveMovement.LatestStatus == "Ready To Deploy")
|
||||
{
|
||||
if (item.Product?.Category == "Disposable")
|
||||
// --- HIERARCHICAL CUSTODY CHECK ---
|
||||
// Verify if the person receiving the item belongs to the Owner Department
|
||||
var receiverUserId = updatedList.ToUser;
|
||||
var receiverDept = await _centralDbContext.Users
|
||||
.Where(u => u.Id == receiverUserId)
|
||||
.Select(u => u.departmentId)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
bool isOwnerDepartment = (item.DepartmentId == receiverDept);
|
||||
|
||||
// ONLY affect the Items table quantity if the Owner is receiving it back
|
||||
if (isOwnerDepartment)
|
||||
{
|
||||
// from movement
|
||||
item.Quantity += (updatedList.Quantity ?? 0);
|
||||
if (item.Product?.Category == "Disposable")
|
||||
{
|
||||
item.Quantity += (updatedList.Quantity ?? 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
item.Quantity = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
item.Quantity = 1;
|
||||
}
|
||||
item.ItemStatus = 1;
|
||||
|
||||
item.ItemStatus = 1; // Mark status as available
|
||||
_centralDbContext.Items.Update(item);
|
||||
}
|
||||
}
|
||||
@ -1272,22 +1266,40 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
||||
|
||||
if (item == null) return NotFound("Item not found.");
|
||||
|
||||
// 1. Logic for Disposable (Variable)
|
||||
if (item.Product?.Category == "Disposable")
|
||||
{
|
||||
var originalMovement = await _centralDbContext.ItemMovements
|
||||
.FirstOrDefaultAsync(m => m.Id == model.MovementId);
|
||||
// Fetch original movement first so we can check who initiated it
|
||||
var originalMovement = await _centralDbContext.ItemMovements
|
||||
.FirstOrDefaultAsync(m => m.Id == model.MovementId);
|
||||
|
||||
if (originalMovement == null) return BadRequest("Original movement not found.");
|
||||
if (originalMovement == null) return BadRequest("Original movement not found.");
|
||||
|
||||
item.Quantity += (originalMovement.Quantity ?? 1);
|
||||
}
|
||||
// 2. Logic for Part and Asset (Binary)
|
||||
else if (item.Product?.Category == "Part" || item.Product?.Category == "Asset")
|
||||
// --- HIERARCHICAL CUSTODY CHECK ---
|
||||
// Verify if the user who initiated the movement (LastUser) belongs to the Owner Department.
|
||||
// *Note: Adjust 'DepartmentId' below to match your actual schema*
|
||||
var senderUserId = originalMovement.LastUser;
|
||||
var senderDept = await _centralDbContext.Users
|
||||
.Where(u => u.Id == senderUserId)
|
||||
.Select(u => u.departmentId)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
bool isOwnerDepartment = (item.DepartmentId == senderDept);
|
||||
|
||||
// ONLY restore the Items table quantity if the Owner initiated the cancelled movement
|
||||
if (isOwnerDepartment)
|
||||
{
|
||||
item.Quantity = 1; // Mark as back in stock/available
|
||||
// 1. Logic for Disposable (Variable)
|
||||
if (item.Product?.Category == "Disposable")
|
||||
{
|
||||
item.Quantity += (originalMovement.Quantity ?? 1);
|
||||
}
|
||||
// 2. Logic for Part and Asset (Binary)
|
||||
else if (item.Product?.Category == "Part" || item.Product?.Category == "Asset")
|
||||
{
|
||||
item.Quantity = 1; // Mark as back in stock/available
|
||||
}
|
||||
}
|
||||
|
||||
// We still save the item regardless, in case other status fields needed updating
|
||||
// (though in this specific snippet it's just quantity being managed)
|
||||
_centralDbContext.Items.Update(item);
|
||||
await _centralDbContext.SaveChangesAsync();
|
||||
|
||||
@ -1979,51 +1991,73 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
||||
[HttpPost("ReturnItemMovementUser")]
|
||||
public async Task<IActionResult> ReturnItemMovementUser([FromBody] ItemMovementModel returnMovement)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
if (!ModelState.IsValid) return BadRequest(ModelState);
|
||||
|
||||
try
|
||||
{
|
||||
// --- CORE FIX: ISOLATE THE CURRENT LIFECYCLE ---
|
||||
// 1. Find the last time the item cycle was "reset" (Returned or newly Registered)
|
||||
var lastResetMovement = await _centralDbContext.ItemMovements
|
||||
.Where(m => m.ItemId == returnMovement.ItemId && (m.Action == "StockIn" || m.Action == "Register"))
|
||||
.OrderByDescending(m => m.Id)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
// Get the ID where the current cycle started (if 0, it means it has never been returned/registered)
|
||||
int currentCycleStartId = lastResetMovement != null ? lastResetMovement.Id : 0;
|
||||
var itemData = await _centralDbContext.Items
|
||||
.Include(i => i.Product)
|
||||
.FirstOrDefaultAsync(i => i.ItemID == returnMovement.ItemId);
|
||||
|
||||
// 2. Find the VERY FIRST movement AFTER the cycle started.
|
||||
// This bypasses the middleman (User/Store who gave it to the station) and
|
||||
// accurately grabs the Inventory Master who originally assigned it at the beginning of the chain.
|
||||
var originalMasterMovement = await _centralDbContext.ItemMovements
|
||||
.Where(m => m.ItemId == returnMovement.ItemId
|
||||
&& m.Id > currentCycleStartId
|
||||
&& (m.LastUser != null || m.LastStore != null))
|
||||
.OrderBy(m => m.Id) // <-- Get the FIRST movement of the current chain
|
||||
.FirstOrDefaultAsync();
|
||||
if (itemData == null) return BadRequest("Item not found.");
|
||||
|
||||
if (originalMasterMovement != null)
|
||||
if (itemData.Product?.Category == "Disposable")
|
||||
{
|
||||
// Set the destination back to the original Inventory Master
|
||||
returnMovement.ToUser = originalMasterMovement.LastUser;
|
||||
returnMovement.ToStore = originalMasterMovement.LastStore;
|
||||
// Sum everything this specific user/store/station RECEIVED
|
||||
IQueryable<ItemMovementModel> totalInQuery = _centralDbContext.ItemMovements
|
||||
.Where(m => m.ItemId == returnMovement.ItemId && m.MovementComplete == true);
|
||||
|
||||
// Sum everything this specific user/store/station SENT OUT
|
||||
IQueryable<ItemMovementModel> totalOutQuery = _centralDbContext.ItemMovements
|
||||
.Where(m => m.ItemId == returnMovement.ItemId);
|
||||
|
||||
// Filter down to the specific custody level initiating the return
|
||||
if (returnMovement.LastStation != null)
|
||||
{
|
||||
totalInQuery = totalInQuery.Where(m => m.ToStation == returnMovement.LastStation);
|
||||
totalOutQuery = totalOutQuery.Where(m => m.LastStation == returnMovement.LastStation);
|
||||
}
|
||||
else if (returnMovement.LastUser != null)
|
||||
{
|
||||
totalInQuery = totalInQuery.Where(m => m.ToUser == returnMovement.LastUser);
|
||||
totalOutQuery = totalOutQuery.Where(m => m.LastUser == returnMovement.LastUser);
|
||||
}
|
||||
else if (returnMovement.LastStore != null)
|
||||
{
|
||||
totalInQuery = totalInQuery.Where(m => m.ToStore == returnMovement.LastStore);
|
||||
totalOutQuery = totalOutQuery.Where(m => m.LastStore == returnMovement.LastStore);
|
||||
}
|
||||
|
||||
var totalIn = await totalInQuery.SumAsync(m => m.Quantity ?? 0);
|
||||
var totalOut = await totalOutQuery.SumAsync(m => m.Quantity ?? 0);
|
||||
|
||||
// The true current custody balance for this borrower
|
||||
int currentBalance = totalIn - totalOut;
|
||||
|
||||
// Override the frontend quantity with the calculated actual balance
|
||||
returnMovement.Quantity = currentBalance > 0 ? currentBalance : 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback just in case history isn't found
|
||||
returnMovement.ToUser = null;
|
||||
returnMovement.ToStore = null;
|
||||
// Parts and Assets are binary, so they are always 1
|
||||
returnMovement.Quantity = 1;
|
||||
}
|
||||
|
||||
// Set the destination to the Item's DepartmentId
|
||||
// Tracing the item's department and saving in ToStore
|
||||
returnMovement.ToStore = itemData.DepartmentId;
|
||||
|
||||
returnMovement.ToUser = null;
|
||||
returnMovement.ToStation = null;
|
||||
|
||||
returnMovement.ToOther = "Return";
|
||||
returnMovement.Action = "Stock Out";
|
||||
|
||||
if (!string.IsNullOrEmpty(returnMovement.ConsignmentNote))
|
||||
{
|
||||
var findUniqueCode = _centralDbContext.Items.Include(i => i.Product).FirstOrDefault(r => r.ItemID == returnMovement.ItemId);
|
||||
|
||||
// Fetch the user data for the file name based on the destination we just assigned
|
||||
var findUniqueUser = _centralDbContext.Users.FirstOrDefault(r => r.Id == returnMovement.ToUser);
|
||||
|
||||
var bytes = Convert.FromBase64String(returnMovement.ConsignmentNote);
|
||||
@ -2053,43 +2087,25 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
||||
_centralDbContext.ItemMovements.Add(returnMovement);
|
||||
await _centralDbContext.SaveChangesAsync();
|
||||
|
||||
itemData.MovementId = returnMovement.Id;
|
||||
itemData.ItemStatus = 2;
|
||||
_centralDbContext.Items.Update(itemData);
|
||||
await _centralDbContext.SaveChangesAsync();
|
||||
|
||||
var updateItemIdMovement = await _centralDbContext.ItemMovements
|
||||
.FirstOrDefaultAsync(m => m.Id == returnMovement.Id);
|
||||
|
||||
if (updateItemIdMovement != null)
|
||||
{
|
||||
var returnItems = await _centralDbContext.Items.FindAsync(updateItemIdMovement.ItemId);
|
||||
if (returnItems != null)
|
||||
{
|
||||
returnItems.MovementId = updateItemIdMovement.Id;
|
||||
returnItems.ItemStatus = 2;
|
||||
_centralDbContext.Items.Update(returnItems);
|
||||
await _centralDbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return Json(new
|
||||
{
|
||||
updateItemIdMovement.Id,
|
||||
updateItemIdMovement.ItemId,
|
||||
updateItemIdMovement.LastStation,
|
||||
updateItemIdMovement.LastStore,
|
||||
updateItemIdMovement.LastUser,
|
||||
updateItemIdMovement.ToOther,
|
||||
updateItemIdMovement.sendDate,
|
||||
updateItemIdMovement.Action,
|
||||
updateItemIdMovement.Quantity,
|
||||
updateItemIdMovement.Remark,
|
||||
updateItemIdMovement.ConsignmentNote,
|
||||
updateItemIdMovement.Date,
|
||||
updateItemIdMovement.ToUser,
|
||||
updateItemIdMovement.ToStore,
|
||||
updateItemIdMovement.ToStation,
|
||||
updateItemIdMovement.LatestStatus,
|
||||
updateItemIdMovement.receiveDate,
|
||||
updateItemIdMovement.MovementComplete
|
||||
Id = updateItemIdMovement.Id,
|
||||
ItemId = updateItemIdMovement.ItemId,
|
||||
ToStore = updateItemIdMovement.ToStore,
|
||||
ToUser = updateItemIdMovement.ToUser,
|
||||
Action = updateItemIdMovement.Action,
|
||||
ToOther = updateItemIdMovement.ToOther,
|
||||
ConsignmentNote = updateItemIdMovement.ConsignmentNote,
|
||||
MovementComplete = updateItemIdMovement.MovementComplete
|
||||
});
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -2097,6 +2113,84 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost("ReturnToStore")]
|
||||
public async Task<IActionResult> ReturnToStore([FromBody] ItemMovementModel returnMovement)
|
||||
{
|
||||
if (!ModelState.IsValid) return BadRequest(ModelState);
|
||||
|
||||
try
|
||||
{
|
||||
var currentUser = await _userManager.GetUserAsync(User);
|
||||
if (currentUser == null) return Unauthorized("User not found.");
|
||||
|
||||
if (currentUser.departmentId == null)
|
||||
{
|
||||
return BadRequest("Your user profile is not assigned to a Department.");
|
||||
}
|
||||
|
||||
// Assign the current user's department to ToStore
|
||||
returnMovement.ToStore = currentUser.departmentId;
|
||||
returnMovement.ToUser = null;
|
||||
returnMovement.ToStation = null;
|
||||
returnMovement.ToOther = "Return";
|
||||
returnMovement.Action = "StockIn";
|
||||
|
||||
if (!string.IsNullOrEmpty(returnMovement.ConsignmentNote))
|
||||
{
|
||||
var bytes = Convert.FromBase64String(returnMovement.ConsignmentNote);
|
||||
|
||||
var itemData = await _centralDbContext.Items
|
||||
.Include(i => i.Product)
|
||||
.FirstOrDefaultAsync(r => r.ItemID == returnMovement.ItemId);
|
||||
|
||||
string safeUserName = string.Join("_", (currentUser.FullName ?? "Unknown").Split(Path.GetInvalidFileNameChars()));
|
||||
string safeModelNo = string.Join("_", (itemData?.Product?.ModelNo ?? "NA").Split(Path.GetInvalidFileNameChars()));
|
||||
string uniqueId = Guid.NewGuid().ToString().Substring(0, 8);
|
||||
string ext = IsPdf(bytes) ? ".pdf" : ".jpg";
|
||||
|
||||
string relativePath = $"media/inventory/itemmovement/{safeUserName}_{safeModelNo}_{uniqueId}_Return{ext}";
|
||||
string folderPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", relativePath);
|
||||
|
||||
if (!Directory.Exists(Path.GetDirectoryName(folderPath))) Directory.CreateDirectory(Path.GetDirectoryName(folderPath));
|
||||
|
||||
await System.IO.File.WriteAllBytesAsync(folderPath, bytes);
|
||||
returnMovement.ConsignmentNote = "/" + relativePath;
|
||||
}
|
||||
|
||||
_centralDbContext.ItemMovements.Add(returnMovement);
|
||||
await _centralDbContext.SaveChangesAsync();
|
||||
|
||||
if (returnMovement.ItemId.HasValue)
|
||||
{
|
||||
var item = await _centralDbContext.Items.FindAsync(returnMovement.ItemId.Value);
|
||||
if (item != null)
|
||||
{
|
||||
item.MovementId = returnMovement.Id;
|
||||
item.ItemStatus = 2;
|
||||
_centralDbContext.Items.Update(item);
|
||||
await _centralDbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
return Json(new
|
||||
{
|
||||
id = returnMovement.Id,
|
||||
itemId = returnMovement.ItemId,
|
||||
toStore = returnMovement.ToStore,
|
||||
toUser = returnMovement.ToUser,
|
||||
lastUser = returnMovement.LastUser,
|
||||
lastStore = returnMovement.LastStore,
|
||||
action = returnMovement.Action,
|
||||
toOther = returnMovement.ToOther,
|
||||
remark = returnMovement.Remark,
|
||||
consignmentNote = returnMovement.ConsignmentNote
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return BadRequest($"Error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost("StationItemMovementUser")]
|
||||
public async Task<IActionResult> StationItemMovementUser([FromBody] ItemMovementModel stationMovement)
|
||||
{
|
||||
|
||||
Loading…
Reference in New Issue
Block a user