po Request form

This commit is contained in:
2025-07-23 10:20:05 +08:00
parent fafe505b5a
commit 36a27b8844

View File

@@ -3,24 +3,9 @@
import { supabase } from "$lib/supabaseClient"; import { supabase } from "$lib/supabaseClient";
import logo from "$lib/images/logo.webp"; import logo from "$lib/images/logo.webp";
type TimesheetForm = { type POItem = {
entered_by: string; id: string;
work_description: string; item_name: string;
type_of_work: "Running" | "Periodic" | "Irregular";
category_of_work:
| "Cleaning"
| "Gardening/Pool"
| "Maintenance"
| "Supervision"
| "Guest Service"
| "Administration"
| "Non Billable";
villa_id: string;
datetime_in: string;
datetime_out: string;
total_work_hour: number;
remarks: string;
approval: boolean | null; // Allow null for new entries
}; };
type Villa = { type Villa = {
@@ -33,37 +18,20 @@
name: string; name: string;
}; };
let employees: Employee[] = []; let poItemOptions: POItem[] = [];
let villas: Villa[] = []; let villas: Villa[] = [];
let employees: Employee[] = [];
let form: TimesheetForm = { let addPOForm = {
entered_by: "", po_type: "",
work_description: "",
type_of_work: "Running",
category_of_work: "Cleaning",
villa_id: "", villa_id: "",
datetime_in: "", po_item: "",
datetime_out: "", po_quantity: 0,
total_work_hour: 0, po_remark: "",
remarks: "", requested_by: "",
approval: null, // Default null requested_date: ""
}; };
const typeOfWorkOptions: TimesheetForm["type_of_work"][] = [
"Running",
"Periodic",
"Irregular",
];
const categoryOptions: TimesheetForm["category_of_work"][] = [
"Cleaning",
"Gardening/Pool",
"Maintenance",
"Supervision",
"Guest Service",
"Administration",
"Non Billable",
];
onMount(async () => { onMount(async () => {
// Fetch villas // Fetch villas
const { data: villaData, error: villaError } = await supabase const { data: villaData, error: villaError } = await supabase
@@ -90,49 +58,58 @@
} else if (empData) { } else if (empData) {
employees = empData.map((e) => ({ id: e.id, name: e.employee_name })); employees = empData.map((e) => ({ id: e.id, name: e.employee_name }));
} }
// Fetch PO Items
const { data: poItemData, error: poItemError } = await supabase
.from("vb_po_item")
.select("id, item_name")
.order("item_name", { ascending: true });
if (poItemError) {
console.error("Failed to fetch PO items:", poItemError.message);
} else if (poItemData) {
poItemOptions = poItemData;
}
}); });
function calculateTotalHours() {
if (form.datetime_in && form.datetime_out) {
const start = new Date(form.datetime_in);
const end = new Date(form.datetime_out);
const diffInMs = end.getTime() - start.getTime();
const hours = diffInMs / (1000 * 60 * 60);
form.total_work_hour = Math.max(Number(hours.toFixed(2)), 0);
} else {
form.total_work_hour = 0;
}
}
async function submitForm() { async function submitForm() {
calculateTotalHours(); if (!addPOForm.requested_by) {
if (!form.entered_by) {
alert("Please select an employee."); alert("Please select an employee.");
return; return;
} }
if (!form.villa_id) { if (!addPOForm.villa_id) {
alert("Please select a villa."); alert("Please select a villa.");
return; return;
} }
if (!addPOForm.po_item) {
alert("Please select a PO item.");
return;
}
const { error } = await supabase.from("vb_timesheet").insert([form]); const { error } = await supabase.from("vb_purchase_orders").insert({
po_type: addPOForm.po_type,
villa_id: addPOForm.villa_id,
po_item: addPOForm.po_item,
po_quantity: addPOForm.po_quantity,
po_status: "requested",
po_remark: addPOForm.po_remark,
requested_by: addPOForm.requested_by,
requested_date: addPOForm.requested_date,
created_at: new Date().toISOString()
});
if (error) { if (error) {
alert("Failed to submit timesheet: " + error.message); alert("Failed to submit Purchase Order: " + error.message);
} else { } else {
alert("Timesheet submitted successfully!"); alert("Purchase Order submitted successfully!");
form = { addPOForm = {
entered_by: "", po_type: "",
work_description: "",
type_of_work: "Running",
category_of_work: "Cleaning",
villa_id: "", villa_id: "",
datetime_in: "", po_item: "",
datetime_out: "", po_quantity: 0,
total_work_hour: 0, po_remark: "",
remarks: "", requested_by: "",
approval: null, requested_date: ""
}; };
} }
} }
@@ -148,127 +125,64 @@
<h2 class="text-2xl font-bold text-center mb-6">Timesheet Entry</h2> <h2 class="text-2xl font-bold text-center mb-6">Timesheet Entry</h2>
<div> <div>
<label for="t_eb" class="block text-sm font-medium mb-1">Entered By</label <label>PO Type</label>
> <select bind:value={addPOForm.po_type} class="w-full border p-2">
<select <option value="" disabled>Select PO Type</option>
id="t_eb" <option value="purchase">Purchase</option>
class="w-full border p-2 rounded" <option value="project">Project</option>
bind:value={form.entered_by} <option value="repair">Repair</option>
required </select>
>
<option value="" disabled selected>Select Employee</option>
{#each employees as employee}
<option value={employee.id}>{employee.name}</option>
{/each}
</select>
</div> </div>
<div> <div>
<label for="t_wd" class="block text-sm font-medium mb-1" <label>Villa</label>
>Work Description</label <select bind:value={addPOForm.villa_id} class="w-full border p-2">
> <option value="" disabled>Select Villa</option>
<textarea {#each villas as v}
id="t_wd" <option value={v.id}>{v.name}</option>
class="w-full border border-gray-300 p-2 rounded" {/each}
bind:value={form.work_description} </select>
placeholder="Describe the work"
required
></textarea>
</div> </div>
<div> <div>
<label for="t_ow" class="block text-sm font-medium mb-1" <label>PO Item</label>
>Type of Work</label <select bind:value={addPOForm.po_item} class="w-full border p-2">
> <option value="" disabled>Select Item</option>
<select {#each poItemOptions as item}
id="t_ow" <option value={item.item_name}>{item.item_name}</option>
class="w-full border p-2 rounded" {/each}
bind:value={form.type_of_work} </select>
>
{#each typeOfWorkOptions as option}
<option value={option}>{option}</option>
{/each}
</select>
</div> </div>
<div> <div>
<label for="t_cow" class="block text-sm font-medium mb-1" <label>PO Quantity</label>
>Category of Work</label <input type="number" bind:value={addPOForm.po_quantity} class="w-full border p-2"/>
>
<select
id="t_cow"
class="w-full border p-2 rounded"
bind:value={form.category_of_work}
>
{#each categoryOptions as option}
<option value={option}>{option}</option>
{/each}
</select>
</div> </div>
<div> <div>
<label for="t_vn" class="block text-sm font-medium mb-1">Villa</label> <label>PO Remark</label>
<select <textarea bind:value={addPOForm.po_remark} class="w-full border p-2"></textarea>
id="t_vn"
class="w-full border p-2 rounded"
bind:value={form.villa_id}
required
>
<option value="" disabled selected>Select Villa</option>
{#each villas as villa}
<option value={villa.id}>{villa.name}</option>
{/each}
</select>
</div> </div>
<div> <div>
<label for="tdto" class="block text-sm font-medium mb-1" <label>Requested By</label>
>Date/Time In</label <select bind:value={addPOForm.requested_by} class="w-full border p-2">
> <option value="" disabled>Select Employee</option>
<input {#each employees as e}
id="tdto" <option value={e.id}>{e.name}</option>
type="datetime-local" {/each}
class="w-full border p-2 rounded" </select>
bind:value={form.datetime_in}
on:change={calculateTotalHours}
required
/>
</div> </div>
<div> <div>
<label for="dto" class="block text-sm font-medium mb-1" <label>Requested Date</label>
>Date/Time Out</label <input type="date" bind:value={addPOForm.requested_date} class="w-full border p-2"/>
>
<input
id="dto"
type="datetime-local"
class="w-full border p-2 rounded"
bind:value={form.datetime_out}
on:change={calculateTotalHours}
required
/>
</div> </div>
<div class="text-sm">
<label for="ttwo" class="block font-medium mb-1">Total Work Hours</label>
<div id="ttwo" class="px-3 py-2">{form.total_work_hour}</div>
</div>
<div>
<label for="trmk" class="block text-sm font-medium mb-1">Remarks</label>
<textarea
id="trmk"
class="w-full border border-gray-300 p-2 rounded"
bind:value={form.remarks}
placeholder="Optional remarks"
></textarea>
</div>
<button <button
type="submit" type="submit"
class="w-full bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700 transition" class="w-full bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700 transition"
> >
Submit Timesheet Submit Purchase Order
</button> </button>
</form> </form>
</div> </div>