kamau1's picture
Fix: Update ON CONFLICT to use (user_id, work_date) and align reconciliation logic with deployed migrations
a9afcba
Invalid JSON: No number after minus sign in JSON at line 1, column 2
-- 1. Get all columns in timesheets table
SELECT
column_name,
data_type,
is_nullable,
column_default,
character_maximum_length
FROM information_schema.columns
WHERE table_name = 'timesheets'
ORDER BY ordinal_position;
[
{
"column_name": "id",
"data_type": "uuid",
"is_nullable": "NO",
"column_default": "gen_random_uuid()",
"character_maximum_length": null
},
{
"column_name": "user_id",
"data_type": "uuid",
"is_nullable": "NO",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "project_id",
"data_type": "uuid",
"is_nullable": "YES",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "work_date",
"data_type": "date",
"is_nullable": "NO",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "status",
"data_type": "USER-DEFINED",
"is_nullable": "NO",
"column_default": "'present'::timesheetstatus",
"character_maximum_length": null
},
{
"column_name": "check_in_time",
"data_type": "timestamp with time zone",
"is_nullable": "YES",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "check_out_time",
"data_type": "timestamp with time zone",
"is_nullable": "YES",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "hours_worked",
"data_type": "numeric",
"is_nullable": "YES",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "leave_reason",
"data_type": "text",
"is_nullable": "YES",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "leave_approved_by_user_id",
"data_type": "uuid",
"is_nullable": "YES",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "notes",
"data_type": "text",
"is_nullable": "YES",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "additional_metadata",
"data_type": "jsonb",
"is_nullable": "YES",
"column_default": "'{}'::jsonb",
"character_maximum_length": null
},
{
"column_name": "created_at",
"data_type": "timestamp with time zone",
"is_nullable": "YES",
"column_default": "timezone('utc'::text, now())",
"character_maximum_length": null
},
{
"column_name": "updated_at",
"data_type": "timestamp with time zone",
"is_nullable": "YES",
"column_default": "timezone('utc'::text, now())",
"character_maximum_length": null
},
{
"column_name": "deleted_at",
"data_type": "timestamp with time zone",
"is_nullable": "YES",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "tickets_assigned",
"data_type": "integer",
"is_nullable": "NO",
"column_default": "0",
"character_maximum_length": null
},
{
"column_name": "tickets_completed",
"data_type": "integer",
"is_nullable": "NO",
"column_default": "0",
"character_maximum_length": null
},
{
"column_name": "tickets_rescheduled",
"data_type": "integer",
"is_nullable": "NO",
"column_default": "0",
"character_maximum_length": null
},
{
"column_name": "tickets_cancelled",
"data_type": "integer",
"is_nullable": "NO",
"column_default": "0",
"character_maximum_length": null
},
{
"column_name": "tickets_rejected",
"data_type": "integer",
"is_nullable": "NO",
"column_default": "0",
"character_maximum_length": null
},
{
"column_name": "is_payroll_generated",
"data_type": "boolean",
"is_nullable": "NO",
"column_default": "false",
"character_maximum_length": null
},
{
"column_name": "payroll_id",
"data_type": "uuid",
"is_nullable": "YES",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "total_expenses",
"data_type": "numeric",
"is_nullable": "YES",
"column_default": "0",
"character_maximum_length": null
},
{
"column_name": "approved_expenses",
"data_type": "numeric",
"is_nullable": "YES",
"column_default": "0",
"character_maximum_length": null
},
{
"column_name": "pending_expenses",
"data_type": "numeric",
"is_nullable": "YES",
"column_default": "0",
"character_maximum_length": null
},
{
"column_name": "rejected_expenses",
"data_type": "numeric",
"is_nullable": "YES",
"column_default": "0",
"character_maximum_length": null
},
{
"column_name": "expense_claims_count",
"data_type": "integer",
"is_nullable": "YES",
"column_default": "0",
"character_maximum_length": null
},
{
"column_name": "reconciliation_run_id",
"data_type": "uuid",
"is_nullable": "YES",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "last_reconciled_at",
"data_type": "timestamp with time zone",
"is_nullable": "YES",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "update_source",
"data_type": "text",
"is_nullable": "YES",
"column_default": "'realtime'::text",
"character_maximum_length": null
},
{
"column_name": "last_realtime_update_at",
"data_type": "timestamp with time zone",
"is_nullable": "YES",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "last_validated_at",
"data_type": "timestamp with time zone",
"is_nullable": "YES",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "needs_review",
"data_type": "boolean",
"is_nullable": "YES",
"column_default": "false",
"character_maximum_length": null
},
{
"column_name": "discrepancy_notes",
"data_type": "text",
"is_nullable": "YES",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "version",
"data_type": "integer",
"is_nullable": "NO",
"column_default": "1",
"character_maximum_length": null
},
{
"column_name": "inventory_issued_count",
"data_type": "integer",
"is_nullable": "YES",
"column_default": "0",
"character_maximum_length": null
},
{
"column_name": "inventory_issued_value",
"data_type": "numeric",
"is_nullable": "YES",
"column_default": "0",
"character_maximum_length": null
},
{
"column_name": "inventory_installed_count",
"data_type": "integer",
"is_nullable": "YES",
"column_default": "0",
"character_maximum_length": null
},
{
"column_name": "inventory_consumed_count",
"data_type": "integer",
"is_nullable": "YES",
"column_default": "0",
"character_maximum_length": null
},
{
"column_name": "inventory_returned_count",
"data_type": "integer",
"is_nullable": "YES",
"column_default": "0",
"character_maximum_length": null
},
{
"column_name": "inventory_returned_value",
"data_type": "numeric",
"is_nullable": "YES",
"column_default": "0",
"character_maximum_length": null
},
{
"column_name": "inventory_lost_count",
"data_type": "integer",
"is_nullable": "YES",
"column_default": "0",
"character_maximum_length": null
},
{
"column_name": "inventory_damaged_count",
"data_type": "integer",
"is_nullable": "YES",
"column_default": "0",
"character_maximum_length": null
},
{
"column_name": "inventory_loss_value",
"data_type": "numeric",
"is_nullable": "YES",
"column_default": "0",
"character_maximum_length": null
},
{
"column_name": "inventory_on_hand_count",
"data_type": "integer",
"is_nullable": "YES",
"column_default": "0",
"character_maximum_length": null
},
{
"column_name": "inventory_on_hand_value",
"data_type": "numeric",
"is_nullable": "YES",
"column_default": "0",
"character_maximum_length": null
},
{
"column_name": "inventory_details",
"data_type": "jsonb",
"is_nullable": "YES",
"column_default": "'[]'::jsonb",
"character_maximum_length": null
}
]
-- 2. Get all columns in reconciliation_runs table
SELECT
column_name,
data_type,
is_nullable,
column_default,
character_maximum_length
FROM information_schema.columns
WHERE table_name = 'reconciliation_runs'
ORDER BY ordinal_position;
[
{
"column_name": "id",
"data_type": "uuid",
"is_nullable": "NO",
"column_default": "gen_random_uuid()",
"character_maximum_length": null
},
{
"column_name": "project_id",
"data_type": "uuid",
"is_nullable": "NO",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "reconciliation_date",
"data_type": "date",
"is_nullable": "NO",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "run_type",
"data_type": "text",
"is_nullable": "NO",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "started_at",
"data_type": "timestamp with time zone",
"is_nullable": "NO",
"column_default": "timezone('utc'::text, now())",
"character_maximum_length": null
},
{
"column_name": "completed_at",
"data_type": "timestamp with time zone",
"is_nullable": "YES",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "status",
"data_type": "text",
"is_nullable": "NO",
"column_default": "'running'::text",
"character_maximum_length": null
},
{
"column_name": "user_ids",
"data_type": "ARRAY",
"is_nullable": "YES",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "agents_processed",
"data_type": "integer",
"is_nullable": "YES",
"column_default": "0",
"character_maximum_length": null
},
{
"column_name": "timesheets_created",
"data_type": "integer",
"is_nullable": "YES",
"column_default": "0",
"character_maximum_length": null
},
{
"column_name": "timesheets_updated",
"data_type": "integer",
"is_nullable": "YES",
"column_default": "0",
"character_maximum_length": null
},
{
"column_name": "assignments_processed",
"data_type": "integer",
"is_nullable": "YES",
"column_default": "0",
"character_maximum_length": null
},
{
"column_name": "expenses_processed",
"data_type": "integer",
"is_nullable": "YES",
"column_default": "0",
"character_maximum_length": null
},
{
"column_name": "execution_time_ms",
"data_type": "integer",
"is_nullable": "YES",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "query_time_ms",
"data_type": "integer",
"is_nullable": "YES",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "summary_stats",
"data_type": "jsonb",
"is_nullable": "YES",
"column_default": "'{}'::jsonb",
"character_maximum_length": null
},
{
"column_name": "anomalies_detected",
"data_type": "jsonb",
"is_nullable": "YES",
"column_default": "'[]'::jsonb",
"character_maximum_length": null
},
{
"column_name": "error_message",
"data_type": "text",
"is_nullable": "YES",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "error_details",
"data_type": "jsonb",
"is_nullable": "YES",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "triggered_by_user_id",
"data_type": "uuid",
"is_nullable": "YES",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "created_at",
"data_type": "timestamp with time zone",
"is_nullable": "YES",
"column_default": "timezone('utc'::text, now())",
"character_maximum_length": null
},
{
"column_name": "updated_at",
"data_type": "timestamp with time zone",
"is_nullable": "YES",
"column_default": "timezone('utc'::text, now())",
"character_maximum_length": null
},
{
"column_name": "deleted_at",
"data_type": "timestamp with time zone",
"is_nullable": "YES",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "discrepancies_found",
"data_type": "integer",
"is_nullable": "YES",
"column_default": "0",
"character_maximum_length": null
},
{
"column_name": "orphaned_records_found",
"data_type": "integer",
"is_nullable": "YES",
"column_default": "0",
"character_maximum_length": null
},
{
"column_name": "corrections_made",
"data_type": "integer",
"is_nullable": "YES",
"column_default": "0",
"character_maximum_length": null
},
{
"column_name": "discrepancy_details",
"data_type": "jsonb",
"is_nullable": "YES",
"column_default": "'[]'::jsonb",
"character_maximum_length": null
}
]
-- 3. Get all columns in timesheet_updates table
SELECT
column_name,
data_type,
is_nullable,
column_default,
character_maximum_length
FROM information_schema.columns
WHERE table_name = 'timesheet_updates'
ORDER BY ordinal_position;
[
{
"column_name": "id",
"data_type": "uuid",
"is_nullable": "NO",
"column_default": "gen_random_uuid()",
"character_maximum_length": null
},
{
"column_name": "timesheet_id",
"data_type": "uuid",
"is_nullable": "NO",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "trigger_type",
"data_type": "text",
"is_nullable": "NO",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "trigger_entity_type",
"data_type": "text",
"is_nullable": "YES",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "trigger_entity_id",
"data_type": "uuid",
"is_nullable": "YES",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "fields_changed",
"data_type": "jsonb",
"is_nullable": "NO",
"column_default": "'{}'::jsonb",
"character_maximum_length": null
},
{
"column_name": "updated_by_user_id",
"data_type": "uuid",
"is_nullable": "YES",
"column_default": null,
"character_maximum_length": null
},
{
"column_name": "updated_at",
"data_type": "timestamp with time zone",
"is_nullable": "YES",
"column_default": "now()",
"character_maximum_length": null
},
{
"column_name": "additional_metadata",
"data_type": "jsonb",
"is_nullable": "YES",
"column_default": "'{}'::jsonb",
"character_maximum_length": null
},
{
"column_name": "created_at",
"data_type": "timestamp with time zone",
"is_nullable": "YES",
"column_default": "now()",
"character_maximum_length": null
}
]
-- 4. Get all indexes on timesheets
SELECT
indexname,
indexdef
FROM pg_indexes
WHERE tablename = 'timesheets'
ORDER BY indexname;
[
{
"indexname": "idx_timesheets_inventory_details_gin",
"indexdef": "CREATE INDEX idx_timesheets_inventory_details_gin ON public.timesheets USING gin (inventory_details)"
},
{
"indexname": "idx_timesheets_inventory_loss",
"indexdef": "CREATE INDEX idx_timesheets_inventory_loss ON public.timesheets USING btree (work_date, inventory_lost_count, inventory_damaged_count) WHERE (((inventory_lost_count > 0) OR (inventory_damaged_count > 0)) AND (deleted_at IS NULL))"
},
{
"indexname": "idx_timesheets_inventory_on_hand",
"indexdef": "CREATE INDEX idx_timesheets_inventory_on_hand ON public.timesheets USING btree (user_id, work_date, inventory_on_hand_count) WHERE ((inventory_on_hand_count > 0) AND (deleted_at IS NULL))"
},
{
"indexname": "idx_timesheets_metadata_gin",
"indexdef": "CREATE INDEX idx_timesheets_metadata_gin ON public.timesheets USING gin (additional_metadata)"
},
{
"indexname": "idx_timesheets_needs_review",
"indexdef": "CREATE INDEX idx_timesheets_needs_review ON public.timesheets USING btree (needs_review, last_validated_at) WHERE ((needs_review = true) AND (deleted_at IS NULL))"
},
{
"indexname": "idx_timesheets_payroll",
"indexdef": "CREATE INDEX idx_timesheets_payroll ON public.timesheets USING btree (payroll_id) WHERE (payroll_id IS NOT NULL)"
},
{
"indexname": "idx_timesheets_payroll_status",
"indexdef": "CREATE INDEX idx_timesheets_payroll_status ON public.timesheets USING btree (user_id, is_payroll_generated, work_date DESC)"
},
{
"indexname": "idx_timesheets_project",
"indexdef": "CREATE INDEX idx_timesheets_project ON public.timesheets USING btree (project_id, work_date DESC) WHERE (deleted_at IS NULL)"
},
{
"indexname": "idx_timesheets_project_date",
"indexdef": "CREATE INDEX idx_timesheets_project_date ON public.timesheets USING btree (project_id, work_date DESC) WHERE (deleted_at IS NULL)"
},
{
"indexname": "idx_timesheets_realtime_updates",
"indexdef": "CREATE INDEX idx_timesheets_realtime_updates ON public.timesheets USING btree (user_id, work_date, last_realtime_update_at DESC) WHERE (deleted_at IS NULL)"
},
{
"indexname": "idx_timesheets_reconciliation_run",
"indexdef": "CREATE INDEX idx_timesheets_reconciliation_run ON public.timesheets USING btree (reconciliation_run_id) WHERE (deleted_at IS NULL)"
},
{
"indexname": "idx_timesheets_ticket_metrics",
"indexdef": "CREATE INDEX idx_timesheets_ticket_metrics ON public.timesheets USING btree (work_date, tickets_completed) WHERE (tickets_completed > 0)"
},
{
"indexname": "idx_timesheets_unique",
"indexdef": "CREATE UNIQUE INDEX idx_timesheets_unique ON public.timesheets USING btree (user_id, project_id, work_date) WHERE (deleted_at IS NULL)"
},
{
"indexname": "idx_timesheets_user",
"indexdef": "CREATE INDEX idx_timesheets_user ON public.timesheets USING btree (user_id, work_date DESC) WHERE (deleted_at IS NULL)"
},
{
"indexname": "idx_timesheets_user_date_unique",
"indexdef": "CREATE UNIQUE INDEX idx_timesheets_user_date_unique ON public.timesheets USING btree (user_id, work_date) WHERE (deleted_at IS NULL)"
},
{
"indexname": "timesheets_pkey",
"indexdef": "CREATE UNIQUE INDEX timesheets_pkey ON public.timesheets USING btree (id)"
}
]
-- 5. Get all indexes on reconciliation_runs
SELECT
indexname,
indexdef
FROM pg_indexes
WHERE tablename = 'reconciliation_runs'
ORDER BY indexname;
[
{
"indexname": "idx_reconciliation_runs_anomalies_gin",
"indexdef": "CREATE INDEX idx_reconciliation_runs_anomalies_gin ON public.reconciliation_runs USING gin (anomalies_detected)"
},
{
"indexname": "idx_reconciliation_runs_discrepancies",
"indexdef": "CREATE INDEX idx_reconciliation_runs_discrepancies ON public.reconciliation_runs USING btree (discrepancies_found, reconciliation_date DESC) WHERE (discrepancies_found > 0)"
},
{
"indexname": "idx_reconciliation_runs_project_date",
"indexdef": "CREATE INDEX idx_reconciliation_runs_project_date ON public.reconciliation_runs USING btree (project_id, reconciliation_date DESC) WHERE (deleted_at IS NULL)"
},
{
"indexname": "idx_reconciliation_runs_status",
"indexdef": "CREATE INDEX idx_reconciliation_runs_status ON public.reconciliation_runs USING btree (status, started_at DESC) WHERE (deleted_at IS NULL)"
},
{
"indexname": "idx_reconciliation_runs_summary_gin",
"indexdef": "CREATE INDEX idx_reconciliation_runs_summary_gin ON public.reconciliation_runs USING gin (summary_stats)"
},
{
"indexname": "idx_reconciliation_runs_triggered_by",
"indexdef": "CREATE INDEX idx_reconciliation_runs_triggered_by ON public.reconciliation_runs USING btree (triggered_by_user_id, started_at DESC) WHERE (deleted_at IS NULL)"
},
{
"indexname": "idx_reconciliation_runs_unique_active_run",
"indexdef": "CREATE UNIQUE INDEX idx_reconciliation_runs_unique_active_run ON public.reconciliation_runs USING btree (project_id, reconciliation_date, status) WHERE ((status = 'running'::text) AND (deleted_at IS NULL))"
},
{
"indexname": "reconciliation_runs_pkey",
"indexdef": "CREATE UNIQUE INDEX reconciliation_runs_pkey ON public.reconciliation_runs USING btree (id)"
}
]
-- 6. Get all indexes on timesheet_updates
SELECT
indexname,
indexdef
FROM pg_indexes
WHERE tablename = 'timesheet_updates'
ORDER BY indexname;
[
{
"indexname": "idx_timesheet_updates_entity",
"indexdef": "CREATE INDEX idx_timesheet_updates_entity ON public.timesheet_updates USING btree (trigger_entity_type, trigger_entity_id) WHERE (trigger_entity_id IS NOT NULL)"
},
{
"indexname": "idx_timesheet_updates_fields_gin",
"indexdef": "CREATE INDEX idx_timesheet_updates_fields_gin ON public.timesheet_updates USING gin (fields_changed)"
},
{
"indexname": "idx_timesheet_updates_timesheet",
"indexdef": "CREATE INDEX idx_timesheet_updates_timesheet ON public.timesheet_updates USING btree (timesheet_id, updated_at DESC)"
},
{
"indexname": "idx_timesheet_updates_trigger",
"indexdef": "CREATE INDEX idx_timesheet_updates_trigger ON public.timesheet_updates USING btree (trigger_type, updated_at DESC)"
},
{
"indexname": "timesheet_updates_pkey",
"indexdef": "CREATE UNIQUE INDEX timesheet_updates_pkey ON public.timesheet_updates USING btree (id)"
}
]
-- 7. Get all constraints on timesheets
SELECT
conname AS constraint_name,
contype AS constraint_type,
pg_get_constraintdef(oid) AS constraint_definition
FROM pg_constraint
WHERE conrelid = 'timesheets'::regclass
ORDER BY conname;
[
{
"constraint_name": "chk_check_times",
"constraint_type": "c",
"constraint_definition": "CHECK (((check_out_time IS NULL) OR (check_in_time IS NULL) OR (check_out_time >= check_in_time)))"
},
{
"constraint_name": "chk_valid_hours",
"constraint_type": "c",
"constraint_definition": "CHECK (((hours_worked IS NULL) OR ((hours_worked >= (0)::numeric) AND (hours_worked <= (24)::numeric))))"
},
{
"constraint_name": "timesheets_approved_expenses_check",
"constraint_type": "c",
"constraint_definition": "CHECK ((approved_expenses >= (0)::numeric))"
},
{
"constraint_name": "timesheets_expense_claims_count_check",
"constraint_type": "c",
"constraint_definition": "CHECK ((expense_claims_count >= 0))"
},
{
"constraint_name": "timesheets_inventory_consumed_count_check",
"constraint_type": "c",
"constraint_definition": "CHECK ((inventory_consumed_count >= 0))"
},
{
"constraint_name": "timesheets_inventory_damaged_count_check",
"constraint_type": "c",
"constraint_definition": "CHECK ((inventory_damaged_count >= 0))"
},
{
"constraint_name": "timesheets_inventory_installed_count_check",
"constraint_type": "c",
"constraint_definition": "CHECK ((inventory_installed_count >= 0))"
},
{
"constraint_name": "timesheets_inventory_issued_count_check",
"constraint_type": "c",
"constraint_definition": "CHECK ((inventory_issued_count >= 0))"
},
{
"constraint_name": "timesheets_inventory_issued_value_check",
"constraint_type": "c",
"constraint_definition": "CHECK ((inventory_issued_value >= (0)::numeric))"
},
{
"constraint_name": "timesheets_inventory_loss_value_check",
"constraint_type": "c",
"constraint_definition": "CHECK ((inventory_loss_value >= (0)::numeric))"
},
{
"constraint_name": "timesheets_inventory_lost_count_check",
"constraint_type": "c",
"constraint_definition": "CHECK ((inventory_lost_count >= 0))"
},
{
"constraint_name": "timesheets_inventory_on_hand_count_check",
"constraint_type": "c",
"constraint_definition": "CHECK ((inventory_on_hand_count >= 0))"
},
{
"constraint_name": "timesheets_inventory_on_hand_value_check",
"constraint_type": "c",
"constraint_definition": "CHECK ((inventory_on_hand_value >= (0)::numeric))"
},
{
"constraint_name": "timesheets_inventory_returned_count_check",
"constraint_type": "c",
"constraint_definition": "CHECK ((inventory_returned_count >= 0))"
},
{
"constraint_name": "timesheets_inventory_returned_value_check",
"constraint_type": "c",
"constraint_definition": "CHECK ((inventory_returned_value >= (0)::numeric))"
},
{
"constraint_name": "timesheets_leave_approved_by_user_id_fkey",
"constraint_type": "f",
"constraint_definition": "FOREIGN KEY (leave_approved_by_user_id) REFERENCES users(id) ON DELETE SET NULL"
},
{
"constraint_name": "timesheets_payroll_id_fkey",
"constraint_type": "f",
"constraint_definition": "FOREIGN KEY (payroll_id) REFERENCES user_payroll(id) ON DELETE SET NULL"
},
{
"constraint_name": "timesheets_pending_expenses_check",
"constraint_type": "c",
"constraint_definition": "CHECK ((pending_expenses >= (0)::numeric))"
},
{
"constraint_name": "timesheets_pkey",
"constraint_type": "p",
"constraint_definition": "PRIMARY KEY (id)"
},
{
"constraint_name": "timesheets_project_id_fkey",
"constraint_type": "f",
"constraint_definition": "FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE"
},
{
"constraint_name": "timesheets_reconciliation_run_id_fkey",
"constraint_type": "f",
"constraint_definition": "FOREIGN KEY (reconciliation_run_id) REFERENCES reconciliation_runs(id) ON DELETE SET NULL"
},
{
"constraint_name": "timesheets_rejected_expenses_check",
"constraint_type": "c",
"constraint_definition": "CHECK ((rejected_expenses >= (0)::numeric))"
},
{
"constraint_name": "timesheets_total_expenses_check",
"constraint_type": "c",
"constraint_definition": "CHECK ((total_expenses >= (0)::numeric))"
},
{
"constraint_name": "timesheets_update_source_check",
"constraint_type": "c",
"constraint_definition": "CHECK ((update_source = ANY (ARRAY['realtime'::text, 'scheduled'::text, 'manual'::text])))"
},
{
"constraint_name": "timesheets_user_id_fkey",
"constraint_type": "f",
"constraint_definition": "FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE"
}
]
-- 8. Check if specific columns exist (quick verification)
SELECT
EXISTS(SELECT 1 FROM information_schema.columns WHERE table_name = 'timesheets' AND column_name = 'total_expenses') as has_total_expenses,
EXISTS(SELECT 1 FROM information_schema.columns WHERE table_name = 'timesheets' AND column_name = 'approved_expenses') as has_approved_expenses,
EXISTS(SELECT 1 FROM information_schema.columns WHERE table_name = 'timesheets' AND column_name = 'pending_expenses') as has_pending_expenses,
EXISTS(SELECT 1 FROM information_schema.columns WHERE table_name = 'timesheets' AND column_name = 'rejected_expenses') as has_rejected_expenses,
EXISTS(SELECT 1 FROM information_schema.columns WHERE table_name = 'timesheets' AND column_name = 'expense_claims_count') as has_expense_claims_count,
EXISTS(SELECT 1 FROM information_schema.columns WHERE table_name = 'timesheets' AND column_name = 'update_source') as has_update_source,
EXISTS(SELECT 1 FROM information_schema.columns WHERE table_name = 'timesheets' AND column_name = 'last_realtime_update_at') as has_last_realtime_update_at,
EXISTS(SELECT 1 FROM information_schema.columns WHERE table_name = 'timesheets' AND column_name = 'check_in_time') as has_check_in_time,
EXISTS(SELECT 1 FROM information_schema.columns WHERE table_name = 'timesheets' AND column_name = 'clock_in_time') as has_clock_in_time,
EXISTS(SELECT 1 FROM information_schema.columns WHERE table_name = 'timesheets' AND column_name = 'inventory_on_hand_count') as has_inventory_on_hand_count,
EXISTS(SELECT 1 FROM information_schema.columns WHERE table_name = 'timesheets' AND column_name = 'inventory_issued_count') as has_inventory_issued_count;
[
{
"has_total_expenses": true,
"has_approved_expenses": true,
"has_pending_expenses": true,
"has_rejected_expenses": true,
"has_expense_claims_count": true,
"has_update_source": true,
"has_last_realtime_update_at": true,
"has_check_in_time": true,
"has_clock_in_time": false,
"has_inventory_on_hand_count": true,
"has_inventory_issued_count": true
}
]