Phase 3: Hire wizard, draft resume, and two real SQL bugfixes
- components/hire/: 4-step Hire Wizard (Person/Position/Vertrag/ Zusammenfassung) matching sec4.4, with a HireWizardProvider context so it can be opened both from the global "+ Neueinstellung" button and from a "Fortsetzen" link on a saved draft. - actions/hireDrafts.ts: save/delete hire_drafts (owner-scoped RLS already in place from Phase 1). Dashboard now shows the "Entwuerfe" card the Phase 1 plan deferred, since the wizard it depends on now exists. - lib/positions.ts: shared open-positions loader (position number, org breadcrumb, resolved manager name) used by both the wizard and (later) the Positions page. Two real bugs found via live testing and fixed in supabase/functions.sql: 1. hire_employee/rehire_employee: a two-branch CASE returning bare string literals defaults to `text`, not the target enum, so `status = case when ... then 'Geplant' else 'Aktiv' end` failed against the employment_status column. Fixed with an explicit ::employment_status cast on the whole CASE expression. 2. Postgres precedence gotcha: ->> and || sit at the *same* precedence tier and left-associate, so `payload->>'first_name' || ' ' || payload->>'last_name'` does not group the way it reads - it tries to apply ->> to an intermediate text value and fails with "operator does not exist: text ->> unknown". Fixed by parenthesizing every ->>'...' expression that participates in a || chain. Also fixed: hire_employee referenced v_position.title outside the branch that assigns v_position, raising "record not assigned" whenever a hire wasn't tied to a position_id; extracted a v_job_title variable instead. Verified live end-to-end: wizard search -> select position -> submit creates the employee, closes the position, and writes matching employee_history + audit_log rows atomically.
This commit is contained in:
@@ -74,6 +74,7 @@ declare
|
||||
v_team_id uuid;
|
||||
v_division_id uuid;
|
||||
v_position record;
|
||||
v_job_title text;
|
||||
v_email text;
|
||||
v_manager uuid;
|
||||
begin
|
||||
@@ -86,9 +87,11 @@ begin
|
||||
end if;
|
||||
v_team_id := v_position.team_id;
|
||||
v_division_id := v_position.division_id;
|
||||
v_job_title := coalesce(payload->>'job_title', v_position.title);
|
||||
else
|
||||
v_team_id := (payload->>'team_id')::uuid;
|
||||
select division_id into v_division_id from teams t join departments d on d.id = t.department_id where t.id = v_team_id;
|
||||
v_job_title := payload->>'job_title';
|
||||
end if;
|
||||
|
||||
v_manager := resolve_manager_for(v_team_id, false, v_division_id);
|
||||
@@ -103,7 +106,7 @@ begin
|
||||
payload->>'first_name', payload->>'last_name', (payload->>'gender')::gender_type,
|
||||
(payload->>'birth_date')::date, payload->>'sv_nummer', coalesce(payload->>'nationality', 'Österreich'),
|
||||
v_email, payload->>'phone',
|
||||
v_team_id, v_division_id, coalesce(payload->>'job_title', v_position.title), (payload->>'location_id')::uuid,
|
||||
v_team_id, v_division_id, v_job_title, (payload->>'location_id')::uuid,
|
||||
v_manager, 3, false,
|
||||
coalesce((payload->>'employment_type')::employment_type, 'Vollzeit'),
|
||||
coalesce((payload->>'weekly_hours')::numeric, 38.5),
|
||||
@@ -112,7 +115,7 @@ begin
|
||||
nullif(payload->>'contract_end_date', '')::date,
|
||||
coalesce((payload->>'paygrade')::paygrade_type, 'B'),
|
||||
coalesce((payload->>'source')::source_type, 'Extern'),
|
||||
case when (payload->>'entry_date')::date > current_date then 'Geplant' else 'Aktiv' end,
|
||||
(case when (payload->>'entry_date')::date > current_date then 'Geplant' else 'Aktiv' end)::employment_status,
|
||||
(payload->>'entry_date')::date
|
||||
) returning id into v_id;
|
||||
|
||||
@@ -122,10 +125,10 @@ begin
|
||||
end if;
|
||||
|
||||
insert into employee_history (employee_id, event_date, event_type, description)
|
||||
values (v_id, (payload->>'entry_date')::date, 'Eintritt', 'Eintritt als ' || coalesce(payload->>'job_title', v_position.title));
|
||||
values (v_id, (payload->>'entry_date')::date, 'Eintritt', 'Eintritt als ' || v_job_title);
|
||||
|
||||
insert into audit_log (actor_user_id, actor_name, action, target_label, target_employee_id, details)
|
||||
values (auth.uid(), current_actor_name(), 'Neueinstellung', payload->>'first_name' || ' ' || payload->>'last_name', v_id, 'Eintritt am ' || (payload->>'entry_date'));
|
||||
values (auth.uid(), current_actor_name(), 'Neueinstellung', (payload->>'first_name') || ' ' || (payload->>'last_name'), v_id, 'Eintritt am ' || (payload->>'entry_date'));
|
||||
|
||||
return v_id;
|
||||
end;
|
||||
@@ -376,7 +379,7 @@ begin
|
||||
v_manager := resolve_manager_for(v_team_id, v_is_lead, v_division_id);
|
||||
|
||||
update employees set
|
||||
status = case when v_rehire_date > current_date then 'Geplant' else 'Aktiv' end,
|
||||
status = (case when v_rehire_date > current_date then 'Geplant' else 'Aktiv' end)::employment_status,
|
||||
entry_date = v_rehire_date,
|
||||
exit_date = null,
|
||||
exit_reason = null,
|
||||
|
||||
Reference in New Issue
Block a user