update qrmaster
This commit is contained in:
parent
11e8e84064
commit
18ecaedda8
@ -18,64 +18,282 @@
|
||||
</style>
|
||||
@await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml");
|
||||
<div id="registerItem" class="row">
|
||||
<div class="row mb-3" v-if="currentRole == 'Super Admin'">
|
||||
<h2 for="sortSelect" class="col-sm-1 col-form-h2" style="min-width:140px;">Sort by:</h2>
|
||||
<div class="col-sm-4">
|
||||
<select id="sortSelect" class="form-control" v-model="sortBy" v-on:change="handleSorting">
|
||||
<option value="all">All</option>
|
||||
<option value="item">Item</option>
|
||||
<option value="logs">Logs</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3" v-if="sortBy === 'item'">
|
||||
<h4 class="col-sm-1 col-form-h2" style="min-width:140px;">Search Item:</h4>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" class="form-control" v-model="searchQuery" placeholder="Search by item code...">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="sortBy === 'all'">
|
||||
<div class="row card">
|
||||
<div class="card-header">
|
||||
<h2>Pending Item Movement</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-bordered table-hover table-striped no-wrap" id="itemMovementNotCompleteDatatable" style="width:100%;border-style: solid; border-width: 1px"></table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row card">
|
||||
<div class="card-header">
|
||||
<h2>Complete Item Movement</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-bordered table-hover table-striped no-wrap" id="itemMovementCompleteDatatable" style="width:100%;border-style: solid; border-width: 1px"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="sortBy === 'logs'">
|
||||
<div class="row card">
|
||||
<div class="card-header">
|
||||
<h2>Item Movement List</h2>
|
||||
@* <button id="addItemBtn" class="btn btn-success col-md-3 col-lg-3 m-1 col-12"><i class="fa fa-plus"></i> Add Item</button> *@
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@* <div v-if="loading">
|
||||
<div class="spinner-border text-info" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
</div> *@
|
||||
<table class="table table-bordered table-hover table-striped no-wrap" id="itemDatatable" style=" width:100%;border-style: solid; border-width: 1px"></table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" id="QrItemModal" tabindex="-1" role="dialog" aria-labelledby="QrItemModalLabel" aria-hidden="true" data-bs-target="#staticBackdrop">
|
||||
<div class="modal-dialog modal-dialog-centered modal-md" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="QrItemModalLabel"></h5>
|
||||
<button type="button" class="closeModal btn-close" data-bs-dismiss="modal" aria-label="Close" v-on:click="showItemModal=false"></button>
|
||||
</div>
|
||||
<div class="modal-body d-flex justify-content-center align-items-center">
|
||||
<div class="container" style="font-family: 'OCR A', monospace;">
|
||||
<div class="row" ref="qrInfo" id="qrInfo">
|
||||
<div class="col-5 text-center d-flex align-items-center justify-content-center">
|
||||
|
||||
<div v-if="sortBy === 'item'">
|
||||
<div v-for="(group, itemId) in filteredItems" :key="itemId" class="row card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h2>Item : {{ group.uniqueID }}</h2>
|
||||
<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
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Hide all details unless button is clicked -->
|
||||
<div v-show="categoryVisible[itemId]" class="card-body">
|
||||
<div v-for="(movement, index) in group.movements.sort((a, b) => a.id - b.id).reverse()" :key="movement.id" class="movement-row">
|
||||
<!-- 📌 Show Only Latest Movement -->
|
||||
<div v-if="index === 0" class="row">
|
||||
<strong>Latest Movement</strong>
|
||||
<div class="col-md-12 d-flex flex-wrap align-items-center gap-3 p-2 border-bottom">
|
||||
<!-- Movement Type -->
|
||||
<h3 :class="movement.toOther === 'On Delivery' ? 'text-primary' : 'text-warning'"
|
||||
class="flex-shrink-0 text-nowrap" style="max-width:90px; min-width:90px;">
|
||||
{{ movement.toOther === 'On Delivery' ? 'Receive' : 'Return' }}
|
||||
</h3>
|
||||
|
||||
<!-- Send Date -->
|
||||
<div class="d-flex flex-wrap align-items-center gap-2 flex-grow-1">
|
||||
<h4 class="fixed-label m-0 text-nowrap">Send Date:</h4>
|
||||
<span class="fixed-value">{{ movement.sendDate }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Receive Date -->
|
||||
<div class="d-flex flex-wrap align-items-center gap-2 flex-grow-1">
|
||||
<h4 class="fixed-label m-0 text-nowrap">Receive Date:</h4>
|
||||
<span class="fixed-value">{{ movement.receiveDate || 'Not arrive' }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Action -->
|
||||
<div class="d-flex flex-wrap align-items-center gap-2 flex-grow-1">
|
||||
<h4 class="fixed-labelStatus m-0 text-nowrap">Action:</h4>
|
||||
<span class="fixed-value">{{ movement.action }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Status -->
|
||||
<div class="d-flex flex-wrap align-items-center gap-2 flex-grow-1">
|
||||
<h4 class="fixed-labelStatus m-0 text-nowrap">Status:</h4>
|
||||
<span class="fixed-value">{{ movement.latestStatus || movement.toOther }}</span>
|
||||
</div>
|
||||
|
||||
<!-- More Details Button -->
|
||||
<button class="btn btn-info btn-sm ms-auto" v-on:click="toggleDetails(movement.id)">
|
||||
More Details
|
||||
</button>
|
||||
|
||||
<!-- Completion Status -->
|
||||
<h4 :class="movement.movementComplete == 1 && movement.latestStatus !== 'Ready To Deploy' ? 'text-success' : 'text-danger'" class="text-nowrap ms-3">
|
||||
{{ movement.movementComplete == 1 && movement.latestStatus !== 'Ready To Deploy' ? 'Complete' : (movement.latestStatus === 'Ready To Deploy' ? 'Canceled' : 'Incomplete') }}
|
||||
</h4>
|
||||
|
||||
</div>
|
||||
|
||||
<div v-show="detailsVisible[movement.id]" class="col-md-12 mt-2">
|
||||
<div class="row">
|
||||
<div class="col-12 text-center">
|
||||
<div id="QrContainer"></div>
|
||||
<div class="col-12 text-center">
|
||||
{{thisQRInfo.itemId}}
|
||||
<div class="col-md-4 text-center">
|
||||
<!-- Conditionally render Start Icon -->
|
||||
<i v-if="movement.toOther !== 'On Delivery'" class="fas fa-user fa-2x"></i>
|
||||
<i v-else class="fas fa-warehouse fa-2x"></i>
|
||||
<p><strong>Start</strong></p>
|
||||
<p><strong>User:</strong> {{ movement.toUserName }}</p>
|
||||
<p><strong>Station:</strong> {{ movement.toStationName }}</p>
|
||||
<p><strong>Store:</strong> {{ movement.toStoreName }}</p>
|
||||
</div>
|
||||
<div class="col-md-4 text-center">
|
||||
<p></p>
|
||||
<i class="fas fa-arrow-right fa-2x"></i>
|
||||
<p>{{ movement.latestStatus || movement.toOther }}</p>
|
||||
<p>
|
||||
<button class="btn btn-info btn-sm ms-auto" v-on:click="remark(movement.remark)" v-if="movement.toOther !== 'On Delivery'">
|
||||
Remark
|
||||
</button>
|
||||
</p>
|
||||
<p>
|
||||
<button class="btn btn-info btn-sm ms-auto" v-on:click="consignmentNote(movement.consignmentNote)" v-if="movement.toOther !== 'On Delivery'">
|
||||
Consignment Note
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-4 text-center">
|
||||
<!-- Conditionally render End Icon -->
|
||||
<i v-if="movement.toOther !== 'On Delivery'" class="fas fa-warehouse fa-2x"></i>
|
||||
<i v-else class="fas fa-user fa-2x"></i>
|
||||
<p><strong>End</strong></p>
|
||||
<p><strong>User:</strong> {{ movement.lastUserName }}</p>
|
||||
<p><strong>Station:</strong> {{ movement.lastStationName }}</p>
|
||||
<p><strong>Store:</strong> {{ movement.lastStoreName }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-7 d-flex align-items-center justify-content-center">
|
||||
<div class="text-center fs-4 text">
|
||||
<div class="col-12 my-3">
|
||||
{{thisQRInfo.departmentName}}
|
||||
</div>
|
||||
<div class="col-12 my-3">
|
||||
{{thisQRInfo.productShortName}}
|
||||
</div>
|
||||
<div class="col-12 my-3">
|
||||
{{thisQRInfo.serialNumber}}
|
||||
</div>
|
||||
<div class="col-12 my-3">
|
||||
{{thisQRInfo.partNumber}}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* <!-- 📌 Single View History Button --> *@
|
||||
<button class="btn btn-light w-100 text-left" v-on:click="toggleHistory(itemId)">
|
||||
<i :class="historyVisible[itemId] ? 'fas fa-chevron-up' : 'fas fa-chevron-down'"></i> View History
|
||||
</button>
|
||||
|
||||
<div v-show="historyVisible[itemId]" class="history-row">
|
||||
<div v-for="(movement, i) in group.movements.slice(1)" :key="i" class="row mt-2">
|
||||
<div class="col-md-12 d-flex flex-wrap align-items-center gap-3 p-2 border-bottom">
|
||||
<!-- Movement Type -->
|
||||
<h3 :class="movement.toOther === 'On Delivery' ? 'text-primary' : 'text-warning'"
|
||||
class="flex-shrink-0 text-nowrap" style="max-width:90px; min-width:90px;">
|
||||
{{ movement.toOther === 'On Delivery' ? 'Receive' : 'Return' }}
|
||||
</h3>
|
||||
|
||||
<!-- Send Date -->
|
||||
<div class="d-flex flex-wrap align-items-center gap-2 flex-grow-1" style="max-width:285px; min-width:285px;">
|
||||
<h4 class="fixed-label m-0 text-nowrap">Send Date:</h4>
|
||||
<span class="fixed-value text-truncate">{{ movement.sendDate }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Receive Date -->
|
||||
<div class="d-flex flex-wrap align-items-center gap-2 flex-grow-1" style="max-width:290px; min-width:290px;">
|
||||
<h4 class="fixed-label m-0 text-nowrap">Receive Date:</h4>
|
||||
<span class="fixed-value text-truncate" style="max-width:160px;">{{ movement.receiveDate || 'Not arrive' }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Action -->
|
||||
<div class="d-flex flex-wrap align-items-center gap-2 flex-grow-1" style="max-width:150px; min-width:150px;">
|
||||
<h4 class="fixed-labelStatus m-0 text-nowrap">Action:</h4>
|
||||
<span class="fixed-value text-truncate">{{ movement.action }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Status -->
|
||||
<div class="d-flex flex-wrap align-items-center gap-2 flex-grow-1" style="max-width:160px; min-width:160px;">
|
||||
<h4 class="fixed-labelStatus m-0 text-nowrap">Status:</h4>
|
||||
<span class="fixed-value text-truncate" style="max-width:90px;">{{ movement.latestStatus || movement.toOther }}</span>
|
||||
</div>
|
||||
|
||||
<!-- More Details Button -->
|
||||
<button class="btn btn-info btn-sm ms-auto" v-on:click="toggleDetails(movement.id)">
|
||||
More Details
|
||||
</button>
|
||||
|
||||
<!-- Completion Status -->
|
||||
<h4 :class="movement.movementComplete == 1 && movement.latestStatus !== 'Ready To Deploy' ? 'text-success' : 'text-danger'"
|
||||
class="text-nowrap ms-3">
|
||||
{{ movement.movementComplete == 1 && movement.latestStatus !== 'Ready To Deploy' ? 'Complete' : (movement.latestStatus === 'Ready To Deploy' ? 'Canceled' : 'Incomplete') }}
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 📌 Details Section (Hidden by Default) -->
|
||||
<div v-show="detailsVisible[movement.id]" class="col-md-12 mt-2">
|
||||
<div class="row">
|
||||
<button v-on:click="printQRInfo">Print QR Info</button>
|
||||
<div class="col-md-4 text-center">
|
||||
<!-- Conditionally render Start Icon -->
|
||||
<i v-if="movement.toOther !== 'On Delivery'" class="fas fa-user fa-2x"></i>
|
||||
<i v-else class="fas fa-warehouse fa-2x"></i>
|
||||
<p><strong>Start</strong></p>
|
||||
<p><strong>User:</strong> {{ movement.toUserName }}</p>
|
||||
<p><strong>Station:</strong> {{ movement.toStationName }}</p>
|
||||
<p><strong>Store:</strong> {{ movement.toStoreName }}</p>
|
||||
</div>
|
||||
<div class="col-md-4 text-center">
|
||||
<p></p>
|
||||
<i class="fas fa-arrow-right fa-2x"></i>
|
||||
<p>{{ movement.latestStatus || movement.toOther }}</p>
|
||||
<p>
|
||||
<button class="btn btn-info btn-sm ms-auto" v-on:click="remark(movement.remark)" v-if="movement.toOther !== 'On Delivery'">
|
||||
Remark
|
||||
</button>
|
||||
</p>
|
||||
<p>
|
||||
<button class="btn btn-info btn-sm ms-auto" v-on:click="consignmentNote(movement.consignmentNote)" v-if="movement.toOther !== 'On Delivery'">
|
||||
Consignment Note
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-4 text-center">
|
||||
<!-- Conditionally render End Icon -->
|
||||
<i v-if="movement.toOther !== 'On Delivery'" class="fas fa-warehouse fa-2x"></i>
|
||||
<i v-else class="fas fa-user fa-2x"></i>
|
||||
<p><strong>End</strong></p>
|
||||
<p><strong>User:</strong> {{ movement.lastUserName }}</p>
|
||||
<p><strong>Station:</strong> {{ movement.lastStationName }}</p>
|
||||
<p><strong>Store:</strong> {{ movement.lastStoreName }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* <div class="modal fade" id="remarkModal" tabindex="-1" aria-labelledby="remarkModalLabel" aria-hidden="true"> *@
|
||||
@* <div class="modal-dialog"> *@
|
||||
@* <div class="modal-content"> *@
|
||||
@* <div class="modal-header"> *@
|
||||
@* <h5 class="modal-title" id="remarkModalLabel">Remark</h5> *@
|
||||
@* <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> *@
|
||||
@* </div> *@
|
||||
@* <div class="modal-body" id="remarkContent"> *@
|
||||
@* <!-- Remark Content Here --> *@
|
||||
@* </div> *@
|
||||
@* <div class="modal-footer"> *@
|
||||
@* <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button> *@
|
||||
@* </div> *@
|
||||
@* </div> *@
|
||||
@* </div> *@
|
||||
@* </div> *@
|
||||
@* <div class="modal fade" id="consignmentModal" tabindex="-1" aria-labelledby="consignmentModalLabel" aria-hidden="true"> *@
|
||||
@* <div class="modal-dialog modal-xl"> *@
|
||||
@* <div class="modal-content"> *@
|
||||
@* <div class="modal-header"> *@
|
||||
@* <h5 class="modal-title" id="consignmentModalLabel">Consignment Note</h5> *@
|
||||
@* <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> *@
|
||||
@* </div> *@
|
||||
@* <div class="modal-body text-center"> *@
|
||||
@* <img v-if="/\.(jpeg|jpg|png|gif)$/i.test(consignmentNoteUrl)" :src="consignmentNoteUrl" class="img-fluid" alt="Consignment Note Image"> *@
|
||||
@* <iframe v-else-if="/\.pdf$/i.test(consignmentNoteUrl)" :src="consignmentNoteUrl" style="width:100%; height: 80vh;"></iframe> *@
|
||||
@* <a v-else class="btn btn-primary">There's no Folder or Picture</a> *@
|
||||
@* </div> *@
|
||||
@* </div> *@
|
||||
@* </div> *@
|
||||
@* </div> *@
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -169,118 +387,49 @@
|
||||
items: [],
|
||||
currentUser: null,
|
||||
currentUserCompanyDept: null,
|
||||
sortBy: "item",
|
||||
searchQuery: "",
|
||||
categoryVisible: {},
|
||||
historyVisible: {},
|
||||
detailsVisible: {},
|
||||
currentRole:"",
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.fetchUser();
|
||||
this.fetchItem();
|
||||
this.fetchCurrencyData();
|
||||
this.fetchCompanies();
|
||||
this.fetchProducts();
|
||||
this.fetchSuppliers();
|
||||
this.fetchStation();
|
||||
this.fetchStore();
|
||||
this.fetchUsers();
|
||||
|
||||
|
||||
},
|
||||
computed: {
|
||||
filteredDepartments() {
|
||||
if (!this.selectedCompany) {
|
||||
return []; // No company selected, return empty list
|
||||
groupedItems() {
|
||||
return this.items.reduce((acc, movement) => {
|
||||
if (!acc[movement.itemId]) {
|
||||
acc[movement.itemId] = {
|
||||
uniqueID: movement.uniqueID,
|
||||
movements: [],
|
||||
};
|
||||
}
|
||||
const company = this.companies.find(c => c.companyId === this.selectedCompany);
|
||||
// this.selectedDepartment = '';
|
||||
return company ? company.departments : [];
|
||||
acc[movement.itemId].movements.push(movement);
|
||||
return acc;
|
||||
}, {});
|
||||
},
|
||||
showProduct() {
|
||||
if (!this.selectedProduct) {
|
||||
return []; // No company selected, return empty list
|
||||
filteredItems() {
|
||||
if (!this.searchQuery.trim()) {
|
||||
return this.groupedItems;
|
||||
}
|
||||
const product = this.products.find(c => c.productId === this.selectedProduct);
|
||||
return product ? product : {};
|
||||
},
|
||||
showSerialNumber() {
|
||||
return this.showProduct.category === 'Asset' || this.showProduct.category === 'Part';
|
||||
const searchLower = this.searchQuery.toLowerCase();
|
||||
return Object.fromEntries(
|
||||
Object.entries(this.groupedItems).filter(([_, group]) =>
|
||||
group.uniqueID.toLowerCase().includes(searchLower)
|
||||
)
|
||||
);
|
||||
|
||||
},
|
||||
|
||||
},
|
||||
methods: {
|
||||
async addItem() {
|
||||
if (this.showProduct.category == "Disposable") {
|
||||
this.serialNumber = "";
|
||||
}
|
||||
const formData = {
|
||||
CompanyId: this.selectedCompany,
|
||||
DepartmentId: this.selectedDepartment,
|
||||
ProductId: this.selectedProduct,
|
||||
SerialNumber: this.serialNumber,
|
||||
Quantity: this.quantity,
|
||||
Supplier: this.selectedSupplier,
|
||||
PurchaseDate: this.purchaseDate,
|
||||
PONo: this.PO,
|
||||
Currency: this.currency,
|
||||
DefaultPrice: this.DefaultPrice,
|
||||
CurrencyRate: this.currencyRate,
|
||||
ConvertPrice: this.convertPrice,
|
||||
DODate: this.DODate,
|
||||
Warranty: this.warranty,
|
||||
EndWDate: this.EndWDate,
|
||||
InvoiceDate: this.invoiceDate,
|
||||
CreatedByUserId: this.currentUser.id,
|
||||
TeamType: this.selectedTeamType,
|
||||
PartNumber: this.partNumber,
|
||||
};
|
||||
|
||||
try {
|
||||
|
||||
// Additional specific checks
|
||||
if (this.showSerialNumber) {
|
||||
this.quantity = 0;
|
||||
if (this.serialNumber === null || this.serialNumber === '') {
|
||||
alert('Serial Number Error', 'Serial Number must be filled when selecting Item or Part.', 'warning');
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.serialNumber = null;
|
||||
if (this.quantity === 0 || this.quantity === null || this.quantity === '') {
|
||||
alert('quantity Error', 'Quantity is required when selecting Disposable.', 'warning');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Proceed to send the data to the API
|
||||
const response = await fetch('/InvMainAPI/AddItem', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
// 'Authorization': `Bearer ${this.token}`
|
||||
},
|
||||
body: JSON.stringify(formData)
|
||||
});
|
||||
if (response.ok) {
|
||||
// If the form submission was successful, display a success message
|
||||
alert('Success!', 'Item form has been successfully submitted.', 'success');
|
||||
const updatedItem = await response.json();
|
||||
this.items.push(updatedItem);
|
||||
|
||||
this.fetchItem();
|
||||
|
||||
// Reset the form
|
||||
this.resetForm();
|
||||
} else {
|
||||
throw new Error('Failed to submit form.');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
|
||||
// Displaying error message
|
||||
alert('Inventory PSTW Error', `An error occurred: ${error.message}`, 'error');
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
initiateTable() {
|
||||
self = this;
|
||||
@ -291,6 +440,7 @@
|
||||
{ title: "Product Code", data: "uniqueID" },
|
||||
{ title: "From User", data: "toUserName" },
|
||||
{ title: "Last User", data: "lastUserName" },
|
||||
{ title: "Completion", data: "movementComplete", render: function (data) {return data ? "Completed" : "Pending";}},
|
||||
{ title: "From Station", data: "toStationName" },
|
||||
{ title: "Last Station", data: "lastStationName" },
|
||||
{ title: "From Store", data: "toStoreName" },
|
||||
@ -298,6 +448,7 @@
|
||||
{ title: "Action", data: "action" },
|
||||
{ title: "Start Status", data: "toOther" },
|
||||
{ title: "Latest Status", data: "latestStatus" },
|
||||
{ title: "Product Category", data: "productCategory" },
|
||||
{ title: "Qty", data: "quantity" },
|
||||
{ title: "Send Date", data: "sendDate" },
|
||||
{ title: "Receive Date", data: "receiveDate" },
|
||||
@ -307,11 +458,9 @@
|
||||
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;" />
|
||||
@ -330,11 +479,8 @@
|
||||
},
|
||||
},
|
||||
{ title: "Remark", data: "remark" },
|
||||
{
|
||||
"title": "Completion",
|
||||
"data": "movementComplete",
|
||||
},
|
||||
],
|
||||
order: [[0, "desc"]], // Sorting by "Product Code" (uniqueID) in descending order
|
||||
responsive: true,
|
||||
drawCallback: function (settings) {
|
||||
// Generate QR codes after rows are rendered
|
||||
@ -413,7 +559,17 @@
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch item');
|
||||
}
|
||||
if(this.currentRole == "Super Admin"){
|
||||
this.items = await response.json();
|
||||
} else {
|
||||
const data = await response.json();
|
||||
this.items = data.filter(item =>
|
||||
item.toUser === this.currentUser.id ||
|
||||
item.lastUser === this.currentUser.id
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
// const allowedKeys = ["toUser", "lastUser"];
|
||||
// this.items = (await response.json()).filter(item => allowedKeys.some(key => item[key] === this.currentUser.id));
|
||||
// this.items = (await response.json()).filter(item => item.lastUser === this.currentUser);
|
||||
@ -432,153 +588,12 @@
|
||||
}
|
||||
},
|
||||
|
||||
async fetchProducts() {
|
||||
try {
|
||||
// const token = localStorage.getItem('token'); // Get the token from localStorage
|
||||
const response = await fetch('/InvMainAPI/ProductList', {
|
||||
method: 'POST', // Specify the HTTP method
|
||||
headers: {
|
||||
'Content-Type': 'application/json', // Set content type
|
||||
// 'Authorization': `Bearer ${token}` // Include the token in the headers
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch products');
|
||||
}
|
||||
|
||||
this.products = await response.json();
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Error fetching products:', error);
|
||||
}
|
||||
},
|
||||
|
||||
async fetchCompanies() {
|
||||
try {
|
||||
const response = await fetch('/AdminAPI/GetDepartmentWithCompanyList', {
|
||||
method: 'POST', // Specify the HTTP method
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch companies');
|
||||
}
|
||||
|
||||
this.companies = await response.json();
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error fetching products:', error);
|
||||
}
|
||||
},
|
||||
|
||||
async fetchSuppliers() {
|
||||
try {
|
||||
const response = await fetch('/InvMainAPI/SupplierList', {
|
||||
method: 'POST', // Specify the HTTP method
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch suppliers');
|
||||
}
|
||||
this.suppliers = await response.json(); // Get the full response object
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error fetching suppliers:', error);
|
||||
}
|
||||
},
|
||||
async fetchStation() {
|
||||
try {
|
||||
const response = await fetch('/InvMainAPI/StationList', {
|
||||
method: 'POST', // Specify the HTTP method
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch suppliers');
|
||||
}
|
||||
this.stations = await response.json(); // Get the full response object
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error fetching suppliers:', error);
|
||||
}
|
||||
},
|
||||
async fetchStore() {
|
||||
try {
|
||||
const response = await fetch('/InvMainAPI/StoreList', {
|
||||
method: 'POST', // Specify the HTTP method
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch suppliers');
|
||||
}
|
||||
this.stores = await response.json(); // Get the full response object
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error fetching suppliers:', error);
|
||||
}
|
||||
},
|
||||
async fetchUsers() {
|
||||
try {
|
||||
const response = await fetch('/InvMainAPI/UserList', {
|
||||
method: 'POST', // Specify the HTTP method
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch suppliers');
|
||||
}
|
||||
this.users = await response.json(); // Get the full response object
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error fetching suppliers:', error);
|
||||
}
|
||||
},
|
||||
async fetchCurrencyData() {
|
||||
try {
|
||||
// Fetch currency data from the API
|
||||
const response = await fetch('https://openexchangerates.org/api/currencies.json'); // Example API
|
||||
this.currencies = await response.json();
|
||||
} catch (error) {
|
||||
console.error('Error fetching currency data:', error);
|
||||
}
|
||||
},
|
||||
convertCurrency() {
|
||||
// Your currency conversion logic here
|
||||
console.log('Selected currency:', this.currency);
|
||||
},
|
||||
resetForm() {
|
||||
this.company = '';
|
||||
this.Dept = null;
|
||||
this.productName = null;
|
||||
this.imageProduct = null;
|
||||
this.serialNumber = '';
|
||||
this.quantity = 1;
|
||||
this.supplierName = null;
|
||||
this.purchaseDate = null;
|
||||
this.PO = null;
|
||||
this.currency = 'MYR';
|
||||
this.DefaultPrice = 0.01;
|
||||
this.currencyRate = 1;
|
||||
this.convertPrice = 0.01;
|
||||
this.DODate = null;
|
||||
this.warranty = 0;
|
||||
this.EndWDate = null;
|
||||
this.invoiceDate = null;
|
||||
this.selectedProduct = '';
|
||||
this.selectedSupplier = '';
|
||||
this.selectedCompany = this.currentUserCompanyDept.companyId;
|
||||
this.selectedDepartment = '';
|
||||
this.selectedTeamType = '';
|
||||
this.partNumber = null;
|
||||
},
|
||||
|
||||
// FRONT END FUNCTIONS
|
||||
//----------------------//
|
||||
@ -687,6 +702,15 @@
|
||||
this.selectedCompany = companyDeptData?.companyId || "";
|
||||
this.selectedDepartment = companyDeptData?.departmentId || "";
|
||||
|
||||
const roles = this.currentUser.role;
|
||||
|
||||
if (roles.includes("SuperAdmin")) {
|
||||
this.currentRole = "Super Admin";
|
||||
} else if (roles.includes("Inventory Master")) {
|
||||
this.currentRole = "Inventory Master";
|
||||
this.sortBy = "item";
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
console.error(`Failed to fetch user: ${response.statusText}`);
|
||||
@ -696,90 +720,220 @@
|
||||
console.error('There was a problem with the fetch operation:', error);
|
||||
}
|
||||
},
|
||||
getPrintedQR(uniqueID) {
|
||||
if (!this.items || !Array.isArray(this.items)) {
|
||||
console.error("Items list is not available or is not an array.");
|
||||
return null;
|
||||
}
|
||||
return this.items.find(item => item.uniqueID === uniqueID);
|
||||
},
|
||||
printQRInfo() {
|
||||
// getPrintedQR(uniqueID) {
|
||||
// if (!this.items || !Array.isArray(this.items)) {
|
||||
// console.error("Items list is not available or is not an array.");
|
||||
// return null;
|
||||
// }
|
||||
// return this.items.find(item => item.uniqueID === uniqueID);
|
||||
// },
|
||||
// printQRInfo() {
|
||||
// Create a virtual DOM element
|
||||
const virtualElement = document.createElement('div');
|
||||
virtualElement.style.width = '330px '; // Match label size for 2 inches at 203 DPI
|
||||
virtualElement.style.height = '160px';
|
||||
virtualElement.style.position = 'absolute';
|
||||
virtualElement.style.left = '-9999px'; // Position offscreen to avoid rendering on the main UI
|
||||
// virtualElement.style.border = '1px solid #000'; // Optional: Add a border for debugging dimensions
|
||||
// const virtualElement = document.createElement('div');
|
||||
// virtualElement.style.width = '330px '; Match label size for 2 inches at 203 DPI
|
||||
// virtualElement.style.height = '160px';
|
||||
// virtualElement.style.position = 'absolute';
|
||||
// virtualElement.style.left = '-9999px'; Position offscreen to avoid rendering on the main UI
|
||||
// virtualElement.style.border = '1px solid #000'; Optional: Add a border for debugging dimensions
|
||||
|
||||
// Populate the virtual DOM with content
|
||||
virtualElement.innerHTML = `
|
||||
<div class="container-fluid my-3 QrPrintFont" style="font-family: 'OCR A', monospace;">
|
||||
<div class="row" >
|
||||
<div class="col-5 text-center d-flex align-items-center justify-content-center">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div>${this.thisQRInfo.imgContainer}</div>
|
||||
<div class="col-12 h4"style="font-family: 'Arial', monospace;"><b>${this.thisQRInfo.uniqueID}</b></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-7 d-flex align-items-center justify-content-left">
|
||||
<div class="row-fluid">
|
||||
<div class="col-12 h3"style="font-family: 'Verdana', monospace;"><b>${this.thisQRInfo.departmentName}</b></div>
|
||||
<div class="col-12 h4"style="font-family: 'Arial', monospace;"><b>${this.thisQRInfo.productShortName}</b></div>
|
||||
<div class="col-12 h4"style="font-family: 'Arial', monospace;"><b>${this.thisQRInfo.serialNumber??"-"}</b></div>
|
||||
<div class="col-12 h4"style="font-family: 'Arial', monospace;"><b>${this.thisQRInfo.partNumber}</b></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
// virtualElement.innerHTML = `
|
||||
// <div class="container-fluid my-3 QrPrintFont" style="font-family: 'OCR A', monospace;">
|
||||
// <div class="row" >
|
||||
// <div class="col-5 text-center d-flex align-items-center justify-content-center">
|
||||
// <div class="row">
|
||||
// <div class="col-12">
|
||||
// <div>${this.thisQRInfo.imgContainer}</div>
|
||||
// <div class="col-12 h4"style="font-family: 'Arial', monospace;"><b>${this.thisQRInfo.uniqueID}</b></div>
|
||||
// </div>
|
||||
// </div>
|
||||
// </div>
|
||||
// <div class="col-7 d-flex align-items-center justify-content-left">
|
||||
// <div class="row-fluid">
|
||||
// <div class="col-12 h3"style="font-family: 'Verdana', monospace;"><b>${this.thisQRInfo.departmentName}</b></div>
|
||||
// <div class="col-12 h4"style="font-family: 'Arial', monospace;"><b>${this.thisQRInfo.productShortName}</b></div>
|
||||
// <div class="col-12 h4"style="font-family: 'Arial', monospace;"><b>${this.thisQRInfo.serialNumber??"-"}</b></div>
|
||||
// <div class="col-12 h4"style="font-family: 'Arial', monospace;"><b>${this.thisQRInfo.partNumber}</b></div>
|
||||
// </div>
|
||||
// </div>
|
||||
// </div>
|
||||
// </div>
|
||||
// `;
|
||||
|
||||
// Append the virtual DOM to the body (temporarily)
|
||||
document.body.appendChild(virtualElement);
|
||||
// document.body.appendChild(virtualElement);
|
||||
|
||||
// Wait for the font to be loaded (important for custom fonts like OCR-A)
|
||||
document.fonts.load('1em "OCR A"').then(() => {
|
||||
// document.fonts.load('1em "OCR A"').then(() => {
|
||||
// Use html2canvas to convert the virtual DOM to an image
|
||||
html2canvas(virtualElement, {
|
||||
scale: 1, // Increase scale for sharper images
|
||||
}).then((canvas) => {
|
||||
// html2canvas(virtualElement, {
|
||||
// scale: 1, Increase scale for sharper images
|
||||
// }).then((canvas) => {
|
||||
// Convert the canvas to an image
|
||||
const imgData = canvas.toDataURL('image/png');
|
||||
// const imgData = canvas.toDataURL('image/png');
|
||||
// Open the image in a new tab for preview (optional)
|
||||
// const newWindow = window.open();
|
||||
// newWindow.location.href = imgData;
|
||||
// console.log(imgData)
|
||||
// Use printJS to print the image
|
||||
printJS({
|
||||
printable: imgData,
|
||||
type: 'image',
|
||||
css: '/../lib/bootstrap/dist/css/bootstrap.css',
|
||||
style: `
|
||||
@@media print {
|
||||
@@page {
|
||||
margin: 5px 5px 0px 5px;
|
||||
}
|
||||
body { margin: 0; }
|
||||
}
|
||||
`
|
||||
});
|
||||
// printJS({
|
||||
// printable: imgData,
|
||||
// type: 'image',
|
||||
// css: '/../lib/bootstrap/dist/css/bootstrap.css',
|
||||
// style: `
|
||||
// @@media print {
|
||||
// @@page {
|
||||
// margin: 5px 5px 0px 5px;
|
||||
// }
|
||||
// body { margin: 0; }
|
||||
// }
|
||||
// `
|
||||
// });
|
||||
|
||||
// Remove the virtual DOM from the body after use
|
||||
document.body.removeChild(virtualElement);
|
||||
}).catch((error) => {
|
||||
console.error("Error generating image:", error);
|
||||
// document.body.removeChild(virtualElement);
|
||||
// }).catch((error) => {
|
||||
// console.error("Error generating image:", error);
|
||||
// Remove the virtual DOM if an error occurs
|
||||
document.body.removeChild(virtualElement);
|
||||
});
|
||||
}).catch((error) => {
|
||||
console.error("Error loading font:", error);
|
||||
// document.body.removeChild(virtualElement);
|
||||
// });
|
||||
// }).catch((error) => {
|
||||
// console.error("Error loading font:", error);
|
||||
// Remove the virtual DOM if font loading fails
|
||||
document.body.removeChild(virtualElement);
|
||||
// document.body.removeChild(virtualElement);
|
||||
// });
|
||||
// },
|
||||
handleSorting() {
|
||||
this.renderTables();
|
||||
},
|
||||
renderTables() {
|
||||
if (this.sortBy === "logs") {
|
||||
// this.initAllTables();
|
||||
this.initiateTable();
|
||||
} else
|
||||
if (this.sortBy === "all") {
|
||||
this.initAllTables();
|
||||
// this.initiateTable();
|
||||
}
|
||||
},
|
||||
initAllTables() {
|
||||
if (this.itemMovementNotCompleteDatatable) {
|
||||
this.itemMovementNotCompleteDatatable.destroy();
|
||||
}
|
||||
if (this.itemMovementCompleteDatatable) {
|
||||
this.itemMovementCompleteDatatable.destroy();
|
||||
}
|
||||
|
||||
this.itemMovementNotCompleteDatatable = $("#itemMovementNotCompleteDatatable").DataTable({
|
||||
data: this.items.filter((m) => m.movementComplete == 0),
|
||||
columns: [
|
||||
{ title: "Unique Id", data: "id" },
|
||||
{ title: "Product Code", data: "uniqueID" },
|
||||
{ title: "From User", data: "toUserName" },
|
||||
{ title: "Last User", data: "lastUserName" },
|
||||
{ title: "From Station", data: "toStationName" },
|
||||
{ title: "From Store", data: "toStoreName" },
|
||||
{ title: "Action", data: "action" },
|
||||
{ title: "Start Status", data: "toOther" },
|
||||
{ title: "Product Category", data: "productCategory" },
|
||||
{ title: "Qty", data: "quantity" },
|
||||
{ title: "Send Date", data: "sendDate" },
|
||||
{
|
||||
title: "Note",
|
||||
data: "consignmentNote",
|
||||
render: function (data, type, full, meta) {
|
||||
if (!data) {
|
||||
return "No Document";
|
||||
}
|
||||
|
||||
// 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: "remark" },
|
||||
],
|
||||
order: [[0, "desc"]],
|
||||
responsive: true,
|
||||
});
|
||||
|
||||
this.itemMovementCompleteDatatable = $("#itemMovementCompleteDatatable").DataTable({
|
||||
data: this.items.filter((m) => m.movementComplete == 1),
|
||||
columns: [
|
||||
{ title: "Unique Id", data: "id" },
|
||||
{ title: "Product Code", data: "uniqueID" },
|
||||
{ title: "From User", data: "toUserName" },
|
||||
{ title: "Last User", data: "lastUserName" },
|
||||
{ title: "From Station", data: "toStationName" },
|
||||
{ title: "Last Station", data: "lastStationName" },
|
||||
{ title: "From Store", data: "toStoreName" },
|
||||
{ title: "Last Store", data: "lastStoreName" },
|
||||
{ title: "Action", data: "action" },
|
||||
{ title: "Start Status", data: "toOther" },
|
||||
{ title: "Latest Status", data: "latestStatus" },
|
||||
{ title: "Product Category", data: "productCategory" },
|
||||
{ title: "Qty", data: "quantity" },
|
||||
{ title: "Send Date", data: "sendDate" },
|
||||
{ title: "Receive Date", data: "receiveDate" },
|
||||
{ title: "Note",
|
||||
data: "consignmentNote",
|
||||
render: function (data, type, full, meta) {
|
||||
if (!data) {
|
||||
return "No Document";
|
||||
}
|
||||
|
||||
// Check if the document is an image based on file extension
|
||||
var isImage = /\.(jpeg|jpg|png|gif)$/i.test(data);
|
||||
var isPdf = /\.pdf$/i.test(data);
|
||||
|
||||
if (isImage) {
|
||||
return `<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: "remark" },
|
||||
],
|
||||
order: [[0, "desc"]],
|
||||
responsive: true,
|
||||
});
|
||||
},
|
||||
|
||||
toggleCategory(itemId) {
|
||||
this.categoryVisible[itemId] = !this.categoryVisible[itemId];
|
||||
},
|
||||
toggleHistory(itemId) {
|
||||
this.historyVisible[itemId] = !this.historyVisible[itemId];
|
||||
},
|
||||
toggleDetails(movementId) {
|
||||
this.detailsVisible[movementId] = !this.detailsVisible[movementId];
|
||||
},
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
@ -93,6 +93,68 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="approveModal" tabindex="-1" role="dialog" aria-labelledby="approveRequestModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered modal-xl" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="approveRequestModalLabel">Approve Request</h5>
|
||||
<button type="button" class="closeModal" data-dismiss="modal" aria-label="Close" v-on:click="showRequestModal=false">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="container-fluid">
|
||||
<form v-on:submit.prevent="approveRequest" data-aos="fade-right">
|
||||
@* <div class=" register" data-aos="fade-right"> *@
|
||||
<div data-aos="fade-right">
|
||||
<div class="row" data-aos="fade-right">
|
||||
|
||||
<div class="col-md-12">
|
||||
<div class="tab-content" id="myTabContent">
|
||||
<div class="tab-pane fade show active" id="home" role="tabpanel" aria-labelledby="home-tab">
|
||||
<h3 class="register-heading">APPROVE REQUEST</h3>
|
||||
<div class="row register-form">
|
||||
<div class="col-md-12">
|
||||
|
||||
<div class="form-group row">
|
||||
@* <label class="col-sm-4 col-form-label hidden-label">Request Id</label> *@
|
||||
<div class="col-sm-8">
|
||||
<div class="dropdown">
|
||||
<input type="text" id="currentRequestId" name="currentRequestId" v-model="currentRequestId" class="form-control" hidden />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label">Remark</label>
|
||||
<div class="col-sm-8">
|
||||
<div class="dropdown">
|
||||
<input type="text" id="approveremark" name="approveremark" v-model="approveremark" class="form-control" required />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Submit and Reset Buttons *@
|
||||
<div class="form-group row">
|
||||
<div class="col-sm-8 offset-sm-3">
|
||||
<button type="button" v-on:click="resetForm" class="btn btn-secondary m-1">Reset</button>
|
||||
<button type="submit" class="btn btn-primary m-1 submit-button">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section Scripts {
|
||||
@ -115,6 +177,7 @@
|
||||
$('.submit-button').on('click', function () {
|
||||
// Show the modal
|
||||
$('#rejectModal').modal('hide');
|
||||
$('#approveModal').modal('hide');
|
||||
});
|
||||
});
|
||||
const app = Vue.createApp({
|
||||
@ -139,6 +202,7 @@
|
||||
selectedCategory: "",
|
||||
showRequestModal: false,
|
||||
showRejectModal: false,
|
||||
showApproveModal: false,
|
||||
loading: false,
|
||||
request: [],
|
||||
currentUser: null,
|
||||
@ -447,7 +511,7 @@
|
||||
|
||||
$('#requestDatatable tbody').on('click', '.approve-btn', function () {
|
||||
const requestId = $(this).data('id');
|
||||
self.approveRequest(requestId);
|
||||
self.approveRequestModal(requestId);
|
||||
});
|
||||
|
||||
$('#requestDatatable tbody').on('click', '.print-btn', function () {
|
||||
@ -665,16 +729,25 @@
|
||||
this.EndWDate = null;
|
||||
}
|
||||
},
|
||||
async approveRequest(itemId) {
|
||||
async approveRequest() {
|
||||
// if (!confirm("Are you sure you want to approve this request?")) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
const formData = {
|
||||
RemarkMasterInv: this.rejectremark,
|
||||
|
||||
};
|
||||
|
||||
let requestId = this.currentRequestId;
|
||||
try {
|
||||
const response = await fetch(`/InvMainAPI/ApproveRequest/${itemId}`, {
|
||||
const response = await fetch(`/InvMainAPI/ApproveRequest/${requestId}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(formData)
|
||||
|
||||
});
|
||||
const result = await response.json();
|
||||
|
||||
@ -682,7 +755,7 @@
|
||||
alert(result.message);
|
||||
|
||||
//static update
|
||||
const row = $(`.approve-btn[data-id="${itemId}"]`).closest('tr');
|
||||
const row = $(`.approve-btn[data-id="${requestId}"]`).closest('tr');
|
||||
let rowData = this.requestDatatable.row(row).data();
|
||||
|
||||
// Update the status and remark
|
||||
@ -769,6 +842,16 @@
|
||||
$(`#rejectModal`).modal('show');
|
||||
|
||||
|
||||
},
|
||||
async approveRequestModal(requestId, remark) {
|
||||
|
||||
this.currentRequestId = requestId;
|
||||
this.approveremark = remark;
|
||||
|
||||
|
||||
$(`#approveModal`).modal('show');
|
||||
|
||||
|
||||
},
|
||||
async printItem(itemId, imgSrc) {
|
||||
try {
|
||||
|
||||
@ -16,32 +16,51 @@
|
||||
display: block !important;
|
||||
}
|
||||
</style>
|
||||
@await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml");
|
||||
<div id="registerItem" class="row">
|
||||
@await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml")
|
||||
<div id="registerItemMovement" class="row">
|
||||
<div class="row card">
|
||||
<div v-if="thisItem" class="card-header">
|
||||
<button v-on:click="resetScanner" class="btn btn-secondary">
|
||||
<i class="fas fa-arrow-left"></i> Back to Scanner
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<div data-aos="fade-right"></div>
|
||||
<div id="app" data-aos="fade-right">
|
||||
<div v-if="thisItem == null">
|
||||
<h1 data-aos="fade-right">QR & Barcode Scanner</h1>
|
||||
<div id="reader" data-aos="fade-right"></div>
|
||||
|
||||
<select class="form-select" v-if="!thisItem" v-model="selectedCameraId" v-on:change="updateCamera">
|
||||
<option v-for="device in videoInputDevices" :key="device.deviceId" :value="device.deviceId">
|
||||
{{ device.label || `Camera ${videoInputDevices.indexOf(device) + 1}` }}
|
||||
</option>
|
||||
</select>
|
||||
|
||||
<div id="registerItemMovement" v-if="!thisItem" data-aos="fade-right">
|
||||
<p style="text-align:center; padding:10px;">Scan QR Code Here:</p>
|
||||
<qrcode-stream :constraints="selectedConstraints"
|
||||
:formats="['qr_code']"
|
||||
:track="trackFunctionSelected.value"
|
||||
v-on:camera-on="onCameraReady"
|
||||
v-on:detect="onDecode"
|
||||
v-on:error="onError">
|
||||
</qrcode-stream>
|
||||
|
||||
<p class="error">{{ error }}</p>
|
||||
</div>
|
||||
|
||||
<div v-if="thisItem" id="qrCodeResult" style="text-align: center; margin: 20px 0; padding: 20px;">
|
||||
<h2>Scan Result:</h2>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div v-if="thisItem" style="display: flex; justify-content: center; align-items: center;">
|
||||
<div class="col-lg-7 col-11 border rounded p-3 shadow-sm">
|
||||
|
||||
<div class="row m-3 d-flex align-items-center justify-content-center">
|
||||
<div class="col-lg-7 col-11 border rounded p-3 shadow-sm">
|
||||
<div class="col-12 text-center">
|
||||
<img :src="thisItem.imageProduct" alt="Product Image" class="img-fluid rounded" data-toggle="modal" data-target="#imageModal" style="max-height: 300px;" />
|
||||
</div>
|
||||
<div class="col-12 text-center mt-3">
|
||||
<p class="h4 fw-bold text-primary">{{ thisItem.uniqueID }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Item Name -->
|
||||
<div class="col-12 mb-3">
|
||||
<p class="h5 fw-bold">
|
||||
@ -89,7 +108,7 @@
|
||||
<i class="fas fa-user me-2 text-secondary"></i>User:
|
||||
</span>
|
||||
<span class="text-muted text-end" style="max-width: 70%; word-wrap: break-word;">
|
||||
{{ thisItem.currentUser }}
|
||||
{{ thisItem.toUserName }}
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
@ -97,9 +116,9 @@
|
||||
<!-- Store -->
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<span class="fw-bold">
|
||||
<i class="fas fa-store me-2 text-secondary"></i>Store:
|
||||
<i class="mdi mdi-factory me-2 text-secondary"></i>Store:
|
||||
</span>
|
||||
<span class="text-muted">{{ thisItem.currentStore }}</span>
|
||||
<span class="text-muted">{{ thisItem.toStoreName }}</span>
|
||||
</li>
|
||||
|
||||
<!-- Station -->
|
||||
@ -107,7 +126,7 @@
|
||||
<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>
|
||||
<span class="text-muted">{{ thisItem.toStationName || 'N/A' }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@ -224,6 +243,7 @@
|
||||
@* <option class="btn-light" value="supplier" v-if="itemlateststatus != 'Delivered'">Assign to Supplier</option> *@
|
||||
@* <option class="btn-light" value="faulty" v-if="itemlateststatus != 'Delivered'">Faulty</option> *@
|
||||
<option class="btn-light" value="user">Assign to User</option>
|
||||
<option class="btn-light" value="station">Assign to Station</option>
|
||||
<option class="btn-light" value="store">Assign to Store</option>
|
||||
<option class="btn-light" value="supplier">Assign to Supplier</option>
|
||||
<option class="btn-light" value="faulty">Faulty</option>
|
||||
@ -267,6 +287,83 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label">Consignment Note</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="file" id="document" name="document" class="form-control-file" v-on:change="handleFileUpload" accept="image/png, image/jpeg, application/pdf" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label">Remark:</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" id="remark" name="remark" v-model="remark" class="form-control" required />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@* Submit and Reset Buttons *@
|
||||
<div class="form-group row">
|
||||
<div class="col-sm-8 offset-sm-3">
|
||||
<button type="button" v-on:click="resetForm" class="btn btn-secondary m-1">Reset</button>
|
||||
<button type="submit" class="btn btn-primary m-1">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div v-if="selectedAction === 'station'">
|
||||
|
||||
<div class="row register-form">
|
||||
<div class="col-md-3"></div>
|
||||
<div class="col-md-6">
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label">To Station:</label>
|
||||
<div class="col-sm-8">
|
||||
<div class="dropdown">
|
||||
<select class="btn btn-primary dropdown-toggle col-md-10" v-model="selectedStation" v-on:change="handleSelection" required style="width: 100%;">
|
||||
<option class="btn-light" value="" disabled selected>Select Station</option>
|
||||
<option class="btn-light" v-for="(station, index) in stationlist" :key="index" :value="station.stationId">{{station.stationName}}</option>
|
||||
</select>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label">To PIC:</label>
|
||||
<div class="col-sm-8">
|
||||
<div class="dropdown">
|
||||
<input type="text" id="selectedStationPIC" name="selectedStationPIC" v-model="selectedStationPIC" class="form-control" readonly />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="invoiceDate" class="col-sm-4">Assign Date:</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="date" id="assigndate" name="assigndate" class="form-control" v-model="assigndate">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label">Consignment Note</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="file" id="document" name="document" class="form-control-file" v-on:change="handleFileUpload" accept="image/png, image/jpeg, application/pdf" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label">Remark:</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" id="remark" name="remark" v-model="remark" class="form-control" required />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@ -305,7 +402,20 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label">Consignment Note</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="file" id="document" name="document" class="form-control-file" v-on:change="handleFileUpload" accept="image/png, image/jpeg, application/pdf" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label">Remark:</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="text" id="remark" name="remark" v-model="remark" class="form-control" required />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* Submit and Reset Buttons *@
|
||||
@ -357,6 +467,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label">Consignment Note</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="file" id="document" name="document" class="form-control-file" v-on:change="handleFileUpload" accept="image/png, image/jpeg, application/pdf" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label">Remark:</label>
|
||||
<div class="col-sm-8">
|
||||
@ -438,12 +555,11 @@
|
||||
await Html.RenderPartialAsync("_ValidationScriptsPartial");
|
||||
}
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/html5-qrcode/minified/html5-qrcode.min.js"></script>
|
||||
|
||||
<script src="~/js/vue-qrcode-reader.umd.js"></script>
|
||||
|
||||
<script>
|
||||
$(function () {
|
||||
app.mount('#registerItem');
|
||||
|
||||
|
||||
// Attach a click event listener to elements with the class 'btn-success'.
|
||||
$('#addItemBtn').on('click', function () {
|
||||
@ -460,12 +576,15 @@
|
||||
return {
|
||||
thisItem: null,
|
||||
qrCodeResult: null,
|
||||
html5QrCodeScanner: null,
|
||||
|
||||
debounceTimeout: null,
|
||||
userlist: null,
|
||||
stationlist: null,
|
||||
storelist: null,
|
||||
supplierlist: null,
|
||||
selectedUser: "",
|
||||
selectedStation: "",
|
||||
selectedStationPIC: "",
|
||||
selectedStore: "",
|
||||
selectedAction: "",
|
||||
assigndate: null,
|
||||
@ -489,15 +608,43 @@
|
||||
currentUser: null,
|
||||
currentUserCompanyDept: null,
|
||||
itemlateststatus: "",
|
||||
|
||||
//QR VARIABLE
|
||||
qrCodeResult: null,
|
||||
debounceTimeout: null,
|
||||
error: "",
|
||||
selectedConstraints: { facingMode: "environment" },
|
||||
trackFunctionSelected: { text: 'outline', value: null },
|
||||
barcodeFormats: {
|
||||
qr_code: true, // Hanya mendukung QR Code
|
||||
code_128: true,
|
||||
ean_13: true
|
||||
},
|
||||
constraintOptions: [
|
||||
{ label: "Rear Camera", constraints: { facingMode: "environment" } },
|
||||
{ label: "Front Camera", constraints: { facingMode: "user" } }
|
||||
],
|
||||
videoInputDevices: [],
|
||||
selectedCameraId: null,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.fetchUser();
|
||||
this.fetchSuppliers();
|
||||
this.startScanner();
|
||||
this.fetchUsers();
|
||||
this.fetchStores();
|
||||
//this.fetchItem('ARA00500008'); // for testing only. clear this
|
||||
this.fetchStations();
|
||||
this.trackFunctionSelected.value = this.paintOutline;
|
||||
},
|
||||
watch: {
|
||||
selectedStation(newStationId) {
|
||||
console.log(newStationId);
|
||||
console.log(this.selectedStation);
|
||||
// Find the station object that matches the selectedStation id
|
||||
const selectedStationObj = this.stationlist.find(station => station.stationId === newStationId);
|
||||
// Set the selectedPIC based on the stationPIC
|
||||
this.selectedStationPIC = selectedStationObj ? selectedStationObj.stationPicID : "";
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
filteredDepartments() {
|
||||
@ -520,10 +667,86 @@
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
|
||||
// handleSelection(event) {
|
||||
// console.log("Event Target Value:", event.target.value); Debugging
|
||||
// const selectedstationid = event.target.value;
|
||||
// console.log(this.stationlist);
|
||||
// const selectedStationObj = this.stationlist.find(station => station.stationId == selectedstationid);
|
||||
// Set the selectedPIC based on the stationPIC
|
||||
// this.selectedStationPIC = selectedStationObj ? selectedStationObj.stationPicID : "";
|
||||
// },
|
||||
// Split Url dapatkan unique ID Je
|
||||
onDecode(detectedCodes) {
|
||||
if (detectedCodes.length > 0) {
|
||||
this.qrCodeResult = detectedCodes[0].rawValue; // Ambil URL dari rawValue
|
||||
this.UniqueID = this.qrCodeResult.split('/').pop(); // Ambil UniqueID dari URL
|
||||
this.fetchItem(this.UniqueID);
|
||||
}
|
||||
},
|
||||
|
||||
//Showing Qr Error
|
||||
onError(err) {
|
||||
let message = `[${err.name}]: `;
|
||||
if (err.name === "NotAllowedError") {
|
||||
message += "You have to allow camera accecss.";
|
||||
} else if (err.name === "NotFoundError") {
|
||||
message += "There's no camera detect.";
|
||||
} else if (err.name === "NotReadableError") {
|
||||
message += "You are using camera on the other application.";
|
||||
} else {
|
||||
message += err.message;
|
||||
}
|
||||
this.error = message;
|
||||
},
|
||||
|
||||
//Setting Camera
|
||||
async onCameraReady() {
|
||||
try {
|
||||
const devices = await navigator.mediaDevices.enumerateDevices();
|
||||
this.videoInputDevices = devices.filter(device => device.kind === 'videoinput');
|
||||
|
||||
if (this.videoInputDevices.length > 0) {
|
||||
// Keep the selected camera if already chosen
|
||||
if (!this.selectedCameraId) {
|
||||
this.selectedCameraId = this.videoInputDevices[0].deviceId;
|
||||
}
|
||||
|
||||
this.selectedConstraints = { deviceId: { exact: this.selectedCameraId } };
|
||||
} else {
|
||||
this.error = "No camera detected.";
|
||||
}
|
||||
} catch (err) {
|
||||
this.error = "Error accessing camera: " + err.message;
|
||||
}
|
||||
},
|
||||
|
||||
//Update Camera Category
|
||||
updateCamera() {
|
||||
this.selectedConstraints = { deviceId: { exact: this.selectedCameraId } };
|
||||
},
|
||||
|
||||
//Red box if QR Detect
|
||||
paintOutline(detectedCodes, ctx) {
|
||||
for (const detectedCode of detectedCodes) {
|
||||
const [firstPoint, ...otherPoints] = detectedCode.cornerPoints;
|
||||
|
||||
ctx.strokeStyle = 'red'; // Warna garis merah
|
||||
ctx.lineWidth = 3;
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(firstPoint.x, firstPoint.y);
|
||||
for (const { x, y } of otherPoints) {
|
||||
ctx.lineTo(x, y);
|
||||
}
|
||||
ctx.lineTo(firstPoint.x, firstPoint.y);
|
||||
ctx.closePath();
|
||||
ctx.stroke();
|
||||
}
|
||||
},
|
||||
resetScanner(){
|
||||
this.thisItem = null;
|
||||
this.resetForm();
|
||||
this.startScanner();
|
||||
},
|
||||
handleFileUpload(event) {
|
||||
const file = event.target.files[0];
|
||||
@ -547,10 +770,11 @@
|
||||
const now = new Date();
|
||||
const formData = {
|
||||
|
||||
...(this.selectedAction === 'user' ? { toUser: this.currentUser.id, toOther: 'On Delivery', SendDate: this.assigndate, lastUser: this.selectedUser, MovementComplete: false,} : {}),
|
||||
...(this.selectedAction === 'store' ? { toUser: this.currentUser.id, toOther: 'On Delivery', SendDate: this.assigndate, lastUser: this.selectedStore, MovementComplete: false, ItemId: this.thisItem.itemID, Action: 'Stock Out', Quantity: 1,} : {}),
|
||||
...(this.selectedAction === 'supplier' ? { toUser: this.currentUser.id, toOther: this.selectedOther, SendDate: this.assigndate, Remark: this.remark + '. Item sent to ' + this.selectedSupplier + ' for ' + this.selectedOther,lastUser: this.currentUser.id, MovementComplete: false, ItemId: this.thisItem.itemID, Action: 'Stock Out', Quantity: 1, } : {}),
|
||||
...(this.selectedAction === 'faulty' ? { 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, Action: 'Stock Out', Quantity: 1,} : {}),
|
||||
...(this.selectedAction === 'user' ? { toUser: this.currentUser.id, toOther: 'On Delivery', SendDate: this.assigndate, lastUser: this.selectedUser, MovementComplete: false, Remark: this.remark, ConsignmentNote: this.document} : {}),
|
||||
...(this.selectedAction === 'station' ? { toStation: this.selectedStation, toUser: this.currentUser.id, toOther: 'On Delivery', SendDate: this.assigndate, lastUser: this.selectedUser, MovementComplete: false, Remark: this.remark, ConsignmentNote: this.document} : {}),
|
||||
...(this.selectedAction === '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' ? { 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' ? { 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,
|
||||
Action: 'Stock Out',
|
||||
@ -649,60 +873,6 @@
|
||||
}
|
||||
|
||||
},
|
||||
startScanner() {
|
||||
const config = {
|
||||
fps: 60,
|
||||
qrbox: 400
|
||||
};
|
||||
|
||||
// navigator.mediaDevices.getUserMedia({
|
||||
// video: {
|
||||
// width: { ideal: 1920 }, Higher resolution
|
||||
// height: { ideal: 1080 },
|
||||
// }
|
||||
// })
|
||||
|
||||
// .catch((err) => {
|
||||
// console.error("Error accessing camera:", err);
|
||||
// });
|
||||
|
||||
// this.html5QrCodeScanner = new Html5QrcodeScanner(
|
||||
// "reader", config, false
|
||||
// );
|
||||
|
||||
// this.html5QrCodeScanner.render(
|
||||
// (decodedText, decodedResult) => {
|
||||
// if (!this.debounceTimeout) {
|
||||
// this.debounceTimeout = setTimeout(() => {
|
||||
// this.qrCodeResult = decodedText;
|
||||
// this.sendDataToBackend(decodedText);
|
||||
// this.fetchItem(decodedText.split('/').pop());
|
||||
// this.fetchItem('ARA00500008'); for testing only. clear
|
||||
// this.debounceTimeout = null;
|
||||
// }, this.debounceTime);
|
||||
// }
|
||||
// }
|
||||
// );
|
||||
|
||||
|
||||
navigator.mediaDevices.getUserMedia({ video: true })
|
||||
.then(() => {
|
||||
this.html5QrCodeScanner = new Html5QrcodeScanner("reader", config, false);
|
||||
this.html5QrCodeScanner.render((decodedText) => {
|
||||
if (!this.debounceTimeout) {
|
||||
this.debounceTimeout = setTimeout(() => {
|
||||
this.qrCodeResult = decodedText;
|
||||
// this.UniqueID = decodedText.split('/').pop();
|
||||
this.fetchItem(decodedText.split('/').pop());
|
||||
this.debounceTimeout = null;
|
||||
}, this.debounceTime);
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("Error accessing camera:", err);
|
||||
});
|
||||
},
|
||||
async fetchItem(itemid) {
|
||||
try {
|
||||
const response = await fetch('/InvMainAPI/GetItem/' + itemid, {
|
||||
@ -804,6 +974,29 @@
|
||||
this.userlist = await response.json();
|
||||
|
||||
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Error fetching item:', error);
|
||||
}
|
||||
},
|
||||
async fetchStations() {
|
||||
try {
|
||||
// const token = localStorage.getItem('token'); // Get the token from localStorage
|
||||
const response = await fetch('/InvMainAPI/StationList', {
|
||||
method: 'POST', // Specify the HTTP method
|
||||
headers: {
|
||||
'Content-Type': 'application/json', // Set content type
|
||||
// 'Authorization': `Bearer ${token}` // Include the token in the headers
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch item');
|
||||
}
|
||||
this.stationlist = await response.json();
|
||||
console.log(this.stationlist);
|
||||
|
||||
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Error fetching item:', error);
|
||||
@ -834,6 +1027,10 @@
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
app.component("qrcode-stream", VueQrcodeReader.QrcodeStream);
|
||||
|
||||
app.mount('#registerItemMovement');
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
@ -590,6 +590,7 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
||||
i.ToUser,
|
||||
UniqueID = i.Item?.UniqueID,
|
||||
ProductName = i.Item?.Product?.ProductName,
|
||||
ProductCategory = i.Item?.Product?.Category,
|
||||
LastUserName = i.FromUser?.FullName,
|
||||
LastStoreName = i.FromStore?.StoreName,
|
||||
LastStationName = i.FromStation?.StationName,
|
||||
@ -980,7 +981,7 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
||||
}
|
||||
|
||||
[HttpPost("ApproveRequest/{id}")]
|
||||
public async Task<IActionResult> ApproveRequest(int id)
|
||||
public async Task<IActionResult> ApproveRequest(int id, [FromBody] RequestModel request)
|
||||
{
|
||||
var Request = await _centralDbContext.Requests.FindAsync(id);
|
||||
if (Request == null)
|
||||
@ -989,6 +990,7 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
||||
}
|
||||
|
||||
Request.status = "Approved";
|
||||
Request.remarkMasterInv = request.remarkMasterInv;
|
||||
Request.approvalDate = DateTime.UtcNow;
|
||||
_centralDbContext.SaveChanges();
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 78 KiB |
Loading…
Reference in New Issue
Block a user