update inventory
This commit is contained in:
parent
d671db342a
commit
1922f78cef
@ -47,4 +47,12 @@ namespace PSTW_CentralSystem.Areas.Inventory.Models
|
|||||||
public virtual ItemMovementModel? Movement { get; set; }
|
public virtual ItemMovementModel? Movement { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ItemQuantityUpdateModel
|
||||||
|
{
|
||||||
|
public int ItemId { get; set; }
|
||||||
|
public int Quantity { get; set; }
|
||||||
|
public int MovementId { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,4 +45,10 @@ namespace PSTW_CentralSystem.Areas.Inventory.Models
|
|||||||
[ForeignKey("LastUser")]
|
[ForeignKey("LastUser")]
|
||||||
public virtual UserModel? FromUser { get; set; }
|
public virtual UserModel? FromUser { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ItemStatusUpdateModel
|
||||||
|
{
|
||||||
|
public int ItemId { get; set; }
|
||||||
|
public int Status { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
ViewData["Title"] = "QR Scanner";
|
ViewData["Title"] = "QR Scanner";
|
||||||
Layout = "~/Views/Shared/_Layout.cshtml";
|
Layout = "~/Views/Shared/_Layout.cshtml";
|
||||||
}
|
}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@@font-face {
|
@@font-face {
|
||||||
font-family: 'OCR-A';
|
font-family: 'OCR-A';
|
||||||
@ -16,7 +17,9 @@
|
|||||||
display: block !important;
|
display: block !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
@await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml")
|
@await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartial.cshtml")
|
||||||
|
|
||||||
<div id="registerItemMovement" class="row">
|
<div id="registerItemMovement" class="row">
|
||||||
<div class="row card">
|
<div class="row card">
|
||||||
<div v-if="thisItem" class="card-header">
|
<div v-if="thisItem" class="card-header">
|
||||||
@ -63,7 +66,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Item Name -->
|
|
||||||
<div class="col-12 mb-3">
|
<div class="col-12 mb-3">
|
||||||
<p class="h5 fw-bold">
|
<p class="h5 fw-bold">
|
||||||
<i class="fas fa-tag me-2 text-secondary"></i>Item Name:
|
<i class="fas fa-tag me-2 text-secondary"></i>Item Name:
|
||||||
@ -71,7 +73,6 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Part Number -->
|
|
||||||
<div class="col-12 mb-3">
|
<div class="col-12 mb-3">
|
||||||
<p class="h5 fw-bold">
|
<p class="h5 fw-bold">
|
||||||
<i class="fas fa-barcode me-2 text-secondary"></i>Part Number:
|
<i class="fas fa-barcode me-2 text-secondary"></i>Part Number:
|
||||||
@ -79,7 +80,6 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Serial Number -->
|
|
||||||
<div class="col-12 mb-3">
|
<div class="col-12 mb-3">
|
||||||
<p class="h5 fw-bold">
|
<p class="h5 fw-bold">
|
||||||
<i class="fas fa-hashtag me-2 text-secondary"></i>Serial Number:
|
<i class="fas fa-hashtag me-2 text-secondary"></i>Serial Number:
|
||||||
@ -87,7 +87,6 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- PIC -->
|
|
||||||
<div class="col-12 mb-3">
|
<div class="col-12 mb-3">
|
||||||
<p class="h5 fw-bold">
|
<p class="h5 fw-bold">
|
||||||
<i class="fas fa-user-tie me-2 text-secondary"></i>PIC:
|
<i class="fas fa-user-tie me-2 text-secondary"></i>PIC:
|
||||||
@ -95,7 +94,6 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Current Information Card -->
|
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="card shadow-sm border-0">
|
<div class="card shadow-sm border-0">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -103,7 +101,6 @@
|
|||||||
<i class="fas fa-info-circle me-2"></i>Current Information
|
<i class="fas fa-info-circle me-2"></i>Current Information
|
||||||
</h5>
|
</h5>
|
||||||
<ul class="list-group list-group-flush">
|
<ul class="list-group list-group-flush">
|
||||||
<!-- User -->
|
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<div class="d-flex justify-content-between align-items-start">
|
<div class="d-flex justify-content-between align-items-start">
|
||||||
<span class="fw-bold">
|
<span class="fw-bold">
|
||||||
@ -115,7 +112,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<!-- Store -->
|
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
<span class="fw-bold">
|
<span class="fw-bold">
|
||||||
<i class="mdi mdi-factory me-2 text-secondary"></i>Store:
|
<i class="mdi mdi-factory me-2 text-secondary"></i>Store:
|
||||||
@ -123,7 +119,6 @@
|
|||||||
<span class="text-muted">{{ thisItem.toStoreName }}</span>
|
<span class="text-muted">{{ thisItem.toStoreName }}</span>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<!-- Station -->
|
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
<span class="fw-bold">
|
<span class="fw-bold">
|
||||||
<i class="fas fa-map-marker-alt me-2 text-secondary"></i>Station:
|
<i class="fas fa-map-marker-alt me-2 text-secondary"></i>Station:
|
||||||
@ -145,24 +140,29 @@
|
|||||||
<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 && !isCancelled">
|
<div v-if="itemlateststatus == 'On Delivery'">
|
||||||
<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">
|
||||||
<form v-on:submit.prevent="receiveItemMovement" data-aos="fade-right">
|
</div>
|
||||||
<div class="row register-form">
|
</div>
|
||||||
|
|
||||||
|
<div v-if="itemlateststatus == 'On Delivery' && this.thisItem.toUser == this.currentUser.id">
|
||||||
|
<h3 class="register-heading">Cancel Item Movement</h3>
|
||||||
|
<div class="col-sm-3"></div>
|
||||||
|
<div class="col-sm-6 offset-sm-3">
|
||||||
|
<form v-on:submit.prevent="confirmCancelItemMovement" data-aos="fade-right">
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label class="col-sm-4 col-form-label">Remark:</label>
|
<label class="col-sm-4 col-form-label">Reason for Cancellation:</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<input type="text" id="remark" name="remark" v-model="remark" class="form-control" required />
|
<input type="text" id="cancelRemark" name="cancelRemark" v-model="cancelRemark" class="form-control" required />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="display: flex; justify-content: center; margin-top: 20px;">
|
<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;">
|
<button type="submit" class="btn btn-danger" style="width: 200px; padding: 10px; font-size: 16px;">
|
||||||
Cancel Item Movement
|
Confirm Cancel Movement
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -225,22 +225,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@* <div v-if=""> *@
|
|
||||||
@* <h2 class="register-heading">Item is not assigned to user to make movement</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 *@
|
|
||||||
@* </button> *@
|
|
||||||
@* </div> *@
|
|
||||||
@* </div> *@
|
|
||||||
@* </form> *@
|
|
||||||
@* </div> *@
|
|
||||||
@* </div> *@
|
|
||||||
|
|
||||||
<div v-if="itemlateststatus == 'Faulty' && this.itemassignedtouser">
|
<div v-if="itemlateststatus == 'Faulty' && this.itemassignedtouser">
|
||||||
<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>
|
||||||
@ -255,7 +239,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="isCancelled || (itemlateststatus == 'Ready To Deploy' && this.itemassignedtouser)">
|
<div v-if="itemlateststatus == 'Ready To Deploy' && this.itemassignedtouser">
|
||||||
<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">
|
||||||
@ -271,6 +255,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label class="col-sm-3 col-form-label"></label>
|
<label class="col-sm-3 col-form-label"></label>
|
||||||
@ -299,6 +284,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group row" v-if="thisItem && thisItem.category === 'Disposable'">
|
||||||
|
<label class="col-sm-4 col-form-label">Quantity:</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<input type="number" id="quantity" name="quantity" v-model.number="quantity" class="form-control" min="1" :max="maxQuantity" required />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label for="invoiceDate" class="col-sm-4">Assign Date:</label>
|
<label for="invoiceDate" class="col-sm-4">Assign Date:</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
@ -348,7 +339,6 @@
|
|||||||
<option class="btn-light" v-for="(station, index) in stationlist" :key="index" :value="station.stationId">{{station.stationName}}</option>
|
<option class="btn-light" v-for="(station, index) in stationlist" :key="index" :value="station.stationId">{{station.stationName}}</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -363,6 +353,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group row" v-if="thisItem && thisItem.category === 'Disposable'">
|
||||||
|
<label class="col-sm-4 col-form-label">Quantity:</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<input type="number" id="quantity" name="quantity" v-model.number="quantity" class="form-control" min="1" :max="maxQuantity" required />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label for="invoiceDate" class="col-sm-4">Assign Date:</label>
|
<label for="invoiceDate" class="col-sm-4">Assign Date:</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
@ -421,6 +417,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group row" v-if="thisItem && thisItem.category === 'Disposable'">
|
||||||
|
<label class="col-sm-4 col-form-label">Quantity:</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<input type="number" id="quantity" name="quantity" v-model.number="quantity" class="form-control" min="1" :max="maxQuantity" required />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label class="col-sm-4 col-form-label">Consignment Note</label>
|
<label class="col-sm-4 col-form-label">Consignment Note</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
@ -435,6 +437,7 @@
|
|||||||
<input type="text" id="remark" name="remark" v-model="remark" class="form-control" required />
|
<input type="text" id="remark" name="remark" v-model="remark" class="form-control" required />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@* Submit and Reset Buttons *@
|
@* Submit and Reset Buttons *@
|
||||||
@ -479,6 +482,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group row" v-if="thisItem && thisItem.category === 'Disposable'">
|
||||||
|
<label class="col-sm-4 col-form-label">Quantity:</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<input type="number" id="quantity" name="quantity" v-model.number="quantity" class="form-control" min="1" :max="maxQuantity" required />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label for="invoiceDate" class="col-sm-4">Assign Date:</label>
|
<label for="invoiceDate" class="col-sm-4">Assign Date:</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
@ -526,6 +535,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group row" v-if="thisItem && thisItem.category === 'Disposable'">
|
||||||
|
<label class="col-sm-4 col-form-label">Quantity:</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<input type="number" id="quantity" name="quantity" v-model.number="quantity" class="form-control" min="1" :max="maxQuantity" required />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label class="col-sm-4 col-form-label">Remark:</label>
|
<label class="col-sm-4 col-form-label">Remark:</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
@ -544,6 +559,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@ -551,18 +567,6 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
@* <div v-if="selectedAction === 'receive'"> *@
|
|
||||||
@* <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 *@
|
|
||||||
@* </button> *@
|
|
||||||
@* </div> *@
|
|
||||||
@* </div> *@
|
|
||||||
@* </form> *@
|
|
||||||
@* </div> *@
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -577,8 +581,8 @@
|
|||||||
<script src="~/js/vue-qrcode-reader.umd.js"></script>
|
<script src="~/js/vue-qrcode-reader.umd.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
$(function () {
|
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
|
||||||
// Attach a click event listener to elements with the class 'btn-success'.
|
// Attach a click event listener to elements with the class 'btn-success'.
|
||||||
$('#addItemBtn').on('click', function () {
|
$('#addItemBtn').on('click', function () {
|
||||||
@ -610,10 +614,13 @@
|
|||||||
selectedOther: "",
|
selectedOther: "",
|
||||||
remark: "",
|
remark: "",
|
||||||
document: null,
|
document: null,
|
||||||
|
cancelRemark: "",
|
||||||
currentUser: null,
|
currentUser: null,
|
||||||
currentUserCompanyDept: null,
|
currentUserCompanyDept: null,
|
||||||
itemlateststatus: "",
|
itemlateststatus: "",
|
||||||
isCancelled: false,
|
quantity: 1,
|
||||||
|
maxQuantity: null,
|
||||||
|
|
||||||
|
|
||||||
//QR VARIABLE
|
//QR VARIABLE
|
||||||
qrCodeResult: null,
|
qrCodeResult: null,
|
||||||
@ -652,25 +659,26 @@
|
|||||||
// Set the selectedPIC based on the stationPIC
|
// Set the selectedPIC based on the stationPIC
|
||||||
this.selectedStationPIC = selectedStationObj ? selectedStationObj.stationPicID : "";
|
this.selectedStationPIC = selectedStationObj ? selectedStationObj.stationPicID : "";
|
||||||
// this.selectedStationPIC = selectedStationObj ? selectedStationObj : null;
|
// this.selectedStationPIC = selectedStationObj ? selectedStationObj : null;
|
||||||
|
},
|
||||||
|
// Watch for changes in `thisItem` to reset `quantity` when a new item is scanned
|
||||||
|
thisItem: {
|
||||||
|
handler(newItem) {
|
||||||
|
if (newItem && newItem.category === 'Disposable') {
|
||||||
|
this.quantity = 1; // Reset to 1 or default quantity when a disposable item is scanned
|
||||||
|
this.maxQuantity = newItem.quantity; // Set maxQuantity for disposable items
|
||||||
|
} else {
|
||||||
|
this.quantity = 1; // Ensure it's 1 for non-disposable items
|
||||||
|
this.maxQuantity = null; // Clear maxQuantity for non-disposable items
|
||||||
|
}
|
||||||
|
},
|
||||||
|
immediate: true // Run the handler immediately when the component is mounted
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
selectedStationPicName() {
|
selectedStationPicName() {
|
||||||
const selectedStationObj = this.stationlist.find(
|
const selectedStationObj = this.stationlist.find(station => station.stationId === this.selectedStation);
|
||||||
station => station.stationId === this.selectedStation
|
return selectedStationObj?.stationPic?.fullName || "";
|
||||||
);
|
|
||||||
|
|
||||||
if (
|
|
||||||
selectedStationObj &&
|
|
||||||
selectedStationObj.stationPic &&
|
|
||||||
selectedStationObj.stationPic.fullName
|
|
||||||
) {
|
|
||||||
return selectedStationObj.stationPic.fullName;
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
},
|
},
|
||||||
|
|
||||||
filteredDepartments() {
|
filteredDepartments() {
|
||||||
if (!this.selectedCompany) {
|
if (!this.selectedCompany) {
|
||||||
return []; // No company selected, return empty list
|
return []; // No company selected, return empty list
|
||||||
@ -735,6 +743,7 @@
|
|||||||
|
|
||||||
if (capabilities.sharpness) {
|
if (capabilities.sharpness) {
|
||||||
|
|
||||||
|
|
||||||
// Step 1: Apply resolution constraints first
|
// Step 1: Apply resolution constraints first
|
||||||
track.applyConstraints({
|
track.applyConstraints({
|
||||||
advanced: [{ width: 1280, height: 720 }]
|
advanced: [{ width: 1280, height: 720 }]
|
||||||
@ -746,6 +755,7 @@
|
|||||||
}).then(() => {
|
}).then(() => {
|
||||||
// console.log("✅ Sharpness applied")
|
// console.log("✅ Sharpness applied")
|
||||||
|
|
||||||
|
|
||||||
return track.applyConstraints({ advanced: [{ exposureMode: 'continuous' }] });
|
return track.applyConstraints({ advanced: [{ exposureMode: 'continuous' }] });
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
// console.log("✅ exposureMode applied");
|
// console.log("✅ exposureMode applied");
|
||||||
@ -810,7 +820,6 @@
|
|||||||
},
|
},
|
||||||
resetScanner(){
|
resetScanner(){
|
||||||
this.thisItem = null;
|
this.thisItem = null;
|
||||||
this.isCancelled = false; // Add this
|
|
||||||
this.resetForm();
|
this.resetForm();
|
||||||
},
|
},
|
||||||
handleFileUpload(event) {
|
handleFileUpload(event) {
|
||||||
@ -827,9 +836,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
async addItemMovement() {
|
async addItemMovement() {
|
||||||
|
// Client-side validation for quantity
|
||||||
|
if (this.thisItem && this.thisItem.category === "Disposable" && this.quantity > this.thisItem.quantity) {
|
||||||
|
alert('Error!', `The quantity you entered (${this.quantity}) exceeds the available stock (${this.thisItem.quantity}). Please enter a quantity less than or equal to the available stock.`, 'error');
|
||||||
|
return; // Prevent form submission
|
||||||
|
}
|
||||||
|
|
||||||
if (this.showProduct.category == "Disposable") {
|
// Check if the item is disposable and set serial number accordingly
|
||||||
this.serialNumber = "";
|
let itemQuantityToSend = 1; // Default quantity for non-disposable
|
||||||
|
if (this.thisItem && this.thisItem.category === "Disposable") {
|
||||||
|
// Ensure serial number is null for disposable items
|
||||||
|
this.thisItem.serialNumber = null;
|
||||||
|
itemQuantityToSend = this.quantity; // Use the quantity from the input for disposable
|
||||||
}
|
}
|
||||||
|
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
@ -843,11 +861,10 @@
|
|||||||
|
|
||||||
ItemId: this.thisItem.itemID,
|
ItemId: this.thisItem.itemID,
|
||||||
Action: 'Stock Out',
|
Action: 'Stock Out',
|
||||||
Quantity: 1,
|
Quantity: itemQuantityToSend, // Use the determined quantity here
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// Proceed to send the data to the API
|
// Proceed to send the data to the API
|
||||||
@ -883,66 +900,87 @@
|
|||||||
|
|
||||||
},
|
},
|
||||||
async receiveItemMovement() {
|
async receiveItemMovement() {
|
||||||
if (this.showProduct.category == "Disposable") {
|
|
||||||
this.serialNumber = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if(this.thisItem.toOther === "On Delivery" && this.thisItem.toUser == this.currentUser.id){
|
|
||||||
if(!window.confirm("Are you sure you want to cancel item delivery?")){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
|
console.log('currentuser'+this.currentUser.id);
|
||||||
|
console.log('lastuser'+this.thisItem.lastuser);
|
||||||
|
|
||||||
|
const formData = {
|
||||||
|
|
||||||
|
Id: this.thisItem.movementId,
|
||||||
|
ReceiveDate: new Date(now.getTime() + 8 * 60 * 60 * 1000).toISOString(),
|
||||||
|
Remark: this.thisItem.remark,
|
||||||
|
LastUser: this.thisItem.lastuser == null ? this.currentUser.id : this.thisItem.lastuser,
|
||||||
|
LatestStatus: this.thisItem.toOther === "Return" ? "Faulty" : (this.thisItem.toOther === "Calibration" || this.thisItem.toOther === "Repair" || this.thisItem.toOther === "On Delivery" ) ? "Ready To Deploy" : (this.itemlateststatus == 'On Delivery' && this.thisItem.lastStore == this.currentUser.store ? "Delivered" : "")
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// First, update the current movement to mark it as complete
|
|
||||||
const updateResponse = await fetch('/InvMainAPI/UpdateItemMovementMaster', {
|
// Proceed to send the data to the API
|
||||||
|
const response = await fetch('/InvMainAPI/UpdateItemMovementMaster', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
// 'Authorization': `Bearer ${this.token}`
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify(formData)
|
||||||
Id: this.thisItem.movementId,
|
|
||||||
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,
|
|
||||||
LastUser: this.thisItem.lastuser == null ? this.currentUser.id : this.thisItem.lastuser,
|
|
||||||
LatestStatus: "Ready To Deploy", // Set status to Ready To Deploy
|
|
||||||
MovementComplete: true
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
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);
|
||||||
|
// console.log(updatedItem);
|
||||||
|
|
||||||
if (!updateResponse.ok) {
|
// Reset the form
|
||||||
throw new Error('Failed to update current movement');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set cancelled flag and reset form
|
|
||||||
this.isCancelled = true;
|
|
||||||
this.resetForm();
|
this.resetForm();
|
||||||
|
window.location.href = '/Inventory/InventoryMaster/ItemMovement';
|
||||||
|
|
||||||
// Show the movement form by setting selectedAction
|
} else {
|
||||||
this.selectedAction = "user"; // Default to assign to user
|
throw new Error('Failed to submit form.');
|
||||||
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error:', error);
|
console.error('Error:', error);
|
||||||
|
|
||||||
|
// Displaying error message
|
||||||
alert('Inventory PSTW Error', `An error occurred: ${error.message}`, 'error');
|
alert('Inventory PSTW Error', `An error occurred: ${error.message}`, 'error');
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
async fetchItem(itemid) {
|
async fetchItem(itemid) {
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/InvMainAPI/GetItem/' + itemid, {
|
const response = await fetch('/InvMainAPI/GetItem/' + itemid, {
|
||||||
method: 'POST',
|
method: 'POST',}
|
||||||
});
|
);
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
this.thisItem = await response.json();
|
// this.thisItem = await response.json();
|
||||||
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;
|
this.thisItem = await response.json();
|
||||||
|
// If the item is disposable, set the quantity to 1 by default, or to its current quantity if available
|
||||||
|
if (this.thisItem.category === 'Disposable') {
|
||||||
|
this.quantity = 1; // Reset to 1 or default quantity when a disposable item is scanned
|
||||||
|
this.maxQuantity = this.thisItem.quantity; // Set maxQuantity for disposable items
|
||||||
|
} else {
|
||||||
|
this.quantity = 1; // For non-disposable items, quantity is always 1
|
||||||
|
this.maxQuantity = null; // Clear maxQuantity for non-disposable items
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('last store'+this.thisItem.lastStore);
|
||||||
|
|
||||||
|
this.itemlateststatus = this.thisItem.latestStatus ? this.thisItem.latestStatus : this.thisItem.toOther;
|
||||||
|
this.itemassignedtouser = (this.thisItem.toUser === this.currentUser.id || this.thisItem.lastUser === this.currentUser.id ) && this.thisItem.lastStore === this.currentUser.store ? true : false;
|
||||||
|
// console.log(this.thisItem);
|
||||||
|
// console.log(this.itemassignedtouser);
|
||||||
|
console.log(this.thisItem.lastStore);
|
||||||
|
console.log( this.thisItem.lastStore == this.currentUser.store? true : false);
|
||||||
|
console.log(this.thisItem.toUser == this.currentUser.id? true : false);
|
||||||
|
console.log( this.thisItem.lastUser == this.currentUser.id ? true : false);
|
||||||
|
console.log(((this.thisItem.toUser == this.currentUser.id) || ( this.thisItem.lastUser == this.currentUser.id)) ? true : false);
|
||||||
|
console.log('currentuser store'+this.currentUser.store);
|
||||||
|
|
||||||
|
|
||||||
// Reset cancellation flag when scanning
|
|
||||||
this.isCancelled = false;
|
|
||||||
} else {
|
} else {
|
||||||
console.error('Failed to fetch item information');
|
console.error('Failed to fetch item information');
|
||||||
this.responseMessage = await response.text();
|
this.responseMessage = await response.text();
|
||||||
@ -978,9 +1016,119 @@
|
|||||||
this.selectedOther = "";
|
this.selectedOther = "";
|
||||||
this.selectedStation = "";
|
this.selectedStation = "";
|
||||||
this.selectedStationPIC = "";
|
this.selectedStationPIC = "";
|
||||||
|
this.cancelRemark = "";
|
||||||
|
this.quantity = 1; // Reset quantity when the form is reset
|
||||||
|
this.maxQuantity = null; // Clear maxQuantity on form reset
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
async confirmCancelItemMovement() {
|
||||||
|
if (!window.confirm("Are you sure you want to cancel this item movement?")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const now = new Date();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// First Movement: Cancellation Record (EXACTLY AS YOU HAVE IT)
|
||||||
|
const cancellationMovementData = {
|
||||||
|
ItemId: this.thisItem.itemID,
|
||||||
|
ToStore: this.currentUser.store,
|
||||||
|
ToUser: this.currentUser.id,
|
||||||
|
ToOther: null,
|
||||||
|
sendDate: new Date(now.getTime() + 8 * 60 * 60 * 1000).toISOString(),
|
||||||
|
Action: 'Stock Out',
|
||||||
|
Quantity: this.thisItem.quantity,
|
||||||
|
Remark: `Item has been cancelled: ${this.cancelRemark}`,
|
||||||
|
ConsignmentNote: this.thisItem.consignmentNote,
|
||||||
|
LastUser: this.currentUser.id,
|
||||||
|
LastStore: this.currentUser.store,
|
||||||
|
LatestStatus: 'Ready To Deploy',
|
||||||
|
receiveDate: null,
|
||||||
|
MovementComplete: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Second Movement: Re-registration/Re-stock Record (EXACTLY AS YOU HAVE IT)
|
||||||
|
const registrationMovementData = {
|
||||||
|
ItemId: this.thisItem.itemID,
|
||||||
|
ToStore: this.currentUser.store,
|
||||||
|
ToUser: this.currentUser.id,
|
||||||
|
ToOther: null,
|
||||||
|
sendDate: null,
|
||||||
|
Action: 'Register',
|
||||||
|
Quantity: this.thisItem.quantity,
|
||||||
|
Remark: null,
|
||||||
|
ConsignmentNote: null,
|
||||||
|
LastUser: this.currentUser.id,
|
||||||
|
LastStore: this.currentUser.store,
|
||||||
|
LatestStatus: 'Ready To Deploy',
|
||||||
|
receiveDate: null,
|
||||||
|
MovementComplete: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update the original movement to mark it as cancelled
|
||||||
|
const updateOriginalResponse = await fetch('/InvMainAPI/UpdateItemMovementMaster', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
Id: this.thisItem.movementId,
|
||||||
|
MovementComplete: true,
|
||||||
|
LatestStatus: 'Cancelled',
|
||||||
|
Remark: `Movement cancelled: ${this.cancelRemark}`
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!updateOriginalResponse.ok) {
|
||||||
|
throw new Error('Failed to update original movement as cancelled.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the first movement (cancellation)
|
||||||
|
const response1 = await fetch('/InvMainAPI/AddItemMovement', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(cancellationMovementData),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response1.ok) {
|
||||||
|
throw new Error('Failed to record cancellation movement.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the second movement (registration/re-stock)
|
||||||
|
const response2 = await fetch('/InvMainAPI/AddItemMovement', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(registrationMovementData),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response2.ok) {
|
||||||
|
throw new Error('Failed to record re-registration movement.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the item's quantity by adding back the assigned quantity
|
||||||
|
const updateItemResponse = await fetch('/InvMainAPI/UpdateItemQuantity', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
ItemId: this.thisItem.itemID,
|
||||||
|
Quantity: this.thisItem.quantity, // The quantity to add back
|
||||||
|
MovementId: this.thisItem.movementId // Add the movement ID
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!updateItemResponse.ok) {
|
||||||
|
throw new Error('Failed to update item quantity.');
|
||||||
|
}
|
||||||
|
|
||||||
|
alert('Success!', 'Item movement cancelled and quantity returned successfully.', 'success');
|
||||||
|
this.resetForm();
|
||||||
|
window.location.href = '/Inventory/InventoryMaster/ItemMovement';
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error during cancellation process:', error);
|
||||||
|
alert('Error', `An error occurred during cancellation: ${error.message}`, 'error');
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// FRONT END FUNCTIONS
|
// FRONT END FUNCTIONS
|
||||||
@ -1070,7 +1218,6 @@
|
|||||||
this.storelist = await response.json();
|
this.storelist = await response.json();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
console.error('Error fetching item:', error);
|
console.error('Error fetching item:', error);
|
||||||
@ -1083,7 +1230,4 @@
|
|||||||
|
|
||||||
app.mount('#registerItemMovement');
|
app.mount('#registerItemMovement');
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -498,21 +498,27 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
|||||||
{
|
{
|
||||||
var product = await _centralDbContext.Products.FirstOrDefaultAsync(p => p.ProductId == item.ProductId) ?? throw new Exception("Product not found");
|
var product = await _centralDbContext.Products.FirstOrDefaultAsync(p => p.ProductId == item.ProductId) ?? throw new Exception("Product not found");
|
||||||
var inventoryMaster = await _centralDbContext.InventoryMasters.Include("User").FirstOrDefaultAsync(i => i.UserId == item.CreatedByUserId) ?? new InventoryMasterModel { UserId = item.CreatedByUserId };
|
var inventoryMaster = await _centralDbContext.InventoryMasters.Include("User").FirstOrDefaultAsync(i => i.UserId == item.CreatedByUserId) ?? new InventoryMasterModel { UserId = item.CreatedByUserId };
|
||||||
var addToProduct = item.Quantity;
|
|
||||||
|
|
||||||
if (product.Category == "Disposable")
|
if (product.Category == "Disposable")
|
||||||
{
|
{
|
||||||
item.SerialNumber = null;
|
// For disposable items, the quantity product is increased by the item's quantity
|
||||||
|
product.QuantityProduct += item.Quantity;
|
||||||
|
item.SerialNumber = null; // Ensure serial number is null for disposables
|
||||||
|
}
|
||||||
|
else if (product.Category == "Asset" || product.Category == "Part")
|
||||||
|
{
|
||||||
|
// For assets or parts, each added item counts as 1 to the product quantity
|
||||||
|
// and the item's quantity should be set to 1 if it's not already, or based on specific logic.
|
||||||
|
// Assuming for Assets/Parts, each 'AddItem' call registers one unit of that product.
|
||||||
|
product.QuantityProduct = (product.QuantityProduct ?? 0) + 1; // Increment by 1 for Asset/Part
|
||||||
|
item.Quantity = 1; // Force quantity to 1 for Assets/Parts if it's not already
|
||||||
}
|
}
|
||||||
|
|
||||||
_centralDbContext.Items.Add(item);
|
_centralDbContext.Items.Add(item);
|
||||||
|
_centralDbContext.Products.Update(product); // Update the product quantity
|
||||||
product.QuantityProduct += addToProduct;
|
|
||||||
_centralDbContext.Products.Update(product);
|
|
||||||
|
|
||||||
await _centralDbContext.SaveChangesAsync(); // This generates the auto-incremented ItemID
|
await _centralDbContext.SaveChangesAsync(); // This generates the auto-incremented ItemID
|
||||||
|
|
||||||
|
|
||||||
ItemMovementModel itemMovement = new ItemMovementModel
|
ItemMovementModel itemMovement = new ItemMovementModel
|
||||||
{
|
{
|
||||||
ItemId = item.ItemID,
|
ItemId = item.ItemID,
|
||||||
@ -521,7 +527,7 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
|||||||
LastStore = inventoryMaster.StoreId,
|
LastStore = inventoryMaster.StoreId,
|
||||||
LastUser = inventoryMaster.UserId,
|
LastUser = inventoryMaster.UserId,
|
||||||
LatestStatus = "Ready To Deploy",
|
LatestStatus = "Ready To Deploy",
|
||||||
Quantity = item.Quantity,
|
Quantity = item.Quantity, // Use the item's quantity for movement record
|
||||||
Action = "Register",
|
Action = "Register",
|
||||||
Date = DateTime.Now,
|
Date = DateTime.Now,
|
||||||
MovementComplete = true,
|
MovementComplete = true,
|
||||||
@ -530,10 +536,9 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
|||||||
_centralDbContext.ItemMovements.Add(itemMovement);
|
_centralDbContext.ItemMovements.Add(itemMovement);
|
||||||
await _centralDbContext.SaveChangesAsync();
|
await _centralDbContext.SaveChangesAsync();
|
||||||
|
|
||||||
// Fetch the generated ItemID
|
// Fetch the generated ItemID and MovementId for the response
|
||||||
var savedItem = await _centralDbContext.Items.FirstOrDefaultAsync(i => i.ItemID == item.ItemID);
|
var savedItem = await _centralDbContext.Items.FirstOrDefaultAsync(i => i.ItemID == item.ItemID);
|
||||||
// Fetch the generated itemMovement
|
var savedMovement = await _centralDbContext.ItemMovements.FirstOrDefaultAsync(im => im.Id == itemMovement.Id);
|
||||||
var savedMovement = await _centralDbContext.ItemMovements.FirstOrDefaultAsync(i => i.Id == itemMovement.Id);
|
|
||||||
|
|
||||||
if (savedItem != null)
|
if (savedItem != null)
|
||||||
{
|
{
|
||||||
@ -545,8 +550,8 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
|||||||
string? deptCode = companyDepartment!.DepartmentCode?.ToString();
|
string? deptCode = companyDepartment!.DepartmentCode?.ToString();
|
||||||
char? initialCategory = itemProduct!.Category.ToString().Substring(0, 1).ToUpper().FirstOrDefault();
|
char? initialCategory = itemProduct!.Category.ToString().Substring(0, 1).ToUpper().FirstOrDefault();
|
||||||
string? productId = itemProduct!.ProductId.ToString("D3");
|
string? productId = itemProduct!.ProductId.ToString("D3");
|
||||||
string? itemId = item.ItemID.ToString("D5");
|
string? itemIdString = item.ItemID.ToString("D5");
|
||||||
var uniqueId = $"{deptCode}{initialCategory}{productId}{itemId}".ToUpper();
|
var uniqueId = $"{deptCode}{initialCategory}{productId}{itemIdString}".ToUpper();
|
||||||
savedItem.UniqueID = uniqueId;
|
savedItem.UniqueID = uniqueId;
|
||||||
savedItem.MovementId = savedMovement?.Id;
|
savedItem.MovementId = savedMovement?.Id;
|
||||||
|
|
||||||
@ -584,6 +589,7 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[HttpPost("EditItem")]
|
[HttpPost("EditItem")]
|
||||||
public async Task<IActionResult> EditItem([FromBody] ItemModel item)
|
public async Task<IActionResult> EditItem([FromBody] ItemModel item)
|
||||||
{
|
{
|
||||||
@ -594,20 +600,76 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var savedItem = await _centralDbContext.Items.FirstOrDefaultAsync(i => i.ItemID == item.ItemID);
|
var savedItem = await _centralDbContext.Items
|
||||||
|
.Include(i => i.Product) // Include product to get the original category
|
||||||
|
.FirstOrDefaultAsync(i => i.ItemID == item.ItemID);
|
||||||
if (savedItem == null)
|
if (savedItem == null)
|
||||||
{
|
{
|
||||||
return NotFound(new { success = false, message = "Item not found" });
|
return NotFound(new { success = false, message = "Item not found" });
|
||||||
}
|
}
|
||||||
|
|
||||||
var product = await _centralDbContext.Products.FirstOrDefaultAsync(p => p.ProductId == item.ProductId) ?? throw new Exception("Product not found");
|
var product = await _centralDbContext.Products.FirstOrDefaultAsync(p => p.ProductId == item.ProductId) ?? throw new Exception("Product not found");
|
||||||
|
var originalProduct = savedItem.Product; // Get the original product associated with the item
|
||||||
|
|
||||||
|
// Calculate quantity changes for Disposable category
|
||||||
|
if (originalProduct?.Category == "Disposable" && product.Category == "Disposable")
|
||||||
|
{
|
||||||
|
int quantityDifference = item.Quantity - savedItem.Quantity;
|
||||||
|
product.QuantityProduct += quantityDifference;
|
||||||
|
}
|
||||||
|
else if (originalProduct?.Category != "Disposable" && product.Category == "Disposable")
|
||||||
|
{
|
||||||
|
// Category changed from Asset/Part to Disposable: add new quantity
|
||||||
|
product.QuantityProduct += item.Quantity;
|
||||||
|
// Optionally, if the old item was counted as 1 in QuantityProduct (for Asset/Part), decrement it.
|
||||||
|
if (originalProduct?.QuantityProduct > 0) // Ensure it doesn't go below zero
|
||||||
|
{
|
||||||
|
var oldProduct = await _centralDbContext.Products.FirstOrDefaultAsync(p => p.ProductId == originalProduct.ProductId);
|
||||||
|
if (oldProduct != null)
|
||||||
|
{
|
||||||
|
oldProduct.QuantityProduct = (oldProduct.QuantityProduct ?? 0) - 1;
|
||||||
|
_centralDbContext.Products.Update(oldProduct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (originalProduct?.Category == "Disposable" && product.Category != "Disposable")
|
||||||
|
{
|
||||||
|
// Category changed from Disposable to Asset/Part: subtract old quantity
|
||||||
|
product.QuantityProduct -= savedItem.Quantity;
|
||||||
|
// Add 1 to the new product's quantity if it's now an Asset/Part
|
||||||
|
product.QuantityProduct = (product.QuantityProduct ?? 0) + 1;
|
||||||
|
}
|
||||||
|
// If both are Asset/Part, no quantity change needed for ProductModel based on ItemModel quantity
|
||||||
|
// If ProductId changes for Asset/Part, you need to decrement old product and increment new product by 1
|
||||||
|
else if ((originalProduct?.Category == "Asset" || originalProduct?.Category == "Part") && (product.Category == "Asset" || product.Category == "Part"))
|
||||||
|
{
|
||||||
|
if (savedItem.ProductId != item.ProductId) // Product changed for Asset/Part
|
||||||
|
{
|
||||||
|
// Decrement old product quantity
|
||||||
|
var oldProduct = await _centralDbContext.Products.FirstOrDefaultAsync(p => p.ProductId == savedItem.ProductId);
|
||||||
|
if (oldProduct != null)
|
||||||
|
{
|
||||||
|
oldProduct.QuantityProduct = (oldProduct.QuantityProduct ?? 0) - 1;
|
||||||
|
_centralDbContext.Products.Update(oldProduct);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increment new product quantity
|
||||||
|
product.QuantityProduct = (product.QuantityProduct ?? 0) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle serial number for Disposable
|
||||||
if (product.Category == "Disposable")
|
if (product.Category == "Disposable")
|
||||||
{
|
{
|
||||||
item.SerialNumber = null;
|
item.SerialNumber = null;
|
||||||
}
|
}
|
||||||
|
else if (product.Category == "Asset" || product.Category == "Part")
|
||||||
|
{
|
||||||
|
item.Quantity = 1; // Enforce quantity to 1 for Assets/Parts
|
||||||
|
}
|
||||||
|
|
||||||
savedItem.ItemID = item.ItemID;
|
|
||||||
|
// Update savedItem properties from item model
|
||||||
savedItem.DefaultPrice = item.DefaultPrice;
|
savedItem.DefaultPrice = item.DefaultPrice;
|
||||||
savedItem.CompanyId = item.CompanyId;
|
savedItem.CompanyId = item.CompanyId;
|
||||||
savedItem.DepartmentId = item.DepartmentId;
|
savedItem.DepartmentId = item.DepartmentId;
|
||||||
@ -628,30 +690,30 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
|||||||
savedItem.InvoiceNo = item.InvoiceNo;
|
savedItem.InvoiceNo = item.InvoiceNo;
|
||||||
savedItem.InvoiceDate = item.InvoiceDate;
|
savedItem.InvoiceDate = item.InvoiceDate;
|
||||||
savedItem.PartNumber = item.PartNumber;
|
savedItem.PartNumber = item.PartNumber;
|
||||||
savedItem.UniqueID = item.PartNumber;
|
savedItem.UniqueID = item.PartNumber; // This might need to be re-evaluated for UniqueID generation if PartNumber can change
|
||||||
|
|
||||||
|
_centralDbContext.Products.Update(product); // Update the product with the new quantity
|
||||||
|
_centralDbContext.Items.Update(savedItem); // Update the item
|
||||||
|
|
||||||
_centralDbContext.Items.Update(savedItem);
|
await _centralDbContext.SaveChangesAsync();
|
||||||
|
|
||||||
await _centralDbContext.SaveChangesAsync(); // This generates the auto-incremented ItemID
|
// Regenerate UniqueID if necessary (e.g., if PartNumber is part of it and changed)
|
||||||
|
// Note: The UniqueID generation logic seems to re-use PartNumber in your code,
|
||||||
if (savedItem != null)
|
// which might be fine, but if UniqueID should be truly unique and immutable
|
||||||
{
|
// after creation, you might reconsider updating it on edit.
|
||||||
var companyDepartment = await GetDepartmentWithCompany(item.CompanyId, item.DepartmentId);
|
var companyDepartment = await GetDepartmentWithCompany(savedItem.CompanyId, savedItem.DepartmentId);
|
||||||
var itemProduct = _centralDbContext.Products.Where(p => p.ProductId == item.ProductId).FirstOrDefault();
|
var itemProduct = _centralDbContext.Products.Where(p => p.ProductId == savedItem.ProductId).FirstOrDefault();
|
||||||
|
|
||||||
string? companyInitial = companyDepartment!.CompanyName?.ToString().Substring(0, 1).ToUpper();
|
string? companyInitial = companyDepartment!.CompanyName?.ToString().Substring(0, 1).ToUpper();
|
||||||
string? departmentInitial = companyDepartment!.DepartmentName?.ToString().Substring(0, 1).ToUpper();
|
string? departmentInitial = companyDepartment!.DepartmentName?.ToString().Substring(0, 1).ToUpper();
|
||||||
string? deptCode = companyDepartment!.DepartmentCode?.ToString();
|
string? deptCode = companyDepartment!.DepartmentCode?.ToString();
|
||||||
char? initialCategory = itemProduct!.Category.ToString().Substring(0, 1).ToUpper().FirstOrDefault();
|
char? initialCategory = itemProduct!.Category.ToString().Substring(0, 1).ToUpper().FirstOrDefault();
|
||||||
string? productId = itemProduct!.ProductId.ToString("D3");
|
string? productId = itemProduct!.ProductId.ToString("D3");
|
||||||
string? itemId = item.ItemID.ToString("D5");
|
string? itemIdString = savedItem.ItemID.ToString("D5");
|
||||||
var uniqueId = $"{deptCode}{initialCategory}{productId}{itemId}".ToUpper();
|
savedItem.UniqueID = $"{deptCode}{initialCategory}{productId}{itemIdString}".ToUpper(); // Re-generate UniqueID based on updated fields
|
||||||
savedItem.UniqueID = uniqueId;
|
|
||||||
|
|
||||||
_centralDbContext.Items.Update(savedItem);
|
_centralDbContext.Items.Update(savedItem);
|
||||||
await _centralDbContext.SaveChangesAsync();
|
await _centralDbContext.SaveChangesAsync();
|
||||||
}
|
|
||||||
|
|
||||||
var updatedItem = new
|
var updatedItem = new
|
||||||
{
|
{
|
||||||
@ -682,6 +744,7 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
|||||||
return BadRequest(ex.Message);
|
return BadRequest(ex.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpDelete("DeleteItem/{id}")]
|
[HttpDelete("DeleteItem/{id}")]
|
||||||
public async Task<IActionResult> DeleteItem(int id)
|
public async Task<IActionResult> DeleteItem(int id)
|
||||||
{
|
{
|
||||||
@ -694,7 +757,7 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
|||||||
var products = _centralDbContext.Products
|
var products = _centralDbContext.Products
|
||||||
.FirstOrDefault(i => i.ProductId == item.ProductId);
|
.FirstOrDefault(i => i.ProductId == item.ProductId);
|
||||||
|
|
||||||
products.QuantityProduct = products.QuantityProduct - 1;
|
products.QuantityProduct = products.QuantityProduct - item.Quantity;
|
||||||
|
|
||||||
// Get related item movements
|
// Get related item movements
|
||||||
var itemMovements = await _centralDbContext.ItemMovements
|
var itemMovements = await _centralDbContext.ItemMovements
|
||||||
@ -771,6 +834,7 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
|||||||
item.Product!.ProductName,
|
item.Product!.ProductName,
|
||||||
item.Product!.ProductShortName,
|
item.Product!.ProductShortName,
|
||||||
item.Product!.ImageProduct,
|
item.Product!.ImageProduct,
|
||||||
|
Category = item.Product!.Category,
|
||||||
CurrentUser = item.Movement?.FromUser?.UserName,
|
CurrentUser = item.Movement?.FromUser?.UserName,
|
||||||
CurrentUserFullName = item.Movement?.FromUser?.FullName,
|
CurrentUserFullName = item.Movement?.FromUser?.FullName,
|
||||||
CurrentUserId = item.Movement?.FromUser?.Id,
|
CurrentUserId = item.Movement?.FromUser?.Id,
|
||||||
@ -866,7 +930,6 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
|||||||
[HttpPost("AddItemMovement")]
|
[HttpPost("AddItemMovement")]
|
||||||
public async Task<IActionResult> AddItemMovement([FromBody] ItemMovementModel itemmovement)
|
public async Task<IActionResult> AddItemMovement([FromBody] ItemMovementModel itemmovement)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
if (!ModelState.IsValid)
|
||||||
{
|
{
|
||||||
return BadRequest(ModelState);
|
return BadRequest(ModelState);
|
||||||
@ -874,11 +937,6 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//if (itemmovement.ToUser == null)
|
|
||||||
//{
|
|
||||||
// throw new Exception("itemmovement.ToUser is null");
|
|
||||||
//}
|
|
||||||
|
|
||||||
var inventoryMaster = await _centralDbContext.InventoryMasters.Include("User").FirstOrDefaultAsync(i => i.UserId == itemmovement.ToUser);
|
var inventoryMaster = await _centralDbContext.InventoryMasters.Include("User").FirstOrDefaultAsync(i => i.UserId == itemmovement.ToUser);
|
||||||
if (inventoryMaster != null)
|
if (inventoryMaster != null)
|
||||||
{
|
{
|
||||||
@ -931,9 +989,19 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
|||||||
{
|
{
|
||||||
updateItem.ItemStatus = 8;
|
updateItem.ItemStatus = 8;
|
||||||
}
|
}
|
||||||
|
// Handle quantity update for disposable items here
|
||||||
|
// This is crucial: if it's a disposable item, decrement the Item's Quantity
|
||||||
|
// You'll need to fetch the Product to know if it's Disposable
|
||||||
|
var product = await _centralDbContext.Products.FindAsync(updateItem.ProductId);
|
||||||
|
if (product != null && product.Category == "Disposable" && itemmovement.Quantity.HasValue)
|
||||||
|
{
|
||||||
|
updateItem.Quantity -= itemmovement.Quantity.Value;
|
||||||
|
if (updateItem.Quantity < 0)
|
||||||
|
{
|
||||||
|
updateItem.Quantity = 0; // Prevent negative quantity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Console.WriteLine("updateItem.MovementId" + updateItem.MovementId);
|
|
||||||
//Console.WriteLine("itemmovement.Id" + itemmovement.Id);
|
|
||||||
|
|
||||||
updateItem.MovementId = itemmovement.Id;
|
updateItem.MovementId = itemmovement.Id;
|
||||||
_centralDbContext.Items.Update(updateItem);
|
_centralDbContext.Items.Update(updateItem);
|
||||||
@ -963,10 +1031,6 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
|||||||
itemmovement.MovementComplete
|
itemmovement.MovementComplete
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//return Json(itemmovement);
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -1016,6 +1080,70 @@ namespace PSTW_CentralSystem.Controllers.API.Inventory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost("UpdateItemQuantity")]
|
||||||
|
public async Task<IActionResult> UpdateItemQuantity([FromBody] ItemQuantityUpdateModel model)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Find the item
|
||||||
|
var item = await _centralDbContext.Items
|
||||||
|
.Include(i => i.Product) // Include product for category check
|
||||||
|
.FirstOrDefaultAsync(i => i.ItemID == model.ItemId);
|
||||||
|
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
return NotFound("Item not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only process if it's a disposable item
|
||||||
|
if (item.Product?.Category == "Disposable")
|
||||||
|
{
|
||||||
|
// Get the original movement to find the exact quantity that was assigned
|
||||||
|
var originalMovement = await _centralDbContext.ItemMovements
|
||||||
|
.FirstOrDefaultAsync(m => m.Id == model.MovementId);
|
||||||
|
|
||||||
|
if (originalMovement == null)
|
||||||
|
{
|
||||||
|
return BadRequest("Original movement record not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// The quantity to return is the original movement's quantity
|
||||||
|
var quantityToReturn = originalMovement.Quantity ?? 1;
|
||||||
|
|
||||||
|
// Update the item quantity by adding back the assigned amount
|
||||||
|
item.Quantity += quantityToReturn;
|
||||||
|
|
||||||
|
// Ensure quantity doesn't go negative (just in case)
|
||||||
|
if (item.Quantity < 0)
|
||||||
|
{
|
||||||
|
item.Quantity = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_centralDbContext.Items.Update(item);
|
||||||
|
await _centralDbContext.SaveChangesAsync();
|
||||||
|
|
||||||
|
return Ok(new
|
||||||
|
{
|
||||||
|
item.ItemID,
|
||||||
|
OriginalQuantity = originalMovement.Quantity,
|
||||||
|
NewQuantity = item.Quantity,
|
||||||
|
Message = $"Successfully returned {quantityToReturn} to item quantity"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// For non-disposable items, just return success without changing quantity
|
||||||
|
return Ok(new
|
||||||
|
{
|
||||||
|
item.ItemID,
|
||||||
|
Message = "No quantity change - item is not disposable"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return BadRequest($"Error updating item quantity: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion ItemMovement
|
#endregion ItemMovement
|
||||||
|
|
||||||
#region ItemMovementUser
|
#region ItemMovementUser
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 980 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 118 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 118 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
Loading…
Reference in New Issue
Block a user