Update Inv & OT

This commit is contained in:
Naz 2025-07-23 17:17:23 +08:00
parent bde383ced7
commit 98ba700ef2
6 changed files with 82 additions and 67 deletions

View File

@ -36,6 +36,9 @@ namespace PSTW_CentralSystem.Areas.Inventory.Models
public string PartNumber { get; set; } = string.Empty; public string PartNumber { get; set; } = string.Empty;
public int CreatedByUserId { get; set; } public int CreatedByUserId { get; set; }
[ForeignKey("CreatedByUserId")] [ForeignKey("CreatedByUserId")]
public DateTime CreateDate { get; set; } = DateTime.Now;
public virtual UserModel? CreatedBy { get; set; } public virtual UserModel? CreatedBy { get; set; }
[ForeignKey("CompanyId")] [ForeignKey("CompanyId")]
public virtual CompanyModel? Company { get; set; } public virtual CompanyModel? Company { get; set; }

View File

@ -952,27 +952,24 @@
async fetchItem(itemid) { async fetchItem(itemid) {
try { try {
const response = await fetch('/InvMainAPI/GetItem/' + itemid, { const response = await fetch('/InvMainAPI/GetItem/' + itemid, {
method: 'POST',} method: 'POST',
); });
if (response.ok) {
// this.thisItem = await response.json();
if (response.ok) {
this.thisItem = await response.json(); this.thisItem = await response.json();
// If the item is disposable, set the quantity to 1 by default, or to its current quantity if available // If the item is disposable, set the quantity to 1 by default, or to its current quantity if available
if (this.thisItem.category === 'Disposable') { if (this.thisItem.category === 'Disposable') {
this.quantity = 1; // Reset to 1 or default quantity when a disposable item is scanned this.quantity = 1;
this.maxQuantity = this.thisItem.quantity; // Set maxQuantity for disposable items this.maxQuantity = this.thisItem.quantity;
} else { } else {
this.quantity = 1; // For non-disposable items, quantity is always 1 this.quantity = 1;
this.maxQuantity = null; // Clear maxQuantity for non-disposable items this.maxQuantity = null;
} }
console.log('last store' + this.thisItem.lastStore); console.log('last store' + this.thisItem.lastStore);
this.itemlateststatus = this.thisItem.latestStatus ? this.thisItem.latestStatus : this.thisItem.toOther; this.itemlateststatus = this.thisItem.latestStatus ? this.thisItem.latestStatus : this.thisItem.toOther;
this.itemassignedtouser = (this.thisItem.toUser === this.currentUser.id || this.thisItem.lastUser === this.currentUser.id) && this.thisItem.lastStore === this.currentUser.store ? true : false; this.itemassignedtouser = (this.thisItem.toUser === this.currentUser.id || this.thisItem.lastUser === this.currentUser.id) && this.thisItem.lastStore === this.currentUser.store ? true : false;
// console.log(this.thisItem);
// console.log(this.itemassignedtouser);
console.log(this.thisItem.lastStore); console.log(this.thisItem.lastStore);
console.log(this.thisItem.lastStore == this.currentUser.store ? true : false); console.log(this.thisItem.lastStore == this.currentUser.store ? true : false);
console.log(this.thisItem.toUser == this.currentUser.id ? true : false); console.log(this.thisItem.toUser == this.currentUser.id ? true : false);
@ -980,13 +977,18 @@
console.log(((this.thisItem.toUser == this.currentUser.id) || (this.thisItem.lastUser == this.currentUser.id)) ? true : false); console.log(((this.thisItem.toUser == this.currentUser.id) || (this.thisItem.lastUser == this.currentUser.id)) ? true : false);
console.log('currentuser store' + this.currentUser.store); console.log('currentuser store' + this.currentUser.store);
} else { } else {
console.error('Failed to fetch item information'); // If the response is not OK (e.g., 404 Not Found)
this.responseMessage = await response.text(); const errorData = await response.json(); // Assuming your API sends a JSON error object
// Show an alert message to the user
alert('QR Scan Error: ' + errorData.message);
this.resetScanner(); // Optionally reset the scanner on error
} }
} catch (error) { } catch (error) {
console.error('Error fetching item information:', error); console.error('Error fetching item information:', error);
// Show an alert message for network or other unhandled errors
alert('An unexpected error occurred: ' + error.message);
this.resetScanner(); // Optionally reset the scanner on unexpected error
} }
}, },
async fetchSuppliers() { async fetchSuppliers() {
@ -1032,25 +1034,17 @@
const now = new Date(); const now = new Date();
try { try {
// First Movement: Cancellation Record (EXACTLY AS YOU HAVE IT) // --- REMOVED: First Movement: Cancellation Record (cancellationMovementData) ---
const cancellationMovementData = {
ItemId: this.thisItem.itemID,
ToStore: this.currentUser.store,
ToUser: this.currentUser.id,
ToOther: null,
sendDate: new Date(now.getTime() + 8 * 60 * 60 * 1000).toISOString(),
Action: 'Stock Out',
Quantity: this.thisItem.quantity,
Remark: `Item has been cancelled: ${this.cancelRemark}`,
ConsignmentNote: this.thisItem.consignmentNote,
LastUser: this.currentUser.id,
LastStore: this.currentUser.store,
LatestStatus: 'Ready To Deploy',
receiveDate: null,
MovementComplete: true,
};
// Second Movement: Re-registration/Re-stock Record (EXACTLY AS YOU HAVE IT) // 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
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
// Second Movement: Re-registration/Re-stock Record
const registrationMovementData = { const registrationMovementData = {
ItemId: this.thisItem.itemID, ItemId: this.thisItem.itemID,
ToStore: this.currentUser.store, ToStore: this.currentUser.store,
@ -1058,7 +1052,7 @@
ToOther: null, ToOther: null,
sendDate: null, sendDate: null,
Action: 'Register', Action: 'Register',
Quantity: this.thisItem.quantity, Quantity: this.thisItem.movementQuantity, // Use the movement quantity, not item quantity
Remark: null, Remark: null,
ConsignmentNote: null, ConsignmentNote: null,
LastUser: this.currentUser.id, LastUser: this.currentUser.id,
@ -1076,7 +1070,8 @@
Id: this.thisItem.movementId, Id: this.thisItem.movementId,
MovementComplete: true, MovementComplete: true,
LatestStatus: 'Cancelled', LatestStatus: 'Cancelled',
Remark: `Movement cancelled: ${this.cancelRemark}` // Append the cancellation remark to the current remark
Remark: `${currentRemark.trim()}${currentRemark.trim() ? ' / ' : ''}Movement cancelled: ${this.cancelRemark}`
}), }),
}); });
@ -1084,16 +1079,8 @@
throw new Error('Failed to update original movement as cancelled.'); throw new Error('Failed to update original movement as cancelled.');
} }
// Send the first movement (cancellation) // --- REMOVED: Send the first movement (cancellation) ---
const response1 = await fetch('/InvMainAPI/AddItemMovement', { // const response1 = await fetch('/InvMainAPI/AddItemMovement', { ... });
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(cancellationMovementData),
});
if (!response1.ok) {
throw new Error('Failed to record cancellation movement.');
}
// Send the second movement (registration/re-stock) // Send the second movement (registration/re-stock)
const response2 = await fetch('/InvMainAPI/AddItemMovement', { const response2 = await fetch('/InvMainAPI/AddItemMovement', {
@ -1112,8 +1099,8 @@
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ body: JSON.stringify({
ItemId: this.thisItem.itemID, ItemId: this.thisItem.itemID,
Quantity: this.thisItem.quantity, // The quantity to add back MovementId: this.thisItem.movementId // Pass the movement ID to find the exact quantity
MovementId: this.thisItem.movementId // Add the movement ID // Don't pass Quantity here - API will get it from the movement record
}), }),
}); });

