-
-
-
-
-
-
-
-
-
-
- {{thisQRInfo.itemId}}
-
-
-
-
-
-
-
- {{thisQRInfo.departmentName}}
-
-
- {{thisQRInfo.productShortName}}
-
-
- {{thisQRInfo.serialNumber}}
-
-
- {{thisQRInfo.partNumber}}
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Latest Movement
+
+
+
+ {{ movement.toOther === 'On Delivery' ? 'Receive' : 'Return' }}
+
+
+
+
+
Send Date:
+ {{ movement.sendDate }}
+
+
+
+
+
Receive Date:
+ {{ movement.receiveDate || 'Not arrive' }}
+
+
+
+
+
Action:
+ {{ movement.action }}
+
+
+
+
+
Status:
+ {{ movement.latestStatus || movement.toOther }}
+
+
+
+
+
+
+
+ {{ movement.movementComplete == 1 && movement.latestStatus !== 'Ready To Deploy' ? 'Complete' : (movement.latestStatus === 'Ready To Deploy' ? 'Canceled' : 'Incomplete') }}
+
+
+
+
+
+
+
+
+
+
+
Start
+
User: {{ movement.toUserName }}
+
Station: {{ movement.toStationName }}
+
Store: {{ movement.toStoreName }}
+
+
+
+
+
{{ movement.latestStatus || movement.toOther }}
+
+
+
+
+
+
+
+
+
+
+
+
End
+
User: {{ movement.lastUserName }}
+
Station: {{ movement.lastStationName }}
+
Store: {{ movement.lastStoreName }}
+
+
+
+
+
+
+
+ @* *@
+
+
+
+
+
+
+
+ {{ movement.toOther === 'On Delivery' ? 'Receive' : 'Return' }}
+
+
+
+
+
Send Date:
+ {{ movement.sendDate }}
+
+
+
+
+
Receive Date:
+ {{ movement.receiveDate || 'Not arrive' }}
+
+
+
+
+
Action:
+ {{ movement.action }}
+
+
+
+
+
Status:
+ {{ movement.latestStatus || movement.toOther }}
+
+
+
+
+
+
+
+ {{ movement.movementComplete == 1 && movement.latestStatus !== 'Ready To Deploy' ? 'Complete' : (movement.latestStatus === 'Ready To Deploy' ? 'Canceled' : 'Incomplete') }}
+
+
+
+
+
+
+
+
+
+
+
+
Start
+
User: {{ movement.toUserName }}
+
Station: {{ movement.toStationName }}
+
Store: {{ movement.toStoreName }}
+
+
+
+
+
{{ movement.latestStatus || movement.toOther }}
+
+
+
+
+
+
+
+
+
+
+
+
End
+
User: {{ movement.lastUserName }}
+
Station: {{ movement.lastStationName }}
+
Store: {{ movement.lastStoreName }}
+
+
+
+
+
+
+
+
+
+
+ @* *@
+ @*
*@
+
@@ -169,172 +387,100 @@
items: [],
currentUser: null,
currentUserCompanyDept: null,
+ sortBy: "item",
+ searchQuery: "",
+ categoryVisible: {},
+ historyVisible: {},
+ detailsVisible: {},
+ currentRole:"",
+
+
}
},
mounted() {
- this.fetchUser();
this.fetchItem();
- this.fetchCurrencyData();
- this.fetchCompanies();
- this.fetchProducts();
- this.fetchSuppliers();
- this.fetchStation();
- this.fetchStore();
- this.fetchUsers();
-
},
computed: {
- filteredDepartments() {
- if (!this.selectedCompany) {
- return []; // No company selected, return empty list
- }
- const company = this.companies.find(c => c.companyId === this.selectedCompany);
- // this.selectedDepartment = '';
- return company ? company.departments : [];
- },
- showProduct() {
- if (!this.selectedProduct) {
- return []; // No company selected, return empty list
- }
- const product = this.products.find(c => c.productId === this.selectedProduct);
- return product ? product : {};
- },
- showSerialNumber() {
- return this.showProduct.category === 'Asset' || this.showProduct.category === 'Part';
- },
+ groupedItems() {
+ return this.items.reduce((acc, movement) => {
+ if (!acc[movement.itemId]) {
+ acc[movement.itemId] = {
+ uniqueID: movement.uniqueID,
+ movements: [],
+ };
+ }
+ acc[movement.itemId].movements.push(movement);
+ return acc;
+ }, {});
+ },
+ filteredItems() {
+ if (!this.searchQuery.trim()) {
+ return this.groupedItems;
+ }
+ const searchLower = this.searchQuery.toLowerCase();
+ return Object.fromEntries(
+ Object.entries(this.groupedItems).filter(([_, group]) =>
+ group.uniqueID.toLowerCase().includes(searchLower)
+ )
+ );
+
+ },
},
methods: {
- async addItem() {
- if (this.showProduct.category == "Disposable") {
- this.serialNumber = "";
- }
- const formData = {
- CompanyId: this.selectedCompany,
- DepartmentId: this.selectedDepartment,
- ProductId: this.selectedProduct,
- SerialNumber: this.serialNumber,
- Quantity: this.quantity,
- Supplier: this.selectedSupplier,
- PurchaseDate: this.purchaseDate,
- PONo: this.PO,
- Currency: this.currency,
- DefaultPrice: this.DefaultPrice,
- CurrencyRate: this.currencyRate,
- ConvertPrice: this.convertPrice,
- DODate: this.DODate,
- Warranty: this.warranty,
- EndWDate: this.EndWDate,
- InvoiceDate: this.invoiceDate,
- CreatedByUserId: this.currentUser.id,
- TeamType: this.selectedTeamType,
- PartNumber: this.partNumber,
- };
-
- try {
-
- // Additional specific checks
- if (this.showSerialNumber) {
- this.quantity = 0;
- if (this.serialNumber === null || this.serialNumber === '') {
- alert('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 === '') {
- alert('quantity Error', 'Quantity is required when selecting Disposable.', 'warning');
- return;
- }
- }
-
- // Proceed to send the data to the API
- const response = await fetch('/InvMainAPI/AddItem', {
- 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
- alert('Success!', 'Item form has been successfully submitted.', 'success');
- const updatedItem = await response.json();
- this.items.push(updatedItem);
-
- this.fetchItem();
-
- // Reset the form
- this.resetForm();
- } else {
- throw new Error('Failed to submit form.');
- }
-
- } catch (error) {
- console.error('Error:', error);
-
- // Displaying error message
- alert('Inventory PSTW Error', `An error occurred: ${error.message}`, 'error');
- }
-
- },
+
initiateTable() {
self = this;
this.itemDatatable = $('#itemDatatable').DataTable({
"data": this.items,
"columns": [
- { title: "Unique Id", data: "id" },
- { title: "Product Code", data: "uniqueID" },
- { title: "From User", data: "toUserName" },
- { title: "Last User", data: "lastUserName" },
- { title: "From Station", data: "toStationName" },
- { title: "Last Station", data: "lastStationName" },
- { title: "From Store", data: "toStoreName" },
- { title: "Last Store", data: "lastStoreName" },
- { title: "Action", data: "action" },
- { title: "Start Status", data: "toOther" },
- { title: "Latest Status", data: "latestStatus" },
- { title: "Qty", data: "quantity" },
- { title: "Send Date", data: "sendDate" },
- { title: "Receive Date", data: "receiveDate" },
- { title: "Note",
- data: "consignmentNote",
- render: function (data, type, full, meta) {
- if (!data) {
- return "No Document";
- }
-
- // Check if the document is an image based on file extension
- var isImage = /\.(jpeg|jpg|png|gif)$/i.test(data);
- var isPdf = /\.pdf$/i.test(data);
-
- if (isImage) {
- return `
-
- `;
- }
- else if (isPdf) {
- return `
-
-
View PDF
- `;
- } else {
- return `
Download File`;
- }
- },
+ { title: "Unique Id", data: "id" },
+ { title: "Product Code", data: "uniqueID" },
+ { title: "From User", data: "toUserName" },
+ { title: "Last User", data: "lastUserName" },
+ { title: "Completion", data: "movementComplete", render: function (data) {return data ? "Completed" : "Pending";}},
+ { title: "From Station", data: "toStationName" },
+ { title: "Last Station", data: "lastStationName" },
+ { title: "From Store", data: "toStoreName" },
+ { title: "Last Store", data: "lastStoreName" },
+ { title: "Action", data: "action" },
+ { title: "Start Status", data: "toOther" },
+ { title: "Latest Status", data: "latestStatus" },
+ { title: "Product Category", data: "productCategory" },
+ { title: "Qty", data: "quantity" },
+ { title: "Send Date", data: "sendDate" },
+ { title: "Receive Date", data: "receiveDate" },
+ { title: "Note",
+ data: "consignmentNote",
+ render: function (data, type, full, meta) {
+ if (!data) {
+ return "No Document";
+ }
+ // Check if the document is an image based on file extension
+ var isImage = /\.(jpeg|jpg|png|gif)$/i.test(data);
+ var isPdf = /\.pdf$/i.test(data);
+ if (isImage) {
+ return `
+
+ `;
+ }
+ else if (isPdf) {
+ return `
+
+
View PDF
+ `;
+ } else {
+ return `
Download File`;
+ }
},
- { title: "Remark", data: "remark" },
- {
- "title": "Completion",
- "data": "movementComplete",
},
+ { title: "Remark", data: "remark" },
],
+ order: [[0, "desc"]], // Sorting by "Product Code" (uniqueID) in descending order
responsive: true,
drawCallback: function (settings) {
// Generate QR codes after rows are rendered
@@ -413,7 +559,17 @@
if (!response.ok) {
throw new Error('Failed to fetch item');
}
- this.items = await response.json();
+ if(this.currentRole == "Super Admin"){
+ this.items = await response.json();
+ } else {
+ const data = await response.json();
+ this.items = data.filter(item =>
+ item.toUser === this.currentUser.id ||
+ item.lastUser === this.currentUser.id
+ );
+
+
+ }
// const allowedKeys = ["toUser", "lastUser"];
// this.items = (await response.json()).filter(item => allowedKeys.some(key => item[key] === this.currentUser.id));
// this.items = (await response.json()).filter(item => item.lastUser === this.currentUser);
@@ -432,153 +588,12 @@
}
},
- async fetchProducts() {
- try {
- // const token = localStorage.getItem('token'); // Get the token from localStorage
- const response = await fetch('/InvMainAPI/ProductList', {
- method: 'POST', // 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('/AdminAPI/GetDepartmentWithCompanyList', {
- method: 'POST', // 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 fetchSuppliers() {
- try {
- const response = await fetch('/InvMainAPI/SupplierList', {
- method: 'POST', // Specify the HTTP method
- headers: {
- 'Content-Type': 'application/json'
- }
- });
- if (!response.ok) {
- throw new Error('Failed to fetch suppliers');
- }
- this.suppliers = await response.json(); // Get the full response object
-
- } catch (error) {
- console.error('Error fetching suppliers:', error);
- }
- },
- async fetchStation() {
- try {
- const response = await fetch('/InvMainAPI/StationList', {
- method: 'POST', // Specify the HTTP method
- headers: {
- 'Content-Type': 'application/json'
- }
- });
- if (!response.ok) {
- throw new Error('Failed to fetch suppliers');
- }
- this.stations = await response.json(); // Get the full response object
-
- } catch (error) {
- console.error('Error fetching suppliers:', error);
- }
- },
- async fetchStore() {
- try {
- const response = await fetch('/InvMainAPI/StoreList', {
- method: 'POST', // Specify the HTTP method
- headers: {
- 'Content-Type': 'application/json'
- }
- });
- if (!response.ok) {
- throw new Error('Failed to fetch suppliers');
- }
- this.stores = await response.json(); // Get the full response object
-
- } catch (error) {
- console.error('Error fetching suppliers:', error);
- }
- },
- async fetchUsers() {
- try {
- const response = await fetch('/InvMainAPI/UserList', {
- method: 'POST', // Specify the HTTP method
- headers: {
- 'Content-Type': 'application/json'
- }
- });
- if (!response.ok) {
- throw new Error('Failed to fetch suppliers');
- }
- this.users = await response.json(); // Get the full response object
-
- } catch (error) {
- console.error('Error fetching suppliers:', 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 = '';
- this.Dept = null;
- this.productName = null;
- this.imageProduct = null;
- this.serialNumber = '';
- this.quantity = 1;
- this.supplierName = null;
- this.purchaseDate = null;
- this.PO = null;
- this.currency = 'MYR';
- this.DefaultPrice = 0.01;
- this.currencyRate = 1;
- this.convertPrice = 0.01;
- this.DODate = null;
- this.warranty = 0;
- this.EndWDate = null;
- this.invoiceDate = null;
- this.selectedProduct = '';
- this.selectedSupplier = '';
- this.selectedCompany = this.currentUserCompanyDept.companyId;
- this.selectedDepartment = '';
- this.selectedTeamType = '';
- this.partNumber = null;
- },
+
+
+
+
+
+
// FRONT END FUNCTIONS
//----------------------//
@@ -686,6 +701,15 @@
this.currentUserCompanyDept = companyDeptData;
this.selectedCompany = companyDeptData?.companyId || "";
this.selectedDepartment = companyDeptData?.departmentId || "";
+
+ const roles = this.currentUser.role;
+
+ if (roles.includes("SuperAdmin")) {
+ this.currentRole = "Super Admin";
+ } else if (roles.includes("Inventory Master")) {
+ this.currentRole = "Inventory Master";
+ this.sortBy = "item";
+ }
}
else {
@@ -696,90 +720,220 @@
console.error('There was a problem with the fetch operation:', error);
}
},
- getPrintedQR(uniqueID) {
- if (!this.items || !Array.isArray(this.items)) {
- console.error("Items list is not available or is not an array.");
- return null;
+ // getPrintedQR(uniqueID) {
+ // if (!this.items || !Array.isArray(this.items)) {
+ // console.error("Items list is not available or is not an array.");
+ // return null;
+ // }
+ // return this.items.find(item => item.uniqueID === uniqueID);
+ // },
+ // printQRInfo() {
+ // Create a virtual DOM element
+ // const virtualElement = document.createElement('div');
+ // virtualElement.style.width = '330px '; Match label size for 2 inches at 203 DPI
+ // virtualElement.style.height = '160px';
+ // virtualElement.style.position = 'absolute';
+ // virtualElement.style.left = '-9999px'; Position offscreen to avoid rendering on the main UI
+ // virtualElement.style.border = '1px solid #000'; Optional: Add a border for debugging dimensions
+
+ // Populate the virtual DOM with content
+ // virtualElement.innerHTML = `
+ //
+ //
+ //
+ //
+ //
+ //
${this.thisQRInfo.imgContainer}
+ //
${this.thisQRInfo.uniqueID}
+ //
+ //
+ //
+ //
+ //
+ //
${this.thisQRInfo.departmentName}
+ //
${this.thisQRInfo.productShortName}
+ //
${this.thisQRInfo.serialNumber??"-"}
+ //
${this.thisQRInfo.partNumber}
+ //
+ //
+ //
+ //
+ // `;
+
+ // Append the virtual DOM to the body (temporarily)
+ // document.body.appendChild(virtualElement);
+
+ // Wait for the font to be loaded (important for custom fonts like OCR-A)
+ // document.fonts.load('1em "OCR A"').then(() => {
+ // Use html2canvas to convert the virtual DOM to an image
+ // html2canvas(virtualElement, {
+ // scale: 1, Increase scale for sharper images
+ // }).then((canvas) => {
+ // Convert the canvas to an image
+ // const imgData = canvas.toDataURL('image/png');
+ // Open the image in a new tab for preview (optional)
+ // const newWindow = window.open();
+ // newWindow.location.href = imgData;
+ // console.log(imgData)
+ // Use printJS to print the image
+ // printJS({
+ // printable: imgData,
+ // type: 'image',
+ // css: '/../lib/bootstrap/dist/css/bootstrap.css',
+ // style: `
+ // @@media print {
+ // @@page {
+ // margin: 5px 5px 0px 5px;
+ // }
+ // body { margin: 0; }
+ // }
+ // `
+ // });
+
+ // Remove the virtual DOM from the body after use
+ // document.body.removeChild(virtualElement);
+ // }).catch((error) => {
+ // console.error("Error generating image:", error);
+ // Remove the virtual DOM if an error occurs
+ // document.body.removeChild(virtualElement);
+ // });
+ // }).catch((error) => {
+ // console.error("Error loading font:", error);
+ // Remove the virtual DOM if font loading fails
+ // document.body.removeChild(virtualElement);
+ // });
+ // },
+ handleSorting() {
+ this.renderTables();
+ },
+ renderTables() {
+ if (this.sortBy === "logs") {
+ // this.initAllTables();
+ this.initiateTable();
+ } else
+ if (this.sortBy === "all") {
+ this.initAllTables();
+ // this.initiateTable();
}
- return this.items.find(item => item.uniqueID === uniqueID);
},
- printQRInfo() {
- // Create a virtual DOM element
- const virtualElement = document.createElement('div');
- virtualElement.style.width = '330px '; // Match label size for 2 inches at 203 DPI
- virtualElement.style.height = '160px';
- virtualElement.style.position = 'absolute';
- virtualElement.style.left = '-9999px'; // Position offscreen to avoid rendering on the main UI
- // virtualElement.style.border = '1px solid #000'; // Optional: Add a border for debugging dimensions
+ initAllTables() {
+ if (this.itemMovementNotCompleteDatatable) {
+ this.itemMovementNotCompleteDatatable.destroy();
+ }
+ if (this.itemMovementCompleteDatatable) {
+ this.itemMovementCompleteDatatable.destroy();
+ }
- // Populate the virtual DOM with content
- virtualElement.innerHTML = `
-
-
-
-
-
-
${this.thisQRInfo.imgContainer}
-
${this.thisQRInfo.uniqueID}
-
-
-
-
-
-
${this.thisQRInfo.departmentName}
-
${this.thisQRInfo.productShortName}
-
${this.thisQRInfo.serialNumber??"-"}
-
${this.thisQRInfo.partNumber}
-
-
-
-
- `;
-
- // Append the virtual DOM to the body (temporarily)
- document.body.appendChild(virtualElement);
-
- // Wait for the font to be loaded (important for custom fonts like OCR-A)
- document.fonts.load('1em "OCR A"').then(() => {
- // Use html2canvas to convert the virtual DOM to an image
- html2canvas(virtualElement, {
- scale: 1, // Increase scale for sharper images
- }).then((canvas) => {
- // Convert the canvas to an image
- const imgData = canvas.toDataURL('image/png');
- // Open the image in a new tab for preview (optional)
- // const newWindow = window.open();
- // newWindow.location.href = imgData;
- // console.log(imgData)
- // Use printJS to print the image
- printJS({
- printable: imgData,
- type: 'image',
- css: '/../lib/bootstrap/dist/css/bootstrap.css',
- style: `
- @@media print {
- @@page {
- margin: 5px 5px 0px 5px;
+ this.itemMovementNotCompleteDatatable = $("#itemMovementNotCompleteDatatable").DataTable({
+ data: this.items.filter((m) => m.movementComplete == 0),
+ columns: [
+ { title: "Unique Id", data: "id" },
+ { title: "Product Code", data: "uniqueID" },
+ { title: "From User", data: "toUserName" },
+ { title: "Last User", data: "lastUserName" },
+ { title: "From Station", data: "toStationName" },
+ { title: "From Store", data: "toStoreName" },
+ { title: "Action", data: "action" },
+ { title: "Start Status", data: "toOther" },
+ { title: "Product Category", data: "productCategory" },
+ { title: "Qty", data: "quantity" },
+ { title: "Send Date", data: "sendDate" },
+ {
+ title: "Note",
+ data: "consignmentNote",
+ render: function (data, type, full, meta) {
+ if (!data) {
+ return "No Document";
}
- body { margin: 0; }
- }
- `
- });
- // Remove the virtual DOM from the body after use
- document.body.removeChild(virtualElement);
- }).catch((error) => {
- console.error("Error generating image:", error);
- // Remove the virtual DOM if an error occurs
- document.body.removeChild(virtualElement);
+ // Check if the document is an image based on file extension
+ var isImage = /\.(jpeg|jpg|png|gif)$/i.test(data);
+ var isPdf = /\.pdf$/i.test(data);
+
+ if (isImage) {
+ return `
+
+ `;
+ }
+ else if (isPdf) {
+ return `
+
+
View PDF
+ `;
+ } else {
+ return `
Download File`;
+ }
+ },
+ },
+ { title: "Remark", data: "remark" },
+ ],
+ order: [[0, "desc"]],
+ responsive: true,
});
- }).catch((error) => {
- console.error("Error loading font:", error);
- // Remove the virtual DOM if font loading fails
- document.body.removeChild(virtualElement);
- });
- },
+ this.itemMovementCompleteDatatable = $("#itemMovementCompleteDatatable").DataTable({
+ data: this.items.filter((m) => m.movementComplete == 1),
+ columns: [
+ { title: "Unique Id", data: "id" },
+ { title: "Product Code", data: "uniqueID" },
+ { title: "From User", data: "toUserName" },
+ { title: "Last User", data: "lastUserName" },
+ { title: "From Station", data: "toStationName" },
+ { title: "Last Station", data: "lastStationName" },
+ { title: "From Store", data: "toStoreName" },
+ { title: "Last Store", data: "lastStoreName" },
+ { title: "Action", data: "action" },
+ { title: "Start Status", data: "toOther" },
+ { title: "Latest Status", data: "latestStatus" },
+ { title: "Product Category", data: "productCategory" },
+ { title: "Qty", data: "quantity" },
+ { title: "Send Date", data: "sendDate" },
+ { title: "Receive Date", data: "receiveDate" },
+ { title: "Note",
+ data: "consignmentNote",
+ render: function (data, type, full, meta) {
+ if (!data) {
+ return "No Document";
+ }
+
+ // Check if the document is an image based on file extension
+ var isImage = /\.(jpeg|jpg|png|gif)$/i.test(data);
+ var isPdf = /\.pdf$/i.test(data);
+
+ if (isImage) {
+ return `
+
+ `;
+ }
+ else if (isPdf) {
+ return `
+
+
View PDF
+ `;
+ } else {
+ return `
Download File`;
+ }
+ },
+ },
+ { title: "Remark", data: "remark" },
+ ],
+ order: [[0, "desc"]],
+ responsive: true,
+ });
+ },
+ toggleCategory(itemId) {
+ this.categoryVisible[itemId] = !this.categoryVisible[itemId];
+ },
+ toggleHistory(itemId) {
+ this.historyVisible[itemId] = !this.historyVisible[itemId];
+ },
+ toggleDetails(movementId) {
+ this.detailsVisible[movementId] = !this.detailsVisible[movementId];
+ },
},
});
diff --git a/Areas/Inventory/Views/InventoryMaster/ItemRequestMaster.cshtml b/Areas/Inventory/Views/InventoryMaster/ItemRequestMaster.cshtml
index 97482c8..f775b3c 100644
--- a/Areas/Inventory/Views/InventoryMaster/ItemRequestMaster.cshtml
+++ b/Areas/Inventory/Views/InventoryMaster/ItemRequestMaster.cshtml
@@ -93,6 +93,68 @@