This commit is contained in:
ArifHilmi 2024-11-26 16:26:56 +08:00
parent b378c73152
commit f9666d341c
31 changed files with 133819 additions and 106 deletions

View File

@ -0,0 +1,13 @@
using Microsoft.AspNetCore.Mvc;
namespace PSTW_CentralSystem.Areas.Inventory.Controllers.Admin
{
[Area("Inventory")]
public class InventoryAdminController : Controller
{
public IActionResult AdminDashboard()
{
return View();
}
}
}

View File

@ -1,9 +1,10 @@
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace PSTW_CentralSystem.Controllers.Inventory namespace PSTW_CentralSystem.Areas.Inventory.Controllers
{ {
public class InventoryController : Controller [Area("Inventory")]
public class ItemController : Controller
{ {
// GET: Inventory // GET: Inventory
public ActionResult Index() public ActionResult Index()
@ -11,6 +12,16 @@ namespace PSTW_CentralSystem.Controllers.Inventory
return View(); return View();
} }
public IActionResult ItemRegistration()
{
return View();
}
public IActionResult ProductRegistration()
{
return View();
}
// GET: Inventory/Details/5 // GET: Inventory/Details/5
public ActionResult Details(int id) public ActionResult Details(int id)
{ {

View File

@ -0,0 +1,95 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace PSTW_CentralSystem.Areas.Inventory.Controllers
{
[Area("Inventory")]
//[Route("Inventory/[controller]/[action]")]
public class MainController : Controller
{
// GET: Inventory
public ActionResult Index()
{
return View();
}
public IActionResult SupplierRegistration()
{
return View();
}
public IActionResult ManifacturerRegistration()
{
return View();
}
// GET: Inventory/Details/5
public ActionResult Details(int id)
{
return View();
}
// GET: Inventory/Create
public ActionResult Create()
{
return View();
}
// POST: Inventory/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(IFormCollection collection)
{
try
{
return RedirectToAction(nameof(Index));
}
catch
{
return View();
}
}
// GET: Inventory/Edit/5
public ActionResult Edit(int id)
{
return View();
}
// POST: Inventory/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(int id, IFormCollection collection)
{
try
{
return RedirectToAction(nameof(Index));
}
catch
{
return View();
}
}
// GET: Inventory/Delete/5
public ActionResult Delete(int id)
{
return View();
}
// POST: Inventory/Delete/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Delete(int id, IFormCollection collection)
{
try
{
return RedirectToAction(nameof(Index));
}
catch
{
return View();
}
}
}
}

View File

@ -0,0 +1,11 @@
using System.ComponentModel.DataAnnotations;
namespace PSTW_CentralSystem.Areas.Inventory.Models
{
public class CompanyModel
{
[Key]
public int CompanyId { get; set; }
public required string Name { get; set; }
}
}

View File

@ -0,0 +1,15 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace PSTW_CentralSystem.Areas.Inventory.Models
{
public class DepartmentModel
{
[Key]
public int DepartmentId { get; set; }
public required string Name { get; set; }
public required int CompanyId { get; set; }
[ForeignKey("CompanyId")]
public virtual required CompanyModel Company { get; set; }
}
}

View File

@ -0,0 +1,33 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace PSTW_CentralSystem.Areas.Inventory.Models
{
public class ItemModel
{
[Key]
public required string ItemID { get; set; }
public required int CompanyId { get; set; }
public required int DepartmentId { get; set; }
public required int ProductId { get; set; }
public required string SerialNumber { get; set; }
public required int Quantity { get; set; }
public required string Supplier { get; set; }
public required DateTime PurchaseDate { get; set; }
public required string PONo { get; set; }
public required string Currency { get; set; }
public required float PriceInRM { get; set; }
public required float CurrencyRate { get; set; }
public required float ConvertPrice { get; set; }
public required DateTime DODate { get; set; }
public required int Warranty { get; set; }
public required DateTime EndWDate { get; set; }
public required DateTime InvoiceDate { get; set; }
[ForeignKey("CompanyId")]
public required virtual CompanyModel Company { get; set; }
[ForeignKey("DepartmentId")]
public required virtual DepartmentModel Department { get; set; }
[ForeignKey("ProductId")]
public required virtual ProductModel Product { get; set; }
}
}

View File

@ -0,0 +1,11 @@
using System.ComponentModel.DataAnnotations;
namespace PSTW_CentralSystem.Areas.Inventory.Models
{
public class ManufacturerModel
{
[Key]
public int ManufacturerId { get; set; }
public required string ManufacturerName { get; set; }
}
}

View File

@ -0,0 +1,20 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace PSTW_CentralSystem.Areas.Inventory.Models
{
public class ProductModel
{
[Key]
public int ProductId { get; set; }
public required string ProductName { get; set; }
public required string Manufacturer { get; set; }
public required string Category { get; set; }
public required string ModelNo { get; set; }
public required int QuantityProduct { get; set; }
public required string ImageProduct { get; set; }
public required int CompanyId { get; set; }
[ForeignKey("CompanyId")]
public required virtual CompanyModel Company { get; set; }
}
}

View File

@ -0,0 +1,14 @@
using System.ComponentModel.DataAnnotations;
namespace PSTW_CentralSystem.Areas.Inventory.Models
{
public class SupplierModel
{
[Key]
public int SupplierId { get; set; }
public required string SupplierName { get; set; }
public required string SupplierGender { get; set; }
public required string SupplierEmail { get; set; }
public required string SupplierPhoneNo { get; set; }
}
}

View File

@ -0,0 +1,12 @@
@{
ViewData["Title"] = "PSTW Centralized System";
Layout = "~/Views/Shared/_Layout.cshtml";
}
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<div class="row">
<div class="text-center">
<h1 class="display-4">Inventory Admin Dashboard</h1>
<p>Learn about <a href="https://learn.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>
</div>
@await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml");

View File

@ -0,0 +1,595 @@

@{
ViewData["Title"] = "Item Form";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div id="registerItem">
<form v-on:submit.prevent="addItem" data-aos="fade-right">
<div class="container register" data-aos="fade-right">
<div class="row" data-aos="fade-right">
@*Left Side*@
<div class="col-md-3 register-left">
<img src="https://media.licdn.com/dms/image/C4E03AQEJ_X-GwTi3xg/profile-displayphoto-shrink_200_200/0/1607307680517?e=2147483647&v=beta&t=UL8IX1nO9iqRxGrQrNZ1O_i4tpjnOVVecIktw-GB6QI" alt="" />
<h3>Welcome</h3>
<p>Registration Product! Click button to go Product Page</p>
<a href="@Url.Action("Product", "Home")" class="btn btn-primary">Product Registration</a><br />
</div>
@*Right Side*@
<div class="col-md-9 register-right">
<div class="tab-content" id="myTabContent">
<div class="tab-pane fade show active" id="home" role="tabpanel" aria-labelledby="home-tab">
<h3 class="register-heading">REGISTRATION ITEM</h3>
<div class="row register-form">
<div class="col-md-6">
<!-- Company Dropdown -->
<div class="form-group row">
<label class="col-sm-3 col-form-label">Company:</label>
<div class="col-sm-9">
<div class="dropdown">
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
<span id="updateCompany">{{ company || 'Select Company' }}</span>
</button>
<div class="dropdown-menu p-3">
<div v-for="(comp, index) in companies" :key="index" class="form-check">
<input class="form-check-input" type="radio" :id="'company-' + index" :value="comp.Name" name="company" v-model="company" v-on:change="updateDepts(comp.Departments)">
<label class="form-check-label" :for="'company-' + index">{{ comp.Name }}</label>
</div>
</div>
</div>
</div>
</div>
<!-- Department Dropdown -->
<div class="form-group row">
<label class="col-sm-3 col-form-label">Department:</label>
<div class="col-sm-9">
<div class="dropdown">
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
<span id="updateDept">{{ Dept || 'Select Dept/Div' }}</span>
</button>
<div class="dropdown-menu p-3">
<div v-for="(dept, index) in depts" :key="index" class="form-check">
<input class="form-check-input" type="radio" :id="'Dept-' + index" :value="dept" name="Dept" v-model="Dept">
<label class="form-check-label" :for="'Dept-' + index">{{ dept }}</label>
</div>
</div>
</div>
</div>
</div>
@* Product Name Coding *@
<div class="form-group row">
<label class="col-sm-3 col-form-label">Product Name:</label>
<div class="col-sm-9">
<div class="dropdown">
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
<span id="updateName">{{ productName || 'Select Product Name' }}</span>
</button>
<div class="dropdown-menu p-3">
<div class="form-check" v-for="product in products" :key="product.modelNo">
<!-- Use modelNo as the key -->
<input class="form-check-input" type="radio" :id="product.modelNo" :value="product.modelNo"
v-on:click="updateProduct(product)" v-model="selectedProduct">
<label class="form-check-label" :for="product.modelNo">{{ product.productName }}</label>
</div>
</div>
</div>
</div>
</div>
@* Product Image Display *@
<div class="form-group row align-items-center">
<label for="imageProduct" class="col-sm-3 col-form-label">Product Image: </label>
<div class="col-sm-9">
<img v-if="imageProduct" :src="'data:image/png;base64,' + imageProduct" alt="Product Image" class="img-fluid" v-on:click="openModal" />
<input type="hidden" id="imageProduct" name="imageProduct" v-model="imageProduct">
</div>
</div>
<div v-if="isModalOpen" class="modal" v-on:click="closeModal">
<div class="modal-content" v-on:click.stop>
<span class="close" v-on:click="closeModal">&times;</span>
<img :src="'data:image/png;base64,' + imageProduct" alt="Product Image" class="enlarged-image" />
</div>
</div>
@* Product Category Coding *@
<div class="form-group row">
<label class="col-sm-3 col-form-label">Product Category:</label>
<div class="col-sm-9">
<div class="dropdown">
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
<span id="updateProductCategory">{{ productCategory || 'Select Product' }}</span>
</button>
<div class="dropdown-menu p-3">
<div class="form-check">
<input class="form-check-input" type="radio" name="productCategory" id="item" value="Item" v-on:click="updateProductCategory('Item')" v-model="productCategory">
<label class="form-check-label" for="item">Item</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="productCategory" id="part" value="Part" v-on:click="updateProductCategory('Part')" v-model="productCategory">
<label class="form-check-label" for="part">Part</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="productCategory" id="disposable" value="Disposable" v-on:click="updateProductCategory('Disposable')" v-model="productCategory">
<label class="form-check-label" for="disposable">Disposable</label>
</div>
</div>
</div>
</div>
</div>
@* Serial Number and Quantity Coding *@
<div v-if="showSerialNumber">
<div class="form-group row align-items-center">
<div class="col-sm-3">
<label for="serialNumber">Serial Number: </label>
</div>
<div class="col-sm-9">
<input type="text" id="serialNumber" name="serialNumber" v-if="showSerialNumber" v-model="serialNumber" class="form-control">
</div>
</div>
</div>
<div v-if="!showSerialNumber">
<div class="form-group row align-items-center">
<div class="col-sm-3">
<label for="quantity">Quantity: </label>
</div>
<div class="col-sm-9">
<input type="number" id="quantity" name="quantity" v-if="!showSerialNumber" v-model="quantity" class="form-control">
</div>
</div>
</div>
@* Supplier coding *@
<div class="form-group row align-items-center">
<label class="col-sm-3 col-form-label">Supplier: </label>
<div class="col-sm-9">
<div class="dropdown">
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
<span id="updateSupplierName">{{ supplierName || 'Select Supplier' }}</span>
</button>
<div class="dropdown-menu p-3">
<div class="form-check" v-for="supplier in supplies" :key="supplier.modelNoes">
<input class="form-check-input" type="radio" :id="supplier.modelNoes" :value="supplier.supplierName" v-on:click="updateSupplier(supplier)" v-model="selectedSupplier">
<label class="form-check-label" :for="supplier.modelNoes">{{ supplier.supplierName }}</label>
</div>@*
<div class="form-check">
<input class="form-check-input" type="radio" name="Supplier" id="otherS" v-on:click="toggleOtherInput('Supplier')">
<label class="form-check-label" for="otherS">Other:</label>
</div>
<div v-if="showOtherSupplier">
<input type="text" class="form-control" id="otherSupplier" name="Supplier" placeholder="Your Supplier Name" v-model="Supplier">
</div> *@
</div>
</div>
</div>
</div>
@* Purchase Date coding *@
<div class="form-group row align-items-center">
<label for="purchaseDate" class="col-sm-3 col-form-label">Purchase Date: </label>
<div class="col-sm-9">
<input type="date" id="purchaseDate" name="purchaseDate" required v-model="purchaseDate" class="form-control">
</div>
</div>
@* PO coding *@
<div class="form-group row align-items-center">
<label for="PO" class="col-sm-3 col-form-label">Enter PO: </label>
<div class="col-sm-9">
<input type="text" id="PO" name="PO" required v-model="PO" placeholder="PO123456" class="form-control">
</div>
</div>
</div>
<div class="col-md-6">
@* Item Price in RM *@
<div class="form-group row">
<label for="priceInRM" class="col-sm-3">Item Price In(RM):</label>
<div class="col-sm-9">
<input type="number" id="priceInRM" name="priceInRM" class="form-control" placeholder="RM 00.00" step="0.01" v-on:input="convertCurrency()" required v-model="priceInRM">
</div>
</div>
@* Currency Selection *@
<div class="form-group row">
<label for="currency" class="col-sm-3">Select Currency:</label>
<div class="col-sm-9">
<select id="currency" name="currency" class="form-control" v-model="currency" v-on:change="convertCurrency()">
<option value="" disabled selected>Select a currency</option>
<option v-for="(name, code) in currencies" :key="code" :value="code">
{{ code }} - {{ name }}
</option>
</select>
</div>
</div>
@* Currency Rate *@
<div class="form-group row">
<label for="currencyRate" class="col-sm-3">Currency Rate(%):</label>
<div class="col-sm-9">
<input type="number" id="currencyRate" name="currencyRate" class="form-control" placeholder="0.01%" step="0.01" v-on:input="convertCurrency()" required v-model="currencyRate">
</div>
</div>
@* Item Convert Price *@
<div class="form-group row">
<label for="convertPrice" class="col-sm-3">{{ currency ? 'Item Price (' + currency + ') : ' : 'Item Price : ' }}</label>
<div class="col-sm-9">
<input type="number" id="convertPrice" name="convertPrice" class="form-control" readonly v-model="convertPrice">
</div>
</div>
@* Delivery Order Date *@
<div class="form-group row">
<label for="DODate" class="col-sm-3">Enter DO Date:</label>
<div class="col-sm-9">
<input type="date" id="DODate" name="DODate" class="form-control" v-on:input="calculateWarrantyEndDate()" required v-model="DODate">
</div>
</div>
@* Warranty *@
<div class="form-group row">
<label for="warranty" class="col-sm-3">Enter Warranty Months(Number):</label>
<div class="col-sm-9">
<input type="number" id="warranty" name="warranty" class="form-control" placeholder="0 , 1 , 2 , 3, ..." step="1" min="0" v-on:input="calculateWarrantyEndDate()" required v-model="warranty">
</div>
</div>
@* Warranty End Date *@
<div class="form-group row">
<label for="EndWDate" class="col-sm-3">Warranty End:</label>
<div class="col-sm-9">
<input type="date" id="EndWDate" name="EndWDate" class="form-control" readonly v-model="EndWDate">
</div>
</div>
@* Invoice Date *@
<div class="form-group row">
<label for="invoiceDate" class="col-sm-3">Invoice Date:</label>
<div class="col-sm-9">
<input type="date" id="invoiceDate" name="invoiceDate" class="form-control" required v-model="invoiceDate">
</div>
</div>
</div>
@* Submit and Reset Buttons *@
<div class="form-group row">
<div class="col-sm-9 offset-sm-3">
<button type="button" v-on:click="resetForm" class="btn btn-secondary">Reset</button>
<input type="submit" class="btn btn-primary" value="Submit" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
@*Vue Js - POST & RESET*@
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
new Vue({
el: '#registerItem',
data() {
return {
company: null,
Dept: null,
productName: null,
imageProduct: null,
productCategory: null,
serialNumber: '',
quantity: 0,
supplierName: null,
purchaseDate: null,
PO: null,
currency: null,
priceInRM: null,
currencyRate: null,
convertPrice: null,
DODate: null,
warranty: null,
EndWDate: null,
invoiceDate: null,
products: [],
companies: [],
depts: [],
supplies: [],
showOtherCompany: false,
showOtherDept: false,
showOtherSupplier: false,
isModalOpen: false,
selectedProduct: null,
selectedSupplier: null,
selectedCompany: null,
selectedDepartment: null,
currencies: {},
}
},
mounted() {// Log the token to check its value
// Fetch companies, depts, and products from the API
this.fetchCurrencyData();
this.fetchCompanies();
this.fetchProducts();
this.fetchSupplies();
},
computed: {
showSerialNumber() {
return this.productCategory === 'Item' || this.productCategory === 'Part';
}
},
methods: {
async addItem() {
const formData = {
company: this.showOtherCompany ? this.selectedCompany : this.company,
Dept: this.showOtherDept ? this.Dept : this.Dept,
productName: this.productName,
imageProduct: this.imageProduct,
productCategory: this.productCategory,
serialNumber: this.serialNumber,
quantity: this.quantity,
supplierName: this.supplierName,
purchaseDate: this.purchaseDate,
PO: this.PO,
currency: this.currency,
priceInRM: this.priceInRM,
currencyRate: this.currencyRate,
convertPrice: this.convertPrice,
DODate: this.DODate,
warranty: this.warranty,
EndWDate: this.EndWDate,
invoiceDate: this.invoiceDate
};
try {
// List of required fields (excluding serialNumber based on showSerialNumber)
const requiredFields = ['company', 'Dept', 'productCategory', 'productName', 'quantity', 'supplierName', 'purchaseDate', 'PO', 'currency', 'priceInRM', 'currencyRate', 'convertPrice', 'DODate', 'warranty', 'EndWDate', 'invoiceDate'];
// Loop through required fields and check if any are null or empty
for (let field of requiredFields) {
if (this[field] === null || this[field] === '') {
swal(`${field} Error`, `Please fill in required fields: ${field}.`, 'warning');
return; // Exit early if validation fails
}
}
// Additional specific checks
if (this.showSerialNumber) {
this.quantity = 0;
if (this.serialNumber === null || this.serialNumber === '') {
swal('Serial Number Error', 'Serial Number must be filled when selecting Item or Part.', 'warning');
return;
}
}
else {
this.serialNumber = null;
if (this.quantity === 0 || this.quantity === null || this.quantity === '') {
swal('quantity Error', 'Quantity is required when selecting Disposable.', 'warning');
return;
}
}
// Proceed to send the data to the API
const response = await fetch('/api/Item', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.token}`
},
body: JSON.stringify(formData)
});
if (response.ok) {
// If the form submission was successful, display a success message
swal('Success!', 'Item form has been successfully submitted.', 'success');
// Reset the form
this.resetForm();
} else {
throw new Error('Failed to submit form.');
}
} catch (error) {
console.error('Error:', error);
// Displaying error message
swal('Inventory PSTW Error', `An error occurred: ${error.message}`, 'error');
}
},
async fetchProducts() {
try {
const token = localStorage.getItem('token'); // Get the token from localStorage
const response = await fetch('/api/Product/GetProducts', {
method: 'GET', // Specify the HTTP method
headers: {
'Content-Type': 'application/json', // Set content type
'Authorization': `Bearer ${token}` // Include the token in the headers
}
});
if (!response.ok) {
throw new Error('Failed to fetch products');
}
this.products = await response.json();
} catch (error) {
console.error('Error fetching products:', error);
}
},
async fetchCompanies() {
try {
const response = await fetch('/api/Item/GetCompanies', {
method: 'GET', // Specify the HTTP method
headers: {
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error('Failed to fetch companies');
}
this.companies = await response.json();
} catch (error) {
console.error('Error fetching products:', error);
}
},
async fetchSupplies() {
try {
const response = await fetch('/api/Item/GetSupplies', {
method: 'GET', // Specify the HTTP method
headers: {
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error('Failed to fetch supplies');
}
this.supplies = await response.json(); // Get the full response object
} catch (error) {
console.error('Error fetching supplies:', error);
}
},
async fetchCurrencyData() {
try {
// Fetch currency data from the API
const response = await fetch('https://openexchangerates.org/api/currencies.json'); // Example API
this.currencies = await response.json();
} catch (error) {
console.error('Error fetching currency data:', error);
}
},
convertCurrency() {
// Your currency conversion logic here
console.log('Selected currency:', this.currency);
},
resetForm() {
this.company = null;
this.Dept = null;
this.productName = null;
this.imageProduct = null;
this.productCategory = null;
this.serialNumber = '';
this.quantity = 0;
this.supplierName = null;
this.purchaseDate = null;
this.PO = null;
this.currency = null;
this.priceInRM = null;
this.currencyRate = null;
this.convertPrice = null;
this.DODate = null;
this.warranty = null;
this.EndWDate = null;
this.invoiceDate = null;
this.showOtherCompany = false;
this.showOtherDept = false;
this.showOtherSupplier = false;
this.selectedCompany = null;
this.selectedSupplier = null;
},
// FRONT END FUNCTIONS
//----------------------//
//Calculate Total Price
convertCurrency() {
const total = this.priceInRM / this.currencyRate;
this.convertPrice = total.toFixed(2);
this.priceInRM = this.priceInRM
.replace(/[^0-9.]/g, '') // Remove non-numeric characters except decimal points
.replace(/(\..*)\..*/g, '$1') // Allow only one decimal point
.replace(/^(\d*\.\d{0,2})\d*$/, '$1'); // Limit to two decimal places
},
openModal() {
this.isModalOpen = true; // Open the modal
},
closeModal() {
this.isModalOpen = false; // Close the modal
},
calculateWarrantyEndDate() {
// Check if DODate and warranty are valid
if (!this.DODate || isNaN(Date.parse(this.DODate))) {
this.EndWDate = null;
return;
}
const DODates = new Date(this.DODate);
const warrantyMonth = parseInt(this.warranty);
// Ensure warranty is a valid number
if (!isNaN(warrantyMonth)) {
DODates.setMonth(DODates.getMonth() + warrantyMonth);
this.EndWDate = DODates.toISOString().split('T')[0];
} else {
this.EndWDate = null;
}
},
//Update Select View
updateCompany(company) {
this.company = company.Name; // Only set the company name
this.depts = company.Departments || []; // Populate depts based on selected company
this.Dept = null; // Reset the selected department
this.showOtherCompany = false; // Hide other company input if needed
},
updateDepts(departments) {
this.depts = departments || []; // Populate depts for the selected company
this.Dept = null; // Reset the selected department
},
updateDept(dept) {
this.Dept = dept;
this.showOtherDept = false;
},
updateProductCategory(productCategory) {
this.productCategory = productCategory;
},
updateProduct(selectedProduct) {
this.productName = selectedProduct.productName;
this.imageProduct = selectedProduct.imageProduct;
this.selectedProduct = selectedProduct.modelNo;
},
updateSupplier(selectedSupplier) {
this.supplierName = selectedSupplier.supplierName;
this.selectedSupplier = selectedSupplier.supplierName;
},
//User Press button Other
toggleOtherInput(type) {
if (type === 'company') {
this.showOtherCompany = true;
this.selectedCompany = null; // Clear company selection when "Other" is chosen
this.company = null;
}
else if (type === 'Dept') {
this.showOtherDept = true;
this.Dept = null; // Clear department selection when "Other" is chosen
}
else if (type === 'Supplier') {
this.supplierName = null; // Clear supplier selection when "Other" is chosen
}
},
},
});
</script>

View File

@ -0,0 +1,291 @@
@{
ViewData["Title"] = "Product Form";
Layout = "~/Views/Shared/_Layout.cshtml";
}
@await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml");
<div id="registerProduct">
<form v-on:submit.prevent="addProduct" data-aos="fade-right">
<div class="container register" data-aos="fade-right">
<div class="row" data-aos="fade-right">
<div class="col-md-12">
<div class="tab-content" id="myTabContent">
<div class="tab-pane fade show active" id="home" role="tabpanel" aria-labelledby="home-tab">
<h3 class="register-heading">REGISTRATION PRODUCT</h3>
<div class="row register-form">
<div class="col-md-6">
@* Product Name *@
<div class="form-group row">
<label for="productName" class="col-sm-3">Product Name:</label>
<div class="col-sm-9">
<input type="text" id="productName" name="productName" class="form-control" required v-model="productName">
</div>
</div>
@* Manufacturer *@
<div class="form-group row">
<label class="col-sm-3">Manufacturer:</label>
<div class="col-sm-9">
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown" aria-expanded="false">
<span id="updateManufacturer">{{ manufacturer || 'Select Manufacturer' }}</span>
</button>
<div class="dropdown-menu p-3">
<div v-for="(manuc, index) in manufactures" :key="index" class="form-check">
<input class="form-check-input" type="radio" :id="'manufacturer-' + index" :value="manuc" name="manufacturer" v-on:click="updateManufacturer(manuc)" v-model="manufacturer">
<label class="form-check-label" :for="'manufacturer-' + index">{{ manuc }}</label>
</div>@*
<div class="form-check">
<input class="form-check-input" type="radio" name="manufacturer" id="otherM" v-on:click="toggleOtherInput('manufacturer')" v-model="manufacturer">
<label class="form-check-label" for="otherM">Other:</label>
</div>
<div v-if="showOtherManufacturer">
<input type="text" class="form-control" id="otherManufacturer" placeholder="Your Manufacturer Name" v-model="manufacturer">
</div> *@
</div>
</div>
</div>
</div>
@* Category *@
<div class="form-group row">
<label class="col-sm-3">Category:</label>
<div class="col-sm-9">
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle w-100" type="button" data-toggle="dropdown" aria-expanded="false">
<span id="updateCategory">{{ category || 'Select Category' }}</span>
</button>
<div class="dropdown-menu w-100 p-3">
<div class="form-check">
<input class="form-check-input" type="radio" name="category" id="item" value="Item" v-on:click="updateCategory('Item')" v-model="category">
<label class="form-check-label" for="item">Item</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="category" id="part" value="Part" v-on:click="updateCategory('Part')" v-model="category">
<label class="form-check-label" for="part">Part</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="category" id="disposable" value="Disposable" v-on:click="updateCategory('Disposable')" v-model="category">
<label class="form-check-label" for="disposable">Disposable</label>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-6">
@* Model No Coding *@
<div class="form-group row">
<label for="modelNo" class="col-sm-3">Model No:</label>
<div class="col-sm-9">
<input type="text" id="modelNo" name="modelNo" class="form-control" required v-model="modelNo">
</div>
</div>
@* Min Quantity Coding *@
<div class="form-group row">
<label for="quantityProduct" class="col-sm-3">Quantity:</label>
<div class="col-sm-9">
<input type="number" id="quantityProduct" name="quantityProduct" class="form-control" min="0" required v-model="quantityProduct">
</div>
</div>
@* Image Product Coding *@
<div class="form-group row">
<label for="imageProduct" class="col-sm-3">Image:</label>
<div class="col-sm-9">
<input type="file" id="imageProduct" name="imageProduct" class="form-control" v-on:change="previewImage" accept="image/*" required>
<br>
<img v-if="imageSrc" :src="imageSrc" alt="Image Preview" class="img-thumbnail" style="width: 200px; margin-top: 10px;" />
</div>
</div>
</div>
<div class="form-group row">
<div class="col-sm-9 offset-sm-3">
<button type="button" v-on:click="resetForm" class="btn btn-secondary">Reset</button>
<input type="submit" class="btn btn-primary">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
new Vue({
el: '#registerProduct',
data: {
productName: null,
manufacturer: null,
category: null,
modelNo: null,
quantityProduct: null,
imageProduct: null,
manufactures: [],
showOtherManufacturer: false,
imageSrc: '',
},
mounted() {
// Fetch companies, depts, and products from the API
this.fetchManufactures();
this.fetchProducts();
},
methods: {
async fetchManufactures() {
try {
const response = await fetch('/api/Product/GetManufactures'); // Call the API
if (!response.ok) {
throw new Error('Failed to fetch manufactures');
}
const data = await response.json(); // Get the full response object
this.manufactures = data.manufacturer; // Extract the 'manufacturer' array
} catch (error) {
console.error('Error fetching manufactures:', error);
}
},
async fetchProducts() {
try {
const response = await fetch('/api/Product/GetProducts'); // Call the API
if (!response.ok) {
throw new Error('Failed to fetch products');
}
this.products = await response.json(); // Store the fetched products
} catch (error) {
console.error('Error fetching products:', error);
}
},
async addProduct() {
const existingProduct = this.products.find(p => p.modelNo === this.modelNo);
if (existingProduct) {
swal('Product Error', `The model number ${this.modelNo} already exists.`, 'error');
return; // Exit early if the modelNo exists
}
// Create the payload
const formData = {
productName: this.productName,
manufacturer: this.manufacturer,
category: this.category,
modelNo: this.modelNo,
quantityProduct: this.quantityProduct,
imageProduct: this.imageProduct
};
try {
// List of required fields
const requiredFields = ['productName', 'manufacturer', 'category', 'modelNo', 'quantityProduct', 'imageProduct'];
// Loop through required fields and check if any are null or empty
for (let field of requiredFields) {
if (this[field] === null || this[field] === '') {
swal('Product Error', `Please fill in required fields: ${field}.`, 'warning');
return; // Exit early if validation fails
}
}
// Proceed to send the data as raw JSON string
const response = await fetch('/api/Product', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(formData) // Convert the formData to a JSON string
});
if (!response.ok) {
const errorData = await response.json();
console.error('Error response:', errorData);
this.errorMessage = 'Error: ' + (errorData.message || 'Unknown error');
} else {
swal('Success!', 'Product form has been successfully submitted.', 'success');
this.resetForm();
}
} catch (error) {
console.error('Error:', error);
swal('Product Error', `An error occurred: ${error.message}`, 'error');
}
}
,
resetForm() {
this.productName = null;
this.manufacturer = '';
this.category = null;
this.modelNo = null;
this.quantityProduct = null;
this.imageProduct = null;
this.imageSrc = '';
const fileInput = document.getElementById('imageProduct');
if (fileInput) {
fileInput.value = ''; // Clear the file input value
}
},
// Update Select View
updateManufacturer(manufacturer) {
this.manufacturer = manufacturer;
this.showOtherManufacturer = false;
},
updateCategory(category) {
this.category = category;
},
// When User Presses Button Other
toggleOtherInput(type) {
if (type === 'manufacturer') {
this.showOtherManufacturer = true;
}
},
// User Inserting an Image
previewImage(event) {
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)
};
reader.readAsDataURL(file);
} else {
this.imageSrc = '';
this.imageProduct = null;
}
},
async fetchManufactures() {
fetch('/InvMainAPI/ManufacturerList', {
method: 'POST'
})
.then(response => response.json())
.then(data => {
console.log(data);
if (data != null && data.length > 0)
{
this.manufacturer = data;
}
if (!this.manufacturerDatatable) {
this.initiateTable();
} else {
this.fillTable(data);
}
})
.catch(error => {
console.error('There was a problem with the fetch operation:', error);
});
},
}
});
</script>

View File

@ -0,0 +1,107 @@
@{
ViewData["Title"] = "QR & Barcode Scanner";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div id="app" data-aos="fade-right">
<h1 data-aos="fade-right">QR & Barcode Scanner</h1>
<div id="reader" data-aos="fade-right"></div>
<div v-if="qrCodeResult" id="qrCodeResult">
<h2>Scan Result:</h2>
<p>{{ qrCodeResult }}</p>
</div>
</div>
<script>
new Vue({
el: '#app',
data() {
return {
qrCodeResult: null,
html5QrCodeScanner: null,
debounceTimeout: null,
};
},
mounted() {
this.startScanner();
},
methods: {
startScanner() {
const config = {
fps: 60,
qrbox: 200
};
navigator.mediaDevices.getUserMedia({
video: {
width: { ideal: 1920 }, // Higher resolution
height: { ideal: 1080 },
}
})
.catch((err) => {
console.error("Error accessing camera:", err);
});
this.html5QrCodeScanner = new Html5QrcodeScanner(
"reader", config, false
);
this.html5QrCodeScanner.render(
(decodedText, decodedResult) => {
if (!this.debounceTimeout) {
this.debounceTimeout = setTimeout(() => {
this.qrCodeResult = decodedText;
this.sendDataToBackend(decodedText);
this.debounceTimeout = null;
}, this.debounceTime);
}
}
);
},
sendDataToBackend(data) {
fetch("/api/Qr", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ data: data }),
})
.then((response) => response.json())
.then((result) => {
console.log("Response from server:", result);
})
.catch((error) => {
console.error("Error sending data to the backend:", error);
});
},
decodeWithApi(barcodeData) {
fetch(`https://api.qrserver.com/v1/read-qr-code/?fileurl=${encodeURIComponent(barcodeData)}`)
.then(response => response.json())
.then(data => {
console.log("Decoded using API:", data);
if (data[0].symbol[0].data) {
this.qrCodeResult = data[0].symbol[0].data; // Update result with API response
}
})
.catch(error => {
console.error("Error decoding with API:", error);
});
},
decodeWithZxing() {
const reader = new ZXing.BrowserQRCodeReader();
reader.decodeFromInputVideoDevice(undefined, 'reader').then(result => {
this.qrCodeResult = result.text;
this.sendDataToBackend(result.text);
}).catch(err => {
console.error("ZXing decoding failed:", err);
});
},
},
beforeDestroy() {
if (this.html5QrCodeScanner) {
this.html5QrCodeScanner.clear();
}
},
});
</script>

View File

@ -0,0 +1,11 @@
@{
ViewData["Title"] = "PSTW Centralized System";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="row">
<div class="text-center">
<h1 class="display-4">Welcome To Invetory Module</h1>
<p>Learn about <a href="https://learn.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>
</div>

View File

@ -0,0 +1,208 @@
@{
ViewData["Title"] = "Manufactures";
Layout = "~/Views/Shared/_Layout.cshtml";
}
@await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml");
<div id="app">
<div class="row card">
<div class="card-header">
<button id="addManufacturerBtn" class="btn btn-success col-md-3 m-1"><i class="fa fa-plus"></i>&nbsp;Add Manufacturer</button>
</div>
<div class="card-body">
<div v-if="loading">
<div class="spinner-border text-info" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
<table class="table table-bordered table-hover" id="manufacturerTable"></table>
</div>
</div>
<div class="modal fade" id="addManufacturerModal" tabindex="-1" role="dialog" aria-labelledby="addManufacturerModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="addManufacturerModalLabel">Add Manufacturer</h5>
<button type="button" class="closeModal" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<form v-on:submit.prevent="addManufacturer">
<div class="modal-body">
<div class="form-group">
<label for="manufacturerName">Manufacturer Name:</label>
<input type="text" class="form-control" id="manufacturerName" v-model="newManufacturer.manufacturerName" required>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary closeModal" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Save changes</button>
</div>
</form>
</div>
</div>
</div>
</div>
@section Scripts {
@{
await Html.RenderPartialAsync("_ValidationScriptsPartial");
}
<script>
const app = Vue.createApp({
data() {
return {
manufacturer: null,
manufacturerDatatable: null,
newManufacturer: {
manufacturerName: null,
},
loading: true,
}
},
mounted() {
// Fetch companies, depts, and products from the API
this.fetchManufactures();
this.initiateTable();
},
methods: {
async fetchManufactures() {
fetch('/InvMainAPI/ManufacturerList', {
method: 'POST'
})
.then(response => response.json())
.then(data => {
console.log(data);
if (data != null && data.length > 0)
{
this.manufacturer = data;
}
if (!this.manufacturerDatatable) {
this.initiateTable();
} else {
this.fillTable(data);
}
})
.catch(error => {
console.error('There was a problem with the fetch operation:', error);
});
},
async initiateTable() {
this.manufacturerDatatable = $('#manufacturerTable').DataTable({
"data": this.manufacturer,
"columns": [
{ "title": "Manufacturer Name",
"data": "manufacturerName",
},
{ "title": "Delete",
"data": "manufacturerName",
"render": function (data, type, full, meta) {
var deleteButton = `<button type="button" class="btn btn-danger delete-btn" data-id="${full.manufacturerId}">Delete</button>`;
return deleteButton;
},
"width": '10%',
},
],
})
self = this;
// Attach click event listener to the delete buttons
$('#manufacturerTable tbody').on('click', '.delete-btn', function () {
const manufacturerId = $(this).data('id'); // Get the manufacturer ID from the button
self.deleteManufacturer(manufacturerId); // Call the Vue method
});
this.loading = false;
},
fillTable(data){
if (!this.manufacturerDatatable) {
console.error("DataTable not initialized");
return;
}
this.manufacturerDatatable.clear();
this.manufacturerDatatable.rows.add(data);
this.manufacturerDatatable.draw();
this.loading = false;
},
addManufacturer() {
this.loading = true;
const existingManufacturer = this.manufacturer != null ? this.manufacturer.find(m => m.manufacturerName.toLowerCase() === this.newManufacturer.manufacturerName.toLowerCase()) : null;
if (existingManufacturer) {
alert('Manufacturer already exists');
return;
}
fetch('/InvMainAPI/AddManufacturer', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(this.newManufacturer)
})
.then(response => response.json())
.then(data => {
if (data != null && data.length > 0)
{
this.manufacturer = data;
}
this.fillTable(data);
})
.catch(error => {
console.error('There was a problem with the fetch operation:', error);
})
.finally(() => {
$('#preloader').modal('hide');
this.newManufacturer.manufacturerName = null;
});
},
async deleteManufacturer(manufacturerId) {
if (!confirm("Are you sure you want to delete this manufacturer?")) {
return;
}
try {
const response = await fetch(`/InvMainAPI/DeleteManufacturer/${manufacturerId}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
},
});
const result = await response.json();
if (result.success) {
alert(result.message);
// Remove the row from DataTables
this.manufacturerDatatable
.row($(`.delete-btn[data-id="${manufacturerId}"]`).closest('tr'))
.remove()
.draw();
} else {
alert(result.message);
}
}
catch (error) {
console.error("Error deleting manufacturer:", error);
alert("An error occurred while deleting the manufacturer.");
}
finally {
this.loading = false;
}
},
}
});
$(function () {
app.mount('#app');
// Attach a click event listener to elements with the class 'btn-success'.
$('#addManufacturerBtn').on('click', function () {
// Show the modal with the ID 'addManufacturerModal'.
$('#addManufacturerModal').modal('show');
});
$('.closeModal').on('click', function () {
// Show the modal with the ID 'addManufacturerModal'.
$('#addManufacturerModal').modal('hide');
});
});
</script>
}

View File

@ -0,0 +1,147 @@
@{
ViewData["Title"] = "User Form";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div id="registerSupplier">
<form v-on:submit.prevent="addSupplier" data-aos="fade-right">
<div class="container register" data-aos="fade-right">
<div class="row">
@*Right Side*@
<div class="col-md-9 register-rights" data-aos="fade-right">
<div class="tab-content" id="myTabContent" data-aos="fade-right">
<div class="tab-pane fade show active" id="home" role="tabpanel" aria-labelledby="home-tab" data-aos="fade-right">
<h3 class="register-heading">REGISTRATION SUPPLIER</h3>
<div class="row register-form">
<div class="col-md-61">
@* Supplier Name *@
<div class="form-group row">
<label for="supplierName" class="col-sm-3">Supplier Name:</label>
<div class="col-sm-9">
<input type="text" id="supplierName" name="supplierName" class="form-control" required v-model="supplierName">
</div>
</div>
@* Supplier Gender *@
<div class="form-group row">
<label class="col-sm-3">Supplier Gender:</label>
<div class="col-sm-9">
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle w-100" type="button" data-toggle="dropdown" aria-expanded="false">
<span id="updateGender">{{ supplierGender || 'Select Gender' }}</span>
</button>
<div class="dropdown-menu w-100 p-3">
<div class="form-check">
<input class="form-check-input" type="radio" name="supplierGender" id="Male" value="Male" v-on:click="updateGender('Male')" v-model="supplierGender">
<label class="form-check-label" for="Male">Male</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="supplierGender" id="Female" value="Female" v-on:click="updateGender('Female')" v-model="supplierGender">
<label class="form-check-label" for="Female">Female</label>
</div>
</div>
</div>
</div>
</div>
@* Supplier Email *@
<div class="form-group row">
<label class="col-sm-3">Supplier Email:</label>
<div class="col-sm-9">
<input type="email" id="supplierName" name="supplierEmail" class="form-control" required v-model="supplierEmail">
</div>
</div>
@* Supplier Number Phone *@
<div class="form-group row">
<label class="col-sm-3">Supplier Phone Number:</label>
<div class="col-sm-9">
<input type="tel" id="supplierPhoneNo" name="supplierPhoneNo" class="form-control" required v-model="supplierPhoneNo">
</div>
</div>
</div>
<div class="form-group row">
<div class="col-sm-9 offset-sm-3">
<button type="button" v-on:click="resetForm" class="btn btn-secondary">Reset</button>
<input type="submit" class="btn btn-primary">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
new Vue({
el: '#registerSupplier',
data: {
supplierName : null,
supplierEmail : null,
supplierGender : null,
supplierPhoneNo : null
},
methods: {
async addSupplier() {
// Create the payload
const formData = {
supplierName: this.supplierName,
supplierEmail: this.supplierEmail,
supplierGender: this.supplierGender,
supplierPhoneNo: this.supplierPhoneNo
};
try {
// List of required fields
const requiredFields = ['supplierName', 'supplierEmail', 'supplierGender', 'supplierPhoneNo'];
// Loop through required fields and check if any are null or empty
for (let field of requiredFields) {
if (this[field] === null || this[field] === '') {
swal('Product Error', `Please fill in required fields: ${field}.`, 'warning');
return; // Exit early if validation fails
}
}
// Proceed to send the data as raw JSON string
const response = await fetch('/api/Supplier', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(formData) // Convert the formData to a JSON string
});
if (!response.ok) {
const errorData = await response.json();
console.error('Error response:', errorData);
this.errorMessage = 'Error: ' + (errorData.message || 'Unknown error');
} else {
swal('Success!', 'Supplier form has been successfully submitted.', 'success');
this.resetForm();
}
} catch (error) {
console.error('Error:', error);
swal('Product Error', `An error occurred: ${error.message}`, 'error');
}
}
,
resetForm() {
this.supplierName = null;
this.supplierEmail = null;
this.supplierGender = null;
this.supplierPhoneNo = null;
},
updateGender(supplierGender){
this.supplierGender = supplierGender;
}
}
});
</script>

View File

@ -0,0 +1,51 @@
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<div class="row">
<div class="col-md-6 col-lg-3">
<a href="@Url.Action("ProductRegistration", "Item", new { area = "Inventory" })">
<div class="card card-hover">
<div class="box bg-cyan text-center">
<h1 class="font-light text-white">
<i class="mdi mdi-view-dashboard"></i>
</h1>
<h6 class="text-white">Product Registration</h6>
</div>
</div>
</a>
</div>
<div class="col-md-6 col-lg-3">
<div class="card card-hover">
<a asp-area="Inventory" asp-controller="Item" asp-action="ItemRegistration">
<div class="box bg-success text-center">
<h1 class="font-light text-white">
<i class="mdi mdi-view-dashboard"></i>
</h1>
<h6 class="text-white">Register Item</h6>
</div>
</a>
</div>
</div>
<div class="col-md-6 col-lg-3">
<div class="card card-hover">
<a asp-area="Inventory" asp-controller="Main" asp-action="SupplierRegistration">
<div class="box bg-info text-center">
<h1 class="font-light text-white">
<i class="mdi mdi-view-dashboard"></i>
</h1>
<h6 class="text-white">Supplier Registration</h6>
</div>
</a>
</div>
</div>
<div class="col-md-6 col-lg-3">
<div class="card card-hover">
<a asp-area="Inventory" asp-controller="Main" asp-action="ManifacturerRegistration">
<div class="box bg-warning text-center">
<h1 class="font-light text-white">
<i class="mdi mdi-view-dashboard"></i>
</h1>
<h6 class="text-white">Manifacturer Registration</h6>
</div>
</a>
</div>
</div>
</div>

View File

@ -50,5 +50,34 @@ namespace PSTW_CentralSystem.Controllers.API
return Json(controllerAndMethodList); return Json(controllerAndMethodList);
} }
[HttpPost("GetListClassAndMethodInformation")]
public async Task<IActionResult> GetListClassAndMethodInformation()
{
var controllerAndMethodList = new List<object>();
// Get the assembly containing the controllers
var assembly = Assembly.GetExecutingAssembly();
// Get all types in the assembly (controllers will typically be in the "Controllers" namespace)
//var controllerTypes = await Task.Run(() => assembly.GetTypes().Where(type => typeof(ControllerBase).IsAssignableFrom(type) && type.IsClass && type.Name.Contains("Controller") && type.Name != "AdminController") .ToList());
var controllerTypes = await Task.Run(() => assembly.GetTypes().Where(type => typeof(ControllerBase).IsAssignableFrom(type) && type.IsClass && !type.Name.Contains("API") && !type.Name.Contains("Admin")).ToList());
// Iterate over the controller types and get their methods
foreach (var controllerType in controllerTypes)
{
var methods = controllerType?.GetMethods(BindingFlags.Public | BindingFlags.Instance)
.Where(m => m.DeclaringType == controllerType) // Filter methods declared directly in the controller (ignoring inherited ones)
.Select(m => m.Name) // Get the method names
.ToList();
controllerAndMethodList.Add(new
{
Controller = controllerType?.Name,
Methods = methods
});
}
// Return the list as JSON
return Json(controllerAndMethodList);
}
} }
} }

View File

@ -0,0 +1,77 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Mono.TextTemplating;
using PSTW_CentralSystem.Areas.Inventory.Models;
using PSTW_CentralSystem.DBContext;
using PSTW_CentralSystem.Models;
using System.Diagnostics;
using System.Reflection;
namespace PSTW_CentralSystem.Controllers.API.Inventory
{
[ApiController]
[Route("[controller]")]
public class InvMainAPI : Controller
{
private readonly ILogger<InvMainAPI> _logger;
private readonly AuthDBContext _authDbContext;
public InvMainAPI(ILogger<InvMainAPI> logger, AuthDBContext authDbContext)
{
_logger = logger;
_authDbContext = authDbContext;
}
[HttpPost("ManufacturerList")]
public async Task<IActionResult> ManufacturerList()
{
var manifacturerList = await _authDbContext.Manufacturers.ToListAsync();
return Json(manifacturerList);
}
[HttpPost("AddManufacturer")]
public async Task<IActionResult> AddManufacturer([FromBody] ManufacturerModel manufacturer)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (manufacturer == null)
{
return NotFound("Manufacturer is null");
}
try
{
_authDbContext.Manufacturers.Add(new ManufacturerModel
{
ManufacturerName = manufacturer.ManufacturerName,
});
await _authDbContext.SaveChangesAsync();
var updatedList = await _authDbContext.Manufacturers.ToListAsync();
return Json(updatedList);
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
[HttpDelete("DeleteManufacturer/{id}")]
public async Task<IActionResult> DeleteManufacturer(int id)
{
var manufacturer = await _authDbContext.Manufacturers.FindAsync(id);
if (manufacturer == null)
{
return NotFound(new { success = false, message = "Manufacturer not found" });
}
_authDbContext.Manufacturers.Remove(manufacturer);
await _authDbContext.SaveChangesAsync();
return Ok(new { success = true, message = "Manufacturer deleted successfully" });
}
}
}

View File

@ -111,6 +111,15 @@ namespace PSTW_CentralSystem.Controllers.API
return NotFound("Module is null"); return NotFound("Module is null");
} }
var existName = await _authDbContext.ModuleSettings
.Where(x => x.ModuleName == module.ModuleName)
.FirstOrDefaultAsync();
if (existName != null)
{
return BadRequest("Name Module Already Exist");
}
try try
{ {
_authDbContext.ModuleSettings.Add(module); _authDbContext.ModuleSettings.Add(module);

View File

@ -43,7 +43,7 @@ namespace PSTW_CentralSystem.Controllers
return View(moduleSettings); return View(moduleSettings);
} }
public IActionResult AddModule() public IActionResult CreateModule()
{ {
return View(); return View();
} }

View File

@ -18,7 +18,7 @@ namespace PSTW_CentralSystem.CustomPolicy
private readonly UserManager<UserModel> _userManager; private readonly UserManager<UserModel> _userManager;
private readonly RoleManager<RoleModel> _roleManager; private readonly RoleManager<RoleModel> _roleManager;
private readonly IHttpContextAccessor _httpContextAccessor; private readonly IHttpContextAccessor _httpContextAccessor;
public RoleModuleHandler( AuthDBContext authDBContext, UserManager<UserModel> userManager, RoleManager<RoleModel> roleManager, IHttpContextAccessor httpContextAccessor) public RoleModuleHandler(AuthDBContext authDBContext, UserManager<UserModel> userManager, RoleManager<RoleModel> roleManager, IHttpContextAccessor httpContextAccessor)
{ {
_authDBContext = authDBContext; _authDBContext = authDBContext;
_userManager = userManager; _userManager = userManager;
@ -39,7 +39,8 @@ namespace PSTW_CentralSystem.CustomPolicy
context.Succeed(requirement); context.Succeed(requirement);
return; return;
} }
else { else
{
checkModuleExistOrNot(); checkModuleExistOrNot();
checkModuleHaveRoleOrNot(); checkModuleHaveRoleOrNot();
} }
@ -65,7 +66,7 @@ namespace PSTW_CentralSystem.CustomPolicy
void checkModuleExistOrNot() void checkModuleExistOrNot()
{ {
if ( moduleName == "Admin") if (moduleName == "Admin")
{ {
context.Fail(); context.Fail();
return; return;
@ -98,7 +99,7 @@ namespace PSTW_CentralSystem.CustomPolicy
context.Succeed(requirement); context.Succeed(requirement);
return; return;
} }
else if (currentUser != null && allowedUserTypes == "Registered User" ) else if (currentUser != null && allowedUserTypes == "Registered User")
{ {
checkMethodAndRole(); checkMethodAndRole();
} }

View File

@ -2,6 +2,7 @@
using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json; using Newtonsoft.Json;
using PSTW_CentralSystem.Areas.Inventory.Models;
using PSTW_CentralSystem.Models; using PSTW_CentralSystem.Models;
using System.Text.Json; using System.Text.Json;
@ -71,5 +72,12 @@ namespace PSTW_CentralSystem.DBContext
public new DbSet<UserModel> Users { get; set; } public new DbSet<UserModel> Users { get; set; }
public new DbSet<RoleModel> Roles { get; set; } public new DbSet<RoleModel> Roles { get; set; }
public DbSet<ModuleSettingModel> ModuleSettings { get; set; } public DbSet<ModuleSettingModel> ModuleSettings { get; set; }
public DbSet<CompanyModel> Companies { get; set; }
public DbSet<DepartmentModel> Departments { get; set; }
public DbSet<ManufacturerModel> Manufacturers { get; set; }
public DbSet<ItemModel> Items { get; set; }
public DbSet<ProductModel> Products { get; set; }
public DbSet<SupplierModel> Suppliers { get; set; }
} }
} }

View File

@ -1,93 +0,0 @@

@{
ViewData["Title"] = "Add Module";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="row" id="app">
<div class="col-md-12 col-lg-12">
<div class="card">
<div class="card-body">
<div class="col-md-12 col-lg-12">
<form v-on:submit.prevent="">
<div class="card">
<div class="card-body">
<h5 class="card-title">Settings</h5>
<div class="form-group row">
<label class="col-md-3 mt-3">Module Name</label>
<div class="col-md-6">
<input type="text" class="form-control" name="ModuleName" v-model="moduleData.ModuleName" />
</div>
</div>
<div class="form-group row">
<label class="col-md-3 mt-3">Module Access</label>
<div class="col-md-6">
<select class="form-select shadow-none mt-3" name="AllowedUserType" v-model="moduleData.AllowedUserType" style="height: 36px; width: 100%">
<optgroup label="General">
<option value="Public">Public</option>
<option value="Registered User">Registered User</option>
</optgroup>
</select>
</div>
</div>
</div>
<div class="border-top">
<div class="card-body">
<button type="button" class="btn btn-primary" v-on:click="saveData">
Add
</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@section Scripts {
@{
await Html.RenderPartialAsync("_ValidationScriptsPartial");
}
<script>
</script>
<script>
const app = Vue.createApp({
data() {
return {
moduleData:{
ModuleName : null,
AllowedUserType : null,
MethodAllowedUserType : null,
ModuleStatus : "1",
Description : null,
}
};
},
methods: {
saveData() {
fetch('/ModuleAPI/AddModule', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(this.moduleData)
})
.then(response => {
if (!response.ok) {
throw new Error('Name module already exist');
}
alert('Module information saved successfully');
})
.catch(error => {
console.error('There was a problem with the update operation:', error);
alert('Failed to save data: ' + error.message);
});
}
}
})
$(function () {
app.mount('#app');
});
</script>
}

View File

@ -0,0 +1,177 @@

@{
ViewData["Title"] = "Create Module";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="row" id="app">
<div class="col-md-12 col-lg-12">
<div class="card">
<div class="card-body">
<div class="col-md-12 col-lg-12">
<form v-on:submit.prevent="">
<div class="card">
<div class="card-body">
<h5 class="card-title">Settings</h5>
<div class="form-group row">
<label class="col-md-3 mt-3">Module Name</label>
<div class="col-md-6">
<select class="form-select shadow-none mt-3" name="ModuleName" v-model="moduleData.ModuleName" style="height: 36px; width: 100%">
<optgroup label="Module">
<option v-for="(prefix, index) in classList" :key="index" :value="prefix">
{{ prefix }}
</option>
</optgroup>
</select>
</div>
</div>
<div class="form-group row">
<label class="col-md-3 mt-3">Module Access</label>
<div class="col-md-6">
<select class="form-select shadow-none mt-3" name="AllowedUserType" v-model="moduleData.AllowedUserType" style="height: 36px; width: 100%">
<optgroup label="General">
<option value="Public">Public</option>
<option value="Registered User">Registered User</option>
</optgroup>
<optgroup label="Role">
<option v-for="(roleType, index) in roleData" :key="index" :value="roleType.name">{{ roleType.name }}</option>
</optgroup>
</select>
</div>
</div>
<div class="form-group row">
<label class="col-md-3 mt-3">Module Status</label>
<div class="col-md-6">
<select class="form-select shadow-none mt-3" name="ModuleStatus" v-model="moduleData.ModuleStatus" style="height: 36px; width: 100%">
<optgroup label="General">
<option value="1">Enabled</option>
<option value="0">Disabled</option>
</optgroup>
</select>
</div>
</div>
</div>
<div class="border-top">
<div class="card-body">
<button type="button" class="btn btn-primary" v-on:click="saveData">
Add
</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@section Scripts {
@{
await Html.RenderPartialAsync("_ValidationScriptsPartial");
}
<script>
</script>
<script>
const app = Vue.createApp({
data() {
return {
moduleData:{
ModuleName : null,
AllowedUserType : null,
MethodAllowedUserType: [],
ModuleStatus : null,
Description : null,
},
classList: null,
roleData: null,
moduleList: null
};
},
mounted(){
this.classMethod();
this.fetchRoleList();
this.fetchModuleList();
},
methods: {
fetchRoleList() {
fetch('/RoleAPI/GetRoleList', {
method: 'POST'
})
.then(response => response.json())
.then(data => {
console.log(data);
if (data != null) {
this.roleData = data;
this.$nextTick(() => {
$(".select2").select2().on("change", (event) => {
const index = $(event.target).closest('.tab-pane').index();
this.moduleData.methodAllowedUserType[index].allowedUserTypesArray = $(event.target).val();
});
});
}
})
.catch(error => {
console.error('There was a problem with the fetch operation:', error);
});
},
saveData() {
if (!this.moduleData.ModuleName || !this.moduleData.ModuleStatus || !this.moduleData.AllowedUserType) {
alert("Please select a valid module name or status or module access.");
return;
}
fetch('/ModuleAPI/AddModule', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(this.moduleData)
})
.then(response => {
if (!response.ok) {
throw new Error('Name module already exists');
}
alert('Module information saved successfully');
})
.catch(error => {
console.error('There was a problem with the update operation:', error);
alert('Failed to save data: ' + error.message);
});
},
classMethod(){
fetch('/AdminAPI/GetListClassAndMethodInformation', {
method: 'POST'
})
.then(response => response.json())
.then(data => {
if (data != null) {
this.classList = data.map(data => data.controller.replace("Controller", ""));
}
})
.catch(error => {
console.error('There was a problem with the fetch operation:', error);
});
},
fetchModuleList() {
fetch('/ModuleAPI/GetModuleInformation', {
method: 'POST'
})
.then(response => response.json())
.then(data => {
console.log(data);
if (data != null) {
this.moduleList = data;
}
})
.catch(error => {
console.error('There was a problem with the fetch operation:', error);
});
}
}
})
$(function () {
app.mount('#app');
});
</script>
}

View File

@ -29,6 +29,10 @@
<link rel="stylesheet" href="~/assets/libs/bootstrap-datepicker/dist/css/bootstrap-datepicker.min.css" /> <link rel="stylesheet" href="~/assets/libs/bootstrap-datepicker/dist/css/bootstrap-datepicker.min.css" />
<link rel="stylesheet" href="~/assets/libs/quill/dist/quill.snow.css" /> <link rel="stylesheet" href="~/assets/libs/quill/dist/quill.snow.css" />
<link href="~/dist/css/style.min.css" rel="stylesheet" /> <link href="~/dist/css/style.min.css" rel="stylesheet" />
<!-- DataTables CSS-->
<link href="~/lib/datatables/datatables.css" rel="stylesheet" />
<link href="~/lib/datatables/datatables.min.css" rel="stylesheet" />
<!-- Vue Js CSS --> <!-- Vue Js CSS -->
<script src="~/js/vue.global.js"></script> <script src="~/js/vue.global.js"></script>
@* <script src="~/js/vue.global.prod.js"></script> *@ @* <script src="~/js/vue.global.prod.js"></script> *@
@ -45,7 +49,7 @@
<!-- ============================================================== --> <!-- ============================================================== -->
<!-- Preloader - style you can find in spinners.css --> <!-- Preloader - style you can find in spinners.css -->
<!-- ============================================================== --> <!-- ============================================================== -->
<div class="preloader"> <div id="preloader" class="preloader">
<div class="lds-ripple"> <div class="lds-ripple">
<div class="lds-pos"></div> <div class="lds-pos"></div>
<div class="lds-pos"></div> <div class="lds-pos"></div>
@ -384,6 +388,36 @@
<i class="mdi mdi-view-dashboard"></i><span class="hide-menu">Dashboard</span> <i class="mdi mdi-view-dashboard"></i><span class="hide-menu">Dashboard</span>
</a> </a>
</li> </li>
<li class="sidebar-item">
<a class="sidebar-link has-arrow waves-effect waves-dark"
href="javascript:void(0)"
aria-expanded="false">
<i class="mdi mdi-receipt"></i><span class="hide-menu">Inventory </span>
</a>
<ul aria-expanded="false" class="collapse first-level">
<li class="sidebar-item">
<a class="sidebar-link waves-effect waves-dark sidebar-link"
asp-area="Inventory" asp-controller="InventoryAdmin" asp-action="AdminDashboard"
aria-expanded="false">
<i class="mdi mdi-view-dashboard"></i><span class="hide-menu">AdminDashboard</span>
</a>
</li>
<li class="sidebar-item">
<a class="sidebar-link waves-effect waves-dark sidebar-link"
asp-area="Inventory" asp-controller="Item" asp-action="ProductRegistration"
aria-expanded="false">
<i class="mdi mdi-view-dashboard"></i><span class="hide-menu">Product Registration</span>
</a>
</li>
<li class="sidebar-item">
<a class="sidebar-link waves-effect waves-dark sidebar-link"
asp-area="Inventory" asp-controller="Item" asp-action="ItemRegistration"
aria-expanded="false">
<i class="mdi mdi-view-dashboard"></i><span class="hide-menu">Item Registration</span>
</a>
</li>
</ul>
</li>
<li class="sidebar-item"> <li class="sidebar-item">
<a class="sidebar-link waves-effect waves-dark sidebar-link" <a class="sidebar-link waves-effect waves-dark sidebar-link"
href="charts.html" href="charts.html"
@ -674,7 +708,9 @@
<script src="~/assets/libs/jquery-minicolors/jquery.minicolors.min.js"></script> <script src="~/assets/libs/jquery-minicolors/jquery.minicolors.min.js"></script>
<script src="~/assets/libs/bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js"></script> <script src="~/assets/libs/bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js"></script>
<script src="~/assets/libs/quill/dist/quill.min.js"></script> <script src="~/assets/libs/quill/dist/quill.min.js"></script>
<!-- Datatables JS-->
<script src="~/lib/datatables/datatables.js"></script>
<script src="~/lib/datatables/datatables.min.js"></script>
@await RenderSectionAsync("Scripts", required: false) @await RenderSectionAsync("Scripts", required: false)
</body> </body>
</html> </html>

BIN
wwwroot/lib/DataTables.zip Normal file

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

309
wwwroot/lib/DataTables/datatables.min.js vendored Normal file

File diff suppressed because one or more lines are too long