Update Inventory Model No.

This commit is contained in:
Naz 2026-01-14 11:34:09 +08:00
parent fa75a383ba
commit 4ebac3888e
7 changed files with 108 additions and 37 deletions

View File

@ -17,5 +17,8 @@ namespace PSTW_CentralSystem.Areas.Inventory.Models
[ForeignKey("ManufacturerId")] [ForeignKey("ManufacturerId")]
public virtual ManufacturerModel? Manufacturer { get; set; } public virtual ManufacturerModel? Manufacturer { get; set; }
public virtual ICollection<ItemModel>? Items { get; set; } // Navigation property> public virtual ICollection<ItemModel>? Items { get; set; } // Navigation property>
[System.ComponentModel.DataAnnotations.Schema.NotMapped]
public string? ImageFileName { get; set; }
} }
} }

View File

@ -70,7 +70,10 @@
<div class="form-group row"> <div class="form-group row">
<label for="modelNo" class="col-sm-3">Model No:</label> <label for="modelNo" class="col-sm-3">Model No:</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" id="modelNo" name="modelNo" class="form-control" required v-model="modelNo"> <input type="text" id="modelNo" name="modelNo" class="form-control"
required v-model="modelNo"
:disabled="category === 'Disposable'"
:placeholder="category === 'Disposable' ? 'N/A' : ''">
</div> </div>
</div> </div>
@ -238,6 +241,17 @@
existingFileName: null, existingFileName: null,
} }
}, },
watch: {
category(newVal) {
// If user clicks Disposable, auto-fill N/A
if (newVal === 'Disposable') {
this.modelNo = 'N/A';
} else {
// Clear it if they switch back to Asset/Part so they can type
if (this.modelNo === 'N/A') this.modelNo = '';
}
}
},
mounted() { mounted() {
// Fetch companies, depts, and products from the API // Fetch companies, depts, and products from the API
this.fetchManufactures(); this.fetchManufactures();
@ -387,7 +401,8 @@
ManufacturerId: this.manufacturer, ManufacturerId: this.manufacturer,
category: this.category, category: this.category,
ModelNo: this.modelNo, ModelNo: this.modelNo,
ImageProduct: this.imageProduct ImageProduct: this.imageProduct,
ImageFileName: this.existingFileName
}; };
try { try {
@ -441,7 +456,8 @@
manufacturerId: this.manufacturer, manufacturerId: this.manufacturer,
category: this.category, category: this.category,
modelNo: this.modelNo, modelNo: this.modelNo,
imageProduct: this.imageProduct imageProduct: this.imageProduct,
ImageFileName: this.existingFileName
}; };
try { try {
@ -512,21 +528,20 @@
} }
}, },
// User Inserting an Image
previewImage(event) { previewImage(event) {
if (typeof event === "string") { if (typeof event === "string") {
this.imageSrc = event; this.imageSrc = event;
this.existingFileName = event.split('/').pop(); // Ambil nama fail daripada URL this.existingFileName = event.split('/').pop();
return; return;
} }
const file = event.target.files[0]; const file = event.target.files[0];
if (file) { if (file) {
this.existingFileName = file.name;
const reader = new FileReader(); const reader = new FileReader();
reader.onload = (e) => { reader.onload = (e) => {
this.imageSrc = e.target.result; this.imageSrc = e.target.result;
this.imageProduct = e.target.result.split(',')[1]; this.imageProduct = e.target.result.split(',')[1];
this.existingFileName = file.name; // Simpan nama fail
}; };
reader.readAsDataURL(file); reader.readAsDataURL(file);
} else { } else {

View File

@ -207,29 +207,69 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
} }
// HELPER FUNCTION TO HANDLE DUPLICATE NAMES e.g. image(1).jpg
private string GetUniqueFilePath(string folderPath, string fileName)
{
string nameWithoutExt = Path.GetFileNameWithoutExtension(fileName);
string extension = Path.GetExtension(fileName);
string fullPath = Path.Combine(folderPath, fileName);
int count = 1;
while (System.IO.File.Exists(fullPath))
{
string tempFileName = $"{nameWithoutExt}({count}){extension}";
fullPath = Path.Combine(folderPath, tempFileName);
count++;
}
return fullPath;
}
[HttpPost("AddProduct")] [HttpPost("AddProduct")]
public async Task<IActionResult> AddProduct([FromBody] ProductModel product) public async Task<IActionResult> AddProduct([FromBody] ProductModel product)
{ {
if (!ModelState.IsValid) if (!ModelState.IsValid) return BadRequest(ModelState);
{ if (product == null) return NotFound("Product is null");
return BadRequest(ModelState);
}
if (product == null)
{
return NotFound("Product is null");
}
try try
{ {
product.QuantityProduct = 0; product.QuantityProduct = 0;
var productImage = product.ImageProduct;
// --- LOGIC START ---
if (product.Category == "Disposable")
{
// 1. Force ModelNo to N/A for Disposable
product.ModelNo = "N/A";
// 2. Save using Original Filename with (1) logic
if (!string.IsNullOrEmpty(product.ImageProduct) && !string.IsNullOrEmpty(product.ImageFileName))
{
var bytes = Convert.FromBase64String(product.ImageProduct);
var folderPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/media/inventory/images");
if (!Directory.Exists(folderPath)) Directory.CreateDirectory(folderPath);
// Get unique path (e.g., mouse(1).png)
string fullPath = GetUniqueFilePath(folderPath, product.ImageFileName);
await System.IO.File.WriteAllBytesAsync(fullPath, bytes);
// Save relative path to DB
product.ImageProduct = "/media/inventory/images/" + Path.GetFileName(fullPath);
}
}
else
{
// OLD LOGIC FOR ASSETS/PARTS (Preserved)
if (!string.IsNullOrEmpty(product.ImageProduct)) if (!string.IsNullOrEmpty(product.ImageProduct))
{ {
var bytes = Convert.FromBase64String(product.ImageProduct); var bytes = Convert.FromBase64String(product.ImageProduct);
var filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/media/inventory/images", product.ModelNo + ".jpg"); var filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/media/inventory/images", product.ModelNo + ".jpg");
await System.IO.File.WriteAllBytesAsync(filePath, bytes); await System.IO.File.WriteAllBytesAsync(filePath, bytes);
product.ImageProduct = "/media/inventory/images/" + product.ModelNo + ".jpg"; product.ImageProduct = "/media/inventory/images/" + product.ModelNo + ".jpg";
} }
}
_centralDbContext.Products.Add(product); _centralDbContext.Products.Add(product);
await _centralDbContext.SaveChangesAsync(); await _centralDbContext.SaveChangesAsync();
var updatedList = await _centralDbContext.Products.Include("Manufacturer").Where(x => x.ManufacturerId == x.ManufacturerId).ToListAsync(); var updatedList = await _centralDbContext.Products.Include("Manufacturer").Where(x => x.ManufacturerId == x.ManufacturerId).ToListAsync();
@ -244,19 +284,32 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
[HttpPost("EditProduct")] [HttpPost("EditProduct")]
public async Task<IActionResult> EditProduct([FromBody] ProductModel editedProduct) public async Task<IActionResult> EditProduct([FromBody] ProductModel editedProduct)
{ {
if (!ModelState.IsValid) if (!ModelState.IsValid) return BadRequest(ModelState);
{
return BadRequest(ModelState);
}
var product = await _centralDbContext.Products.FindAsync(editedProduct.ProductId); var product = await _centralDbContext.Products.FindAsync(editedProduct.ProductId);
if (product == null) if (product == null) return NotFound("Product is null");
{
return NotFound("Product is null");
}
try try
{ {
var productImage = editedProduct.ImageProduct; // Save image to wwwroot/media/inventory/images | Images name is product.ModelNo | product.ImageProduct is in base64 string if (editedProduct.Category == "Disposable")
{
editedProduct.ModelNo = "N/A";
if (product.ImageProduct != editedProduct.ImageProduct && !string.IsNullOrEmpty(editedProduct.ImageFileName))
{
var bytes = Convert.FromBase64String(editedProduct.ImageProduct);
var folderPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/media/inventory/images");
if (!Directory.Exists(folderPath)) Directory.CreateDirectory(folderPath);
string fullPath = GetUniqueFilePath(folderPath, editedProduct.ImageFileName);
await System.IO.File.WriteAllBytesAsync(fullPath, bytes);
editedProduct.ImageProduct = "/media/inventory/images/" + Path.GetFileName(fullPath);
}
}
else
{
// OLD LOGIC FOR ASSETS/PARTS (Preserved)
if (product.ImageProduct != editedProduct.ImageProduct) if (product.ImageProduct != editedProduct.ImageProduct)
{ {
var bytes = Convert.FromBase64String(editedProduct.ImageProduct); var bytes = Convert.FromBase64String(editedProduct.ImageProduct);
@ -264,6 +317,7 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
await System.IO.File.WriteAllBytesAsync(filePath, bytes); await System.IO.File.WriteAllBytesAsync(filePath, bytes);
editedProduct.ImageProduct = "/media/inventory/images/" + editedProduct.ModelNo + ".jpg"; editedProduct.ImageProduct = "/media/inventory/images/" + editedProduct.ModelNo + ".jpg";
} }
}
product.ProductName = editedProduct.ProductName; product.ProductName = editedProduct.ProductName;
product.ProductShortName = editedProduct.ProductShortName; product.ProductShortName = editedProduct.ProductShortName;
@ -272,7 +326,6 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
product.ModelNo = editedProduct.ModelNo; product.ModelNo = editedProduct.ModelNo;
product.ImageProduct = editedProduct.ImageProduct; product.ImageProduct = editedProduct.ImageProduct;
_centralDbContext.Products.Update(product); _centralDbContext.Products.Update(product);
await _centralDbContext.SaveChangesAsync(); await _centralDbContext.SaveChangesAsync();

View File

@ -2,8 +2,8 @@
"ConnectionStrings": { "ConnectionStrings": {
//"DefaultConnection": "Server=localhost;uid=root;Password='';Database=web_interface;" //"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" //"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=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 dev Public connection //"CentralConnnection": "Server=219.92.7.60;Port=3307;uid=installer;password='pstw_mysql_installer';database=pstw_cs;", //DB_dev dev Public connection
//"CentralConnnection": "Server=219.92.7.60;Port=3307;uid=installer;password='pstw_mysql_installer';database=pstw_cs_prod;", //DB_dev prod connection //"CentralConnnection": "Server=219.92.7.60;Port=3307;uid=installer;password='pstw_mysql_installer';database=pstw_cs_prod;", //DB_dev prod connection
//"DefaultConnection": "Server=219.92.7.60;Port=3307;uid=intern;password='intern_mysql_acct';database=web_interface;",//DB_dev connection //"DefaultConnection": "Server=219.92.7.60;Port=3307;uid=intern;password='intern_mysql_acct';database=web_interface;",//DB_dev connection
//"CentralConnnection": "Server=192.168.12.13;Port=3306;uid=installer;password='pstw_mysql_installer';database=pstw_cs_prod;", // DB_prod live connection //"CentralConnnection": "Server=192.168.12.13;Port=3306;uid=installer;password='pstw_mysql_installer';database=pstw_cs_prod;", // DB_prod live connection

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB