diff --git a/Areas/Inventory/Models/RequestModel.cs b/Areas/Inventory/Models/RequestModel.cs index 66b6628..5de6fac 100644 --- a/Areas/Inventory/Models/RequestModel.cs +++ b/Areas/Inventory/Models/RequestModel.cs @@ -26,6 +26,12 @@ namespace PSTW_CentralSystem.Areas.Inventory.Models public DateTime? approvalDate { get; set; } public int? RequestQuantity { get; set; } public string? Document { get; set; } + public int? fromStoreItem { get; set; } + [ForeignKey("fromStoreItem")] + public virtual StoreModel? Store { get; set; } + public int? assignStoreItem { get; set; } + [ForeignKey("assignStoreItem")] + public virtual StoreModel? Stores { get; set; } } } diff --git a/Areas/Inventory/Views/InventoryMaster/ItemMovement.cshtml b/Areas/Inventory/Views/InventoryMaster/ItemMovement.cshtml index 9e10baa..6f0a0b3 100644 --- a/Areas/Inventory/Views/InventoryMaster/ItemMovement.cshtml +++ b/Areas/Inventory/Views/InventoryMaster/ItemMovement.cshtml @@ -49,7 +49,7 @@ margin-left: auto !important; /* Push Complete/Incomplete to right */ } -@await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml"); +@await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml")

Sort by:

@@ -118,7 +118,8 @@

Item Movement List

-
+
@@ -131,7 +132,9 @@
-

Item : {{ group.uniqueID }}

+ @*

Item : {{ group.uniqueID }}

*@ +

Item : {{ group.uniqueID }}

+

Item : No Item Tracked

@@ -250,7 +253,10 @@ 'text-weird': movement.action === 'Register'}" class="flex-shrink-0 text-nowrap" style="max-width:140px; min-width:90px;"> - {{ movement.toOther === 'Return' ? 'Return' : (movement.toOther === 'On Delivery' ? 'Receive' : ( movement.toStation !== null ? 'Change' : ( movement.toOther == 'Faulty' || movement.toOther == 'Calibration' || movement.toOther == 'Repair' ? movement.toOther : ( movement.action == 'Register' ? 'Register' : 'Assign')))) }} + {{ movement.toOther === 'Return' ? 'Return' : (movement.toOther === 'On Delivery' ? 'Receive' : + ( movement.toStation !== null ? 'Change' : + ( movement.toOther == 'Faulty' || movement.toOther == 'Calibration' || movement.toOther == 'Repair' ? movement.toOther : + ( movement.action == 'Register' ? 'Register' : 'Assign')))) }} @@ -283,9 +289,13 @@ -

- {{ movement.action == 'Register' ? 'Complete' : (movement.movementComplete == 1 && movement.latestStatus !== 'Ready To Deploy' ? 'Complete' : ( movement.toOther === 'Repair' || movement.toOther === 'Calibration' && movement.latestStatus === 'Ready To Deploy' ? 'Complete' : (movement.latestStatus === 'Ready To Deploy' ? 'Canceled' : 'Incomplete'))) }} + {{ movement.action == 'Register' ? 'Complete' : + (movement.movementComplete == 1 && movement.latestStatus !== 'Ready To Deploy' ? 'Complete' : + ( movement.toOther === 'Repair' || movement.toOther === 'Calibration' && movement.latestStatus === 'Ready To Deploy' ? 'Complete' : + (movement.latestStatus === 'Ready To Deploy' ? 'Canceled' : 'Incomplete'))) }}

@@ -341,7 +351,8 @@
-
+

{{ station }}

@@ -355,7 +366,9 @@
-

Item : {{ group.uniqueID }}

+ @*

Item : {{ group.uniqueID }}

*@ +

Item : {{ group.uniqueID }}

+

Item : No Item Tracked

@@ -664,26 +677,13 @@ return acc; }, {}); - console.log(grouped); - // Sort items from newest to oldest & filter them for (let itemId in grouped) { let movements = grouped[itemId].movements .sort((a, b) => b.id - a.id); // Newest to oldest - // console.log(movements); - // let stopIndex = movements.findIndex(m => - // m.toOther === 'Return' && m.movementComplete == 1 - // ); - - // if (stopIndex !== -1) { - // movements = movements.slice(0, stopIndex + 1); - // } - // Ensure at least 3 movements before stopping - let stopIndex = movements.slice(3).findIndex(m => - m.toOther === 'Return' && m.movementComplete == 1 - ); + let stopIndex = movements.slice(3).findIndex(m => m.toOther === 'Return' && m.movementComplete == 1); if (stopIndex !== -1) { stopIndex += 3; // Adjust index since we sliced after the first 3 @@ -692,7 +692,6 @@ grouped[itemId].movements = movements; } - return grouped; }, @@ -716,9 +715,7 @@ .sort((a, b) => b.id - a.id); // Newest → Oldest // Ensure at least 3 movements before stopping - let stopIndex = movements.slice(3).findIndex(m => - m.toOther === 'Return' && m.movementComplete == 1 - ); + let stopIndex = movements.slice(3).findIndex(m => m.toOther === 'Return' && m.movementComplete == 1); // Remove older movements if (stopIndex !== -1) { @@ -730,9 +727,7 @@ let latestMovement = movements[0]; let station = latestMovement.lastStationName || latestMovement.toStationName || "Not Assigned"; - if (!groupedByStation[station]) { - groupedByStation[station] = {}; - } + if (!groupedByStation[station]) { groupedByStation[station] = {}; } groupedByStation[station][itemId] = { uniqueID: itemId, movements }; } @@ -752,8 +747,6 @@ return sortedGrouped; - - }, filteredItems() { if (!this.searchQuery.trim()) { @@ -766,7 +759,7 @@ ) ); - }, + }, filteredStation() { if (!this.searchStation) { return this.groupedByStation; @@ -781,10 +774,8 @@ filtered[station] = grouped[station]; } }); - - return filtered; - - }, + return filtered; + }, }, methods: { @@ -914,8 +905,6 @@ } if(this.currentRole == "Super Admin"){ this.items = await response.json(); - - console.log(this.items); this.initAllTables(); } else { @@ -929,10 +918,6 @@ this.initAllTables(); - - // console.log(this.items); - - } if (this.itemDatatable) { @@ -982,16 +967,10 @@ this.renderTables(); }, renderTables() { - // if (this.sortBy === "logs") { - // // this.initAllTables(); - // this.initiateTable(); - // } else - // if (this.sortBy === "all") { - // this.initAllTables(); - // // this.initiateTable(); - // } - this.initAllTables(); + this.initAllTables(); + this.initiateTable(); + }, initAllTables() { if (this.itemMovementNotCompleteDatatable) { diff --git a/Areas/Inventory/Views/InventoryMaster/ItemRegistration.cshtml b/Areas/Inventory/Views/InventoryMaster/ItemRegistration.cshtml index f91c0dc..2f41ebb 100644 --- a/Areas/Inventory/Views/InventoryMaster/ItemRegistration.cshtml +++ b/Areas/Inventory/Views/InventoryMaster/ItemRegistration.cshtml @@ -603,8 +603,8 @@ "data": "convertPrice", }, { - "title": "Invoice Date", - "data": "invoiceDate", + "title": "Register Date", + "data": "createDate", }, { "title": "Warranty Until", @@ -638,18 +638,27 @@ ], responsive: true, drawCallback: function (settings) { - // Generate QR codes after rows are rendered - const api = this.api(); - api.rows().every(function () { - const data = this.data(); // Row data - const containerId = `qr${data.uniqueID}`; - const container = $(`#${containerId}`); - container.empty(); - container.append(`${data.uniqueID}`); - // console.log(container[0]); - if (container) { - // Generate QR code only if not already generated - new QRCode(container[0], { + setTimeout(() => { + const api = this.api(); + api.rows().every(function () { + const data = this.data(); + const containerId = `qr${data.uniqueID}`; + const container = document.getElementById(containerId); + + if (!container) { + return; + } + + container.innerHTML = ""; + container.append(data.uniqueID); + + // Ensure qrString is valid before generating QR code + if (!data.qrString) { + return; + } + + // Generate QR Code + new QRCode(container, { text: data.qrString, width: 100, height: 100, @@ -657,20 +666,18 @@ colorLight: "#ffffff", correctLevel: QRCode.CorrectLevel.M }); - } - // container.on('click', function() { - // window.open(data.qrString, '_blank'); - // }); - }); - }, + }); + }, 100); // Small delay to ensure elements exist + } }) // Attach click event listener to the delete buttons - $('#itemDatatable tbody').on('click', '.delete-btn', function () { + $('#itemDatatable tbody').off('click', '.delete-btn').on('click', '.delete-btn', function () { const itemId = $(this).data('id'); self.deleteItem(itemId); }); + $('#itemDatatable tbody').on('click', '.print-btn', function () { const $button = $(this); // The clicked button const $row = $button.closest('tr'); // The parent row of the button @@ -686,9 +693,8 @@ // For expanded view: Find the img in the first column of the current row imageSrc = $row.find('td:nth-child(1) img').attr('src'); } - if (imageSrc) { - self.printItem(itemId, imageSrc); // Call the print function with the itemId and imageSrc + self.printItem(itemId, imageSrc); //\ Call the print function with the itemId and imageSrc } else { console.error("Image source not found."); } @@ -870,9 +876,7 @@ .row($(`.delete-btn[data-id="${itemId}"]`).closest('tr')) .remove() .draw(); - } else { - alert(result.message); - } + } } catch (error) { console.error("Error deleting item:", error); @@ -887,7 +891,6 @@ this.thisQRInfo.uniqueID = itemId; const uniqueQR = itemId; const container = document.getElementById("QrContainer"); - if (!container) { console.error("Container not found."); return; @@ -940,7 +943,11 @@ console.error("Items list is not available or is not an array."); return null; } - return this.items.find(item => item.uniqueID === uniqueID); + + //FIX ERROR + const foundItem = this.items.find(item => String(item.uniqueID).trim() === String(uniqueID).trim()); + + return foundItem ? JSON.parse(JSON.stringify(foundItem)) : null; }, printQRInfo() { // Create a virtual DOM element @@ -1019,7 +1026,6 @@ }); }, - }, }); diff --git a/Areas/Inventory/Views/InventoryMaster/ItemRequestMaster.cshtml b/Areas/Inventory/Views/InventoryMaster/ItemRequestMaster.cshtml index f37ab62..e154879 100644 --- a/Areas/Inventory/Views/InventoryMaster/ItemRequestMaster.cshtml +++ b/Areas/Inventory/Views/InventoryMaster/ItemRequestMaster.cshtml @@ -2,36 +2,129 @@ ViewData["Title"] = "Product Request"; Layout = "~/Views/Shared/_Layout.cshtml"; } -@await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml"); +@await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml") + +
-
-
-

Pending Request

- @* *@ -
-
- @*
-
- Loading... -
-
*@ -
+
+

Sort by:

+
+
-
-
-

Complete Requestt

- @* *@ + +
+
+
+

Outgoing Requests to Other Stores

+ + +
+
+
+
-
- @*
-
- Loading... -
-
*@ -
+ +
+
+

Incoming Requests from Other Inventory Masters

+
+
+
+
+
+ +
+
+

Complete Request Master

+
+
+
+
+ +
+
+
+

Pending Request

+
+
+
+
+
+ +
+
+

Complete Request

