po process

This commit is contained in:
2025-06-30 14:46:43 +08:00
parent 00c6abe44d
commit f378cbb522

View File

@@ -133,9 +133,50 @@
if (page >= 1 && page <= totalPages) currentPage = page;
}
let showApprovalModal = false;
let approvalForm = {
po_number: "",
approval: "",
approved_by: "",
approved_date: "",
reject_comment: ""
};
let currentUserId = "";
let currentUserFullName = "";
async function fetchCurrentUser() {
const {
data: { user }
} = await supabase.auth.getUser();
if (user) {
currentUserId = user.id;
const { data, error } = await supabase
.from("vb_users")
.select("full_name")
.eq("id", user.id)
.single();
if (!error && data) {
currentUserFullName = data.full_name;
}
}
}
function openApprovalModal(row) {
selectedPO = row;
approvalForm = {
po_number: row.purchase_order_number || "",
approval: row.approval ? "approve" : "reject",
approved_by: currentUserId,
approved_date: new Date().toISOString().split("T")[0],
reject_comment: row.reject_comment || ""
};
showApprovalModal = true;
}
let showPaymentModal = false;
let paymentForm = {
payment_method: "",
@@ -155,6 +196,27 @@
due_remaining: 0
};
let showAcknowledgedModal = false;
let acknowledgedForm = {
po_number: "",
acknowledged: "",
acknowledged_by: "",
acknowledged_date: ""
};
function openAcknowledgedModal(row) {
selectedPO = row;
acknowledgedForm = {
po_number: row.purchase_order_number || "",
acknowledged: row.acknowledged ? "acknowledged" : "reject",
acknowledged_by: currentUserId,
acknowledged_date: new Date().toISOString().split("T")[0]
};
showAcknowledgedModal = true;
}
let showPreparedModal = false;
let selectedPO = null;
@@ -180,8 +242,82 @@
approved_price: 0,
total_approved_order_amount: 0
};
let showReceivedModal = false;
let receivedForm = {
po_number: "",
received: "",
received_by: "",
received_date: ""
};
function openReceivedModal(row) {
selectedPO = row;
receivedForm = {
po_number: row.purchase_order_number || "",
received: row.received ? "received" : "reject",
received_by: currentUserId,
received_date: new Date().toISOString().split("T")[0]
};
showReceivedModal = true;
}
let showCompletedModal = false;
let completedForm = {
po_number: "",
completed: "",
completed_by: "",
completed_date: ""
};
function openCompletedModal(row) {
selectedPO = row;
completedForm = {
po_number: row.purchase_order_number || "",
completed: row.completed ? "completed" : "reject",
completed_by: currentUserId,
completed_date: new Date().toISOString().split("T")[0]
};
showCompletedModal = true;
}
async function saveCompleted() {
const { error } = await supabase
.from("vb_purchase_orders")
.update({
completed: completedForm.completed === "completed",
completed_by: completedForm.completed === "completed" ? currentUserId : null,
completed_date: completedForm.completed_date
})
.eq("id", selectedPO.id);
if (error) {
console.error("Error saving completed:", error);
alert("Failed to save.");
return;
}
// ✅ Fire the webhook after saving:
try {
await fetch("https://flow.catalis.app/webhook-test/vb_need_complete_new", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
po_id: selectedPO.id,
completed: completedForm.completed === "completed",
completed_by: completedForm.completed === "completed" ? currentUserId : null,
completed_date: completedForm.completed_date
})
});
} catch (webhookError) {
console.error("Webhook failed:", webhookError);
alert("Saved, but webhook failed.");
}
showCompletedModal = false;
await fetchPurchaseOrder();
}
async function openPreparedModal(row) {
selectedPO = row;
@@ -329,6 +465,7 @@
onMount(() => {
fetchPurchaseOrder();
fetchVendors();
fetchCurrentUser();
});
$: currentPage = 1; // Reset to first page when allRows changes
@@ -567,6 +704,40 @@
}
return true;
}
async function saveReceived() {
const { error } = await supabase
.from("vb_purchase_orders")
.update({
received: receivedForm.received === "received",
received_by: receivedForm.received === "received" ? currentUserId : null,
received_date: receivedForm.received_date
})
.eq("id", selectedPO.id);
if (error) {
console.error("Error saving received:", error);
alert("Failed to save.");
return;
}
// ✅ Fire the webhook after the DB update succeeds:
try {
await fetch("https://flow.catalis.app/webhook-test/vb_need_received_new", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
po_id: selectedPO.id,
received: receivedForm.received === "received",
received_by: receivedForm.received === "received" ? currentUserId : null,
received_date: receivedForm.received_date
})
});
} catch (webhookError) {
console.error("Webhook failed:", webhookError);
alert("Saved, but webhook failed.");
}
showReceivedModal = false;
await fetchPurchaseOrder();
}
function validateInputProsesToAprroval() {
const requiredFields = ["po_type", "po_quantity", "po_price"];
@@ -673,6 +844,43 @@
await fetchPurchaseOrder();
}
async function saveAcknowledged() {
const { error } = await supabase
.from("vb_purchase_orders")
.update({
acknowledged: acknowledgedForm.acknowledged === "acknowledged",
acknowledge_by: acknowledgedForm.acknowledged === "acknowledged" ? currentUserId : null,
acknowledged_date: acknowledgedForm.acknowledged_date
})
.eq("id", selectedPO.id);
if (error) {
console.error("Error saving acknowledged:", error);
alert("Failed to save.");
return;
}
// ✅ Fire the webhook after successful update:
try {
await fetch("https://flow.catalis.app/webhook/vb_acknowledged_new", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
po_id: selectedPO.id,
acknowledged: acknowledgedForm.acknowledged === "acknowledged",
acknowledged_by: acknowledgedForm.acknowledged === "acknowledged" ? currentUserId : null,
acknowledged_date: acknowledgedForm.acknowledged_date
})
});
} catch (webhookError) {
console.error("Failed to fire webhook:", webhookError);
alert("Saved, but webhook failed.");
}
showAcknowledgedModal = false;
await fetchPurchaseOrder();
}
async function receivedOk(id: string, status: boolean) {
const sessionId = await getSessionAuthId();
if (!sessionId) {
@@ -838,7 +1046,27 @@
showPaymentModal = false;
await fetchPurchaseOrder();
}
async function saveApproval() {
const { error } = await supabase
.from("vb_purchase_orders")
.update({
approved: approvalForm.approval === "approve",
approved_by: approvalForm.approval === "approve" ? currentUserId : null,
approved_date: approvalForm.approved_date,
reject_comment: approvalForm.reject_comment || null,
po_status: "approved"
})
.eq("id", selectedPO.id);
if (error) {
console.error("Error saving approval:", error);
alert("Failed to save.");
return;
}
showApprovalModal = false;
await fetchPurchaseOrder();
}
</script>
<div>
@@ -932,10 +1160,94 @@
{row.prepared === true ? "Prepared" : "Set Prepared"}
</button>
</td>
{:else if col.key === "approved" || col.key === "acknowledged" || col.key === "completed" || col.key === "received"}
{:else if col.key === "approved"}
<td class="px-4 py-2 text-center">
<input type="checkbox" checked={row[col.key]} disabled />
<button
class="inline-flex items-center gap-1 rounded bg-yellow-600 px-3 py-1.5 text-white text-xs font-medium
hover:bg-yellow-700 disabled:bg-gray-400 disabled:cursor-not-allowed"
on:click={() => openApprovalModal(row)}
disabled={
row.approved === true ||
row.approved === false ||
row.po_status !== 'prepared'
}
>
{#if row.approved === true}
Approved
{:else if row.approved === false}
Rejected
{:else if row.po_status !== 'prepared'}
Not Prepared
{:else}
Approval
{/if}
</button>
</td>
{:else if col.key === "acknowledged"}
<td class="px-4 py-2 text-center">
<button
class="inline-flex items-center gap-1 rounded bg-green-600 px-3 py-1.5 text-white text-xs font-medium
hover:bg-green-700 disabled:bg-gray-400 disabled:cursor-not-allowed"
on:click={() => openAcknowledgedModal(row)}
disabled={
row.approved !== true || row.acknowledged === true || row.acknowledged === false
}
>
{#if row.acknowledged === true}
Acknowledged
{:else if row.acknowledged === false}
Rejected
{:else if row.approved !== true}
Pending
{:else}
Acknowledge
{/if}
</button>
</td>
{:else if col.key === "completed"}
<td class="px-4 py-2 text-center">
<button
class="inline-flex items-center gap-1 rounded bg-purple-600 px-3 py-1.5 text-white text-xs font-medium
hover:bg-purple-700 disabled:bg-gray-400 disabled:cursor-not-allowed"
on:click={() => openCompletedModal(row)}
disabled={
row.acknowledged !== true || row.completed === true || row.completed === false
}
>
{#if row.completed === true}
Completed
{:else if row.completed === false}
Rejected
{:else if row.acknowledged !== true}
Pending
{:else}
Complete
{/if}
</button>
</td>
{:else if col.key === "received"}
<td class="px-4 py-2 text-center">
<button
class="inline-flex items-center gap-1 rounded bg-green-600 px-3 py-1.5 text-white text-xs font-medium
hover:bg-green-700 disabled:bg-gray-400 disabled:cursor-not-allowed"
on:click={() => openReceivedModal(row)}
disabled={
row.completed !== true || row.received === true || row.received === false
}
>
{#if row.received === true}
Received
{:else if row.received === false}
Rejected
{:else if row.completed !== true}
Pending
{:else}
Receive
{/if}
</button>
</td>
{:else if col.key === "payment"}
<td class="px-4 py-2 text-center">
<button
@@ -1370,4 +1682,161 @@
</div>
</div>
</div>
{/if}
{/if}
{#if showApprovalModal}
<div class="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50 overflow-y-auto">
<div class="min-h-screen flex items-center justify-center p-4">
<div class="bg-white rounded-lg shadow-lg w-full max-w-md max-h-[90vh] overflow-y-auto p-6 space-y-4">
<h2 class="text-xl font-bold">Approve Purchase Order</h2>
<!-- PO Number -->
<label>PO Number</label>
<input
type="text"
value={approvalForm.po_number}
disabled
class="w-full border p-2 bg-gray-100"
/>
<!-- Approval -->
<label>Approval</label>
<select bind:value={approvalForm.approval} class="w-full border p-2">
<option value="" disabled>Select Approval</option>
<option value="approve">Approve</option>
<option value="reject">Reject</option>
</select>
{#if approvalForm.approval === 'reject'}
<label>Reject Comment</label>
<textarea
bind:value={approvalForm.reject_comment}
class="w-full border p-2"
rows="3"
placeholder="Enter reason for rejection..."
></textarea>
{/if}
<!-- Hidden: approved_by -->
<input type="hidden" value={approvalForm.approved_by} />
<!-- Hidden: approved_date -->
<input type="hidden" value={approvalForm.approved_date} />
<!-- Actions -->
<div class="flex justify-end space-x-2 pt-4">
<button on:click={saveApproval} class="bg-blue-600 text-white px-4 py-2 rounded">Save</button>
<button on:click={() => showApprovalModal = false} class="px-4 py-2 rounded border">Cancel</button>
</div>
</div>
</div>
</div>
{/if}
{#if showAcknowledgedModal}
<div class="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50 overflow-y-auto">
<div class="min-h-screen flex items-center justify-center p-4">
<div class="bg-white rounded-lg shadow-lg w-full max-w-md max-h-[90vh] overflow-y-auto p-6 space-y-4">
<h2 class="text-xl font-bold">Acknowledge Purchase Order</h2>
<!-- PO Number -->
<label>PO Number</label>
<input
type="text"
value={acknowledgedForm.po_number}
disabled
class="w-full border p-2 bg-gray-100"
/>
<!-- Acknowledged -->
<label>Acknowledged</label>
<select bind:value={acknowledgedForm.acknowledged} class="w-full border p-2">
<option value="" disabled>Select Acknowledgement</option>
<option value="acknowledged">Acknowledged</option>
<option value="reject">Reject</option>
</select>
<!-- Hidden fields -->
<input type="hidden" value={acknowledgedForm.acknowledged_by} />
<input type="hidden" value={acknowledgedForm.acknowledged_date} />
<!-- Actions -->
<div class="flex justify-end space-x-2 pt-4">
<button on:click={saveAcknowledged} class="bg-blue-600 text-white px-4 py-2 rounded">Save</button>
<button on:click={() => showAcknowledgedModal = false} class="px-4 py-2 rounded border">Cancel</button>
</div>
</div>
</div>
</div>
{/if}
{#if showCompletedModal}
<div class="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50 overflow-y-auto">
<div class="min-h-screen flex items-center justify-center p-4">
<div class="bg-white rounded-lg shadow-lg w-full max-w-md max-h-[90vh] overflow-y-auto p-6 space-y-4">
<h2 class="text-xl font-bold">Complete Purchase Order</h2>
<!-- PO Number -->
<label>PO Number</label>
<input
type="text"
value={completedForm.po_number}
disabled
class="w-full border p-2 bg-gray-100"
/>
<!-- Completed -->
<label>Completion</label>
<select bind:value={completedForm.completed} class="w-full border p-2">
<option value="" disabled>Select Status</option>
<option value="completed">Completed</option>
<option value="reject">Reject</option>
</select>
<!-- Hidden -->
<input type="hidden" value={completedForm.completed_by} />
<input type="hidden" value={completedForm.completed_date} />
<!-- Actions -->
<div class="flex justify-end space-x-2 pt-4">
<button on:click={saveCompleted} class="bg-blue-600 text-white px-4 py-2 rounded">Save</button>
<button on:click={() => showCompletedModal = false} class="px-4 py-2 rounded border">Cancel</button>
</div>
</div>
</div>
</div>
{/if}
{#if showReceivedModal}
<div class="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50 overflow-y-auto">
<div class="min-h-screen flex items-center justify-center p-4">
<div class="bg-white rounded-lg shadow-lg w-full max-w-md max-h-[90vh] overflow-y-auto p-6 space-y-4">
<h2 class="text-xl font-bold">Receive Purchase Order</h2>
<!-- PO Number -->
<label>PO Number</label>
<input
type="text"
value={receivedForm.po_number}
disabled
class="w-full border p-2 bg-gray-100"
/>
<!-- Received -->
<label>Received</label>
<select bind:value={receivedForm.received} class="w-full border p-2">
<option value="" disabled>Select Status</option>
<option value="received">Received</option>
<option value="reject">Reject</option>
</select>
<!-- Hidden -->
<input type="hidden" value={receivedForm.received_by} />
<input type="hidden" value={receivedForm.received_date} />
<!-- Actions -->
<div class="flex justify-end space-x-2 pt-4">
<button on:click={saveReceived} class="bg-blue-600 text-white px-4 py-2 rounded">Save</button>
<button on:click={() => showReceivedModal = false} class="px-4 py-2 rounded border">Cancel</button>
</div>
</div>
</div>
</div>
{/if}