Compare commits

..

No commits in common. "b9a830f86aa51960d68e1370c5b5eab6f9b249d5" and "4e7c5757e0148d2da5a9c942e16c50f0f684598b" have entirely different histories.

36 changed files with 804 additions and 5073 deletions

View File

@ -26,12 +26,6 @@ namespace PSTW_CentralSystem.Areas.Inventory.Models
public DateTime? approvalDate { get; set; } public DateTime? approvalDate { get; set; }
public int? RequestQuantity { get; set; } public int? RequestQuantity { get; set; }
public string? Document { 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; }
} }
} }

View File

@ -49,7 +49,7 @@
margin-left: auto !important; /* Push Complete/Incomplete to right */ margin-left: auto !important; /* Push Complete/Incomplete to right */
} }
</style> </style>
@await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml") @await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml");
<div id="registerItem" class="row"> <div id="registerItem" class="row">
<div class="row mb-3" > <div class="row mb-3" >
<h2 for="sortSelect" class="col-sm-1 col-form-h2" style="min-width:140px;">Sort by:</h2> <h2 for="sortSelect" class="col-sm-1 col-form-h2" style="min-width:140px;">Sort by:</h2>
@ -118,8 +118,7 @@
<h2>Item Movement List</h2> <h2>Item Movement List</h2>
</div> </div>
<div class="card-body"> <div class="card-body">
<table class="table table-bordered table-hover table-striped no-wrap" id="itemDatatable" <table class="table table-bordered table-hover table-striped no-wrap" id="itemDatatable" style=" width:100%;border-style: solid; border-width: 1px"></table>
style=" width:100%;border-style: solid; border-width: 1px"></table>
</div> </div>
</div> </div>
</div> </div>
@ -132,9 +131,7 @@
</div> </div>
<div v-for="(group, itemId) in filteredItems" :key="itemId" class="row card"> <div v-for="(group, itemId) in filteredItems" :key="itemId" class="row card">
<div class="card-header d-flex justify-content-between align-items-center"> <div class="card-header d-flex justify-content-between align-items-center">
@* <h2>Item : {{ group.uniqueID }}</h2> *@ <h2>Item : {{ group.uniqueID }}</h2>
<h2 v-if="group.uniqueID">Item : {{ group.uniqueID }}</h2>
<h2 v-else>Item : No Item Tracked</h2>
<button class="btn btn-light" v-on:click="toggleCategory(itemId)"> <button class="btn btn-light" v-on:click="toggleCategory(itemId)">
<i :class="categoryVisible[itemId] ? 'fas fa-chevron-up' : 'fas fa-chevron-down'"></i> Show Details <i :class="categoryVisible[itemId] ? 'fas fa-chevron-up' : 'fas fa-chevron-down'"></i> Show Details
</button> </button>
@ -253,10 +250,7 @@
'text-weird': movement.action === 'Register'}" 'text-weird': movement.action === 'Register'}"
class="flex-shrink-0 text-nowrap" style="max-width:140px; min-width:90px;"> class="flex-shrink-0 text-nowrap" style="max-width:140px; min-width:90px;">
{{ movement.toOther === 'Return' ? 'Return' : (movement.toOther === 'On Delivery' ? 'Receive' : {{ 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.toStation !== null ? 'Change' :
( movement.toOther == 'Faulty' || movement.toOther == 'Calibration' || movement.toOther == 'Repair' ? movement.toOther :
( movement.action == 'Register' ? 'Register' : 'Assign')))) }}
</h3> </h3>
<!-- Send Date --> <!-- Send Date -->
@ -289,13 +283,9 @@
</button> </button>
<!-- Completion Status --> <!-- Completion Status -->
<h4 :class="movement.action == 'Register' ? 'text-success' : movement.movementComplete == 1 && movement.latestStatus !== 'Ready To Deploy' ? 'text-success' : <h4 :class="movement.action == 'Register' ? 'text-success' : movement.movementComplete == 1 && movement.latestStatus !== 'Ready To Deploy' ? 'text-success' : movement.toOther === 'Repair' || movement.toOther === 'Calibration' && movement.latestStatus === 'Ready To Deploy' ? 'text-success' :'text-danger'"
movement.toOther === 'Repair' || movement.toOther === 'Calibration' && movement.latestStatus === 'Ready To Deploy' ? 'text-success' :'text-danger'"
class="text-nowrap ms-3"> class="text-nowrap ms-3">
{{ movement.action == 'Register' ? 'Complete' : {{ 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.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'))) }}
</h4> </h4>
</div> </div>
@ -351,8 +341,7 @@
<!--------------------------------------------STATION CATEGORY----------------------------------------------------------------------> <!--------------------------------------------STATION CATEGORY---------------------------------------------------------------------->
<div v-if="sortBy === 'station'"> <div v-if="sortBy === 'station'">
<div v-for="(items, station) in filteredStation" :key="stationName" <div v-for="(items, station) in filteredStation" :key="stationName" :class="{'bg-light-gray': station === 'Unassign Station', 'bg-white': station !== 'Unassign Station'}" class="station-category card mt-3">
:class="{'bg-light-gray': station === 'Unassign Station', 'bg-white': station !== 'Unassign Station'}" class="station-category card mt-3">
<!-- Station Header --> <!-- Station Header -->
<div class="card-header d-flex justify-content-between align-items-center"> <div class="card-header d-flex justify-content-between align-items-center">
<h3>{{ station }}</h3> <h3>{{ station }}</h3>
@ -366,9 +355,7 @@
<div v-for="(group, itemId) in items" :key="itemId" class="row card"> <div v-for="(group, itemId) in items" :key="itemId" class="row card">
<!-- Item Header --> <!-- Item Header -->
<div class="card-header d-flex justify-content-between align-items-center"> <div class="card-header d-flex justify-content-between align-items-center">
@* <h2>Item : {{ group.uniqueID }}</h2> *@ <h2>Item : {{ group.uniqueID }}</h2>
<h2 v-if="group.uniqueID">Item : {{ group.uniqueID }}</h2>
<h2 v-else>Item : No Item Tracked</h2>
<button class="btn btn-light" v-on:click="toggleCategory(itemId)"> <button class="btn btn-light" v-on:click="toggleCategory(itemId)">
<i :class="categoryVisible[itemId] ? 'fas fa-chevron-up' : 'fas fa-chevron-down'"></i> Show Details <i :class="categoryVisible[itemId] ? 'fas fa-chevron-up' : 'fas fa-chevron-down'"></i> Show Details
</button> </button>
@ -677,13 +664,26 @@
return acc; return acc;
}, {}); }, {});
console.log(grouped);
// Sort items from newest to oldest & filter them // Sort items from newest to oldest & filter them
for (let itemId in grouped) { for (let itemId in grouped) {
let movements = grouped[itemId].movements let movements = grouped[itemId].movements
.sort((a, b) => b.id - a.id); // Newest to oldest .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 // 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) { if (stopIndex !== -1) {
stopIndex += 3; // Adjust index since we sliced after the first 3 stopIndex += 3; // Adjust index since we sliced after the first 3
@ -692,6 +692,7 @@
grouped[itemId].movements = movements; grouped[itemId].movements = movements;
} }
return grouped; return grouped;
}, },
@ -715,7 +716,9 @@
.sort((a, b) => b.id - a.id); // Newest → Oldest .sort((a, b) => b.id - a.id); // Newest → Oldest
// Ensure at least 3 movements before stopping // 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 // Remove older movements
if (stopIndex !== -1) { if (stopIndex !== -1) {
@ -727,7 +730,9 @@
let latestMovement = movements[0]; let latestMovement = movements[0];
let station = latestMovement.lastStationName || latestMovement.toStationName || "Not Assigned"; let station = latestMovement.lastStationName || latestMovement.toStationName || "Not Assigned";
if (!groupedByStation[station]) { groupedByStation[station] = {}; } if (!groupedByStation[station]) {
groupedByStation[station] = {};
}
groupedByStation[station][itemId] = { uniqueID: itemId, movements }; groupedByStation[station][itemId] = { uniqueID: itemId, movements };
} }
@ -747,6 +752,8 @@
return sortedGrouped; return sortedGrouped;
}, },
filteredItems() { filteredItems() {
if (!this.searchQuery.trim()) { if (!this.searchQuery.trim()) {
@ -774,7 +781,9 @@
filtered[station] = grouped[station]; filtered[station] = grouped[station];
} }
}); });
return filtered; return filtered;
}, },
}, },
@ -905,6 +914,8 @@
} }
if(this.currentRole == "Super Admin"){ if(this.currentRole == "Super Admin"){
this.items = await response.json(); this.items = await response.json();
console.log(this.items);
this.initAllTables(); this.initAllTables();
} else { } else {
@ -918,6 +929,10 @@
this.initAllTables(); this.initAllTables();
// console.log(this.items);
} }
if (this.itemDatatable) { if (this.itemDatatable) {
@ -967,10 +982,16 @@
this.renderTables(); this.renderTables();
}, },
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() { initAllTables() {
if (this.itemMovementNotCompleteDatatable) { if (this.itemMovementNotCompleteDatatable) {

View File

@ -603,8 +603,8 @@
"data": "convertPrice", "data": "convertPrice",
}, },
{ {
"title": "Register Date", "title": "Invoice Date",
"data": "createDate", "data": "invoiceDate",
}, },
{ {
"title": "Warranty Until", "title": "Warranty Until",
@ -638,27 +638,18 @@
], ],
responsive: true, responsive: true,
drawCallback: function (settings) { drawCallback: function (settings) {
setTimeout(() => { // Generate QR codes after rows are rendered
const api = this.api(); const api = this.api();
api.rows().every(function () { api.rows().every(function () {
const data = this.data(); const data = this.data(); // Row data
const containerId = `qr${data.uniqueID}`; const containerId = `qr${data.uniqueID}`;
const container = document.getElementById(containerId); const container = $(`#${containerId}`);
container.empty();
if (!container) { container.append(`${data.uniqueID}`);
return; // console.log(container[0]);
} if (container) {
// Generate QR code only if not already generated
container.innerHTML = ""; new QRCode(container[0], {
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, text: data.qrString,
width: 100, width: 100,
height: 100, height: 100,
@ -666,18 +657,20 @@
colorLight: "#ffffff", colorLight: "#ffffff",
correctLevel: QRCode.CorrectLevel.M correctLevel: QRCode.CorrectLevel.M
}); });
});
}, 100); // Small delay to ensure elements exist
} }
// container.on('click', function() {
// window.open(data.qrString, '_blank');
// });
});
},
}) })
// Attach click event listener to the delete buttons // Attach click event listener to the delete buttons
$('#itemDatatable tbody').off('click', '.delete-btn').on('click', '.delete-btn', function () { $('#itemDatatable tbody').on('click', '.delete-btn', function () {
const itemId = $(this).data('id'); const itemId = $(this).data('id');
self.deleteItem(itemId); self.deleteItem(itemId);
}); });
$('#itemDatatable tbody').on('click', '.print-btn', function () { $('#itemDatatable tbody').on('click', '.print-btn', function () {
const $button = $(this); // The clicked button const $button = $(this); // The clicked button
const $row = $button.closest('tr'); // The parent row of the button const $row = $button.closest('tr'); // The parent row of the button
@ -693,8 +686,9 @@
// For expanded view: Find the img in the first column of the current row // For expanded view: Find the img in the first column of the current row
imageSrc = $row.find('td:nth-child(1) img').attr('src'); imageSrc = $row.find('td:nth-child(1) img').attr('src');
} }
if (imageSrc) { 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 { } else {
console.error("Image source not found."); console.error("Image source not found.");
} }
@ -876,6 +870,8 @@
.row($(`.delete-btn[data-id="${itemId}"]`).closest('tr')) .row($(`.delete-btn[data-id="${itemId}"]`).closest('tr'))
.remove() .remove()
.draw(); .draw();
} else {
alert(result.message);
} }
} }
catch (error) { catch (error) {
@ -891,6 +887,7 @@
this.thisQRInfo.uniqueID = itemId; this.thisQRInfo.uniqueID = itemId;
const uniqueQR = itemId; const uniqueQR = itemId;
const container = document.getElementById("QrContainer"); const container = document.getElementById("QrContainer");
if (!container) { if (!container) {
console.error("Container not found."); console.error("Container not found.");
return; return;
@ -943,11 +940,7 @@
console.error("Items list is not available or is not an array."); console.error("Items list is not available or is not an array.");
return null; 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() { printQRInfo() {
// Create a virtual DOM element // Create a virtual DOM element
@ -1026,6 +1019,7 @@
}); });
}, },
}, },
}); });
</script> </script>

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@
Layout = "~/Views/Shared/_Layout.cshtml"; Layout = "~/Views/Shared/_Layout.cshtml";
} }
@await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml") @await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml");
<div id="app"> <div id="app">
<div class="row card"> <div class="row card">
<div class="card-header"> <div class="card-header">