+
+
+
+
+
+
+ + + +
@section Scripts { @@ -167,7 +420,7 @@ // Attach a click event listener to elements with the class 'btn-success'. $('#addRequestBtn').on('click', function () { - // Show the modal + // Show the modal $('#requestModal').modal('show'); }); $('.closeModal').on('click', function () { @@ -194,50 +447,141 @@ requestDate : null, approvalDate : null, productCategory: "", + fromStoreItem : "", + assignStoreItem : "", + stores: null, + sortBy: "tech", productName: null, productCategory: null, stations: [], selectedProduct: "", selectedStation: "", selectedCategory: "", + selectedStore: "", showRequestModal: false, showRejectModal: false, showApproveModal: false, loading: false, request: [], currentUser: null, + currentUserId: null, currentrequestID: "", rejectremark: "", approveremark: "", + storeUser: "", + searchQuery: "", + dropdownOpen: false, + showRequestModal: false, } - }, - mounted() { - this.fetchRequest(); - this.fetchUser(); + }, + async mounted() { this.fetchProducts(); this.fetchStation(); + await this.fetchUser(); + + // Wait for fetchStoreSpecific to complete before calling fetchStore + await this.fetchStoreSpecific(this.currentUserId); + await Promise.all([ + await this.fetchRequest(), + await this.fetchStore(), + ]); + }, + watch: { + showRequestModal(newVal) { + if (newVal) { + $('#requestModal').modal('show'); + } else { + $('#requestModal').modal('hide'); + } + } }, 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 : {}; - // }, + showProduct() { + if (!this.productId) { + return []; // No company selected, return empty list + } + const product = this.products.find(c => c.productId === this.productId); + + this.productCategory = product.category; + + return product ? product : {}; + }, + filteredProducts() { + return this.products.filter(item => + item.productName.toLowerCase().includes(this.searchQuery.toLowerCase()) || + item.modelNo.toLowerCase().includes(this.searchQuery.toLowerCase()) + ); + } }, methods: { - resetForm() { - this.rejectremark = ""; + + async addRequestMaster() { + try { + const requiredFields = ['productId', 'quantity', 'fromStoreItem', 'assignStoreItem']; + + // Loop through required fields and check if any are null or empty + for (let field of requiredFields) { + if (this[field] === null || this[field] === '') { + alert('Request Error', `Please fill in required fields: ${field}.`, 'warning'); + return; // Exit early if validation fails + } + } + + this.userId = this.currentUser.id; + this.status = "Requested"; + + const now = new Date(); + this.requestDate = new Date(now.getTime() + 8 * 60 * 60 * 1000).toISOString(); + + + // Prepare data as JSON (No file upload) + const requestDatas = { + ProductId: this.productId, + StationId: this.stationId, + UserId: this.userId, + ProductCategory: this.productCategory, + RequestQuantity: this.quantity, + remarkUser: this.remark || '', + remarkMasterInv: '', + status: this.status, + requestDate: this.requestDate, + approvalDate: null, + fromStoreItem: this.fromStoreItem, + assignStoreItem: this.assignStoreItem, + Document: this.document + }; + + $('.modal').modal('hide'); + + // Proceed to send the data to the API + const response = await fetch('/InvMainAPI/AddRequestMaster', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + // 'Authorization': `Bearer ${this.token}` + }, + body: JSON.stringify(requestDatas) + }); + if (response.ok) { + // If the form submission was successful, display a success message + alert('Success!', 'Request form has been successfully submitted.', 'success'); + const requestItem = await response.json(); + this.items.push(requestItem); + this.resetForm(); + this.fetchRequest(); + + } 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'); + } }, + async addRequest() { try { const requiredFields = ['stationId', 'productId', 'quantity', 'productCategory']; @@ -250,8 +594,6 @@ } } - - // Proceed to send the data to the API const response = await fetch('/InvMainAPI/AddRequest', { method: 'POST', @@ -284,359 +626,180 @@ initiateTable() { self = this; + + function renderActionButtons(data, type, row) { + var actiontButtons = `
`; + return actiontButtons; + } + function renderDocument(data, type, full, meta) { + if (!data) { + return "No Document"; + } + + var imageSrc = full.productImage; + // Check if the document is an image based on file extension + var isImage = /\.(jpeg|jpg|png|gif)$/i.test(imageSrc); + var isPdf = /\.pdf$/i.test(imageSrc); + // var imageSrc = full.productImage; Fallback to data if imgsrc is unavailable + + if (isImage) { + return `
${data}
+ + Image + `; + } + else if (isPdf) { + return `
${data}
+ + PDF Document +
View PDF +
`; + } + } + this.requestDatatable = $('#requestDatatable').DataTable({ - "data": this.items.filter(item => item.status == "Requested"), + "data": this.items.filter(item => item.status === "Requested" && item.assignStoreItem == null), "columns": [ - { - "title": "Request ID", - "data": "requestID", - }, - { - "title": "Action", - "data" :"requestID", - "render": function (data, type, row) { - var actiontButtons = `
`; - return actiontButtons - }, - "className": "align-middle", - }, - { - "title": "Product", - "data": "productName", - "render": function (data, type, full, meta) { - if (!data) { - return "No Document"; - } - - var imageSrc = full.productImage; - // Check if the document is an image based on file extension - var isImage = /\.(jpeg|jpg|png|gif)$/i.test(imageSrc); - var isPdf = /\.pdf$/i.test(imageSrc); - // var imageSrc = full.productImage; Fallback to data if imgsrc is unavailable - console.log(full); - - if (isImage) { - return `
${data}
- - Image - `; - } - else if (isPdf) { - return `
${data}
- - PDF Document -
View PDF -
`; - } - // else { - // return `Download File`; - // } - }, - }, - { - "title": "Requested by User", - "data": "userName", - }, - { - "title": "Requested by Station", - "data": "stationName", - }, - { - "title": "Product Category", - "data": "productCategory", - }, - { - "title": "Request Quantity", - "data": "requestQuantity", - }, - { - "title": "Document/Picture", - "data": "document", - "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 ` - Image - `; - } - else if (isPdf) { - return ` - PDF Document -
View PDF -
`; - } else { - return `Download File`; - } - }, - }, - { - "title": "User Remark", - "data": "remarkUser", - }, - // { - // "title": "InvMaster Remark", - // "data": "remarkMasterInv", - // }, - { - "title": "Status", - "data": "status", - }, - { - "title": "Request Date", - "data": "requestDate", - }, - { - "title": "Approval Date", - "data": "approvalDate", - }, - // { - // "title": "Reject", - // "data" :"requestID", - // "render": function (data, type, row) { - // var rejectButton = ``; - // return rejectButton - // }, - // "className": "align-middle", - // }, - // { - // "title": "Approve", - // "data": "requestID", - // "render": function (data) { - // var approveButton = ``; - // return approveButton; - // }, - // "className": "align-middle", - // } + { "title": "Request ID", "data": "requestID" }, + { "title": "Action", "data": "requestID", "render": renderActionButtons, "className": "align-middle" }, + { "title": "Product", "data": "productName", "render": renderDocument }, + { "title": "Requested by User", "data": "userName" }, + { "title": "Requested by Station", "data": "stationName" }, + { "title": "Product Category", "data": "productCategory" }, + { "title": "Request Quantity", "data": "requestQuantity" }, + { "title": "Document/Picture", "data": "document", "render": renderDocument }, + { "title": "User Remark", "data": "remarkUser" }, + { "title": "Status", "data": "status" }, + { "title": "Request Date", "data": "requestDate" }, + { "title": "Approval Date", "data": "approvalDate" } ], responsive: true, - drawCallback: function (settings) { - // Generate QR codes after rows are rendered - // const api = this.api(); - // api.rows().every(function () { - // const data = this.data(); Row data - // const containerId = `qr${data.requestID}`; - // const container = $(`#${containerId}`); - // container.empty(); - // container.append(`${data.requestID}`); - // console.log(container[0]); - // if (container) { - // Generate QR code only if not already generated - // new QRCode(container[0], { - // text: data.qrString, - // width: 100, - // height: 100, - // colorDark: "#000000", - // colorLight: "#ffffff", - // correctLevel: QRCode.CorrectLevel.M - // }); - // } - // container.on('click', function() { - // window.open(data.qrString, '_blank'); - // }); - // }); - }, + drawCallback: function (settings) { } }); this.settledrequestDatatable = $('#settledrequestDatatable').DataTable({ - "data": this.items.filter(item => item.status !== "Requested"), + "data": this.items.filter(item => item.status !== "Requested" && item.assignStoreItem == null), "columns": [ + { "title": "Request ID", "data": "requestID" }, + { "title": "Product", "data": "productName", "render": renderDocument }, + { "title": "Requested by User", "data": "userName" }, + { "title": "Requested by Station", "data": "stationName" }, + { "title": "Product Category", "data": "productCategory" }, + { "title": "Request Quantity", "data": "requestQuantity" }, + { "title": "Document/Picture", "data": "document", "render": renderDocument }, + { "title": "User Remark", "data": "remarkUser" }, + { "title": "InvMaster Remark", "data": "remarkMasterInv" }, + { "title": "Status", "data": "status" }, + { "title": "Request Date", "data": "requestDate" }, + { "title": "Approval Date", "data": "approvalDate" } + ], + responsive: true + }); + this.requestMasterDatatable = $('#requestMasterDatatable').DataTable({ + "data": this.items.filter(item => item.assignStoreItem != null && item.status == "Requested" && item.userId == this.currentUserId), + "columns": [ + { "title": "Request ID", "data": "requestID" }, + { "title": "Product", "data": "productName", "render": renderDocument }, + { "title": "From Store", "data": "fromStoreItem" }, + { "title": "Assign Store", "data": "assignStoreItem" }, + { "title": "Product Category", "data": "productCategory" }, + { "title": "Request Quantity", "data": "requestQuantity" }, + { "title": "Document/Picture", "data": "document", "render": renderDocument }, + { "title": "Remark", "data": "remarkUser" }, + { "title": "Status", "data": "status" }, + { "title": "Request Date", "data": "requestDate" }, + { "title": "Approval Date", "data": "approvalDate" }, { - "title": "Request ID", - "data": "requestID", - }, - { - "title": "Product", - "data": "productName", - "render": function (data, type, full, meta) { - if (!data) { - return "No Document"; - } - - var imageSrc = full.productImage; - // Check if the document is an image based on file extension - var isImage = /\.(jpeg|jpg|png|gif)$/i.test(imageSrc); - var isPdf = /\.pdf$/i.test(imageSrc); - // var imageSrc = full.productImage; Fallback to data if imgsrc is unavailable - - if (isImage) { - return `
${data}
- - Image - `; - } - else if (isPdf) { - return `
${data}
- - PDF Document -
View PDF -
`; - } - // else { - // return `Download File`; - // } + "title": "Delete", "data": "requestID", + "render": function (data) { + var deleteButton = ``; + return deleteButton; }, - }, - { - "title": "Requested by User", - "data": "userName", - }, - { - "title": "Requested by Station", - "data": "stationName", - }, - { - "title": "Product Category", - "data": "productCategory", - }, - { - "title": "Request Quantity", - "data": "requestQuantity", - }, - { - "title": "Document/Picture", - "data": "document", - "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 ` - Image - `; - } - else if (isPdf) { - return ` - PDF Document -
View PDF -
`; - } else { - return `Download File`; - } - }, - }, - { - "title": "User Remark", - "data": "remarkUser", - }, - { - "title": "InvMaster Remark", - "data": "remarkMasterInv", - }, - { - "title": "Status", - "data": "status", - }, - { - "title": "Request Date", - "data": "requestDate", - }, - { - "title": "Approval Date", - "data": "approvalDate", - }, - // { - // "title": "Reject", - // "data" :null, - // "render": function (data, type, row) { - // return ``; - // }, - // "className": "align-middle", - // }, - // { - // "title": "Approve", - // "data": "requestID", - // "render": function (data) { - // var approveButton = ``; - // return approveButton; - // }, - // "className": "align-middle", - // } + "className": "align-middle", + } ], responsive: true, - + drawCallback: function (settings) { } }); - - - - // Attach click event listener to the delete buttons + this.requestOtherMasterDatatable = $('#requestOtherMasterDatatable').DataTable({ + "data": this.items.filter(item => item.status == "Requested" && this.storeUser.some(store => store.id === item.fromStoreItem)), + "columns": [ + { "title": "Request ID", "data": "requestID" }, + { "title": "Action", "data": "requestID", "render": renderActionButtons, "className": "align-middle" }, + { "title": "Product", "data": "productName", "render": renderDocument }, + { "title": "Requested by User", "data": "userName" }, + { "title": "From Store", "data": "fromStoreItem" }, + { "title": "Assign Store", "data": "assignStoreItem" }, + { "title": "Product Category", "data": "productCategory" }, + { "title": "Request Quantity", "data": "requestQuantity" }, + { "title": "Document/Picture", "data": "document", "render": renderDocument }, + { "title": "User Remark", "data": "remarkUser" }, + { "title": "Status", "data": "status" }, + { "title": "Request Date", "data": "requestDate" }, + { "title": "Approval Date", "data": "approvalDate" } + ], + responsive: true + }); + this.settledrequestMasterDatatable = $('#settledrequestMasterDatatable').DataTable({ + "data": this.items.filter(item => item.status != "Requested" && item.assignStoreItem != null), + "columns": [ + { "title": "Request ID", "data": "requestID" }, + { "title": "Product", "data": "productName", "render": renderDocument }, + { "title": "Requested by User", "data": "userName" }, + { "title": "From Store", "data": "fromStoreItem" }, + { "title": "Assign Store", "data": "assignStoreItem" }, + { "title": "Product Category", "data": "productCategory" }, + { "title": "Request Quantity", "data": "requestQuantity" }, + { "title": "Document/Picture", "data": "document", "render": renderDocument }, + { "title": "User Remark", "data": "remarkUser" }, + { "title": "Status", "data": "status" }, + { "title": "Request Date", "data": "requestDate" }, + { "title": "Approval Date", "data": "approvalDate" } + ], + responsive: true + }); + + // Attach event listeners $('#requestDatatable tbody').on('click', '.reject-btn', function () { const requestID = $(this).data('id'); - self.rejectRequestModal(requestID); + self.rejectRequestModal(requestID); }); $('#requestDatatable tbody').on('click', '.approve-btn', function () { const requestID = $(this).data('id'); - self.approveRequestModal(requestID); + self.approveRequestModal(requestID); }); - $('#requestDatatable tbody').on('click', '.print-btn', function () { - const $button = $(this); // The clicked button - const $row = $button.closest('tr'); // The parent row of the button - const itemId = $button.data('id'); // Get the item ID from the button's data attribute - - let imageSrc; - - // Check if the table is collapsed - if ($row.hasClass('child')) { - // For collapsed view: Look for the closest `.dtr-data` that contains the img - imageSrc = $row.prev('tr').find('td:nth-child(1) img').attr('src'); - } else { - // For expanded view: Find the img in the first column of the current row - imageSrc = $row.find('td:nth-child(1) img').attr('src'); - } - - if (imageSrc) { - self.printItem(itemId, imageSrc); // Call the print function with the itemId and imageSrc - } else { - console.error("Image source not found."); - } + // Attach event listeners + $('#requestOtherMasterDatatable tbody').on('click', '.reject-btn', function () { + const requestID = $(this).data('id'); + self.rejectRequestModal(requestID); }); - $('#itemDatatable tbody').on('click', '.reject-btn', function () { - const $button = $(this); // The clicked button - const $row = $button.closest('tr'); // The parent row of the button - const itemId = $button.data('id'); // Get the item ID from the button's data attribute + $('#requestOtherMasterDatatable tbody').on('click', '.approve-btn', function () { + const requestID = $(this).data('id'); + self.approveRequestModal(requestID); + }); - - self.printItem(itemId, imageSrc); // Call the print function with the itemId and imageSrc - - }); + $('#requestMasterDatatable tbody').off('click', '.delete-btn'); + + $('#requestMasterDatatable tbody').on('click', '.delete-btn', function () { + const requestID = $(this).data('id'); + self.deleteRequestItem(requestID); + }); this.loading = false; + }, async fetchRequest() { try { - // const token = localStorage.getItem('token'); // Get the token from localStorage const response = await fetch('/InvMainAPI/ItemRequestList', { method: 'GET', // Specify the HTTP method headers: { 'Content-Type': 'application/json', // Set content type - // 'Authorization': `Bearer ${token}` // Include the token in the headers } }); @@ -648,6 +811,18 @@ if (this.requestDatatable) { this.requestDatatable.clear().destroy(); } + if (this.settledrequestDatatable) { + this.settledrequestDatatable.clear().destroy(); + } + if (this.requestMasterDatatable) { + this.requestMasterDatatable.clear().destroy(); + } + if (this.requestOtherMasterDatatable) { + this.requestOtherMasterDatatable.clear().destroy(); + } + if (this.settledrequestMasterDatatable) { + this.settledrequestMasterDatatable.clear().destroy(); + } this.initiateTable(); } catch (error) { @@ -705,7 +880,29 @@ if (!response.ok) { throw new Error('Failed to fetch suppliers'); } - this.stores = await response.json(); // Get the full response object + + const data = await response.json(); + this.stores = data.filter(store => + !this.storeUser.some(userStore => userStore.id === store.id) + ); + + + } catch (error) { + console.error('Error fetching suppliers:', error); + } + }, + async fetchStoreSpecific(currentUserId) { + try { + const response = await fetch('/InvMainAPI/StoreSpecificMasterList/' + currentUserId, { + method: 'POST', // Specify the HTTP method + headers: { + 'Content-Type': 'application/json' + } + }); + if (!response.ok) { + throw new Error('Failed to fetch store'); + } + this.storeUser = await response.json(); // Get the full response object } catch (error) { console.error('Error fetching suppliers:', error); @@ -883,38 +1080,6 @@ $(`#approveModal`).modal('show'); - }, - async printItem(itemId, imgSrc) { - try { - this.thisQRInfo.uniqueID = itemId; - const uniqueQR = itemId; - const container = document.getElementById("QrContainer"); - - if (!container) { - console.error("Container not found."); - return; - } - - // Safely set image content - const sanitizedImgSrc = encodeURI(imgSrc); // Sanitize the URL - container.innerHTML = `QR Code`; - - // Fetch QR information - const qrInfo = this.getPrintedQR(uniqueQR); - if (!qrInfo) { - console.error("QR Info not found."); - return; - } - - this.thisQRInfo = qrInfo; - this.thisQRInfo.imgSrc = sanitizedImgSrc - this.thisQRInfo.imgContainer = container.innerHTML - $(`#QrItemModal`).modal('show'); // Show modal - } - catch (error) { - console.error("Error generating QR code:", error); - alert("An error occurred while generating the QR code."); - } }, async fetchUser() { try { @@ -928,6 +1093,7 @@ this.currentUserCompanyDept = companyDeptData; this.selectedCompany = companyDeptData?.companyId || ""; this.selectedDepartment = companyDeptData?.departmentId || ""; + this.currentUserId = this.currentUser.id; } else { console.error(`Failed to fetch user: ${response.statusText}`); @@ -938,10 +1104,130 @@ } }, - + closeDropdown() { + this.dropdownOpen = false; // Tutup dropdown + }, + selectProduct(item) { + this.selectedProduct = item; + this.productId = item.productId; + this.searchQuery = item.productName + " (" + item.modelNo + ")"; + this.dropdownOpen = false; + }, + closeModal() { + this.showRequestModal = false; + }, + + handleFileUpload(event) { + const file = event.target.files[0]; + + if (file) { + const reader = new FileReader(); + reader.onload = (e) => { + this.document = e.target.result.split(',')[1]; // Get Base64 string (remove metadata) + }; + reader.readAsDataURL(file); + } else { + this.document = null; + } + }, + + resetForm() { + this.searchQuery = ""; + this.stationId = ""; + this.productId = ""; + this.remark = ""; + this.document = null; + this.quantity = 0; + this.status = ""; + this.requestDate = null; + this.approvalDate = null; + this.productCategory = ""; + this.fromStoreItem = "", + this.assignStoreItem = "", + + this.productName = null; + this.selectedProduct = ""; + this.selectedStation = ""; + this.selectedCategory = ""; + this.loading = false; + this.rejectremark = ""; + }, + + async deleteRequestItem(requestID) { + if (!confirm("Are you sure you want to delete this request?")) { + return false; + } + try { + const response = await fetch(`/InvMainAPI/DeleteRequest/${requestID}`, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json', + }, + }); + const result = await response.json(); + + if (result.success) { + alert(result.message); + + if ($.fn.dataTable.isDataTable('#requestMasterDatatable')) { + const table = $('#requestMasterDatatable').DataTable(); + table.row($(`.delete-btn[data-id="${requestID}"]`).closest('tr')).remove().draw(); + } + + this.request = this.request.filter(req => req.requestID !== requestID); + } else { + alert(result.message); + } + } + catch (error) { + console.error("Error deleting item:", error); + alert("An error occurred while deleting the item."); + } + finally { + this.loading = false; + } + }, + + handleSorting() { + if (this.requestDatatable) { + this.requestDatatable.clear().destroy(); + } + if (this.settledrequestDatatable) { + this.settledrequestDatatable.clear().destroy(); + } + if (this.requestMasterDatatable) { + this.requestMasterDatatable.clear().destroy(); + } + if (this.requestOtherMasterDatatable) { + this.requestOtherMasterDatatable.clear().destroy(); + } + if (this.settledrequestMasterDatatable) { + this.settledrequestMasterDatatable.clear().destroy(); + } + this.initiateTable(); + }, }, + directives: { + clickOutside: { + beforeMount(el, binding) { + el.clickOutsideEvent = (event) => { + // Make sure the click is outside the element + if (!el.contains(event.target) && el !== event.target) { + binding.value?.(); // Call the function to close the modal + } + }; + setTimeout(() => { + document.body.addEventListener("click", el.clickOutsideEvent); + }, 0); // Delay to avoid triggering immediately when opening + }, + beforeUnmount(el) { + document.body.removeEventListener("click", el.clickOutsideEvent); + } + } + } + }); } \ No newline at end of file diff --git a/Areas/Inventory/Views/InventoryMaster/ManifacturerRegistration.cshtml b/Areas/Inventory/Views/InventoryMaster/ManifacturerRegistration.cshtml index c0de4db..2b43e03 100644 --- a/Areas/Inventory/Views/InventoryMaster/ManifacturerRegistration.cshtml +++ b/Areas/Inventory/Views/InventoryMaster/ManifacturerRegistration.cshtml @@ -3,7 +3,7 @@ Layout = "~/Views/Shared/_Layout.cshtml"; } -@await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml"); +@await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml")
diff --git a/Areas/Inventory/Views/InventoryMaster/ProductRegistration.cshtml b/Areas/Inventory/Views/InventoryMaster/ProductRegistration.cshtml index 28fcb41..0d50396 100644 --- a/Areas/Inventory/Views/InventoryMaster/ProductRegistration.cshtml +++ b/Areas/Inventory/Views/InventoryMaster/ProductRegistration.cshtml @@ -4,7 +4,7 @@ string userId = ViewBag.UserId; } -@await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml"); +@await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml")
@@ -145,7 +145,6 @@ }, methods: { initiateTable() { - console.log(this.products) this.productDatatable = $('#productDatatable').DataTable({ "data": this.products, "columns": [ @@ -180,7 +179,7 @@ "title": "Delete", "data": "productId", "render": function (data) { - var deleteButton = ``; + var deleteButton = ``; return deleteButton; }, } diff --git a/Areas/Inventory/Views/InventoryMaster/QrMaster.cshtml b/Areas/Inventory/Views/InventoryMaster/QrMaster.cshtml index 1b0258f..9ce62fd 100644 --- a/Areas/Inventory/Views/InventoryMaster/QrMaster.cshtml +++ b/Areas/Inventory/Views/InventoryMaster/QrMaster.cshtml @@ -144,8 +144,8 @@
- -
+ +

Item is on Delivery

@@ -169,6 +169,23 @@
+
+

Receive Item

+
+
+
+
+ +
+ +
+
+
+
+
+

Receive Repair / Calibration

@@ -226,7 +243,7 @@ @*
*@ @*
*@ -
+

Add Item Movement

@@ -240,7 +257,7 @@
-
+

Add Item Movement

@@ -730,8 +747,9 @@ }) .then(() => { console.log("📷 Applied Constraintsss:", track.getSettings()); - }).catch(err => - // console.error("❌ Failed to apply constraints:", err) + }) + .catch(err => + console.error("❌ Failed to apply constraints:", err) ); } else { @@ -812,9 +830,9 @@ ...(this.selectedAction === 'user' ? { toStore: this.currentUser.store, toUser: this.currentUser.id, toOther: 'On Delivery', SendDate: this.assigndate, lastUser: this.selectedUser, MovementComplete: false, Remark: this.remark, ConsignmentNote: this.document} : {}), ...(this.selectedAction === 'station' ? { toStore: this.currentUser.store, toUser: this.currentUser.id, toOther: 'On Delivery', SendDate: this.assigndate, lastStation: this.selectedStation, lastUser: this.selectedStationPIC, MovementComplete: false, Remark: this.remark, ConsignmentNote: this.document} : {}), - ...(this.selectedAction === 'store' ? { toStore: this.currentUser.store, toUser: this.currentUser.id, toOther: 'On Delivery', SendDate: this.assigndate, lastUser: this.selectedStore, MovementComplete: false, Remark: this.remark, ConsignmentNote: this.document} : {}), - ...(this.selectedAction === 'supplier' ? { toStore: this.currentUser.store, toUser: this.currentUser.id, toOther: this.selectedOther, SendDate: this.assigndate, Remark: this.remark + '. Item sent to ' + this.selectedSupplier + ' for ' + this.selectedOther, ConsignmentNote: this.document, lastUser: this.currentUser.id, MovementComplete: false, } : {}), - ...(this.selectedAction === 'faulty' ? { toStore: this.currentUser.store, toUser: this.currentUser.id,toOther: 'Faulty', Date: new Date(now.getTime() + 8 * 60 * 60 * 1000).toISOString(), Remark: this.remark, ConsignmentNote: this.document, MovementComplete: true, } : {}), + ...(this.selectedAction === 'store' ? { toStore: this.currentUser.store, toUser: this.currentUser.id, toOther: 'On Delivery', SendDate: this.assigndate, lastStore: this.selectedStore, MovementComplete: false, Remark: this.remark, ConsignmentNote: this.document} : {}), + ...(this.selectedAction === 'supplier' ? { toStore: this.currentUser.store, toUser: this.currentUser.id, toOther: this.selectedOther, SendDate: this.assigndate, Remark: this.remark + '. Item sent to ' + this.selectedSupplier + ' for ' + this.selectedOther, ConsignmentNote: this.document, lastUser: this.currentUser.id, lastStore: this.currentUser.store, MovementComplete: false, } : {}), + ...(this.selectedAction === 'faulty' ? { toStore: this.currentUser.store, toUser: this.currentUser.id,toOther: 'Faulty', SendDate: new Date(now.getTime() + 8 * 60 * 60 * 1000).toISOString(), ReceiveDate: new Date(now.getTime() + 8 * 60 * 60 * 1000).toISOString(), Remark: this.remark, ConsignmentNote: this.document, MovementComplete: true, } : {}), ItemId: this.thisItem.itemID, Action: 'Stock Out', @@ -863,19 +881,23 @@ this.serialNumber = ""; } - if(this.thisItem.toOther === "On Delivery"){ + if(this.thisItem.toOther === "On Delivery" && this.thisItem.toUser == this.currentUser.id){ if(!window.confirm("Are you sure you want to cancel item delivery?")){ return; } } const now = new Date(); + console.log('currentuser'+this.currentUser.id); + console.log('lastuser'+this.thisItem.lastuser); + const formData = { Id: this.thisItem.movementId, ReceiveDate: new Date(now.getTime() + 8 * 60 * 60 * 1000).toISOString(), - Remark: this.thisItem.toOther === "On Delivery" ? this.thisItem.remark + ". Inventory Master cancelled delivery with remark: " + this.remark : this.thisItem.remark, - LatestStatus: this.thisItem.toOther === "Return" ? "Faulty" : (this.thisItem.toOther === "Calibration" || this.thisItem.toOther === "Repair" || this.thisItem.toOther === "On Delivery" ) ? "Ready To Deploy" : "" + Remark: this.thisItem.toOther === "On Delivery" && this.thisItem.toUser == this.currentUser.id ? this.thisItem.remark + ". Inventory Master cancelled delivery with remark: " + this.remark : this.thisItem.remark, + LastUser: this.thisItem.lastuser == null ? this.currentUser.id : this.thisItem.lastuser, + LatestStatus: this.thisItem.toOther === "Return" ? "Faulty" : (this.thisItem.toOther === "Calibration" || this.thisItem.toOther === "Repair" || this.thisItem.toOther === "On Delivery" ) ? "Ready To Deploy" : (this.itemlateststatus == 'On Delivery' && this.thisItem.lastStore == this.currentUser.store ? "Delivered" : "") }; @@ -923,9 +945,19 @@ // this.thisItem = await response.json(); this.thisItem = await response.json(); + console.log('last store'+this.thisItem.lastStore); + this.itemlateststatus = this.thisItem.latestStatus ? this.thisItem.latestStatus : this.thisItem.toOther; - this.itemassignedtouser = this.thisItem.toUser == this.currentUser.id || this.thisItem.lastUser == this.currentUser.id ? true : false; + this.itemassignedtouser = (this.thisItem.toUser === this.currentUser.id || this.thisItem.lastUser === this.currentUser.id ) && this.thisItem.lastStore === this.currentUser.store ? true : false; // console.log(this.thisItem); + // console.log(this.itemassignedtouser); + console.log(this.thisItem.lastStore); + console.log( this.thisItem.lastStore == this.currentUser.store? true : false); + console.log(this.thisItem.toUser == this.currentUser.id? true : false); + console.log( this.thisItem.lastUser == this.currentUser.id ? true : false); + console.log(((this.thisItem.toUser == this.currentUser.id) || ( this.thisItem.lastUser == this.currentUser.id)) ? true : false); + console.log('currentuser store'+this.currentUser.store); + } else { console.error('Failed to fetch item information'); diff --git a/Areas/Inventory/Views/InventoryMaster/StationRegistration.cshtml b/Areas/Inventory/Views/InventoryMaster/StationRegistration.cshtml index 5988894..45bfc6d 100644 --- a/Areas/Inventory/Views/InventoryMaster/StationRegistration.cshtml +++ b/Areas/Inventory/Views/InventoryMaster/StationRegistration.cshtml @@ -3,7 +3,7 @@ Layout = "~/Views/Shared/_Layout.cshtml"; } -@await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml"); +@await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml")
diff --git a/Areas/Inventory/Views/InventoryMaster/SupplierRegistration.cshtml b/Areas/Inventory/Views/InventoryMaster/SupplierRegistration.cshtml index 422308b..4763b05 100644 --- a/Areas/Inventory/Views/InventoryMaster/SupplierRegistration.cshtml +++ b/Areas/Inventory/Views/InventoryMaster/SupplierRegistration.cshtml @@ -3,7 +3,7 @@ Layout = "~/Views/Shared/_Layout.cshtml"; } -@await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml"); +@await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml")
diff --git a/Areas/Inventory/Views/ItemMovement/ItemMovementUser.cshtml b/Areas/Inventory/Views/ItemMovement/ItemMovementUser.cshtml index 63fef19..ec360da 100644 --- a/Areas/Inventory/Views/ItemMovement/ItemMovementUser.cshtml +++ b/Areas/Inventory/Views/ItemMovement/ItemMovementUser.cshtml @@ -64,7 +64,8 @@

Pending Item Movement

-
+
@@ -73,7 +74,8 @@

Complete Item Movement

-
+
@@ -284,7 +286,8 @@
-
+

{{ station }}

@@ -569,7 +572,8 @@ return acc; }, {}); - // Sort items from newest to oldest & filter them + let filteredGrouped = {}; + for (let itemId in grouped) { let movements = grouped[itemId].movements .sort((a, b) => b.id - a.id); // Newest to oldest @@ -578,14 +582,27 @@ m.toOther === 'Return' && m.movementComplete == 1 ); + let nextIndex = movements.findIndex(m => + m.latestStatus === 'Ready To Deploy' && m.movementComplete == 1 + ); + if (stopIndex !== -1) { movements = movements.slice(0, stopIndex); } - grouped[itemId].movements = movements; + if (nextIndex !== -1) { + movements = movements.slice(0, nextIndex); + } + + if (movements.length > 0) { + filteredGrouped[itemId] = { + uniqueID: grouped[itemId].uniqueID, + movements: movements, + }; + } } - return grouped; + return filteredGrouped; }, groupedByStation() { @@ -611,11 +628,18 @@ m.toOther === 'Return' && m.movementComplete == 1 ); - // Remove older movements + let nextIndex = movements.findIndex(m => + m.latestStatus === 'Ready To Deploy' && m.movementComplete == 1 + ); + if (stopIndex !== -1) { movements = movements.slice(0, stopIndex); } + if (nextIndex !== -1) { + movements = movements.slice(0, nextIndex); + } + if (movements.length > 0) { let latestMovement = movements[0]; let station = latestMovement.lastStationName || latestMovement.toStationName || "Self Assigned"; @@ -648,11 +672,17 @@ return this.processedGroupedItems; } const searchLower = this.searchQuery.toLowerCase(); - return Object.fromEntries( - Object.entries(this.processedGroupedItems).filter(([_, group]) => - group.uniqueID.toLowerCase().includes(searchLower) - ) - ); + let grouped = this.processedGroupedItems; + let filtered = {}; + + Object.keys(grouped).forEach(item => { + if (item.toLowerCase().includes(searchLower)) { + if (grouped[item] > 0) { + filtered[item] = grouped[item]; + } + } + }); + return filtered; }, filteredStation() { @@ -720,6 +750,10 @@ } }, + handleSorting() { + this.renderTables(); + }, + renderTables() { if (this.sortBy === "all") { this.initAllTables(); @@ -737,7 +771,7 @@ this.stationDatatable.destroy(); } - // Get latest movement per uniqueID + // Get latest movement per uniqueID after filtering function getLatestMovements(data) { let latestMovements = {}; data.forEach(movement => { @@ -749,17 +783,41 @@ return Object.values(latestMovements); } - // Distribute items based on priority + // Filter movements based on conditions + function filterMovements(movements) { + let stopIndex = movements.findIndex(m => + m.toOther === 'Return' && m.movementComplete == 1 + ); + + let nextIndex = movements.findIndex(m => + m.latestStatus === 'Ready To Deploy' && m.movementComplete == 1 + ); + + if (stopIndex !== -1) { + movements = movements.slice(0, stopIndex); + } + + if (nextIndex !== -1) { + movements = movements.slice(0, nextIndex); + } + + return movements; + } + let latestMovements = getLatestMovements(this.itemMovements); + let notCompleteData = []; let completeData = []; - let assignedData = []; latestMovements.forEach(movement => { - if (movement.movementComplete == 0) { - notCompleteData.push(movement); - } else if (movement.movementComplete == 1) { - completeData.push(movement); + let filteredMovements = filterMovements([movement]); + + if (filteredMovements.length > 0) { + if (movement.movementComplete == 0) { + notCompleteData.push(movement); + } else if (movement.movementComplete == 1) { + completeData.push(movement); + } } }); @@ -818,21 +876,22 @@ var isPdf = /\.pdf$/i.test(data); if (isImage) { return ` - Image - `; - } else if (isPdf) { - return ` - PDF Document -
View PDF -
`; + Image + `; + } else if (isPdf) { + return ` + PDF Document +
View PDF +
`; } else { return `Download File`; } } }, + toggleCategory(itemId) { this.categoryVisible[itemId] = !this.categoryVisible[itemId]; @@ -857,9 +916,6 @@ this.detailsVisible[movementId] = !this.detailsVisible[movementId]; }, - handleSorting() { - this.renderTables(); - }, }, }); diff --git a/Areas/Inventory/Views/ItemMovement/ItemRequest.cshtml b/Areas/Inventory/Views/ItemMovement/ItemRequest.cshtml index 9402849..f4ea3c2 100644 --- a/Areas/Inventory/Views/ItemMovement/ItemRequest.cshtml +++ b/Areas/Inventory/Views/ItemMovement/ItemRequest.cshtml @@ -297,7 +297,7 @@ requestDate : null, approvalDate : null, productCategory: "", - assign: "", + assign: "", productName: null, searchQuery: "", @@ -439,242 +439,80 @@ }, - initiateTable() { - self = this; - this.requestDatatable = $('#requestDatatable').DataTable({ - "data": this.request.filter(request => request.status == "Requested"), - "columns": [ - { - "title": "Request ID", - "data": "requestID", - "createdCell": function (td, cellData, rowData, row, col) { - // Assign a unique ID to the element - $(td).attr('id', `qr${cellData}`); - }, - }, - { - "title": "Product Name", - "data": "productName", - "render": function (data, type, full, meta) { - if (!data) { - return "No Document"; - } + initiateTable() { + let self = this; - var imageSrc = full.productPicture; - // Check if the document is an image based on file extension - var isImage = /\.(jpeg|jpg|png|gif)$/i.test(imageSrc); - var isPdf = /\.pdf$/i.test(imageSrc); - // var imageSrc = full.productImage; Fallback to data if imgsrc is unavailable - console.log(full); + function renderDocument(data, full) { + if (!data) return "No Document"; - if (isImage) { - return `
${data}
- - Image - `; - } - else if (isPdf) { - return `
${data}
- - PDF Document -
View PDF -
`; - } - }, - }, - { - "title": "Product Category", - "data": "productCategory", - }, - { - "title": "Request Quantity", - "data": "requestQuantity", - }, - - { - "title": "Document / Picture", - "data": "document", - "render": function (data, type, full, meta) { - if (!data) { - return "No Document"; - } + let isImage = /\.(jpeg|jpg|png|gif)$/i.test(data); + let isPdf = /\.pdf$/i.test(data); - // 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 ` - Image - `; - } - else if (isPdf) { - return ` - PDF Document -
View PDF -
`; - } else { - return `Download File`; - } - }, - }, - { - "title": "Remark", - "data": "remarkUser", - }, - { - "title": "Station Deploy", - "data": "stationName", - "render": function (data, type, full, meta) { - return data ? data : "Self Assign"; - } - }, - { - "title": "Request Date", - "data": "requestDate", - }, - { - "title": "Status", - "data": "status", - }, - { - "title": "Delete", - "data": "requestID", - "render": function (data) { - var deleteButton = ``; - return deleteButton; - }, - "className": "align-middle", + if (isImage) { + return ` + Image + `; + } else if (isPdf) { + return ` + PDF Document +
View PDF +
`; + } else { + return `Download File`; } + } - ], - responsive: true, - }); - this.requestDatatable = $('#settledrequestDatatable').DataTable({ - "data": this.request.filter(request => request.status !== "Requested"), - "columns": [ - { - "title": "Request ID", - "data": "requestID", - "createdCell": function (td, cellData, rowData, row, col) { - // Assign a unique ID to the element - $(td).attr('id', `qr${cellData}`); - }, - }, - { - "title": "Status", - "data": "status", - }, - { - "title": "Product Name", - "data": "productName", - "render": function (data, type, full, meta) { - if (!data) { - return "No Document"; - } + function renderDeleteButton(data) { + return ``; + } - var imageSrc = full.productPicture; - // Check if the document is an image based on file extension - var isImage = /\.(jpeg|jpg|png|gif)$/i.test(imageSrc); - var isPdf = /\.pdf$/i.test(imageSrc); - // var imageSrc = full.productImage; Fallback to data if imgsrc is unavailable - console.log(full); + this.pendingRequestDatatable = $('#requestDatatable').DataTable({ + "data": this.request.filter(req => req.status === "Requested"), + "columns": [ + { "title": "Request ID", "data": "requestID", "createdCell": (td, cellData) => $(td).attr('id', `qr${cellData}`) }, + { "title": "Product Name", "data": "productName", "render": (data, type, full) => renderDocument(full.productPicture) }, + { "title": "Product Category", "data": "productCategory" }, + { "title": "Request Quantity", "data": "requestQuantity" }, + { "title": "Document / Picture", "data": "document", "render": (data, type, full) => renderDocument(data) }, + { "title": "Remark", "data": "remarkUser" }, + { "title": "Station Deploy", "data": "stationName", "render": (data) => data || "Self Assign" }, + { "title": "Request Date", "data": "requestDate" }, + { "title": "Status", "data": "status" }, + { "title": "Delete", "data": "requestID", "render": renderDeleteButton, "className": "align-middle" } + ], + responsive: true, + }); - if (isImage) { - return `
${data}
- - Image - `; - } - else if (isPdf) { - return `
${data}
- - PDF Document -
View PDF -
`; - } - }, - }, - { - "title": "Product Category", - "data": "productCategory", - }, - { - "title": "Request Quantity", - "data": "requestQuantity", - }, - { - "title": "Station Deploy", - "data": "stationName", - "render": function (data, type, full, meta) { - return data ? data : "Self Assign"; - } - }, - { - "title": "Document / Picture", - "data": "document", - "render": function (data, type, full, meta) { - if (!data) { - return "No Document"; - } + this.settledRequestDatatable = $('#settledrequestDatatable').DataTable({ + "data": this.request.filter(req => req.status !== "Requested"), + "columns": [ + { "title": "Request ID", "data": "requestID", "createdCell": (td, cellData) => $(td).attr('id', `qr${cellData}`) }, + { "title": "Status", "data": "status" }, + { "title": "Product Name", "data": "productName", "render": (data, type, full) => renderDocument(full.productPicture) }, + { "title": "Product Category", "data": "productCategory" }, + { "title": "Request Quantity", "data": "requestQuantity" }, + { "title": "Station Deploy", "data": "stationName", "render": (data) => data || "Self Assign" }, + { "title": "Document / Picture", "data": "document", "render": (data, type, full) => renderDocument(data) }, + { "title": "Remark", "data": "remarkUser" }, + { "title": "Remark (Master)", "data": "remarkMasterInv" }, + { "title": "Request Date", "data": "requestDate" }, + { "title": "Approval Date", "data": "approvalDate" } + ], + responsive: true, + }); - // 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 ` - Image - `; - } else if (isPdf) { - return ` - PDF Document -
View PDF -
`; - } else { - return `Download File`; - } - }, - }, - { - "title": "Remark", - "data": "remarkUser", - }, - { - "title": "Remark (Master)", - "data": "remarkMasterInv", - }, - { - "title": "Request Date", - "data": "requestDate", - }, - { - "title": "Approval Date", - "data": "approvalDate", - } - - ], - responsive: true, - }); - - $('#requestDatatable tbody').off('click', '.delete-btn'); + $('#requestDatatable tbody').off('click', '.delete-btn'); $('#requestDatatable tbody').on('click', '.delete-btn', function () { const requestID = $(this).data('id'); self.deleteRequestItem(requestID); }); + this.loading = false; + } - this.loading = false; - }, async fetchRequest() { try diff --git a/Areas/Inventory/Views/ItemMovement/QrUser.cshtml b/Areas/Inventory/Views/ItemMovement/QrUser.cshtml index f410385..72bd12d 100644 --- a/Areas/Inventory/Views/ItemMovement/QrUser.cshtml +++ b/Areas/Inventory/Views/ItemMovement/QrUser.cshtml @@ -145,14 +145,6 @@
- - - - - - - -
@@ -542,15 +534,6 @@ async returnItemMovement() { - // const requiredFields = ['remark', 'consignmentNote']; - - // for (let field of requiredFields) { - // if (!this[field]) { - // alert(`Request Error: Please fill in required field ${field}.`, 'warning'); - // return; - // } - // } - if (!confirm("Are you sure you want to return this item?")) { return false; } diff --git a/Areas/Inventory/Views/_InventoryPartial.cshtml b/Areas/Inventory/Views/_InventoryPartial.cshtml index 0179e8e..17e3546 100644 --- a/Areas/Inventory/Views/_InventoryPartial.cshtml +++ b/Areas/Inventory/Views/_InventoryPartial.cshtml @@ -19,7 +19,7 @@

-
Manifacturer
+
Manufacturer
diff --git a/Areas/MMS/Controllers/MarineController.cs b/Areas/MMS/Controllers/MarineController.cs new file mode 100644 index 0000000..3cacec2 --- /dev/null +++ b/Areas/MMS/Controllers/MarineController.cs @@ -0,0 +1,415 @@ +using Microsoft.AspNetCore.Mvc; +using PSTW_CentralSystem.DBContext; +//using PSTW_CentralSystem.Areas.MMS.Models; +//using System.IO; +//using System.Linq; +using PSTW_CentralSystem.Areas.MMS.Models.PDFGenerator; +using QuestPDF.Fluent; +//using System.Threading.Tasks; +//using System.Threading; +//using System.Collections.Generic; +//using Microsoft.Data.SqlClient; +using Microsoft.EntityFrameworkCore; +using MySqlConnector; + +namespace PSTW_CentralSystem.Areas.MMS.Controllers +{ + public class TarballPdfDto //data transfer object, only holds data, used to move data between programs + { + // From tbl_marine_tarball + public int Id { get; set; } + public required string StationID { get; set; } + public required string Longitude { get; set; } + public required string Latitude { get; set; } + public required DateTime DateSample { get; set; } + public required TimeSpan TimeSample { get; set; } + public required string ClassifyID { get; set; } + public string? OptionalName1 { get; set; } + public string? OptionalName2 { get; set; } + public string? OptionalName3 { get; set; } + public string? OptionalName4 { get; set; } + public required string FirstSampler { get; set; } + + // From joined tables + public required string LocationName { get; set; } // From tbl_marine_station + public required string StateName { get; set; } // From tbl_state + public required string FullName { get; set; } // From tbl_user + public required string LevelName { get; set; } // From tbl_level + } + + [Area("MMS")] + public class MarineController : Controller + { + private readonly MMSSystemContext _context;//Used in TarBallForm and GeneratePdfResponse to query the database. + private readonly NetworkShareAccess _networkAccessService;//used in GetImage and GeneratePdfResponse + private const string PhotoBasePath = @"\\192.168.12.42\images\marine\manual_tarball";//used in GetImage and GeneratePdfResponse + + public MarineController(MMSSystemContext context, NetworkShareAccess networkAccessService) + { + _context = context; + _networkAccessService = networkAccessService; + } + + public IActionResult Index() + { + return View(); + } + + public async Task TarBallForm()//make it async in case of traffic/frequent usage + { + try + { + var marineTarballs = await _context.MarineTarballs + .Select(t => new + { + id = t.Id, + date = t.DateSample.ToString("yyyy/MM/dd"), + station = t.StationID, + time = t.TimeSample.ToString("hh\\:mm\\:ss") + }) + .ToListAsync(); + + Console.WriteLine($"Marine Tarballs Count: {marineTarballs.Count}"); //??? + return View(marineTarballs); + } + catch (Exception ex) + { + return Content($"Error: {ex.Message}
{ex.StackTrace}", "text/html"); + } + } + + [HttpGet] // Explicitly mark as a GET endpoint + //removal TBD===============!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + public IActionResult TestCredentials() + { + try + { + // Use the EXACT same path/credentials as in Program.cs + var testService = new NetworkShareAccess( + @"\\192.168.12.42\images\marine\manual_tarball", + "installer", + "mms@pstw" + ); + + testService.ConnectToNetworkPath(); + testService.DisconnectFromNetworkShare(); + + return Ok("Network credentials and path are working correctly!"); + } + catch (Exception ex) + { + // Log the full error (including stack trace) + Console.WriteLine($"TestCredentials failed: {ex}"); + return StatusCode(500, $"Credentials test failed: {ex.Message}"); + } + } + //====================!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + public IActionResult GetImage(string fileName) + { + if (string.IsNullOrEmpty(fileName)) + { + return BadRequest("Filename cannot be empty"); + } + + // Sanitize filename to prevent path traversal attacks + var sanitizedFileName = Path.GetFileName(fileName); + if (sanitizedFileName != fileName) + { + return BadRequest("Invalid filename"); + } + + int retryCount = 0; + const int maxRetries = 3; + bool connectionSuccess = false; + + // Retry loop for network connection + while (retryCount < maxRetries && !connectionSuccess) + { + try + { + Console.WriteLine($"Attempt {retryCount + 1} to connect to network share..."); + + // Connect to network share + _networkAccessService.ConnectToNetworkPath(); + connectionSuccess = true; + + Console.WriteLine("Network share connected successfully"); + } + catch (Exception ex) + { + retryCount++; + Console.WriteLine($"Connection attempt {retryCount} failed: {ex.Message}"); + + if (retryCount >= maxRetries) + { + Console.WriteLine($"Max connection attempts reached. Last error: {ex}"); + return StatusCode(503, $"Could not establish connection to image server after {maxRetries} attempts"); + } + + // Wait before retrying (1s, 2s, 3s) + Thread.Sleep(1000 * retryCount); + } + } + + try + { + string imagePath = Path.Combine(PhotoBasePath, sanitizedFileName); + Console.WriteLine($"Attempting to access image at: {imagePath}"); + + // Verify file exists + //removal TBD + if (!System.IO.File.Exists(imagePath)) + { + Console.WriteLine($"Image not found at path: {imagePath}"); + return NotFound($"Image '{sanitizedFileName}' not found on server"); + } + + // Verify file is an image + //consider removal if/since verification already happened during image uploading (other program) + if (!IsImageValid(imagePath)) + { + Console.WriteLine($"Invalid image file at path: {imagePath}"); + return BadRequest("The requested file is not a valid image"); + } + + // Read and return the image + byte[] imageBytes = System.IO.File.ReadAllBytes(imagePath); + Console.WriteLine($"Successfully read image: {sanitizedFileName} ({imageBytes.Length} bytes)"); + + // Determine content type based on extension + //removal TBD??? IF image type verification already done during image uploading =========!!!!!!!!!!! + string contentType = "image/jpeg"; // default + string extension = Path.GetExtension(sanitizedFileName).ToLower(); + //string extension = Path.GetExtension(sanitizedFileName)?.ToLower(); + + if (extension == ".png") + { + contentType = "image/png"; + } + else if (extension == ".gif") + { + contentType = "image/gif"; + } + + return File(imageBytes, contentType); + } + catch (UnauthorizedAccessException ex) + { + Console.WriteLine($"Access denied to image: {ex}"); + return StatusCode(403, "Access to the image was denied"); + } + catch (IOException ex) + { + Console.WriteLine($"IO error accessing image: {ex}"); + return StatusCode(503, "Error accessing image file"); + } + catch (Exception ex) + { + Console.WriteLine($"Unexpected error: {ex}"); + return StatusCode(500, "An unexpected error occurred while processing the image"); + } + finally + { + try + { + if (connectionSuccess) + { + Console.WriteLine("Disconnecting from network share..."); + _networkAccessService.DisconnectFromNetworkShare(); + } + } + catch (Exception ex) + { + Console.WriteLine($"Warning: Error disconnecting from share: {ex.Message}"); + // Don't fail the request because of disconnect issues + } + } + } + + public async Task GenerateReport(int id)//calls GeneratePdfResponse to generate a PDF for inline viewing + { + return await GeneratePdfResponse(id, true); + } + + //public async Task DownloadPDF(int id) + //{ + // return await GeneratePdfResponse(id, true); + //} + + public IActionResult ViewPDF(int id) + { + try + { + // Add timeout for safety + var task = Task.Run(() => GeneratePdfResponse(id, false)); + if (task.Wait(TimeSpan.FromSeconds(30))) // 30 second timeout + { + return task.Result; + } + return StatusCode(500, "PDF generation took too long"); + } + catch (Exception ex) + { + Console.WriteLine($"PDF VIEW ERROR: {ex}"); + return StatusCode(500, $"Error showing PDF: {ex.Message}"); + } + } + + private async Task GeneratePdfResponse(int id, bool forceDownload) + { + Console.WriteLine($"Requested ID in {(forceDownload ? "GenerateReport" : "ViewPDF")}: {id}"); + + // Test network connection first + try + { + _networkAccessService.ConnectToNetworkPath(); + _networkAccessService.DisconnectFromNetworkShare(); + } + catch (Exception ex) + { + return StatusCode(500, $"Cannot access network: {ex.Message}"); + } + + try + { + _networkAccessService.ConnectToNetworkPath(); + + // ===== 1. Get Data from Database ===== + var query = @" + SELECT + marine.*, + station.LocationName, + state.StateName, + user.FullName, + level.LevelName + FROM tbl_marine_tarball marine + JOIN tbl_marine_station station ON marine.StationID = station.StationID + JOIN tbl_state state ON station.StateID = state.StateID + JOIN tbl_user user ON marine.FirstSampler = user.FullName + JOIN tbl_level level ON user.LevelID = level.LevelID + WHERE marine.Id = @id"; + + var tarball = await _context.Database + .SqlQueryRaw(query, new MySqlParameter("@id", id)) + .FirstOrDefaultAsync(); + + if (tarball == null) + return NotFound("Record not found"); + + // Prepare boolean values for PDF + bool tarBallYes = tarball.ClassifyID != "NO"; + bool tarBallNo = tarball.ClassifyID == "NO"; + bool isSand = tarball.ClassifyID == "SD"; + bool isNonSandy = tarball.ClassifyID == "NS"; + bool isCoquina = tarball.ClassifyID == "CO"; + + // ===== 2. Get Images ===== + // For date (stored as DATE in DB → "2025-01-30" becomes "20250130") + var sampleDateString = tarball.DateSample.ToString("yyyyMMdd"); + + // For time (stored as TIME in DB → "16:49:02" becomes "164902") + var sampleTimeString = tarball.TimeSample.ToString("hhmmss"); + var stationFolder = Path.Combine(PhotoBasePath, tarball.StationID); + + var stationImages = new Dictionary(); + var foundAnyImages = false; + + if (Directory.Exists(stationFolder)) + { + var basePattern = $"{tarball.StationID}_{sampleDateString}_{sampleTimeString}_"; + var allImages = Directory.GetFiles(stationFolder, $"{basePattern}*"); + + foreach (var imagePath in allImages) + { + var fileName = Path.GetFileNameWithoutExtension(imagePath); + var type = fileName.Split('_').Last(); + stationImages[type] = imagePath; + foundAnyImages = true; + } + } + + if (!foundAnyImages) + { + return StatusCode(404, "No images found for this record"); + } + + // Verify mandatory images exist + var mandatoryImages = new[] { + "LEFTSIDECOASTALVIEW", + "RIGHTSIDECOASTALVIEW", + "DRAWINGVERTICALLINES", + "DRAWINGHORIZONTALLINES" + }; + + foreach (var type in mandatoryImages) + { + if (!stationImages.ContainsKey(type)) + { + return StatusCode(400, $"Missing mandatory image: {type}"); + } + } + + // ===== 3. Generate PDF ===== + var pdf = new TarBallPDF( + tarball.StateName, + tarball.StationID, + tarball.LocationName, + tarball.Longitude, + tarball.Latitude, + tarball.DateSample, + tarball.TimeSample, + tarball.ClassifyID, + tarBallYes, + tarBallNo, + isSand, + isNonSandy, + isCoquina, + stationImages["LEFTSIDECOASTALVIEW"], + stationImages["RIGHTSIDECOASTALVIEW"], + stationImages["DRAWINGVERTICALLINES"], + stationImages["DRAWINGHORIZONTALLINES"], + stationImages.GetValueOrDefault("OPTIONAL01"), + stationImages.GetValueOrDefault("OPTIONAL02"), + stationImages.GetValueOrDefault("OPTIONAL03"), + stationImages.GetValueOrDefault("OPTIONAL04"), + tarball.OptionalName1, + tarball.OptionalName2, + tarball.OptionalName3, + tarball.OptionalName4, + tarball.FirstSampler, + tarball.FullName, + tarball.LevelName + ).GeneratePdf(); + + // ===== 4. Return PDF ===== + var downloadName = $"{tarball.StationID}_{sampleDateString}_{sampleTimeString}.pdf"; + return forceDownload + ? File(pdf, "application/pdf", downloadName) + : File(pdf, "application/pdf"); + } + catch (Exception ex) + { + return StatusCode(500, $"PDF generation failed: {ex.Message}"); + } + finally + { + _networkAccessService.DisconnectFromNetworkShare(); + } + } + + private bool IsImageValid(string imagePath) + { + try + { + using (var image = System.Drawing.Image.FromFile(imagePath)) + return true; + } + catch + { + Console.WriteLine($"Invalid image skipped: {imagePath}"); + return false; + } + } + } +} diff --git a/Areas/MMS/Models/NetworkAccessService.cs b/Areas/MMS/Models/NetworkAccessService.cs new file mode 100644 index 0000000..5d3a6c7 --- /dev/null +++ b/Areas/MMS/Models/NetworkAccessService.cs @@ -0,0 +1,128 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using System.ComponentModel; +using System.Threading; + +public class NetworkShareAccess : IDisposable +{ + private readonly string _networkPath; + private readonly string _username; + private readonly string _password; + + private bool _isConnected = false; + private static readonly object _lock = new object(); + + public NetworkShareAccess(string networkPath, string username, string password) + { + _networkPath = networkPath?.Trim().Replace('/', '\\') ?? throw new ArgumentNullException(nameof(networkPath)); + if (!_networkPath.StartsWith(@"\\")) + throw new ArgumentException("Network path must start with \\\\"); + + _username = username ?? throw new ArgumentNullException(nameof(username)); + _password = password ?? throw new ArgumentNullException(nameof(password)); + } + + public void ConnectToNetworkPath() + { + lock (_lock) + { + if (_isConnected) return; + + int retries = 0; + while (retries < 3) + { + try + { + var netResource = new NetResource + { + Scope = ResourceScope.GlobalNetwork, + ResourceType = ResourceType.Disk, + DisplayType = ResourceDisplayType.Share, + RemoteName = _networkPath + }; + + int result = WNetAddConnection2(netResource, _password, _username, 0); + + if (result == 0) + { + _isConnected = true; + Console.WriteLine($"Connected to {_networkPath}"); + return; + } + + if (result == 1219) // Multiple connections + { + WNetCancelConnection2(_networkPath, 0, true); + Thread.Sleep(1000); + retries++; + continue; + } + + throw new IOException($"Failed to connect. Error {result}: {GetNetworkErrorDescription(result)}"); + } + catch + { + if (++retries >= 3) throw; + Thread.Sleep(1000); + } + } + } + } + + public void DisconnectFromNetworkShare() + { + lock (_lock) + { + if (!_isConnected) return; + + try + { + int result = WNetCancelConnection2(_networkPath, 0, true); + if (result != 0) + Console.WriteLine($"Warning: Disconnect failed (Error {result})"); + } + finally + { + _isConnected = false; + } + } + } + + public void Dispose() => DisconnectFromNetworkShare(); + + private string GetNetworkErrorDescription(int errorCode) => errorCode switch + { + 5 => "Access denied", + 53 => "Network path not found", + 67 => "Network name not found", + 85 => "Network connection already exists", + 86 => "Invalid password", + 1219 => "Multiple connections to a server or shared resource not allowed", + _ => new Win32Exception(errorCode).Message + }; + + [DllImport("mpr.dll", CharSet = CharSet.Unicode)] + private static extern int WNetAddConnection2(NetResource netResource, string password, string username, int flags); + + [DllImport("mpr.dll", CharSet = CharSet.Unicode)] + private static extern int WNetCancelConnection2(string name, int flags, bool force); + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + private class NetResource + { + public ResourceScope Scope; + public ResourceType ResourceType; + public ResourceDisplayType DisplayType; + public int Usage; + public string? LocalName; //? or required TBD + public string? RemoteName; // + public string? Comment; // + public string? Provider; // + } + + private enum ResourceScope { Connected = 1, GlobalNetwork, Remembered, Recent, Context } + private enum ResourceType { Any = 0, Disk = 1, Print = 2, Reserved = 8 } + private enum ResourceDisplayType { Generic = 0x0, Domain = 0x01, Server = 0x02, Share = 0x03, File = 0x04, Group = 0x05 } +} \ No newline at end of file diff --git a/Areas/MMS/Models/PDFGenerator/TarBallPDF.cs b/Areas/MMS/Models/PDFGenerator/TarBallPDF.cs new file mode 100644 index 0000000..7fe9c82 --- /dev/null +++ b/Areas/MMS/Models/PDFGenerator/TarBallPDF.cs @@ -0,0 +1,405 @@ +using QuestPDF.Fluent; +using QuestPDF.Infrastructure; +using QuestPDF.Helpers; +using Google.Protobuf.WellKnownTypes; +using PSTW_CentralSystem.Models; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal; + +namespace PSTW_CentralSystem.Areas.MMS.Models.PDFGenerator +{ + public class TarBallPDF(string stateName, string stationID, string locationName, + string longitude, string latitude, DateTime dateSample, TimeSpan timeSample, + string classifyID, bool tarBallYes, bool tarBallNo, bool isSand, bool isNonSandy, + bool isCoquina, string photoPath1, string photoPath2, string photoPath3, string photoPath4, + string? photoPath5, string? photoPath6, string? photoPath7, string? photoPath8, + string? optionalName1, string? optionalName2, string? optionalName3, string? optionalName4, + string firstSampler, string fullName, string levelName + ) + : IDocument + { + //have to be arranged accordingly(?) + private readonly string _stateName = stateName; + private readonly string _stationId = stationID; + private readonly string _locationName = locationName; + private readonly string _longitude = longitude; + private readonly string _latitude = latitude; + private readonly DateTime _dateSample = dateSample; + private readonly TimeSpan _timeSample = timeSample; + private readonly string _classifyID = classifyID; + private readonly bool _tarBallYes = tarBallYes; + private readonly bool _tarBallNo = tarBallNo; + private readonly bool _isSand = isSand; + private readonly bool _isNonSandy = isNonSandy; + private readonly bool _isCoquina = isCoquina; + private readonly string _photoPath1 = photoPath1; + private readonly string _photoPath2 = photoPath2; + private readonly string _photoPath3 = photoPath3; + private readonly string _photoPath4 = photoPath4; + private readonly string? _photoPath5 = photoPath5; + private readonly string? _photoPath6 = photoPath6; + private readonly string? _photoPath7 = photoPath7; + private readonly string? _photoPath8 = photoPath8; + private readonly string? _optionalName1 = optionalName1; + private readonly string? _optionalName2 = optionalName2; + private readonly string? _optionalName3 = optionalName3; + private readonly string? _optionalName4 = optionalName4; + private readonly string _firstSampler = firstSampler; + private readonly string _fullName = fullName; + private readonly string _levelName = levelName; + + private Image? LoadImage(string? imagePath) + { + if (string.IsNullOrEmpty(imagePath)) //check if photo is missing + { + return null; // returns 'nothing' (safe) + } + + try + { + return Image.FromFile(imagePath); //load photo + } + catch + { + return null; //if loading fails, returns 'nothing' (safe) + } + } + + public DocumentMetadata GetMetadata() => new() + { + Title = "TARBALL SAMPLING FORM", + Author = "PAKAR SCIENO TW Integrated Environmental Solutions", + Subject = "Environmental Survey and Observations" + }; + + // Compose the PDF content + public void Compose(IDocumentContainer container) + { + container.Page(page => + { + // Page Setup + page.Size(PageSizes.A4); + page.Margin(1.1f, Unit.Centimetre); + page.DefaultTextStyle(x => x.FontFamily("Arial").FontSize(10)); + + //HEADER SECTION ========================================================================== + //will be included in each page + page.Header().Row(row => + { + row.RelativeItem(1).Element(CellStyle) + .AlignMiddle() + .AlignCenter() + .Image("wwwroot/assets/images/pstw-logo.jpg") + .FitArea(); + + row.RelativeItem(1).Element(CellStyle) + .AlignMiddle() + .AlignCenter() + .Text("TARBALL SAMPLING FORM") + .FontSize(16) + .FontColor("#4B0082"); + + row.RelativeItem(1).Column(column => + { + column.Spacing(0); + + column.Item().Row(innerRow => + { + innerRow.RelativeItem(1).Element(CellStyle).Text("Document:") + .AlignLeft(); + innerRow.RelativeItem(1).Element(CellStyle).Text("F-MM06") + .AlignLeft().Bold(); + }); + column.Item().Row(innerRow => + { + innerRow.RelativeItem(1).Element(CellStyle).Text("Effective Date:") + .AlignLeft(); + innerRow.RelativeItem(1).Element(CellStyle).Text("1 April 2025") + .AlignLeft(); + }); + column.Item().Row(innerRow => + { + innerRow.RelativeItem(1).Element(CellStyle).Text("Revision No.") + .AlignLeft(); + innerRow.RelativeItem(1).Element(CellStyle).Text("02") + .AlignLeft(); + }); + + }); + + static IContainer CellStyle(IContainer container) + => container.Border(0.5f).Padding(5); + + }); + //HEADER SECTION END ========================================================================== + + + // CONTENT SECTION ============================================================================ + page.Content().Column(column => + { + // Observations Table + column.Item().Element(container => + { + container + .PaddingTop(20) + .PaddingBottom(10) + .Text("Please be informed that we have observed the following conditions:"); + }); + column.Item().Table(table => + { + column.Spacing(0); + + table.ColumnsDefinition(columns => + { + columns.RelativeColumn(3); + columns.RelativeColumn(3); + }); + + table.Cell() + .Background(Colors.Grey.Lighten2).Element(CellStyle).Text("STATE") + .Bold(); + table.Cell().Element(CellStyle).Text(_stateName); + + table.Cell() + .Background(Colors.Grey.Lighten2).Element(CellStyle).Text("STATION ID") + .Bold(); + table.Cell().Element(CellStyle).Text(_stationId); + + table.Cell() + .Background(Colors.Grey.Lighten2).Element(CellStyle).Text("LOCATION") + .Bold(); + table.Cell().Element(CellStyle).Text(_locationName); + + table.Cell() + .Background(Colors.Grey.Lighten2).Element(CellStyle).Text("TARBALL SURVEY LOCATION LONGITUDE & LATITUDE") + .Bold(); + table.Cell().Element(CellStyle).Text($"{_longitude}, {_latitude}"); + + table.Cell() + .Background(Colors.Grey.Lighten2).Element(CellStyle).Text("DATE / TIME") + .Bold(); + table.Cell().Element(CellStyle).Text($"{_dateSample:yyyy-MM-dd} {_timeSample:hh\\:mm\\:ss}"); + }); + + column.Spacing(3); + + // Survey Findings ======================================================================================= + column.Item() + .PaddingTop(10) + .PaddingBottom(10) + .Text("SURVEY FINDING:") + .Bold().FontSize(12); + + column.Item() + .PaddingBottom(10) + .Text(text => + { + text.Span("Tar Ball: ").Style(TextStyle.Default.FontSize(10)); + text.Span(_classifyID == "NO" ? " ☐ YES ☑ NO" : " ☑ YES ☐ NO").Style(TextStyle.Default.FontSize(10)); + }); + + column.Item() + .PaddingBottom(10) + .Text("If YES, Tar Ball falls under the Classification of:") + .FontSize(10); + + column.Item() + .PaddingBottom(10) + .Text(text => + { + text.Span(_classifyID == "SD" ? "☑ Sand " : "☐ Sand ").Style(TextStyle.Default.FontSize(10)); + text.Span(_classifyID == "NS" ? " ☑ Non-sandy " : " ☐ Non-sandy ").Style(TextStyle.Default.FontSize(10)); + text.Span(_classifyID == "CQ" ? "☑ Coquina" : "☐ Coquina").Style(TextStyle.Default.FontSize(10)); + }); + + column.Item() + .PaddingBottom(10) + .Text("*tick wherever applicable") + .Italic(); + + // Photos Section Title + column.Item() + .PaddingBottom(5) + .Text("PHOTOGRAPHS OF SAMPLING") + .AlignCenter() + .Bold() + .FontSize(14); + + // Photos Section + column.Item().Table(table => + { + column.Spacing(0); + + table.ColumnsDefinition(columns => + { + columns.RelativeColumn(1); + columns.RelativeColumn(1); + }); + + // Row 1: Photos ==================================== + table.Cell().Element(CellStyle).Height(150) + .Image(LoadImage(_photoPath1) ?? null) // Loads image or uses null. if exist, fill cell. if null, cell stay empty + .FitArea(); + + table.Cell().Element(CellStyle).Height(150) + .Image(LoadImage(_photoPath2) ?? null) + .FitArea(); + + // Row 2: Captions for figure 1 & 2 ================= + table.Cell().Element(CellStyle) + .Text("Figure 1: Left Side Coastal View") + .FontSize(12).AlignLeft(); + + table.Cell().Element(CellStyle) + .Text("Figure 2: Right Side Coastal View") + .FontSize(12).AlignLeft(); + + // Row 3 ============================================= + table.Cell().Element(CellStyle).Height(150) + .Image(LoadImage(_photoPath3) ?? null) // Just pass null if no image + .FitArea(); + + table.Cell().Element(CellStyle).Height(150) + .Image(LoadImage(_photoPath4) ?? null) // Just pass null if no image + .FitArea(); + + // Row 4: Captions for figure 3 & 4 ================= + table.Cell().Element(CellStyle) + .Text("Figure 3: Drawing Vertical Lines") + .FontSize(12).AlignLeft(); + + table.Cell().Element(CellStyle) + .Text("Figure 4: Drawing Horizontal Lines (Racking)") + .FontSize(12).AlignLeft(); + }); + + // Page Break + column.Item().PageBreak(); + + column.Spacing(3); + + // Additional Photos Section + column.Item().Table(table => + { + column.Spacing(3); + + table.ColumnsDefinition(columns => + { + columns.RelativeColumn(1); + columns.RelativeColumn(1); + }); + + // Helper function to safely add image cells + void AddOptionalImageCell(string imagePath) + { + table.Cell().Element(CellStyle).Height(150).Element(cell => + { + var image = LoadImage(imagePath); + if (image != null) + { + cell.Image(image).FitArea(); + } + // If null, leaves an empty cell + }); + } + + // Row 1: Optional images 5 & 6 + AddOptionalImageCell(_photoPath5); + AddOptionalImageCell(_photoPath6); + + // Row 2: Captions + table.Cell().Element(CellStyle) + .Text($"Figure 5: {(_optionalName1 ?? "")}") + .FontSize(12).AlignLeft(); + + table.Cell().Element(CellStyle) + .Text($"Figure 6: {(_optionalName2 ?? "")}") + .FontSize(12).AlignLeft(); + + // Row 3: Optional images 7 & 8 + AddOptionalImageCell(_photoPath7); + AddOptionalImageCell(_photoPath8); + + // Row 4: Captions + table.Cell().Element(CellStyle) + .Text($"Figure 7: {(_optionalName3 ?? "")}") + .FontSize(12).AlignLeft(); + + table.Cell().Element(CellStyle) + .Text($"Figure 8: {(_optionalName4 ?? "")}") + .FontSize(12).AlignLeft(); + }); + + // Note Section + column.Item() + .PaddingTop(10) + .PaddingBottom(20) + .Text("* If there are any event observe at the current station it is compulsory to add optional photo with description (figure 5 to figure 8)") + .Bold() + .FontSize(10) + .AlignLeft(); + + // Signature Section + column.Item().Table(table => + { + table.ColumnsDefinition(columns => + { + //the overall layout of the authorization section + columns.RelativeColumn(2); + columns.RelativeColumn(1); + columns.RelativeColumn(2); + columns.RelativeColumn(1); + columns.RelativeColumn(1); + }); + + table.Cell().RowSpan(2).Element(CellStyle) + .Text(text => + { + text.Span("REPORTED BY: ").Bold().FontSize(12); + text.Span(_firstSampler).FontSize(12); + }); + table.Cell().Element(CellStyle).Text("Signature").FontSize(12); + table.Cell().Element(CellStyle).Text(""); + table.Cell().Element(CellStyle).Text("Date").FontSize(12); + table.Cell().Element(CellStyle).Text($"{_dateSample:dd/MM/yyyy}").FontSize(12); + + table.Cell().Element(CellStyle).Text("Designation").FontSize(12); + table.Cell().ColumnSpan(3).Element(CellStyle).Text(_levelName).FontSize(12); + + table.Cell().RowSpan(2).Element(CellStyle) + .Text(text => + { + text.Span("CHECKED BY: ").Bold().FontSize(12); + text.Span("RIFAIE AZHARI").FontSize(12); + }); + table.Cell().Element(CellStyle).Text("Signature").FontSize(12); + table.Cell().ColumnSpan(2).Element(CellStyle).Text(""); + table.Cell().Element(CellStyle).Text(""); + + table.Cell().Element(CellStyle).Text("Designation").FontSize(12); + table.Cell().ColumnSpan(3).Element(CellStyle).Text("Executive").FontSize(12); + + table.Cell().RowSpan(2).Element(CellStyle) + .Text(text => + { + text.Span("VERIFIED BY: ").Bold().FontSize(12); + text.Span("J SOMU").FontSize(12); + }); + table.Cell().Element(CellStyle).Text("Signature").FontSize(12); + table.Cell().ColumnSpan(2).Element(CellStyle).Text(""); + table.Cell().Element(CellStyle).Text(""); + + table.Cell().Element(CellStyle).Text("Designation").FontSize(12); + table.Cell().ColumnSpan(3).Element(CellStyle).Text("Technical Manager").FontSize(12); + }); + }); + + // Footer Section + page.Footer().AlignCenter().Text(text => + { + }); + + static IContainer CellStyle(IContainer container) => container.Border(0.5f).Padding(5); + }); + } + } +} diff --git a/Areas/MMS/Views/Marine/Index.cshtml b/Areas/MMS/Views/Marine/Index.cshtml new file mode 100644 index 0000000..efc300f --- /dev/null +++ b/Areas/MMS/Views/Marine/Index.cshtml @@ -0,0 +1,6 @@ +@{ + ViewData["Title"] = "MMS Dashboard"; +} + +

Welcome to the MMS Dashboard

+

This is where you’ll add content for MMS later.

\ No newline at end of file diff --git a/Areas/MMS/Views/Marine/TarBallForm.cshtml b/Areas/MMS/Views/Marine/TarBallForm.cshtml new file mode 100644 index 0000000..afae953 --- /dev/null +++ b/Areas/MMS/Views/Marine/TarBallForm.cshtml @@ -0,0 +1,224 @@ +@{ + ViewData["Title"] = "Tarball Report"; + Layout = "~/Views/Shared/_Layout.cshtml"; +} + + + + + + + Tarball Report + + + + + +
+
+

Month

+ + +

Year

+ + +
+ +
+
+ +
+ + + + + + + + + + + + +
No.DateStationTimeStatusPDF
+
+
+ + + +@section Scripts { + + + +} diff --git a/Controllers/API/Inventory/InvMainAPI.cs b/Controllers/API/Inventory/InvMainAPI.cs index 96d5e79..aaa579b 100644 --- a/Controllers/API/Inventory/InvMainAPI.cs +++ b/Controllers/API/Inventory/InvMainAPI.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; +using Microsoft.VisualStudio.Web.CodeGenerators.Mvc.Templates.BlazorIdentity.Pages; using Mono.TextTemplating; using Newtonsoft.Json; using PSTW_CentralSystem.Areas.Inventory.Models; @@ -265,6 +266,7 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory var userRole = await _userManager.GetRolesAsync(user); var isAdmin = userRole.Contains("SystemAdmin") || userRole.Contains("SuperAdmin") || userRole.Contains("Finance"); List itemList = new List(); + List createDate = new List(); // Get the item list if (isAdmin) { @@ -296,14 +298,22 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory .ThenInclude(m => m!.FromUser) .Where(i => i.DepartmentId == user.departmentId) .ToListAsync(); + } + // Get the departments list (DepartmentId references Departments) var departments = await _centralDbContext.Departments.ToListAsync(); + var createDates = await _centralDbContext.ItemMovements.Where(r => r.Action == "Register").ToListAsync(); + + // Buat dictionary agar lebih cepat dicari berdasarkan ItemID + var createDateDict = await _centralDbContext.ItemMovements.Where(r => r.Action == "Register").GroupBy(r => r.ItemId).ToDictionaryAsync(g => g.Key, g => g.Min(m => m.Date)); + // Now join items with users and departments manually var itemListWithDetails = itemList.Select(item => new { + createDate = createDateDict.ContainsKey(item.ItemID) ? createDateDict[item.ItemID].ToString("dd/MM/yyyy HH:mm:ss") : null, item.ItemID, item.UniqueID, item.CompanyId, @@ -324,7 +334,8 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory EndWDate = item.EndWDate.ToString("dd/MM/yyyy"), InvoiceDate = item.InvoiceDate?.ToString("dd/MM/yyyy"), item.Department?.DepartmentName, - CreatedBy=item.CreatedBy!.UserName, + RegisterDate = createDate, + CreatedBy =item.CreatedBy!.UserName, item.Product!.ProductName, item.Product!.ProductShortName, item.Product!.Category, @@ -465,12 +476,26 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory return NotFound(new { success = false, message = "Item not found" }); } + // Get related item movements + var itemMovements = await _centralDbContext.ItemMovements + .Where(i => i.ItemId == item.ItemID) + .ToListAsync(); + + // Remove all related item movements + if (itemMovements.Any()) + { + _centralDbContext.ItemMovements.RemoveRange(itemMovements); + await _centralDbContext.SaveChangesAsync(); + } + + // Remove the item itself _centralDbContext.Items.Remove(item); await _centralDbContext.SaveChangesAsync(); return Ok(new { success = true, message = "Item deleted successfully" }); } + [HttpPost("GetItem/{id}")] // Endpoint to retrieve an item by its ID public async Task GetItem(string id) { @@ -538,6 +563,7 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory item.Movement?.ToOther, item.Movement?.LatestStatus, item.Movement?.LastUser, + item.Movement?.LastStore, item.Movement?.MovementComplete, remark = item.Movement?.Remark, QRString = $"{HttpContext.Request.Scheme}://{HttpContext.Request.Host.Value}/I/{item.UniqueID}" // Generate QR String @@ -565,16 +591,18 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory .Include(i => i.NextUser) .ToListAsync(); - int itemrow = 0; - var itemMovementListWithQR = itemMovementList.Select(item => new - { - id = itemrow++, - item, // Includes all properties of the original item - QRString = $"{HttpContext.Request.Scheme}://{HttpContext.Request.Host.Value}/I/{item.ItemId}", // Generate QR String - ProductName = item.Item?.Product?.ProductName, - toUserName = item.NextUser?.FullName, - lastUserName = item.FromUser?.FullName - }).ToList(); + // if use qr, need to use this. else do simple return json. datatable qr will read dom and replace element with id=qr{qrstring} with qr image. + // then need dynamic numbering for qr even if item movement is repeated by the same item + //int itemrow = 0; + //var itemMovementListWithQR = itemMovementList.Select(item => new + //{ + // id = itemrow++, + // item, // Includes all properties of the original item + // QRString = $"{HttpContext.Request.Scheme}://{HttpContext.Request.Host.Value}/I/{item.ItemId}", // Generate QR String + // ProductName = item.Item?.Product?.ProductName, + // toUserName = item.NextUser?.FullName, + // lastUserName = item.FromUser?.FullName + //}).ToList(); //Console.WriteLine(Json(itemMovementListWithQR)); @@ -736,6 +764,7 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory return NotFound("Item movement record not found."); } + updatedList.LastUser = receiveMovement.LastUser; updatedList.LatestStatus = receiveMovement.LatestStatus; updatedList.receiveDate = receiveMovement.receiveDate; updatedList.Remark = receiveMovement.Remark; @@ -969,6 +998,74 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory #endregion #region ItemRequestAdmin + + [HttpPost("AddRequestMaster")] + public async Task AddRequestMaster([FromBody] RequestModel request) + { + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + try + { + var findUniqueCode = _centralDbContext.Products.FirstOrDefault(r => r.ProductId == request.ProductId); + var findUniqueUser = _centralDbContext.Users.FirstOrDefault(r => r.Id == request.UserId); + + if (!string.IsNullOrEmpty(request.Document)) + { + + var bytes = Convert.FromBase64String(request.Document); + string filePath = ""; + + var uniqueAbjad = new string(Enumerable.Range(0, 8).Select(_ => "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"[new Random().Next(36)]).ToArray()); + + + if (IsImage(bytes)) + { + filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/media/inventory/request", findUniqueUser.FullName + " " + findUniqueCode.ModelNo + "(" + uniqueAbjad + ") Request.jpg"); + request.Document = "/media/inventory/request/" + findUniqueUser.FullName + " " + findUniqueCode.ModelNo + "(" + uniqueAbjad + ") Request.jpg"; + } + else if (IsPdf(bytes)) + { + filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/media/inventory/request", findUniqueUser.FullName + " " + findUniqueCode.ModelNo + "_Request.pdf"); + request.Document = "/media/inventory/request/" + findUniqueUser.FullName + " " + findUniqueCode.ModelNo + "(" + uniqueAbjad + ") Request.pdf"; + } + else + { + return BadRequest("Unsupported file format."); + } + + await System.IO.File.WriteAllBytesAsync(filePath, bytes); + } + + _centralDbContext.Requests.Add(request); + await _centralDbContext.SaveChangesAsync(); + + var updatedList = await _centralDbContext.Requests.ToListAsync(); + + return Json(updatedList.Select(i => new + { + i.ProductId, + i.UserId, + i.status, + i.StationId, + i.RequestQuantity, + i.requestDate, + i.ProductCategory, + i.Document, + i.approvalDate, + i.remarkMasterInv, + i.remarkUser, + i.fromStoreItem, + i.assignStoreItem, + })); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } + } + [HttpGet("ItemRequestList")] public async Task ItemRequestList() { @@ -977,6 +1074,7 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory return Json(itemRequestList.Select(i => new { i.requestID, + i.UserId, productName = i.Product?.ProductName, i.ProductId, productImage = i.Product?.ImageProduct, @@ -991,6 +1089,8 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory i.approvalDate, i.remarkMasterInv, i.remarkUser, + i.assignStoreItem, + i.fromStoreItem, })); @@ -1188,6 +1288,22 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory return Json(storeList); } + [HttpPost("StoreSpecificMasterList/{userId}")] + public async Task StoreSpecificMasterList(int userId) + { + var storeList = await _centralDbContext.InventoryMasters + .Where(i => i.UserId == userId) + .Select(i => i.StoreId) // Extract only StoreIds + .Distinct() // Avoid duplicate queries + .ToListAsync(); + + var storeSpecific = await _centralDbContext.Stores + .Where(s => storeList.Contains(s.Id)) // Fetch all relevant stores at once + .ToListAsync(); + + return Json(storeSpecific); + } + #endregion Store #region AllUser @@ -1222,7 +1338,7 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory { return NotFound("Item movement record not found."); } - + updatedList.MovementComplete = receiveMovement.MovementComplete; updatedList.LatestStatus = receiveMovement.LatestStatus; updatedList.receiveDate = receiveMovement.receiveDate; updatedList.MovementComplete = receiveMovement.MovementComplete; diff --git a/Controllers/API/MarineAPI.cs b/Controllers/API/MarineAPI.cs new file mode 100644 index 0000000..df7ef37 --- /dev/null +++ b/Controllers/API/MarineAPI.cs @@ -0,0 +1,11 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace PSTW_CentralSystem.Controllers.API +{ + [Route("api/[controller]")] + [ApiController] + public class MarineAPI : ControllerBase + { + } +} diff --git a/CustomPolicy/RoleModulePolicy.cs b/CustomPolicy/RoleModulePolicy.cs index bdf280e..b59713d 100644 --- a/CustomPolicy/RoleModulePolicy.cs +++ b/CustomPolicy/RoleModulePolicy.cs @@ -5,6 +5,8 @@ using PSTW_CentralSystem.Models; using Newtonsoft.Json; using System.Text.Json; using System.Data; +using Microsoft.EntityFrameworkCore; +using System.Reflection; namespace PSTW_CentralSystem.CustomPolicy { @@ -32,7 +34,7 @@ namespace PSTW_CentralSystem.CustomPolicy var userRole = await _userManager.GetRolesAsync(currentUser ?? new UserModel()); var moduleName = _httpContextAccessor.HttpContext?.GetRouteData().Values["controller"]?.ToString(); var pageName = _httpContextAccessor.HttpContext?.GetRouteData().Values["action"]?.ToString(); - var registeredModule = _authDBContext.ModuleSettings.FirstOrDefault(x => x.ModuleName == moduleName); + var registeredModule = await _authDBContext.ModuleSettings.Where(x => x.ModuleName == moduleName).ToListAsync(); if (checkIfSuperAdmin()) { @@ -83,30 +85,46 @@ namespace PSTW_CentralSystem.CustomPolicy void checkModuleActiveOrNot() { - if (registeredModule.ModuleStatus == 0) + foreach (var module in registeredModule) { - context.Fail(); - return; + if (module.ModuleStatus == 0) + { + context.Fail(); + return; + } } } void checkModuleHaveRoleOrNot() { - var allowedUserTypes = registeredModule?.AllowedUserType ?? ""; - if (allowedUserTypes == "Public" || userRole.Any(role => allowedUserTypes.Contains(role))) + bool isModuleHaveRole = false; + foreach (var module in registeredModule) { - context.Succeed(requirement); - return; + var allowedUserTypes = module?.AllowedUserType ?? ""; + if (allowedUserTypes == "Public" || userRole.Any(role => allowedUserTypes.Contains(role))) + { + context.Succeed(requirement); + return; + } + else if (currentUser != null && allowedUserTypes == "Registered User") + { + isModuleHaveRole = true; + } + else + { + isModuleHaveRole = false; + } } - else if (currentUser != null && allowedUserTypes == "Registered User" ) - { - checkMethodAndRole(); - } - else + + if (!isModuleHaveRole) { context.Fail(); return; } + else + { + checkMethodAndRole(); + } } void checkMethodAndRole() diff --git a/CustomPolicy/RoleModulePolicy_Backup.cs b/CustomPolicy/RoleModulePolicy_Backup.cs new file mode 100644 index 0000000..e6e224e --- /dev/null +++ b/CustomPolicy/RoleModulePolicy_Backup.cs @@ -0,0 +1,146 @@ +//using Microsoft.AspNetCore.Authorization; +//using Microsoft.AspNetCore.Identity; +//using PSTW_CentralSystem.DBContext; +//using PSTW_CentralSystem.Models; +//using Newtonsoft.Json; +//using System.Text.Json; +//using System.Data; + +//namespace PSTW_CentralSystem.CustomPolicy +//{ +// public class RoleModulePolicy : IAuthorizationRequirement +// { + +// } +// public class RoleModuleHandler : AuthorizationHandler +// { +// private readonly CentralSystemContext _authDBContext; +// private readonly UserManager _userManager; +// private readonly RoleManager _roleManager; +// private readonly IHttpContextAccessor _httpContextAccessor; +// public RoleModuleHandler( CentralSystemContext authDBContext, UserManager userManager, RoleManager roleManager, IHttpContextAccessor httpContextAccessor) +// { +// _authDBContext = authDBContext; +// _userManager = userManager; +// _roleManager = roleManager; +// _httpContextAccessor = httpContextAccessor; +// } +// protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, RoleModulePolicy requirement) +// { +// // Get the current user +// var currentUser = await _userManager.GetUserAsync(context.User); +// var userRole = await _userManager.GetRolesAsync(currentUser ?? new UserModel()); +// var moduleName = _httpContextAccessor.HttpContext?.GetRouteData().Values["controller"]?.ToString(); +// var pageName = _httpContextAccessor.HttpContext?.GetRouteData().Values["action"]?.ToString(); +// var registeredModule = _authDBContext.ModuleSettings.FirstOrDefault(x => x.ModuleName == moduleName); + +// if (checkIfSuperAdmin()) +// { +// context.Succeed(requirement); +// return; +// } +// else { +// checkModuleExistOrNot(); +// checkModuleHaveRoleOrNot(); +// } + +// bool checkIfSuperAdmin() +// { +// var superAdminRole = _authDBContext.Roles.Where(r => r.Name == "SuperAdmin").FirstOrDefault(); +// var sysAdminRole = _authDBContext.Roles.Where(r => r.Name == "SystemAdmin").FirstOrDefault(); +// if (userRole.ToString() != null && userRole.Contains("SuperAdmin") && superAdminRole?.Id == 1) +// { +// return true; +// } +// else if (userRole.ToString() != null && userRole.Contains("SystemAdmin") && sysAdminRole?.Id == 2) +// { +// return true; +// } +// else +// { +// return false; +// } +// } + +// void checkModuleExistOrNot() +// { + +// if ( moduleName == "Admin") +// { +// context.Fail(); +// return; +// } +// else if (registeredModule == null) +// { +// context.Fail(); +// return; +// } +// else +// { +// checkModuleActiveOrNot(); +// } +// } + +// void checkModuleActiveOrNot() +// { +// if (registeredModule.ModuleStatus == 0) +// { +// context.Fail(); +// return; +// } +// } + +// void checkModuleHaveRoleOrNot() +// { +// var allowedUserTypes = registeredModule?.AllowedUserType ?? ""; +// if (allowedUserTypes == "Public" || userRole.Any(role => allowedUserTypes.Contains(role))) +// { +// context.Succeed(requirement); +// return; +// } +// else if (currentUser != null && allowedUserTypes == "Registered User" ) +// { +// checkMethodAndRole(); +// } +// else +// { +// context.Fail(); +// return; +// } +// } + +// void checkMethodAndRole() +// { + +// // Load all ModuleSettings and process them in memory +// var moduleSettings = _authDBContext.ModuleSettings.AsEnumerable(); + +// // Check if the method exists in the module settings +// var isMethodExist = moduleSettings.FirstOrDefault(m => m.MethodAllowedUserType?.Any(mt => mt.MethodName == pageName) == true); + + +// if (isMethodExist != null) // Check if the method exists which means method is registered +// { +// var registeredMethod = moduleSettings.Where(m => m.MethodAllowedUserType != null && m.MethodAllowedUserType.Any(mt => mt.MethodName == pageName)).FirstOrDefault(); +// var allowedUserTypes = registeredMethod?.MethodAllowedUserType?.Where(mt => mt.MethodName == pageName).Select(mt => mt.AllowedUserTypesArray).FirstOrDefault() ?? Array.Empty(); +// if (userRole.Any(role => allowedUserTypes.Contains(role)) || allowedUserTypes.Contains("All")) // Check if the user role is allowed, allowing only registered user to access. +// { +// context.Succeed(requirement); +// return; +// } +// else +// { +// context.Fail(); +// return; +// } +// } +// else // No method is registered to allow all method to be accessed +// { +// context.Succeed(requirement); +// return; +// } +// } +// } + +// } +//} diff --git a/DBContext/CentralSystemContext.cs b/DBContext/CentralSystemContext.cs index 8efb6ec..2199aaf 100644 --- a/DBContext/CentralSystemContext.cs +++ b/DBContext/CentralSystemContext.cs @@ -110,5 +110,6 @@ namespace PSTW_CentralSystem.DBContext public DbSet Approvalflow { get; set; } public DbSet Staffsign { get; set; } + //testingvhjbnadgfsbgdngffdfdsdfdgfdfdg } } diff --git a/DBContext/MMSSystemContext.cs b/DBContext/MMSSystemContext.cs new file mode 100644 index 0000000..bf5474e --- /dev/null +++ b/DBContext/MMSSystemContext.cs @@ -0,0 +1,118 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; +using PSTW_CentralSystem.Models; // Add this to use the MarineTarball class + +namespace PSTW_CentralSystem.DBContext +{ + public class MMSSystemContext : DbContext + { + public MMSSystemContext(DbContextOptions options) : base(options) + { + } + + // DbSet for tbl_marine_tarball + public DbSet MarineTarballs { get; set; } + public DbSet MarineStations { get; set; } + public DbSet States { get; set; } + public DbSet Users { get; set; } + public DbSet Levels { get; set; } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + // Configure properties if needed + modelBuilder.Entity(entity => + { + entity.ToTable("tbl_marine_tarball"); + + entity.HasKey(e => e.Id); // Primary key + entity.Property(e => e.Id).HasColumnName("id"); + entity.Property(e => e.ReportID).HasColumnName("reportID").HasMaxLength(50); + entity.Property(e => e.FirstSampler).HasColumnName("firstSampler").HasMaxLength(50); + entity.Property(e => e.SecondSampler).HasColumnName("secondSampler").HasMaxLength(50); + entity.Property(e => e.DateSample).HasColumnName("dateSample"); + entity.Property(e => e.TimeSample).HasColumnName("timeSample"); + entity.Property(e => e.StationID).HasColumnName("stationID").HasMaxLength(20); + entity.Property(e => e.ClassifyID).HasColumnName("classifyID").HasMaxLength(20); + entity.Property(e => e.Latitude).HasColumnName("latitude"); + entity.Property(e => e.Longitude).HasColumnName("longitude"); + entity.Property(e => e.GetLatitude).HasColumnName("getLatitude"); + entity.Property(e => e.GetLongitude).HasColumnName("getLongitude"); + entity.Property(e => e.OptionalName1).HasColumnName("optionalName1"); + entity.Property(e => e.OptionalName2).HasColumnName("optionalName2"); + entity.Property(e => e.OptionalName3).HasColumnName("optionalName3"); + entity.Property(e => e.OptionalName4).HasColumnName("optionalName4"); + entity.Property(e => e.Timestamp).HasColumnName("timestamp"); + + entity.HasOne(t => t.User) + .WithMany() + .HasForeignKey(t => t.FirstSampler) + .HasPrincipalKey(u => u.FullName); // Assuming User has FullName + + //Configure relationship with TarballStation + entity.HasOne(m => m.MarineStation) + .WithMany() + .HasForeignKey(m => m.StationID) + .HasPrincipalKey(t => t.StationID); + }); + + modelBuilder.Entity(entity => + { + entity.ToTable("tbl_marine_station"); + entity.HasKey(e => e.Id); // Primary key + entity.Property(e => e.Id).HasColumnName("id"); + entity.Property(e => e.StationID).HasColumnName("stationID").HasMaxLength(20); + entity.Property(e => e.StateID).HasColumnName("stateID").HasMaxLength(10); + entity.Property(e => e.CategoryID).HasColumnName("categoryID").HasMaxLength(10); + entity.Property(e => e.LocationName).HasColumnName("locationName").HasMaxLength(50); + entity.Property(e => e.Longitude).HasColumnName("longitude").HasColumnType("decimal(10,5)"); + entity.Property(e => e.Latitude).HasColumnName("latitude").HasColumnType("decimal(10,5)"); + + // Configure relationship with State + entity.HasOne(t => t.State) + .WithMany() + .HasForeignKey(t => t.StateID) + .HasPrincipalKey(s => s.StateID); + }); + + modelBuilder.Entity(entity => + { + entity.ToTable("tbl_state"); + entity.HasKey(e => e.Id); // Primary key + entity.Property(e => e.Id).HasColumnName("id"); + entity.Property(e => e.StateID).HasColumnName("stateID").HasMaxLength(20); + entity.Property(e => e.StateName).HasColumnName("stateName").HasMaxLength(50); + }); + + modelBuilder.Entity(entity => + { + entity.ToTable("tbl_user"); + entity.HasKey(e => e.Id); // Primary key + entity.Property(e => e.Id).HasColumnName("id"); + entity.Property(e => e.UserID).HasColumnName("userID").HasMaxLength(20); + entity.Property(e => e.FullName).HasColumnName("fullname").HasMaxLength(50); + entity.Property(e => e.Username).HasColumnName("username").HasMaxLength(40); + entity.Property(e => e.Password).HasColumnName("pwd").HasMaxLength(100); + entity.Property(e => e.LevelID).HasColumnName("levelID").HasMaxLength(10); + entity.Property(e => e.DeptID).HasColumnName("departID").HasMaxLength(10); + + entity.HasOne(u => u.Level) + .WithMany() + .HasForeignKey(u => u.LevelID) + .HasPrincipalKey(l => l.LevelID); + }); + + modelBuilder.Entity().ToTable("tbl_level"); + + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id); // Primary key + entity.Property(e => e.Id).HasColumnName("id"); + entity.Property(e => e.LevelID).HasColumnName("levelID").HasMaxLength(10); + entity.Property(e => e.LevelName).HasColumnName("levelName").HasMaxLength(10); + }); + } + } +} diff --git a/Migrations/20250310054721_UpdateTableRequest.Designer.cs b/Migrations/20250310054721_UpdateTableRequest.Designer.cs new file mode 100644 index 0000000..0904201 --- /dev/null +++ b/Migrations/20250310054721_UpdateTableRequest.Designer.cs @@ -0,0 +1,1059 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using PSTW_CentralSystem.DBContext; + +#nullable disable + +namespace PSTW_CentralSystem.Migrations +{ + [DbContext(typeof(CentralSystemContext))] + [Migration("20250310054721_UpdateTableRequest")] + partial class UpdateTableRequest + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.11") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("longtext"); + + b.Property("ClaimValue") + .HasColumnType("longtext"); + + b.Property("RoleId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("longtext"); + + b.Property("ClaimValue") + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("varchar(255)"); + + b.Property("ProviderKey") + .HasColumnType("varchar(255)"); + + b.Property("ProviderDisplayName") + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("int"); + + b.Property("RoleId") + .HasColumnType("int"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + + b.HasData( + new + { + UserId = 1, + RoleId = 1 + }, + new + { + UserId = 2, + RoleId = 2 + }); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("int"); + + b.Property("LoginProvider") + .HasColumnType("varchar(255)"); + + b.Property("Name") + .HasColumnType("varchar(255)"); + + b.Property("Value") + .HasColumnType("longtext"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.InventoryMasterModel", b => + { + b.Property("StoreId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("StoreId"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("InventoryMasters"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.ItemModel", b => + { + b.Property("ItemID") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ItemID")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("ConvertPrice") + .HasColumnType("float"); + + b.Property("CreatedByUserId") + .HasColumnType("int"); + + b.Property("Currency") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CurrencyRate") + .HasColumnType("float"); + + b.Property("DODate") + .HasColumnType("datetime(6)"); + + b.Property("DONo") + .HasColumnType("longtext"); + + b.Property("DefaultPrice") + .HasColumnType("float"); + + b.Property("DepartmentId") + .HasColumnType("int"); + + b.Property("EndWDate") + .HasColumnType("datetime(6)"); + + b.Property("InvoiceDate") + .HasColumnType("datetime(6)"); + + b.Property("InvoiceNo") + .HasColumnType("longtext"); + + b.Property("ItemStatus") + .HasColumnType("int") + .HasComment("1 = In stock; 2 = Item Moving; 3 = Item Out; 4 = Item Broken; 5 = Item Lost; 6 = Item Stolen; 7 = Item Damaged; 8 = Item Discarded; 9 = Item Destroyed; 10 = Item Finished;"); + + b.Property("MovementId") + .HasColumnType("int"); + + b.Property("PONo") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("PartNumber") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ProductId") + .HasColumnType("int"); + + b.Property("PurchaseDate") + .HasColumnType("datetime(6)"); + + b.Property("Quantity") + .HasColumnType("int"); + + b.Property("SerialNumber") + .HasColumnType("longtext"); + + b.Property("Supplier") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TeamType") + .HasColumnType("longtext"); + + b.Property("UniqueID") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Warranty") + .HasColumnType("int"); + + b.HasKey("ItemID"); + + b.HasIndex("CompanyId"); + + b.HasIndex("CreatedByUserId"); + + b.HasIndex("DepartmentId"); + + b.HasIndex("MovementId"); + + b.HasIndex("ProductId"); + + b.ToTable("Items"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.ItemMovementModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Action") + .HasColumnType("longtext") + .HasComment("Register, StockIn, Stock Out"); + + b.Property("ConsignmentNote") + .HasColumnType("longtext"); + + b.Property("Date") + .HasColumnType("datetime(6)"); + + b.Property("ItemId") + .HasColumnType("int"); + + b.Property("LastStation") + .HasColumnType("int"); + + b.Property("LastStore") + .HasColumnType("int"); + + b.Property("LastUser") + .HasColumnType("int"); + + b.Property("LatestStatus") + .HasColumnType("longtext") + .HasComment("Repair, Calibration, Faulty, Ready To Deploy, On Delivery"); + + b.Property("MovementComplete") + .HasColumnType("tinyint(1)"); + + b.Property("Quantity") + .HasColumnType("int"); + + b.Property("Remark") + .HasColumnType("longtext"); + + b.Property("ToOther") + .HasColumnType("longtext") + .HasComment("Repair, Calibration, Faulty, Ready To Deploy, On Delivery"); + + b.Property("ToStation") + .HasColumnType("int"); + + b.Property("ToStore") + .HasColumnType("int"); + + b.Property("ToUser") + .HasColumnType("int"); + + b.Property("receiveDate") + .HasColumnType("datetime(6)"); + + b.Property("sendDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("ItemId"); + + b.HasIndex("LastStation"); + + b.HasIndex("LastStore"); + + b.HasIndex("LastUser"); + + b.HasIndex("ToStation"); + + b.HasIndex("ToStore"); + + b.HasIndex("ToUser"); + + b.ToTable("ItemMovements"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.ManufacturerModel", b => + { + b.Property("ManufacturerId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ManufacturerId")); + + b.Property("ManufacturerName") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("ManufacturerId"); + + b.ToTable("Manufacturers"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.ProductModel", b => + { + b.Property("ProductId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ProductId")); + + b.Property("Category") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ImageProduct") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ManufacturerId") + .HasColumnType("int"); + + b.Property("ModelNo") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ProductName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ProductShortName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("QuantityProduct") + .HasColumnType("int"); + + b.HasKey("ProductId"); + + b.HasIndex("ManufacturerId"); + + b.ToTable("Products"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.RequestModel", b => + { + b.Property("requestID") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("requestID")); + + b.Property("Document") + .HasColumnType("longtext"); + + b.Property("ProductCategory") + .HasColumnType("longtext"); + + b.Property("ProductId") + .HasColumnType("int"); + + b.Property("RequestQuantity") + .HasColumnType("int"); + + b.Property("StationId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.Property("approvalDate") + .HasColumnType("datetime(6)"); + + b.Property("assignStoreItem") + .HasColumnType("longtext"); + + b.Property("fromStoreItem") + .HasColumnType("longtext"); + + b.Property("remarkMasterInv") + .HasColumnType("longtext"); + + b.Property("remarkUser") + .HasColumnType("longtext"); + + b.Property("requestDate") + .HasColumnType("datetime(6)"); + + b.Property("status") + .HasColumnType("longtext"); + + b.HasKey("requestID"); + + b.HasIndex("ProductId"); + + b.HasIndex("StationId"); + + b.HasIndex("UserId"); + + b.ToTable("request"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.StationModel", b => + { + b.Property("StationId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("StationId")); + + b.Property("DepartmentId") + .HasColumnType("int"); + + b.Property("StationName") + .HasColumnType("longtext"); + + b.Property("StationPicID") + .HasColumnType("int"); + + b.HasKey("StationId"); + + b.HasIndex("DepartmentId"); + + b.HasIndex("StationPicID"); + + b.ToTable("Stations"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.StoreModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("StoreName") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("CompanyId"); + + b.ToTable("Stores"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.SupplierModel", b => + { + b.Property("SupplierId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("SupplierId")); + + b.Property("SupplierAddress") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("SupplierCompName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("SupplierEmail") + .HasColumnType("longtext"); + + b.Property("SupplierPIC") + .HasColumnType("longtext"); + + b.Property("SupplierPhoneNo") + .HasColumnType("longtext"); + + b.HasKey("SupplierId"); + + b.ToTable("Suppliers"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Models.CompanyModel", b => + { + b.Property("CompanyId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CompanyId")); + + b.Property("CompanyName") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("CompanyId"); + + b.ToTable("Companies"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Models.DepartmentModel", b => + { + b.Property("DepartmentId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("DepartmentId")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("DepartmentCode") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("DepartmentName") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("DepartmentId"); + + b.HasIndex("CompanyId"); + + b.ToTable("Departments"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Models.ModuleSettingModel", b => + { + b.Property("SettingId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("SettingId")); + + b.Property("AllowedUserType") + .HasColumnType("longtext"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("MethodAllowedUserType") + .HasColumnType("json"); + + b.Property("ModuleName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("ModuleStatus") + .HasColumnType("int"); + + b.HasKey("SettingId"); + + b.ToTable("ModuleSettings"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Models.RoleModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("longtext"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + + b.HasData( + new + { + Id = 1, + Description = "Can access all pages", + Name = "SuperAdmin", + NormalizedName = "SUPERADMIN" + }, + new + { + Id = 2, + Description = "Can access some admin pages", + Name = "SystemAdmin", + NormalizedName = "SYSTEMADMIN" + }, + new + { + Id = 3, + Description = "Can access operation pages", + Name = "Engineer", + NormalizedName = "ENGINEER" + }, + new + { + Id = 4, + Description = "Can access data viewer pages", + Name = "Observer", + NormalizedName = "OBSERVER" + }, + new + { + Id = 5, + Description = "Handle inventory module", + Name = "Inventory Master", + NormalizedName = "INVENTORY MASTER" + }, + new + { + Id = 6, + Description = "Involve in inventory transaction", + Name = "Finance", + NormalizedName = "FINANCE" + }); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Models.UserModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("longtext"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("tinyint(1)"); + + b.Property("FullName") + .HasColumnType("longtext"); + + b.Property("LockoutEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("LockoutEnd") + .HasColumnType("datetime(6)"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("longtext"); + + b.Property("PhoneNumber") + .HasColumnType("longtext"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("tinyint(1)"); + + b.Property("SecurityStamp") + .HasColumnType("longtext"); + + b.Property("TwoFactorEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("UserInfoStatus") + .HasColumnType("int"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("departmentId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.HasIndex("departmentId"); + + b.ToTable("AspNetUsers", (string)null); + + b.HasData( + new + { + Id = 1, + AccessFailedCount = 0, + ConcurrencyStamp = "407727d8-2266-45f2-9b48-ef3a450f09c6", + Email = "admin@pstw.com.my", + EmailConfirmed = true, + FullName = "MAAdmin", + LockoutEnabled = false, + NormalizedEmail = "ADMIN@PSTW.COM.MY", + NormalizedUserName = "ADMIN@PSTW.COM.MY", + PasswordHash = "AQAAAAIAAYagAAAAEDc91vi8/AJwNGigDpnzFh7Iplvlph0VGj9GfG1zI6tY/jM/4f3P0CWVQZ/0oetzVg==", + PhoneNumberConfirmed = false, + SecurityStamp = "2faceaca-f491-455a-9f10-3f641a5a7e0d", + TwoFactorEnabled = false, + UserInfoStatus = 1, + UserName = "admin@pstw.com.my" + }, + new + { + Id = 2, + AccessFailedCount = 0, + ConcurrencyStamp = "8065f043-f8ed-4733-aa42-6ee6a1ebb636", + Email = "sysadmin@pstw.com.my", + EmailConfirmed = true, + FullName = "SysAdmin", + LockoutEnabled = false, + NormalizedEmail = "SYSADMIN@PSTW.COM.MY", + NormalizedUserName = "SYSADMIN@PSTW.COM.MY", + PasswordHash = "AQAAAAIAAYagAAAAEOmfi3vsFMnCUitXZqLgUaq5+Jqmigy8HrXwNqd8IELW2yvFQAMrfHLvJM5h0c+lfQ==", + PhoneNumberConfirmed = false, + SecurityStamp = "46a8accc-305f-42e6-a4a2-376bfec07e84", + TwoFactorEnabled = false, + UserInfoStatus = 1, + UserName = "sysadmin@pstw.com.my" + }); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("PSTW_CentralSystem.Models.RoleModel", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("PSTW_CentralSystem.Models.UserModel", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("PSTW_CentralSystem.Models.UserModel", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("PSTW_CentralSystem.Models.RoleModel", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PSTW_CentralSystem.Models.UserModel", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("PSTW_CentralSystem.Models.UserModel", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.InventoryMasterModel", b => + { + b.HasOne("PSTW_CentralSystem.Areas.Inventory.Models.StoreModel", "Store") + .WithMany() + .HasForeignKey("StoreId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PSTW_CentralSystem.Models.UserModel", "User") + .WithOne("Store") + .HasForeignKey("PSTW_CentralSystem.Areas.Inventory.Models.InventoryMasterModel", "UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Store"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.ItemModel", b => + { + b.HasOne("PSTW_CentralSystem.Models.CompanyModel", "Company") + .WithMany() + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PSTW_CentralSystem.Models.UserModel", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedByUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PSTW_CentralSystem.Models.DepartmentModel", "Department") + .WithMany() + .HasForeignKey("DepartmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PSTW_CentralSystem.Areas.Inventory.Models.ItemMovementModel", "Movement") + .WithMany() + .HasForeignKey("MovementId"); + + b.HasOne("PSTW_CentralSystem.Areas.Inventory.Models.ProductModel", "Product") + .WithMany("Items") + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Company"); + + b.Navigation("CreatedBy"); + + b.Navigation("Department"); + + b.Navigation("Movement"); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.ItemMovementModel", b => + { + b.HasOne("PSTW_CentralSystem.Areas.Inventory.Models.ItemModel", "Item") + .WithMany() + .HasForeignKey("ItemId"); + + b.HasOne("PSTW_CentralSystem.Areas.Inventory.Models.StationModel", "FromStation") + .WithMany() + .HasForeignKey("LastStation"); + + b.HasOne("PSTW_CentralSystem.Areas.Inventory.Models.StoreModel", "FromStore") + .WithMany() + .HasForeignKey("LastStore"); + + b.HasOne("PSTW_CentralSystem.Models.UserModel", "FromUser") + .WithMany() + .HasForeignKey("LastUser"); + + b.HasOne("PSTW_CentralSystem.Areas.Inventory.Models.StationModel", "NextStation") + .WithMany() + .HasForeignKey("ToStation"); + + b.HasOne("PSTW_CentralSystem.Areas.Inventory.Models.StoreModel", "NextStore") + .WithMany() + .HasForeignKey("ToStore"); + + b.HasOne("PSTW_CentralSystem.Models.UserModel", "NextUser") + .WithMany() + .HasForeignKey("ToUser"); + + b.Navigation("FromStation"); + + b.Navigation("FromStore"); + + b.Navigation("FromUser"); + + b.Navigation("Item"); + + b.Navigation("NextStation"); + + b.Navigation("NextStore"); + + b.Navigation("NextUser"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.ProductModel", b => + { + b.HasOne("PSTW_CentralSystem.Areas.Inventory.Models.ManufacturerModel", "Manufacturer") + .WithMany() + .HasForeignKey("ManufacturerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Manufacturer"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.RequestModel", b => + { + b.HasOne("PSTW_CentralSystem.Areas.Inventory.Models.ProductModel", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PSTW_CentralSystem.Areas.Inventory.Models.StationModel", "Station") + .WithMany() + .HasForeignKey("StationId"); + + b.HasOne("PSTW_CentralSystem.Models.UserModel", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Product"); + + b.Navigation("Station"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.StationModel", b => + { + b.HasOne("PSTW_CentralSystem.Models.DepartmentModel", "Department") + .WithMany() + .HasForeignKey("DepartmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PSTW_CentralSystem.Models.UserModel", "StationPic") + .WithMany() + .HasForeignKey("StationPicID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Department"); + + b.Navigation("StationPic"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.StoreModel", b => + { + b.HasOne("PSTW_CentralSystem.Models.CompanyModel", "Company") + .WithMany() + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Company"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Models.DepartmentModel", b => + { + b.HasOne("PSTW_CentralSystem.Models.CompanyModel", "Company") + .WithMany("Departments") + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Company"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Models.UserModel", b => + { + b.HasOne("PSTW_CentralSystem.Models.DepartmentModel", "Department") + .WithMany() + .HasForeignKey("departmentId"); + + b.Navigation("Department"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.ProductModel", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Models.CompanyModel", b => + { + b.Navigation("Departments"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Models.UserModel", b => + { + b.Navigation("Store"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Migrations/20250310054721_UpdateTableRequest.cs b/Migrations/20250310054721_UpdateTableRequest.cs new file mode 100644 index 0000000..055e1f4 --- /dev/null +++ b/Migrations/20250310054721_UpdateTableRequest.cs @@ -0,0 +1,68 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace PSTW_CentralSystem.Migrations +{ + /// + public partial class UpdateTableRequest : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "assignStoreItem", + table: "request", + type: "longtext", + nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AddColumn( + name: "fromStoreItem", + table: "request", + type: "longtext", + nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.UpdateData( + table: "AspNetUsers", + keyColumn: "Id", + keyValue: 1, + columns: new[] { "ConcurrencyStamp", "PasswordHash", "SecurityStamp" }, + values: new object[] { "407727d8-2266-45f2-9b48-ef3a450f09c6", "AQAAAAIAAYagAAAAEDc91vi8/AJwNGigDpnzFh7Iplvlph0VGj9GfG1zI6tY/jM/4f3P0CWVQZ/0oetzVg==", "2faceaca-f491-455a-9f10-3f641a5a7e0d" }); + + migrationBuilder.UpdateData( + table: "AspNetUsers", + keyColumn: "Id", + keyValue: 2, + columns: new[] { "ConcurrencyStamp", "PasswordHash", "SecurityStamp" }, + values: new object[] { "8065f043-f8ed-4733-aa42-6ee6a1ebb636", "AQAAAAIAAYagAAAAEOmfi3vsFMnCUitXZqLgUaq5+Jqmigy8HrXwNqd8IELW2yvFQAMrfHLvJM5h0c+lfQ==", "46a8accc-305f-42e6-a4a2-376bfec07e84" }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "assignStoreItem", + table: "request"); + + migrationBuilder.DropColumn( + name: "fromStoreItem", + table: "request"); + + migrationBuilder.UpdateData( + table: "AspNetUsers", + keyColumn: "Id", + keyValue: 1, + columns: new[] { "ConcurrencyStamp", "PasswordHash", "SecurityStamp" }, + values: new object[] { "d801514b-2c36-4df7-9bb5-1c7e351ed27e", "AQAAAAIAAYagAAAAEBSoDiGEYlobLgzVcffYwvTtm1WnXpqrBBT1yYP+kruV4OTtizW7Sel94qAfqUjGcw==", "6132b0af-6a7f-4f38-8959-d049ed486e8f" }); + + migrationBuilder.UpdateData( + table: "AspNetUsers", + keyColumn: "Id", + keyValue: 2, + columns: new[] { "ConcurrencyStamp", "PasswordHash", "SecurityStamp" }, + values: new object[] { "14f11e89-bb92-49dd-a8df-ec5b0d49df2d", "AQAAAAIAAYagAAAAEEvcS1SY+9pxZKH/P1l4TaodgW3SFSRfcZ+PnjB3MiMmEUSyYoo64AQtX0bOxFSX2g==", "6dca2498-5150-4369-9923-6f19a48258d4" }); + } + } +} diff --git a/Migrations/20250311003003_UpdateRequestTable2.Designer.cs b/Migrations/20250311003003_UpdateRequestTable2.Designer.cs new file mode 100644 index 0000000..324e377 --- /dev/null +++ b/Migrations/20250311003003_UpdateRequestTable2.Designer.cs @@ -0,0 +1,1075 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using PSTW_CentralSystem.DBContext; + +#nullable disable + +namespace PSTW_CentralSystem.Migrations +{ + [DbContext(typeof(CentralSystemContext))] + [Migration("20250311003003_UpdateRequestTable2")] + partial class UpdateRequestTable2 + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.11") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("longtext"); + + b.Property("ClaimValue") + .HasColumnType("longtext"); + + b.Property("RoleId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("longtext"); + + b.Property("ClaimValue") + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("varchar(255)"); + + b.Property("ProviderKey") + .HasColumnType("varchar(255)"); + + b.Property("ProviderDisplayName") + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("int"); + + b.Property("RoleId") + .HasColumnType("int"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + + b.HasData( + new + { + UserId = 1, + RoleId = 1 + }, + new + { + UserId = 2, + RoleId = 2 + }); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("int"); + + b.Property("LoginProvider") + .HasColumnType("varchar(255)"); + + b.Property("Name") + .HasColumnType("varchar(255)"); + + b.Property("Value") + .HasColumnType("longtext"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.InventoryMasterModel", b => + { + b.Property("StoreId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("StoreId"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("InventoryMasters"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.ItemModel", b => + { + b.Property("ItemID") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ItemID")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("ConvertPrice") + .HasColumnType("float"); + + b.Property("CreatedByUserId") + .HasColumnType("int"); + + b.Property("Currency") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CurrencyRate") + .HasColumnType("float"); + + b.Property("DODate") + .HasColumnType("datetime(6)"); + + b.Property("DONo") + .HasColumnType("longtext"); + + b.Property("DefaultPrice") + .HasColumnType("float"); + + b.Property("DepartmentId") + .HasColumnType("int"); + + b.Property("EndWDate") + .HasColumnType("datetime(6)"); + + b.Property("InvoiceDate") + .HasColumnType("datetime(6)"); + + b.Property("InvoiceNo") + .HasColumnType("longtext"); + + b.Property("ItemStatus") + .HasColumnType("int") + .HasComment("1 = In stock; 2 = Item Moving; 3 = Item Out; 4 = Item Broken; 5 = Item Lost; 6 = Item Stolen; 7 = Item Damaged; 8 = Item Discarded; 9 = Item Destroyed; 10 = Item Finished;"); + + b.Property("MovementId") + .HasColumnType("int"); + + b.Property("PONo") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("PartNumber") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ProductId") + .HasColumnType("int"); + + b.Property("PurchaseDate") + .HasColumnType("datetime(6)"); + + b.Property("Quantity") + .HasColumnType("int"); + + b.Property("SerialNumber") + .HasColumnType("longtext"); + + b.Property("Supplier") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("TeamType") + .HasColumnType("longtext"); + + b.Property("UniqueID") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Warranty") + .HasColumnType("int"); + + b.HasKey("ItemID"); + + b.HasIndex("CompanyId"); + + b.HasIndex("CreatedByUserId"); + + b.HasIndex("DepartmentId"); + + b.HasIndex("MovementId"); + + b.HasIndex("ProductId"); + + b.ToTable("Items"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.ItemMovementModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Action") + .HasColumnType("longtext") + .HasComment("Register, StockIn, Stock Out"); + + b.Property("ConsignmentNote") + .HasColumnType("longtext"); + + b.Property("Date") + .HasColumnType("datetime(6)"); + + b.Property("ItemId") + .HasColumnType("int"); + + b.Property("LastStation") + .HasColumnType("int"); + + b.Property("LastStore") + .HasColumnType("int"); + + b.Property("LastUser") + .HasColumnType("int"); + + b.Property("LatestStatus") + .HasColumnType("longtext") + .HasComment("Repair, Calibration, Faulty, Ready To Deploy, On Delivery"); + + b.Property("MovementComplete") + .HasColumnType("tinyint(1)"); + + b.Property("Quantity") + .HasColumnType("int"); + + b.Property("Remark") + .HasColumnType("longtext"); + + b.Property("ToOther") + .HasColumnType("longtext") + .HasComment("Repair, Calibration, Faulty, Ready To Deploy, On Delivery"); + + b.Property("ToStation") + .HasColumnType("int"); + + b.Property("ToStore") + .HasColumnType("int"); + + b.Property("ToUser") + .HasColumnType("int"); + + b.Property("receiveDate") + .HasColumnType("datetime(6)"); + + b.Property("sendDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("ItemId"); + + b.HasIndex("LastStation"); + + b.HasIndex("LastStore"); + + b.HasIndex("LastUser"); + + b.HasIndex("ToStation"); + + b.HasIndex("ToStore"); + + b.HasIndex("ToUser"); + + b.ToTable("ItemMovements"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.ManufacturerModel", b => + { + b.Property("ManufacturerId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ManufacturerId")); + + b.Property("ManufacturerName") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("ManufacturerId"); + + b.ToTable("Manufacturers"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.ProductModel", b => + { + b.Property("ProductId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ProductId")); + + b.Property("Category") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ImageProduct") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ManufacturerId") + .HasColumnType("int"); + + b.Property("ModelNo") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ProductName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ProductShortName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("QuantityProduct") + .HasColumnType("int"); + + b.HasKey("ProductId"); + + b.HasIndex("ManufacturerId"); + + b.ToTable("Products"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.RequestModel", b => + { + b.Property("requestID") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("requestID")); + + b.Property("Document") + .HasColumnType("longtext"); + + b.Property("ProductCategory") + .HasColumnType("longtext"); + + b.Property("ProductId") + .HasColumnType("int"); + + b.Property("RequestQuantity") + .HasColumnType("int"); + + b.Property("StationId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.Property("approvalDate") + .HasColumnType("datetime(6)"); + + b.Property("assignStoreItem") + .HasColumnType("int"); + + b.Property("fromStoreItem") + .HasColumnType("int"); + + b.Property("remarkMasterInv") + .HasColumnType("longtext"); + + b.Property("remarkUser") + .HasColumnType("longtext"); + + b.Property("requestDate") + .HasColumnType("datetime(6)"); + + b.Property("status") + .HasColumnType("longtext"); + + b.HasKey("requestID"); + + b.HasIndex("ProductId"); + + b.HasIndex("StationId"); + + b.HasIndex("UserId"); + + b.HasIndex("assignStoreItem"); + + b.HasIndex("fromStoreItem"); + + b.ToTable("request"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.StationModel", b => + { + b.Property("StationId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("StationId")); + + b.Property("DepartmentId") + .HasColumnType("int"); + + b.Property("StationName") + .HasColumnType("longtext"); + + b.Property("StationPicID") + .HasColumnType("int"); + + b.HasKey("StationId"); + + b.HasIndex("DepartmentId"); + + b.HasIndex("StationPicID"); + + b.ToTable("Stations"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.StoreModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("StoreName") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("CompanyId"); + + b.ToTable("Stores"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.SupplierModel", b => + { + b.Property("SupplierId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("SupplierId")); + + b.Property("SupplierAddress") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("SupplierCompName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("SupplierEmail") + .HasColumnType("longtext"); + + b.Property("SupplierPIC") + .HasColumnType("longtext"); + + b.Property("SupplierPhoneNo") + .HasColumnType("longtext"); + + b.HasKey("SupplierId"); + + b.ToTable("Suppliers"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Models.CompanyModel", b => + { + b.Property("CompanyId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CompanyId")); + + b.Property("CompanyName") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("CompanyId"); + + b.ToTable("Companies"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Models.DepartmentModel", b => + { + b.Property("DepartmentId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("DepartmentId")); + + b.Property("CompanyId") + .HasColumnType("int"); + + b.Property("DepartmentCode") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("DepartmentName") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("DepartmentId"); + + b.HasIndex("CompanyId"); + + b.ToTable("Departments"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Models.ModuleSettingModel", b => + { + b.Property("SettingId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("SettingId")); + + b.Property("AllowedUserType") + .HasColumnType("longtext"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("MethodAllowedUserType") + .HasColumnType("json"); + + b.Property("ModuleName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("ModuleStatus") + .HasColumnType("int"); + + b.HasKey("SettingId"); + + b.ToTable("ModuleSettings"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Models.RoleModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("longtext"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + + b.HasData( + new + { + Id = 1, + Description = "Can access all pages", + Name = "SuperAdmin", + NormalizedName = "SUPERADMIN" + }, + new + { + Id = 2, + Description = "Can access some admin pages", + Name = "SystemAdmin", + NormalizedName = "SYSTEMADMIN" + }, + new + { + Id = 3, + Description = "Can access operation pages", + Name = "Engineer", + NormalizedName = "ENGINEER" + }, + new + { + Id = 4, + Description = "Can access data viewer pages", + Name = "Observer", + NormalizedName = "OBSERVER" + }, + new + { + Id = 5, + Description = "Handle inventory module", + Name = "Inventory Master", + NormalizedName = "INVENTORY MASTER" + }, + new + { + Id = 6, + Description = "Involve in inventory transaction", + Name = "Finance", + NormalizedName = "FINANCE" + }); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Models.UserModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("longtext"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("tinyint(1)"); + + b.Property("FullName") + .HasColumnType("longtext"); + + b.Property("LockoutEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("LockoutEnd") + .HasColumnType("datetime(6)"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("longtext"); + + b.Property("PhoneNumber") + .HasColumnType("longtext"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("tinyint(1)"); + + b.Property("SecurityStamp") + .HasColumnType("longtext"); + + b.Property("TwoFactorEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("UserInfoStatus") + .HasColumnType("int"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("departmentId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.HasIndex("departmentId"); + + b.ToTable("AspNetUsers", (string)null); + + b.HasData( + new + { + Id = 1, + AccessFailedCount = 0, + ConcurrencyStamp = "853a1cf1-3482-47c4-b4b0-7b6a3af6696c", + Email = "admin@pstw.com.my", + EmailConfirmed = true, + FullName = "MAAdmin", + LockoutEnabled = false, + NormalizedEmail = "ADMIN@PSTW.COM.MY", + NormalizedUserName = "ADMIN@PSTW.COM.MY", + PasswordHash = "AQAAAAIAAYagAAAAEBJPP1cHHZZyaGLaskNvSj8sOEizvDa1W2JgxMlYtK18+uhZWvW2RPlqBOhaKc0loQ==", + PhoneNumberConfirmed = false, + SecurityStamp = "c911b03d-918a-482f-9c9e-773dc64cdd5d", + TwoFactorEnabled = false, + UserInfoStatus = 1, + UserName = "admin@pstw.com.my" + }, + new + { + Id = 2, + AccessFailedCount = 0, + ConcurrencyStamp = "9ccd914d-6310-4d4e-88c0-e842892e1831", + Email = "sysadmin@pstw.com.my", + EmailConfirmed = true, + FullName = "SysAdmin", + LockoutEnabled = false, + NormalizedEmail = "SYSADMIN@PSTW.COM.MY", + NormalizedUserName = "SYSADMIN@PSTW.COM.MY", + PasswordHash = "AQAAAAIAAYagAAAAELxkKuB4hcfQ7Pqe/XCRgygejUsY7X9ByQuS/3FMl50OSzmz9s0byWxGYWQXbyBpGA==", + PhoneNumberConfirmed = false, + SecurityStamp = "5b9a67a3-8186-474b-9499-c9c40457fb54", + TwoFactorEnabled = false, + UserInfoStatus = 1, + UserName = "sysadmin@pstw.com.my" + }); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("PSTW_CentralSystem.Models.RoleModel", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("PSTW_CentralSystem.Models.UserModel", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("PSTW_CentralSystem.Models.UserModel", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("PSTW_CentralSystem.Models.RoleModel", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PSTW_CentralSystem.Models.UserModel", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("PSTW_CentralSystem.Models.UserModel", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.InventoryMasterModel", b => + { + b.HasOne("PSTW_CentralSystem.Areas.Inventory.Models.StoreModel", "Store") + .WithMany() + .HasForeignKey("StoreId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PSTW_CentralSystem.Models.UserModel", "User") + .WithOne("Store") + .HasForeignKey("PSTW_CentralSystem.Areas.Inventory.Models.InventoryMasterModel", "UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Store"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.ItemModel", b => + { + b.HasOne("PSTW_CentralSystem.Models.CompanyModel", "Company") + .WithMany() + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PSTW_CentralSystem.Models.UserModel", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedByUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PSTW_CentralSystem.Models.DepartmentModel", "Department") + .WithMany() + .HasForeignKey("DepartmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PSTW_CentralSystem.Areas.Inventory.Models.ItemMovementModel", "Movement") + .WithMany() + .HasForeignKey("MovementId"); + + b.HasOne("PSTW_CentralSystem.Areas.Inventory.Models.ProductModel", "Product") + .WithMany("Items") + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Company"); + + b.Navigation("CreatedBy"); + + b.Navigation("Department"); + + b.Navigation("Movement"); + + b.Navigation("Product"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.ItemMovementModel", b => + { + b.HasOne("PSTW_CentralSystem.Areas.Inventory.Models.ItemModel", "Item") + .WithMany() + .HasForeignKey("ItemId"); + + b.HasOne("PSTW_CentralSystem.Areas.Inventory.Models.StationModel", "FromStation") + .WithMany() + .HasForeignKey("LastStation"); + + b.HasOne("PSTW_CentralSystem.Areas.Inventory.Models.StoreModel", "FromStore") + .WithMany() + .HasForeignKey("LastStore"); + + b.HasOne("PSTW_CentralSystem.Models.UserModel", "FromUser") + .WithMany() + .HasForeignKey("LastUser"); + + b.HasOne("PSTW_CentralSystem.Areas.Inventory.Models.StationModel", "NextStation") + .WithMany() + .HasForeignKey("ToStation"); + + b.HasOne("PSTW_CentralSystem.Areas.Inventory.Models.StoreModel", "NextStore") + .WithMany() + .HasForeignKey("ToStore"); + + b.HasOne("PSTW_CentralSystem.Models.UserModel", "NextUser") + .WithMany() + .HasForeignKey("ToUser"); + + b.Navigation("FromStation"); + + b.Navigation("FromStore"); + + b.Navigation("FromUser"); + + b.Navigation("Item"); + + b.Navigation("NextStation"); + + b.Navigation("NextStore"); + + b.Navigation("NextUser"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.ProductModel", b => + { + b.HasOne("PSTW_CentralSystem.Areas.Inventory.Models.ManufacturerModel", "Manufacturer") + .WithMany() + .HasForeignKey("ManufacturerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Manufacturer"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.RequestModel", b => + { + b.HasOne("PSTW_CentralSystem.Areas.Inventory.Models.ProductModel", "Product") + .WithMany() + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PSTW_CentralSystem.Areas.Inventory.Models.StationModel", "Station") + .WithMany() + .HasForeignKey("StationId"); + + b.HasOne("PSTW_CentralSystem.Models.UserModel", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PSTW_CentralSystem.Areas.Inventory.Models.StoreModel", "Stores") + .WithMany() + .HasForeignKey("assignStoreItem"); + + b.HasOne("PSTW_CentralSystem.Areas.Inventory.Models.StoreModel", "Store") + .WithMany() + .HasForeignKey("fromStoreItem"); + + b.Navigation("Product"); + + b.Navigation("Station"); + + b.Navigation("Store"); + + b.Navigation("Stores"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.StationModel", b => + { + b.HasOne("PSTW_CentralSystem.Models.DepartmentModel", "Department") + .WithMany() + .HasForeignKey("DepartmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PSTW_CentralSystem.Models.UserModel", "StationPic") + .WithMany() + .HasForeignKey("StationPicID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Department"); + + b.Navigation("StationPic"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.StoreModel", b => + { + b.HasOne("PSTW_CentralSystem.Models.CompanyModel", "Company") + .WithMany() + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Company"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Models.DepartmentModel", b => + { + b.HasOne("PSTW_CentralSystem.Models.CompanyModel", "Company") + .WithMany("Departments") + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Company"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Models.UserModel", b => + { + b.HasOne("PSTW_CentralSystem.Models.DepartmentModel", "Department") + .WithMany() + .HasForeignKey("departmentId"); + + b.Navigation("Department"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Areas.Inventory.Models.ProductModel", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Models.CompanyModel", b => + { + b.Navigation("Departments"); + }); + + modelBuilder.Entity("PSTW_CentralSystem.Models.UserModel", b => + { + b.Navigation("Store"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Migrations/20250311003003_UpdateRequestTable2.cs b/Migrations/20250311003003_UpdateRequestTable2.cs new file mode 100644 index 0000000..c1742ce --- /dev/null +++ b/Migrations/20250311003003_UpdateRequestTable2.cs @@ -0,0 +1,126 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace PSTW_CentralSystem.Migrations +{ + /// + public partial class UpdateRequestTable2 : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "fromStoreItem", + table: "request", + type: "int", + nullable: true, + oldClrType: typeof(string), + oldType: "longtext", + oldNullable: true) + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "assignStoreItem", + table: "request", + type: "int", + nullable: true, + oldClrType: typeof(string), + oldType: "longtext", + oldNullable: true) + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.UpdateData( + table: "AspNetUsers", + keyColumn: "Id", + keyValue: 1, + columns: new[] { "ConcurrencyStamp", "PasswordHash", "SecurityStamp" }, + values: new object[] { "853a1cf1-3482-47c4-b4b0-7b6a3af6696c", "AQAAAAIAAYagAAAAEBJPP1cHHZZyaGLaskNvSj8sOEizvDa1W2JgxMlYtK18+uhZWvW2RPlqBOhaKc0loQ==", "c911b03d-918a-482f-9c9e-773dc64cdd5d" }); + + migrationBuilder.UpdateData( + table: "AspNetUsers", + keyColumn: "Id", + keyValue: 2, + columns: new[] { "ConcurrencyStamp", "PasswordHash", "SecurityStamp" }, + values: new object[] { "9ccd914d-6310-4d4e-88c0-e842892e1831", "AQAAAAIAAYagAAAAELxkKuB4hcfQ7Pqe/XCRgygejUsY7X9ByQuS/3FMl50OSzmz9s0byWxGYWQXbyBpGA==", "5b9a67a3-8186-474b-9499-c9c40457fb54" }); + + migrationBuilder.CreateIndex( + name: "IX_request_assignStoreItem", + table: "request", + column: "assignStoreItem"); + + migrationBuilder.CreateIndex( + name: "IX_request_fromStoreItem", + table: "request", + column: "fromStoreItem"); + + migrationBuilder.AddForeignKey( + name: "FK_request_Stores_assignStoreItem", + table: "request", + column: "assignStoreItem", + principalTable: "Stores", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_request_Stores_fromStoreItem", + table: "request", + column: "fromStoreItem", + principalTable: "Stores", + principalColumn: "Id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_request_Stores_assignStoreItem", + table: "request"); + + migrationBuilder.DropForeignKey( + name: "FK_request_Stores_fromStoreItem", + table: "request"); + + migrationBuilder.DropIndex( + name: "IX_request_assignStoreItem", + table: "request"); + + migrationBuilder.DropIndex( + name: "IX_request_fromStoreItem", + table: "request"); + + migrationBuilder.AlterColumn( + name: "fromStoreItem", + table: "request", + type: "longtext", + nullable: true, + oldClrType: typeof(int), + oldType: "int", + oldNullable: true) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "assignStoreItem", + table: "request", + type: "longtext", + nullable: true, + oldClrType: typeof(int), + oldType: "int", + oldNullable: true) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.UpdateData( + table: "AspNetUsers", + keyColumn: "Id", + keyValue: 1, + columns: new[] { "ConcurrencyStamp", "PasswordHash", "SecurityStamp" }, + values: new object[] { "407727d8-2266-45f2-9b48-ef3a450f09c6", "AQAAAAIAAYagAAAAEDc91vi8/AJwNGigDpnzFh7Iplvlph0VGj9GfG1zI6tY/jM/4f3P0CWVQZ/0oetzVg==", "2faceaca-f491-455a-9f10-3f641a5a7e0d" }); + + migrationBuilder.UpdateData( + table: "AspNetUsers", + keyColumn: "Id", + keyValue: 2, + columns: new[] { "ConcurrencyStamp", "PasswordHash", "SecurityStamp" }, + values: new object[] { "8065f043-f8ed-4733-aa42-6ee6a1ebb636", "AQAAAAIAAYagAAAAEOmfi3vsFMnCUitXZqLgUaq5+Jqmigy8HrXwNqd8IELW2yvFQAMrfHLvJM5h0c+lfQ==", "46a8accc-305f-42e6-a4a2-376bfec07e84" }); + } + } +} diff --git a/Migrations/CentralSystemContextModelSnapshot.cs b/Migrations/CentralSystemContextModelSnapshot.cs index a1a96b6..3296b5c 100644 --- a/Migrations/CentralSystemContextModelSnapshot.cs +++ b/Migrations/CentralSystemContextModelSnapshot.cs @@ -422,6 +422,12 @@ namespace PSTW_CentralSystem.Migrations b.Property("approvalDate") .HasColumnType("datetime(6)"); + b.Property("assignStoreItem") + .HasColumnType("int"); + + b.Property("fromStoreItem") + .HasColumnType("int"); + b.Property("remarkMasterInv") .HasColumnType("longtext"); @@ -442,6 +448,10 @@ namespace PSTW_CentralSystem.Migrations b.HasIndex("UserId"); + b.HasIndex("assignStoreItem"); + + b.HasIndex("fromStoreItem"); + b.ToTable("request"); }); @@ -754,16 +764,16 @@ namespace PSTW_CentralSystem.Migrations { Id = 1, AccessFailedCount = 0, - ConcurrencyStamp = "d801514b-2c36-4df7-9bb5-1c7e351ed27e", + ConcurrencyStamp = "853a1cf1-3482-47c4-b4b0-7b6a3af6696c", Email = "admin@pstw.com.my", EmailConfirmed = true, FullName = "MAAdmin", LockoutEnabled = false, NormalizedEmail = "ADMIN@PSTW.COM.MY", NormalizedUserName = "ADMIN@PSTW.COM.MY", - PasswordHash = "AQAAAAIAAYagAAAAEBSoDiGEYlobLgzVcffYwvTtm1WnXpqrBBT1yYP+kruV4OTtizW7Sel94qAfqUjGcw==", + PasswordHash = "AQAAAAIAAYagAAAAEBJPP1cHHZZyaGLaskNvSj8sOEizvDa1W2JgxMlYtK18+uhZWvW2RPlqBOhaKc0loQ==", PhoneNumberConfirmed = false, - SecurityStamp = "6132b0af-6a7f-4f38-8959-d049ed486e8f", + SecurityStamp = "c911b03d-918a-482f-9c9e-773dc64cdd5d", TwoFactorEnabled = false, UserInfoStatus = 1, UserName = "admin@pstw.com.my" @@ -772,16 +782,16 @@ namespace PSTW_CentralSystem.Migrations { Id = 2, AccessFailedCount = 0, - ConcurrencyStamp = "14f11e89-bb92-49dd-a8df-ec5b0d49df2d", + ConcurrencyStamp = "9ccd914d-6310-4d4e-88c0-e842892e1831", Email = "sysadmin@pstw.com.my", EmailConfirmed = true, FullName = "SysAdmin", LockoutEnabled = false, NormalizedEmail = "SYSADMIN@PSTW.COM.MY", NormalizedUserName = "SYSADMIN@PSTW.COM.MY", - PasswordHash = "AQAAAAIAAYagAAAAEEvcS1SY+9pxZKH/P1l4TaodgW3SFSRfcZ+PnjB3MiMmEUSyYoo64AQtX0bOxFSX2g==", + PasswordHash = "AQAAAAIAAYagAAAAELxkKuB4hcfQ7Pqe/XCRgygejUsY7X9ByQuS/3FMl50OSzmz9s0byWxGYWQXbyBpGA==", PhoneNumberConfirmed = false, - SecurityStamp = "6dca2498-5150-4369-9923-6f19a48258d4", + SecurityStamp = "5b9a67a3-8186-474b-9499-c9c40457fb54", TwoFactorEnabled = false, UserInfoStatus = 1, UserName = "sysadmin@pstw.com.my" @@ -973,10 +983,22 @@ namespace PSTW_CentralSystem.Migrations .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + b.HasOne("PSTW_CentralSystem.Areas.Inventory.Models.StoreModel", "Stores") + .WithMany() + .HasForeignKey("assignStoreItem"); + + b.HasOne("PSTW_CentralSystem.Areas.Inventory.Models.StoreModel", "Store") + .WithMany() + .HasForeignKey("fromStoreItem"); + b.Navigation("Product"); b.Navigation("Station"); + b.Navigation("Store"); + + b.Navigation("Stores"); + b.Navigation("User"); }); diff --git a/Models/MarineTarball.cs b/Models/MarineTarball.cs new file mode 100644 index 0000000..9321a85 --- /dev/null +++ b/Models/MarineTarball.cs @@ -0,0 +1,83 @@ +using System.ComponentModel.DataAnnotations.Schema; + +namespace PSTW_CentralSystem.Models +{ + public class MarineTarball + { + public int Id { get; set; } // Maps to 'id' + public required string ReportID { get; set; } // Maps to 'reportID' + public required string FirstSampler { get; set; } // Maps to 'firstSampler' + public required string SecondSampler { get; set; } // Maps to 'secondSampler' + public DateTime DateSample { get; set; } // Maps to 'dateSample' + public TimeSpan TimeSample { get; set; } // Maps to 'timeSample' + public required string StationID { get; set; } // Maps to 'stationID' + public required string ClassifyID { get; set; } // Maps to 'classifyID' + public required string Latitude { get; set; } // Maps to 'latitude' + public required string Longitude { get; set; } // Maps to 'longitude' + public double GetLatitude { get; set; } // Maps to 'getLatitude' + public double GetLongitude { get; set; } // Maps to 'getLongitude' + public DateTime Timestamp { get; set; } // Maps to 'timestamp' + public string? OptionalName1 { get; set; } + public string? OptionalName2 { get; set; } + public string? OptionalName3 { get; set; } + public string? OptionalName4 { get; set; } + + public required string PhotoPath1 { get; set; } // Left Side Coastal View + public required string PhotoPath2 { get; set; } // Right Side Coastal View + public required string PhotoPath3 { get; set; } // Vertical Lines + public required string PhotoPath4 { get; set; } // Horizontal Lines + public string? PhotoPath5 { get; set; } // optional + public string? PhotoPath6 { get; set; } // optional + public string? PhotoPath7 { get; set; } // optional + public string? PhotoPath8 { get; set; } // optional + + [ForeignKey("StationID")] + public required MarineStation MarineStation { get; set; } + [ForeignKey("FirstSampler")] + public required User User { get; set; } + } + + public class MarineStation + { + public int Id { get; set; } // Maps to 'id' + public required string StationID { get; set; } // Maps to 'stationID' + public required string StateID { get; set; } // Maps to 'stateID' + public required string CategoryID { get; set; } // Maps to 'categoryID' + public required string LocationName { get; set; } // Maps to 'locationName' + public decimal Longitude { get; set; } // Maps to 'longitude' + public decimal Latitude { get; set; } // Maps to 'latitude' + + [ForeignKey("StateID")] + public required State State { get; set; } + + } + + public class State + { + public int Id { get; set; } // Maps to 'id' + public required string StateID { get; set; } // Maps to 'stateID' + public required string StateName { get; set; } // Maps to 'stateName' + } + + public class User + { + public int Id { get; set; } // Maps to 'id' + public required string UserID { get; set; } // Maps to 'userID' + public required string FullName { get; set; } // Maps to 'fullname' + public required string Username { get; set; } // Maps to 'username' + public required string Password { get; set; } // Maps to 'pwd' + public required string LevelID { get; set; } // Maps to 'levelID' + public required string DeptID { get; set; } // Maps to 'deptID' + + [ForeignKey("LevelID")] + public required Level Level { get; set; } // Maps to 'levelID' + } + + public class Level + { + public int Id { get; set; } // Maps to 'id' + public required string LevelID { get; set; } // Maps to 'levelID' + public required string LevelName { get; set; } // Maps to 'levelName' + } +} + diff --git a/PSTW_CentralSystem.csproj b/PSTW_CentralSystem.csproj index a70452e..1269938 100644 --- a/PSTW_CentralSystem.csproj +++ b/PSTW_CentralSystem.csproj @@ -14,6 +14,7 @@ + @@ -28,11 +29,19 @@ runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + diff --git a/Program.cs b/Program.cs index 29bd396..0938a75 100644 --- a/Program.cs +++ b/Program.cs @@ -10,6 +10,8 @@ using QuestPDF.Infrastructure; using PSTW_CentralSystem.Areas.OTcalculate.Services; using DocumentFormat.OpenXml.Office2016.Drawing.ChartDrawing; +using System.Net; + internal class Program { private static void Main(string[] args) @@ -17,6 +19,7 @@ internal class Program var builder = WebApplication.CreateBuilder(args); var centralConnectionString = builder.Configuration.GetConnectionString("CentralConnnection"); Settings.License = LicenseType.Community; + //var inventoryConnectionString = builder.Configuration.GetConnectionString("InventoryConnection"); // Add services to the container. @@ -25,6 +28,9 @@ internal class Program builder.Services.AddScoped(); + builder.Services.AddScoped(provider => + new NetworkShareAccess(@"\\192.168.12.42\images\marine\manual_tarball", "installer", "mms@pstw")); + Log.Logger = new LoggerConfiguration() .ReadFrom.Configuration(builder.Configuration) @@ -56,6 +62,12 @@ internal class Program ); }); + + builder.Services.AddDbContext(options => + options.UseMySql(builder.Configuration.GetConnectionString("MMSDatabase"), + new MySqlServerVersion(new Version(8, 0, 0)))); + + //builder.Services.AddDbContext(options => //{ // options.UseMySql(inventoryConnectionString, new MySqlServerVersion(new Version(8, 0, 39)), @@ -78,6 +90,7 @@ internal class Program // Add scope builder.Services.AddScoped(); + var app = builder.Build(); // Configure the HTTP request pipeline. @@ -101,6 +114,12 @@ internal class Program app.MapControllerRoute( name: "root", pattern: "{controller=Home}/{action=Index}/{id?}"); + app.MapControllerRoute( + name: "areas", + pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}"); + app.MapControllerRoute( + name: "default", + pattern: "{controller=Home}/{action=Index}/{id?}"); app.Run(); } diff --git a/Views/Shared/_Layout.cshtml b/Views/Shared/_Layout.cshtml index 401f3f2..22b00fb 100644 --- a/Views/Shared/_Layout.cshtml +++ b/Views/Shared/_Layout.cshtml @@ -430,6 +430,7 @@ Module Administration + diff --git a/appsettings.json b/appsettings.json index 5b9735b..2f7706c 100644 --- a/appsettings.json +++ b/appsettings.json @@ -3,10 +3,19 @@ //"DefaultConnection": "Server=localhost;uid=root;Password='';Database=web_interface;" //"DefaultConnection": "server=175.136.244.102;user id=root;password=tw_mysql_root;port=3306;database=web_interface" //"CentralConnnection": "Server=192.168.12.12;Port=3306;uid=installer;password='pstw_mysql_installer';database=pstw_cs;", //DB_dev Local connection - "CentralConnnection": "Server=219.92.7.60;Port=3307;uid=installer;password='pstw_mysql_installer';database=pstw_cs;" //DB_dev Public connection + "CentralConnnection": "Server=219.92.7.60;Port=3307;uid=installer;password='pstw_mysql_installer';database=pstw_cs_prod;" //DB_dev Public connection //"InventoryConnection": "Server=219.92.7.60;Port=3307;uid=installer;password='pstw_mysql_installer';database=pstw_cs_inventory;" //DB_dev connection //"DefaultConnection": "Server=219.92.7.60;Port=3307;uid=intern;password='intern_mysql_acct';database=web_interface;"//DB_dev connection + "MMSDatabase": "Server=192.168.12.42;Port=3306;Uid=mmsuser;password=mms@pstw_mysql_root;database=db_mms;ConvertZeroDateTime=True;" }, + "NetworkCredentials": { + "ImageServer": { + "Username": "installer", + "Password": "mms@pstw", + "Domain": "." + } + }, + "PhotoBasePath": "\\192.168.12.42\\mms\\marine\\manual_tarball", "Logging": { "LogLevel": { "Default": "Information", diff --git a/document.pdf b/document.pdf new file mode 100644 index 0000000..b12d024 Binary files /dev/null and b/document.pdf differ diff --git a/wwwroot/assets/images/pstw-logo.jpg b/wwwroot/assets/images/pstw-logo.jpg new file mode 100644 index 0000000..4e6ffb5 Binary files /dev/null and b/wwwroot/assets/images/pstw-logo.jpg differ