View File

@ -464,13 +464,12 @@
formData.append('File', this.selectedFile); formData.append('File', this.selectedFile);
try { try {
const res = await axios.post('/OvertimeAPI/SubmitOvertime', formData, { const response = await fetch('/OvertimeAPI/SubmitOvertime', {
headers: { method: 'POST',
'Content-Type': 'multipart/form-data' body: formData
}
}); });
if (res.status === 200) { if (response.ok) { // Check if the response status is 2xx
alert('Overtime submitted successfully!'); alert('Overtime submitted successfully!');
const modalEl = document.getElementById('submitModal'); const modalEl = document.getElementById('submitModal');
@ -480,10 +479,12 @@
await this.getSubmissionStatus(); await this.getSubmissionStatus();
} else { } else {
alert('Submission failed.'); const errorText = await response.text(); // Get error message from response body
alert(`Submission failed: ${errorText}`);
console.error('Submission failed:', response.status, errorText);
} }
} catch (error) { } catch (error) {
console.error(error); console.error("Error during submission:", error);
alert('An error occurred during submission.'); alert('An error occurred during submission.');
} }
} }

View File

@ -497,7 +497,9 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
try try
{ {
var product = await _centralDbContext.Products.FirstOrDefaultAsync(p => p.ProductId == item.ProductId) ?? throw new Exception("Product not found"); var product = await _centralDbContext.Products.FirstOrDefaultAsync(p => p.ProductId == item.ProductId) ?? throw new Exception("Product not found");
var inventoryMaster = await _centralDbContext.InventoryMasters.Include("User").FirstOrDefaultAsync(i => i.UserId == item.CreatedByUserId) ?? new InventoryMasterModel { UserId = item.CreatedByUserId }; var inventoryMaster = await _centralDbContext.InventoryMasters
.Include("User")
.FirstOrDefaultAsync(i => i.UserId == item.CreatedByUserId) ?? new InventoryMasterModel { UserId = item.CreatedByUserId };
if (product.Category == "Disposable") if (product.Category == "Disposable")
{ {
@ -514,6 +516,8 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
item.Quantity = 1; // Force quantity to 1 for Assets/Parts if it's not already item.Quantity = 1; // Force quantity to 1 for Assets/Parts if it's not already
} }
item.CreateDate = DateTime.Now;
_centralDbContext.Items.Add(item); _centralDbContext.Items.Add(item);
_centralDbContext.Products.Update(product); // Update the product quantity _centralDbContext.Products.Update(product); // Update the product quantity
@ -580,6 +584,7 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
savedItem.EndWDate, savedItem.EndWDate,
savedItem.InvoiceDate, savedItem.InvoiceDate,
savedItem.PartNumber, savedItem.PartNumber,
CreateDate = savedItem.CreateDate.ToString("dd/MM/yyyy HH:mm:ss")
}; };
return Json(updatedItem); return Json(updatedItem);
} }
@ -1144,6 +1149,25 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
} }
} }
[HttpGet("GetItemMovementById")]
public async Task<IActionResult> GetItemMovementById(int id)
{
try
{
var itemMovement = await _centralDbContext.ItemMovements.FindAsync(id);
if (itemMovement == null)
{
return NotFound("Item movement record not found.");
}
return Ok(itemMovement);
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
#endregion ItemMovement #endregion ItemMovement
#region ItemMovementUser #region ItemMovementUser