View File

@ -4,7 +4,7 @@
string userId = ViewBag.UserId; string userId = ViewBag.UserId;
} }
@await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml") @await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml");
<div class="row"> <div class="row">
<div id="registerProduct" class="card m-1"> <div id="registerProduct" class="card m-1">
<div class="row" v-if="addSection == true"> <div class="row" v-if="addSection == true">
@ -145,6 +145,7 @@
}, },
methods: { methods: {
initiateTable() { initiateTable() {
console.log(this.products)
this.productDatatable = $('#productDatatable').DataTable({ this.productDatatable = $('#productDatatable').DataTable({
"data": this.products, "data": this.products,
"columns": [ "columns": [
@ -179,7 +180,7 @@
"title": "Delete", "title": "Delete",
"data": "productId", "data": "productId",
"render": function (data) { "render": function (data) {
var deleteButton = `<button type="button" class="btn btn-danger delete-btn" data-id="${data}">Delete</button>`; var deleteButton = `<button type="button" class="btn btn-danger delete-btn" data-id="${data.productId}">Delete</button>`;
return deleteButton; return deleteButton;
}, },
} }

View File

@ -145,7 +145,7 @@
<div class="tab-pane fade show active" id="home" role="tabpanel" aria-labelledby="home-tab"> <div class="tab-pane fade show active" id="home" role="tabpanel" aria-labelledby="home-tab">
<div style="text-align: center; margin: 20px 0; padding: 20px;"> <div style="text-align: center; margin: 20px 0; padding: 20px;">
<div v-if="itemlateststatus == 'On Delivery' && this.thisItem.toUser == this.currentUser.id"> <div v-if="itemlateststatus == 'On Delivery' && this.itemassignedtouser">
<h2 class="register-heading">Item is on Delivery</h2> <h2 class="register-heading">Item is on Delivery</h2>
<div class="col-sm-3"></div> <div class="col-sm-3"></div>
<div class="col-sm-6 offset-sm-3"> <div class="col-sm-6 offset-sm-3">
@ -169,23 +169,6 @@
</div> </div>
</div> </div>
<div v-if="itemlateststatus == 'On Delivery' && thisItem.lastStore == currentUser.store">
<h2 class="register-heading">Receive Item</h2>
<div class="col-sm-3"></div>
<div class="col-sm-6 offset-sm-3">
<form v-on:submit.prevent="receiveItemMovement" data-aos="fade-right">
<div class="row register-form">
<div style="display: flex; justify-content: center; margin-top: 20px;">
<button type="submit" class="btn btn-primary" style="width: 200px; padding: 10px; font-size: 16px;">
Receive Item
</button>
</div>
</div>
</form>
</div>
</div>
<div v-if="(itemlateststatus == 'Repair' || itemlateststatus == 'Calibration') && this.itemassignedtouser"> <div v-if="(itemlateststatus == 'Repair' || itemlateststatus == 'Calibration') && this.itemassignedtouser">
<h2 class="register-heading">Receive Repair / Calibration</h2> <h2 class="register-heading">Receive Repair / Calibration</h2>
<div class="col-sm-3"></div> <div class="col-sm-3"></div>
@ -243,7 +226,7 @@
@* </div> *@ @* </div> *@
@* </div> *@ @* </div> *@
<div v-if="itemlateststatus == 'Faulty' && this.itemassignedtouser"> <div v-if="itemlateststatus == 'Faulty'">
<h2 class="register-heading">Add Item Movement</h2> <h2 class="register-heading">Add Item Movement</h2>
<div class="col-sm-3"></div> <div class="col-sm-3"></div>
<div class="col-sm-6 offset-sm-3"> <div class="col-sm-6 offset-sm-3">
@ -257,7 +240,7 @@
</div> </div>
</div> </div>
<div v-if="itemlateststatus == 'Ready To Deploy' && this.itemassignedtouser"> <div v-if="itemlateststatus == 'Ready To Deploy'">
<h2 class="register-heading">Add Item Movement</h2> <h2 class="register-heading">Add Item Movement</h2>
<div class="col-sm-3"></div> <div class="col-sm-3"></div>
<div class="col-sm-6 offset-sm-3"> <div class="col-sm-6 offset-sm-3">
@ -747,9 +730,8 @@
}) })
.then(() => { console.log("📷 Applied Constraintsss:", track.getSettings()); .then(() => { console.log("📷 Applied Constraintsss:", track.getSettings());
}) }).catch(err =>
.catch(err => // console.error("❌ Failed to apply constraints:", err)
console.error("❌ Failed to apply constraints:", err)
); );
} else { } else {
@ -830,9 +812,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 === '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 === '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, lastStore: this.selectedStore, 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, lastStore: this.currentUser.store, MovementComplete: false, } : {}), ...(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', 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, } : {}), ...(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, } : {}),
ItemId: this.thisItem.itemID, ItemId: this.thisItem.itemID,
Action: 'Stock Out', Action: 'Stock Out',
@ -881,23 +863,19 @@
this.serialNumber = ""; this.serialNumber = "";
} }
if(this.thisItem.toOther === "On Delivery" && this.thisItem.toUser == this.currentUser.id){ if(this.thisItem.toOther === "On Delivery"){
if(!window.confirm("Are you sure you want to cancel item delivery?")){ if(!window.confirm("Are you sure you want to cancel item delivery?")){
return; return;
} }
} }
const now = new Date(); const now = new Date();
console.log('currentuser'+this.currentUser.id);
console.log('lastuser'+this.thisItem.lastuser);
const formData = { const formData = {
Id: this.thisItem.movementId, Id: this.thisItem.movementId,
ReceiveDate: new Date(now.getTime() + 8 * 60 * 60 * 1000).toISOString(), ReceiveDate: new Date(now.getTime() + 8 * 60 * 60 * 1000).toISOString(),
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, Remark: this.thisItem.toOther === "On Delivery" ? 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" : ""
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" : "")
}; };
@ -945,19 +923,9 @@
// this.thisItem = await response.json(); // this.thisItem = await response.json();
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.itemlateststatus = this.thisItem.latestStatus ? this.thisItem.latestStatus : this.thisItem.toOther;
this.itemassignedtouser = (this.thisItem.toUser === this.currentUser.id || this.thisItem.lastUser === this.currentUser.id ) && this.thisItem.lastStore === this.currentUser.store ? true : false; this.itemassignedtouser = this.thisItem.toUser == this.currentUser.id || this.thisItem.lastUser == this.currentUser.id ? true : false;
// console.log(this.thisItem); // 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 { } else {
console.error('Failed to fetch item information'); console.error('Failed to fetch item information');

View File

@ -3,7 +3,7 @@
Layout = "~/Views/Shared/_Layout.cshtml"; Layout = "~/Views/Shared/_Layout.cshtml";
} }
@await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml") @await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml");
<div id="registerStation"> <div id="registerStation">
<form v-on:submit.prevent="addStation" data-aos="fade-right" id="registerStationForm" v-if="registerStationForm"> <form v-on:submit.prevent="addStation" data-aos="fade-right" id="registerStationForm" v-if="registerStationForm">
<div class="container register" data-aos="fade-right"> <div class="container register" data-aos="fade-right">

