Compare commits
No commits in common. "b9a830f86aa51960d68e1370c5b5eab6f9b249d5" and "4e7c5757e0148d2da5a9c942e16c50f0f684598b" have entirely different histories.
b9a830f86a
...
4e7c5757e0
@ -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; }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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
@ -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">
|
||||||
|
|||||||
@ -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;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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');
|
||||||
|
|||||||
@ -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">
|
||||||
|
|||||||
@ -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">
|
||||||
|
|||||||
@ -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();
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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 }
|
|
||||||
}
|
|
||||||
@ -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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
@{
|
|
||||||
ViewData["Title"] = "MMS Dashboard";
|
|
||||||
}
|
|
||||||
|
|
||||||
<h1>Welcome to the MMS Dashboard</h1>
|
|
||||||
<p>This is where you’ll add content for MMS later.</p>
|
|
||||||
@ -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>
|
|
||||||
}
|
|
||||||
@ -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;
|
||||||
|
|||||||
@ -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
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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()
|
||||||
|
|||||||
@ -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;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
@ -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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
1059
Migrations/20250310054721_UpdateTableRequest.Designer.cs
generated
1059
Migrations/20250310054721_UpdateTableRequest.Designer.cs
generated
File diff suppressed because it is too large
Load Diff
@ -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" });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
1075
Migrations/20250311003003_UpdateRequestTable2.Designer.cs
generated
1075
Migrations/20250311003003_UpdateRequestTable2.Designer.cs
generated
File diff suppressed because it is too large
Load Diff
@ -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" });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -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'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -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>
|
||||||
|
|||||||
19
Program.cs
19
Program.cs
@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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>
|
||||||
|
|
||||||
|
|||||||
@ -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",
|
||||||
|
|||||||
BIN
document.pdf
BIN
document.pdf
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 30 KiB |
Loading…
Reference in New Issue
Block a user