@@ -215,60 +217,71 @@
app.mount('#registerProduct');
});
const app = Vue.createApp({
- data() {
- return {
- editSection: null,
- productId: null,
- addSection: false,
- productName: null,
- manufacturer: '',
- manufacturers: null,
- category: '',
- categories: ["Asset", "Part", "Disposable"],
- modelNo: null,
- imageProduct: null,
- manufactures: [],
- showOtherManufacturer: false,
- imageSrc: '',
- products: null,
- productDatatable: null,
- productShortName: null,
- }
+ data() {
+ return {
+ editSection: null,
+ productId: null,
+ addSection: false,
+ productName: null,
+ manufacturer: '',
+ manufacturers: null,
+ category: '',
+ categories: ["Asset", "Part", "Disposable"],
+ modelNo: null,
+ imageProduct: null,
+ manufactures: [],
+ showOtherManufacturer: false,
+ imageSrc: '',
+ products: null,
+ productDatatable: null,
+ productShortName: null,
+ existingFileName: null,
+ }
},
mounted() {
// Fetch companies, depts, and products from the API
this.fetchManufactures();
this.fetchProducts();
+ },
+ computed() {
+
},
methods: {
initiateTable() {
this.productDatatable = $('#productDatatable').DataTable({
"data": this.products,
"columns": [
- { "title": "Product Name",
+ {
+ "title": "Product Name",
"data": "productName",
},
- { "title": "Product Short Name",
+ {
+ "title": "Product Short Name",
"data": "productShortName",
},
- { "title": "Model Number",
+ {
+ "title": "Model Number",
"data": "modelNo",
},
- { "title": "Manufacturer",
+ {
+ "title": "Manufacturer",
"data": "manufacturer.manufacturerName",
},
- { "title": "Product Category",
+ {
+ "title": "Product Category",
"data": "category",
},
- { "title": "Product Stock",
+ {
+ "title": "Product Stock",
"data": "quantityProduct",
- },
- { "title": "Image",
+ },
+ {
+ "title": "Image",
"data": "imageProduct",
"render": function (data, type, full, meta) {
var image = `
-
- `;
+

+ `;
return image;
},
},
@@ -279,18 +292,18 @@
var editButton = `
`;
return editButton;
},
- },
- {
+ },
+ {
"title": "Delete",
"data": "productId",
"render": function (data) {
- var deleteButton = `
`;
+ var deleteButton = `
`;
return deleteButton;
- },
+ },
}
],
- responsive:true,
+ responsive: true,
})
self = this;
@@ -301,7 +314,7 @@
});
// Attach click event listener to the delete buttons
- $('#productDatatable tbody').on('click', '.delete-btn', function () {
+ $('#productDatatable tbody').off('click', '.delete-btn').on('click', '.delete-btn', function () {
const productId = $(this).data('id'); // Get the manufacturer ID from the button
self.deleteProduct(productId); // Call the Vue method
});
@@ -310,14 +323,13 @@
},
async fetchManufactures() {
fetch('/InvMainAPI/ManufacturerList', {
- method: 'POST'
- })
+ method: 'POST'
+ })
.then(response => response.json())
.then(data => {
- if (data != null && data.length > 0)
- {
- this.manufacturers = data;
- }
+ if (data != null && data.length > 0) {
+ this.manufacturers = data;
+ }
})
.catch(error => {
console.error('There was a problem with the fetch operation:', error);
@@ -325,13 +337,16 @@
},
async fetchProducts() {
try {
- const response = await fetch('/InvMainAPI/ProductList',{
+ const response = await fetch('/InvMainAPI/ProductList', {
method: 'POST'
}); // Call the API
if (!response.ok) {
throw new Error('Failed to fetch products');
}
this.products = await response.json(); // Store the fetched products
+ if (this.productDatatable) {
+ this.productDatatable.clear().destroy();
+ }
this.$nextTick(() => {
this.initiateTable()
})
@@ -339,74 +354,78 @@
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');
+ 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.manufacturer = product.manufacturer.manufacturerId;
+ this.category = product.category;
+ this.modelNo = product.modelNo;
+ this.imageProduct = product.imageProduct;
+ this.previewImage(this.imageProduct);
+
+ // Show the edit form and hide the add form
+ this.addSection = false;
+ this.editSection = true;
+
+ },
+
+ async submitEditProduct() {
+ const formData = {
+ ProductId: this.productId,
+ productName: this.productName,
+ 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;
}
- // 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;
- }
- },
+ // Refresh station list and reset form
+ alert('Success!', 'Product form has been successfully submitted.', 'success');
+ this.fetchProducts();
+ this.resetForm();
+ this.editSection = false;
+ } catch (error) {
+ console.error('Error editing Product:', error);
+ this.errorMessage = 'Error: ' + error.message;
+ }
+ },
async addProduct() {
// const existingProduct = this.products.find(p => p.modelNo === this.modelNo);
@@ -466,6 +485,7 @@
resetForm() {
this.productName = null;
this.manufacturer = '';
+ this.productShortName = '';
this.category = '';
this.modelNo = null;
this.imageProduct = null;
@@ -494,18 +514,25 @@
// User Inserting an Image
previewImage(event) {
- const file = event.target.files[0];
+ if (typeof event === "string") {
+ this.imageSrc = event;
+ this.existingFileName = event.split('/').pop(); // Ambil nama fail daripada URL
+ return;
+ }
+ const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = (e) => {
- this.imageSrc = e.target.result; // Show the image preview
- this.imageProduct = e.target.result.split(',')[1]; // Get Base64 string (remove metadata)
+ this.imageSrc = e.target.result;
+ this.imageProduct = e.target.result.split(',')[1];
+ this.existingFileName = file.name; // Simpan nama fail
};
reader.readAsDataURL(file);
} else {
this.imageSrc = '';
this.imageProduct = null;
+ this.existingFileName = null;
}
},
async deleteProduct(productId) {
diff --git a/Controllers/API/Inventory/InvMainAPI.cs b/Controllers/API/Inventory/InvMainAPI.cs
index e998b73..0648175 100644
--- a/Controllers/API/Inventory/InvMainAPI.cs
+++ b/Controllers/API/Inventory/InvMainAPI.cs
@@ -199,7 +199,7 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
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))
+ if (product.ImageProduct != editedProduct.ImageProduct)
{
var bytes = Convert.FromBase64String(editedProduct.ImageProduct);
var filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/media/inventory/images", editedProduct.ModelNo + ".jpg");
@@ -368,7 +368,10 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
item.Supplier,
PurchaseDate = item.PurchaseDate.ToString("dd/MM/yyyy"),
item.PONo,
+ item.DONo,
item.Currency,
+ item.InvoiceNo,
+ item.TeamType,
item.DefaultPrice,
item.CurrencyRate,
item.ConvertPrice,
@@ -512,6 +515,104 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
}
}
+ [HttpPost("EditItem")]
+ public async Task
EditItem([FromBody] ItemModel item)
+ {
+ if (!ModelState.IsValid)
+ {
+ return BadRequest(ModelState);
+ }
+
+ try
+ {
+ var savedItem = await _centralDbContext.Items.FirstOrDefaultAsync(i => i.ItemID == item.ItemID);
+ if (savedItem == null)
+ {
+ return NotFound(new { success = false, message = "Item not found" });
+ }
+
+ var product = await _centralDbContext.Products.FirstOrDefaultAsync(p => p.ProductId == item.ProductId) ?? throw new Exception("Product not found");
+
+ if (product.Category == "Disposable")
+ {
+ item.SerialNumber = null;
+ }
+
+ savedItem.ItemID = item.ItemID;
+ savedItem.DefaultPrice = item.DefaultPrice;
+ savedItem.CompanyId = item.CompanyId;
+ savedItem.DepartmentId = item.DepartmentId;
+ savedItem.ProductId = item.ProductId;
+ savedItem.SerialNumber = item.SerialNumber;
+ savedItem.TeamType = item.TeamType;
+ savedItem.Quantity = item.Quantity;
+ savedItem.Supplier = item.Supplier;
+ savedItem.PurchaseDate = item.PurchaseDate;
+ savedItem.PONo = item.PONo;
+ savedItem.Currency = item.Currency;
+ savedItem.CurrencyRate = item.CurrencyRate;
+ savedItem.ConvertPrice = item.ConvertPrice;
+ savedItem.DONo = item.DONo;
+ savedItem.DODate = item.DODate;
+ savedItem.Warranty = item.Warranty;
+ savedItem.EndWDate = item.EndWDate;
+ savedItem.InvoiceNo = item.InvoiceNo;
+ savedItem.InvoiceDate = item.InvoiceDate;
+ savedItem.PartNumber = item.PartNumber;
+ savedItem.UniqueID = item.PartNumber;
+
+
+ _centralDbContext.Items.Update(savedItem);
+
+ await _centralDbContext.SaveChangesAsync(); // This generates the auto-incremented ItemID
+
+ if (savedItem != null)
+ {
+ var companyDepartment = await GetDepartmentWithCompany(item.CompanyId, item.DepartmentId);
+ var itemProduct = _centralDbContext.Products.Where(p => p.ProductId == item.ProductId).FirstOrDefault();
+
+ string? companyInitial = companyDepartment!.CompanyName?.ToString().Substring(0, 1).ToUpper();
+ string? departmentInitial = companyDepartment!.DepartmentName?.ToString().Substring(0, 1).ToUpper();
+ string? deptCode = companyDepartment!.DepartmentCode?.ToString();
+ char? initialCategory = itemProduct!.Category.ToString().Substring(0, 1).ToUpper().FirstOrDefault();
+ string? productId = itemProduct!.ProductId.ToString("D3");
+ string? itemId = item.ItemID.ToString("D5");
+ var uniqueId = $"{deptCode}{initialCategory}{productId}{itemId}".ToUpper();
+ savedItem.UniqueID = uniqueId;
+
+ _centralDbContext.Items.Update(savedItem);
+ await _centralDbContext.SaveChangesAsync();
+ }
+
+ var updatedItem = new
+ {
+ savedItem!.ItemID,
+ savedItem.UniqueID,
+ savedItem.CompanyId,
+ savedItem.DepartmentId,
+ savedItem.ProductId,
+ savedItem.SerialNumber,
+ savedItem.Quantity,
+ savedItem.Supplier,
+ savedItem.PurchaseDate,
+ savedItem.PONo,
+ savedItem.Currency,
+ savedItem.DefaultPrice,
+ savedItem.CurrencyRate,
+ savedItem.ConvertPrice,
+ savedItem.DODate,
+ savedItem.Warranty,
+ savedItem.EndWDate,
+ savedItem.InvoiceDate,
+ savedItem.PartNumber,
+ };
+ return Json(updatedItem);
+ }
+ catch (Exception ex)
+ {
+ return BadRequest(ex.Message);
+ }
+ }
[HttpDelete("DeleteItem/{id}")]
public async Task DeleteItem(int id)
{
diff --git a/appsettings.json b/appsettings.json
index 5b9735b..76db4eb 100644
--- a/appsettings.json
+++ b/appsettings.json
@@ -3,7 +3,7 @@
//"DefaultConnection": "Server=localhost;uid=root;Password='';Database=web_interface;"
//"DefaultConnection": "server=175.136.244.102;user id=root;password=tw_mysql_root;port=3306;database=web_interface"
//"CentralConnnection": "Server=192.168.12.12;Port=3306;uid=installer;password='pstw_mysql_installer';database=pstw_cs;", //DB_dev Local connection
- "CentralConnnection": "Server=219.92.7.60;Port=3307;uid=installer;password='pstw_mysql_installer';database=pstw_cs;" //DB_dev Public connection
+ "CentralConnnection": "Server=219.92.7.60;Port=3307;uid=installer;password='pstw_mysql_installer';database=pstw_cs_prod;" //DB_dev Public connection
//"InventoryConnection": "Server=219.92.7.60;Port=3307;uid=installer;password='pstw_mysql_installer';database=pstw_cs_inventory;" //DB_dev connection
//"DefaultConnection": "Server=219.92.7.60;Port=3307;uid=intern;password='intern_mysql_acct';database=web_interface;"//DB_dev connection
},