View File

@ -3,7 +3,7 @@
Layout = "~/Views/Shared/_Layout.cshtml"; Layout = "~/Views/Shared/_Layout.cshtml";
} }
@await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml") @await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml");
<div id="registerSupplier"> <div id="registerSupplier">
<form v-on:submit.prevent="addSupplier" data-aos="fade-right" id="registerSupplierForm" v-if="registerSupplierForm"> <form v-on:submit.prevent="addSupplier" data-aos="fade-right" id="registerSupplierForm" v-if="registerSupplierForm">
<div class="container register" data-aos="fade-right"> <div class="container register" data-aos="fade-right">

View File

@ -64,8 +64,7 @@
<h2>Pending Item Movement</h2> <h2>Pending Item Movement</h2>
</div> </div>
<div class="card-body"> <div class="card-body">
<table class="table table-bordered table-hover table-striped no-wrap" id="itemMovementNotCompleteDatatable" <table class="table table-bordered table-hover table-striped no-wrap" id="itemMovementNotCompleteDatatable" style="width:100%;border-style: solid; border-width: 1px"></table>
style="width:100%;border-style: solid; border-width: 1px"></table>
</div> </div>
</div> </div>
@ -74,8 +73,7 @@
<h2>Complete Item Movement</h2> <h2>Complete Item Movement</h2>
</div> </div>
<div class="card-body"> <div class="card-body">
<table class="table table-bordered table-hover table-striped no-wrap" id="itemMovementCompleteDatatable" <table class="table table-bordered table-hover table-striped no-wrap" id="itemMovementCompleteDatatable" style="width:100%;border-style: solid; border-width: 1px"></table>
style="width:100%;border-style: solid; border-width: 1px"></table>
</div> </div>
</div> </div>
</div> </div>
@ -286,8 +284,7 @@
<!--------------------------------------------STATION CATEGORY----------------------------------------------------------------------> <!--------------------------------------------STATION CATEGORY---------------------------------------------------------------------->
<div v-if="sortBy === 'station'"> <div v-if="sortBy === 'station'">
<div v-for="(items, station) in filteredStation" :key="stationName" <div v-for="(items, station) in filteredStation" :key="stationName" :class="{'bg-light-gray': station === 'Unassign Station', 'bg-white': station !== 'Unassign Station'}" class="station-category card mt-3">
:class="{'bg-light-gray': station === 'Unassign Station', 'bg-white': station !== 'Unassign Station'}" class="station-category card mt-3">
<!-- Station Header --> <!-- Station Header -->
<div class="card-header d-flex justify-content-between align-items-center"> <div class="card-header d-flex justify-content-between align-items-center">
<h3>{{ station }}</h3> <h3>{{ station }}</h3>
@ -572,8 +569,7 @@
return acc; return acc;
}, {}); }, {});
let filteredGrouped = {}; // Sort items from newest to oldest & filter them
for (let itemId in grouped) { for (let itemId in grouped) {
let movements = grouped[itemId].movements let movements = grouped[itemId].movements
.sort((a, b) => b.id - a.id); // Newest to oldest .sort((a, b) => b.id - a.id); // Newest to oldest
@ -582,27 +578,14 @@
m.toOther === 'Return' && m.movementComplete == 1 m.toOther === 'Return' && m.movementComplete == 1
); );
let nextIndex = movements.findIndex(m =>
m.latestStatus === 'Ready To Deploy' && m.movementComplete == 1
);
if (stopIndex !== -1) { if (stopIndex !== -1) {
movements = movements.slice(0, stopIndex); movements = movements.slice(0, stopIndex);
} }
if (nextIndex !== -1) { grouped[itemId].movements = movements;
movements = movements.slice(0, nextIndex);
} }
if (movements.length > 0) { return grouped;
filteredGrouped[itemId] = {
uniqueID: grouped[itemId].uniqueID,
movements: movements,
};
}
}
return filteredGrouped;
}, },
groupedByStation() { groupedByStation() {
@ -628,18 +611,11 @@
m.toOther === 'Return' && m.movementComplete == 1 m.toOther === 'Return' && m.movementComplete == 1
); );
let nextIndex = movements.findIndex(m => // Remove older movements
m.latestStatus === 'Ready To Deploy' && m.movementComplete == 1
);
if (stopIndex !== -1) { if (stopIndex !== -1) {
movements = movements.slice(0, stopIndex); movements = movements.slice(0, stopIndex);
} }
if (nextIndex !== -1) {
movements = movements.slice(0, nextIndex);
}
if (movements.length > 0) { if (movements.length > 0) {
let latestMovement = movements[0]; let latestMovement = movements[0];
let station = latestMovement.lastStationName || latestMovement.toStationName || "Self Assigned"; let station = latestMovement.lastStationName || latestMovement.toStationName || "Self Assigned";
@ -672,17 +648,11 @@
return this.processedGroupedItems; return this.processedGroupedItems;
} }
const searchLower = this.searchQuery.toLowerCase(); const searchLower = this.searchQuery.toLowerCase();
let grouped = this.processedGroupedItems; return Object.fromEntries(
let filtered = {}; Object.entries(this.processedGroupedItems).filter(([_, group]) =>
group.uniqueID.toLowerCase().includes(searchLower)
Object.keys(grouped).forEach(item => { )
if (item.toLowerCase().includes(searchLower)) { );
if (grouped[item] > 0) {
filtered[item] = grouped[item];
}
}
});
return filtered;
}, },
filteredStation() { filteredStation() {
@ -750,10 +720,6 @@
} }
}, },
handleSorting() {
this.renderTables();
},
renderTables() { renderTables() {
if (this.sortBy === "all") { if (this.sortBy === "all") {
this.initAllTables(); this.initAllTables();
@ -771,7 +737,7 @@
this.stationDatatable.destroy(); this.stationDatatable.destroy();
} }
// Get latest movement per uniqueID after filtering // Get latest movement per uniqueID
function getLatestMovements(data) { function getLatestMovements(data) {
let latestMovements = {}; let latestMovements = {};
data.forEach(movement => { data.forEach(movement => {
@ -783,42 +749,18 @@
return Object.values(latestMovements); return Object.values(latestMovements);
} }
// Filter movements based on conditions // Distribute items based on priority
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 latestMovements = getLatestMovements(this.itemMovements);
let notCompleteData = []; let notCompleteData = [];
let completeData = []; let completeData = [];
let assignedData = [];
latestMovements.forEach(movement => { latestMovements.forEach(movement => {
let filteredMovements = filterMovements([movement]);
if (filteredMovements.length > 0) {
if (movement.movementComplete == 0) { if (movement.movementComplete == 0) {
notCompleteData.push(movement); notCompleteData.push(movement);
} else if (movement.movementComplete == 1) { } else if (movement.movementComplete == 1) {
completeData.push(movement); completeData.push(movement);
} }
}
}); });
// Table 1: Not Complete Movements // Table 1: Not Complete Movements
@ -891,7 +833,6 @@
} }
}, },
toggleCategory(itemId) { toggleCategory(itemId) {
this.categoryVisible[itemId] = !this.categoryVisible[itemId]; this.categoryVisible[itemId] = !this.categoryVisible[itemId];
@ -916,6 +857,9 @@
this.detailsVisible[movementId] = !this.detailsVisible[movementId]; this.detailsVisible[movementId] = !this.detailsVisible[movementId];
}, },
handleSorting() {
this.renderTables();
},
}, },
}); });

