penambahan menu approval per po per proses

This commit is contained in:
Aji Setiaji
2025-05-30 21:59:22 +07:00
parent ec9d47846e
commit 4126f378f5
6 changed files with 239 additions and 195 deletions

View File

@@ -8,12 +8,8 @@
prepared_date: string;
po_type: string;
po_quantity: number;
po_status: string;
approved_vendor: string;
acknowledge_by: string;
approved_by: string;
approved_price: number;
completed_status: string;
po_price: number;
po_total_price: number;
};
let purchaseOrderInsert: PurchaseOrderInsert = {
@@ -21,12 +17,8 @@
prepared_date: "",
po_type: "",
po_quantity: 0,
po_status: "REQUESTED",
approved_vendor: "",
acknowledge_by: "",
approved_by: "",
approved_price: 0,
completed_status: "",
po_price: 0,
po_total_price: 0,
};
type PurchaseOrders = {
@@ -37,6 +29,7 @@
po_quantity: number;
po_status: string;
approved_vendor: string;
proses_to_approval: boolean;
acknowledged: boolean;
approved_vendor_id: string;
acknowledge_by: string;
@@ -62,6 +55,8 @@
prepared_date: string;
po_type: string;
po_quantity: number;
po_price: number;
po_total_price: number;
po_status: string;
approved_vendor: string;
acknowledged: boolean;
@@ -70,6 +65,7 @@
approved_price: number;
approved_quantity: number;
total_approved_order_amount: number;
proses_to_approval: boolean;
approval: string;
completed_status: string;
received: boolean;
@@ -91,7 +87,10 @@
{ key: "prepared_date", title: "Prepared Date" },
{ key: "po_type", title: "PO Type" },
{ key: "po_quantity", title: "PO Quantity" },
{ key: "po_price", title: "PO Price" },
{ key: "po_total_price", title: "PO Total Price" },
{ key: "po_status", title: "PO Status" },
{ key: "proses_to_approval", title: "PROSES TO APPROVAL" },
{ key: "approved_vendor", title: "Approved Vendor" },
{ key: "acknowledged", title: "Acknowledged" },
{ key: "acknowledge_by", title: "Acknowledged By" },
@@ -132,9 +131,7 @@
) {
let query = supabase
.from("purchaseorder_data")
.select(
"id, purchase_order_number, villa_data, issue_id, prepared_date, po_type, po_quantity, po_status, approved_vendor, acknowledged, acknowledge_by, approved_price, approved_quantity, total_approved_order_amount, approval, completed_status, received, received_by, input_by, approved_by, created_at",
)
.select("*")
.order(sort || "created_at", { ascending: order === "asc" })
.range(offset, offset + limit - 1);
if (filter) {
@@ -172,7 +169,7 @@
}
// masukkan villa name dan issue name ke dalam data
allRows = data.map((row) => {
allRows = data.map((row: any) => {
const issue = issues.find((issue) => issue.id === row.issue_id);
const villa = villas.find((villa) => villa.id === issue.villa_id);
const vendor = vendors.find(
@@ -189,6 +186,9 @@
: "Unknown Approved Vendor",
approval: row.approval || "",
completed_status: row.completed_status || "",
proses_to_approval: row.proses_to_approval || false,
po_price: row.po_price || 0,
po_total_price: row.po_total_price || 0,
} as PurchaseOrderDisplay;
});
}
@@ -255,11 +255,14 @@
"completed_status",
"received",
"received_by",
"approved_quantity",
"total_approved_order_amount",
"proses_to_approval",
"approved_by",
"name",
"po_status",
"approved_quantity",
"total_approved_order_amount",
"approved_vendor",
"approved_price",
];
const formColumns = columns.filter(
(col) => !excludedKeys.includes(col.key),
@@ -280,17 +283,18 @@
}
async function saveProject() {
if (!validateInput()) {
return;
}
purchaseOrderInsert = {
issue_id: newPurchaseOrders.issue_id || "",
prepared_date: newPurchaseOrders.prepared_date || "",
po_type: newPurchaseOrders.po_type || "",
po_quantity: newPurchaseOrders.po_quantity || 0,
po_status: newPurchaseOrders.po_status || "REQUESTED",
approved_vendor: newPurchaseOrders.approved_vendor || "",
acknowledge_by: newPurchaseOrders.acknowledge_by || "",
approved_price: newPurchaseOrders.approved_price || "",
approved_by: newPurchaseOrders.approved_by || "",
completed_status: newPurchaseOrders.completed_status || "",
po_price: newPurchaseOrders.po_price || 0,
po_total_price:
newPurchaseOrders.po_quantity * newPurchaseOrders.po_price || 0,
};
if (isEditing && currentEditingId) {
@@ -339,12 +343,12 @@
{ label: "Acknowledged", value: "ACKNOWLEDGE", color: "#60a5fa" },
{
label: "Received - Incomplete",
value: "RECEIVE - INCOMPLETE",
value: "RECEIVED INCOMPLETE",
color: "#fb923c",
},
{
label: "Received - Completed",
value: "RECEIVE COMPLETED",
value: "RECEIVED COMPLETED",
color: "#10b981",
},
{ label: "Canceled", value: "CANCELED", color: "#f87171" },
@@ -360,7 +364,7 @@
"prepared_date",
"po_type",
"po_quantity",
"approved_vendor",
"po_price",
];
for (const field of requiredFields) {
if (!newPurchaseOrders[field]) {
@@ -382,6 +386,38 @@
return true;
}
function validateInputProsesToAprroval() {
const requiredFields = ["po_type", "po_quantity", "po_price"];
for (const field of requiredFields) {
if (!newPurchaseOrders[field]) {
alert(`Please fill in the ${field} field.`);
return false;
}
}
return true;
}
async function updateProsesToApproval(id: string, status: boolean) {
if (!validateInputProsesToAprroval()) {
return;
}
const { data, error } = await supabase
.from("purchase_orders")
.update({ proses_to_approval: status, po_status: "REQUESTED" })
.eq("id", id);
if (error) {
console.error(
"Error updating purchase order proses to approval:",
error,
);
return;
}
await fetchPurchaseOrder();
}
async function updatePurchaseOrderStatus(
e: Event,
id: string,
@@ -600,6 +636,42 @@
>
</select>
</td>
{:else if col.key === "proses_to_approval"}
<td class="px-4 py-2">
<!-- checkbox -->
<input
type="checkbox"
checked={row.proses_to_approval}
on:change={(e) => {
const isChecked = (
e.target as HTMLInputElement
).checked;
if (isChecked) {
newPurchaseOrders = {
...row,
proses_to_approval: true,
};
// map to project
updateProsesToApproval(
row.id,
isChecked,
);
} else {
newPurchaseOrders = {
...row,
proses_to_approval: false,
};
// uncheck
updateProsesToApproval(
row.id,
false,
);
}
}}
disabled={row.proses_to_approval}
/>
</td>
{:else if col.key === "acknowledged"}
<td class="px-4 py-2 text-center">
<input
@@ -671,10 +743,10 @@
<option value="" disabled selected
>ON PROSES</option
>
<option value="APPROVED"
<option value="RECEIVED COMPLETE"
>RECEIVED COMPLETE</option
>
<option value="REJECTED"
<option value="RECEIVED INCOMPLETE"
>COMPLETE INCOMPLETE</option
>
</select>
@@ -694,27 +766,6 @@
🗑️ Delete
</button>
</td>
{:else if col.key === "move_issue"}
<td class="px-4 py-2">
<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"
on:click={() =>
alert(
`Move issue ${row.id} to project`,
)}
>
➡️ PROJECT
</button>
<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"
on:click={() =>
alert(
`Move issue ${row.id} to another area`,
)}
>
➡️ PURCHASE ORDER
</button>
</td>
{:else}
<td class="px-4 py-2 text-gray-700"
>{row[
@@ -795,6 +846,7 @@
(e.target as HTMLSelectElement)?.value ?? "";
newPurchaseOrders.issue_id = selectedIssue;
}}
disabled
>
<option value="">Select Issue</option>
{#each issues as issue}
@@ -873,6 +925,23 @@
class="w-full px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring focus:ring-blue-500"
/>
</div>
{:else if col.key === "po_price"}
<div class="mb-4">
<label
for={col.key}
class="block text-sm font-medium text-gray-700 mb-1"
>
{col.title}
</label>
<input
name="po_price"
placeholder="Enter PO Price"
type="number"
id={col.key}
bind:value={newPurchaseOrders[col.key]}
class="w-full px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring focus:ring-blue-500"
/>
</div>
{:else if col.key === "po_quantity"}
<div class="mb-4">
<label
@@ -882,12 +951,33 @@
{col.title}
</label>
<input
name="po_quantity"
placeholder="Enter PO Quantity"
type="number"
id={col.key}
bind:value={newPurchaseOrders[col.key]}
class="w-full px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring focus:ring-blue-500"
/>
</div>
{:else if col.key === "po_total_price"}
<div class="mb-4">
<label
for={col.key}
class="block text-sm font-medium text-gray-700 mb-1"
>
{col.title}
</label>
<!-- calculate po quantity * price -->
<input
name="po_total_price"
type="number"
id={col.key}
class="w-full px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring focus:ring-blue-500"
readonly
value={newPurchaseOrders.po_quantity *
newPurchaseOrders.po_price}
/>
</div>
{:else if col.key === "approved_price"}
<div class="mb-4">
<label