This commit is contained in:
Naz 2026-03-27 14:06:14 +08:00
parent 3fdfb9b312
commit d9b8990a9b
2 changed files with 12 additions and 38 deletions

View File

@ -876,7 +876,6 @@
if (newItem && newItem.category === 'Disposable') {
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!
@ -1113,18 +1112,16 @@
}
},
async addItemMovement() {
// 🌟 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
return;
}
// Check if the item is disposable and set serial number accordingly
let itemQuantityToSend = 1;
if (this.thisItem && this.thisItem.category === "Disposable") {
// Ensure serial number is null for disposable items
this.thisItem.serialNumber = null;
itemQuantityToSend = this.quantity; // Use the quantity from the input for disposable
itemQuantityToSend = this.quantity;
}
const now = new Date();
@ -1190,7 +1187,6 @@
try {
// Proceed to send the data to the API
const response = await fetch('/InvMainAPI/AddItemMovement', {
method: 'POST',
headers: {
@ -1304,7 +1300,6 @@
if (response.ok) {
this.thisItem = await response.json();
// 🌟 HIERARCHICAL FIX: Set max quantity based on role
if (this.thisItem.category === 'Disposable') {
this.quantity = 1;

View File

@ -570,27 +570,26 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
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 };
// --- NEW LOGIC FOR DEPT CODE ---
var companyDepartment = await GetDepartmentWithCompany(item.CompanyId, item.DepartmentId);
string? deptCode = companyDepartment!.DepartmentCode?.ToString();
if (product.Category == "Disposable")
{
product.QuantityProduct += item.Quantity;
UpdateQuantityJson(product, deptCode, item.Quantity); // <--- ADDED
UpdateQuantityJson(product, deptCode, item.Quantity);
item.SerialNumber = null;
}
else if (product.Category == "Asset" || product.Category == "Part")
{
product.QuantityProduct = (product.QuantityProduct ?? 0) + 1;
UpdateQuantityJson(product, deptCode, 1); // <--- ADDED
UpdateQuantityJson(product, deptCode, 1);
item.Quantity = 1;
}
// Set CreatedDate when adding a new item
item.CreatedDate = DateTime.Now;
// Explicitly set ModifiedDate to null for a new item
item.ModifiedDate = null; // <--- CHANGE IS HERE
item.ModifiedDate = null;
_centralDbContext.Items.Add(item);
_centralDbContext.Products.Update(product);
@ -620,7 +619,6 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
if (savedItem != null)
{
// (Existing UniqueID logic kept exactly as provided)
var itemProduct = _centralDbContext.Products.Where(p => p.ProductId == item.ProductId).FirstOrDefault();
char? initialCategory = itemProduct!.Category.ToString().Substring(0, 1).ToUpper().FirstOrDefault();
string? productId = itemProduct!.ProductId.ToString("D3");
@ -840,7 +838,6 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
if (products != null)
{
// --- ADDED JSON LOGIC ---
var companyDepartment = await GetDepartmentWithCompany(item.CompanyId, item.DepartmentId);
string? deptCode = companyDepartment?.DepartmentCode?.ToString();
@ -867,7 +864,6 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
}
// --- ADDED THIS FUNCTION TO HANDLE JSON DATA ---
private void UpdateQuantityJson(ProductModel product, string? deptCode, int amount)
{
if (string.IsNullOrEmpty(deptCode)) return;
@ -1115,14 +1111,12 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
if (updateItem != null)
{
// 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;
// --- 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)
@ -1130,7 +1124,6 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
bool isOwnerDepartment = (updateItem.DepartmentId == currentUserDept);
// ONLY affect the Items table quantity if the Owner is sending it
if (isOwnerDepartment)
{
var product = await _centralDbContext.Products.FindAsync(updateItem.ProductId);
@ -1210,8 +1203,7 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
{
if (updatedList.ToOther == "Return" || receiveMovement.LatestStatus == "Ready To Deploy")
{
// --- 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)
@ -1220,7 +1212,6 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
bool isOwnerDepartment = (item.DepartmentId == receiverDept);
// ONLY affect the Items table quantity if the Owner is receiving it back
if (isOwnerDepartment)
{
if (item.Product?.Category == "Disposable")
@ -1233,7 +1224,7 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
}
}
item.ItemStatus = 1; // Mark status as available
item.ItemStatus = 1;
_centralDbContext.Items.Update(item);
}
}
@ -1266,15 +1257,11 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
if (item == null) return NotFound("Item not found.");
// 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.");
// --- 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)
@ -1283,23 +1270,18 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
bool isOwnerDepartment = (item.DepartmentId == senderDept);
// ONLY restore the Items table quantity if the Owner initiated the cancelled movement
if (isOwnerDepartment)
{
// 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();
@ -2209,7 +2191,6 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
var bytes = Convert.FromBase64String(stationMovement.ConsignmentNote);
var uniqueAbjad = new string(Enumerable.Range(0, 8).Select(_ => "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"[new Random().Next(36)]).ToArray());
// FIX: Safely handle null users and clean invalid file characters (just like your Return API)
string safeUserName = string.Join("_", (findUniqueUser?.FullName ?? "Station").Split(Path.GetInvalidFileNameChars()));
string safeModelNo = string.Join("_", (findUniqueCode?.Product?.ModelNo ?? "NA").Split(Path.GetInvalidFileNameChars()));
@ -2227,11 +2208,9 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
await System.IO.File.WriteAllBytesAsync(filePath, bytes);
// Save the safe relative path to the database
stationMovement.ConsignmentNote = "/" + relativePath;
}
// Close the previous active movement record
var currentItem = await _centralDbContext.Items.FindAsync(stationMovement.ItemId);
if (currentItem != null && currentItem.MovementId.HasValue)
{