From f4280b9645e6e5c4bda9113b2a0a9971c59e2467 Mon Sep 17 00:00:00 2001 From: ArifHilmi Date: Mon, 17 Mar 2025 10:31:07 +0800 Subject: [PATCH] Update Item & Station --- .../InventoryMaster/ItemRegistration.cshtml | 2 +- .../InventoryMaster/ItemRequestMaster.cshtml | 5 +- .../ProductRegistration.cshtml | 187 +++++++++++++++++- .../StationRegistration.cshtml | 139 +++++++++++++ .../Inventory/Views/_InventoryPartial.cshtml | 2 +- .../Views/_InventoryPartialUser.cshtml | 2 +- Controllers/API/Inventory/InvMainAPI.cs | 77 +++++++- Views/Shared/_Layout.cshtml | 20 +- 8 files changed, 414 insertions(+), 20 deletions(-) diff --git a/Areas/Inventory/Views/InventoryMaster/ItemRegistration.cshtml b/Areas/Inventory/Views/InventoryMaster/ItemRegistration.cshtml index 90cb1b6..f09dee1 100644 --- a/Areas/Inventory/Views/InventoryMaster/ItemRegistration.cshtml +++ b/Areas/Inventory/Views/InventoryMaster/ItemRegistration.cshtml @@ -614,7 +614,7 @@ }, { "title": "Price(RM)", - "data": "convertPrice", + "data": (row) => parseFloat(row.convertPrice).toFixed(2), }, { "title": "Register Date", diff --git a/Areas/Inventory/Views/InventoryMaster/ItemRequestMaster.cshtml b/Areas/Inventory/Views/InventoryMaster/ItemRequestMaster.cshtml index e154879..86a7560 100644 --- a/Areas/Inventory/Views/InventoryMaster/ItemRequestMaster.cshtml +++ b/Areas/Inventory/Views/InventoryMaster/ItemRequestMaster.cshtml @@ -65,8 +65,8 @@

Sort by:

@@ -407,7 +407,6 @@ - @section Scripts { diff --git a/Areas/Inventory/Views/InventoryMaster/ProductRegistration.cshtml b/Areas/Inventory/Views/InventoryMaster/ProductRegistration.cshtml index 0d50396..70e013f 100644 --- a/Areas/Inventory/Views/InventoryMaster/ProductRegistration.cshtml +++ b/Areas/Inventory/Views/InventoryMaster/ProductRegistration.cshtml @@ -99,11 +99,106 @@
- + +
+ +
+
+
+
+
+
+
+
+

EDIT PRODUCT

+
+
+
+ + @* Product Name *@ +
+ +
+ +
+
+ + @* Product Short Name *@ +
+ +
+ +

* Product short name limited to 13 characters

+
+
+ + @* Manufacturer *@ +
+ +
+
+ +
+
+
+ + @* Category *@ +
+ +
+
+ +
+
+
+ +
+
+ + @* Model No Coding *@ +
+ +
+ +
+
+ + @* Image Product Coding *@ +
+ +
+ +
+ Image Preview +
+
+ +
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
- +
@@ -122,6 +217,8 @@ const app = Vue.createApp({ data() { return { + editSection: null, + productId: null, addSection: false, productName: null, manufacturer: '', @@ -165,7 +262,7 @@ }, { "title": "Product Stock", "data": "quantityProduct", - }, + }, { "title": "Image", "data": "imageProduct", "render": function (data, type, full, meta) { @@ -175,6 +272,14 @@ return image; }, }, + { + "title": "Edit", + "data": "productId", + "render": function (data) { + var editButton = ``; + return editButton; + }, + }, { "title": "Delete", "data": "productId", @@ -188,6 +293,13 @@ responsive:true, }) self = this; + + // Attach click event listener to the edit buttons + $('#productDatatable tbody').off('click', '.edit-btn').on('click', '.edit-btn', function () { + const productId = $(this).data('id'); + self.editProduct(productId); + }); + // Attach click event listener to the delete buttons $('#productDatatable tbody').on('click', '.delete-btn', function () { const productId = $(this).data('id'); // Get the manufacturer ID from the button @@ -227,6 +339,75 @@ console.error('Error fetching products:', error); } }, + async editProduct(productId) { + // Find the selected station data + const product = this.products.find(s => s.productId === productId); + if (!product) { + alert('Error', 'Product not found!', 'warning'); + return; + } + + // Populate form fields + this.productId = productId; + this.productName = product.productName; + this.stationName = product.stationName; + this.productShortName = product.productShortName; + this.manufacturers = product.manufacturer; + this.category = product.category; + this.modelNo = product.modelNo; + console.log(this.manufactures); + // Show the edit form and hide the add form + this.addSection = false; + this.editSection = true; + }, + + async submitEditProduct() { + const formData = { + ProductId: this.productId, + productName: this.stationName, + ProductShortName: this.productShortName, + ManufacturerId: this.manufacturer, + category: this.category, + ModelNo: this.modelNo, + ImageProduct: this.imageProduct + }; + + try { + // List of required fields + const requiredFields = ['productName', 'manufacturer', 'category', 'modelNo', 'imageProduct']; + + // Loop through required fields and check if any are null or empty + for (let field of requiredFields) { + if (this[field] === null || this[field] === '') { + alert('Product Error', `Please fill in required fields: ${field}.`, 'warning'); + return; // Exit early if validation fails + } + } + const response = await fetch('/InvMainAPI/EditProduct', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(formData) + }); + + if (!response.ok) { + const errorData = await response.json(); + console.error('Error response:', errorData); + this.errorMessage = 'Error: ' + (errorData.message || 'Unknown error'); + return; + } + + // Refresh station list and reset form + await this.fetchProducts(); + this.resetForm(); + this.editSection = false; + } catch (error) { + console.error('Error editing station:', error); + this.errorMessage = 'Error: ' + error.message; + } + }, + async addProduct() { // const existingProduct = this.products.find(p => p.modelNo === this.modelNo); // if (existingProduct) { diff --git a/Areas/Inventory/Views/InventoryMaster/StationRegistration.cshtml b/Areas/Inventory/Views/InventoryMaster/StationRegistration.cshtml index 9b49354..480d85f 100644 --- a/Areas/Inventory/Views/InventoryMaster/StationRegistration.cshtml +++ b/Areas/Inventory/Views/InventoryMaster/StationRegistration.cshtml @@ -51,6 +51,66 @@
+ +
+
+ + +
+
+ + + + + + + +
+
+
+
+
+
+

EDIT STATION

+
+
+ + @* Station Name *@ +
+ +
+ +
+
+ + @* User ID *@ +
+ +
+
+ +
+
+
+ + @* Department ID *@ + +
+ +
+ + {{ selectedDepartment }} + No department assigned +
+
+ +
@@ -95,6 +155,7 @@ const app = Vue.createApp({ data() { return { + stationId: null, stationName: null, stationUserPIC: null, departmentId : null, @@ -104,6 +165,7 @@ currentUser: null, users : null, registerStationForm: false, + editStationForm: false, } }, mounted() { @@ -235,6 +297,14 @@ "title": "Department", "data": "departmentName", }, + { + "title": "Edit", + "data": "stationId", + "render": function (data) { + var editButton = ``; + return editButton; + }, + }, { "title": "Delete", "data": "stationId", @@ -247,6 +317,11 @@ responsive: true, }) + // Attach click event listener to the edit buttons + $('#stationDatatable tbody').off('click', '.edit-btn').on('click', '.edit-btn', function () { + const stationId = $(this).data('id'); + self.editStation(stationId); + }); // Attach click event listener to the delete buttons $('#stationDatatable tbody').off('click', '.delete-btn').on('click', '.delete-btn', function () { @@ -266,6 +341,70 @@ this.selectedDepartment = selectedUser.department.departmentName; // Set department name } }, + async editStation(stationId) { + // Find the selected station data + const station = this.stations.find(s => s.stationId === stationId); + if (!station) { + alert('Error', 'Station not found!', 'warning'); + return; + } + + // Populate form fields + this.stationId = stationId; + this.stationName = station.stationName; + this.selectedUserName = station.fullName; + this.departmentId = station.departmentId; + this.selectedDepartment = station.departmentName; + this.stationUserPIC = station.stationPicID; + + // Show the edit form and hide the add form + this.registerStationForm = false; + this.editStationForm = true; + }, + + async submitEditStation() { + const formData = { + StationId: this.stationId, + StationName: this.stationName, + StationPicID: this.stationUserPIC, + DepartmentId: this.departmentId, + }; + + try { + // Ensure all required fields are filled + const requiredFields = ['stationName', 'stationUserPIC', 'departmentId']; + for (let field of requiredFields) { + if (!this[field]) { + alert('Error', `Please fill in required fields: ${field}`, 'warning'); + return; + } + } + + const response = await fetch('/InvMainAPI/EditStation', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(formData) + }); + + if (!response.ok) { + const errorData = await response.json(); + console.error('Error response:', errorData); + this.errorMessage = 'Error: ' + (errorData.message || 'Unknown error'); + return; + } + + // Refresh station list and reset form + await this.fetchStations(); + this.resetForm(); + this.editStationForm = false; + } catch (error) { + console.error('Error editing station:', error); + this.errorMessage = 'Error: ' + error.message; + } + }, + async deleteStation(stationId) { if (!confirm("Are you sure you want to delete this station?")) { return; diff --git a/Areas/Inventory/Views/_InventoryPartial.cshtml b/Areas/Inventory/Views/_InventoryPartial.cshtml index 0179e8e..c5bb025 100644 --- a/Areas/Inventory/Views/_InventoryPartial.cshtml +++ b/Areas/Inventory/Views/_InventoryPartial.cshtml @@ -94,7 +94,7 @@

-
QR Scanner
+
Scan Items
diff --git a/Areas/Inventory/Views/_InventoryPartialUser.cshtml b/Areas/Inventory/Views/_InventoryPartialUser.cshtml index f7517c2..63f2646 100644 --- a/Areas/Inventory/Views/_InventoryPartialUser.cshtml +++ b/Areas/Inventory/Views/_InventoryPartialUser.cshtml @@ -20,7 +20,7 @@

-
QR Scanner
+
Scan Items
diff --git a/Controllers/API/Inventory/InvMainAPI.cs b/Controllers/API/Inventory/InvMainAPI.cs index fe4cebf..e998b73 100644 --- a/Controllers/API/Inventory/InvMainAPI.cs +++ b/Controllers/API/Inventory/InvMainAPI.cs @@ -183,6 +183,50 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory } } + [HttpPost("EditProduct")] + public async Task EditProduct([FromBody] ProductModel editedProduct) + { + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + var product = await _centralDbContext.Products.FindAsync(editedProduct.ProductId); + if (product == null) + { + return NotFound("Product is null"); + } + + try + { + var productImage = editedProduct.ImageProduct; // Save image to wwwroot/media/inventory/images | Images name is product.ModelNo | product.ImageProduct is in base64 string + if (!string.IsNullOrEmpty(editedProduct.ImageProduct)) + { + var bytes = Convert.FromBase64String(editedProduct.ImageProduct); + var filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/media/inventory/images", editedProduct.ModelNo + ".jpg"); + await System.IO.File.WriteAllBytesAsync(filePath, bytes); + editedProduct.ImageProduct = "/media/inventory/images/" + editedProduct.ModelNo + ".jpg"; + } + + product.ProductName = editedProduct.ProductName; + product.ProductShortName = editedProduct.ProductShortName; + product.ManufacturerId = editedProduct.ManufacturerId; + product.Category = editedProduct.Category; + product.ModelNo = editedProduct.ModelNo; + product.ImageProduct = editedProduct.ImageProduct; + + + _centralDbContext.Products.Update(product); + await _centralDbContext.SaveChangesAsync(); + + var updatedList = await _centralDbContext.Products.Include("Manufacturer").Where(x => x.ManufacturerId == x.ManufacturerId).ToListAsync(); + return Json(updatedList); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } + } + [HttpDelete("DeleteProduct/{id}")] public async Task DeleteProduct(int id) { @@ -383,7 +427,6 @@ 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 }; var addToProduct = item.Quantity; - product.QuantityProduct += addToProduct; if (product.Category == "Disposable") { @@ -391,6 +434,8 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory } _centralDbContext.Items.Add(item); + + product.QuantityProduct += addToProduct; _centralDbContext.Products.Update(product); await _centralDbContext.SaveChangesAsync(); // This generates the auto-incremented ItemID @@ -476,6 +521,11 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory return NotFound(new { success = false, message = "Item not found" }); } + var products = _centralDbContext.Products + .FirstOrDefault(i => i.ProductId == item.ProductId); + + products.QuantityProduct = products.QuantityProduct - 1; + // Get related item movements var itemMovements = await _centralDbContext.ItemMovements .Where(i => i.ItemId == item.ItemID) @@ -488,6 +538,10 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory await _centralDbContext.SaveChangesAsync(); } + //Handle Rules kalau itemMovement dia xde kat store + + _centralDbContext.Products.Update(products); + // Remove the item itself _centralDbContext.Items.Remove(item); await _centralDbContext.SaveChangesAsync(); @@ -1264,6 +1318,27 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory return BadRequest(ex.Message); } } + + + [HttpPost("EditStation")] + public async Task EditStation([FromBody] StationModel updatedStation) + { + var station = await _centralDbContext.Stations.FindAsync(updatedStation.StationId); + if (station == null) + { + return NotFound(new { success = false, message = "Station not found" }); + } + + station.StationId = updatedStation.StationId; + station.StationPicID = updatedStation.StationPicID; + station.StationName = updatedStation.StationName; + station.DepartmentId = updatedStation.DepartmentId; + + _centralDbContext.Stations.Update(station); + await _centralDbContext.SaveChangesAsync(); + + return Ok(new { success = true, message = "Station Updated successfully" }); + } [HttpDelete("DeleteStation/{id}")] public async Task DeleteStation(int id) diff --git a/Views/Shared/_Layout.cshtml b/Views/Shared/_Layout.cshtml index 3b96819..760f41d 100644 --- a/Views/Shared/_Layout.cshtml +++ b/Views/Shared/_Layout.cshtml @@ -355,14 +355,14 @@ -
- + *@