View File

@ -440,13 +440,193 @@
initiateTable() { initiateTable() {
let self = this; 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 <td> element
$(td).attr('id', `qr${cellData}`);
},
},
{
"title": "Product Name",
"data": "productName",
"render": function (data, type, full, meta) {
if (!data) {
return "No Document";
}
function renderDocument(data, full) { var imageSrc = full.productPicture;
if (!data) return "No Document"; // 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);
let isImage = /\.(jpeg|jpg|png|gif)$/i.test(data); if (isImage) {
let isPdf = /\.pdf$/i.test(data); return ` <div class="row"><td>${data}</td></div>
<a href="${imageSrc}" target="_blank" data-lightbox="image-1">
<img src="${imageSrc}" alt="Image" class="img-thumbnail" style="width: 100px; height: 100px;" />
</a>`;
}
else if (isPdf) {
return `<div class="row"><td>${data}</td></div>
<a href="${imageSrc}" target="_blank">
<img src="https://upload.wikimedia.org/wikipedia/commons/8/87/PDF_file_icon.svg"
alt="PDF Document" class="img-thumbnail"
style="width: 50px; height: 50px;" />
<br>View PDF
</a>`;
}
},
},
{
"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 `<a href="${data}" target="_blank" data-lightbox="image-1">
<img src="${data}" alt="Image" class="img-thumbnail" style="width: 100px; height: 100px;" />
</a>`;
}
else if (isPdf) {
return `<a href="${data}" target="_blank">
<img src="https://upload.wikimedia.org/wikipedia/commons/8/87/PDF_file_icon.svg"
alt="PDF Document" class="img-thumbnail"
style="width: 50px; height: 50px;" />
<br>View PDF
</a>`;
} else {
return `<a href="${data}" target="_blank">Download File</a>`;
}
},
},
{
"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 = `<button type="button" class="btn btn-danger delete-btn" data-id="${data}">Delete</button>`;
return deleteButton;
},
"className": "align-middle",
}
],
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 <td> 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";
}
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);
if (isImage) {
return ` <div class="row"><td>${data}</td></div>
<a href="${imageSrc}" target="_blank" data-lightbox="image-1">
<img src="${imageSrc}" alt="Image" class="img-thumbnail" style="width: 100px; height: 100px;" />
</a>`;
}
else if (isPdf) {
return `<div class="row"><td>${data}</td></div>
<a href="${imageSrc}" target="_blank">
<img src="https://upload.wikimedia.org/wikipedia/commons/8/87/PDF_file_icon.svg"
alt="PDF Document" class="img-thumbnail"
style="width: 50px; height: 50px;" />
<br>View PDF
</a>`;
}
},
},
{
"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";
}
// 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) { if (isImage) {
return `<a href="${data}" target="_blank" data-lightbox="image-1"> return `<a href="${data}" target="_blank" data-lightbox="image-1">
@ -462,43 +642,25 @@
} else { } else {
return `<a href="${data}" target="_blank">Download File</a>`; return `<a href="${data}" target="_blank">Download File</a>`;
} }
},
},
{
"title": "Remark",
"data": "remarkUser",
},
{
"title": "Remark (Master)",
"data": "remarkMasterInv",
},
{
"title": "Request Date",
"data": "requestDate",
},
{
"title": "Approval Date",
"data": "approvalDate",
} }
function renderDeleteButton(data) {
return `<button type="button" class="btn btn-danger delete-btn" data-id="${data}">Delete</button>`;
}
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,
});
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, responsive: true,
}); });
@ -510,9 +672,9 @@
self.deleteRequestItem(requestID); self.deleteRequestItem(requestID);
}); });
this.loading = false;
}
this.loading = false;
},
async fetchRequest() { async fetchRequest() {
try try

View File

@ -145,6 +145,14 @@
</span> </span>
</div> </div>
</li> </li>
<!-- Station -->
<!-- <li class="list-group-item d-flex justify-content-between align-items-center"> -->
<!-- <span class="fw-bold"> -->
<!-- <i class="fas fa-map-marker-alt me-2 text-secondary"></i>Station: -->
<!-- </span> -->
<!-- <span class="text-muted">{{ thisItem.currentStation || 'N/A' }}</span> -->
<!-- </li> -->
</ul> </ul>
</div> </div>
</div> </div>
@ -534,6 +542,15 @@
async returnItemMovement() { 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?")) { if (!confirm("Are you sure you want to return this item?")) {
return false; return false;
} }

View File

@ -19,7 +19,7 @@
<h1 class="font-light text-white"> <h1 class="font-light text-white">
<i class="mdi mdi-factory"></i> <i class="mdi mdi-factory"></i>
</h1> </h1>
<h6 class="text-white">Manufacturer</h6> <h6 class="text-white">Manifacturer</h6>
</div> </div>
</a> </a>
</div> </div>

View File

@ -1,415 +0,0 @@
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<IActionResult> 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}<br/>{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<IActionResult> GenerateReport(int id)//calls GeneratePdfResponse to generate a PDF for inline viewing
{
return await GeneratePdfResponse(id, true);
}
//public async Task<IActionResult> 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<IActionResult> 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<TarballPdfDto>(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<string, string>();
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;
}
}
}
}

View File

@ -1,128 +0,0 @@
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 }
}

View File

@ -1,405 +0,0 @@
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);
});
}
}
}

View File

@ -1,6 +0,0 @@
@{
ViewData["Title"] = "MMS Dashboard";
}
<h1>Welcome to the MMS Dashboard</h1>
<p>This is where youll add content for MMS later.</p>

View File

@ -1,224 +0,0 @@
@{
ViewData["Title"] = "Tarball Report";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>
<title>Tarball Report</title>
<style>
.container {
width: 1400px; /* Approximate width for A4 aspect ratio */
margin: 20px auto;
padding: 20px;
background-color: #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
div {
padding-top: 5px;
padding-bottom: 5px;
}
h4 {
padding-top: 15px;
padding-bottom: 5px;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
border: 1px solid #ccc;
padding: 10px;
}
</style>
<!-- DataTables CSS -->
<link href="~/lib/datatables/datatables.css" rel="stylesheet" />
</head>
<body>
<div id="app" class="container">
<div>
<h4>Month</h4>
<select v-model="selectedMonth" style="width: 100%; padding: 5px;">
<option value="" selected>Filter by Month</option>
<option v-for="month in months" :value="month">{{ month }}</option>
</select>
<h4>Year</h4>
<select v-model="selectedYear" style="width: 100%; padding: 5px;">
<option value="" selected>Filter by Year</option>
<option v-for="year in years" :value="year">{{ year }}</option>
</select>
<div>
<button v-on:click="clearFilters" class="btn btn-default" style="margin-top: 20px; margin-bottom: 25px;">Clear Filter</button>
</div>
</div>
<div class="datatable">
<table id="tarballTable" class="table table-bordered table-hover table-striped" style="width:100%;">
<thead>
<tr>
<th>No.</th>
<th>Date</th>
<th>Station</th>
<th>Time</th>
<th>Status</th>
<th>PDF</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
</body>
</html>
@section Scripts {
<!-- DataTables JS -->
<script src="~/lib/datatables/datatables.js"></script>
<script>
new Vue({
el: '#app',
data: {
selectedMonth: '',
selectedYear: '',
months: [
'January', 'February', 'March', 'April', 'May',
'June', 'July', 'August', 'September',
'October', 'November', 'December'
],
dataFromServer: @Json.Serialize(Model ?? new List<object>()),
dataTable: null
},
mounted() {
if (this.dataFromServer && this.dataFromServer.length > 0) {
this.$nextTick(() => {
this.initializeDataTable();
});
} else {
console.log("No data received from server");
}
},
computed: {
years() {
if (!this.dataFromServer || this.dataFromServer.length === 0) {
return []; // Return an empty array if no data is available
}
// Extract all years from the data
const allYears = this.dataFromServer.map(data => new Date(data.date).getFullYear());
// Find the minimum and maximum years
const minYear = Math.min(...allYears);
const maxYear = Math.max(...allYears);
// Generate a range of years from minYear to maxYear
return Array.from({ length: maxYear - minYear + 1 }, (_, i) => (minYear + i).toString());
},
sortedFilteredData() {
// If no filters are applied, return all data sorted by descending date
if (!this.selectedMonth && !this.selectedYear) {
return this.dataFromServer.sort((a, b) => new Date(b.date) - new Date(a.date));
}
// Filter data by selected month and year
const filtered = this.dataFromServer.filter(data => {
const date = new Date(data.date);
const monthMatches = this.selectedMonth
? date.toLocaleString('default', { month: 'long' }) === this.selectedMonth
: true;
const yearMatches = this.selectedYear
? date.getFullYear().toString() === this.selectedYear
: true;
return monthMatches && yearMatches;
});
// Sort data by date in descending order
return filtered.sort((a, b) => new Date(b.date) - new Date(a.date));
}
},
methods: {
clearFilters() {
this.selectedMonth = '';
this.selectedYear = '';
},
initializeDataTable() {
// Initialize DataTables
const self = this; // Store the Vue instance context
this.dataTable = $('#tarballTable').DataTable({
"pageLength": 10,
"lengthMenu": [5, 10, 15, 20],
"responsive": true,
"order": [[1, "desc"]], // Default sorting by Date column (descending)
"orderMulti": false, // Disable multi-column sorting
"columns": [
{ "data": null,"render": (data, type, row, meta) => meta.row + 1},
{ "data": "date", "render": (data) => new Date(data).toLocaleDateString('en-GB') },
{ "data": "station" },
{ "data": "time" }, // Removed the incorrect toLocaleDateString()
{
"data": null,
"render": () => `
<button class="btn btn-success" disabled>Approve</button>
<button class="btn btn-danger" disabled>Reject</button>
`
},
{
"data": null,
"render": (data) => `
<a href="/MMS/Marine/ViewPDF?id=${data.id}" class="btn btn-primary" target="_blank">View PDF</a>
<a href="/MMS/Marine/GenerateReport?id=${data.id}" class="btn btn-primary">Download PDF</a>
`
//uses ViewPDF for view, GenerateReport for downloading
}
],
"rowCallback": function(row, data, index) {
// Update the "No." column to start from 1 for the current page
const pageInfo = this.api().page.info();
$('td:first', row).html(pageInfo.start + index + 1);
}
});
// Populate the table with initial data
this.updateDataTable(this.sortedFilteredData);
//auto-filtering
$('#tarballTable_filter input').on('keyup', function () {
self.dataTable.search(this.value).draw();
});
},
updateDataTable(data) {
if (this.dataTable) {
this.dataTable.clear();
this.dataTable.rows.add(data);
this.dataTable.draw();
}
}
},
mounted() {
// Initialize DataTables after Vue has rendered the table
this.$nextTick(() => {
this.initializeDataTable();
});
},
watch: {
sortedFilteredData(newData) {
// Automatically update DataTables whenever the filtered data changes
this.updateDataTable(newData);
//trigger search function after updating data(?)
if(this.dataTable) {
this.dataTable.search('').draw();
}
}
}
});
</script>
}

View File

@ -3,7 +3,6 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.VisualStudio.Web.CodeGenerators.Mvc.Templates.BlazorIdentity.Pages;
using Mono.TextTemplating; using Mono.TextTemplating;
using Newtonsoft.Json; using Newtonsoft.Json;
using PSTW_CentralSystem.Areas.Inventory.Models; using PSTW_CentralSystem.Areas.Inventory.Models;
@ -266,7 +265,6 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
var userRole = await _userManager.GetRolesAsync(user); var userRole = await _userManager.GetRolesAsync(user);
var isAdmin = userRole.Contains("SystemAdmin") || userRole.Contains("SuperAdmin") || userRole.Contains("Finance"); var isAdmin = userRole.Contains("SystemAdmin") || userRole.Contains("SuperAdmin") || userRole.Contains("Finance");
List<ItemModel> itemList = new List<ItemModel>(); List<ItemModel> itemList = new List<ItemModel>();
List<ItemMovementModel> createDate = new List<ItemMovementModel>();
// Get the item list // Get the item list
if (isAdmin) if (isAdmin)
{ {
@ -298,22 +296,14 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
.ThenInclude(m => m!.FromUser) .ThenInclude(m => m!.FromUser)
.Where(i => i.DepartmentId == user.departmentId) .Where(i => i.DepartmentId == user.departmentId)
.ToListAsync(); .ToListAsync();
} }
// Get the departments list (DepartmentId references Departments) // Get the departments list (DepartmentId references Departments)
var departments = await _centralDbContext.Departments.ToListAsync(); 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 // Now join items with users and departments manually
var itemListWithDetails = itemList.Select(item => new 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.ItemID,
item.UniqueID, item.UniqueID,
item.CompanyId, item.CompanyId,
@ -334,8 +324,7 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
EndWDate = item.EndWDate.ToString("dd/MM/yyyy"), EndWDate = item.EndWDate.ToString("dd/MM/yyyy"),
InvoiceDate = item.InvoiceDate?.ToString("dd/MM/yyyy"), InvoiceDate = item.InvoiceDate?.ToString("dd/MM/yyyy"),
item.Department?.DepartmentName, item.Department?.DepartmentName,
RegisterDate = createDate, CreatedBy=item.CreatedBy!.UserName,
CreatedBy =item.CreatedBy!.UserName,
item.Product!.ProductName, item.Product!.ProductName,
item.Product!.ProductShortName, item.Product!.ProductShortName,
item.Product!.Category, item.Product!.Category,
@ -476,26 +465,12 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
return NotFound(new { success = false, message = "Item not found" }); 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); _centralDbContext.Items.Remove(item);
await _centralDbContext.SaveChangesAsync(); await _centralDbContext.SaveChangesAsync();
return Ok(new { success = true, message = "Item deleted successfully" }); return Ok(new { success = true, message = "Item deleted successfully" });
} }
[HttpPost("GetItem/{id}")] // Endpoint to retrieve an item by its ID [HttpPost("GetItem/{id}")] // Endpoint to retrieve an item by its ID
public async Task<IActionResult> GetItem(string id) public async Task<IActionResult> GetItem(string id)
{ {
@ -563,7 +538,6 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
item.Movement?.ToOther, item.Movement?.ToOther,
item.Movement?.LatestStatus, item.Movement?.LatestStatus,
item.Movement?.LastUser, item.Movement?.LastUser,
item.Movement?.LastStore,
item.Movement?.MovementComplete, item.Movement?.MovementComplete,
remark = item.Movement?.Remark, remark = item.Movement?.Remark,
QRString = $"{HttpContext.Request.Scheme}://{HttpContext.Request.Host.Value}/I/{item.UniqueID}" // Generate QR String QRString = $"{HttpContext.Request.Scheme}://{HttpContext.Request.Host.Value}/I/{item.UniqueID}" // Generate QR String
@ -591,18 +565,16 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
.Include(i => i.NextUser) .Include(i => i.NextUser)
.ToListAsync(); .ToListAsync();
// 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. int itemrow = 0;
// then need dynamic numbering for qr even if item movement is repeated by the same item var itemMovementListWithQR = itemMovementList.Select(item => new
//int itemrow = 0; {
//var itemMovementListWithQR = itemMovementList.Select(item => new id = itemrow++,
//{ item, // Includes all properties of the original item
// id = itemrow++, QRString = $"{HttpContext.Request.Scheme}://{HttpContext.Request.Host.Value}/I/{item.ItemId}", // Generate QR String
// item, // Includes all properties of the original item ProductName = item.Item?.Product?.ProductName,
// QRString = $"{HttpContext.Request.Scheme}://{HttpContext.Request.Host.Value}/I/{item.ItemId}", // Generate QR String toUserName = item.NextUser?.FullName,
// ProductName = item.Item?.Product?.ProductName, lastUserName = item.FromUser?.FullName
// toUserName = item.NextUser?.FullName, }).ToList();
// lastUserName = item.FromUser?.FullName
//}).ToList();
//Console.WriteLine(Json(itemMovementListWithQR)); //Console.WriteLine(Json(itemMovementListWithQR));
@ -764,7 +736,6 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
return NotFound("Item movement record not found."); return NotFound("Item movement record not found.");
} }
updatedList.LastUser = receiveMovement.LastUser;
updatedList.LatestStatus = receiveMovement.LatestStatus; updatedList.LatestStatus = receiveMovement.LatestStatus;
updatedList.receiveDate = receiveMovement.receiveDate; updatedList.receiveDate = receiveMovement.receiveDate;
updatedList.Remark = receiveMovement.Remark; updatedList.Remark = receiveMovement.Remark;
@ -998,74 +969,6 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
#endregion #endregion
#region ItemRequestAdmin #region ItemRequestAdmin
[HttpPost("AddRequestMaster")]
public async Task<IActionResult> 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")] [HttpGet("ItemRequestList")]
public async Task<IActionResult> ItemRequestList() public async Task<IActionResult> ItemRequestList()
{ {
@ -1074,7 +977,6 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
return Json(itemRequestList.Select(i => new return Json(itemRequestList.Select(i => new
{ {
i.requestID, i.requestID,
i.UserId,
productName = i.Product?.ProductName, productName = i.Product?.ProductName,
i.ProductId, i.ProductId,
productImage = i.Product?.ImageProduct, productImage = i.Product?.ImageProduct,
@ -1089,8 +991,6 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
i.approvalDate, i.approvalDate,
i.remarkMasterInv, i.remarkMasterInv,
i.remarkUser, i.remarkUser,
i.assignStoreItem,
i.fromStoreItem,
})); }));
@ -1288,22 +1188,6 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
return Json(storeList); return Json(storeList);
} }
[HttpPost("StoreSpecificMasterList/{userId}")]
public async Task<IActionResult> 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 #endregion Store
#region AllUser #region AllUser
@ -1338,7 +1222,7 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
{ {
return NotFound("Item movement record not found."); return NotFound("Item movement record not found.");
} }
updatedList.MovementComplete = receiveMovement.MovementComplete;
updatedList.LatestStatus = receiveMovement.LatestStatus; updatedList.LatestStatus = receiveMovement.LatestStatus;
updatedList.receiveDate = receiveMovement.receiveDate; updatedList.receiveDate = receiveMovement.receiveDate;
updatedList.MovementComplete = receiveMovement.MovementComplete; updatedList.MovementComplete = receiveMovement.MovementComplete;

View File

@ -1,11 +0,0 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace PSTW_CentralSystem.Controllers.API
{
[Route("api/[controller]")]
[ApiController]
public class MarineAPI : ControllerBase
{
}
}

View File

@ -5,8 +5,6 @@ using PSTW_CentralSystem.Models;
using Newtonsoft.Json; using Newtonsoft.Json;
using System.Text.Json; using System.Text.Json;
using System.Data; using System.Data;
using Microsoft.EntityFrameworkCore;
using System.Reflection;
namespace PSTW_CentralSystem.CustomPolicy namespace PSTW_CentralSystem.CustomPolicy
{ {
@ -34,7 +32,7 @@ namespace PSTW_CentralSystem.CustomPolicy
var userRole = await _userManager.GetRolesAsync(currentUser ?? new UserModel()); var userRole = await _userManager.GetRolesAsync(currentUser ?? new UserModel());
var moduleName = _httpContextAccessor.HttpContext?.GetRouteData().Values["controller"]?.ToString(); var moduleName = _httpContextAccessor.HttpContext?.GetRouteData().Values["controller"]?.ToString();
var pageName = _httpContextAccessor.HttpContext?.GetRouteData().Values["action"]?.ToString(); var pageName = _httpContextAccessor.HttpContext?.GetRouteData().Values["action"]?.ToString();
var registeredModule = await _authDBContext.ModuleSettings.Where(x => x.ModuleName == moduleName).ToListAsync(); var registeredModule = _authDBContext.ModuleSettings.FirstOrDefault(x => x.ModuleName == moduleName);
if (checkIfSuperAdmin()) if (checkIfSuperAdmin())
{ {
@ -85,46 +83,30 @@ namespace PSTW_CentralSystem.CustomPolicy
void checkModuleActiveOrNot() void checkModuleActiveOrNot()
{ {
foreach (var module in registeredModule) if (registeredModule.ModuleStatus == 0)
{
if (module.ModuleStatus == 0)
{ {
context.Fail(); context.Fail();
return; return;
} }
} }
}
void checkModuleHaveRoleOrNot() void checkModuleHaveRoleOrNot()
{ {
bool isModuleHaveRole = false; var allowedUserTypes = registeredModule?.AllowedUserType ?? "";
foreach (var module in registeredModule)
{
var allowedUserTypes = module?.AllowedUserType ?? "";
if (allowedUserTypes == "Public" || userRole.Any(role => allowedUserTypes.Contains(role))) if (allowedUserTypes == "Public" || userRole.Any(role => allowedUserTypes.Contains(role)))
{ {
context.Succeed(requirement); context.Succeed(requirement);
return; return;
} }
else if (currentUser != null && allowedUserTypes == "Registered User") else if (currentUser != null && allowedUserTypes == "Registered User" )
{ {
isModuleHaveRole = true; checkMethodAndRole();
} }
else else
{
isModuleHaveRole = false;
}
}
if (!isModuleHaveRole)
{ {
context.Fail(); context.Fail();
return; return;
} }
else
{
checkMethodAndRole();
}
} }
void checkMethodAndRole() void checkMethodAndRole()

View File

@ -1,146 +0,0 @@
//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<RoleModulePolicy>
// {
// private readonly CentralSystemContext _authDBContext;
// private readonly UserManager<UserModel> _userManager;
// private readonly RoleManager<RoleModel> _roleManager;
// private readonly IHttpContextAccessor _httpContextAccessor;
// public RoleModuleHandler( CentralSystemContext authDBContext, UserManager<UserModel> userManager, RoleManager<RoleModel> 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<string>();
// 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;
// }
// }
// }
// }
//}

View File

@ -110,6 +110,5 @@ namespace PSTW_CentralSystem.DBContext
public DbSet<ApprovalFlowModel> Approvalflow { get; set; } public DbSet<ApprovalFlowModel> Approvalflow { get; set; }
public DbSet<StaffSignModel> Staffsign { get; set; } public DbSet<StaffSignModel> Staffsign { get; set; }
//testingvhjbnadgfsbgdngffdfdsdfdgfdfdg
} }
} }

View File

@ -1,118 +0,0 @@
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<MMSSystemContext> options) : base(options)
{
}
// DbSet for tbl_marine_tarball
public DbSet<MarineTarball> MarineTarballs { get; set; }
public DbSet<MarineStation> MarineStations { get; set; }
public DbSet<State> States { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<Level> Levels { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Configure properties if needed
modelBuilder.Entity<MarineTarball>(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<MarineStation>(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<State>(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<User>(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<Level>().ToTable("tbl_level");
modelBuilder.Entity<Level>(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);
});
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,68 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace PSTW_CentralSystem.Migrations
{
/// <inheritdoc />
public partial class UpdateTableRequest : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "assignStoreItem",
table: "request",
type: "longtext",
nullable: true)
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AddColumn<string>(
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" });
}
/// <inheritdoc />
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" });
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,126 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace PSTW_CentralSystem.Migrations
{
/// <inheritdoc />
public partial class UpdateRequestTable2 : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<int>(
name: "fromStoreItem",
table: "request",
type: "int",
nullable: true,
oldClrType: typeof(string),
oldType: "longtext",
oldNullable: true)
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<int>(
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");
}
/// <inheritdoc />
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<string>(
name: "fromStoreItem",
table: "request",
type: "longtext",
nullable: true,
oldClrType: typeof(int),
oldType: "int",
oldNullable: true)
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AlterColumn<string>(
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" });
}
}
}

View File

@ -422,12 +422,6 @@ namespace PSTW_CentralSystem.Migrations
b.Property<DateTime?>("approvalDate") b.Property<DateTime?>("approvalDate")
.HasColumnType("datetime(6)"); .HasColumnType("datetime(6)");
b.Property<int?>("assignStoreItem")
.HasColumnType("int");
b.Property<int?>("fromStoreItem")
.HasColumnType("int");
b.Property<string>("remarkMasterInv") b.Property<string>("remarkMasterInv")
.HasColumnType("longtext"); .HasColumnType("longtext");
@ -448,10 +442,6 @@ namespace PSTW_CentralSystem.Migrations
b.HasIndex("UserId"); b.HasIndex("UserId");
b.HasIndex("assignStoreItem");
b.HasIndex("fromStoreItem");
b.ToTable("request"); b.ToTable("request");
}); });
@ -764,16 +754,16 @@ namespace PSTW_CentralSystem.Migrations
{ {
Id = 1, Id = 1,
AccessFailedCount = 0, AccessFailedCount = 0,
ConcurrencyStamp = "853a1cf1-3482-47c4-b4b0-7b6a3af6696c", ConcurrencyStamp = "d801514b-2c36-4df7-9bb5-1c7e351ed27e",
Email = "admin@pstw.com.my", Email = "admin@pstw.com.my",
EmailConfirmed = true, EmailConfirmed = true,
FullName = "MAAdmin", FullName = "MAAdmin",
LockoutEnabled = false, LockoutEnabled = false,
NormalizedEmail = "ADMIN@PSTW.COM.MY", NormalizedEmail = "ADMIN@PSTW.COM.MY",
NormalizedUserName = "ADMIN@PSTW.COM.MY", NormalizedUserName = "ADMIN@PSTW.COM.MY",
PasswordHash = "AQAAAAIAAYagAAAAEBJPP1cHHZZyaGLaskNvSj8sOEizvDa1W2JgxMlYtK18+uhZWvW2RPlqBOhaKc0loQ==", PasswordHash = "AQAAAAIAAYagAAAAEBSoDiGEYlobLgzVcffYwvTtm1WnXpqrBBT1yYP+kruV4OTtizW7Sel94qAfqUjGcw==",
PhoneNumberConfirmed = false, PhoneNumberConfirmed = false,
SecurityStamp = "c911b03d-918a-482f-9c9e-773dc64cdd5d", SecurityStamp = "6132b0af-6a7f-4f38-8959-d049ed486e8f",
TwoFactorEnabled = false, TwoFactorEnabled = false,
UserInfoStatus = 1, UserInfoStatus = 1,
UserName = "admin@pstw.com.my" UserName = "admin@pstw.com.my"
@ -782,16 +772,16 @@ namespace PSTW_CentralSystem.Migrations
{ {
Id = 2, Id = 2,
AccessFailedCount = 0, AccessFailedCount = 0,
ConcurrencyStamp = "9ccd914d-6310-4d4e-88c0-e842892e1831", ConcurrencyStamp = "14f11e89-bb92-49dd-a8df-ec5b0d49df2d",
Email = "sysadmin@pstw.com.my", Email = "sysadmin@pstw.com.my",
EmailConfirmed = true, EmailConfirmed = true,
FullName = "SysAdmin", FullName = "SysAdmin",
LockoutEnabled = false, LockoutEnabled = false,
NormalizedEmail = "SYSADMIN@PSTW.COM.MY", NormalizedEmail = "SYSADMIN@PSTW.COM.MY",
NormalizedUserName = "SYSADMIN@PSTW.COM.MY", NormalizedUserName = "SYSADMIN@PSTW.COM.MY",
PasswordHash = "AQAAAAIAAYagAAAAELxkKuB4hcfQ7Pqe/XCRgygejUsY7X9ByQuS/3FMl50OSzmz9s0byWxGYWQXbyBpGA==", PasswordHash = "AQAAAAIAAYagAAAAEEvcS1SY+9pxZKH/P1l4TaodgW3SFSRfcZ+PnjB3MiMmEUSyYoo64AQtX0bOxFSX2g==",
PhoneNumberConfirmed = false, PhoneNumberConfirmed = false,
SecurityStamp = "5b9a67a3-8186-474b-9499-c9c40457fb54", SecurityStamp = "6dca2498-5150-4369-9923-6f19a48258d4",
TwoFactorEnabled = false, TwoFactorEnabled = false,
UserInfoStatus = 1, UserInfoStatus = 1,
UserName = "sysadmin@pstw.com.my" UserName = "sysadmin@pstw.com.my"
@ -983,22 +973,10 @@ namespace PSTW_CentralSystem.Migrations
.OnDelete(DeleteBehavior.Cascade) .OnDelete(DeleteBehavior.Cascade)
.IsRequired(); .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("Product");
b.Navigation("Station"); b.Navigation("Station");
b.Navigation("Store");
b.Navigation("Stores");
b.Navigation("User"); b.Navigation("User");
}); });

View File

@ -1,83 +0,0 @@
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'
}
}

View File

@ -14,7 +14,6 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="ClosedXML" Version="0.104.2" /> <PackageReference Include="ClosedXML" Version="0.104.2" />
<PackageReference Include="DocumentFormat.OpenXml" Version="3.3.0" /> <PackageReference Include="DocumentFormat.OpenXml" Version="3.3.0" />
<PackageReference Include="Lemonade" Version="1.0.276" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.11" /> <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.11" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="8.0.11" /> <PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="8.0.11" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.11" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.11" />
@ -29,19 +28,11 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="8.0.7" /> <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="8.0.7" />
<PackageReference Include="MySql.EntityFrameworkCore" Version="9.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="PDFsharp" Version="6.1.1" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.2" /> <PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.2" />
<PackageReference Include="QuestPDF" Version="2025.4.0" /> <PackageReference Include="QuestPDF" Version="2025.4.0" />
<PackageReference Include="QuestPDF" Version="2025.1.7" />
<PackageReference Include="QuestPDF.HTML" Version="1.4.2" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.3" /> <PackageReference Include="Serilog.AspNetCore" Version="8.0.3" />
<PackageReference Include="System.Drawing.Common" Version="9.0.5" /> <PackageReference Include="System.Drawing.Common" Version="9.0.5" />
<PackageReference Include="SkiaSharp" Version="3.116.1" />
<PackageReference Include="System.Drawing.Common" Version="9.0.3" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.3" />
<PackageReference Include="Verify.QuestPDF" Version="2.3.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -10,8 +10,6 @@ using QuestPDF.Infrastructure;
using PSTW_CentralSystem.Areas.OTcalculate.Services; using PSTW_CentralSystem.Areas.OTcalculate.Services;
using DocumentFormat.OpenXml.Office2016.Drawing.ChartDrawing; using DocumentFormat.OpenXml.Office2016.Drawing.ChartDrawing;
using System.Net;
internal class Program internal class Program
{ {
private static void Main(string[] args) private static void Main(string[] args)
@ -19,7 +17,6 @@ internal class Program
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
var centralConnectionString = builder.Configuration.GetConnectionString("CentralConnnection"); var centralConnectionString = builder.Configuration.GetConnectionString("CentralConnnection");
Settings.License = LicenseType.Community; Settings.License = LicenseType.Community;
//var inventoryConnectionString = builder.Configuration.GetConnectionString("InventoryConnection"); //var inventoryConnectionString = builder.Configuration.GetConnectionString("InventoryConnection");
// Add services to the container. // Add services to the container.
@ -28,9 +25,6 @@ internal class Program
builder.Services.AddScoped<OvertimeExcel>(); builder.Services.AddScoped<OvertimeExcel>();
builder.Services.AddScoped<NetworkShareAccess>(provider =>
new NetworkShareAccess(@"\\192.168.12.42\images\marine\manual_tarball", "installer", "mms@pstw"));
Log.Logger = new LoggerConfiguration() Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(builder.Configuration) .ReadFrom.Configuration(builder.Configuration)
@ -62,12 +56,6 @@ internal class Program
); );
}); });
builder.Services.AddDbContext<MMSSystemContext>(options =>
options.UseMySql(builder.Configuration.GetConnectionString("MMSDatabase"),
new MySqlServerVersion(new Version(8, 0, 0))));
//builder.Services.AddDbContext<InventoryDBContext>(options => //builder.Services.AddDbContext<InventoryDBContext>(options =>
//{ //{
// options.UseMySql(inventoryConnectionString, new MySqlServerVersion(new Version(8, 0, 39)), // options.UseMySql(inventoryConnectionString, new MySqlServerVersion(new Version(8, 0, 39)),
@ -90,7 +78,6 @@ internal class Program
// Add scope // Add scope
builder.Services.AddScoped<IAuthorizationHandler, RoleModuleHandler>(); builder.Services.AddScoped<IAuthorizationHandler, RoleModuleHandler>();
var app = builder.Build(); var app = builder.Build();
// Configure the HTTP request pipeline. // Configure the HTTP request pipeline.
@ -114,12 +101,6 @@ internal class Program
app.MapControllerRoute( app.MapControllerRoute(
name: "root", name: "root",
pattern: "{controller=Home}/{action=Index}/{id?}"); 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(); app.Run();
} }

View File

@ -430,7 +430,6 @@
<i class="mdi mdi-view-dashboard"></i><span class="hide-menu">Module Administration</span> <i class="mdi mdi-view-dashboard"></i><span class="hide-menu">Module Administration</span>
</a> </a>
</li> </li>
</ul> </ul>
</li> </li>
<li class="sidebar-item"> <li class="sidebar-item">
@ -487,7 +486,7 @@
<a class="sidebar-link has-arrow waves-effect waves-dark" <a class="sidebar-link has-arrow waves-effect waves-dark"
href="javascript:void(0)" href="javascript:void(0)"
aria-expanded="false"> aria-expanded="false">
<i class="mdi mdi-receipt"></i><span class="hide-menu">Report</span> <i class="mdi mdi-receipt"></i><span class="hide-menu">Report </span>
</a> </a>
<ul aria-expanded="false" class="collapse first-level"> <ul aria-expanded="false" class="collapse first-level">
<li class="sidebar-item"> <li class="sidebar-item">
@ -500,31 +499,6 @@
<i class="mdi mdi-view-dashboard"></i><span class="hide-menu">Inventory Report</span> <i class="mdi mdi-view-dashboard"></i><span class="hide-menu">Inventory Report</span>
</a> </a>
</li> </li>
<!--MMS-->
<li class="sidebar-item">
<a class="sidebar-link has-arrow waves-effect waves-dark"
href="javascript:void(0)" aria-expanded="false">
<i class="mdi mdi-view-dashboard"></i><span class="hide-menu">MMS</span>
</a>
<ul aria-expanded="false" class="collapse first-level">
<!-- Marine subsection -->
<li class="sidebar-item">
<a class="sidebar-link has-arrow waves-effect waves-dark"
href="javascript:void(0)" aria-expanded="false">
<i class="mdi mdi-view-dashboard"></i><span class="hide-menu">Marine</span>
</a>
<ul aria-expanded="false" class="collapse second-level">
<!-- Tar Ball Sampling Form link -->
<li class="sidebar-item">
<a class="sidebar-link waves-effect waves-dark"
asp-area="MMS" asp-controller="Marine" asp-action="TarBallForm" aria-expanded="false">
<i class="mdi mdi-view-dashboard"></i><span class="hide-menu">Tarball Report</span>
</a>
</li>
</ul>
</li>
</ul>
</li>
</ul> </ul>
</li> </li>

View File

@ -3,19 +3,10 @@
//"DefaultConnection": "Server=localhost;uid=root;Password='';Database=web_interface;" //"DefaultConnection": "Server=localhost;uid=root;Password='';Database=web_interface;"
//"DefaultConnection": "server=175.136.244.102;user id=root;password=tw_mysql_root;port=3306;database=web_interface" //"DefaultConnection": "server=175.136.244.102;user id=root;password=tw_mysql_root;port=3306;database=web_interface"
//"CentralConnnection": "Server=192.168.12.12;Port=3306;uid=installer;password='pstw_mysql_installer';database=pstw_cs;", //DB_dev Local connection //"CentralConnnection": "Server=192.168.12.12;Port=3306;uid=installer;password='pstw_mysql_installer';database=pstw_cs;", //DB_dev Local connection
"CentralConnnection": "Server=219.92.7.60;Port=3307;uid=installer;password='pstw_mysql_installer';database=pstw_cs_prod;" //DB_dev Public connection "CentralConnnection": "Server=219.92.7.60;Port=3307;uid=installer;password='pstw_mysql_installer';database=pstw_cs;" //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 //"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 //"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": { "Logging": {
"LogLevel": { "LogLevel": {
"Default": "Information", "Default": "Information",

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB