@fayz-ai/plugin-workforce 0.1.7 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/context.tsx","../src/views/SchedulesView.tsx","../src/views/TemplatesView.tsx","../src/views/TimeEntriesView.tsx","../src/views/PeriodsView.tsx","../src/views/PeopleView.tsx","../src/settings/usePayrollAccounts.ts","../src/views/PayrollCostsView.tsx","../src/views/HrView.tsx","../src/views/WorkforcePage.tsx","../src/data/mock.ts","../src/data/supabase.ts","../src/store.ts","../src/migrations/index.ts","../src/index.ts"],"names":["React","toast","jsxs","jsx","Button","Badge","Plus","Skeleton","Modal","ModalContent","ModalHeader","ModalTitle","ModalBody","ModalFooter","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","Input","Users","Fragment","Lock","client","monthLabel","resolveRangePreset","PageToolbar","DateRangeControl","AlertTriangle","PersonLink","getSupabaseClientOptional","hhmm"],"mappings":"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AAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA,CAAA;AA66D/B,IAAM,yCAAA,GAA4C,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAmKlD,IAAM,mDAAA,GAAsD,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAoG5D,IAAM,wDAAA,GAA2D,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA,CAAA;AAgKjE,IAAM,4CAAA,GAA+C,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA,CAAA;AA2KrD,IAAM,gDAAA,GAAmD,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA,CAAA;AAyczD,IAAM,mDAAA,GAAsD,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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","file":"index.js","sourcesContent":["import { createPluginContext, formatCurrency, type CurrencyConfig, type EntityLookup } from '@fayz-ai/admin'\nimport type { WorkforcePluginLabels } from './index'\nimport type { WorkforceDataProvider } from './data/types'\nimport type { WorkforceUIState } from './store'\n\n// ---------------------------------------------------------------------------\n// A configuração RESOLVIDA — nada opcional, tudo já mesclado com o padrão.\n// ---------------------------------------------------------------------------\n\nexport interface WorkforceModules {\n /** Escalas: o calendário mensal e o dia. */\n schedules: boolean\n /** Templates: o molde da escala. */\n templates: boolean\n /** Registros de Ponto: a folha, com ajuste auditado. */\n timeEntries: boolean\n /** Fechamento: a competência mensal. */\n periods: boolean\n /** Pessoas & Documentos: a ficha do colaborador. */\n people: boolean\n /** Encargos e Honorários: o custo de pessoal, lido do Financeiro. */\n payrollCosts: boolean\n /**\n * Ficha de RH: vínculo, férias, afastamentos e pendências.\n *\n * Passa pela permissão `workforce_hr.*`, separada de `workforce.*` — quem vê\n * escala e ponto não vê salário nem CID. É o conserto do V1-069, e o FLOW da\n * Ficha diz que ele tinha de ser resolvido ANTES de portar.\n */\n hr: boolean\n}\n\nexport type WorkforceCurrency = CurrencyConfig\n\nexport interface ResolvedWorkforceConfig {\n modules: WorkforceModules\n labels: WorkforcePluginLabels\n currency: WorkforceCurrency\n /** Ver WorkforcePluginOptions.moduleNav. */\n moduleNav?: 'rail' | 'tabs' | 'sidebar'\n /**\n * O valor da hora, quando o app souber dizer.\n *\n * O SQL da jornada NÃO guarda remuneração em lugar nenhum — nem na batida,\n * nem no turno, nem em `public.people`. Sem isto a coluna \"Valor\" da folha\n * não tem de onde sair, e a tela mostra \"—\" em vez de inventar um número.\n */\n hourlyRate?: number\n /** Busca de pessoa para escalar, quando o app quiser oferecer uma. */\n staffLookup?: EntityLookup\n /** Item de nav → feature de acesso, exatamente como o APP declarou. */\n navFeatureMap: Record<string, string>\n}\n\nconst ctx = createPluginContext<ResolvedWorkforceConfig, WorkforceDataProvider, WorkforceUIState>('WorkforcePage')\n\nexport const WorkforceContextProvider = ctx.ContextProvider\nexport const useWorkforceConfig = ctx.useConfig\nexport const useWorkforceProvider = ctx.useProvider\nexport const useWorkforceStore = ctx.useStore\n\nexport { formatCurrency }\n","import React from 'react'\nimport { CalendarDays, Users, Send, Plus } from 'lucide-react'\nimport { Badge, Button, MiniCalendar, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Skeleton, toLocalISODate, toast, type MiniCalendarMarker } from '@fayz-ai/ui'\nimport { ScheduleEditor } from '@fayz-ai/admin'\nimport { useWorkforceProvider, useWorkforceStore } from '../context'\nimport type { DaySchedule, ScheduleAssignment } from '../types'\n\n// ---------------------------------------------------------------------------\n// Escalas — o mês e o dia.\n//\n// O calendário é o índice, e o painel da direita é o dia. É a forma que o V1\n// tem e que funciona: ninguém procura uma escala por lista, procura por data.\n//\n// O PREVISTO desta tela é a escala publicada (plg_workforce_schedules +\n// assignments). A grade semanal de disponibilidade de UMA pessoa — que vive em\n// `public.schedules` e que a agenda também lê — é o `ScheduleEditor` do\n// @fayz-ai/admin, embaixo: o mesmo editor da ficha da pessoa, sem um segundo\n// jeito de dizer a mesma coisa.\n// ---------------------------------------------------------------------------\n\nfunction monthBounds(date: string): { from: string; to: string } {\n const d = new Date(`${date}T12:00:00`)\n const first = new Date(d.getFullYear(), d.getMonth(), 1)\n const last = new Date(d.getFullYear(), d.getMonth() + 1, 0)\n return { from: toLocalISODate(first), to: toLocalISODate(last) }\n}\n\nconst STATUS_LABEL: Record<string, string> = {\n draft: 'Rascunho',\n published: 'Publicada',\n closed: 'Fechada',\n}\n\nconst ASSIGNMENT_STATUS_LABEL: Record<string, string> = {\n pending: 'Pendente',\n notified: 'Avisado',\n confirmed: 'Confirmado',\n declined: 'Recusou',\n realized: 'Cumprido',\n}\n\n/** Uma vaga do dia: quem, em que turno, com que resposta. */\nfunction AssignmentRow({ assignment }: { assignment: ScheduleAssignment }) {\n return (\n <div className=\"flex items-center justify-between gap-3 rounded-lg border border-border px-3 py-2\">\n <div className=\"min-w-0\">\n <div className=\"truncate text-sm font-medium\">{assignment.personName ?? 'Sem nome'}</div>\n <div className=\"truncate text-xs text-muted-foreground\">\n {assignment.professionName ?? 'Sem função'}\n {assignment.shiftLabel ? ` · ${assignment.shiftLabel}` : ''}\n {assignment.shiftStartTime ? ` · ${assignment.shiftStartTime}–${assignment.shiftEndTime}` : ''}\n </div>\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n {assignment.role === 'standby' && <Badge variant=\"outline\">Reserva</Badge>}\n <Badge variant={assignment.status === 'confirmed' ? 'success' : assignment.status === 'declined' ? 'destructive' : 'secondary'}>\n {ASSIGNMENT_STATUS_LABEL[assignment.status] ?? assignment.status}\n </Badge>\n </div>\n </div>\n )\n}\n\nexport function SchedulesView() {\n const provider = useWorkforceProvider()\n const selectedDate = useWorkforceStore((s) => s.selectedDate)\n const setSelectedDate = useWorkforceStore((s) => s.setSelectedDate)\n const schedules = useWorkforceStore((s) => s.schedules)\n const loading = useWorkforceStore((s) => s.schedulesLoading)\n const fetchSchedules = useWorkforceStore((s) => s.fetchSchedules)\n const templates = useWorkforceStore((s) => s.templates)\n const fetchTemplates = useWorkforceStore((s) => s.fetchTemplates)\n const staff = useWorkforceStore((s) => s.staff)\n const fetchStaff = useWorkforceStore((s) => s.fetchStaff)\n\n const [month, setMonth] = React.useState(() => monthBounds(selectedDate))\n const [templateId, setTemplateId] = React.useState<string>('')\n const [busy, setBusy] = React.useState(false)\n const [personId, setPersonId] = React.useState<string>('')\n\n React.useEffect(() => { void fetchSchedules(month.from, month.to) }, [fetchSchedules, month.from, month.to])\n React.useEffect(() => { void fetchTemplates() }, [fetchTemplates])\n React.useEffect(() => { void fetchStaff() }, [fetchStaff])\n\n const day: DaySchedule | undefined = schedules.find((s) => s.scheduleDate === selectedDate)\n\n // Um ponto por dia que TEM escala, com a cor dizendo se ela já foi avisada.\n const markers = React.useMemo(() => {\n const out: Record<string, MiniCalendarMarker[]> = {}\n for (const s of schedules) {\n out[s.scheduleDate] = [{\n color: s.status === 'published' ? 'hsl(var(--success))' : 'hsl(var(--warning))',\n label: s.status === 'published' ? 'Escala publicada' : 'Escala em rascunho',\n }]\n }\n return out\n }, [schedules])\n\n async function createFromTemplate() {\n if (!templateId) return\n setBusy(true)\n try {\n await provider.createSchedule({ scheduleDate: selectedDate, templateId })\n await fetchSchedules(month.from, month.to)\n toast.success('Escala criada a partir do molde.')\n } catch (e: any) {\n toast.error(e?.message ?? 'Não foi possível criar a escala.')\n } finally {\n setBusy(false)\n }\n }\n\n async function publish() {\n if (!day) return\n setBusy(true)\n try {\n await provider.publishSchedule(day.id)\n await fetchSchedules(month.from, month.to)\n toast.success('Escala publicada — os titulares foram espelhados na agenda.')\n } catch (e: any) {\n toast.error(e?.message ?? 'Não foi possível publicar a escala.')\n } finally {\n setBusy(false)\n }\n }\n\n const titulares = day?.assignments.filter((a) => a.role === 'titular') ?? []\n const pendentes = titulares.filter((a) => a.status === 'pending' || a.status === 'notified')\n\n return (\n <div className=\"grid gap-6 p-6 lg:grid-cols-[320px_1fr]\">\n <div className=\"space-y-4\">\n <MiniCalendar\n selectedDate={new Date(`${selectedDate}T12:00:00`)}\n onDateSelect={(d) => setSelectedDate(toLocalISODate(d))}\n onMonthChange={(d) => setMonth(monthBounds(toLocalISODate(d)))}\n markers={markers}\n />\n\n {/* A grade semanal de UMA pessoa, em `public.schedules`. É o editor que\n a ficha da pessoa já usa — reaproveitado, e não reescrito. */}\n <div className=\"rounded-xl border border-border p-4\">\n <div className=\"mb-3 flex items-center gap-2 text-sm font-medium\">\n <Users className=\"h-4 w-4\" aria-hidden />\n Horário fixo da pessoa\n </div>\n <Select value={personId} onValueChange={setPersonId}>\n <SelectTrigger><SelectValue placeholder=\"Escolha quem\" /></SelectTrigger>\n <SelectContent>\n {staff.map((p) => <SelectItem key={p.id} value={p.id}>{p.name}</SelectItem>)}\n </SelectContent>\n </Select>\n {personId && (\n <div className=\"mt-4\">\n <ScheduleEditor assigneeId={personId} />\n </div>\n )}\n </div>\n </div>\n\n <div className=\"space-y-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div>\n <h2 className=\"text-lg font-semibold\">\n {new Date(`${selectedDate}T12:00:00`).toLocaleDateString('pt-BR', {\n weekday: 'long', day: '2-digit', month: 'long',\n })}\n </h2>\n {day && (\n <div className=\"mt-1 flex items-center gap-2 text-xs text-muted-foreground\">\n <Badge variant={day.status === 'published' ? 'success' : 'warning'}>\n {STATUS_LABEL[day.status] ?? day.status}\n </Badge>\n <span>{titulares.length} titular(es) · {pendentes.length} pendente(s)</span>\n </div>\n )}\n </div>\n {day && day.status === 'draft' && (\n <Button onClick={publish} disabled={busy}>\n <Send className=\"mr-2 h-4 w-4\" aria-hidden />\n Publicar escala\n </Button>\n )}\n </div>\n\n {loading ? (\n <div className=\"space-y-2\">\n <Skeleton className=\"h-12 w-full\" />\n <Skeleton className=\"h-12 w-full\" />\n </div>\n ) : day ? (\n <div className=\"space-y-2\">\n {day.assignments.length === 0\n ? <p className=\"text-sm text-muted-foreground\">Nenhuma vaga preenchida neste dia.</p>\n : day.assignments.map((a) => <AssignmentRow key={a.id} assignment={a} />)}\n </div>\n ) : (\n // O pré-requisito duro do V1, dito na tela em vez de escondido: sem\n // molde não existe escala.\n <div className=\"rounded-xl border border-dashed border-border p-8 text-center\">\n <CalendarDays className=\"mx-auto mb-3 h-8 w-8 text-muted-foreground\" aria-hidden />\n <p className=\"mb-4 text-sm text-muted-foreground\">\n {templates.length === 0\n ? 'Nenhum molde de escala cadastrado. Crie um em Templates para começar.'\n : 'Ainda não há escala neste dia. Escolha um molde para montá-la.'}\n </p>\n {templates.length > 0 && (\n <div className=\"mx-auto flex max-w-sm items-center gap-2\">\n <Select value={templateId} onValueChange={setTemplateId}>\n <SelectTrigger><SelectValue placeholder=\"Molde de escala\" /></SelectTrigger>\n <SelectContent>\n {templates.map((t) => <SelectItem key={t.id} value={t.id}>{t.name}</SelectItem>)}\n </SelectContent>\n </Select>\n <Button onClick={createFromTemplate} disabled={!templateId || busy}>\n <Plus className=\"mr-2 h-4 w-4\" aria-hidden />\n Criar\n </Button>\n </div>\n )}\n </div>\n )}\n </div>\n </div>\n )\n}\n","import React from 'react'\nimport { LayoutTemplate, Plus, Trash2 } from 'lucide-react'\nimport { Badge, Button, Input, Modal, ModalContent, ModalHeader, ModalTitle, ModalBody, ModalFooter, Skeleton, toast } from '@fayz-ai/ui'\nimport { useWorkforceProvider, useWorkforceStore } from '../context'\nimport type { ScheduleShift, ScheduleTemplate } from '../types'\n\n// ---------------------------------------------------------------------------\n// Templates — o molde da escala.\n//\n// Três níveis, e nesta ordem porque é a ordem em que a casa pensa: o MOLDE\n// (\"Almoço Seg. a Sex.\"), os TURNOS dentro dele (11:00–15:00, seg a sex), e a\n// LOTAÇÃO de cada função no turno (\"Garçom (2)\", \"Cozinha (3)\") — que é o\n// denominador do \"1/1\" que a escala do dia mostra.\n// ---------------------------------------------------------------------------\n\nconst WEEKDAYS = ['D', 'S', 'T', 'Q', 'Q', 'S', 'S']\n\nfunction ShiftCard({ shift, onChanged }: { shift: ScheduleShift; onChanged: () => void }) {\n const provider = useWorkforceProvider()\n const [profession, setProfession] = React.useState('')\n const [count, setCount] = React.useState('1')\n\n async function addRequirement() {\n if (!profession.trim()) return\n try {\n await provider.saveRequirement({\n shiftId: shift.id,\n professionName: profession.trim(),\n requiredCount: Math.max(1, Number(count) || 1),\n })\n setProfession('')\n setCount('1')\n onChanged()\n } catch (e: any) {\n toast.error(e?.message ?? 'Não foi possível salvar a função.')\n }\n }\n\n async function removeRequirement(id: string) {\n try {\n await provider.deleteRequirement(id)\n onChanged()\n } catch (e: any) {\n toast.error(e?.message ?? 'Não foi possível remover a função.')\n }\n }\n\n async function removeShift() {\n try {\n await provider.deleteShift(shift.id)\n onChanged()\n } catch (e: any) {\n toast.error(e?.message ?? 'Não foi possível remover o turno.')\n }\n }\n\n return (\n <div className=\"rounded-lg border border-border p-3\">\n <div className=\"flex items-start justify-between gap-3\">\n <div>\n <div className=\"text-sm font-medium\">{shift.label}</div>\n <div className=\"text-xs text-muted-foreground\">\n {shift.startTime}–{shift.endTime}\n {/* Turno que vira o dia é normal em restaurante — e é dito, não escondido. */}\n {shift.crossesMidnight ? ' · vira o dia' : ''}\n </div>\n <div className=\"mt-1 flex gap-1\">\n {WEEKDAYS.map((d, i) => (\n <span\n key={i}\n className={`inline-flex h-5 w-5 items-center justify-center rounded text-[10px] ${\n shift.weekdays.includes(i) ? 'bg-primary/15 text-primary' : 'bg-muted text-muted-foreground'\n }`}\n >\n {d}\n </span>\n ))}\n </div>\n </div>\n <Button variant=\"ghost\" size=\"sm\" onClick={removeShift} aria-label=\"Remover turno\">\n <Trash2 className=\"h-4 w-4\" aria-hidden />\n </Button>\n </div>\n\n <div className=\"mt-3 flex flex-wrap gap-2\">\n {shift.requirements.map((r) => (\n <Badge key={r.id} variant=\"outline\" className=\"gap-1\">\n {r.professionName} ({r.requiredCount})\n <button onClick={() => removeRequirement(r.id)} aria-label={`Remover ${r.professionName}`}>\n <Trash2 className=\"h-3 w-3\" aria-hidden />\n </button>\n </Badge>\n ))}\n </div>\n\n <div className=\"mt-3 flex items-center gap-2\">\n <Input\n value={profession}\n onChange={(e) => setProfession(e.target.value)}\n placeholder=\"Função (ex.: Garçom)\"\n className=\"h-8\"\n />\n <Input\n value={count}\n onChange={(e) => setCount(e.target.value)}\n type=\"number\"\n min={1}\n className=\"h-8 w-20\"\n aria-label=\"Vagas\"\n />\n <Button size=\"sm\" variant=\"secondary\" onClick={addRequirement}>Adicionar</Button>\n </div>\n </div>\n )\n}\n\nfunction TemplateCard({ template, onChanged }: { template: ScheduleTemplate; onChanged: () => void }) {\n const provider = useWorkforceProvider()\n const [open, setOpen] = React.useState(false)\n const [label, setLabel] = React.useState('')\n const [start, setStart] = React.useState('11:00')\n const [end, setEnd] = React.useState('15:00')\n const [weekdays, setWeekdays] = React.useState<number[]>([1, 2, 3, 4, 5])\n\n async function addShift() {\n if (!label.trim()) return\n try {\n await provider.saveShift({\n templateId: template.id,\n label: label.trim(),\n startTime: start,\n endTime: end,\n weekdays,\n sortOrder: template.shifts.length,\n })\n setOpen(false)\n setLabel('')\n onChanged()\n } catch (e: any) {\n toast.error(e?.message ?? 'Não foi possível salvar o turno.')\n }\n }\n\n async function removeTemplate() {\n try {\n await provider.deleteTemplate(template.id)\n onChanged()\n } catch (e: any) {\n toast.error(e?.message ?? 'Não foi possível remover o molde.')\n }\n }\n\n return (\n <div className=\"rounded-xl border border-border p-4\">\n <div className=\"mb-3 flex items-center justify-between gap-3\">\n <div>\n <div className=\"font-medium\">{template.name}</div>\n <div className=\"text-xs text-muted-foreground\">{template.shifts.length} turno(s)</div>\n </div>\n <div className=\"flex items-center gap-2\">\n <Button size=\"sm\" variant=\"secondary\" onClick={() => setOpen(true)}>\n <Plus className=\"mr-1 h-4 w-4\" aria-hidden /> Turno\n </Button>\n <Button size=\"sm\" variant=\"ghost\" onClick={removeTemplate} aria-label=\"Remover molde\">\n <Trash2 className=\"h-4 w-4\" aria-hidden />\n </Button>\n </div>\n </div>\n\n <div className=\"space-y-2\">\n {template.shifts.length === 0\n ? <p className=\"text-sm text-muted-foreground\">Nenhum turno neste molde ainda.</p>\n : template.shifts.map((s) => <ShiftCard key={s.id} shift={s} onChanged={onChanged} />)}\n </div>\n\n <Modal open={open} onOpenChange={setOpen}>\n <ModalContent size=\"sm\">\n <ModalHeader><ModalTitle>Novo turno</ModalTitle></ModalHeader>\n <ModalBody className=\"space-y-3\">\n <Input value={label} onChange={(e) => setLabel(e.target.value)} placeholder=\"Nome do turno (ex.: Almoço)\" />\n <div className=\"flex items-center gap-2\">\n <Input type=\"time\" value={start} onChange={(e) => setStart(e.target.value)} aria-label=\"Início\" />\n <span className=\"text-muted-foreground\">até</span>\n <Input type=\"time\" value={end} onChange={(e) => setEnd(e.target.value)} aria-label=\"Fim\" />\n </div>\n <div className=\"flex gap-1\">\n {WEEKDAYS.map((d, i) => (\n <button\n key={i}\n type=\"button\"\n onClick={() => setWeekdays((w) => (w.includes(i) ? w.filter((x) => x !== i) : [...w, i]))}\n className={`h-8 w-8 rounded text-xs ${\n weekdays.includes(i) ? 'bg-primary text-primary-foreground' : 'bg-muted text-muted-foreground'\n }`}\n >\n {d}\n </button>\n ))}\n </div>\n </ModalBody>\n <ModalFooter>\n <Button variant=\"ghost\" onClick={() => setOpen(false)}>Cancelar</Button>\n <Button onClick={addShift}>Salvar turno</Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n </div>\n )\n}\n\nexport function TemplatesView() {\n const provider = useWorkforceProvider()\n const templates = useWorkforceStore((s) => s.templates)\n const loading = useWorkforceStore((s) => s.templatesLoading)\n const fetchTemplates = useWorkforceStore((s) => s.fetchTemplates)\n const [open, setOpen] = React.useState(false)\n const [name, setName] = React.useState('')\n\n React.useEffect(() => { void fetchTemplates() }, [fetchTemplates])\n\n async function createTemplate() {\n if (!name.trim()) return\n try {\n await provider.saveTemplate({ name: name.trim() })\n setName('')\n setOpen(false)\n await fetchTemplates()\n } catch (e: any) {\n toast.error(e?.message ?? 'Não foi possível criar o molde.')\n }\n }\n\n return (\n <div className=\"space-y-4 p-6\">\n <div className=\"flex items-center justify-between gap-3\">\n <div>\n <h2 className=\"text-lg font-semibold\">Templates de escala</h2>\n <p className=\"text-sm text-muted-foreground\">\n O molde vem primeiro: sem ele não se cria escala nenhuma.\n </p>\n </div>\n <Button onClick={() => setOpen(true)}>\n <Plus className=\"mr-2 h-4 w-4\" aria-hidden /> Novo molde\n </Button>\n </div>\n\n {loading ? (\n <div className=\"space-y-2\"><Skeleton className=\"h-24 w-full\" /><Skeleton className=\"h-24 w-full\" /></div>\n ) : templates.length === 0 ? (\n <div className=\"rounded-xl border border-dashed border-border p-8 text-center\">\n <LayoutTemplate className=\"mx-auto mb-3 h-8 w-8 text-muted-foreground\" aria-hidden />\n <p className=\"text-sm text-muted-foreground\">Nenhum molde cadastrado.</p>\n </div>\n ) : (\n <div className=\"grid gap-4 md:grid-cols-2\">\n {templates.map((t) => <TemplateCard key={t.id} template={t} onChanged={() => void fetchTemplates()} />)}\n </div>\n )}\n\n <Modal open={open} onOpenChange={setOpen}>\n <ModalContent size=\"sm\">\n <ModalHeader><ModalTitle>Novo molde de escala</ModalTitle></ModalHeader>\n <ModalBody>\n <Input value={name} onChange={(e) => setName(e.target.value)} placeholder=\"Nome (ex.: Almoço Seg. a Sex.)\" />\n </ModalBody>\n <ModalFooter>\n <Button variant=\"ghost\" onClick={() => setOpen(false)}>Cancelar</Button>\n <Button onClick={createTemplate}>Criar</Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n </div>\n )\n}\n","import React from 'react'\nimport { Clock, AlertTriangle, Pencil, Lock, Eye, Users, MapPin, ScanFace, ImageOff } from 'lucide-react'\nimport { Avatar, AvatarFallback, AvatarImage, Badge, Button, DateRangeControl, Input, Modal, PageToolbar, ModalContent, ModalHeader, ModalTitle, ModalBody, ModalFooter, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Skeleton, toast } from '@fayz-ai/ui'\nimport { PersonLink } from '@fayz-ai/admin'\nimport { formatCurrency, useWorkforceConfig, useWorkforceProvider, useWorkforceStore } from '../context'\nimport type { AnalyticsDateRange } from '@fayz-ai/core'\nimport { resolveRangePreset, type AnalyticsRangePreset } from '@fayz-ai/ui'\nimport type { PunchPhoto, TimeAdjustmentAction, TimeEntry, WorkDay } from '../types'\n\n// ---------------------------------------------------------------------------\n// Registros de Ponto.\n//\n// A FORMA desta tela é deliberadamente a do V1, e não uma reinvenção: uma\n// tabela por dia, uma linha por pessoa, com Nome · Unidade · Entrada · Saída ·\n// Duração · Valor · Escala · Ações. Quem confere ponto já conferiu mil vezes\n// nessa grade, lendo as colunas na mesma ordem; mudar o arranjo obrigaria a\n// pessoa a reaprender a própria rotina para ganhar nada.\n//\n// Um cartão por pessoa-dia, que era o desenho anterior, empilha 299 cartões num\n// mês e some com a comparação lado a lado — que é o gesto da conferência.\n//\n// O que MUDA em relação ao V1, e muda porque lá está errado:\n//\n// · o V1 marca 325 de 325 batidas como \"Fora da escala\", porque cruza só para\n// profissional e com a data em UTC. Aqui o selo vem de `v_workforce_day`,\n// que cruza de verdade e sabe dizer FALTA (escala sem ponto) de FORA DA\n// ESCALA (ponto sem escala) — duas assimetrias que o V1 não distingue.\n//\n// · Ajustar não edita a batida. Grava uma linha em\n// `plg_workforce_time_adjustments` com motivo obrigatório, e o horário real\n// continua à vista, riscado. É o que torna o ponto prova em vez de um campo\n// que alguém mexeu.\n// ---------------------------------------------------------------------------\n\nconst KIND_LABEL: Record<string, string> = {\n clock_in: 'Entrada',\n break_start: 'Saída p/ intervalo',\n break_end: 'Volta do intervalo',\n clock_out: 'Saída',\n}\n\nfunction firstOfMonth(): string {\n const d = new Date()\n return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-01`\n}\n\nfunction todayISO(): string {\n const d = new Date()\n return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`\n}\n\nfunction hhmm(iso?: string | null): string {\n if (!iso) return '—'\n return new Date(iso).toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' })\n}\n\n/** Minutos em '7h30'. Quem confere folha lê horas, não decimais. */\nfunction hours(minutes?: number | null): string {\n if (minutes == null) return '—'\n const sign = minutes < 0 ? '-' : ''\n const abs = Math.abs(minutes)\n return `${sign}${Math.floor(abs / 60)}h${String(abs % 60).padStart(2, '0')}`\n}\n\n/** Iniciais para o avatar. Duas letras: mais que isso vira sopa em 32px. */\nfunction iniciais(nome?: string | null): string {\n const partes = (nome ?? '').trim().split(/\\s+/).filter(Boolean)\n if (!partes.length) return '—'\n return (partes[0][0] + (partes.length > 1 ? partes[partes.length - 1][0] : '')).toUpperCase()\n}\n\n/**\n * As URLs assinadas da PÁGINA, num mapa só.\n *\n * O bucket é privado, então toda URL tem prazo — cinco minutos, o mesmo do V1 —\n * e por isso ela não pode ser guardada na linha nem num cache de dados: uma URL\n * assinada vencida em cache é uma imagem quebrada que ninguém sabe explicar.\n *\n * O que mudou foi ONDE se assina. Assinar dentro de cada avatar custava uma\n * requisição por linha: trinta dias do Pertinho do Céu são 261 linhas, e a\n * primeira cara só aparecia depois de 261 idas ao storage. Aqui a página inteira\n * vai numa chamada, e as linhas leem o resultado.\n */\nconst FotosContext = React.createContext<Record<string, string>>({})\n\nfunction usePunchPhotoUrl(photo?: PunchPhoto | null): string | null {\n const mapa = React.useContext(FotosContext)\n if (!photo) return null\n return mapa[`${photo.bucket}/${photo.path}`] ?? null\n}\n\n/** Assina, de uma vez, as fotos das batidas que a página vai desenhar. */\nfunction useFotosDaPagina(entries: TimeEntry[]): Record<string, string> {\n const provider = useWorkforceProvider()\n const [mapa, setMapa] = React.useState<Record<string, string>>({})\n // A chave é a LISTA de fotos, não o array de batidas: paginar não muda as\n // batidas carregadas, muda quais delas estão à vista, e reassinar as mesmas\n // fotos a cada troca de página seria a ida ao storage que este código existe\n // para evitar.\n const chave = React.useMemo(\n () => entries.map((e) => (e.photo ? `${e.photo.bucket}/${e.photo.path}` : '')).filter(Boolean).sort().join('|'),\n [entries],\n )\n React.useEffect(() => {\n const fotos = entries.map((e) => e.photo).filter(Boolean) as PunchPhoto[]\n if (!fotos.length) { setMapa({}); return }\n let vivo = true\n provider.signPunchPhotos(fotos)\n .then((m) => { if (vivo) setMapa(m) })\n .catch(() => { if (vivo) setMapa({}) })\n return () => { vivo = false }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [provider, chave])\n return mapa\n}\n\n/** A leitura tipada do que o totem gravou. Ausente é uma resposta legítima. */\nfunction provaDe(entry: TimeEntry): {\n lat?: number; lng?: number; accuracy?: number; faceScore?: number; naoMigrada: boolean\n} {\n const e = (entry.evidence ?? {}) as Record<string, unknown>\n const num = (v: unknown) => (typeof v === 'number' ? v : typeof v === 'string' ? Number(v) : undefined)\n return {\n lat: num(e.lat),\n lng: num(e.lng),\n accuracy: num(e.accuracy_m),\n faceScore: num(e.face_score),\n // Houve captura E a imagem não atravessou. É o estado que a tela precisa\n // distinguir de \"não houve captura\" — dizer \"sem foto\" nos dois casos\n // esconderia 1.320 imagens que existem e não chegaram.\n naoMigrada: !!e.photo_path && !entry.photo,\n }\n}\n\nfunction diasAtras(n: number): string {\n const d = new Date(Date.now() - n * 86400000)\n return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`\n}\n\n/** A cara de quem bateu, quando os bytes atravessaram. */\nfunction FotoDaBatida({ entry, className }: { entry: TimeEntry; className?: string }) {\n const url = usePunchPhotoUrl(entry.photo)\n return (\n <Avatar className={className ?? 'h-8 w-8 shrink-0'}>\n {url && <AvatarImage src={url} alt={`Foto da batida de ${entry.personName ?? 'quem bateu'}`} />}\n <AvatarFallback>{iniciais(entry.personName)}</AvatarFallback>\n </Avatar>\n )\n}\n\n/**\n * A prova que o totem produziu, numa linha: a foto, a coordenada com precisão e\n * o score facial — os quatro campos que o V1 mostra e que fazem uma batida\n * contestada ter defesa.\n *\n * Os três últimos chegaram pelo porte desde a primeira onda. A FOTO não: até a\n * migration 054 do base e a 001 deste plugin, `evidence.photo_path` guardava o\n * caminho de um bucket privado de OUTRO projeto Supabase — 1.320 imagens\n * referenciadas e nenhuma alcançável. Por isso o estado \"não migrada\" é DITO em\n * vez de virar um espaço vazio: espaço vazio lê-se como \"não houve captura\", que\n * é uma afirmação diferente e falsa.\n */\nfunction ProvaDoTotem({ entry }: { entry: TimeEntry }) {\n const p = provaDe(entry)\n const temAlgo = entry.photo || p.naoMigrada || p.lat != null || p.faceScore != null\n if (!temAlgo) return null\n return (\n <div className=\"flex items-center gap-3 pt-1\">\n {entry.photo ? (\n <FotoDaBatida entry={entry} className=\"h-12 w-12 shrink-0 rounded-md\" />\n ) : p.naoMigrada ? (\n <span\n className=\"flex h-12 w-12 shrink-0 items-center justify-center rounded-md border border-dashed border-border text-muted-foreground\"\n title=\"O totem capturou a foto; a imagem ainda não atravessou do V1\"\n >\n <ImageOff className=\"h-4 w-4\" aria-hidden />\n </span>\n ) : null}\n <div className=\"flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground\">\n {p.lat != null && p.lng != null && (\n <span className=\"flex items-center gap-1\">\n <MapPin className=\"h-3.5 w-3.5\" aria-hidden />\n {p.lat.toFixed(5)}, {p.lng.toFixed(5)}\n {p.accuracy != null && <> · ± {Math.round(p.accuracy)}m</>}\n </span>\n )}\n {p.faceScore != null && (\n <span className=\"flex items-center gap-1\">\n <ScanFace className=\"h-3.5 w-3.5\" aria-hidden />\n Match facial {(p.faceScore * 100).toFixed(1)}%\n </span>\n )}\n {p.naoMigrada && <span>Foto capturada no V1, ainda não migrada</span>}\n </div>\n </div>\n )\n}\n\n/**\n * O dossiê do dia: cada batida, o horário REAL ao lado do ajustado, quem\n * ajustou, e a prova que o totem produziu.\n */\nfunction DetalhesDoDia({ day, entries, onClose }: {\n day: WorkDay\n entries: TimeEntry[]\n onClose: () => void\n}) {\n return (\n <Modal open onOpenChange={(o) => { if (!o) onClose() }}>\n <ModalContent>\n <ModalHeader>\n <ModalTitle>{day.personName ?? 'Sem nome'} · {day.workDate}</ModalTitle>\n </ModalHeader>\n <ModalBody className=\"space-y-3\">\n <div className=\"flex flex-wrap gap-4 text-sm\">\n <span>Previsto <b>{hours(day.plannedMinutes)}</b></span>\n <span>Realizado <b>{hours(day.workedMinutes)}</b></span>\n {day.varianceMinutes != null && (\n <span>Saldo <b>{day.varianceMinutes >= 0 ? '+' : ''}{hours(day.varianceMinutes)}</b></span>\n )}\n {day.shiftLabel && (\n <span className=\"text-muted-foreground\">\n Turno {day.shiftLabel} {day.shiftStartTime}–{day.shiftEndTime}\n </span>\n )}\n </div>\n <div className=\"divide-y divide-border rounded-lg border border-border\">\n {entries.length === 0 ? (\n <p className=\"px-3 py-2 text-sm text-muted-foreground\">Nenhuma batida neste dia.</p>\n ) : entries.map((e) => (\n <div key={e.id} className=\"px-3 py-2 text-sm\">\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"flex items-center gap-2\">\n <Clock className=\"h-3.5 w-3.5 text-muted-foreground\" aria-hidden />\n <span className={e.voided ? 'text-muted-foreground line-through' : ''}>\n {KIND_LABEL[e.kind] ?? e.kind} · {hhmm(e.effectiveAt)}\n </span>\n {e.adjusted && (\n // O real fica à vista, riscado. Esconder o horário original\n // transformaria o ajuste numa edição, que é justamente o que\n // o modelo append-only existe para impedir.\n <span className=\"text-xs text-muted-foreground\">\n (real <s>{hhmm(e.punchedAt)}</s>)\n </span>\n )}\n </span>\n {e.adjusted && (\n <span className=\"text-xs text-muted-foreground\">\n {e.adjustedByName ?? 'alguém'}: {e.adjustmentReason}\n </span>\n )}\n </div>\n <ProvaDoTotem entry={e} />\n </div>\n ))}\n </div>\n </ModalBody>\n <ModalFooter>\n <Button variant=\"outline\" onClick={onClose}>Fechar</Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n )\n}\n\n/** O diálogo de ajuste. Motivo obrigatório — o banco recusa em branco. */\nfunction AdjustDialog({ entry, onClose, onSaved }: {\n entry: TimeEntry\n onClose: () => void\n onSaved: () => void\n}) {\n const provider = useWorkforceProvider()\n const [action, setAction] = React.useState<TimeAdjustmentAction>('correct')\n const [time, setTime] = React.useState(() => new Date(entry.effectiveAt).toTimeString().slice(0, 5))\n const [reason, setReason] = React.useState('')\n const [busy, setBusy] = React.useState(false)\n\n async function save() {\n if (!reason.trim()) {\n toast.error('O motivo é obrigatório.')\n return\n }\n setBusy(true)\n try {\n await provider.adjustTimeEntry({\n timeEntryId: entry.id,\n action,\n effectiveAt: action === 'void' ? undefined : new Date(`${entry.workDate}T${time}:00`).toISOString(),\n reason: reason.trim(),\n })\n toast.success('Ajuste registrado. O horário real foi preservado.')\n onSaved()\n onClose()\n } catch (e: any) {\n toast.error(e?.message ?? 'Não foi possível registrar o ajuste.')\n } finally {\n setBusy(false)\n }\n }\n\n return (\n <Modal open onOpenChange={(o) => { if (!o) onClose() }}>\n <ModalContent size=\"sm\">\n <ModalHeader><ModalTitle>Ajustar batida</ModalTitle></ModalHeader>\n <ModalBody className=\"space-y-3\">\n <p className=\"text-xs text-muted-foreground\">\n {entry.personName ?? 'Sem nome'} · {KIND_LABEL[entry.kind] ?? entry.kind} ·\n {' '}registrado às {hhmm(entry.punchedAt)}\n </p>\n <Select value={action} onValueChange={(v) => setAction(v as TimeAdjustmentAction)}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n <SelectItem value=\"correct\">Corrigir o horário</SelectItem>\n <SelectItem value=\"insert\">Inserir a batida que faltou</SelectItem>\n <SelectItem value=\"void\">Anular esta batida</SelectItem>\n </SelectContent>\n </Select>\n {action !== 'void' && (\n <Input type=\"time\" value={time} onChange={(e) => setTime(e.target.value)} aria-label=\"Horário que passa a valer\" />\n )}\n <Input\n value={reason}\n onChange={(e) => setReason(e.target.value)}\n placeholder=\"Motivo (obrigatório)\"\n />\n </ModalBody>\n <ModalFooter>\n <Button variant=\"ghost\" onClick={onClose}>Cancelar</Button>\n <Button onClick={save} disabled={busy}>Registrar ajuste</Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n )\n}\n\n/**\n * Um relógio que anda de minuto em minuto.\n *\n * \"Está dentro há 6h58\" é uma frase que envelhece, e envelhecer em silêncio é o\n * que a tornaria pior que não dizer nada. De minuto e não de segundo porque a\n * folha de ponto se lê em minutos — um tique por segundo repintaria 299 linhas\n * para mover um dígito que ninguém acompanha.\n */\nfunction useAgora(ativo: boolean): number {\n const [agora, setAgora] = React.useState(() => Date.now())\n React.useEffect(() => {\n if (!ativo) return\n const id = setInterval(() => setAgora(Date.now()), 60_000)\n return () => clearInterval(id)\n }, [ativo])\n return agora\n}\n\n// Acima disto, \"em curso\" deixa de ser a explicação provável. A jornada mais\n// longa do vocabulário do V1 é a 12x36 — doze horas —, então dezesseis dá\n// margem para o turno que vira a noite e ainda separa com folga o caso real:\n// alguém que foi embora e não bateu a saída. Chamar as duas coisas de \"em\n// curso\" faria a tela afirmar que a pessoa está no local há dois dias.\nconst LIMITE_EM_CURSO_MIN = 16 * 60\n\n/**\n * A coluna Duração.\n *\n * Até a migration 003 ela mostrava `-497155h02` em todo ponto em aberto — o\n * epoch da entrada, com o sinal trocado, vazando para a tela. A conta foi\n * corrigida lá; o que ficou para cá é a pergunta que o número sozinho não\n * responde: um dia em aberto tem DUAS quantidades, o que já fechou e o que está\n * correndo, e mostrar só a primeira com um \"(parcial)\" ao lado obrigava quem\n * confere a abrir os detalhes para saber desde quando.\n */\nfunction Duracao({ day, agora }: { day: WorkDay; agora: number }) {\n // Fechou, e fechou com uma duração que não é jornada. O número MEDIDO fica à\n // vista — é ele que faz a pessoa procurar a batida — e o motivo fica escrito\n // ao lado, com quantos dias separam a entrada da saída, que é a pista.\n if (day.reviewReason === 'span_too_long') {\n const dias = day.firstIn && day.lastOut\n ? Math.round((new Date(day.lastOut).getTime() - new Date(day.firstIn).getTime()) / 86400000)\n : 0\n return (\n <>\n <span className=\"text-destructive\">{hours(day.workedMinutes)}</span>\n <span\n className=\"block text-xs text-destructive\"\n title=\"Fora da soma: acima de 16h num dia é saída não batida, não jornada. Corrija pelo botão Ajustar.\"\n >\n revisar · {dias > 0 ? `saída ${dias}d depois` : 'saída no dia seguinte'}\n </span>\n </>\n )\n }\n if (!day.isOpen) {\n return <>{hours(day.workedMinutes)}</>\n }\n const fechadas = day.workedMinutes ?? 0\n const correndo = day.openSince\n ? Math.max(0, Math.round((agora - new Date(day.openSince).getTime()) / 60000))\n : null\n const esquecido = correndo != null && correndo > LIMITE_EM_CURSO_MIN\n\n const correndoTexto = correndo == null\n ? 'em aberto'\n : esquecido\n ? `sem saída há ${hours(correndo)}`\n : `${hours(correndo)} em curso`\n const cor = esquecido ? 'text-destructive' : 'text-muted-foreground'\n const desde = day.openSince\n ? `Aberto desde ${new Date(day.openSince).toLocaleString('pt-BR')}`\n : undefined\n\n // Nada fechado ainda: o \"em curso\" vira a linha principal. Um travessão em\n // cima dele seria duas linhas para dizer uma coisa só, e a primeira das duas\n // diria \"sem duração\" ao lado de uma duração.\n if (fechadas === 0) {\n return <span className={cor} title={desde}>{correndoTexto}</span>\n }\n return (\n <>\n {hours(fechadas)}\n <span className={`block text-xs ${cor}`} title={desde}>+ {correndoTexto}</span>\n </>\n )\n}\n\n/** O selo da coluna Escala. Três estados, na precedência do V1. */\nfunction SeloEscala({ day }: { day: WorkDay }) {\n if (day.absent) return <Badge variant=\"destructive\">Falta</Badge>\n if (day.outsideSchedule) return <Badge variant=\"destructive\">Fora da escala</Badge>\n return <Badge variant=\"success\">Na escala</Badge>\n}\n\n/** Uma pessoa numa linha da tabela do dia. */\nfunction LinhaPessoa({ day, entries, unitName, agora, onAdjust, onDetails }: {\n day: WorkDay\n entries: TimeEntry[]\n unitName: string\n /** O relógio vem de cima: um `setInterval` por linha seriam 299 deles. */\n agora: number\n onAdjust: (entry: TimeEntry) => void\n onDetails: (day: WorkDay) => void\n}) {\n const { currency, hourlyRate, staffLookup } = useWorkforceConfig()\n // Valor só sai de hora que conta. Precificar um dia de 45h que ninguém\n // trabalhou seria levar o erro da tela para dentro do dinheiro.\n const value = hourlyRate != null && day.workedMinutes != null && !day.reviewReason\n ? (day.workedMinutes / 60) * hourlyRate\n : null\n // Ajustar age sobre a ÚLTIMA batida do dia: é a que está aberta quando o\n // ponto está aberto, e é a que alguém corrige quando esqueceu de bater a saída.\n const alvo = entries.length ? entries[entries.length - 1] : null\n const travado = entries.some((e) => e.payableInvoiceId)\n // A cara do dia é a da ENTRADA, e não a foto do cadastro: quem confere ponto\n // está conferindo se quem bateu é quem devia bater, e o retrato do cadastro\n // responde a outra pergunta. Sem foto de entrada, qualquer batida com foto\n // serve — a saída também é a pessoa. Sem nenhuma, as iniciais.\n const retrato = entries.find((e) => e.kind === 'clock_in' && e.photo)\n ?? entries.find((e) => e.photo)\n ?? null\n\n return (\n <tr className=\"border-b border-border last:border-0 hover:bg-muted/40\">\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-3\">\n {retrato ? (\n <FotoDaBatida entry={retrato} />\n ) : (\n <Avatar className=\"h-8 w-8 shrink-0\">\n <AvatarFallback>{iniciais(day.personName)}</AvatarFallback>\n </Avatar>\n )}\n <div className=\"min-w-0\">\n <PersonLink\n personId={day.personId}\n name={day.personName ?? 'Sem nome'}\n kind=\"staff\"\n lookup={staffLookup}\n size=\"sm\"\n className=\"text-sm\"\n />\n <div className=\"text-xs text-muted-foreground\">Profissional</div>\n </div>\n </div>\n </td>\n <td className=\"px-4 py-3 text-sm text-muted-foreground\">{unitName}</td>\n <td className=\"px-4 py-3 text-sm tabular-nums\">{hhmm(day.firstIn)}</td>\n <td className=\"px-4 py-3 text-sm tabular-nums\">\n {day.isOpen\n ? <Badge variant=\"outline\">Em aberto</Badge>\n : hhmm(day.lastOut)}\n </td>\n <td className=\"px-4 py-3 text-sm tabular-nums\"><Duracao day={day} agora={agora} /></td>\n <td className=\"px-4 py-3 text-sm tabular-nums\">\n {value != null ? formatCurrency(value, currency) : '—'}\n </td>\n <td className=\"px-4 py-3\"><SeloEscala day={day} /></td>\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-1\">\n {travado ? (\n // A trava do banco, dita na tela: hora já paga não se corrige sem\n // reabrir a competência.\n <span className=\"flex items-center gap-1 px-2 text-xs text-muted-foreground\">\n <Lock className=\"h-3.5 w-3.5\" aria-hidden /> já paga\n </span>\n ) : alvo ? (\n <Button size=\"sm\" variant=\"ghost\" onClick={() => onAdjust(alvo)}>\n <Pencil className=\"mr-1 h-3.5 w-3.5\" aria-hidden /> Ajustar\n </Button>\n ) : null}\n <Button size=\"sm\" variant=\"ghost\" onClick={() => onDetails(day)}>\n <Eye className=\"mr-1 h-3.5 w-3.5\" aria-hidden /> Detalhes\n </Button>\n </div>\n </td>\n </tr>\n )\n}\n\n/** \"Hoje, sexta-feira, 18 de setembro de 2026\" — como o V1 escreve. */\nfunction tituloDoDia(workDate: string): string {\n const d = new Date(`${workDate}T12:00:00`)\n const hoje = new Date()\n const iso = (x: Date) => `${x.getFullYear()}-${String(x.getMonth() + 1).padStart(2, '0')}-${String(x.getDate()).padStart(2, '0')}`\n const ontem = new Date(hoje.getTime() - 86400000)\n const extenso = d.toLocaleDateString('pt-BR', { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' })\n if (workDate === iso(hoje)) return `Hoje, ${extenso}`\n if (workDate === iso(ontem)) return `Ontem, ${extenso}`\n return extenso.charAt(0).toUpperCase() + extenso.slice(1)\n}\n\n/** Um dia: a faixa de cabeçalho com os totais, e a tabela das pessoas. */\nfunction GrupoDoDia({ workDate, days, entriesByPerson, unitNames, agora, onAdjust, onDetails }: {\n workDate: string\n days: WorkDay[]\n entriesByPerson: Map<string, TimeEntry[]>\n unitNames: Map<string, string>\n agora: number\n onAdjust: (entry: TimeEntry) => void\n onDetails: (day: WorkDay) => void\n}) {\n const { currency, hourlyRate } = useWorkforceConfig()\n const pessoas = new Set(days.map((d) => d.personId)).size\n const abertos = days.filter((d) => d.isOpen).length\n const revisar = days.filter((d) => d.reviewReason === 'span_too_long').length\n // UMA regra: dia que o banco marcou com motivo não soma. Era só \"ponto\n // aberto\" até a 004 — contar uma jornada que não terminou inventa hora que\n // ninguém trabalhou —, e um dia de 45h é o mesmo problema com outra cara. Por\n // isso os contadores ficam ao lado: o total é honesto E incompleto, e a tela\n // diz as duas coisas em vez de escolher uma.\n const minutos = days.reduce((sum, d) => sum + (d.reviewReason ? 0 : (d.workedMinutes ?? 0)), 0)\n const valor = hourlyRate != null ? (minutos / 60) * hourlyRate : null\n\n return (\n <div className=\"overflow-hidden rounded-xl border border-border\">\n <div className=\"flex flex-wrap items-center gap-4 border-l-2 border-l-primary bg-muted/40 px-4 py-3\">\n <span className=\"text-sm font-semibold\">{tituloDoDia(workDate)}</span>\n <span className=\"flex items-center gap-1 text-xs text-muted-foreground\">\n <Users className=\"h-3.5 w-3.5\" aria-hidden /> {pessoas} pessoa{pessoas === 1 ? '' : 's'}\n </span>\n {abertos > 0 && (\n <span className=\"flex items-center gap-1 text-xs font-medium text-warning\">\n <AlertTriangle className=\"h-3.5 w-3.5\" aria-hidden /> {abertos} em aberto\n </span>\n )}\n {revisar > 0 && (\n <span\n className=\"flex items-center gap-1 text-xs font-medium text-destructive\"\n title=\"Dias acima de 16h — saída não batida. Fora do total até serem ajustados.\"\n >\n <AlertTriangle className=\"h-3.5 w-3.5\" aria-hidden /> {revisar} a revisar\n </span>\n )}\n <span className=\"flex items-center gap-1 text-xs text-muted-foreground\">\n <Clock className=\"h-3.5 w-3.5\" aria-hidden /> {hours(minutos)}\n </span>\n {valor != null && valor > 0 && (\n <span className=\"text-xs font-medium text-success\">{formatCurrency(valor, currency)}</span>\n )}\n </div>\n\n <div className=\"overflow-x-auto\">\n <table className=\"w-full min-w-[860px] border-collapse text-left\">\n <thead>\n <tr className=\"border-b border-border text-xs font-medium text-muted-foreground\">\n <th scope=\"col\" className=\"px-4 py-2\">Nome</th>\n <th scope=\"col\" className=\"px-4 py-2\">Unidade</th>\n <th scope=\"col\" className=\"px-4 py-2\">Entrada</th>\n <th scope=\"col\" className=\"px-4 py-2\">Saída</th>\n <th scope=\"col\" className=\"px-4 py-2\">Duração</th>\n <th scope=\"col\" className=\"px-4 py-2\">Valor</th>\n <th scope=\"col\" className=\"px-4 py-2\">Escala</th>\n <th scope=\"col\" className=\"px-4 py-2\">Ações</th>\n </tr>\n </thead>\n <tbody>\n {days.map((d) => (\n <LinhaPessoa\n key={`${d.personId}|${d.workDate}`}\n day={d}\n entries={entriesByPerson.get(`${d.personId}|${d.workDate}`) ?? []}\n unitName={(d.unitId && unitNames.get(d.unitId)) || '—'}\n agora={agora}\n onAdjust={onAdjust}\n onDetails={onDetails}\n />\n ))}\n </tbody>\n </table>\n </div>\n </div>\n )\n}\n\nexport function TimeEntriesView() {\n const { currency, hourlyRate } = useWorkforceConfig()\n const entries = useWorkforceStore((s) => s.entries)\n const days = useWorkforceStore((s) => s.days)\n const loading = useWorkforceStore((s) => s.timeLoading)\n const fetchTime = useWorkforceStore((s) => s.fetchTime)\n\n // O MESMO controle de período do /analytics — extraído para @fayz-ai/ui\n // justamente para isto. Dois `<input type=date>` crus não têm preset, não\n // escrevem a janela resolvida e deixam marcar início depois do fim.\n // Sete dias, e não trinta. Conferir ponto é rotina de semana — o gesto é\n // \"o que aconteceu desde a última vez que olhei\", não \"o mês inteiro\". Trinta\n // dias no Pertinho do Céu são 261 linhas-pessoa-dia antes de a tela desenhar\n // a primeira; sete são cerca de sessenta. Quem precisa do mês tem o preset\n // ao lado, e ele é um clique.\n const [preset, setPreset] = React.useState<AnalyticsRangePreset | 'custom'>('last_7_days')\n const [range, setRange] = React.useState<AnalyticsDateRange>(() => resolveRangePreset('last_7_days'))\n const from = range.from\n const to = range.to\n const [adjusting, setAdjusting] = React.useState<TimeEntry | null>(null)\n const [details, setDetails] = React.useState<WorkDay | null>(null)\n\n React.useEffect(() => { void fetchTime(from, to) }, [fetchTime, from, to])\n\n // O relógio só anda quando há ponto em aberto na tela. Num período fechado\n // não há nada correndo, e um timer que repinta a tabela de minuto em minuto\n // para não mudar nada é só uma aba que não deixa a máquina dormir.\n const temAberto = React.useMemo(() => days.some((d) => d.isOpen), [days])\n const agora = useAgora(temAberto)\n\n const entriesByPerson = React.useMemo(() => {\n const map = new Map<string, TimeEntry[]>()\n for (const e of entries) {\n const key = `${e.personId}|${e.workDate}`\n const list = map.get(key) ?? []\n list.push(e)\n map.set(key, list)\n }\n // A última batida é o alvo do ajuste — ordenar aqui evita que a linha\n // dependa da ordem em que o provider devolveu.\n for (const list of map.values()) list.sort((a, b) => a.seq - b.seq)\n return map\n }, [entries])\n\n /** Por dia, mais recente primeiro — como o V1 lista. */\n const porDia = React.useMemo(() => {\n const map = new Map<string, WorkDay[]>()\n for (const d of days) {\n const list = map.get(d.workDate) ?? []\n list.push(d)\n map.set(d.workDate, list)\n }\n for (const list of map.values()) {\n list.sort((a, b) => (a.personName ?? '').localeCompare(b.personName ?? ''))\n }\n return [...map.entries()].sort(([a], [b]) => b.localeCompare(a))\n }, [days])\n\n // A unidade da paginação é o DIA, não a linha: a tela é uma tabela por dia, e\n // cortar no meio de um dia partiria o cabeçalho de totais do dia da gente que\n // ele conta. Sete cabem numa semana inteira sem botão nenhum aparecer.\n const DIAS_POR_PAGINA = 7\n const [pagina, setPagina] = React.useState(0)\n // Período novo, página zero. Sem isto, trocar de intervalo pode cair numa\n // página que não existe mais e a tela fica vazia sem dizer por quê.\n React.useEffect(() => { setPagina(0) }, [from, to])\n const totalPaginas = Math.max(1, Math.ceil(porDia.length / DIAS_POR_PAGINA))\n const paginaAtual = Math.min(pagina, totalPaginas - 1)\n const diasVisiveis = React.useMemo(\n () => porDia.slice(paginaAtual * DIAS_POR_PAGINA, (paginaAtual + 1) * DIAS_POR_PAGINA),\n [porDia, paginaAtual],\n )\n\n // Só as batidas dos dias À VISTA vão para a assinatura. É o que torna a\n // paginação uma economia de rede e não só de pixels.\n const entradasVisiveis = React.useMemo(() => {\n const chaves = new Set<string>()\n for (const [, lista] of diasVisiveis) for (const d of lista) chaves.add(`${d.personId}|${d.workDate}`)\n return entries.filter((e) => chaves.has(`${e.personId}|${e.workDate}`))\n }, [diasVisiveis, entries])\n const fotos = useFotosDaPagina(entradasVisiveis)\n\n const unitNames = React.useMemo(() => {\n const map = new Map<string, string>()\n for (const d of days) if (d.unitId) map.set(d.unitId, d.unitName ?? '—')\n return map\n }, [days])\n\n const totais = React.useMemo(() => {\n const minutos = days.reduce((sum, d) => sum + (d.reviewReason ? 0 : (d.workedMinutes ?? 0)), 0)\n return {\n registros: days.length,\n minutos,\n abertos: days.filter((d) => d.isOpen).length,\n revisar: days.filter((d) => d.reviewReason === 'span_too_long').length,\n valor: hourlyRate != null ? (minutos / 60) * hourlyRate : null,\n }\n }, [days, hourlyRate])\n\n return (\n <div className=\"space-y-4 p-6\">\n {/* A MESMA barra flutuante do /analytics: PageToolbar com alça de\n arrastar e posição persistida. Não é escolha estética — a barra do\n analytics flutua sobre a lista para que o período fique alcançável\n depois de rolar trezentos registros, que é exatamente o que uma\n conferência de ponto faz. Uma barra fixa no topo do documento some na\n primeira rolagem e obriga a voltar. */}\n <PageToolbar\n range={\n <DateRangeControl\n value={range}\n onChange={setRange}\n preset={preset}\n onPresetChange={setPreset}\n />\n }\n onRefresh={() => void fetchTime(from, to)}\n // `storageKey` próprio: a posição que a pessoa escolheu para a barra do\n // ponto não deve mover a do analytics, e vice-versa.\n storageKey=\"workforce.time-entries\"\n />\n\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <h2 className=\"text-lg font-semibold\">Resultados</h2>\n <div className=\"flex flex-wrap items-center gap-4 text-sm text-muted-foreground\">\n <span>{totais.registros} registro(s)</span>\n <span>\n Total: <b className=\"text-foreground\">{hours(totais.minutos)}</b>\n {/* O total é honesto E incompleto, e dizer só a primeira metade é o\n que faz alguém tomar 14.969h por verdade quando 11.197 delas são\n saída não batida. O que ficou de fora fica escrito aqui, com o\n número — não um asterisco que manda procurar a legenda. */}\n {(totais.abertos > 0 || totais.revisar > 0) && (\n <span className=\"ml-1 text-xs\">\n (fora:{' '}\n {[\n totais.abertos > 0 ? `${totais.abertos} em aberto` : null,\n totais.revisar > 0 ? `${totais.revisar} a revisar` : null,\n ].filter(Boolean).join(' · ')})\n </span>\n )}\n </span>\n <span>Valor: <b className=\"text-foreground\">\n {totais.valor != null ? formatCurrency(totais.valor, currency) : '—'}\n </b></span>\n </div>\n </div>\n\n {hourlyRate == null && (\n // Honestidade em vez de um número inventado: o SQL da jornada não guarda\n // remuneração em lugar nenhum, então a coluna Valor só existe quando o\n // app diz quanto vale a hora.\n <p className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <AlertTriangle className=\"h-3.5 w-3.5\" aria-hidden />\n O valor da hora não está configurado — informe <code>hourlyRate</code> no plugin para ver a coluna Valor.\n </p>\n )}\n\n {loading ? (\n <div className=\"space-y-2\"><Skeleton className=\"h-40 w-full\" /><Skeleton className=\"h-40 w-full\" /></div>\n ) : porDia.length === 0 ? (\n <div className=\"rounded-xl border border-dashed border-border p-8 text-center\">\n <Clock className=\"mx-auto mb-3 h-8 w-8 text-muted-foreground\" aria-hidden />\n <p className=\"text-sm text-muted-foreground\">Nenhum registro no período.</p>\n </div>\n ) : (\n <FotosContext.Provider value={fotos}>\n <div className=\"space-y-3\">\n {diasVisiveis.map(([workDate, list]) => (\n <GrupoDoDia\n key={workDate}\n workDate={workDate}\n days={list}\n entriesByPerson={entriesByPerson}\n unitNames={unitNames}\n agora={agora}\n onAdjust={setAdjusting}\n onDetails={setDetails}\n />\n ))}\n {totalPaginas > 1 && (\n <div className=\"flex items-center justify-between gap-3 rounded-xl border border-border px-4 py-3 text-sm\">\n {/* O que a página mostra, em DIAS — é a unidade que a tela usa, e\n dizer \"1 a 7 de 23 registros\" mentiria sobre o que foi\n cortado. */}\n <span className=\"text-muted-foreground\">\n Dias {paginaAtual * DIAS_POR_PAGINA + 1}–\n {Math.min((paginaAtual + 1) * DIAS_POR_PAGINA, porDia.length)} de {porDia.length}\n </span>\n <span className=\"flex items-center gap-2\">\n <Button\n size=\"sm\" variant=\"outline\"\n disabled={paginaAtual === 0}\n onClick={() => setPagina((n) => Math.max(0, n - 1))}\n >\n Mais recentes\n </Button>\n <span className=\"text-xs text-muted-foreground tabular-nums\">\n {paginaAtual + 1} / {totalPaginas}\n </span>\n <Button\n size=\"sm\" variant=\"outline\"\n disabled={paginaAtual >= totalPaginas - 1}\n onClick={() => setPagina((n) => Math.min(totalPaginas - 1, n + 1))}\n >\n Mais antigos\n </Button>\n </span>\n </div>\n )}\n </div>\n </FotosContext.Provider>\n )}\n\n {adjusting && (\n <AdjustDialog\n entry={adjusting}\n onClose={() => setAdjusting(null)}\n onSaved={() => void fetchTime(from, to)}\n />\n )}\n {details && (\n <DetalhesDoDia\n day={details}\n entries={entriesByPerson.get(`${details.personId}|${details.workDate}`) ?? []}\n onClose={() => setDetails(null)}\n />\n )}\n </div>\n )\n}\n","import React from 'react'\nimport { Lock, Unlock, CalendarCheck } from 'lucide-react'\nimport { Badge, Button, Input, Modal, ModalContent, ModalHeader, ModalTitle, ModalBody, ModalFooter, Skeleton, toast } from '@fayz-ai/ui'\nimport { useWorkforceProvider, useWorkforceStore } from '../context'\nimport type { WorkforcePeriod } from '../types'\n\n// ---------------------------------------------------------------------------\n// Fechamento — a competência.\n//\n// Fechar o mês é um ATO, não a edição de uma linha: as duas escritas passam por\n// RPC (`workforce_period_close` / `workforce_period_reopen`), que é onde a\n// permissão e o registro de QUEM moram. Reabrir exige motivo — reabrir sem\n// dizer por quê é como não ter fechado.\n//\n// Fechado significa que nenhuma batida nem ajuste entra com data naquele mês; a\n// trava é de banco (trigger), não de tela.\n// ---------------------------------------------------------------------------\n\nfunction monthLabel(iso: string): string {\n return new Date(`${iso}T12:00:00`).toLocaleDateString('pt-BR', { month: 'long', year: 'numeric' })\n}\n\n/** Os últimos doze meses, do mais recente para trás. É o horizonte que o RH usa. */\nfunction lastMonths(count: number): string[] {\n const out: string[] = []\n const d = new Date()\n d.setDate(1)\n for (let i = 0; i < count; i++) {\n out.push(`${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-01`)\n d.setMonth(d.getMonth() - 1)\n }\n return out\n}\n\nexport function PeriodsView() {\n const provider = useWorkforceProvider()\n const periods = useWorkforceStore((s) => s.periods)\n const loading = useWorkforceStore((s) => s.periodsLoading)\n const fetchPeriods = useWorkforceStore((s) => s.fetchPeriods)\n\n const [dialog, setDialog] = React.useState<{ month: string; mode: 'close' | 'reopen' } | null>(null)\n const [text, setText] = React.useState('')\n const [busy, setBusy] = React.useState(false)\n\n React.useEffect(() => { void fetchPeriods() }, [fetchPeriods])\n\n const byMonth = React.useMemo(() => {\n const map = new Map<string, WorkforcePeriod>()\n for (const p of periods) map.set(p.competenceMonth, p)\n return map\n }, [periods])\n\n async function confirm() {\n if (!dialog) return\n if (dialog.mode === 'reopen' && !text.trim()) {\n toast.error('O motivo da reabertura é obrigatório.')\n return\n }\n setBusy(true)\n try {\n if (dialog.mode === 'close') await provider.closePeriod(dialog.month, text.trim() || undefined)\n else await provider.reopenPeriod(dialog.month, text.trim())\n await fetchPeriods()\n toast.success(dialog.mode === 'close' ? 'Competência fechada.' : 'Competência reaberta.')\n setDialog(null)\n setText('')\n } catch (e: any) {\n toast.error(e?.message ?? 'Não foi possível concluir.')\n } finally {\n setBusy(false)\n }\n }\n\n return (\n <div className=\"space-y-4 p-6\">\n <div>\n <h2 className=\"text-lg font-semibold\">Fechamento de competência</h2>\n <p className=\"text-sm text-muted-foreground\">\n Mês fechado não aceita batida nem ajuste com data dentro dele. A trava é do banco.\n </p>\n </div>\n\n {loading ? (\n <div className=\"space-y-2\"><Skeleton className=\"h-14 w-full\" /><Skeleton className=\"h-14 w-full\" /></div>\n ) : (\n <div className=\"divide-y divide-border rounded-xl border border-border\">\n {lastMonths(12).map((month) => {\n const period = byMonth.get(month)\n const closed = period?.status === 'closed'\n return (\n <div key={month} className=\"flex flex-wrap items-center justify-between gap-3 px-4 py-3\">\n <div className=\"flex items-center gap-3\">\n <CalendarCheck className=\"h-4 w-4 text-muted-foreground\" aria-hidden />\n <div>\n <div className=\"text-sm font-medium capitalize\">{monthLabel(month)}</div>\n <div className=\"text-xs text-muted-foreground\">\n {closed\n ? `Fechada em ${period?.closedAt ? new Date(period.closedAt).toLocaleDateString('pt-BR') : '—'}`\n : period?.reopenReason\n ? `Reaberta: ${period.reopenReason}`\n : 'Aberta'}\n </div>\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n <Badge variant={closed ? 'success' : 'secondary'}>{closed ? 'Fechada' : 'Aberta'}</Badge>\n <Button\n size=\"sm\"\n variant={closed ? 'ghost' : 'secondary'}\n onClick={() => { setText(''); setDialog({ month, mode: closed ? 'reopen' : 'close' }) }}\n >\n {closed\n ? <><Unlock className=\"mr-1 h-3.5 w-3.5\" aria-hidden /> Reabrir</>\n : <><Lock className=\"mr-1 h-3.5 w-3.5\" aria-hidden /> Fechar</>}\n </Button>\n </div>\n </div>\n )\n })}\n </div>\n )}\n\n {dialog && (\n <Modal open onOpenChange={(o) => { if (!o) setDialog(null) }}>\n <ModalContent size=\"sm\">\n <ModalHeader>\n <ModalTitle>\n {dialog.mode === 'close' ? 'Fechar' : 'Reabrir'} {monthLabel(dialog.month)}\n </ModalTitle>\n </ModalHeader>\n <ModalBody>\n <Input\n value={text}\n onChange={(e) => setText(e.target.value)}\n placeholder={dialog.mode === 'close' ? 'Observação (opcional)' : 'Motivo da reabertura (obrigatório)'}\n />\n </ModalBody>\n <ModalFooter>\n <Button variant=\"ghost\" onClick={() => setDialog(null)}>Cancelar</Button>\n <Button onClick={confirm} disabled={busy}>Confirmar</Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n )}\n </div>\n )\n}\n","import React from 'react'\nimport { createCrudPage } from '@fayz-ai/admin'\nimport type { EntityDef } from '@fayz-ai/core'\n\n// ---------------------------------------------------------------------------\n// Pessoas & Documentos — a ficha do colaborador.\n//\n// NADA novo aqui, e é de propósito: o colaborador já é `public.people` com\n// papel de equipe, e o arquétipo de pessoa do @fayz-ai/admin já desenha a ficha\n// inteira — acesso, unidades, horário, endereços, DOCUMENTOS, extrato e\n// atividade — para qualquer entidade declarada com `layout: 'person'`.\n//\n// Uma segunda tela de cadastro de gente aqui dentro seria um segundo lugar para\n// o mesmo nome ficar desatualizado. O que este módulo faz é trazer a ficha para\n// dentro dele, não refazê-la.\n// ---------------------------------------------------------------------------\n\n/** O recorte de `public.people` que o RH edita. O app pode substituir. */\nexport const DEFAULT_STAFF_ENTITY: EntityDef = {\n name: 'Colaborador',\n namePlural: 'Pessoas',\n icon: 'UserCog',\n layout: 'person',\n displayField: 'name',\n defaultSort: 'name',\n fields: [\n { key: 'name', label: 'Nome', type: 'text', required: true, showInTable: true, searchable: true },\n { key: 'phone', label: 'Telefone', type: 'phone', showInTable: true },\n { key: 'email', label: 'E-mail', type: 'email', showInTable: false },\n { key: 'documentNumber', label: 'CPF', type: 'text', showInTable: true },\n { key: 'isActive', label: 'Ativo', type: 'boolean', showInTable: true, defaultValue: true, inlineToggle: true },\n ],\n data: {\n table: 'people',\n tenantScoped: true,\n archetype: 'person',\n archetypeKind: 'staff',\n searchColumns: ['name', 'email', 'phone'],\n },\n}\n\n/** Memoizado por entidade: `createCrudPage` monta um store, e remontá-lo a cada\n * render zeraria a lista sempre que a aba repintasse. */\nconst cache = new Map<EntityDef, React.ComponentType>()\n\nexport function PeopleView({ entity }: { entity?: EntityDef }) {\n const def = entity ?? DEFAULT_STAFF_ENTITY\n const Page = React.useMemo(() => {\n const cached = cache.get(def)\n if (cached) return cached\n const created = createCrudPage(def as never)\n cache.set(def, created)\n return created\n }, [def])\n return <Page />\n}\n","import React from 'react'\nimport { getSupabaseClientOptional } from '@fayz-ai/core'\n\n// ---------------------------------------------------------------------------\n// usePayrollAccounts — quais ramos do plano de contas são custo de pessoal\n// ---------------------------------------------------------------------------\n// Mesma forma do `useDeliverySettings` do plugin-orders, e pela mesma razão: é\n// UMA decisão da casa, guardada em `tenants.settings` pelas RPCs do spine\n// (`tenant_settings` para ler tudo, `tenant_setting_set` para gravar). A função\n// recusa chave não registrada e cobra `settings.manage` — a chave está\n// registrada em workforce/006.\n//\n// Sem escolha gravada o valor é `null`, e é DIFERENTE de `[]`: nulo é \"a casa\n// não disse\", e a tela mostra todas as despesas avisando que é o que está\n// fazendo. Um array vazio seria \"a casa disse que nada é pessoal\", que é uma\n// afirmação — e mostraria a tela vazia.\n\nconst KEY = 'workforce.payroll_account_codes'\n\nexport interface PayrollAccountsHandle {\n /** Os códigos escolhidos, ou null quando a casa nunca escolheu. */\n codes: string[] | null\n /** Grava (ou apaga, com null). */\n save: (next: string[] | null) => Promise<void>\n loading: boolean\n saving: boolean\n /** A gravação foi recusada — em geral falta `settings.manage`. */\n error: string | null\n /** Sem backend montado (mock/standalone): a tela não oferece o controle. */\n supported: boolean\n}\n\nfunction message(e: unknown): string {\n if (e instanceof Error) return e.message\n if (typeof e === 'object' && e && 'message' in e) return String((e as { message: unknown }).message)\n return String(e)\n}\n\nfunction normalize(value: unknown): string[] | null {\n if (!Array.isArray(value)) return null\n const codes = value.map((v) => String(v).trim()).filter(Boolean)\n return codes.length ? codes : null\n}\n\nexport function usePayrollAccounts(): PayrollAccountsHandle {\n const client = React.useMemo(() => getSupabaseClientOptional() as any, [])\n const supported = !!client\n\n const [codes, setCodes] = React.useState<string[] | null>(null)\n const [loading, setLoading] = React.useState(supported)\n const [saving, setSaving] = React.useState(false)\n const [error, setError] = React.useState<string | null>(null)\n\n React.useEffect(() => {\n if (!client) return\n let cancelled = false\n setLoading(true)\n void client\n .rpc('tenant_settings')\n .then(({ data, error: e }: { data: Record<string, unknown> | null; error: unknown }) => {\n if (cancelled || e) return\n setCodes(normalize((data ?? {})[KEY]))\n })\n // Leitura falhada cai em \"não escolheu\": a tela então mostra tudo e diz\n // isso, que é o mesmo comportamento seguro de uma casa sem escolha.\n .catch(() => {})\n .finally(() => { if (!cancelled) setLoading(false) })\n return () => { cancelled = true }\n }, [client])\n\n const save = React.useCallback(async (next: string[] | null) => {\n const value = next && next.length ? next : null\n setCodes(value)\n if (!client) return\n setError(null)\n setSaving(true)\n try {\n const { error: e } = await client.rpc('tenant_setting_set', { p_key: KEY, p_value: value })\n if (e) throw e\n } catch (e) {\n setError(message(e))\n } finally {\n setSaving(false)\n }\n }, [client])\n\n return { codes, save, loading, saving, error, supported }\n}\n","import React from 'react'\nimport { HandCoins, ExternalLink, ListTree, AlertTriangle } from 'lucide-react'\nimport type { AnalyticsDateRange, AnalyticsRow, AnalyticsStatementDef } from '@fayz-ai/core'\nimport {\n Button, Checkbox, DateRangeControl, PageToolbar, Popover, PopoverContent, PopoverTrigger,\n StatTiles, StatementTable, compareCodes, resolveRangePreset, type AnalyticsRangePreset,\n} from '@fayz-ai/ui'\nimport { adminNavigateTo, usePermissionOptional } from '@fayz-ai/admin'\nimport { formatCurrency, useWorkforceConfig, useWorkforceProvider } from '../context'\nimport { usePayrollAccounts } from '../settings/usePayrollAccounts'\nimport type { PayrollCostRow } from '../types'\n\n// ---------------------------------------------------------------------------\n// Encargos e Honorários — o custo de pessoal, LIDO, e desenhado como\n// demonstrativo.\n//\n// Este módulo não cria tabela de folha, e não escreve nada aqui. Quem lança\n// salário, encargo e honorário é o Financeiro, e o demonstrativo dele já sabe\n// onde cada despesa cai — `plg_financial_rep_dre`, a MESMA view do relatório de\n// DRE, agregada por conta × mês.\n//\n// Duplicar a escrita aqui daria dois livros para a mesma despesa, e a pergunta\n// \"quanto custou a equipe em março?\" passaria a ter duas respostas. Ler uma\n// segunda fonte daria o mesmo estrago mais devagar: era assim até 19/09/2026 —\n// esta tela somava `v_financial_invoice_lines` linha a linha, e as duas contas\n// podiam divergir sem que nada avisasse.\n//\n// ── Por que demonstrativo e não lista ──────────────────────────────────────\n//\n// A tela mostrava uma lista chapada por mês: `5.4.1 Freela Cozinha · R$ 57.289`\n// ao lado de `5 DESPESAS COM PESSOAL`, sem hierarquia, sem as mães e sem\n// comparação entre meses. O mesmo dado é um DEMONSTRATIVO — a árvore do plano de\n// contas, uma coluna por mês, o valor do pai somado dos filhos — e o SDK já tem\n// o componente que o desenha: `StatementTable`, o mesmo do relatório de DRE.\n// Aqui ele recebe uma seção só (despesa) e o recorte de pessoal.\n//\n// ── O recorte é uma DECLARAÇÃO da casa ─────────────────────────────────────\n//\n// Sem recorte esta tela somava aluguel, IPTU, ICMS e equipamentos sob o título\n// \"custo de pessoal\": no cluster onde isto foi medido, R$ 2.036.706 de despesa\n// classificada em 2026 contra R$ 511.131 do ramo de pessoal — quatro quintos do\n// total não eram gente. Qual ramo é pessoal só a casa sabe (aqui é `5`; o template\n// que o SDK semeia põe folha em `4.03`), então mora em `tenants.settings`:\n// `workforce.payroll_account_codes`, registrada em workforce/006.\n//\n// Nulo é \"não escolheu\", e a tela então mostra TODAS as despesas classificadas\n// AVISANDO que é o que está fazendo. Um padrão inventado ('5') mentiria com\n// convicção no primeiro plano que usa outro número.\n// ---------------------------------------------------------------------------\n\n/** A conta pertence ao recorte? `null` = sem recorte, tudo pertence. */\nfunction noEscopo(code: string, escopo: string[] | null): boolean {\n if (!escopo) return true\n return escopo.some((c) => code === c || code.startsWith(`${c}.`))\n}\n\n/** Um ancestral já escolhido cobre este código — o filho não precisa ser marcado. */\nfunction cobertoPorAncestral(code: string, escopo: string[]): boolean {\n return escopo.some((c) => c !== code && code.startsWith(`${c}.`))\n}\n\n/** Todo 1º de mês entre duas datas, inclusive — as colunas do demonstrativo.\n * É ela que diz qual COMPETÊNCIA está na tela — o seletor de período fala em\n * dias, e o demonstrativo responde em meses. */\nfunction mesesEntre(de: string, ate: string): string[] {\n const out: string[] = []\n const fim = new Date(`${ate.slice(0, 10)}T12:00:00`)\n const cursor = new Date(`${de.slice(0, 7)}-01T12:00:00`)\n while (cursor <= fim && out.length < 120) {\n out.push(`${cursor.getFullYear()}-${String(cursor.getMonth() + 1).padStart(2, '0')}-01`)\n cursor.setMonth(cursor.getMonth() + 1)\n }\n return out\n}\n\nconst MESES = ['jan', 'fev', 'mar', 'abr', 'mai', 'jun', 'jul', 'ago', 'set', 'out', 'nov', 'dez']\n\n/** '2026-09-01' → 'set/26'. Escrito à mão porque o `Intl` do pt-BR devolve\n * 'set. de 26', que num cabeçalho de coluna ocupa o triplo do espaço. */\nfunction monthLabel(iso: string): string {\n const [ano, mes] = iso.slice(0, 7).split('-')\n return `${MESES[Number(mes) - 1] ?? mes}/${ano.slice(2)}`\n}\n\n\n// Uma seção só: esta tela é o ramo de DESPESA do demonstrativo, não o resultado\n// do exercício. As linhas de total do DRE (\"= RESULTADO OPERACIONAL\") não têm\n// sentido aqui — não há receita para subtrair de nada.\nconst DEF: AnalyticsStatementDef = {\n codeKey: 'statement_code',\n labelKey: 'statement_name',\n periodKey: 'competence_month',\n valueKey: 'amount',\n sectionKey: 'direction',\n sections: [\n {\n value: 'payable',\n label: 'Despesas',\n // A linha sem conta é uma linha de verdade. Escondê-la faria a soma da\n // árvore não fechar com o total do rodapé.\n unclassifiedLabel: 'Sem classificação',\n },\n ],\n lines: [\n { kind: 'section', section: 'payable' },\n { kind: 'total', label: 'TOTAL NO PERÍODO', of: { payable: 1 }, emphasis: 'rule' },\n ],\n defaultDepth: 1,\n}\n\nexport function PayrollCostsView() {\n const provider = useWorkforceProvider()\n const { currency } = useWorkforceConfig()\n const can = usePermissionOptional()\n const podeConfigurar = can('settings', 'manage')\n const escopoStore = usePayrollAccounts()\n\n // O mesmo controle de período das outras telas — ver TimeEntriesView.\n const [preset, setPreset] = React.useState<AnalyticsRangePreset | 'custom'>('this_month')\n const [range, setRange] = React.useState<AnalyticsDateRange>(() => resolveRangePreset('this_month'))\n const from = range.from\n const to = range.to\n const [rows, setRows] = React.useState<PayrollCostRow[] | null>(null)\n const [unavailable, setUnavailable] = React.useState(false)\n const [loading, setLoading] = React.useState(true)\n\n React.useEffect(() => {\n let cancelled = false\n setLoading(true)\n const load = provider.getPayrollCosts\n if (!load) {\n setUnavailable(true)\n setLoading(false)\n return\n }\n // Estrutura e movimento vêm na MESMA resposta: a linha sem mês é a conta do\n // plano (\"existe, não teve movimento\"), a linha com mês é o lançamento.\n load({ from, to })\n .then((r) => {\n if (cancelled) return\n setRows(r)\n setUnavailable(false)\n })\n // Cluster sem o Financeiro instalado: a tela se explica em vez de quebrar.\n .catch(() => { if (!cancelled) setUnavailable(true) })\n .finally(() => { if (!cancelled) setLoading(false) })\n return () => { cancelled = true }\n }, [provider, from, to])\n\n const escopo = escopoStore.codes\n\n /** O plano de despesa, para o seletor: as linhas de estrutura da resposta. */\n const despesas = React.useMemo(\n () => (rows ?? [])\n .filter((r) => r.competenceMonth === null && r.chartAccountCode)\n .map((r) => ({ code: r.chartAccountCode as string, name: r.chartAccountName }))\n .sort((a, b) => compareCodes(a.code, b.code)),\n [rows],\n )\n\n /** O que o período mediu, dentro do recorte. A linha SEM conta não pertence a\n * ramo nenhum: ela entra quando não há recorte (a tela mostra tudo e avisa) e\n * fica de fora quando a casa declarou quais ramos são pessoal. */\n const movimento = React.useMemo(\n () => (rows ?? []).filter((r) => r.competenceMonth !== null\n && (r.chartAccountCode ? noEscopo(r.chartAccountCode, escopo) : !escopo)),\n [rows, escopo],\n )\n\n const analyticsRows = React.useMemo<AnalyticsRow[]>(() => {\n const out: AnalyticsRow[] = []\n // ESTRUTURA: a conta existe e pode não ter tido movimento. Sem mês, de\n // propósito — cria o nó na árvore e não cria coluna (ver `buildStatement`).\n for (const a of despesas) {\n if (!noEscopo(a.code, escopo)) continue\n out.push({\n direction: 'payable',\n statement_code: a.code,\n statement_name: a.name,\n competence_month: null,\n amount: 0,\n })\n }\n // MOVIMENTO. Sem código é a linha \"sem classificação\" do demonstrativo —\n // uma despesa lançada em conta que não é de despesa. Fica à vista e dentro\n // do total: escondê-la faria a árvore não fechar com o rodapé.\n for (const r of movimento) {\n out.push({\n direction: 'payable',\n statement_code: r.chartAccountCode ?? '',\n statement_name: r.chartAccountName,\n competence_month: r.competenceMonth,\n amount: r.total,\n })\n }\n return out\n }, [despesas, movimento, escopo])\n\n const total = movimento.reduce((s, r) => s + r.total, 0)\n const meses = new Set(movimento.map((r) => r.competenceMonth)).size\n\n // O que a tela REALMENTE mediu. O demonstrativo é por competência mensal, e o\n // seletor de período fala em dias: \"últimos 7 dias\" traz o mês inteiro. Dizer\n // qual competência está na tela custa uma linha e evita que alguém leia o\n // total de setembro como o total de uma semana.\n const competencia = React.useMemo(() => {\n const ms = mesesEntre(from, to)\n if (ms.length === 0) return null\n return ms.length === 1\n ? monthLabel(ms[0])\n : `${monthLabel(ms[0])} a ${monthLabel(ms[ms.length - 1])}`\n }, [from, to])\n\n return (\n <div className=\"space-y-4 p-6\">\n <PageToolbar\n range={\n <DateRangeControl value={range} onChange={setRange} preset={preset} onPresetChange={setPreset} />\n }\n storageKey=\"workforce.payroll-costs\"\n />\n <div className=\"flex flex-wrap items-end justify-between gap-3\">\n <div>\n <h2 className=\"text-lg font-semibold\">Encargos e honorários</h2>\n <p className=\"text-sm text-muted-foreground\">\n O custo de pessoal como o Financeiro o registrou, na árvore do plano de contas.\n Esta tela só lê — o lançamento continua sendo lá.\n </p>\n {competencia ? (\n <p className=\"mt-0.5 text-xs text-muted-foreground\">\n Competência <span className=\"font-medium\">{competencia}</span> — o\n demonstrativo é mensal, e o período escolhido vira meses inteiros.\n </p>\n ) : null}\n </div>\n <div className=\"flex items-center gap-2\">\n {unavailable ? null : (\n <EscopoPopover\n contas={despesas}\n escopo={escopo}\n podeConfigurar={podeConfigurar}\n store={escopoStore}\n />\n )}\n <Button variant=\"secondary\" onClick={() => adminNavigateTo('/financial')}>\n <ExternalLink className=\"mr-1 h-4 w-4\" aria-hidden /> Abrir Financeiro\n </Button>\n </div>\n </div>\n\n {unavailable ? (\n <div className=\"rounded-xl border border-dashed border-border p-8 text-center\">\n <HandCoins className=\"mx-auto mb-3 h-8 w-8 text-muted-foreground\" aria-hidden />\n <p className=\"text-sm text-muted-foreground\">\n O razão do Financeiro não está disponível neste ambiente — instale o módulo Financeiro\n para ver o custo de pessoal aqui.\n </p>\n </div>\n ) : (\n <>\n {/* O aviso é a parte não-cosmética da tela: sem recorte o total inclui\n aluguel e imposto, e quem lê precisa saber disso ANTES do número. */}\n {!escopoStore.loading && !escopo ? (\n <div className=\"flex items-start gap-3 rounded-xl border border-warning/40 bg-warning/5 p-4\">\n <AlertTriangle className=\"mt-0.5 h-4 w-4 shrink-0 text-warning\" aria-hidden />\n <div className=\"space-y-1 text-sm\">\n <p className=\"font-medium\">Nenhum ramo de pessoal escolhido.</p>\n <p className=\"text-muted-foreground\">\n O demonstrativo abaixo soma <strong>todas</strong> as despesas classificadas em\n conta contábil — inclusive aluguel, imposto e equipamento. Escolha em{' '}\n <span className=\"whitespace-nowrap font-medium\">Contas de pessoal</span> os ramos\n do seu plano que são gente, e o total passa a valer como custo de equipe.\n </p>\n </div>\n </div>\n ) : null}\n\n <StatTiles\n loading={loading}\n tiles={[\n { id: 'total', label: 'Total no período', value: formatCurrency(total, currency) },\n { id: 'months', label: 'Competências', value: String(meses) },\n {\n id: 'avg',\n label: 'Média mensal',\n value: meses > 0 ? formatCurrency(total / meses, currency) : formatCurrency(0, currency),\n },\n ]}\n />\n\n <StatementTable\n rows={analyticsRows}\n def={DEF}\n currency={currency}\n formatPeriod={monthLabel}\n accountLabel=\"Conta\"\n totalLabel=\"Período\"\n emptyMessage=\"Nenhuma despesa classificada em conta contábil no período.\"\n loading={loading}\n />\n </>\n )}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// O recorte, escolhido na árvore\n// ---------------------------------------------------------------------------\n\nfunction EscopoPopover({\n contas, escopo, podeConfigurar, store,\n}: {\n contas: { code: string; name: string }[]\n escopo: string[] | null\n podeConfigurar: boolean\n store: ReturnType<typeof usePayrollAccounts>\n}) {\n const marcados = React.useMemo(() => new Set(escopo ?? []), [escopo])\n\n const alterna = (code: string) => {\n const next = new Set(marcados)\n if (next.has(code)) next.delete(code)\n else {\n // Marcar um pai dispensa os filhos: o código carrega a descendência, e\n // guardar as duas coisas faria a configuração envelhecer a cada conta\n // nova criada dentro do ramo.\n for (const c of [...next]) if (c.startsWith(`${code}.`)) next.delete(c)\n next.add(code)\n }\n void store.save([...next].sort(compareCodes))\n }\n\n const rotulo = escopo\n ? `${escopo.length} ${escopo.length === 1 ? 'ramo' : 'ramos'} de pessoal`\n : 'Contas de pessoal'\n\n return (\n <Popover>\n <PopoverTrigger asChild>\n <Button variant={escopo ? 'secondary' : 'default'}>\n <ListTree className=\"mr-1 h-4 w-4\" aria-hidden /> {rotulo}\n </Button>\n </PopoverTrigger>\n <PopoverContent align=\"end\" className=\"w-[26rem] p-0\">\n <div className=\"border-b p-3\">\n <p className=\"text-sm font-medium\">O que é custo de pessoal</p>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n Marque os ramos do seu plano de contas. Um ramo marcado traz toda a descendência —\n inclusive contas criadas depois.\n </p>\n </div>\n <div className=\"max-h-80 overflow-y-auto py-1\">\n {contas.length === 0 ? (\n <p className=\"p-3 text-xs text-muted-foreground\">\n Nenhuma conta de despesa ativa no plano.\n </p>\n ) : (\n contas.map((c) => {\n const depth = c.code.split('.').length - 1\n const herdado = cobertoPorAncestral(c.code, [...marcados])\n const checked = marcados.has(c.code) || herdado\n return (\n <label\n key={c.code}\n className=\"flex cursor-pointer items-center gap-2 px-3 py-1.5 text-sm hover:bg-muted/50\"\n style={{ paddingLeft: `${12 + depth * 14}px` }}\n >\n <Checkbox\n checked={checked}\n // Herdado do pai: desmarcar aqui não faria nada, então o\n // controle diz que a escolha é lá em cima.\n disabled={!podeConfigurar || store.saving || herdado}\n onChange={() => alterna(c.code)}\n />\n <span className=\"w-16 shrink-0 font-mono text-xs text-muted-foreground\">{c.code}</span>\n <span className=\"truncate\">{c.name}</span>\n </label>\n )\n })\n )}\n </div>\n <div className=\"flex items-center justify-between gap-2 border-t p-3\">\n <span className=\"text-xs text-muted-foreground\">\n {!podeConfigurar\n ? 'Só quem tem settings.manage pode mudar isto.'\n : store.error\n ? store.error\n : store.saving\n ? 'Salvando…'\n : 'Salva sozinho, para toda a casa.'}\n </span>\n {escopo && podeConfigurar ? (\n <Button variant=\"ghost\" size=\"sm\" onClick={() => void store.save(null)}>\n Limpar\n </Button>\n ) : null}\n </div>\n </PopoverContent>\n </Popover>\n )\n}\n","import React from 'react'\nimport { CalendarClock, CakeSlice, UserMinus, UserPlus, Users, AlertTriangle, ShieldAlert, Plane, Stethoscope, ClipboardList, Plus } from 'lucide-react'\nimport {\n Badge, Button, Input, Modal, ModalContent, ModalHeader, ModalTitle, ModalBody, ModalFooter,\n Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Skeleton, toast,\n} from '@fayz-ai/ui'\nimport { PersonLink } from '@fayz-ai/admin'\nimport { useWorkforceConfig, useWorkforceProvider } from '../context'\nimport type {\n Absence, AbsenceKind, ContractKind, Employment, HrOverview, HrUpcoming, WorkforcePerson,\n PayFrequency, PendingItem, PendingPriority, ScheduleRegime, Vacation, VacationStatus,\n} from '../types'\n\n// ---------------------------------------------------------------------------\n// Recursos Humanos.\n//\n// Portado de `~/dev/beautyplace/docs/v1-guide/rh`, e é o NÚCLEO do módulo do V1,\n// não a cópia dele. O V1 tem dezesseis vistas na ficha; doze estão vazias no\n// banco inteiro — não \"vazias nesses tenants\", vazias em produção — e portar\n// formulário para zero linha é construir tela por leitura de documento.\n//\n// Ficam as quatro que sustentam os números e a rotina:\n//\n// Vínculo de onde saem headcount, admissões, demissões, turnover e\n// experiência vencendo. Sem ele nenhum número de RH existe\n// Férias obrigação legal, recorrente, e a única lista do V1 que\n// alimenta um cartão do painel\n// Afastamentos e aqui o V2 faz o que o V1 não faz: ver o comentário em\n// `v_workforce_day` da migration 005\n// Pendências a outra lista que o painel cobra\n//\n// A TELA É UMA SÓ, e isso é decisão. O V1 separa o painel (`/rh`) da ficha\n// (dentro do cadastro da pessoa), e o próprio FLOW anota que nenhum cartão e\n// nenhuma linha do painel é clicável — \"daqui não se chega à ficha da pessoa\".\n// Ler que três pessoas têm férias vencendo e ter de procurar cada uma noutra\n// tela é o gesto que a divisão custa. Aqui o painel é a porta: clicar no nome\n// abre a ficha embaixo.\n// ---------------------------------------------------------------------------\n\nconst CONTRATO: Record<ContractKind, string> = {\n clt: 'CLT', pj: 'PJ', estagio: 'Estágio', jovem_aprendiz: 'Jovem Aprendiz',\n autonomo: 'Autônomo', socio: 'Sócio', temporario: 'Temporário', intermitente: 'Intermitente',\n}\nconst REGIME: Record<ScheduleRegime, string> = {\n mensalista: 'Mensalista', horista: 'Horista', diarista: 'Diarista',\n escala_12x36: 'Escala 12x36', escala_6x1: 'Escala 6x1', escala_5x2: 'Escala 5x2',\n}\nconst PAGAMENTO: Record<PayFrequency, string> = {\n mensal: 'Mensal', quinzenal: 'Quinzenal', semanal: 'Semanal', diario: 'Diário', por_hora: 'Por hora',\n}\nconst FERIAS: Record<VacationStatus, string> = {\n pendente: 'Pendente', programada: 'Programada', em_gozo: 'Em gozo',\n concluida: 'Concluída', vencida: 'Vencida',\n}\nexport const AFASTAMENTO: Record<AbsenceKind, string> = {\n falta_justificada: 'Falta justificada', falta_injustificada: 'Falta injustificada',\n atestado: 'Atestado médico', licenca_maternidade: 'Licença maternidade',\n licenca_paternidade: 'Licença paternidade', licenca_nao_remunerada: 'Licença não remunerada',\n suspensao: 'Suspensão', ferias: 'Férias', afastamento_inss: 'Afastamento INSS',\n}\nconst PRIORIDADE: Record<PendingPriority, string> = {\n baixa: 'Baixa', normal: 'Normal', alta: 'Alta', urgente: 'Urgente',\n}\n\nfunction dm(iso?: string | null): string {\n if (!iso) return '—'\n const [a, m, d] = iso.slice(0, 10).split('-')\n return `${d}/${m}/${a}`\n}\n\n/** Um cartão de número. Zero é resposta, não ausência — ver o comentário abaixo. */\nfunction Cartao({ icon: Icon, label, value, alerta }: {\n icon: React.ComponentType<{ className?: string }>\n label: string\n value: React.ReactNode\n alerta?: boolean\n}) {\n return (\n <div className=\"rounded-xl border border-border p-4\">\n <div className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <Icon className=\"h-3.5 w-3.5\" aria-hidden /> {label}\n </div>\n <div className={`mt-1 text-2xl font-semibold tabular-nums ${alerta ? 'text-destructive' : ''}`}>\n {value}\n </div>\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// O painel\n// ---------------------------------------------------------------------------\n\nfunction Painel({ overview, upcoming, onPessoa }: {\n overview: HrOverview\n upcoming: HrUpcoming[]\n onPessoa: (id: string) => void\n}) {\n // Turnover é conta de tela de propósito: a view devolve as duas parcelas, e\n // dividir aqui evita uma coluna que mente quando o headcount é zero.\n const turnover = overview.headcount > 0\n ? ((overview.dismissals30d / overview.headcount) * 100).toFixed(1)\n : null\n\n const porEspecie = (k: HrUpcoming['kind']) => upcoming.filter((u) => u.kind === k).slice(0, 10)\n\n const listas: Array<{ kind: HrUpcoming['kind']; titulo: string; vazio: string }> = [\n { kind: 'vacation', titulo: 'Férias a vencer', vazio: 'Nenhuma.' },\n { kind: 'probation', titulo: 'Experiência vencendo', vazio: 'Nenhuma.' },\n { kind: 'pending', titulo: 'Pendências críticas', vazio: 'Nenhuma.' },\n ]\n\n return (\n <div className=\"space-y-4\">\n <div className=\"grid gap-3 sm:grid-cols-2 lg:grid-cols-4\">\n <Cartao icon={Users} label=\"Headcount ativo\" value={overview.headcount} />\n <Cartao icon={UserPlus} label=\"Admissões (30d)\" value={overview.admissions30d} />\n <Cartao icon={UserMinus} label=\"Demissões (30d)\" value={overview.dismissals30d} />\n <Cartao icon={AlertTriangle} label=\"Turnover (30d)\" value={turnover != null ? `${turnover}%` : '—'} />\n <Cartao icon={CakeSlice} label=\"Aniversariantes do mês\" value={overview.birthdaysThisMonth} />\n <Cartao icon={Plane} label=\"Férias vencendo (60d)\" value={overview.vacationsDue60d}\n alerta={overview.vacationsDue60d > 0} />\n <Cartao icon={CalendarClock} label=\"Experiência vencendo\" value={overview.probationEnding}\n alerta={overview.probationEnding > 0} />\n <Cartao icon={ShieldAlert} label=\"Pendências críticas\" value={overview.criticalPending}\n alerta={overview.criticalPending > 0} />\n </div>\n\n <div className=\"grid gap-3 lg:grid-cols-3\">\n {listas.map(({ kind, titulo, vazio }) => {\n const itens = porEspecie(kind)\n return (\n <div key={kind} className=\"overflow-hidden rounded-xl border border-border\">\n <div className=\"border-b border-border bg-muted/40 px-4 py-2 text-sm font-medium\">{titulo}</div>\n {itens.length === 0 ? (\n <p className=\"px-4 py-3 text-sm text-muted-foreground\">{vazio}</p>\n ) : (\n <ul className=\"divide-y divide-border\">\n {itens.map((u, i) => (\n <li key={`${u.personId}|${u.dueOn}|${i}`} className=\"flex items-center justify-between gap-2 px-4 py-2 text-sm\">\n {/* O NOME, que o V1 não mostra nesta lista (V1-073) — lá\n são só datas, e descobrir de quem é exige outra tela. */}\n <button type=\"button\" onClick={() => onPessoa(u.personId)}\n className=\"truncate text-left underline decoration-dashed decoration-muted-foreground/40 underline-offset-2 hover:text-primary\">\n {u.personName ?? 'Sem nome'}\n </button>\n <span className=\"shrink-0 text-xs tabular-nums text-muted-foreground\">{dm(u.dueOn)}</span>\n </li>\n ))}\n </ul>\n )}\n </div>\n )\n })}\n </div>\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// A ficha de uma pessoa\n// ---------------------------------------------------------------------------\n\nfunction CampoData({ label, value, onChange }: { label: string; value?: string | null; onChange: (v: string) => void }) {\n return (\n <label className=\"block\">\n <span className=\"mb-1 block text-xs text-muted-foreground\">{label}</span>\n <Input type=\"date\" value={value ?? ''} onChange={(e) => onChange(e.target.value)} />\n </label>\n )\n}\n\nfunction Vinculo({ personId }: { personId: string }) {\n const provider = useWorkforceProvider()\n const { currency } = useWorkforceConfig()\n const [form, setForm] = React.useState<Employment>({ personId })\n const [busy, setBusy] = React.useState(false)\n const [carregando, setCarregando] = React.useState(true)\n\n React.useEffect(() => {\n let vivo = true\n setCarregando(true)\n provider.getEmployment(personId)\n .then((e) => { if (vivo) { setForm(e ?? { personId }); setCarregando(false) } })\n .catch(() => { if (vivo) { setForm({ personId }); setCarregando(false) } })\n return () => { vivo = false }\n }, [provider, personId])\n\n const set = <K extends keyof Employment>(k: K, v: Employment[K]) => setForm((f) => ({ ...f, [k]: v }))\n\n async function salvar() {\n setBusy(true)\n try {\n await provider.saveEmployment({ ...form, personId })\n toast.success('Vínculo salvo.')\n } catch (e: any) {\n toast.error('Não deu para salvar', { description: e?.message })\n } finally {\n setBusy(false)\n }\n }\n\n if (carregando) return <Skeleton className=\"h-48 w-full\" />\n\n return (\n <div className=\"space-y-3 rounded-xl border border-border p-4\">\n <h4 className=\"text-sm font-semibold\">Vínculo</h4>\n <div className=\"grid gap-3 sm:grid-cols-2 lg:grid-cols-4\">\n <label className=\"block\">\n <span className=\"mb-1 block text-xs text-muted-foreground\">Tipo de contrato</span>\n <Select value={form.contractKind ?? ''} onValueChange={(v) => set('contractKind', v as ContractKind)}>\n <SelectTrigger><SelectValue placeholder=\"—\" /></SelectTrigger>\n <SelectContent>\n {Object.entries(CONTRATO).map(([k, r]) => <SelectItem key={k} value={k}>{r}</SelectItem>)}\n </SelectContent>\n </Select>\n </label>\n <CampoData label=\"Admissão\" value={form.admissionDate} onChange={(v) => set('admissionDate', v)} />\n <CampoData label=\"Demissão\" value={form.dismissalDate} onChange={(v) => set('dismissalDate', v)} />\n <CampoData label=\"Fim da experiência\" value={form.probationFinalEnd} onChange={(v) => set('probationFinalEnd', v)} />\n <label className=\"block\">\n <span className=\"mb-1 block text-xs text-muted-foreground\">Cargo</span>\n <Input value={form.jobTitle ?? ''} onChange={(e) => set('jobTitle', e.target.value)} />\n </label>\n <label className=\"block\">\n <span className=\"mb-1 block text-xs text-muted-foreground\">Setor</span>\n <Input value={form.department ?? ''} onChange={(e) => set('department', e.target.value)} />\n </label>\n <label className=\"block\">\n <span className=\"mb-1 block text-xs text-muted-foreground\">Regime de jornada</span>\n <Select value={form.scheduleRegime ?? ''} onValueChange={(v) => set('scheduleRegime', v as ScheduleRegime)}>\n <SelectTrigger><SelectValue placeholder=\"—\" /></SelectTrigger>\n <SelectContent>\n {Object.entries(REGIME).map(([k, r]) => <SelectItem key={k} value={k}>{r}</SelectItem>)}\n </SelectContent>\n </Select>\n </label>\n <label className=\"block\">\n <span className=\"mb-1 block text-xs text-muted-foreground\">Horas semanais</span>\n <Input type=\"number\" value={form.weeklyHours ?? ''} onChange={(e) => set('weeklyHours', e.target.value ? Number(e.target.value) : null)} />\n </label>\n <label className=\"block\">\n <span className=\"mb-1 block text-xs text-muted-foreground\">Salário base ({currency.symbol})</span>\n <Input type=\"number\" step=\"0.01\" value={form.baseSalary ?? ''} onChange={(e) => set('baseSalary', e.target.value ? Number(e.target.value) : null)} />\n </label>\n <label className=\"block\">\n <span className=\"mb-1 block text-xs text-muted-foreground\">Forma de pagamento</span>\n <Select value={form.payFrequency ?? ''} onValueChange={(v) => set('payFrequency', v as PayFrequency)}>\n <SelectTrigger><SelectValue placeholder=\"—\" /></SelectTrigger>\n <SelectContent>\n {Object.entries(PAGAMENTO).map(([k, r]) => <SelectItem key={k} value={k}>{r}</SelectItem>)}\n </SelectContent>\n </Select>\n </label>\n </div>\n {/* A frase que o V1 não escreve e que o FLOW teve de transcrever: estes\n valores não viram lançamento. Sem ela alguém espera o salário na conta\n a pagar do mês seguinte. */}\n <p className=\"text-xs text-muted-foreground\">\n Salário e auxílios são <b>valores de referência</b>: não viram conta a pagar, comissão nem desconto.\n </p>\n <div className=\"flex justify-end\">\n <Button onClick={salvar} disabled={busy}>Salvar vínculo</Button>\n </div>\n </div>\n )\n}\n\n/** Uma lista da ficha: cabeçalho, linhas e o diálogo de lançamento. */\nfunction Lista({ titulo, icon: Icon, itens, vazio, onNovo, children }: {\n titulo: string\n icon: React.ComponentType<{ className?: string }>\n itens: unknown[]\n vazio: string\n onNovo: () => void\n children: React.ReactNode\n}) {\n return (\n <div className=\"overflow-hidden rounded-xl border border-border\">\n <div className=\"flex items-center justify-between gap-2 border-b border-border bg-muted/40 px-4 py-2\">\n <span className=\"flex items-center gap-2 text-sm font-medium\">\n <Icon className=\"h-4 w-4 text-muted-foreground\" aria-hidden /> {titulo}\n </span>\n <Button size=\"sm\" variant=\"outline\" onClick={onNovo}>\n <Plus className=\"mr-1 h-3.5 w-3.5\" aria-hidden /> Novo\n </Button>\n </div>\n {itens.length === 0\n ? <p className=\"px-4 py-3 text-sm text-muted-foreground\">{vazio}</p>\n : <ul className=\"divide-y divide-border\">{children}</ul>}\n </div>\n )\n}\n\nfunction Ficha({ personId, personName }: { personId: string; personName?: string | null }) {\n const provider = useWorkforceProvider()\n const [ferias, setFerias] = React.useState<Vacation[]>([])\n const [faltas, setFaltas] = React.useState<Absence[]>([])\n const [pendencias, setPendencias] = React.useState<PendingItem[]>([])\n const [dialogo, setDialogo] = React.useState<'ferias' | 'falta' | 'pendencia' | null>(null)\n\n const recarregar = React.useCallback(() => {\n provider.getVacations(personId).then(setFerias).catch(() => setFerias([]))\n provider.getAbsences(personId).then(setFaltas).catch(() => setFaltas([]))\n provider.getPendingItems(personId).then(setPendencias).catch(() => setPendencias([]))\n }, [provider, personId])\n\n React.useEffect(() => { recarregar() }, [recarregar])\n\n return (\n <div className=\"space-y-3\">\n <h3 className=\"text-base font-semibold\">{personName ?? 'Ficha'}</h3>\n <Vinculo personId={personId} />\n\n <div className=\"grid gap-3 lg:grid-cols-3\">\n <Lista titulo=\"Férias\" icon={Plane} itens={ferias} vazio=\"Nenhum registro.\"\n onNovo={() => setDialogo('ferias')}>\n {ferias.map((v) => (\n <li key={v.id} className=\"flex items-center justify-between gap-2 px-4 py-2 text-sm\">\n <span className=\"truncate\">{dm(v.accrualStart)} – {dm(v.accrualEnd)}</span>\n <Badge variant={v.status === 'concluida' ? 'secondary' : v.status === 'vencida' ? 'destructive' : 'outline'}>\n {FERIAS[v.status]}\n </Badge>\n </li>\n ))}\n </Lista>\n\n <Lista titulo=\"Afastamentos\" icon={Stethoscope} itens={faltas} vazio=\"Nenhum registro.\"\n onNovo={() => setDialogo('falta')}>\n {faltas.map((a) => (\n <li key={a.id} className=\"flex items-center justify-between gap-2 px-4 py-2 text-sm\">\n <span className=\"truncate\">{AFASTAMENTO[a.kind]}</span>\n <span className=\"shrink-0 text-xs tabular-nums text-muted-foreground\">\n {dm(a.startsOn)}{a.endsOn ? ` – ${dm(a.endsOn)}` : ''}\n </span>\n </li>\n ))}\n </Lista>\n\n <Lista titulo=\"Pendências\" icon={ClipboardList} itens={pendencias} vazio=\"Nenhum registro.\"\n onNovo={() => setDialogo('pendencia')}>\n {pendencias.map((p) => (\n <li key={p.id} className=\"flex items-center justify-between gap-2 px-4 py-2 text-sm\">\n <label className=\"flex min-w-0 items-center gap-2\">\n <input\n type=\"checkbox\"\n checked={!!p.resolvedAt}\n onChange={(e) => provider.resolvePendingItem(p.id!, e.target.checked).then(recarregar)}\n />\n <span className={`truncate ${p.resolvedAt ? 'text-muted-foreground line-through' : ''}`}>{p.title}</span>\n </label>\n {!p.resolvedAt && (p.priority === 'alta' || p.priority === 'urgente') && (\n <Badge variant=\"destructive\">{PRIORIDADE[p.priority]}</Badge>\n )}\n </li>\n ))}\n </Lista>\n </div>\n\n {dialogo && (\n <DialogoLancamento\n tipo={dialogo}\n personId={personId}\n onClose={() => setDialogo(null)}\n onSaved={() => { setDialogo(null); recarregar() }}\n />\n )}\n </div>\n )\n}\n\n/** Um diálogo para as três listas. As três têm a mesma forma: datas e um tipo. */\nfunction DialogoLancamento({ tipo, personId, onClose, onSaved }: {\n tipo: 'ferias' | 'falta' | 'pendencia'\n personId: string\n onClose: () => void\n onSaved: () => void\n}) {\n const provider = useWorkforceProvider()\n const [busy, setBusy] = React.useState(false)\n const [de, setDe] = React.useState('')\n const [ate, setAte] = React.useState('')\n const [kind, setKind] = React.useState<AbsenceKind>('atestado')\n const [titulo, setTitulo] = React.useState('')\n const [prioridade, setPrioridade] = React.useState<PendingPriority>('normal')\n\n const rotulo = tipo === 'ferias' ? 'Período de férias'\n : tipo === 'falta' ? 'Afastamento' : 'Pendência'\n\n async function salvar() {\n setBusy(true)\n try {\n if (tipo === 'ferias') {\n if (!de || !ate) { toast.error('O período aquisitivo é obrigatório.'); return }\n await provider.saveVacation({ personId, accrualStart: de, accrualEnd: ate, status: 'pendente' })\n } else if (tipo === 'falta') {\n if (!de) { toast.error('A data de início é obrigatória.'); return }\n await provider.saveAbsence({ personId, kind, startsOn: de, endsOn: ate || null, paid: true })\n } else {\n if (!titulo.trim()) { toast.error('A pendência precisa de um título.'); return }\n await provider.savePendingItem({ personId, title: titulo.trim(), priority: prioridade, dueOn: de || null })\n }\n toast.success(`${rotulo} lançado.`)\n onSaved()\n } catch (e: any) {\n toast.error('Não deu para salvar', { description: e?.message })\n } finally {\n setBusy(false)\n }\n }\n\n return (\n <Modal open onOpenChange={(o) => { if (!o) onClose() }}>\n <ModalContent>\n {/* \"Novo período de férias\", e não \"Novo Férias\". O V1 monta este título\n por concatenação e sai com a concordância errada — V1-076. */}\n <ModalHeader><ModalTitle>Novo {rotulo.toLowerCase()}</ModalTitle></ModalHeader>\n <ModalBody className=\"space-y-3\">\n {tipo === 'falta' && (\n <Select value={kind} onValueChange={(v) => setKind(v as AbsenceKind)}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n {Object.entries(AFASTAMENTO).map(([k, r]) => <SelectItem key={k} value={k}>{r}</SelectItem>)}\n </SelectContent>\n </Select>\n )}\n {tipo === 'pendencia' && (\n <>\n <Input value={titulo} onChange={(e) => setTitulo(e.target.value)} placeholder=\"O que falta (obrigatório)\" />\n <Select value={prioridade} onValueChange={(v) => setPrioridade(v as PendingPriority)}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n {Object.entries(PRIORIDADE).map(([k, r]) => <SelectItem key={k} value={k}>{r}</SelectItem>)}\n </SelectContent>\n </Select>\n </>\n )}\n <CampoData\n label={tipo === 'ferias' ? 'Início aquisitivo' : tipo === 'falta' ? 'Início' : 'Prazo'}\n value={de} onChange={setDe}\n />\n {tipo !== 'pendencia' && (\n <CampoData label={tipo === 'ferias' ? 'Fim aquisitivo' : 'Fim'} value={ate} onChange={setAte} />\n )}\n </ModalBody>\n <ModalFooter>\n <Button variant=\"ghost\" onClick={onClose}>Cancelar</Button>\n <Button onClick={salvar} disabled={busy}>Salvar</Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n )\n}\n\n// ---------------------------------------------------------------------------\n\nexport function HrView() {\n const provider = useWorkforceProvider()\n const { staffLookup } = useWorkforceConfig()\n const [overview, setOverview] = React.useState<HrOverview | null>(null)\n const [upcoming, setUpcoming] = React.useState<HrUpcoming[]>([])\n const [equipe, setEquipe] = React.useState<WorkforcePerson[]>([])\n const [loading, setLoading] = React.useState(true)\n const [pessoa, setPessoa] = React.useState<{ id: string; name?: string | null } | null>(null)\n\n React.useEffect(() => {\n let vivo = true\n Promise.all([provider.getHrOverview(), provider.getHrUpcoming(), provider.getStaff()])\n .then(([o, u, e]) => { if (vivo) { setOverview(o); setUpcoming(u); setEquipe(e); setLoading(false) } })\n .catch(() => { if (vivo) { setOverview(null); setUpcoming([]); setEquipe([]); setLoading(false) } })\n return () => { vivo = false }\n }, [provider])\n\n const nomeDe = React.useCallback(\n (id: string) => upcoming.find((u) => u.personId === id)?.personName ?? null,\n [upcoming],\n )\n\n if (loading) return <div className=\"space-y-3\"><Skeleton className=\"h-28 w-full\" /><Skeleton className=\"h-40 w-full\" /></div>\n\n return (\n <div className=\"space-y-4\">\n {/* O seletor fica em cima, sempre — inclusive quando há painel.\n Sem ele a tela vazia é um beco: ela manda abrir a ficha \"pelo\n cadastro\" e não diz como, que é literalmente a crítica que o FLOW faz\n ao V1 (\"daqui não se chega à ficha da pessoa\"). Uma ficha nasce aqui. */}\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"text-sm text-muted-foreground\">Abrir a ficha de</span>\n <Select value={pessoa?.id ?? ''} onValueChange={(id) => {\n const p = equipe.find((x) => x.id === id)\n setPessoa({ id, name: p?.name ?? nomeDe(id) })\n }}>\n <SelectTrigger className=\"w-72\">\n <SelectValue placeholder={equipe.length ? 'Escolha alguém da equipe…' : 'Nenhuma pessoa cadastrada'} />\n </SelectTrigger>\n <SelectContent>\n {equipe.map((p) => <SelectItem key={p.id} value={p.id}>{p.name ?? 'Sem nome'}</SelectItem>)}\n </SelectContent>\n </Select>\n </div>\n\n {overview\n ? <Painel overview={overview} upcoming={upcoming} onPessoa={(id) => setPessoa({ id, name: nomeDe(id) })} />\n : (\n // `null` aqui não é erro: `v_workforce_hr_overview` agrupa por tenant e\n // só devolve linha quando existe ao menos um VÍNCULO. Ninguém com\n // vínculo = nada para agrupar. Dizer \"nenhuma ficha ainda\" é a leitura\n // certa; um painel de zeros diria que o time tem zero pessoas.\n <div className=\"rounded-xl border border-dashed border-border p-8 text-center\">\n <Users className=\"mx-auto mb-3 h-8 w-8 text-muted-foreground\" aria-hidden />\n <p className=\"text-sm text-muted-foreground\">\n Nenhuma ficha trabalhista ainda. Escolha alguém acima e preencha o vínculo —\n é dele que saem headcount, admissões e experiência vencendo.\n </p>\n </div>\n )}\n\n {pessoa && (\n <div className=\"rounded-xl border border-border p-4\">\n <div className=\"mb-3 flex items-center justify-between gap-2\">\n <PersonLink personId={pessoa.id} name={pessoa.name ?? 'Pessoa'} kind=\"staff\" lookup={staffLookup} />\n <Button size=\"sm\" variant=\"ghost\" onClick={() => setPessoa(null)}>Fechar</Button>\n </div>\n <Ficha personId={pessoa.id} personName={pessoa.name} />\n </div>\n )}\n </div>\n )\n}\n","import React from 'react'\nimport type { StoreApi } from 'zustand/vanilla'\nimport { ModulePage, type ModuleNavItem } from '@fayz-ai/ui'\nimport {\n useModuleNavigation, parseViewId, useModuleNavAccess,\n EntitlementGate, UpgradePrompt,\n} from '@fayz-ai/admin'\nimport type { EntityDef } from '@fayz-ai/core'\nimport { WorkforceContextProvider, type ResolvedWorkforceConfig } from '../context'\nimport type { WorkforceDataProvider } from '../data/types'\nimport type { WorkforceUIState } from '../store'\nimport { SchedulesView } from './SchedulesView'\nimport { TemplatesView } from './TemplatesView'\nimport { TimeEntriesView } from './TimeEntriesView'\nimport { PeriodsView } from './PeriodsView'\nimport { PeopleView } from './PeopleView'\nimport { PayrollCostsView } from './PayrollCostsView'\nimport { HrView } from './HrView'\n\n// ---------------------------------------------------------------------------\n// A intenção: que subtela, em que modo.\n// ---------------------------------------------------------------------------\n\nexport interface ViewIntent {\n view: string\n mode?: 'list' | 'new' | 'edit' | 'detail'\n editId?: string\n}\n\nfunction parseIntent(activeView: string): ViewIntent {\n // `parseViewId` recolhe '<base>-detail:<id>' / '<base>-edit:<id>' — a forma\n // que `useModuleNavigation` produz a partir da rota.\n const { base, id } = parseViewId(activeView)\n const m = base.match(/^(people)-(new|list|detail|edit)$/)\n if (m) return { view: m[1], mode: m[2] as ViewIntent['mode'], editId: id }\n return { view: base }\n}\n\n// ---------------------------------------------------------------------------\n// A sub-navegação do módulo.\n// ---------------------------------------------------------------------------\n\nfunction buildNav(config: ResolvedWorkforceConfig, activeView: string, navigate: (view: string) => void): ModuleNavItem[] {\n const items: ModuleNavItem[] = []\n\n if (config.modules.schedules) {\n items.push({\n id: 'schedules',\n label: config.labels.schedules,\n icon: 'CalendarDays',\n active: activeView === 'schedules',\n onClick: () => navigate('schedules'),\n })\n }\n\n if (config.modules.templates) {\n items.push({\n id: 'templates',\n label: config.labels.templates,\n icon: 'LayoutTemplate',\n active: activeView === 'templates',\n onClick: () => navigate('templates'),\n })\n }\n\n if (config.modules.timeEntries) {\n items.push({\n id: 'time-entries',\n label: config.labels.timeEntries,\n icon: 'Clock',\n active: activeView === 'time-entries',\n onClick: () => navigate('time-entries'),\n })\n }\n\n if (config.modules.periods) {\n items.push({\n id: 'periods',\n label: config.labels.periods,\n icon: 'Lock',\n active: activeView === 'periods',\n onClick: () => navigate('periods'),\n })\n }\n\n if (config.modules.people) {\n items.push({\n id: 'people',\n label: config.labels.people,\n icon: 'UserCog',\n active: activeView.startsWith('people'),\n onClick: () => navigate('people'),\n })\n }\n\n // Depois do ponto e antes do fechamento: a ficha é o que explica o que a\n // folha de ponto mostra — quem está de atestado, quem está em férias.\n if (config.modules.hr) {\n items.push({\n id: 'hr',\n label: config.labels.hr,\n icon: 'BriefcaseBusiness',\n active: activeView === 'hr',\n onClick: () => navigate('hr'),\n })\n }\n\n if (config.modules.payrollCosts) {\n items.push({\n id: 'payroll-costs',\n label: config.labels.payrollCosts,\n icon: 'HandCoins',\n active: activeView === 'payroll-costs',\n onClick: () => navigate('payroll-costs'),\n })\n }\n\n // Cada item carrega a feature de acesso que o APP mapeou. `useModuleNavAccess`\n // esconde o que o papel nega e coroa o que o plano nega; id fora do mapa fica\n // aberto — o plugin não tem opinião sobre o que é pago.\n for (const item of items) {\n const feature = config.navFeatureMap[item.id]\n if (feature) item.feature = feature\n }\n\n return items\n}\n\n// ---------------------------------------------------------------------------\n// A página\n// ---------------------------------------------------------------------------\n\nexport function WorkforcePage({ config, provider, store, staffEntity }: {\n config: ResolvedWorkforceConfig\n provider: WorkforceDataProvider\n store: StoreApi<WorkforceUIState>\n staffEntity?: EntityDef\n}) {\n // A casa do módulo é Escalas: é a tela que se abre todo dia, e é onde o RH\n // decide alguma coisa. Fechamento é mensal e Templates é anual.\n const { view, direction, navigate } = useModuleNavigation(\n '/workforce',\n {\n schedules: 0, templates: 0, 'time-entries': 0, periods: 0,\n people: 0, 'people-detail': 1, 'people-edit': 2,\n 'payroll-costs': 0,\n },\n 'schedules',\n )\n\n const intent = parseIntent(view)\n const nav = useModuleNavAccess(buildNav(config, view, navigate))\n\n function renderView() {\n // Módulo desligado é desligado também pela URL: tirar o link sem fechar a\n // rota deixaria /workforce/periods inteiro de pé para quem digitar.\n const off =\n (intent.view === 'schedules' && !config.modules.schedules) ||\n (intent.view === 'templates' && !config.modules.templates) ||\n (intent.view === 'time-entries' && !config.modules.timeEntries) ||\n (intent.view === 'periods' && !config.modules.periods) ||\n (intent.view === 'people' && !config.modules.people) ||\n (intent.view === 'hr' && !config.modules.hr) ||\n (intent.view === 'payroll-costs' && !config.modules.payrollCosts)\n if (off) return <SchedulesView />\n\n switch (intent.view) {\n case 'templates': return <TemplatesView />\n case 'time-entries': return <TimeEntriesView />\n case 'periods': return <PeriodsView />\n case 'people': return <PeopleView entity={staffEntity} />\n case 'hr': return <HrView />\n case 'payroll-costs': return <PayrollCostsView />\n case 'schedules':\n default: return <SchedulesView />\n }\n }\n\n // O paywall da subtela vive AQUI porque uma aba interna não é rota do shell —\n // o guarda de rota nunca a vê. Mesmo mapa que coroa o link acima, para que um\n // link de graça nunca fique sobre conteúdo trancado.\n function renderGatedView() {\n const feature = config.navFeatureMap[intent.view]\n if (!feature) return renderView()\n return (\n <EntitlementGate feature={feature} fallback={<UpgradePrompt feature={feature} />}>\n {renderView()}\n </EntitlementGate>\n )\n }\n\n return (\n <WorkforceContextProvider config={config} provider={provider} store={store}>\n <ModulePage\n title={config.labels.pageTitle}\n subtitle={config.labels.pageSubtitle}\n nav={nav}\n navVariant={config.moduleNav}\n showHeader={intent.view === 'schedules'}\n viewKey={view}\n direction={direction}\n >\n {renderGatedView()}\n </ModulePage>\n </WorkforceContextProvider>\n )\n}\n","import type { WorkforceDataProvider } from './types'\nimport type {\n TimeEntry, TimeEntryQuery, TimeAdjustmentInput,\n WorkDay,\n WorkforcePeriod,\n ScheduleTemplate, SaveTemplateInput, SaveShiftInput, SaveRequirementInput,\n DaySchedule, ScheduleQuery, CreateScheduleInput,\n WorkforcePerson,\n PayrollCostRow, PayrollCostQuery,\n} from '../types'\n\n// ---------------------------------------------------------------------------\n// O provider de memória.\n//\n// Serve para montar o app sem banco nenhum: a mesma superfície do Supabase, com\n// uma semente pequena o bastante para caber na cabeça e grande o bastante para\n// a tela mostrar os três estados que importam — o dia certo, a FALTA e o ponto\n// FORA DA ESCALA.\n// ---------------------------------------------------------------------------\n\nlet seq = 1\nconst uid = () => `mock-${seq++}`\n\nfunction isoDate(offsetDays: number): string {\n const d = new Date()\n d.setDate(d.getDate() + offsetDays)\n return d.toISOString().slice(0, 10)\n}\n\nfunction at(date: string, time: string): string {\n return new Date(`${date}T${time}:00`).toISOString()\n}\n\nexport function createMockWorkforceProvider(): WorkforceDataProvider {\n const people: WorkforcePerson[] = [\n { id: 'p1', name: 'Ana Ribeiro', isActive: true },\n { id: 'p2', name: 'Carlos Menezes', isActive: true },\n { id: 'p3', name: 'Júlia Prado', isActive: true },\n ]\n\n const yesterday = isoDate(-1)\n const today = isoDate(0)\n\n const entries: TimeEntry[] = [\n {\n id: uid(), personId: 'p1', personName: 'Ana Ribeiro', kind: 'clock_in',\n workDate: yesterday, seq: 1, origin: 'totem',\n punchedAt: at(yesterday, '08:03'), effectiveAt: at(yesterday, '08:00'),\n adjusted: true, voided: false, adjustmentReason: 'Totem fora de hora',\n adjustedByName: 'Gerente', evidence: {},\n },\n {\n id: uid(), personId: 'p1', personName: 'Ana Ribeiro', kind: 'break_start',\n workDate: yesterday, seq: 2, origin: 'totem',\n punchedAt: at(yesterday, '12:00'), effectiveAt: at(yesterday, '12:00'),\n adjusted: false, voided: false, evidence: {},\n },\n {\n id: uid(), personId: 'p1', personName: 'Ana Ribeiro', kind: 'break_end',\n workDate: yesterday, seq: 3, origin: 'totem',\n punchedAt: at(yesterday, '13:00'), effectiveAt: at(yesterday, '13:00'),\n adjusted: false, voided: false, evidence: {},\n },\n {\n id: uid(), personId: 'p1', personName: 'Ana Ribeiro', kind: 'clock_out',\n workDate: yesterday, seq: 4, origin: 'totem',\n punchedAt: at(yesterday, '17:00'), effectiveAt: at(yesterday, '17:00'),\n adjusted: false, voided: false, evidence: {},\n },\n // Ponto em aberto: entrou e não saiu. É o caso que o V1 nunca soma.\n {\n id: uid(), personId: 'p2', personName: 'Carlos Menezes', kind: 'clock_in',\n workDate: today, seq: 1, origin: 'totem',\n punchedAt: at(today, '09:12'), effectiveAt: at(today, '09:12'),\n adjusted: false, voided: false, evidence: {},\n },\n ]\n\n const days: WorkDay[] = [\n {\n personId: 'p1', personName: 'Ana Ribeiro', workDate: yesterday,\n assignmentId: 'a1', shiftLabel: 'Almoço', shiftStartTime: '08:00', shiftEndTime: '17:00',\n assignmentStatus: 'confirmed', plannedMinutes: 540, workedMinutes: 480, varianceMinutes: -60,\n firstIn: at(yesterday, '08:00'), lastOut: at(yesterday, '17:00'), breakCount: 1,\n isOpen: false, absent: false, outsideSchedule: false,\n },\n // FALTA: escala publicada e nenhuma batida.\n {\n personId: 'p3', personName: 'Júlia Prado', workDate: yesterday,\n assignmentId: 'a2', shiftLabel: 'Jantar', shiftStartTime: '17:00', shiftEndTime: '23:00',\n assignmentStatus: 'notified', plannedMinutes: 360, workedMinutes: null, varianceMinutes: null,\n isOpen: false, absent: true, outsideSchedule: false,\n },\n // FORA DA ESCALA: batida sem previsto.\n {\n personId: 'p2', personName: 'Carlos Menezes', workDate: today,\n plannedMinutes: null, workedMinutes: null, varianceMinutes: null,\n firstIn: at(today, '09:12'), breakCount: 0,\n isOpen: true, absent: false, outsideSchedule: true,\n },\n ]\n\n const periods: WorkforcePeriod[] = [\n { id: uid(), competenceMonth: isoDate(0).slice(0, 7) + '-01', status: 'open' },\n ]\n\n const templates: ScheduleTemplate[] = [\n {\n id: 't1', name: 'Almoço Seg. a Sex.', isActive: true, shifts: [\n {\n id: 's1', templateId: 't1', label: 'Almoço',\n startTime: '11:00', endTime: '15:00', weekdays: [1, 2, 3, 4, 5],\n crossesMidnight: false, sortOrder: 0,\n requirements: [\n { id: 'r1', shiftId: 's1', professionName: 'Garçom', requiredCount: 2 },\n { id: 'r2', shiftId: 's1', professionName: 'Cozinha', requiredCount: 3 },\n ],\n },\n ],\n },\n ]\n\n const schedules: DaySchedule[] = [\n {\n id: 'sc1', scheduleDate: yesterday, templateId: 't1', status: 'published',\n publishedAt: at(yesterday, '07:00'), isSpecialDay: false,\n assignments: [\n {\n id: 'a1', scheduleId: 'sc1', shiftId: 's1', shiftLabel: 'Almoço',\n shiftStartTime: '08:00', shiftEndTime: '17:00', professionName: 'Garçom',\n personId: 'p1', personName: 'Ana Ribeiro', role: 'titular', priority: 0, status: 'confirmed',\n },\n {\n id: 'a2', scheduleId: 'sc1', shiftId: 's1', shiftLabel: 'Jantar',\n shiftStartTime: '17:00', shiftEndTime: '23:00', professionName: 'Cozinha',\n personId: 'p3', personName: 'Júlia Prado', role: 'titular', priority: 1, status: 'notified',\n },\n ],\n },\n ]\n\n function inRange(date: string, from: string, to: string) {\n return date >= from && date <= to\n }\n\n return {\n async getTimeEntries(query: TimeEntryQuery) {\n return entries.filter(\n (e) => inRange(e.workDate, query.from, query.to)\n && (!query.personId || e.personId === query.personId),\n )\n },\n async getWorkDays(query: TimeEntryQuery) {\n return days.filter(\n (d) => inRange(d.workDate, query.from, query.to)\n && (!query.personId || d.personId === query.personId),\n )\n },\n // Sem storage não há foto. `null` e não uma imagem de exemplo: o mock existe\n // para montar a tela sem banco, e um rosto inventado aqui esconderia\n // justamente o estado que a tela precisa saber desenhar.\n async signPunchPhotos() {\n return {}\n },\n\n // ── A ficha trabalhista, em memória ──────────────────────────────────\n //\n // Vazia, e não semeada. O mock existe para montar a tela sem banco, e um\n // salário de exemplo aqui apareceria numa ficha de RH — que é o lugar onde\n // dado inventado é mais caro de distinguir do real.\n async getHrOverview() { return null },\n async getHrUpcoming() { return [] },\n async getEmployment() { return null },\n async saveEmployment() { /* sem banco, nada persiste */ },\n async getVacations() { return [] },\n async saveVacation() { },\n async getAbsences() { return [] },\n async saveAbsence() { },\n async getPendingItems() { return [] },\n async savePendingItem() { },\n async resolvePendingItem() { },\n async adjustTimeEntry(input: TimeAdjustmentInput) {\n const entry = entries.find((e) => e.id === input.timeEntryId)\n if (!entry) return\n if (input.action === 'void') {\n entry.voided = true\n } else if (input.effectiveAt) {\n entry.effectiveAt = input.effectiveAt\n entry.adjusted = true\n }\n entry.adjustmentReason = input.reason\n },\n\n async getPeriods() { return [...periods] },\n async closePeriod(competenceMonth: string, notes?: string) {\n const found = periods.find((p) => p.competenceMonth === competenceMonth)\n if (found) {\n found.status = 'closed'\n found.closedAt = new Date().toISOString()\n found.notes = notes ?? null\n } else {\n periods.unshift({\n id: uid(), competenceMonth, status: 'closed',\n closedAt: new Date().toISOString(), notes: notes ?? null,\n })\n }\n },\n async reopenPeriod(competenceMonth: string, reason: string) {\n const found = periods.find((p) => p.competenceMonth === competenceMonth)\n if (!found) return\n found.status = 'open'\n found.reopenedAt = new Date().toISOString()\n found.reopenReason = reason\n },\n\n async getTemplates() { return templates },\n async saveTemplate(input: SaveTemplateInput) {\n if (input.id) {\n const found = templates.find((t) => t.id === input.id)\n if (found) Object.assign(found, { name: input.name, isActive: input.isActive ?? true, notes: input.notes ?? null })\n return input.id\n }\n const id = uid()\n templates.push({ id, name: input.name, isActive: input.isActive ?? true, notes: input.notes ?? null, shifts: [] })\n return id\n },\n async deleteTemplate(id: string) {\n const i = templates.findIndex((t) => t.id === id)\n if (i >= 0) templates.splice(i, 1)\n },\n async saveShift(input: SaveShiftInput) {\n const template = templates.find((t) => t.id === input.templateId)\n if (!template) return ''\n if (input.id) {\n const found = template.shifts.find((s) => s.id === input.id)\n if (found) Object.assign(found, {\n label: input.label, startTime: input.startTime, endTime: input.endTime, weekdays: input.weekdays,\n })\n return input.id\n }\n const id = uid()\n template.shifts.push({\n id, templateId: template.id, label: input.label,\n startTime: input.startTime, endTime: input.endTime, weekdays: input.weekdays,\n crossesMidnight: input.endTime <= input.startTime,\n sortOrder: input.sortOrder ?? template.shifts.length,\n requirements: [],\n })\n return id\n },\n async deleteShift(id: string) {\n for (const t of templates) {\n const i = t.shifts.findIndex((s) => s.id === id)\n if (i >= 0) t.shifts.splice(i, 1)\n }\n },\n async saveRequirement(input: SaveRequirementInput) {\n for (const t of templates) {\n const shift = t.shifts.find((s) => s.id === input.shiftId)\n if (!shift) continue\n if (input.id) {\n const found = shift.requirements.find((r) => r.id === input.id)\n if (found) Object.assign(found, { professionName: input.professionName, requiredCount: input.requiredCount })\n return input.id\n }\n const id = uid()\n shift.requirements.push({ id, shiftId: shift.id, professionName: input.professionName, requiredCount: input.requiredCount })\n return id\n }\n return ''\n },\n async deleteRequirement(id: string) {\n for (const t of templates) {\n for (const s of t.shifts) {\n const i = s.requirements.findIndex((r) => r.id === id)\n if (i >= 0) s.requirements.splice(i, 1)\n }\n }\n },\n\n async getSchedules(query: ScheduleQuery) {\n return schedules.filter((s) => inRange(s.scheduleDate, query.from, query.to))\n },\n async createSchedule(input: CreateScheduleInput) {\n const id = uid()\n schedules.push({\n id, scheduleDate: input.scheduleDate, templateId: input.templateId,\n status: 'draft', isSpecialDay: false, notes: input.notes ?? null, assignments: [],\n })\n return id\n },\n async publishSchedule(scheduleId: string) {\n const found = schedules.find((s) => s.id === scheduleId)\n if (!found) return\n found.status = 'published'\n found.publishedAt = new Date().toISOString()\n },\n\n async getStaff() { return people },\n\n // Mesma forma do provider real: ESTRUTURA (sem mês) + MOVIMENTO, com uma\n // conta zerada e uma linha sem classificação, que são os dois casos que a\n // tela desenha de um jeito próprio.\n async getPayrollCosts(query: PayrollCostQuery): Promise<PayrollCostRow[]> {\n const month = query.from.slice(0, 7) + '-01'\n return [\n { chartAccountId: 'r3', chartAccountCode: '3', chartAccountName: 'DESPESAS COM PESSOAL', competenceMonth: null, total: 0 },\n { chartAccountId: 'r31', chartAccountCode: '3.1', chartAccountName: 'Folha de pagamento', competenceMonth: null, total: 0 },\n { chartAccountId: 'c1', chartAccountCode: '3.1.01', chartAccountName: 'Salários', competenceMonth: null, total: 0 },\n { chartAccountId: 'c2', chartAccountCode: '3.1.02', chartAccountName: 'Encargos sociais', competenceMonth: null, total: 0 },\n { chartAccountId: 'c3', chartAccountCode: '3.1.03', chartAccountName: 'Honorários', competenceMonth: null, total: 0 },\n { chartAccountId: 'c4', chartAccountCode: '3.1.04', chartAccountName: 'Vale-transporte', competenceMonth: null, total: 0 },\n { chartAccountId: 'r4', chartAccountCode: '4', chartAccountName: 'DESPESAS ADMINISTRATIVAS', competenceMonth: null, total: 0 },\n { chartAccountId: 'c5', chartAccountCode: '4.1', chartAccountName: 'Aluguel', competenceMonth: null, total: 0 },\n { chartAccountId: 'c1', chartAccountCode: '3.1.01', chartAccountName: 'Salários', competenceMonth: month, total: 42800 },\n { chartAccountId: 'c2', chartAccountCode: '3.1.02', chartAccountName: 'Encargos sociais', competenceMonth: month, total: 13640 },\n { chartAccountId: 'c3', chartAccountCode: '3.1.03', chartAccountName: 'Honorários', competenceMonth: month, total: 5200 },\n { chartAccountId: null, chartAccountCode: null, chartAccountName: '', competenceMonth: month, total: 980 },\n ]\n },\n }\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { getSupabaseClientOptional, getActiveTenantId } from '@fayz-ai/core'\nimport { saveSchedule } from '@fayz-ai/admin'\nimport type { WorkforceDataProvider } from './types'\nimport type {\n TimeEntry, TimeEntryQuery, TimeAdjustmentInput, PunchPhoto,\n WorkDay,\n WorkforcePeriod,\n ScheduleTemplate, ScheduleShift, SaveTemplateInput, SaveShiftInput, SaveRequirementInput,\n DaySchedule, ScheduleAssignment, ScheduleQuery, CreateScheduleInput,\n WorkforcePerson,\n PayrollCostRow, PayrollCostQuery,\n Employment, Vacation, Absence, PendingItem, HrOverview, HrUpcoming,\n} from '../types'\n\n/** A espécie de horário que o RH oferta. Semeada pela migration 000. */\nexport const WORK_SHIFT_KIND = 'work_shift'\n\nfunction client(): any {\n const supabase = getSupabaseClientOptional() as any\n if (!supabase) throw new Error('Supabase not initialized')\n return supabase\n}\n\nfunction tenantId(): string | undefined {\n return getActiveTenantId() ?? undefined\n}\n\n// ---------------------------------------------------------------------------\n// O teto de uma resposta\n//\n// O PostgREST devolve no máximo 1000 linhas e NÃO avisa que cortou. Para uma\n// lista isso é paginação; para uma SOMA é um número menor que o real entregue\n// com cara de total — foi assim que esta tela mostrou R$ 140.406 onde o razão\n// dizia R$ 511.131, com quatro meses de folha ausentes da árvore. Quem soma\n// confere o tamanho do que voltou.\nconst PAGINA = 1000\n\n/** 'HH:MM:SS' → 'HH:MM'. O Postgres devolve segundos que nenhuma tela mostra. */\nfunction hhmm(t?: string | null): string | null {\n if (!t) return null\n return t.slice(0, 5)\n}\n\n// ---------------------------------------------------------------------------\n// Leituras\n// ---------------------------------------------------------------------------\n\nfunction mapTimeEntry(r: any): TimeEntry {\n return {\n id: r.id,\n unitId: r.unit_id,\n personId: r.person_id,\n personName: r.person_name,\n kind: r.kind,\n workDate: r.work_date,\n seq: r.seq,\n origin: r.origin,\n punchedAt: r.punched_at,\n effectiveAt: r.effective_at,\n adjusted: !!r.adjusted,\n voided: !!r.voided,\n adjustmentReason: r.adjustment_reason,\n adjustedByName: r.adjusted_by_name,\n assignmentId: r.assignment_id,\n payableInvoiceId: r.payable_invoice_id,\n evidence: r.evidence ?? {},\n photo: readPhoto(r.evidence),\n }\n}\n\n/**\n * `evidence.photo` → PunchPhoto, e nada além disso.\n *\n * `evidence.photo_path` NÃO serve: ele é o caminho no bucket privado do V1, de\n * outro projeto Supabase. Tratá-lo como ponteiro daria uma URL assinada que\n * sempre falha, e o erro apareceria como \"foto quebrada\" em vez de\n * \"foto não migrada\".\n */\nfunction readPhoto(evidence: any): PunchPhoto | null {\n const p = evidence?.photo\n if (!p || typeof p !== 'object' || !p.bucket || !p.path) return null\n return { bucket: String(p.bucket), path: String(p.path), documentId: p.document_id ?? null }\n}\n\nfunction mapWorkDay(r: any): WorkDay {\n return {\n personId: r.person_id,\n unitId: r.unit_id,\n workDate: r.work_date,\n assignmentId: r.assignment_id,\n shiftLabel: r.shift_label,\n shiftStartTime: hhmm(r.shift_start_time),\n shiftEndTime: hhmm(r.shift_end_time),\n assignmentStatus: r.assignment_status,\n plannedMinutes: r.planned_minutes,\n workedMinutes: r.worked_minutes,\n varianceMinutes: r.variance_minutes,\n firstIn: r.first_in,\n lastOut: r.last_out,\n breakCount: r.break_count,\n openSince: r.open_since,\n reviewReason: r.review_reason ?? null,\n isOpen: !!r.is_open,\n absent: !!r.absent,\n outsideSchedule: !!r.outside_schedule,\n }\n}\n\nexport function createSupabaseWorkforceProvider(): WorkforceDataProvider {\n /** Nome de gente por id, resolvido uma vez por consulta. A view do dia não\n * traz nome — ela agrupa por id, e inventar um join lá dentro custaria a\n * todo leitor. Aqui é uma consulta a mais e a tela ganha um rótulo. */\n /** Nome das unidades em lote. Vazio entra e sai vazio, sem ida ao banco. */\n async function unitNamesOf(ids: string[]): Promise<Map<string, string>> {\n const unique = [...new Set(ids)]\n if (!unique.length) return new Map()\n // `v_units`, não `app.units`: o PostgREST só expõe `public`, e a view é a\n // porta que o resto do SDK já usa (packages/admin/src/units/data.ts).\n const { data } = await client().from('v_units').select('id,name').in('id', unique)\n return new Map(((data ?? []) as any[]).map((u) => [u.id as string, u.name as string]))\n }\n\n async function namesOf(ids: string[]): Promise<Map<string, string>> {\n const out = new Map<string, string>()\n const unique = [...new Set(ids.filter(Boolean))]\n if (unique.length === 0) return out\n const { data } = await client().from('people').select('id,name').in('id', unique)\n for (const p of (data ?? []) as any[]) out.set(p.id, p.name)\n return out\n }\n\n // ── A ficha trabalhista (005) ───────────────────────────────────────────\n //\n // Sem `try/catch` por cima: a RLS de `workforce_hr` não devolve erro para quem\n // não tem a permissão, devolve ZERO LINHAS. Transformar isso num toast de erro\n // diria \"deu problema\" onde o certo é \"isto não é seu\".\n const hr = {\n async getHrOverview(): Promise<HrOverview | null> {\n const { data } = await client().from('v_workforce_hr_overview').select('*').maybeSingle()\n if (!data) return null\n const r = data as any\n return {\n headcount: r.headcount ?? 0,\n admissions30d: r.admissions_30d ?? 0,\n dismissals30d: r.dismissals_30d ?? 0,\n probationEnding: r.probation_ending ?? 0,\n birthdaysThisMonth: r.birthdays_this_month ?? 0,\n vacationsDue60d: r.vacations_due_60d ?? 0,\n criticalPending: r.critical_pending ?? 0,\n }\n },\n\n async getHrUpcoming(): Promise<HrUpcoming[]> {\n const { data } = await client().from('v_workforce_hr_upcoming').select('*').order('due_on')\n return ((data ?? []) as any[]).map((r) => ({\n kind: r.kind, personId: r.person_id, personName: r.person_name,\n dueOn: r.due_on, detail: r.detail,\n }))\n },\n\n async getEmployment(personId: string): Promise<Employment | null> {\n const { data } = await client().from('plg_workforce_employment')\n .select('*').eq('person_id', personId).maybeSingle()\n if (!data) return null\n const r = data as any\n return {\n id: r.id, personId: r.person_id,\n contractKind: r.contract_kind, admissionDate: r.admission_date,\n dismissalDate: r.dismissal_date, dismissalReason: r.dismissal_reason,\n probationFirstEnd: r.probation_first_end, probationFinalEnd: r.probation_final_end,\n jobTitle: r.job_title, department: r.department,\n scheduleRegime: r.schedule_regime,\n weeklyHours: r.weekly_hours, monthlyHours: r.monthly_hours,\n esocialRegistration: r.esocial_registration,\n baseSalary: r.base_salary, payFrequency: r.pay_frequency, notes: r.notes,\n }\n },\n\n async saveEmployment(input: Employment): Promise<void> {\n // `onConflict` no par (tenant, pessoa): é a UNIQUE da 005, e é ela que faz\n // \"salvar\" ser idempotente em vez de criar o segundo vínculo da mesma\n // pessoa — dois vínculos seriam dois headcounts para uma cabeça.\n const { error } = await client().from('plg_workforce_employment').upsert({\n tenant_id: tenantId(),\n person_id: input.personId,\n contract_kind: input.contractKind || null,\n admission_date: input.admissionDate || null,\n dismissal_date: input.dismissalDate || null,\n dismissal_reason: input.dismissalReason || null,\n probation_first_end: input.probationFirstEnd || null,\n probation_final_end: input.probationFinalEnd || null,\n job_title: input.jobTitle || null,\n department: input.department || null,\n schedule_regime: input.scheduleRegime || null,\n weekly_hours: input.weeklyHours ?? null,\n monthly_hours: input.monthlyHours ?? null,\n esocial_registration: input.esocialRegistration || null,\n base_salary: input.baseSalary ?? null,\n pay_frequency: input.payFrequency || null,\n notes: input.notes || null,\n }, { onConflict: 'tenant_id,person_id' })\n if (error) throw error\n },\n\n async getVacations(personId: string): Promise<Vacation[]> {\n const { data } = await client().from('plg_workforce_vacations')\n .select('*').eq('person_id', personId).order('accrual_end', { ascending: false })\n return ((data ?? []) as any[]).map((r) => ({\n id: r.id, personId: r.person_id,\n accrualStart: r.accrual_start, accrualEnd: r.accrual_end,\n takenStart: r.taken_start, takenEnd: r.taken_end,\n daysTaken: r.days_taken, daysSold: r.days_sold,\n status: r.status, notes: r.notes,\n }))\n },\n\n async saveVacation(input: Vacation): Promise<void> {\n const row = {\n tenant_id: tenantId(), person_id: input.personId,\n accrual_start: input.accrualStart, accrual_end: input.accrualEnd,\n taken_start: input.takenStart || null, taken_end: input.takenEnd || null,\n days_taken: input.daysTaken ?? null, days_sold: input.daysSold ?? null,\n status: input.status, notes: input.notes || null,\n }\n const q = client().from('plg_workforce_vacations')\n const { error } = input.id ? await q.update(row).eq('id', input.id) : await q.insert(row)\n if (error) throw error\n },\n\n async getAbsences(personId: string): Promise<Absence[]> {\n const { data } = await client().from('plg_workforce_absences')\n .select('*').eq('person_id', personId).order('starts_on', { ascending: false })\n return ((data ?? []) as any[]).map((r) => ({\n id: r.id, personId: r.person_id, kind: r.kind,\n startsOn: r.starts_on, endsOn: r.ends_on, days: r.days,\n paid: !!r.paid, icdCode: r.icd_code, doctor: r.doctor, notes: r.notes,\n }))\n },\n\n async saveAbsence(input: Absence): Promise<void> {\n const row = {\n tenant_id: tenantId(), person_id: input.personId, kind: input.kind,\n starts_on: input.startsOn, ends_on: input.endsOn || null,\n days: input.days ?? null, paid: input.paid,\n icd_code: input.icdCode || null, doctor: input.doctor || null,\n notes: input.notes || null,\n }\n const q = client().from('plg_workforce_absences')\n const { error } = input.id ? await q.update(row).eq('id', input.id) : await q.insert(row)\n if (error) throw error\n },\n\n async getPendingItems(personId: string): Promise<PendingItem[]> {\n const { data } = await client().from('plg_workforce_pending_items')\n .select('*').eq('person_id', personId)\n .order('resolved_at', { ascending: true, nullsFirst: true })\n .order('due_on', { ascending: true })\n return ((data ?? []) as any[]).map((r) => ({\n id: r.id, personId: r.person_id, title: r.title,\n category: r.category, priority: r.priority,\n dueOn: r.due_on, resolvedAt: r.resolved_at, description: r.description,\n }))\n },\n\n async savePendingItem(input: PendingItem): Promise<void> {\n const row = {\n tenant_id: tenantId(), person_id: input.personId, title: input.title,\n category: input.category || null, priority: input.priority,\n due_on: input.dueOn || null, description: input.description || null,\n }\n const q = client().from('plg_workforce_pending_items')\n const { error } = input.id ? await q.update(row).eq('id', input.id) : await q.insert(row)\n if (error) throw error\n },\n\n async resolvePendingItem(id: string, resolved: boolean): Promise<void> {\n const { error } = await client().from('plg_workforce_pending_items')\n .update({ resolved_at: resolved ? new Date().toISOString() : null }).eq('id', id)\n if (error) throw error\n },\n }\n\n return {\n ...hr,\n // --- O realizado -------------------------------------------------------\n async getTimeEntries(query: TimeEntryQuery): Promise<TimeEntry[]> {\n let q = client()\n .from('v_workforce_time_entries')\n .select('*')\n .gte('work_date', query.from)\n .lte('work_date', query.to)\n .order('work_date', { ascending: false })\n .order('seq', { ascending: true })\n if (query.personId) q = q.eq('person_id', query.personId)\n if (query.unitId) q = q.eq('unit_id', query.unitId)\n const { data, error } = await q\n if (error) throw error\n return ((data ?? []) as any[]).map(mapTimeEntry)\n },\n\n async getWorkDays(query: TimeEntryQuery): Promise<WorkDay[]> {\n let q = client()\n .from('v_workforce_day')\n .select('*')\n .gte('work_date', query.from)\n .lte('work_date', query.to)\n .order('work_date', { ascending: false })\n if (query.personId) q = q.eq('person_id', query.personId)\n if (query.unitId) q = q.eq('unit_id', query.unitId)\n const { data, error } = await q\n if (error) throw error\n const rows = ((data ?? []) as any[]).map(mapWorkDay)\n // Nome da pessoa E da unidade em duas consultas, não uma por linha: a\n // view agrupa por id, e a tabela mostra nome. Resolver aqui, em lote, é a\n // diferença entre duas idas ao banco e trezentas.\n const [names, units] = await Promise.all([\n namesOf(rows.map((r) => r.personId)),\n unitNamesOf(rows.map((r) => r.unitId).filter(Boolean) as string[]),\n ])\n return rows.map((r) => ({\n ...r,\n personName: names.get(r.personId) ?? null,\n unitName: (r.unitId && units.get(r.unitId)) ?? null,\n }))\n },\n\n async signPunchPhotos(photos: PunchPhoto[], expiresInSeconds = 300): Promise<Record<string, string>> {\n const out: Record<string, string> = {}\n if (!photos.length) return out\n // Agrupado por bucket porque `createSignedUrls` assina uma lista DENTRO de\n // um bucket. Hoje é sempre o mesmo; agrupar agora é o que evita que a\n // segunda espécie de foto vire um caso especial mais tarde.\n const porBucket = new Map<string, string[]>()\n for (const p of photos) {\n const lista = porBucket.get(p.bucket) ?? []\n if (!lista.includes(p.path)) lista.push(p.path)\n porBucket.set(p.bucket, lista)\n }\n await Promise.all([...porBucket.entries()].map(async ([bucket, paths]) => {\n // A leitura de `storage.objects` é escopada por pasta de tenant pela\n // policy da migration 001: quem não é do tenant recebe erro aqui, e não\n // uma imagem.\n const { data, error } = await client().storage.from(bucket).createSignedUrls(paths, expiresInSeconds)\n if (error || !data) return\n for (const item of data as any[]) {\n // O item traz `path` (o que foi pedido) e `signedUrl`, ou `error`\n // quando aquele objeto específico não existe — um arquivo que o V1\n // perdeu não pode derrubar a assinatura dos outros 260.\n if (item?.signedUrl && item?.path) out[`${bucket}/${item.path}`] = item.signedUrl\n }\n }))\n return out\n },\n\n async adjustTimeEntry(input: TimeAdjustmentInput): Promise<void> {\n // INSERT, e só INSERT. A batida é append-only por trigger; o ajuste é\n // uma linha nova com autor e motivo, e o histórico fica.\n const { error } = await client()\n .from('plg_workforce_time_adjustments')\n .insert({\n tenant_id: tenantId(),\n time_entry_id: input.timeEntryId,\n action: input.action,\n effective_at: input.action === 'void' ? null : input.effectiveAt,\n reason: input.reason,\n })\n if (error) throw error\n },\n\n // --- A competência -----------------------------------------------------\n async getPeriods(): Promise<WorkforcePeriod[]> {\n const { data, error } = await client()\n .from('plg_workforce_periods')\n .select('*')\n .order('competence_month', { ascending: false })\n if (error) throw error\n return ((data ?? []) as any[]).map((r) => ({\n id: r.id,\n competenceMonth: r.competence_month,\n status: r.status,\n closedAt: r.closed_at,\n reopenedAt: r.reopened_at,\n reopenReason: r.reopen_reason,\n notes: r.notes,\n }))\n },\n\n async closePeriod(competenceMonth: string, notes?: string): Promise<void> {\n const { error } = await client().rpc('workforce_period_close', {\n p_month: competenceMonth,\n p_notes: notes ?? null,\n })\n if (error) throw error\n },\n\n async reopenPeriod(competenceMonth: string, reason: string): Promise<void> {\n const { error } = await client().rpc('workforce_period_reopen', {\n p_month: competenceMonth,\n p_reason: reason,\n })\n if (error) throw error\n },\n\n // --- O molde -----------------------------------------------------------\n async getTemplates(): Promise<ScheduleTemplate[]> {\n const { data: templates, error } = await client()\n .from('plg_workforce_schedule_templates')\n .select('*')\n .order('name')\n if (error) throw error\n const ids = ((templates ?? []) as any[]).map((t) => t.id)\n if (ids.length === 0) return []\n\n const { data: shifts } = await client()\n .from('plg_workforce_schedule_shifts')\n .select('*')\n .in('template_id', ids)\n .order('sort_order')\n const shiftIds = ((shifts ?? []) as any[]).map((s) => s.id)\n const { data: reqs } = shiftIds.length\n ? await client()\n .from('plg_workforce_schedule_requirements')\n .select('*')\n .in('shift_id', shiftIds)\n : { data: [] as any[] }\n\n const reqsByShift = new Map<string, any[]>()\n for (const r of (reqs ?? []) as any[]) {\n const list = reqsByShift.get(r.shift_id) ?? []\n list.push(r)\n reqsByShift.set(r.shift_id, list)\n }\n const shiftsByTemplate = new Map<string, ScheduleShift[]>()\n for (const s of (shifts ?? []) as any[]) {\n const list = shiftsByTemplate.get(s.template_id) ?? []\n list.push({\n id: s.id,\n templateId: s.template_id,\n label: s.label,\n startTime: hhmm(s.start_time) ?? '',\n endTime: hhmm(s.end_time) ?? '',\n weekdays: s.weekdays ?? [],\n crossesMidnight: !!s.crosses_midnight,\n sortOrder: s.sort_order ?? 0,\n requirements: (reqsByShift.get(s.id) ?? []).map((r) => ({\n id: r.id,\n shiftId: r.shift_id,\n professionName: r.profession_name,\n requiredCount: r.required_count,\n })),\n })\n shiftsByTemplate.set(s.template_id, list)\n }\n\n return ((templates ?? []) as any[]).map((t) => ({\n id: t.id,\n unitId: t.unit_id,\n name: t.name,\n isActive: !!t.is_active,\n notes: t.notes,\n shifts: shiftsByTemplate.get(t.id) ?? [],\n }))\n },\n\n async saveTemplate(input: SaveTemplateInput): Promise<string> {\n const row = {\n tenant_id: tenantId(),\n name: input.name,\n unit_id: input.unitId ?? null,\n is_active: input.isActive ?? true,\n notes: input.notes ?? null,\n }\n const table = client().from('plg_workforce_schedule_templates')\n const { data, error } = input.id\n ? await table.update(row).eq('id', input.id).select('id').single()\n : await table.insert(row).select('id').single()\n if (error) throw error\n return (data as any).id\n },\n\n async deleteTemplate(id: string): Promise<void> {\n const { error } = await client().from('plg_workforce_schedule_templates').delete().eq('id', id)\n if (error) throw error\n },\n\n async saveShift(input: SaveShiftInput): Promise<string> {\n const row = {\n tenant_id: tenantId(),\n template_id: input.templateId,\n label: input.label,\n start_time: input.startTime,\n end_time: input.endTime,\n weekdays: input.weekdays,\n sort_order: input.sortOrder ?? 0,\n }\n const table = client().from('plg_workforce_schedule_shifts')\n const { data, error } = input.id\n ? await table.update(row).eq('id', input.id).select('id').single()\n : await table.insert(row).select('id').single()\n if (error) throw error\n return (data as any).id\n },\n\n async deleteShift(id: string): Promise<void> {\n const { error } = await client().from('plg_workforce_schedule_shifts').delete().eq('id', id)\n if (error) throw error\n },\n\n async saveRequirement(input: SaveRequirementInput): Promise<string> {\n const row = {\n tenant_id: tenantId(),\n shift_id: input.shiftId,\n profession_name: input.professionName,\n required_count: input.requiredCount,\n }\n const table = client().from('plg_workforce_schedule_requirements')\n const { data, error } = input.id\n ? await table.update(row).eq('id', input.id).select('id').single()\n : await table.insert(row).select('id').single()\n if (error) throw error\n return (data as any).id\n },\n\n async deleteRequirement(id: string): Promise<void> {\n const { error } = await client().from('plg_workforce_schedule_requirements').delete().eq('id', id)\n if (error) throw error\n },\n\n // --- A instância do dia ------------------------------------------------\n async getSchedules(query: ScheduleQuery): Promise<DaySchedule[]> {\n let q = client()\n .from('plg_workforce_schedules')\n .select('*')\n .gte('schedule_date', query.from)\n .lte('schedule_date', query.to)\n .order('schedule_date')\n if (query.unitId) q = q.eq('unit_id', query.unitId)\n const { data: schedules, error } = await q\n if (error) throw error\n const ids = ((schedules ?? []) as any[]).map((s) => s.id)\n if (ids.length === 0) return []\n\n const { data: assignments } = await client()\n .from('plg_workforce_schedule_assignments')\n .select('*')\n .in('schedule_id', ids)\n .order('priority')\n const names = await namesOf(((assignments ?? []) as any[]).map((a) => a.person_id))\n\n const bySchedule = new Map<string, ScheduleAssignment[]>()\n for (const a of (assignments ?? []) as any[]) {\n const list = bySchedule.get(a.schedule_id) ?? []\n list.push({\n id: a.id,\n scheduleId: a.schedule_id,\n shiftId: a.shift_id,\n shiftLabel: a.shift_label,\n shiftStartTime: hhmm(a.shift_start_time),\n shiftEndTime: hhmm(a.shift_end_time),\n professionName: a.profession_name,\n personId: a.person_id,\n personName: names.get(a.person_id) ?? null,\n role: a.role,\n priority: a.priority ?? 0,\n status: a.status,\n scheduleRowId: a.schedule_row_id,\n })\n bySchedule.set(a.schedule_id, list)\n }\n\n return ((schedules ?? []) as any[]).map((s) => ({\n id: s.id,\n scheduleDate: s.schedule_date,\n templateId: s.template_id,\n unitId: s.unit_id,\n status: s.status,\n publishedAt: s.published_at,\n isSpecialDay: !!s.is_special_day,\n specialDayLabel: s.special_day_label,\n notes: s.notes,\n assignments: bySchedule.get(s.id) ?? [],\n }))\n },\n\n async createSchedule(input: CreateScheduleInput): Promise<string> {\n const tid = tenantId()\n const { data: created, error } = await client()\n .from('plg_workforce_schedules')\n .insert({\n tenant_id: tid,\n unit_id: input.unitId ?? null,\n schedule_date: input.scheduleDate,\n template_id: input.templateId,\n status: 'draft',\n notes: input.notes ?? null,\n })\n .select('id')\n .single()\n if (error) throw error\n const scheduleId = (created as any).id\n\n // O SNAPSHOT. O turno é copiado AGORA para dentro da atribuição: é o que\n // faz a escala de terça passada sobreviver a uma edição do molde hoje.\n const { data: shifts } = await client()\n .from('plg_workforce_schedule_shifts')\n .select('id,label,start_time,end_time,weekdays')\n .eq('template_id', input.templateId)\n const shiftById = new Map<string, any>()\n for (const s of (shifts ?? []) as any[]) shiftById.set(s.id, s)\n\n // Só os turnos que acontecem NESTE dia da semana. Copiar o molde inteiro\n // escalaria gente para um turno que não existe na terça.\n const dow = new Date(`${input.scheduleDate}T12:00:00`).getDay()\n const shiftIds = [...shiftById.values()]\n .filter((s) => (s.weekdays ?? []).includes(dow))\n .map((s) => s.id)\n if (shiftIds.length === 0) return scheduleId\n\n const { data: templateAssignments } = await client()\n .from('plg_workforce_schedule_template_assignments')\n .select('*')\n .in('shift_id', shiftIds)\n const rows = ((templateAssignments ?? []) as any[]).map((a) => {\n const shift = shiftById.get(a.shift_id)\n return {\n tenant_id: tid,\n unit_id: input.unitId ?? null,\n schedule_id: scheduleId,\n shift_id: a.shift_id,\n shift_label: shift?.label ?? null,\n shift_start_time: shift?.start_time ?? null,\n shift_end_time: shift?.end_time ?? null,\n profession_name: a.profession_name,\n person_id: a.person_id,\n role: a.role,\n priority: a.priority ?? 0,\n status: 'pending',\n }\n })\n if (rows.length > 0) {\n const { error: insErr } = await client()\n .from('plg_workforce_schedule_assignments')\n .insert(rows)\n if (insErr) throw insErr\n }\n return scheduleId\n },\n\n async publishSchedule(scheduleId: string): Promise<void> {\n const { data: schedule, error } = await client()\n .from('plg_workforce_schedules')\n .select('id,schedule_date,unit_id')\n .eq('id', scheduleId)\n .single()\n if (error) throw error\n\n const { data: assignments } = await client()\n .from('plg_workforce_schedule_assignments')\n .select('*')\n .eq('schedule_id', scheduleId)\n .eq('role', 'titular')\n .is('schedule_row_id', null)\n\n // A PONTE. Cada titular vira uma linha de `public.schedules` com\n // kind 'work_shift' — escrita pelo MESMO serviço que a agenda usa\n // (schedule-service do @fayz-ai/admin), e não por um segundo writer.\n for (const a of (assignments ?? []) as any[]) {\n if (!a.shift_start_time || !a.shift_end_time) continue\n try {\n const row = await saveSchedule({\n kind: WORK_SHIFT_KIND,\n assigneeId: a.person_id,\n locationId: (schedule as any).unit_id ?? undefined,\n specificDate: (schedule as any).schedule_date,\n startsAt: a.shift_start_time,\n endsAt: a.shift_end_time,\n })\n await client()\n .from('plg_workforce_schedule_assignments')\n .update({ schedule_row_id: row.id })\n .eq('id', a.id)\n } catch {\n // Uma atribuição que não materializa não pode impedir a publicação\n // das outras: a escala publicada é o aviso, e o espelho na agenda é\n // consequência dele.\n }\n }\n\n const { error: upErr } = await client()\n .from('plg_workforce_schedules')\n .update({ status: 'published', published_at: new Date().toISOString() })\n .eq('id', scheduleId)\n if (upErr) throw upErr\n },\n\n // --- Gente -------------------------------------------------------------\n async getStaff(): Promise<WorkforcePerson[]> {\n const { data, error } = await client()\n .from('people')\n .select('id,name,is_active')\n .eq('kind', 'staff')\n .order('name')\n if (error) throw error\n return ((data ?? []) as any[]).map((p) => ({\n id: p.id,\n name: p.name,\n isActive: p.is_active !== false,\n }))\n },\n\n // --- Encargos e honorários --------------------------------------------\n //\n // LEITURA do demonstrativo do Financeiro — `plg_financial_rep_dre`, a MESMA\n // view que o relatório de DRE desenha. Foram duas fontes por um tempo: esta\n // tela somava `v_financial_invoice_lines` linha a linha, e as duas podiam\n // discordar sem que nada avisasse. Conferido no cluster de Pertinho do Céu\n // em 19/09/2026, mês a mês: R$ 511.131,08 nos dois caminhos, nos cinco meses\n // com movimento.\n //\n // A view já faz três coisas que esta tela precisaria refazer:\n //\n // · AGREGA por conta × mês — a resposta cabe numa página em vez das 5.409\n // linhas do ano, que o PostgREST cortava em mil sem avisar;\n // · traz a ESTRUTURA do plano (linha com `competence_month` nulo), que é o\n // que põe a conta-mãe e a conta zerada na árvore;\n // · aplica a regra do demonstrativo: `statement_code` só classifica quando\n // a NATUREZA da conta casa com o sentido do título. Uma conta a pagar\n // lançada em conta de receita não vira um ramo de receita no meio das\n // despesas — vira \"sem classificação\", e continua no total.\n //\n // Um pedido por mês, em paralelo: a view devolve uma linha por conta × mês ×\n // unidade, e um ano inteiro de uma vez passaria de mil linhas num plano\n // grande. Somar as unidades é daqui — a tela mostra a casa inteira.\n async getPayrollCosts(query: PayrollCostQuery): Promise<PayrollCostRow[]> {\n // UM pedido, e não um por mês. A view varre fatura × pedido × item do\n // tenant inteiro e agrega; fria, uma varredura custa ~6s neste cluster e\n // meia dúzia em paralelo estoura o tempo do PostgREST — seis respostas\n // 500 e a tela dizendo que o Financeiro não está instalado. Uma varredura\n // só devolve tudo: 550 linhas para o ano inteiro, medido em 19/09/2026.\n const deMes = `${query.from.slice(0, 7)}-01`\n const { data, error } = await client()\n .from('plg_financial_rep_dre')\n .select('account_id,statement_code,statement_name,competence_month,amount')\n .eq('direction', 'payable')\n // A linha de ESTRUTURA não tem mês e precisa vir junto — é ela que põe\n // a conta-mãe e a conta zerada na árvore.\n .or(`competence_month.is.null,and(competence_month.gte.${deMes},competence_month.lte.${query.to})`)\n .limit(PAGINA)\n if (error) throw error\n\n const lote = (data ?? []) as any[]\n // Página cheia é suspeita de corte, e uma soma cortada é um número menor\n // que o real com cara de total.\n if (lote.length >= PAGINA) {\n throw new Error(`plg_financial_rep_dre: resposta no limite de ${PAGINA} `\n + 'linhas — o total não pode ser confiado')\n }\n\n // A view devolve uma linha por conta × mês × UNIDADE. A tela mostra a casa\n // inteira, então as unidades somam aqui.\n const out = new Map<string, PayrollCostRow>()\n for (const r of lote) {\n const code = (r.statement_code as string | null) ?? null\n const month = (r.competence_month as string | null) ?? null\n const key = `${code ?? ''}|${month ?? ''}`\n const atual = out.get(key) ?? {\n chartAccountId: (r.account_id as string | null) ?? null,\n chartAccountCode: code,\n chartAccountName: (r.statement_name as string | null) ?? '',\n competenceMonth: month,\n total: 0,\n }\n atual.total += Number(r.amount ?? 0)\n out.set(key, atual)\n }\n return [...out.values()]\n },\n }\n}\n\n","import { createStore, type StoreApi } from 'zustand/vanilla'\nimport type { WorkforceDataProvider } from './data/types'\nimport type { DaySchedule, ScheduleTemplate, TimeEntry, WorkDay, WorkforcePeriod, WorkforcePerson } from './types'\n\n/**\n * O estado que mais de uma tela do módulo lê.\n *\n * O que é só de uma tela (o formulário de turno, o diálogo de ajuste) fica na\n * própria tela — um store que guarda rascunho de formulário é um store que\n * ninguém consegue limpar.\n */\nexport interface WorkforceUIState {\n /** O dia selecionado no calendário de Escalas, em 'YYYY-MM-DD'. */\n selectedDate: string\n setSelectedDate: (date: string) => void\n\n schedules: DaySchedule[]\n schedulesLoading: boolean\n fetchSchedules: (from: string, to: string) => Promise<void>\n\n templates: ScheduleTemplate[]\n templatesLoading: boolean\n fetchTemplates: () => Promise<void>\n\n entries: TimeEntry[]\n days: WorkDay[]\n timeLoading: boolean\n fetchTime: (from: string, to: string) => Promise<void>\n\n periods: WorkforcePeriod[]\n periodsLoading: boolean\n fetchPeriods: () => Promise<void>\n\n staff: WorkforcePerson[]\n fetchStaff: () => Promise<void>\n}\n\nfunction todayISO(): string {\n const d = new Date()\n return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`\n}\n\nexport function createWorkforceStore(provider: WorkforceDataProvider): StoreApi<WorkforceUIState> {\n return createStore<WorkforceUIState>((set) => ({\n selectedDate: todayISO(),\n setSelectedDate: (date) => set({ selectedDate: date }),\n\n schedules: [],\n schedulesLoading: false,\n fetchSchedules: async (from, to) => {\n set({ schedulesLoading: true })\n try {\n set({ schedules: await provider.getSchedules({ from, to }) })\n } catch {\n set({ schedules: [] })\n } finally {\n set({ schedulesLoading: false })\n }\n },\n\n templates: [],\n templatesLoading: false,\n fetchTemplates: async () => {\n set({ templatesLoading: true })\n try {\n set({ templates: await provider.getTemplates() })\n } catch {\n set({ templates: [] })\n } finally {\n set({ templatesLoading: false })\n }\n },\n\n entries: [],\n days: [],\n timeLoading: false,\n fetchTime: async (from, to) => {\n set({ timeLoading: true })\n try {\n // As duas juntas de propósito: a lista de batidas sem o cruzamento é\n // uma folha de ponto que não sabe dizer quem faltou.\n const [entries, days] = await Promise.all([\n provider.getTimeEntries({ from, to }),\n provider.getWorkDays({ from, to }),\n ])\n set({ entries, days })\n } catch {\n set({ entries: [], days: [] })\n } finally {\n set({ timeLoading: false })\n }\n },\n\n periods: [],\n periodsLoading: false,\n fetchPeriods: async () => {\n set({ periodsLoading: true })\n try {\n set({ periods: await provider.getPeriods() })\n } catch {\n set({ periods: [] })\n } finally {\n set({ periodsLoading: false })\n }\n },\n\n staff: [],\n fetchStaff: async () => {\n try {\n set({ staff: await provider.getStaff() })\n } catch {\n set({ staff: [] })\n }\n },\n }))\n}\n","// AUTO-GENERATED from 000_baseline.sql, 001_a_prova_da_batida_tem_bytes.sql, 002_o_guarda_da_foto_olhava_o_nome_errado.sql, 003_o_ponto_em_aberto_para_de_mentir_a_duracao.sql, 004_a_jornada_implausivel_nao_soma.sql, 005_a_ficha_trabalhista_tem_onde_morar.sql, 006_o_custo_de_pessoal_e_um_ramo_do_plano.sql, 007_a_porta_de_servico_do_ponto_fecha_tambem.sql — regenerate with scripts/embed-migrations.mjs\n// SQL files are the source of truth; this inline copy lets the manifest declare\n// migrations as data. Do not edit by hand — run the embed script instead.\n\nexport const MIGRATION_000_BASELINE = `-- O RH ganha ponto e escala.\n--\n-- D9 · Gente & Jornada de trabalho é o último domínio inteiro do V1 sem NENHUMA\n-- contraparte no V2. O registro de features do app diz isso feature por feature:\n-- \\`sch.templates\\` P0 missing, \\`sch.calendar\\` P0 missing (\"Nenhum módulo do SDK é\n-- dono disso hoje — precisa de uma decisão antes de código\"), \\`sch.clock\\` P1\n-- missing (\"O que existe é o horário PREVISTO de trabalho. A batida realizada,\n-- com ajuste auditado, não existe\"), \\`sch.clock.adjust\\` P1 missing. O host\n-- previsto para os quatro é o mesmo: **plugin-workforce**. Este arquivo é a\n-- camada de dados dele.\n--\n-- ── O que foi medido na origem (Pertinho do Céu, licença 8, 07/09/2026) ──────\n--\n-- Da documentação do V1 (\\`docs/v1-guide/restaurante/escalas/FLOW.md\\` e\n-- \\`docs/v1-guide/agenda/ponto-eletronico/FLOW.md\\`), tudo verificado na tela:\n--\n-- 325 registros de ponto no período — e TODOS os 325 marcados\n-- \"Fora da escala\" (V1-043). A coluna existe justamente para cruzar\n-- ponto × escala e nunca varia: o ponto está ativo em \\`PC Serviços\\`\n-- enquanto a operação e as escalas são de \\`Pertinho do Céu\\`.\n-- 20 batimentos EM ABERTO, incluindo 5 de 5 hoje e 8 de 16 ontem; um\n-- deles com entrada às 23:29 e \"13h07 (parcial)\".\n-- R$ 47.747 o valor do período — SUBESTIMADO, porque o V1 só calcula valor no\n-- fechamento do par, e 20 pares nunca fecharam.\n-- 103 profissionais habilitados para arrastar numa vaga de template.\n-- 7 templates de escala no tenant.\n--\n-- Três dos números acima são sintoma do MESMO defeito de modelo, e é ele que\n-- este arquivo existe para não repetir: no V1 a batida é um par entrada/saída\n-- numa única linha, com o ajuste como colunas \\`*_adjusted_at\\` por cima. Um par\n-- que nunca fecha não tem duração, não tem valor e não tem como ser conferido\n-- contra nada.\n--\n-- ── Duas decisões de arquitetura que o repositório já tomou ─────────────────\n--\n-- 1. *\"Ponto é razão append-only, como todo saldo — nunca uma coluna que alguém\n-- edita.\"* (\\`docs/migration/how-to-port.json\\`, mv.sch.clock: *\"Batida é\n-- append-only e ajuste é registro separado com autor e motivo — apagar\n-- batida é o que a lei não permite.\"*)\n--\n-- Por isso \\`plg_workforce_time_entries\\` é append-only de verdade — trigger\n-- que recusa UPDATE e DELETE, e as policies de UPDATE/DELETE derrubadas\n-- depois do scaffold — e o ajuste do V1 (\\`checkin_adjusted_at\\`,\n-- \\`checkout_adjusted_at\\`, \\`adjustment_reason\\`, \\`adjusted_by_*\\`) vira LINHA em\n-- \\`plg_workforce_time_adjustments\\`, com autor, motivo e carimbo. A própria\n-- tela do V1 já enuncia a regra que o V2 passa a garantir no banco: *\"Os\n-- horários reais dos batimentos são preservados.\"*\n--\n-- 2. *\"Escala de funcionário NÃO mora na agenda — quem oferta horário é o RH, a\n-- agenda só consome.\"* (registro de features, domínio D3.)\n--\n-- Por isso a escala é deste plugin, e a ponte com a agenda é UMA coluna:\n-- \\`plg_workforce_schedule_assignments.schedule_row_id\\`, que aponta para a\n-- linha de \\`public.schedules\\` que a publicação materializa.\n--\n-- ── O que este arquivo NÃO cria, porque já existe ───────────────────────────\n--\n-- O PREVISTO já está no V2. \\`public.schedules\\` (spine) tem exatamente a forma\n-- de uma oferta de horário — \\`kind\\`, \\`assignee_id\\` → \\`public.people\\`,\n-- \\`day_of_week\\`, \\`specific_date\\`, \\`starts_at\\`, \\`ends_at\\`, \\`unit_id\\` — e\n-- \\`public.schedule_kinds\\` é o registro de espécies dela (hoje: working_hours,\n-- exception, block, unclassified). Criar uma tabela de escala prevista aqui\n-- seria a segunda tabela de horário do cluster, que diverge da primeira na\n-- próxima mudança. Em vez disso este arquivo **semeia a espécie \\`work_shift\\`** e\n-- usa \\`public.schedules\\`.\n--\n-- \\`public.people\\` também já resolve sozinha o pior defeito do modelo do V1: lá o\n-- ponto aponta para \\`person_type ENUM('professional','employee')\\` + \\`person_id\\`,\n-- uma FK polimórfica para duas tabelas de cadastro que a própria tela mistura\n-- (\"A aba mistura Profissional e Funcionário no mesmo filtro e na mesma lista, e\n-- a diferença entre os dois cadastros não é explicada em lugar nenhum\"). No V2\n-- os dois já são \\`public.people\\` com papel em \\`public.person_roles\\`, então o par\n-- vira UMA FK \\`person_id uuid → public.people(id)\\`.\n--\n-- NÃO porta \\`schedule_grids\\` / \\`schedule_grid_blocks\\`: apesar do nome são grade\n-- de disponibilidade de AGENDAMENTO, não escala de trabalho. Ficam registradas\n-- em \\`migration.excluded_tables\\` com o motivo, que é mais barato que descobrir\n-- isso de novo daqui a seis meses.\n--\n-- ── As três lacunas do V1 que o V2 resolve aqui ─────────────────────────────\n--\n-- (a) FECHAMENTO DE COMPETÊNCIA. O V1 não tem nenhum. Qualquer ajuste pode\n-- mudar, em silêncio, um mês de horas já entregue ao contador e já pago —\n-- e a única trava que existe é de tela: \\`payable_invoice_id\\` preenchido\n-- esconde o botão \"Ajustar\". Uma trava de tela é uma trava até a primeira\n-- chamada de API.\n-- → \\`plg_workforce_periods\\`, no MESMO padrão que o financeiro já provou em\n-- \\`plugin-financial/src/migrations/006\\`: competência é o MÊS (data no dia\n-- 1º, por constraint), é do TENANT e não da unidade (um mês meio fechado é\n-- a pior resposta possível para quem precisa dizer que acabou), a escrita\n-- é só por RPC (\\`workforce_period_close\\` / \\`workforce_period_reopen\\`, sem\n-- policy de INSERT/UPDATE — uma policy de UPDATE seria a porta dos fundos\n-- da trava), reabrir exige motivo, e a permissão de fechar é própria\n-- (\\`workforce.close_period\\`): quem bate ponto não é quem fecha o mês.\n-- A trava vira trigger sobre a batida E sobre o ajuste, e o ajuste ganha\n-- a segunda trava do V1, agora no banco: batida já vinculada a um título\n-- a pagar não aceita ajuste.\n--\n-- (b) JORNADA PREVISTA × REALIZADA. No V1 elas nunca se encontram: a coluna\n-- \"Escala\" da lista de ponto existe para isso e marcou 325 de 325 registros\n-- como \"Fora da escala\".\n-- → O PREVISTO mora em \\`public.schedules\\` com \\`kind = 'work_shift'\\` (não em\n-- tabela nova — ver acima); o REALIZADO mora em\n-- \\`plg_workforce_time_entries\\`; e o cruzamento é a view\n-- \\`public.v_workforce_day\\`, um FULL OUTER JOIN de propósito, para que as\n-- duas assimetrias apareçam em vez de sumirem: previsto sem realizado é\n-- FALTA, realizado sem previsto é FORA DA ESCALA. A publicação da escala\n-- materializa a linha de \\`public.schedules\\` e guarda o id em\n-- \\`plg_workforce_schedule_assignments.schedule_row_id\\`, que é o que torna\n-- o cruzamento uma chave e não uma heurística de nome e horário.\n--\n-- (c) INTERVALO / ALMOÇO. O V1 tem UM par entrada/saída por ciclo. Quem sai para\n-- almoçar e volta ou não registra o intervalo, ou bate a saída e a entrada e\n-- o dia vira dois registros que ninguém soma. Num restaurante com turno\n-- partido isso é a jornada inteira.\n-- → A batida deixa de ser um PAR numa linha e passa a ser um EVENTO:\n-- \\`kind ∈ (clock_in, break_start, break_end, clock_out)\\`, N por dia,\n-- agrupados por \\`(person_id, work_date)\\` e ordenados por \\`seq\\`. A mesma\n-- decisão que satisfaz o append-only resolve o intervalo de graça, e ainda\n-- responde \"quais pontos estão em aberto?\" sem coluna derivada: em aberto\n-- é o dia cujos eventos de abertura (clock_in, break_end) não empatam com\n-- os de fechamento (clock_out, break_start).\n-- \\`work_date\\` é coluna, e não \\`punched_at::date\\`, porque o V1 já convive\n-- com o turno que cruza a meia-noite — a própria caixa de ajuste avisa:\n-- *\"útil quando o funcionário esqueceu de bater a saída e o registro\n-- cruzou para o dia seguinte\"*. A jornada da noite de sábado é de sábado.\n--\n-- ── Uma decisão a mais, tomada na fronteira da migração ─────────────────────\n--\n-- No molde do V1, titular vs stand-by é POSICIONAL: são titulares os primeiros\n-- \\`required_count\\` de \\`schedule_template_assignments\\` por \\`priority\\`, e o resto\n-- é reserva. Ninguém grava isso; é uma regra que vive no código da tela. Na\n-- instância o V1 já tem \\`role\\` como coluna de verdade. Aqui o molde também tem:\n-- \\`plg_workforce_schedule_template_assignments.role\\` é coluna, e o writer da\n-- migração CALCULA a posição uma vez, contra o \\`required_count\\` da função,\n-- em vez de deixar a regra escondida em cada leitor que vier depois.\n--\n-- Idempotente. Nada aqui apaga dado.\n\n-- A RPC de fechamento consulta a view de cruzamento, que nasce três seções\n-- depois dela — as duas moram onde o assunto está, não onde o carregador\n-- preferiria. Sessão, e é o que os baselines gerados do cluster já fazem.\nSET check_function_bodies = false;\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 0. O plugin existe: as permissões\n-- ═══════════════════════════════════════════════════════════════════════════\n--\n-- O scaffold desenha as policies em cima de \\`<plugin>.read/create/edit/delete\\`\n-- e \\`<plugin>.read_all\\`. Sem essas chaves no catálogo, a policy compila e nega\n-- tudo para todo mundo — uma tabela protegida por não existir para ninguém.\n--\n-- Duas chaves são separadas de propósito, e as duas são segregação de função:\n-- \\`workforce.adjust_time\\` porque corrigir a batida de outra pessoa é outra\n-- ordem de decisão que editar uma escala, e \\`workforce.close_period\\` porque\n-- quem aponta não é quem fecha o mês.\nSELECT app.seed_permissions('[\n {\"key\": \"workforce.read\", \"plugin\": \"workforce\", \"description\": \"Ver escala, ponto e competência.\"},\n {\"key\": \"workforce.create\", \"plugin\": \"workforce\", \"description\": \"Criar escala, template e batida.\"},\n {\"key\": \"workforce.edit\", \"plugin\": \"workforce\", \"description\": \"Editar escala e template.\"},\n {\"key\": \"workforce.delete\", \"plugin\": \"workforce\", \"description\": \"Excluir escala e template.\"},\n {\"key\": \"workforce.manage\", \"plugin\": \"workforce\", \"description\": \"Administrar o módulo de jornada.\"},\n {\"key\": \"workforce.read_all\", \"plugin\": \"workforce\", \"description\": \"Ver a jornada de todo mundo, e não só a própria.\"},\n {\"key\": \"workforce.adjust_time\", \"plugin\": \"workforce\", \"description\": \"Ajustar batida de ponto. Separada de workforce.edit: corrigir a hora de outra pessoa é prova, não edição.\"},\n {\"key\": \"workforce.close_period\", \"plugin\": \"workforce\", \"description\": \"Fechar e reabrir a competência de jornada. Separada de workforce.edit: quem aponta não é quem fecha.\"}\n]'::jsonb);\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 1. O PREVISTO já existe — só falta a espécie\n-- ═══════════════════════════════════════════════════════════════════════════\n--\n-- \\`working_hours\\` é a semana recorrente do PROFISSIONAL, para a agenda saber que\n-- um horário pode existir. \\`work_shift\\` é outra coisa: é o turno de trabalho que\n-- o RH ofertou para uma pessoa num dia, e é contra ele que o ponto é conferido.\n-- Reaproveitar \\`working_hours\\` misturaria \"posso ser agendado\" com \"estou\n-- escalado\", que é justamente a confusão que o D3 mandou não fazer.\nINSERT INTO public.schedule_kinds (kind, plugin, description, status)\nVALUES ('work_shift', 'workforce',\n 'O turno de trabalho que o RH escalou para uma pessoa — o PREVISTO contra o qual o ponto é conferido. Distinto de working_hours, que diz apenas quando um horário PODE existir na agenda.',\n 'declared')\nON CONFLICT (kind) DO UPDATE\n SET plugin = EXCLUDED.plugin, description = EXCLUDED.description, updated_at = now();\n\n-- \\`public.schedules\\` foi scaffoldada em modo \\`shadow\\` (065): as policies de\n-- autorização existem, mas as anteriores nunca foram derrubadas, e RLS soma\n-- policies em OR — uma policy legada sobrevivente alarga tudo silenciosamente.\n-- A partir do momento em que a escala do RH mora aqui dentro, sombra não serve:\n-- \\`scaffold_set_mode\\` reemite com os MESMOS resource_type/plugin já registrados\n-- (\\`agenda.schedule\\` / \\`agenda\\`) e derruba o que sobrou. Não é \\`scaffold_table\\`:\n-- repetir o scaffold aqui reclassificaria uma tabela do spine para dentro deste\n-- plugin, e a agenda perderia a própria mesa.\nDO $$\nBEGIN\n IF to_regclass('public.schedules') IS NOT NULL\n AND EXISTS (SELECT 1 FROM app.scaffold_registry\n WHERE table_schema = 'public' AND table_name = 'schedules' AND mode = 'shadow') THEN\n PERFORM app.scaffold_set_mode('public.schedules'::regclass, 'enforce');\n END IF;\nEND $$;\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 2. O REALIZADO: a batida, append-only\n-- ═══════════════════════════════════════════════════════════════════════════\n\nCREATE TABLE IF NOT EXISTS public.plg_workforce_time_entries (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n unit_id uuid REFERENCES app.units(id),\n -- UMA fk, onde o V1 tem person_type + person_id. \\`public.people\\` já é o\n -- cadastro único; profissional e funcionário são papéis em person_roles.\n person_id uuid NOT NULL REFERENCES public.people(id) ON DELETE RESTRICT,\n -- O nome COMO ESTAVA na hora da batida. Não é desnormalização por preguiça: a\n -- folha de ponto é prova, e prova não pode mudar porque alguém corrigiu um\n -- cadastro dois anos depois.\n person_name text,\n -- O evento, não o par. É esta coluna que resolve o intervalo (c): o almoço é\n -- break_start + break_end, e o dia aceita quantos pares de intervalo houver.\n kind text NOT NULL\n CHECK (kind IN ('clock_in', 'break_start', 'break_end', 'clock_out')),\n punched_at timestamptz NOT NULL,\n -- O DIA DA JORNADA, que não é \\`punched_at::date\\`. O turno da noite de sábado\n -- que sai às 02:10 é jornada de sábado; o V1 já convive com isso e a própria\n -- caixa de ajuste dele avisa que o registro \"cruzou para o dia seguinte\".\n work_date date NOT NULL,\n -- Ordena os eventos do dia quando dois caem no mesmo instante (totem com\n -- clique duplo, importação em lote). Sem ele o \"último evento do dia\" é\n -- indeterminado, e é ele que diz se o ponto está em aberto.\n seq integer NOT NULL DEFAULT 1,\n origin text NOT NULL DEFAULT 'totem'\n CHECK (origin IN ('totem', 'device', 'manual', 'import', 'migration')),\n -- A prova que o totem produz: foto, coordenada com precisão, semelhança\n -- facial, IP e aparelho. Fica em jsonb e não em dez colunas porque é um\n -- conjunto de evidência de UM canal de captura — o totem com AWS Rekognition\n -- do V1 — e o próximo canal (crachá, biometria local) traz outro conjunto.\n -- O que não pode é perder: no V1 são \\`photo_path\\`, \\`lat\\`, \\`lng\\`, \\`accuracy_m\\`,\n -- \\`ip\\`, \\`user_agent\\` e \\`face_score\\`, medidos em campo como\n -- \"-22.89342, -43.39140 · ± 14m\" e \"Match facial 100.0%\".\n evidence jsonb NOT NULL DEFAULT '{}'::jsonb,\n -- O turno que esta batida cumpre, quando há um. Nulo é uma resposta legítima\n -- e frequente — é literalmente 325 de 325 no tenant medido — e o V2 prefere\n -- o nulo honesto a um vínculo inventado.\n assignment_id uuid,\n -- Onde esta hora custa. O turno traz o padrão (ver plg_workforce_schedule_shifts);\n -- a batida carrega o que de fato foi classificado, porque a hora do cozinheiro\n -- e a do garçom caem em centros de custo diferentes no mesmo dia.\n -- Sem FK inline: as três colunas abaixo apontam para tabelas de OUTRO plugin,\n -- e a jornada tem de poder ser instalada num cluster que não ligou o\n -- financeiro. A FK é declarada no fim do arquivo, condicionada à existência do\n -- destino — presente vira integridade, ausente vira só um uuid guardado.\n chart_account_id uuid,\n cost_center_id uuid,\n -- O \\`payable_invoice_id\\` do V1. No V1 ele é uma trava DE TELA (preenchido,\n -- o botão \"Ajustar\" some); aqui ele é uma trava de banco, pela trigger da\n -- seção 4. Hora já paga não se corrige sem reabrir a competência.\n payable_invoice_id uuid,\n notes text,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n -- A mesma pessoa não bate o mesmo evento duas vezes no mesmo instante. É o\n -- que torna o replay da migração e o clique duplo no totem inofensivos.\n UNIQUE (tenant_id, person_id, work_date, kind, punched_at, seq)\n);\n\nCOMMENT ON TABLE public.plg_workforce_time_entries IS\n 'A batida, append-only: um EVENTO (entrada, início/fim de intervalo, saída), nunca um par editável. '\n 'UPDATE e DELETE são recusados por trigger; a correção é uma linha em plg_workforce_time_adjustments.';\n\n-- \"O que foi batido neste período, nesta unidade?\" — a pergunta da aba Registros\n-- de Ponto, que o V1 responde com filtros De/Até/Unidade/Pessoa.\nCREATE INDEX IF NOT EXISTS plg_workforce_time_entries_period_idx\n ON public.plg_workforce_time_entries (tenant_id, unit_id, work_date, punched_at);\n\n-- \"Quais pontos estão em aberto?\" — 20 no tenant medido. Em aberto não é coluna\n-- (seria estado derivado numa tabela append-only): é o dia em que os eventos de\n-- ABERTURA não empatam com os de fechamento. Este índice serve a metade que a\n-- view varre, e responde sozinho \"quem entrou hoje e onde\".\nCREATE INDEX IF NOT EXISTS plg_workforce_time_entries_open_idx\n ON public.plg_workforce_time_entries (tenant_id, person_id, work_date, seq)\n WHERE kind IN ('clock_in', 'break_end');\n\n-- \"O que esta pessoa bateu?\" — a folha individual, e o que a folha de pagamento\n-- soma no fim do mês.\nCREATE INDEX IF NOT EXISTS plg_workforce_time_entries_person_idx\n ON public.plg_workforce_time_entries (tenant_id, person_id, work_date DESC);\n\nDROP TRIGGER IF EXISTS plg_workforce_time_entries_updated_at ON public.plg_workforce_time_entries;\nCREATE TRIGGER plg_workforce_time_entries_updated_at\n BEFORE UPDATE ON public.plg_workforce_time_entries\n FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();\n\nGRANT SELECT, INSERT ON public.plg_workforce_time_entries TO authenticated;\nGRANT SELECT, INSERT, UPDATE, DELETE ON public.plg_workforce_time_entries TO service_role;\n\n-- O scaffold é quem sabe desenhar a política deste cluster (tenant, unidade,\n-- permissão do plugin, escotilhas de compartilhamento). Escrever a policy à mão\n-- criaria a segunda regra de autorização da jornada, que diverge da primeira na\n-- próxima mudança do scaffold.\n--\n-- \\`p_owner_scoping = false\\`: a batida não tem dono no sentido de \"criada por\n-- mim\". Quem enxerga ponto de quem é \\`workforce.read\\` por unidade.\nSELECT app.scaffold_table('public.plg_workforce_time_entries'::regclass,\n 'workforce.time_entry', 'workforce', false, 'enforce');\n\n-- ── append-only, das duas formas ────────────────────────────────────────────\n--\n-- O scaffold acabou de criar policies de UPDATE e DELETE, porque é isso que ele\n-- faz em toda tabela. Aqui elas não deveriam existir: apagar batida é o que a\n-- lei não permite. As duas defesas são deliberadamente redundantes — a policy\n-- some para quem entra por \\`authenticated\\`, e a trigger pega também service_role\n-- e qualquer SECURITY DEFINER esquecido.\nDROP POLICY IF EXISTS plg_workforce_time_entries_authz_update ON public.plg_workforce_time_entries;\nDROP POLICY IF EXISTS plg_workforce_time_entries_authz_delete ON public.plg_workforce_time_entries;\n\nCREATE OR REPLACE FUNCTION public.plg_workforce_time_entries_append_only()\n RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $$\nBEGIN\n -- A escotilha é a mesma que o resto do cluster usa: durante uma onda de\n -- migração o motor marca a sessão, e só ela pode reescrever a linha que ela\n -- mesma acabou de trazer. Fora disso não há caminho.\n IF coalesce(current_setting('migration.writer', true), '') = 'on' THEN\n RETURN CASE TG_OP WHEN 'DELETE' THEN OLD ELSE NEW END;\n END IF;\n RAISE EXCEPTION 'plg_workforce_time_entries é append-only (% recusado) — corrija pelo ajuste, que é uma linha com autor e motivo', TG_OP\n USING ERRCODE = '42501',\n HINT = 'INSERT em plg_workforce_time_adjustments (action correct|insert|void) exige workforce.adjust_time.';\nEND $$;\n\nDROP TRIGGER IF EXISTS plg_workforce_time_entries_append_only ON public.plg_workforce_time_entries;\nCREATE TRIGGER plg_workforce_time_entries_append_only\n BEFORE UPDATE OR DELETE ON public.plg_workforce_time_entries\n FOR EACH ROW EXECUTE FUNCTION public.plg_workforce_time_entries_append_only();\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 3. O AJUSTE é uma linha, não uma coluna\n-- ═══════════════════════════════════════════════════════════════════════════\n--\n-- O V1 guarda o ajuste como quatro colunas na própria batida\n-- (\\`checkin_adjusted_at\\`, \\`checkout_adjusted_at\\`, \\`adjustment_reason\\`,\n-- \\`adjusted_by_*\\`) — o que já é melhor que sobrescrever, e é a parte boa do\n-- modelo dele: *\"Os horários reais dos batimentos são preservados.\"* O que ele\n-- não tem é HISTÓRICO: o segundo ajuste apaga o primeiro, e ninguém consegue\n-- dizer quantas vezes aquela hora mudou nem por quem.\n--\n-- Três ações, porque o V1 faz as três e chama todas de \"ajustar\":\n-- correct — a hora é outra (o caso comum)\n-- insert — faltou a batida (o \"esqueceu de bater a saída\" do V1; a batida\n-- nova entra em plg_workforce_time_entries com origin 'manual' e\n-- esta linha é quem carrega o autor e o motivo dela)\n-- void — esta batida não conta (o clique duplo, o totem testado). Não é\n-- DELETE: a linha fica, marcada, porque sumir com prova é o que o\n-- append-only existe para impedir.\nCREATE TABLE IF NOT EXISTS public.plg_workforce_time_adjustments (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n unit_id uuid REFERENCES app.units(id),\n time_entry_id uuid NOT NULL\n REFERENCES public.plg_workforce_time_entries(id) ON DELETE CASCADE,\n action text NOT NULL CHECK (action IN ('correct', 'insert', 'void')),\n -- A hora que passa a valer. Obrigatória em correct/insert e sem sentido em\n -- void — a constraint diz isso em vez de deixar para a tela lembrar.\n effective_at timestamptz,\n -- No V1 o motivo é OPCIONAL (\"Motivo (opcional)\"), e é por isso que ninguém\n -- sabe por que 20 pontos foram mexidos. Aqui é NOT NULL: um ajuste sem motivo\n -- registrado é indistinguível de uma fraude bem-educada.\n reason text NOT NULL,\n adjusted_by_user_id uuid,\n -- O nome de quem ajustou, congelado — mesma razão de \\`person_name\\`.\n adjusted_by_name text,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n CONSTRAINT plg_workforce_time_adjustments_effective_check\n CHECK ((action = 'void' AND effective_at IS NULL) OR (action <> 'void' AND effective_at IS NOT NULL)),\n CONSTRAINT plg_workforce_time_adjustments_reason_check\n CHECK (btrim(reason) <> '')\n);\n\nCOMMENT ON TABLE public.plg_workforce_time_adjustments IS\n 'O ajuste de ponto como LINHA, com autor e motivo obrigatório. O V1 guarda isso em colunas da própria batida e perde o histórico no segundo ajuste; aqui cada correção fica, e a hora que vale é a da última não anulada.';\n\n-- \"Qual a hora que vale nesta batida?\" — a view da seção 7 pergunta isso uma vez\n-- por batida, e é o caminho quente da folha de ponto inteira.\nCREATE INDEX IF NOT EXISTS plg_workforce_time_adjustments_entry_idx\n ON public.plg_workforce_time_adjustments (time_entry_id, created_at DESC);\n\nDROP TRIGGER IF EXISTS plg_workforce_time_adjustments_updated_at ON public.plg_workforce_time_adjustments;\nCREATE TRIGGER plg_workforce_time_adjustments_updated_at\n BEFORE UPDATE ON public.plg_workforce_time_adjustments\n FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();\n\nGRANT SELECT, INSERT, UPDATE, DELETE ON public.plg_workforce_time_adjustments TO authenticated, service_role;\n\nSELECT app.scaffold_table('public.plg_workforce_time_adjustments'::regclass,\n 'workforce.time_adjustment', 'workforce', false, 'enforce');\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 4. A COMPETÊNCIA (lacuna a)\n-- ═══════════════════════════════════════════════════════════════════════════\n--\n-- Mesmo desenho de \\`plg_financial_periods\\` (plugin-financial/006), de\n-- propósito: a empresa fecha UM mês, e ter dois calendários de fechamento com\n-- regras diferentes — um do dinheiro e outro das horas — é como não ter\n-- fechamento nenhum, porque a pergunta \"fevereiro está fechado?\" passa a ter\n-- duas respostas.\nCREATE TABLE IF NOT EXISTS public.plg_workforce_periods (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n -- A competência é do TENANT, não da unidade: fechar o mês é um ato de\n -- empresa, e um mês meio fechado é a pior resposta para quem precisa dizer ao\n -- contador que acabou. A coluna existe porque o scaffold precisa dela.\n unit_id uuid REFERENCES app.units(id),\n -- Sempre o dia 1º, por constraint e não por convenção de quem escreve.\n competence_month date NOT NULL,\n status text NOT NULL DEFAULT 'open' CHECK (status IN ('open', 'closed')),\n closed_at timestamptz,\n closed_by_user_id uuid,\n reopened_at timestamptz,\n reopened_by_user_id uuid,\n -- Reabrir sem dizer por quê é como não ter fechado. Obrigatório na RPC; a\n -- coluna aceita nulo porque um período nunca reaberto não tem um.\n reopen_reason text,\n -- O que o fechamento virou no financeiro, quando virou. A folha é uma conta a\n -- pagar como outra qualquer, e a classificação dela mora aqui porque é o\n -- fechamento — não a batida — que produz o lançamento.\n payable_invoice_id uuid,\n chart_account_id uuid,\n cost_center_id uuid,\n notes text,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n CONSTRAINT plg_workforce_periods_first_of_month_check\n CHECK (competence_month = date_trunc('month', competence_month)::date),\n CONSTRAINT plg_workforce_periods_tenant_month_key UNIQUE (tenant_id, competence_month)\n);\n\nCOMMENT ON TABLE public.plg_workforce_periods IS\n 'Competência mensal da jornada e seu estado. Fechada = nenhuma batida nem ajuste entra com data naquele mês. Escrita só por workforce_period_close/reopen.';\n\n-- A trava consulta \"este mês está fechado?\" a cada batida: índice parcial.\nCREATE INDEX IF NOT EXISTS plg_workforce_periods_closed_idx\n ON public.plg_workforce_periods (tenant_id, competence_month) WHERE status = 'closed';\n\nDROP TRIGGER IF EXISTS plg_workforce_periods_updated_at ON public.plg_workforce_periods;\nCREATE TRIGGER plg_workforce_periods_updated_at\n BEFORE UPDATE ON public.plg_workforce_periods\n FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();\n\nGRANT SELECT ON public.plg_workforce_periods TO authenticated;\nGRANT SELECT, INSERT, UPDATE, DELETE ON public.plg_workforce_periods TO service_role;\n\nSELECT app.scaffold_table('public.plg_workforce_periods'::regclass,\n 'workforce.period', 'workforce', false, 'enforce');\n\n-- ESCREVER É SÓ PELA RPC. Fechar e reabrir são ATOS, não edições de linha, e o\n-- ato é onde a permissão e o registro de QUEM moram. Uma policy de UPDATE aqui\n-- seria a porta dos fundos da trava — é a mesma decisão do financeiro/006.\nDROP POLICY IF EXISTS plg_workforce_periods_authz_insert ON public.plg_workforce_periods;\nDROP POLICY IF EXISTS plg_workforce_periods_authz_update ON public.plg_workforce_periods;\nDROP POLICY IF EXISTS plg_workforce_periods_authz_delete ON public.plg_workforce_periods;\n\nCREATE OR REPLACE FUNCTION public.plg_workforce_period_is_closed(p_tenant uuid, p_date date)\n RETURNS boolean LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO ''\nAS $$\n SELECT EXISTS (\n SELECT 1 FROM public.plg_workforce_periods p\n WHERE p.tenant_id = p_tenant\n AND p.status = 'closed'\n AND p.competence_month = date_trunc('month', p_date)::date);\n$$;\n\nCOMMENT ON FUNCTION public.plg_workforce_period_is_closed(uuid, date) IS\n 'O mês desta data está fechado para a jornada deste tenant?';\n\n-- ── a trava sobre a batida ──────────────────────────────────────────────────\nCREATE OR REPLACE FUNCTION public.trg_workforce_refuse_closed_period()\n RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $$\nDECLARE\n v_date date;\nBEGIN\n -- Uma onda de migração traz o passado inteiro, e o passado inteiro está em\n -- meses que o V1 já tratou como encerrados. Fechar por cima do que ainda está\n -- chegando seria fechar antes de existir.\n IF coalesce(current_setting('migration.writer', true), '') = 'on' THEN\n RETURN NEW;\n END IF;\n\n -- A data que conta é a da JORNADA, não a de criação da linha.\n IF TG_TABLE_NAME = 'plg_workforce_time_entries' THEN\n v_date := NEW.work_date;\n ELSE\n SELECT e.work_date INTO v_date\n FROM public.plg_workforce_time_entries e WHERE e.id = NEW.time_entry_id;\n END IF;\n\n IF v_date IS NOT NULL AND public.plg_workforce_period_is_closed(NEW.tenant_id, v_date) THEN\n RAISE EXCEPTION 'a competência de % está fechada — reabra o período para lançar nela', to_char(v_date, 'MM/YYYY')\n USING ERRCODE = '23514',\n HINT = 'workforce_period_reopen(date_trunc(''month'', data)::date, ''motivo'') exige workforce.close_period.';\n END IF;\n\n RETURN NEW;\nEND $$;\n\nDROP TRIGGER IF EXISTS plg_workforce_time_entries_refuse_closed_period ON public.plg_workforce_time_entries;\nCREATE TRIGGER plg_workforce_time_entries_refuse_closed_period\n BEFORE INSERT ON public.plg_workforce_time_entries\n FOR EACH ROW EXECUTE FUNCTION public.trg_workforce_refuse_closed_period();\n\nDROP TRIGGER IF EXISTS plg_workforce_time_adjustments_refuse_closed_period ON public.plg_workforce_time_adjustments;\nCREATE TRIGGER plg_workforce_time_adjustments_refuse_closed_period\n BEFORE INSERT OR UPDATE ON public.plg_workforce_time_adjustments\n FOR EACH ROW EXECUTE FUNCTION public.trg_workforce_refuse_closed_period();\n\n-- ── a segunda trava do V1, agora no banco ───────────────────────────────────\n--\n-- No V1, batida com \\`payable_invoice_id\\` preenchido não pode ser ajustada — e a\n-- regra vive no componente que esconde o botão. Aqui ela vive onde não dá para\n-- contornar. A linha migrada é coberta pela mesma trava: o V1 aponta para uma\n-- tabela de títulos cuja contraparte no V2 não é a mesma coisa (ver a nota do\n-- de-para), então a referência crua fica em \\`metadata.v1.payable_invoice_id\\` — e\n-- basta ela existir para a hora estar travada.\nCREATE OR REPLACE FUNCTION public.trg_workforce_refuse_settled_adjustment()\n RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $$\nDECLARE\n v_entry public.plg_workforce_time_entries%ROWTYPE;\nBEGIN\n IF coalesce(current_setting('migration.writer', true), '') = 'on' THEN\n RETURN NEW;\n END IF;\n SELECT * INTO v_entry FROM public.plg_workforce_time_entries WHERE id = NEW.time_entry_id;\n IF v_entry.payable_invoice_id IS NOT NULL\n OR (v_entry.metadata #>> '{v1,payable_invoice_id}') IS NOT NULL THEN\n RAISE EXCEPTION 'esta batida já virou título a pagar — a hora paga não se corrige sem estornar o título'\n USING ERRCODE = '23514';\n END IF;\n IF NOT app.has_permission('workforce.adjust_time', v_entry.unit_id) THEN\n RAISE EXCEPTION 'ajustar ponto exige workforce.adjust_time' USING ERRCODE = '42501';\n END IF;\n RETURN NEW;\nEND $$;\n\nDROP TRIGGER IF EXISTS plg_workforce_time_adjustments_refuse_settled ON public.plg_workforce_time_adjustments;\nCREATE TRIGGER plg_workforce_time_adjustments_refuse_settled\n BEFORE INSERT ON public.plg_workforce_time_adjustments\n FOR EACH ROW EXECUTE FUNCTION public.trg_workforce_refuse_settled_adjustment();\n\n-- ── fechar e reabrir ────────────────────────────────────────────────────────\nCREATE OR REPLACE FUNCTION public.workforce_period_close(p_month date, p_notes text DEFAULT NULL)\n RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $$\nDECLARE\n v_tenant uuid := app.current_tenant_id();\n v_month date := date_trunc('month', p_month)::date;\n v_open bigint;\n v_row public.plg_workforce_periods%ROWTYPE;\nBEGIN\n IF v_tenant IS NULL THEN\n RAISE EXCEPTION 'workforce_period_close: sem tenant na sessão' USING ERRCODE = '42501';\n END IF;\n IF NOT app.has_permission('workforce.close_period', NULL) THEN\n RAISE EXCEPTION 'workforce_period_close: exige workforce.close_period' USING ERRCODE = '42501';\n END IF;\n IF v_month > date_trunc('month', current_date)::date THEN\n RAISE EXCEPTION 'workforce_period_close: % ainda não terminou', to_char(v_month, 'MM/YYYY')\n USING ERRCODE = '22023';\n END IF;\n\n -- Ponto em aberto é jornada que ainda vai mudar. Fechar por cima produz um\n -- total de horas que muda depois de fechado, que é exatamente o que a trava\n -- existe para impedir — e é o defeito medido no V1: 20 batimentos em aberto\n -- fazem o valor do período (R$ 47.747) ser um número menor que o real.\n SELECT count(*) INTO v_open\n FROM public.v_workforce_day d\n WHERE d.tenant_id = v_tenant\n AND d.is_open\n AND date_trunc('month', d.work_date)::date <= v_month;\n IF v_open > 0 THEN\n RAISE EXCEPTION 'workforce_period_close: % ponto(s) em aberto em % ou antes — feche ou ajuste antes', v_open, to_char(v_month, 'MM/YYYY')\n USING ERRCODE = '23514',\n HINT = 'SELECT * FROM public.v_workforce_day WHERE is_open;';\n END IF;\n\n INSERT INTO public.plg_workforce_periods (tenant_id, competence_month, status, closed_at, closed_by_user_id, notes)\n VALUES (v_tenant, v_month, 'closed', now(), auth.uid(), p_notes)\n ON CONFLICT (tenant_id, competence_month) DO UPDATE\n SET status = 'closed', closed_at = now(), closed_by_user_id = auth.uid(),\n notes = coalesce(EXCLUDED.notes, public.plg_workforce_periods.notes), updated_at = now()\n RETURNING * INTO v_row;\n\n RETURN jsonb_build_object('period_id', v_row.id, 'competence_month', v_month,\n 'status', 'closed', 'closed_at', v_row.closed_at);\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.workforce_period_reopen(p_month date, p_reason text)\n RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $$\nDECLARE\n v_tenant uuid := app.current_tenant_id();\n v_month date := date_trunc('month', p_month)::date;\n v_row public.plg_workforce_periods%ROWTYPE;\nBEGIN\n IF v_tenant IS NULL THEN\n RAISE EXCEPTION 'workforce_period_reopen: sem tenant na sessão' USING ERRCODE = '42501';\n END IF;\n IF NOT app.has_permission('workforce.close_period', NULL) THEN\n RAISE EXCEPTION 'workforce_period_reopen: exige workforce.close_period' USING ERRCODE = '42501';\n END IF;\n IF nullif(btrim(coalesce(p_reason, '')), '') IS NULL THEN\n RAISE EXCEPTION 'workforce_period_reopen: o motivo é obrigatório' USING ERRCODE = '22023';\n END IF;\n\n UPDATE public.plg_workforce_periods SET\n status = 'open', reopened_at = now(), reopened_by_user_id = auth.uid(),\n reopen_reason = p_reason, updated_at = now()\n WHERE tenant_id = v_tenant AND competence_month = v_month\n RETURNING * INTO v_row;\n\n IF v_row.id IS NULL THEN\n RAISE EXCEPTION 'workforce_period_reopen: % nunca foi fechado', to_char(v_month, 'MM/YYYY')\n USING ERRCODE = 'P0002';\n END IF;\n\n RETURN jsonb_build_object('period_id', v_row.id, 'competence_month', v_month,\n 'status', 'open', 'reopened_at', v_row.reopened_at, 'reason', p_reason);\nEND $$;\n\nREVOKE ALL ON FUNCTION public.workforce_period_close(date, text) FROM PUBLIC;\nREVOKE ALL ON FUNCTION public.workforce_period_reopen(date, text) FROM PUBLIC;\nGRANT EXECUTE ON FUNCTION public.workforce_period_close(date, text) TO authenticated;\nGRANT EXECUTE ON FUNCTION public.workforce_period_reopen(date, text) TO authenticated;\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 5. A ESCALA: o molde\n-- ═══════════════════════════════════════════════════════════════════════════\n\nCREATE TABLE IF NOT EXISTS public.plg_workforce_schedule_templates (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n -- No V1 o template é POR UNIDADE (o editor abre com um seletor de Unidade), e\n -- aqui também: \"Almoço Seg. a Sex.\" da matriz não é o da filial.\n unit_id uuid REFERENCES app.units(id),\n name text NOT NULL,\n is_active boolean NOT NULL DEFAULT true,\n notes text,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now()\n);\n\nCOMMENT ON TABLE public.plg_workforce_schedule_templates IS\n 'O molde da escala. Pré-requisito duro no V1: sem template não se cria escala nenhuma — \"Selecione um template de escala acima para começar.\"';\n\nCREATE TABLE IF NOT EXISTS public.plg_workforce_schedule_shifts (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n unit_id uuid REFERENCES app.units(id),\n template_id uuid NOT NULL\n REFERENCES public.plg_workforce_schedule_templates(id) ON DELETE CASCADE,\n label text NOT NULL,\n start_time time NOT NULL,\n end_time time NOT NULL,\n -- 0 = domingo, como \\`extract(dow)\\` e como \\`public.schedules.day_of_week\\`.\n -- A constraint existe porque um 7 solto num array é um turno que nunca\n -- acontece e que ninguém percebe faltando.\n weekdays smallint[] NOT NULL DEFAULT '{}'::smallint[],\n -- Turno que vira o dia (16:00–02:00) é normal em restaurante, e é a razão de\n -- \\`work_date\\` ser coluna na batida. Guardar a travessia aqui evita que cada\n -- leitor redescubra \\`end_time < start_time\\` à sua maneira.\n crosses_midnight boolean NOT NULL GENERATED ALWAYS AS (end_time <= start_time) STORED,\n sort_order integer NOT NULL DEFAULT 0,\n -- O padrão de onde a hora deste turno custa. A batida copia e pode divergir.\n -- FK condicional no fim do arquivo, como nas outras duas tabelas.\n chart_account_id uuid,\n cost_center_id uuid,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n CONSTRAINT plg_workforce_schedule_shifts_weekdays_check\n CHECK (weekdays <@ ARRAY[0,1,2,3,4,5,6]::smallint[])\n);\n\nCREATE TABLE IF NOT EXISTS public.plg_workforce_schedule_requirements (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n unit_id uuid REFERENCES app.units(id),\n shift_id uuid NOT NULL\n REFERENCES public.plg_workforce_schedule_shifts(id) ON DELETE CASCADE,\n -- Texto, e não FK para um cadastro de profissão: no V1 isto é o nome livre que\n -- a tela mostra (\"Garçom (1/1)\", \"Cozinha (0/3)\"), e o V2 ainda não tem o\n -- cadastro de profissão que seria o destino honesto. Inventar a FK agora seria\n -- criar um cadastro a partir de dado sujo; o texto atravessa e fica auditável.\n profession_name text NOT NULL,\n required_count integer NOT NULL DEFAULT 1 CHECK (required_count > 0),\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n UNIQUE (shift_id, profession_name)\n);\n\nCOMMENT ON COLUMN public.plg_workforce_schedule_requirements.required_count IS\n 'A lotação da função no turno — o denominador do \"Garçom (1/1)\" da tela. É contra ele que a posição por prioridade vira titular ou stand-by.';\n\nCREATE TABLE IF NOT EXISTS public.plg_workforce_schedule_template_assignments (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n unit_id uuid REFERENCES app.units(id),\n template_id uuid NOT NULL\n REFERENCES public.plg_workforce_schedule_templates(id) ON DELETE CASCADE,\n shift_id uuid NOT NULL\n REFERENCES public.plg_workforce_schedule_shifts(id) ON DELETE CASCADE,\n profession_name text NOT NULL,\n person_id uuid NOT NULL REFERENCES public.people(id) ON DELETE CASCADE,\n -- COLUNA, e não posição. No V1 titular vs stand-by no molde é implícito — são\n -- titulares os primeiros \\`required_count\\` por \\`priority\\` — e essa regra só\n -- existe no código da tela. Aqui ela é calculada uma vez, na entrada, e fica\n -- escrita: a mesma verdade que a instância já grava.\n role text NOT NULL DEFAULT 'titular' CHECK (role IN ('titular', 'standby')),\n priority integer NOT NULL DEFAULT 0,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n UNIQUE (shift_id, profession_name, person_id)\n);\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 6. A ESCALA: a instância do dia\n-- ═══════════════════════════════════════════════════════════════════════════\n\nCREATE TABLE IF NOT EXISTS public.plg_workforce_schedules (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n unit_id uuid REFERENCES app.units(id),\n schedule_date date NOT NULL,\n -- SET NULL e não CASCADE: apagar o molde não pode apagar a escala de terça\n -- passada, que é registro de quem trabalhou. A cópia do turno já está no\n -- snapshot da atribuição, então a escala sobrevive sozinha ao molde.\n template_id uuid REFERENCES public.plg_workforce_schedule_templates(id) ON DELETE SET NULL,\n status text NOT NULL DEFAULT 'draft'\n CHECK (status IN ('draft', 'published', 'closed')),\n published_at timestamptz,\n published_by_user_id uuid,\n is_special_day boolean NOT NULL DEFAULT false,\n special_day_label text,\n notes text,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n -- Publicada sem carimbo de quando é uma escala que ninguém consegue provar\n -- ter avisado — e avisar é a única coisa que a publicação faz.\n CONSTRAINT plg_workforce_schedules_published_check\n CHECK (status <> 'published' OR published_at IS NOT NULL)\n);\n\n-- \"Qual a escala deste dia?\" — é o clique do calendário, e é a consulta que a\n-- tela faz primeiro em toda sessão.\nCREATE INDEX IF NOT EXISTS plg_workforce_schedules_day_idx\n ON public.plg_workforce_schedules (tenant_id, unit_id, schedule_date DESC, status);\n\nCREATE TABLE IF NOT EXISTS public.plg_workforce_schedule_assignments (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n unit_id uuid REFERENCES app.units(id),\n schedule_id uuid NOT NULL\n REFERENCES public.plg_workforce_schedules(id) ON DELETE CASCADE,\n -- A referência ao turno do molde é conveniência, não dependência: o snapshot\n -- abaixo é quem manda. Por isso SET NULL.\n shift_id uuid REFERENCES public.plg_workforce_schedule_shifts(id) ON DELETE SET NULL,\n -- SNAPSHOT, copiado na criação da escala, exatamente como o V1 faz. Mudar o\n -- molde não pode reescrever a escala de anteontem: o que a pessoa foi chamada\n -- para cumprir é um fato daquele dia, e é contra ESTE horário que o ponto dela\n -- é conferido.\n shift_label text,\n shift_start_time time,\n shift_end_time time,\n profession_name text,\n person_id uuid NOT NULL REFERENCES public.people(id) ON DELETE RESTRICT,\n role text NOT NULL DEFAULT 'titular' CHECK (role IN ('titular', 'standby')),\n priority integer NOT NULL DEFAULT 0,\n status text NOT NULL DEFAULT 'pending'\n CHECK (status IN ('pending', 'notified', 'confirmed', 'declined', 'realized')),\n -- O convite que sai por link, sem sessão. Único no tenant porque é uma\n -- credencial: dois convites com o mesmo token são duas pessoas confirmando\n -- pelo mesmo endereço.\n response_token text,\n response_channel text,\n notified_at timestamptz,\n responded_at timestamptz,\n -- A PONTE COM A AGENDA, e a razão de a escala não morar lá. O RH oferta; ao\n -- publicar, a atribuição materializa uma linha de \\`public.schedules\\` com\n -- kind 'work_shift' e a agenda consome. A coluna é o que torna o cruzamento\n -- previsto × realizado uma chave em vez de um casamento por nome e hora.\n schedule_row_id uuid REFERENCES public.schedules(id) ON DELETE SET NULL,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n -- A mesma pessoa não ocupa a mesma vaga duas vezes no mesmo dia. No V1 nada\n -- impede, e o resultado é a lotação \"2/1\" que a tela não sabe desenhar.\n UNIQUE (schedule_id, shift_id, profession_name, person_id)\n);\n\nCREATE UNIQUE INDEX IF NOT EXISTS plg_workforce_schedule_assignments_token_uq\n ON public.plg_workforce_schedule_assignments (tenant_id, response_token)\n WHERE response_token IS NOT NULL;\n\n-- \"Quem está escalado hoje, e quem ainda não respondeu?\" — os contadores\n-- \"N titulares · N pendentes\" do cartão da escala.\nCREATE INDEX IF NOT EXISTS plg_workforce_schedule_assignments_schedule_idx\n ON public.plg_workforce_schedule_assignments (schedule_id, role, status);\n\n-- \"O que ESTA pessoa tem pela frente?\" — a folha individual e o convite.\nCREATE INDEX IF NOT EXISTS plg_workforce_schedule_assignments_person_idx\n ON public.plg_workforce_schedule_assignments (tenant_id, person_id, status);\n\n-- O log da atribuição: quem mudou o quê, por qual canal. No V1 é\n-- \\`schedule_assignment_logs\\`, e é a única parte do modelo de escala dele que já\n-- nasceu append-only.\nCREATE TABLE IF NOT EXISTS public.plg_workforce_assignment_logs (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n unit_id uuid REFERENCES app.units(id),\n assignment_id uuid NOT NULL\n REFERENCES public.plg_workforce_schedule_assignments(id) ON DELETE CASCADE,\n from_status text,\n to_status text NOT NULL,\n channel text,\n note text,\n changed_by_user_id uuid,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now()\n);\n\nCREATE INDEX IF NOT EXISTS plg_workforce_assignment_logs_assignment_idx\n ON public.plg_workforce_assignment_logs (assignment_id, created_at DESC);\n\n-- ── triggers, grants e scaffold das seis tabelas de escala ──────────────────\n--\n-- Em laço porque são seis vezes a mesma disciplina: o gatilho de updated_at, o\n-- GRANT para os dois papéis que existem, e o scaffold desenhando a policy. Seis\n-- blocos copiados divergiriam no primeiro dia em que alguém editasse um só.\nDO $$\nDECLARE\n r record;\nBEGIN\n FOR r IN\n SELECT * FROM (VALUES\n ('plg_workforce_schedule_templates', 'workforce.schedule_template'),\n ('plg_workforce_schedule_shifts', 'workforce.schedule_shift'),\n ('plg_workforce_schedule_requirements', 'workforce.schedule_requirement'),\n ('plg_workforce_schedule_template_assignments', 'workforce.schedule_template_assignment'),\n ('plg_workforce_schedules', 'workforce.schedule'),\n ('plg_workforce_schedule_assignments', 'workforce.schedule_assignment'),\n ('plg_workforce_assignment_logs', 'workforce.assignment_log')\n ) AS t(tbl, resource)\n LOOP\n EXECUTE format('DROP TRIGGER IF EXISTS %I ON public.%I', r.tbl || '_updated_at', r.tbl);\n EXECUTE format('CREATE TRIGGER %I BEFORE UPDATE ON public.%I FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at()',\n r.tbl || '_updated_at', r.tbl);\n EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE ON public.%I TO authenticated, service_role', r.tbl);\n PERFORM app.scaffold_table(format('public.%I', r.tbl)::regclass, r.resource, 'workforce', false, 'enforce');\n END LOOP;\nEND $$;\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 7. O CRUZAMENTO previsto × realizado (lacuna b)\n-- ═══════════════════════════════════════════════════════════════════════════\n\n-- A hora que VALE em cada batida: a última correção não anulada, ou o horário\n-- real. É a leitura que substitui as colunas \\`*_adjusted_at\\` do V1 sem perder a\n-- propriedade que o V1 acertou — o horário real continua ali, intocado.\n--\n-- \\`security_invoker\\` em todas as views desta seção: uma folha de ponto que\n-- ignora escopo é um vazamento com totais.\n-- REPLAY: \\`DROP\\` e depois \\`CREATE\\`, e não \\`CREATE OR REPLACE\\`.\n--\n-- As migrations 003/004/005 ACRESCENTAM colunas a esta view. Acrescentar,\n-- \\`CREATE OR REPLACE\\` faz; TIRAR, não faz — e é o que a baseline faria numa\n-- segunda passada, porque a versão dela é a estreita. O cluster devolve\n-- \\`42P16: cannot drop columns from view\\` e a corrente para aqui.\n--\n-- Conferido em \\`pg_depend\\` antes de derrubar: nada pende destas duas views,\n-- então o \\`DROP\\` é sem \\`CASCADE\\` — de propósito. Sem ele, o dia em que\n-- alguém construir sobre elas o \\`DROP\\` falha alto em vez de levar junto.\n-- Na ordem da dependência: \\`v_workforce_day\\` é construída SOBRE esta, então\n-- sai primeiro. Sem isso o \\`DROP\\` de baixo recusa — e recusar é o certo,\n-- foi assim que esta dependência apareceu.\nDROP VIEW IF EXISTS public.v_workforce_day;\nDROP VIEW IF EXISTS public.v_workforce_time_entries;\nCREATE VIEW public.v_workforce_time_entries\nWITH (security_invoker = 'true') AS\nSELECT e.id,\n e.tenant_id,\n e.unit_id,\n e.person_id,\n e.person_name,\n e.kind,\n e.work_date,\n e.seq,\n e.origin,\n e.punched_at,\n coalesce(c.effective_at, e.punched_at) AS effective_at,\n (c.id IS NOT NULL) AS adjusted,\n (v.id IS NOT NULL) AS voided,\n c.reason AS adjustment_reason,\n c.adjusted_by_name,\n e.assignment_id,\n e.payable_invoice_id,\n e.evidence,\n e.metadata\n FROM public.plg_workforce_time_entries e\n LEFT JOIN LATERAL (\n SELECT a.id, a.effective_at, a.reason, a.adjusted_by_name\n FROM public.plg_workforce_time_adjustments a\n WHERE a.time_entry_id = e.id AND a.action IN ('correct', 'insert')\n ORDER BY a.created_at DESC, a.id DESC\n LIMIT 1) c ON true\n LEFT JOIN LATERAL (\n SELECT a.id FROM public.plg_workforce_time_adjustments a\n WHERE a.time_entry_id = e.id AND a.action = 'void'\n LIMIT 1) v ON true;\n\nCOMMENT ON VIEW public.v_workforce_time_entries IS\n 'A batida com a hora que vale: a última correção não anulada, ou o horário real. O real (punched_at) nunca some — é o que torna o ponto auditável.';\n\n-- O dia de trabalho de uma pessoa, previsto ao lado de realizado.\n--\n-- FULL OUTER JOIN de propósito. As duas assimetrias são exatamente o que o V1\n-- não consegue mostrar, e são as duas perguntas do RH: previsto sem realizado é\n-- FALTA; realizado sem previsto é FORA DA ESCALA (que no tenant medido é o\n-- estado de 325 de 325 registros — não porque as pessoas trabalhem fora da\n-- escala, mas porque o ponto está ligado numa unidade e a escala em outra).\n--\n-- As horas trabalhadas saem de uma soma com sinal: clock_out e break_start\n-- FECHAM um trecho, clock_in e break_end ABREM. Quantos intervalos houver no\n-- dia, a conta é a mesma — é isso que o par único do V1 não consegue fazer.\n-- REPLAY: \\`DROP\\` e depois \\`CREATE\\`, e não \\`CREATE OR REPLACE\\`.\n--\n-- As migrations 003/004/005 ACRESCENTAM colunas a esta view. Acrescentar,\n-- \\`CREATE OR REPLACE\\` faz; TIRAR, não faz — e é o que a baseline faria numa\n-- segunda passada, porque a versão dela é a estreita. O cluster devolve\n-- \\`42P16: cannot drop columns from view\\` e a corrente para aqui.\n--\n-- Conferido em \\`pg_depend\\` antes de derrubar: nada pende destas duas views,\n-- então o \\`DROP\\` é sem \\`CASCADE\\` — de propósito. Sem ele, o dia em que\n-- alguém construir sobre elas o \\`DROP\\` falha alto em vez de levar junto.\nDROP VIEW IF EXISTS public.v_workforce_day;\nCREATE VIEW public.v_workforce_day\nWITH (security_invoker = 'true') AS\nWITH realized AS (\n SELECT e.tenant_id,\n e.unit_id,\n e.person_id,\n e.work_date,\n min(e.effective_at) FILTER (WHERE e.kind = 'clock_in') AS first_in,\n max(e.effective_at) FILTER (WHERE e.kind = 'clock_out') AS last_out,\n count(*) FILTER (WHERE e.kind = 'break_start') AS break_count,\n count(*) FILTER (WHERE e.kind IN ('clock_in', 'break_end'))\n <> count(*) FILTER (WHERE e.kind IN ('clock_out', 'break_start')) AS is_open,\n sum(CASE\n WHEN e.kind IN ('clock_out', 'break_start') THEN extract(epoch FROM e.effective_at)\n WHEN e.kind IN ('clock_in', 'break_end') THEN -extract(epoch FROM e.effective_at)\n END) AS worked_seconds\n FROM public.v_workforce_time_entries e\n WHERE NOT e.voided\n GROUP BY e.tenant_id, e.unit_id, e.person_id, e.work_date\n),\nplanned AS (\n SELECT a.tenant_id,\n a.unit_id,\n a.person_id,\n s.schedule_date AS work_date,\n a.id AS assignment_id,\n a.role,\n a.status AS assignment_status,\n a.shift_label,\n a.shift_start_time,\n a.shift_end_time,\n -- O turno que vira o dia é normal aqui; sem o +24h a jornada da noite\n -- daria negativa.\n (extract(epoch FROM a.shift_end_time - a.shift_start_time)\n + CASE WHEN a.shift_end_time <= a.shift_start_time THEN 86400 ELSE 0 END) AS planned_seconds\n FROM public.plg_workforce_schedule_assignments a\n JOIN public.plg_workforce_schedules s ON s.id = a.schedule_id\n WHERE s.status IN ('published', 'closed')\n AND a.role = 'titular'\n AND a.shift_start_time IS NOT NULL\n AND a.shift_end_time IS NOT NULL\n)\nSELECT coalesce(p.tenant_id, r.tenant_id) AS tenant_id,\n coalesce(p.unit_id, r.unit_id) AS unit_id,\n coalesce(p.person_id, r.person_id) AS person_id,\n coalesce(p.work_date, r.work_date) AS work_date,\n p.assignment_id,\n p.shift_label,\n p.shift_start_time,\n p.shift_end_time,\n p.assignment_status,\n (p.planned_seconds / 60)::integer AS planned_minutes,\n (r.worked_seconds / 60)::integer AS worked_minutes,\n ((r.worked_seconds - p.planned_seconds) / 60)::integer AS variance_minutes,\n r.first_in,\n r.last_out,\n r.break_count,\n coalesce(r.is_open, false) AS is_open,\n -- As duas assimetrias, nomeadas. São as perguntas do RH, e nenhuma delas\n -- tem resposta no V1.\n (r.person_id IS NULL) AS absent,\n (p.assignment_id IS NULL) AS outside_schedule\n FROM planned p\n FULL OUTER JOIN realized r\n ON r.tenant_id = p.tenant_id\n AND r.person_id = p.person_id\n AND r.work_date = p.work_date;\n\nCOMMENT ON VIEW public.v_workforce_day IS\n 'Jornada prevista × realizada por pessoa e dia. Previsto vem da escala publicada, realizado das batidas com ajuste aplicado. FULL OUTER JOIN: \\`absent\\` é escala sem ponto, \\`outside_schedule\\` é ponto sem escala — as duas perguntas que o V1 não responde.';\n\nGRANT SELECT ON public.v_workforce_time_entries TO authenticated, service_role;\nGRANT SELECT ON public.v_workforce_day TO authenticated, service_role;\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 8. OS WRITERS da migração\n-- ═══════════════════════════════════════════════════════════════════════════\n\n-- O vocabulário do de-para é lista fechada de propósito: uma linha que nomeia um\n-- writer inexistente falha na hora, não na terceira hora da onda.\n--\n-- ACRÉSCIMO, e não reemissão. A versão anterior reescrevia a lista INTEIRA —\n-- \"a lista até aqui (046) mais os oito da jornada\". Uma lista escrita por\n-- extenso é um retrato: ela apaga todo writer que outro passo registrou e que\n-- o retrato não viu. Medido no cluster vivo, re-aplicar esta baseline dava\n--\n-- 23514: check constraint \"allowlist_writer_check\" is violated by some row\n--\n-- porque lá já havia writers que esta lista não nomeia. É o mesmo defeito que\n-- \\`agenda/008\\` e \\`financial/072\\` já pagaram, e a forma abaixo é a de\n-- \\`inventory/004\\`: leia o que existe, acrescente o que falta, nunca reemita.\nDO $$\nDECLARE\n v_def text;\n v_falta text[];\n v_meus text[] := ARRAY[\n 'wf_time_entry', 'wf_schedule_template', 'wf_schedule_shift',\n 'wf_schedule_requirement', 'wf_schedule_template_assignment',\n 'wf_schedule', 'wf_schedule_assignment', 'wf_assignment_log'];\nBEGIN\n SELECT pg_get_constraintdef(oid) INTO v_def\n FROM pg_constraint WHERE conname = 'allowlist_writer_check';\n\n IF v_def IS NULL THEN\n -- Ninguém escreveu a regra ainda: aqui ela nasce, com os writers desta\n -- jornada e os que a corrente já registrou até este ponto.\n ALTER TABLE migration.allowlist ADD CONSTRAINT allowlist_writer_check\n CHECK (writer IS NULL OR writer = ANY (ARRAY[\n 'person', 'unit', 'category', 'product', 'order', 'invoice', 'price_table',\n 'price_table_item', 'package', 'package_item', 'field_rule', 'holiday', 'facet',\n 'fin_account', 'fin_payment_method_type', 'fin_payment_method', 'fin_card_brand',\n 'fin_chart_account', 'fin_cost_center', 'inv_measurement_unit', 'inv_unit_conversion',\n 'inv_location', 'inv_movement', 'order_item', 'fin_movement', 'authz_role',\n 'authz_role_permission', 'person_registration',\n 'fin_recurring_bill', 'fin_recurring_bill_item', 'fin_recurring_bill_occurrence',\n 'wf_time_entry', 'wf_schedule_template', 'wf_schedule_shift', 'wf_schedule_requirement',\n 'wf_schedule_template_assignment', 'wf_schedule', 'wf_schedule_assignment',\n 'wf_assignment_log']));\n RETURN;\n END IF;\n\n SELECT array_agg(w) INTO v_falta\n FROM unnest(v_meus) AS w\n WHERE strpos(v_def, '''' || w || '''') = 0;\n\n IF v_falta IS NULL THEN RETURN; END IF;\n\n -- Entram na frente do primeiro elemento: a posição não importa para um\n -- \\`= ANY\\`, e ancorar em \\`ARRAY[\\` dispensa conhecer qualquer valor da lista\n -- — que é justamente o que não se pode presumir.\n ALTER TABLE migration.allowlist DROP CONSTRAINT allowlist_writer_check;\n EXECUTE 'ALTER TABLE migration.allowlist ADD CONSTRAINT allowlist_writer_check '\n || replace(v_def, 'ARRAY[',\n 'ARRAY[' || (SELECT string_agg(quote_literal(w) || '::text, ', '')\n FROM unnest(v_falta) AS w));\nEND $$;\n\n-- ── o de-para da pessoa polimórfica ─────────────────────────────────────────\n--\n-- Este helper é a tradução de \\`person_type\\` + \\`person_id\\` para a FK única do V2,\n-- e existe uma vez porque quatro writers precisam dela. O ledger é a única fonte\n-- que sabe o de-para, e ele guarda a TABELA de origem — então 'professional' e\n-- 'employee' resolvem pelo mesmo caminho, e o writer não precisa conhecer\n-- nenhuma das duas.\nCREATE OR REPLACE FUNCTION migration._wf_person(p_tenant uuid, p_meta jsonb)\n RETURNS uuid LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO ''\nAS $$\n SELECT l.target_id\n FROM migration.ledger l\n WHERE l.tenant_id = p_tenant\n AND l.source_table = CASE WHEN (p_meta #>> '{v1,person_type}') = 'professional'\n THEN 'professionals' ELSE 'employees' END\n AND l.source_numeric_id = nullif(p_meta #>> '{v1,person_id}', '')::bigint\n AND l.target_table = 'public.people'\n AND l.status = 'migrated'\n LIMIT 1;\n$$;\n\nCOMMENT ON FUNCTION migration._wf_person(uuid, jsonb) IS\n 'person_type + person_id do V1 → o uuid de public.people. Duas tabelas de cadastro no V1, um cadastro só no V2.';\n\n-- Helper de migração lê o ledger inteiro do tenant: não é função de aplicação.\nREVOKE ALL ON FUNCTION migration._wf_person(uuid, jsonb) FROM PUBLIC, anon, authenticated;\n\n-- ── a batida ────────────────────────────────────────────────────────────────\n--\n-- UMA linha do V1 vira ATÉ QUATRO linhas do V2: a entrada, a saída (quando\n-- existe), e o ajuste de cada uma (quando \\`*_adjusted_at\\` está preenchido). É a\n-- tradução do par-com-colunas-de-ajuste para eventos-com-ajuste-em-linha.\n--\n-- Os ids derivados são determinísticos (md5 do id de origem + o sufixo do papel)\n-- para que reoferecer a mesma linha numa segunda passada ATUALIZE em vez de\n-- duplicar o dia de trabalho de alguém. \\`target_id\\` devolvido é o da ENTRADA:\n-- é a linha do V1 que ela representa.\nCREATE OR REPLACE FUNCTION migration.upsert_wf_time_entry(\n p_tenant uuid, p_id uuid, p_row jsonb, p_args jsonb DEFAULT '{}'::jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $function$\nDECLARE\n v_meta jsonb := coalesce(p_row -> 'metadata', '{}'::jsonb);\n v_person uuid;\n v_unit uuid := (p_row ->> 'unit_id')::uuid;\n v_in timestamptz := (p_row ->> 'checkin_at')::timestamptz;\n v_out timestamptz := (p_row ->> 'checkout_at')::timestamptz;\n v_in_adj timestamptz := (p_row ->> 'checkin_adjusted_at')::timestamptz;\n v_out_adj timestamptz := (p_row ->> 'checkout_adjusted_at')::timestamptz;\n v_work_date date;\n v_out_id uuid;\n v_reason text := coalesce(nullif(btrim(coalesce(p_row ->> 'adjustment_reason', '')), ''),\n 'ajuste importado do V1 sem motivo registrado');\n v_evidence jsonb;\n v_created boolean := false;\n v_standalone boolean := migration._standalone();\nBEGIN\n IF v_standalone THEN PERFORM migration._assert_fence(p_tenant); PERFORM set_config('migration.writer', 'on', true); END IF;\n\n IF p_id IS NULL OR v_in IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'state',\n 'reason', 'uma batida precisa de id e de hora de entrada');\n END IF;\n\n -- Recusar é o certo, e é temporário: a pessoa entra na mesma onda, e a segunda\n -- passada oferece a batida de novo. Inventar a pessoa aqui seria pendurar\n -- horas de trabalho — e portanto dinheiro — em quem não existe.\n v_person := migration._wf_person(p_tenant, v_meta);\n IF v_person IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'fk',\n 'reason', format('batida de %s #%s cuja pessoa ainda não migrou',\n coalesce(v_meta #>> '{v1,person_type}', '<sem tipo>'),\n coalesce(v_meta #>> '{v1,person_id}', '<sem id>')));\n END IF;\n\n -- A jornada é do dia da ENTRADA, sempre — mesmo quando a saída é do dia\n -- seguinte. É a regra que o V1 admite na caixa de ajuste e nunca grava.\n v_work_date := coalesce((p_row ->> 'work_date')::date, v_in::date);\n v_out_id := md5(p_id::text || ':clock_out')::uuid;\n\n -- Todo o conjunto de prova do totem numa chave só. Perder qualquer um destes\n -- campos é perder a defesa de uma batida contestada.\n v_evidence := jsonb_strip_nulls(jsonb_build_object(\n 'photo_path', p_row ->> 'checkin_photo_path',\n 'lat', (p_row ->> 'checkin_lat')::numeric,\n 'lng', (p_row ->> 'checkin_lng')::numeric,\n 'accuracy_m', (p_row ->> 'checkin_accuracy_m')::numeric,\n 'ip', p_row ->> 'checkin_ip',\n 'user_agent', p_row ->> 'checkin_user_agent',\n 'face_score', (p_row ->> 'checkin_face_score')::numeric));\n\n IF NOT EXISTS (SELECT 1 FROM public.plg_workforce_time_entries WHERE id = p_id) THEN\n INSERT INTO public.plg_workforce_time_entries\n (id, tenant_id, unit_id, person_id, person_name, kind, punched_at, work_date, seq,\n origin, evidence, assignment_id, notes, metadata)\n VALUES (p_id, p_tenant, v_unit, v_person, p_row ->> 'person_name', 'clock_in', v_in,\n v_work_date, 1, 'migration', v_evidence,\n (p_row ->> 'assignment_id')::uuid, p_row ->> 'notes', v_meta);\n v_created := true;\n ELSE\n UPDATE public.plg_workforce_time_entries SET\n unit_id = coalesce(v_unit, unit_id),\n person_id = v_person,\n person_name = coalesce(p_row ->> 'person_name', person_name),\n punched_at = v_in,\n work_date = v_work_date,\n evidence = migration._merge_meta(evidence, v_evidence),\n assignment_id = coalesce((p_row ->> 'assignment_id')::uuid, assignment_id),\n notes = CASE WHEN p_row ? 'notes' THEN p_row ->> 'notes' ELSE notes END,\n metadata = migration._merge_meta(metadata, v_meta)\n WHERE id = p_id;\n END IF;\n\n -- A saída só existe quando existe. \\`checkout_at IS NULL\\` é o \"ponto em aberto\"\n -- do V1 — 20 deles no tenant medido — e ele atravessa como ausência de evento,\n -- que é o que ele é. Fabricar uma saída para \"fechar\" o registro inventaria\n -- horas trabalhadas.\n IF v_out IS NOT NULL THEN\n IF NOT EXISTS (SELECT 1 FROM public.plg_workforce_time_entries WHERE id = v_out_id) THEN\n INSERT INTO public.plg_workforce_time_entries\n (id, tenant_id, unit_id, person_id, person_name, kind, punched_at, work_date, seq,\n origin, evidence, assignment_id, metadata)\n VALUES (v_out_id, p_tenant, v_unit, v_person, p_row ->> 'person_name', 'clock_out', v_out,\n v_work_date, 2, 'migration',\n jsonb_strip_nulls(jsonb_build_object(\n 'photo_path', p_row ->> 'checkout_photo_path',\n 'lat', (p_row ->> 'checkout_lat')::numeric,\n 'lng', (p_row ->> 'checkout_lng')::numeric,\n 'accuracy_m', (p_row ->> 'checkout_accuracy_m')::numeric,\n 'ip', p_row ->> 'checkout_ip',\n 'user_agent', p_row ->> 'checkout_user_agent',\n 'face_score', (p_row ->> 'checkout_face_score')::numeric)),\n (p_row ->> 'assignment_id')::uuid,\n migration._deep_set(v_meta, ARRAY['migration', 'derived_from'], to_jsonb(p_id::text)));\n ELSE\n UPDATE public.plg_workforce_time_entries SET\n punched_at = v_out, work_date = v_work_date, person_id = v_person\n WHERE id = v_out_id;\n END IF;\n END IF;\n\n -- O ajuste vira LINHA. No V1 ele é um par de colunas por cima da batida, e o\n -- histórico morre no segundo ajuste; aqui cada correção fica, com autor e\n -- motivo. O motivo é opcional no V1 e obrigatório aqui — quando vem vazio, o\n -- texto diz exatamente isso, em vez de fingir que alguém justificou.\n IF v_in_adj IS NOT NULL THEN\n INSERT INTO public.plg_workforce_time_adjustments\n (id, tenant_id, unit_id, time_entry_id, action, effective_at, reason,\n adjusted_by_user_id, adjusted_by_name, metadata)\n VALUES (md5(p_id::text || ':adjust_in')::uuid, p_tenant, v_unit, p_id, 'correct',\n v_in_adj, v_reason,\n (p_row ->> 'adjusted_by_user_id')::uuid, p_row ->> 'adjusted_by_name',\n migration._deep_set(v_meta, ARRAY['migration', 'from'], to_jsonb('checkin_adjusted_at'::text)))\n ON CONFLICT (id) DO UPDATE\n SET effective_at = EXCLUDED.effective_at, reason = EXCLUDED.reason,\n adjusted_by_name = EXCLUDED.adjusted_by_name, updated_at = now();\n END IF;\n\n IF v_out_adj IS NOT NULL AND v_out IS NOT NULL THEN\n INSERT INTO public.plg_workforce_time_adjustments\n (id, tenant_id, unit_id, time_entry_id, action, effective_at, reason,\n adjusted_by_user_id, adjusted_by_name, metadata)\n VALUES (md5(p_id::text || ':adjust_out')::uuid, p_tenant, v_unit, v_out_id, 'correct',\n v_out_adj, v_reason,\n (p_row ->> 'adjusted_by_user_id')::uuid, p_row ->> 'adjusted_by_name',\n migration._deep_set(v_meta, ARRAY['migration', 'from'], to_jsonb('checkout_adjusted_at'::text)))\n ON CONFLICT (id) DO UPDATE\n SET effective_at = EXCLUDED.effective_at, reason = EXCLUDED.reason,\n adjusted_by_name = EXCLUDED.adjusted_by_name, updated_at = now();\n END IF;\n\n IF v_standalone THEN PERFORM migration._audit(p_tenant, 'public.plg_workforce_time_entries', p_id, '{}'::jsonb); END IF;\n RETURN jsonb_build_object('status', 'migrated', 'target_id', p_id,\n 'reason', CASE WHEN v_created THEN 'created' ELSE 'updated' END,\n 'entries', CASE WHEN v_out IS NULL THEN 1 ELSE 2 END,\n 'open', v_out IS NULL);\nEND $function$;\n\n-- ── o molde ─────────────────────────────────────────────────────────────────\nCREATE OR REPLACE FUNCTION migration.upsert_wf_schedule_template(\n p_tenant uuid, p_id uuid, p_row jsonb, p_args jsonb DEFAULT '{}'::jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $function$\nDECLARE\n v_meta jsonb := coalesce(p_row -> 'metadata', '{}'::jsonb);\n v_name text := nullif(btrim(coalesce(p_row ->> 'name', '')), '');\n v_created boolean := false;\n v_standalone boolean := migration._standalone();\nBEGIN\n IF v_standalone THEN PERFORM migration._assert_fence(p_tenant); PERFORM set_config('migration.writer', 'on', true); END IF;\n IF p_id IS NULL OR v_name IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'state',\n 'reason', 'um template de escala precisa de id e de nome — é por ele que a tela o oferece');\n END IF;\n\n IF NOT EXISTS (SELECT 1 FROM public.plg_workforce_schedule_templates WHERE id = p_id) THEN\n INSERT INTO public.plg_workforce_schedule_templates (id, tenant_id, unit_id, name, is_active, notes, metadata)\n VALUES (p_id, p_tenant, (p_row ->> 'unit_id')::uuid, v_name,\n coalesce((p_row ->> 'is_active')::boolean, true), p_row ->> 'notes', v_meta);\n v_created := true;\n ELSE\n UPDATE public.plg_workforce_schedule_templates SET\n unit_id = CASE WHEN p_row ? 'unit_id' THEN (p_row ->> 'unit_id')::uuid ELSE unit_id END,\n name = v_name,\n is_active = CASE WHEN p_row ? 'is_active' THEN coalesce((p_row ->> 'is_active')::boolean, true) ELSE is_active END,\n notes = CASE WHEN p_row ? 'notes' THEN p_row ->> 'notes' ELSE notes END,\n metadata = migration._merge_meta(metadata, v_meta)\n WHERE id = p_id;\n END IF;\n\n IF v_standalone THEN PERFORM migration._audit(p_tenant, 'public.plg_workforce_schedule_templates', p_id, '{}'::jsonb); END IF;\n RETURN jsonb_build_object('status', 'migrated', 'target_id', p_id,\n 'reason', CASE WHEN v_created THEN 'created' ELSE 'updated' END);\nEND $function$;\n\nCREATE OR REPLACE FUNCTION migration.upsert_wf_schedule_shift(\n p_tenant uuid, p_id uuid, p_row jsonb, p_args jsonb DEFAULT '{}'::jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $function$\nDECLARE\n v_meta jsonb := coalesce(p_row -> 'metadata', '{}'::jsonb);\n v_template uuid := (p_row ->> 'template_id')::uuid;\n v_start time := (p_row ->> 'start_time')::time;\n v_end time := (p_row ->> 'end_time')::time;\n v_days smallint[];\n v_bad smallint[];\n v_unit uuid;\n v_created boolean := false;\n v_standalone boolean := migration._standalone();\nBEGIN\n IF v_standalone THEN PERFORM migration._assert_fence(p_tenant); PERFORM set_config('migration.writer', 'on', true); END IF;\n IF p_id IS NULL OR v_template IS NULL OR v_start IS NULL OR v_end IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'state',\n 'reason', 'um turno precisa de id, do template, de início e de fim');\n END IF;\n SELECT unit_id INTO v_unit FROM public.plg_workforce_schedule_templates\n WHERE id = v_template AND tenant_id = p_tenant;\n IF NOT FOUND THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'fk',\n 'reason', format('o template %s não existe neste tenant', v_template));\n END IF;\n\n -- Sem correção silenciosa nos dias da semana. Um 7 solto (ou um 1..7 em vez de\n -- 0..6) é um turno que nunca acontece, e um turno que nunca acontece é uma\n -- pessoa que ninguém chamou — some sem erro nenhum.\n SELECT coalesce(array_agg(x::smallint ORDER BY x), '{}'::smallint[])\n INTO v_days\n FROM jsonb_array_elements_text(coalesce(p_row -> 'weekdays', '[]'::jsonb)) AS t(x);\n SELECT coalesce(array_agg(d), '{}'::smallint[]) INTO v_bad\n FROM unnest(v_days) AS d WHERE d < 0 OR d > 6;\n IF array_length(v_bad, 1) > 0 THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'value',\n 'reason', format('dia da semana fora de 0..6 (domingo..sábado): %s', v_bad::text));\n END IF;\n\n IF NOT EXISTS (SELECT 1 FROM public.plg_workforce_schedule_shifts WHERE id = p_id) THEN\n INSERT INTO public.plg_workforce_schedule_shifts\n (id, tenant_id, unit_id, template_id, label, start_time, end_time, weekdays, sort_order, metadata)\n VALUES (p_id, p_tenant, v_unit, v_template,\n coalesce(nullif(btrim(coalesce(p_row ->> 'label', '')), ''), 'Turno'),\n v_start, v_end, v_days, coalesce((p_row ->> 'sort_order')::integer, 0), v_meta);\n v_created := true;\n ELSE\n UPDATE public.plg_workforce_schedule_shifts SET\n unit_id = v_unit,\n label = coalesce(nullif(btrim(coalesce(p_row ->> 'label', '')), ''), label),\n start_time = v_start,\n end_time = v_end,\n weekdays = v_days,\n sort_order = CASE WHEN p_row ? 'sort_order' THEN coalesce((p_row ->> 'sort_order')::integer, sort_order) ELSE sort_order END,\n metadata = migration._merge_meta(metadata, v_meta)\n WHERE id = p_id;\n END IF;\n\n IF v_standalone THEN PERFORM migration._audit(p_tenant, 'public.plg_workforce_schedule_shifts', p_id, '{}'::jsonb); END IF;\n RETURN jsonb_build_object('status', 'migrated', 'target_id', p_id,\n 'reason', CASE WHEN v_created THEN 'created' ELSE 'updated' END,\n 'crosses_midnight', v_end <= v_start);\nEND $function$;\n\nCREATE OR REPLACE FUNCTION migration.upsert_wf_schedule_requirement(\n p_tenant uuid, p_id uuid, p_row jsonb, p_args jsonb DEFAULT '{}'::jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $function$\nDECLARE\n v_meta jsonb := coalesce(p_row -> 'metadata', '{}'::jsonb);\n v_shift uuid := (p_row ->> 'shift_id')::uuid;\n v_prof text := nullif(btrim(coalesce(p_row ->> 'profession_name', '')), '');\n v_count integer := coalesce((p_row ->> 'required_count')::integer, 1);\n v_unit uuid;\n v_id uuid;\n v_standalone boolean := migration._standalone();\nBEGIN\n IF v_standalone THEN PERFORM migration._assert_fence(p_tenant); PERFORM set_config('migration.writer', 'on', true); END IF;\n IF p_id IS NULL OR v_shift IS NULL OR v_prof IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'state',\n 'reason', 'uma vaga precisa de id, do turno e do nome da função');\n END IF;\n SELECT unit_id INTO v_unit FROM public.plg_workforce_schedule_shifts\n WHERE id = v_shift AND tenant_id = p_tenant;\n IF NOT FOUND THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'fk',\n 'reason', format('o turno %s não existe neste tenant', v_shift));\n END IF;\n -- Lotação zero ou negativa é vaga que não existe; e a constraint recusaria a\n -- linha inteira mais tarde, sem dizer qual era.\n IF v_count <= 0 THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'value',\n 'reason', format('lotação de %L é %s — uma vaga precisa de pelo menos uma pessoa', v_prof, v_count));\n END IF;\n\n -- Devolve o id da linha que de fato ficou: quando duas vagas do V1 nomeiam a\n -- mesma função no mesmo turno, a segunda funde na primeira, e o ledger tem de\n -- apontar para onde o dado foi parar — não para o id que ela trazia.\n INSERT INTO public.plg_workforce_schedule_requirements\n (id, tenant_id, unit_id, shift_id, profession_name, required_count, metadata)\n VALUES (p_id, p_tenant, v_unit, v_shift, v_prof, v_count, v_meta)\n ON CONFLICT (shift_id, profession_name) DO UPDATE\n SET required_count = EXCLUDED.required_count,\n metadata = migration._merge_meta(public.plg_workforce_schedule_requirements.metadata, EXCLUDED.metadata),\n updated_at = now()\n RETURNING id INTO v_id;\n\n IF v_standalone THEN PERFORM migration._audit(p_tenant, 'public.plg_workforce_schedule_requirements', v_id, '{}'::jsonb); END IF;\n RETURN jsonb_build_object('status', 'migrated', 'target_id', v_id,\n 'reason', CASE WHEN v_id = p_id THEN 'upserted' ELSE 'fundida na vaga que já existia para esta função neste turno' END);\nEND $function$;\n\n-- No molde do V1, titular vs stand-by é POSICIONAL — os primeiros\n-- \\`required_count\\` por \\`priority\\`. Este writer faz essa conta UMA vez, na\n-- entrada, e grava o resultado em \\`role\\`. Deixar a regra implícita no V2 seria\n-- repor um comportamento que só existe no código de uma tela, e que a próxima\n-- tela a ler a mesma tabela erraria em silêncio.\nCREATE OR REPLACE FUNCTION migration.upsert_wf_schedule_template_assignment(\n p_tenant uuid, p_id uuid, p_row jsonb, p_args jsonb DEFAULT '{}'::jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $function$\nDECLARE\n v_meta jsonb := coalesce(p_row -> 'metadata', '{}'::jsonb);\n v_shift uuid := (p_row ->> 'shift_id')::uuid;\n v_prof text := nullif(btrim(coalesce(p_row ->> 'profession_name', '')), '');\n v_priority integer := coalesce((p_row ->> 'priority')::integer, 0);\n v_person uuid;\n v_template uuid;\n v_unit uuid;\n v_required integer;\n v_rank integer;\n v_role text;\n v_standalone boolean := migration._standalone();\nBEGIN\n IF v_standalone THEN PERFORM migration._assert_fence(p_tenant); PERFORM set_config('migration.writer', 'on', true); END IF;\n IF p_id IS NULL OR v_shift IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'state',\n 'reason', 'uma alocação de molde precisa de id e do turno');\n END IF;\n\n -- No molde a pessoa é sempre \\`professionals\\` — o V1 não escala funcionário\n -- pelo template — mas o helper resolve pelo que o metadata disser, e não pelo\n -- que este writer supõe.\n v_person := migration._wf_person(p_tenant,\n CASE WHEN (v_meta #>> '{v1,person_type}') IS NULL\n THEN migration._deep_set(v_meta, ARRAY['v1', 'person_type'], to_jsonb('professional'::text))\n ELSE v_meta END);\n IF v_person IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'fk',\n 'reason', format('alocação de molde cuja pessoa ainda não migrou (%s #%s)',\n coalesce(v_meta #>> '{v1,person_type}', 'professional'),\n coalesce(v_meta #>> '{v1,person_id}', '<sem id>')));\n END IF;\n\n SELECT s.template_id, s.unit_id INTO v_template, v_unit\n FROM public.plg_workforce_schedule_shifts s\n WHERE s.id = v_shift AND s.tenant_id = p_tenant;\n IF NOT FOUND THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'fk',\n 'reason', format('o turno %s não existe neste tenant', v_shift));\n END IF;\n\n INSERT INTO public.plg_workforce_schedule_template_assignments\n (id, tenant_id, unit_id, template_id, shift_id, profession_name, person_id, role, priority, metadata)\n VALUES (p_id, p_tenant, v_unit, v_template, v_shift, coalesce(v_prof, '—'), v_person,\n 'titular', v_priority, v_meta)\n ON CONFLICT (shift_id, profession_name, person_id) DO UPDATE\n SET priority = EXCLUDED.priority,\n metadata = migration._merge_meta(public.plg_workforce_schedule_template_assignments.metadata, EXCLUDED.metadata),\n updated_at = now();\n\n -- A POSIÇÃO vira PAPEL. Recalculada a cada linha porque a ordem muda quando a\n -- próxima chega: a quarta pessoa de uma vaga de três rebaixa ninguém, mas\n -- entra como reserva, e a sétima também.\n SELECT r.required_count INTO v_required\n FROM public.plg_workforce_schedule_requirements r\n WHERE r.shift_id = v_shift AND r.profession_name = coalesce(v_prof, '—');\n\n SELECT rank INTO v_rank FROM (\n SELECT a.id, row_number() OVER (ORDER BY a.priority, a.created_at, a.id) AS rank\n FROM public.plg_workforce_schedule_template_assignments a\n WHERE a.shift_id = v_shift AND a.profession_name = coalesce(v_prof, '—')) s\n WHERE s.id = p_id;\n\n -- Sem vaga declarada não há denominador, e chutar um faria a pessoa virar\n -- titular ou reserva por acaso. \\`titular\\` é o que o V1 mostra nesse caso.\n v_role := CASE WHEN v_required IS NULL THEN 'titular'\n WHEN v_rank <= v_required THEN 'titular'\n ELSE 'standby' END;\n UPDATE public.plg_workforce_schedule_template_assignments SET role = v_role WHERE id = p_id;\n\n IF v_standalone THEN PERFORM migration._audit(p_tenant, 'public.plg_workforce_schedule_template_assignments', p_id, '{}'::jsonb); END IF;\n RETURN jsonb_build_object('status', 'migrated', 'target_id', p_id, 'role', v_role,\n 'reason', format('posição %s de %s vaga(s) → %s', v_rank, coalesce(v_required::text, 'sem lotação declarada'), v_role));\nEND $function$;\n\n-- ── a instância ─────────────────────────────────────────────────────────────\nCREATE OR REPLACE FUNCTION migration.upsert_wf_schedule(\n p_tenant uuid, p_id uuid, p_row jsonb, p_args jsonb DEFAULT '{}'::jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $function$\nDECLARE\n v_meta jsonb := coalesce(p_row -> 'metadata', '{}'::jsonb);\n v_date date := (p_row ->> 'schedule_date')::date;\n v_status_v1 text := nullif(btrim(lower(coalesce(p_row ->> 'status', ''))), '');\n v_status text;\n v_published timestamptz := (p_row ->> 'published_at')::timestamptz;\n v_created boolean := false;\n v_standalone boolean := migration._standalone();\nBEGIN\n IF v_standalone THEN PERFORM migration._assert_fence(p_tenant); PERFORM set_config('migration.writer', 'on', true); END IF;\n IF p_id IS NULL OR v_date IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'state',\n 'reason', 'uma escala precisa de id e do dia a que pertence');\n END IF;\n\n v_status := CASE v_status_v1\n WHEN 'draft' THEN 'draft'\n WHEN 'published' THEN 'published'\n WHEN 'closed' THEN 'closed'\n ELSE NULL END;\n IF v_status IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'value',\n 'reason', format('estado de escala desconhecido: %L (o V2 conhece draft, published e closed)', v_status_v1));\n END IF;\n\n -- Publicada sem carimbo é o rascunho do V1 que alguém marcou como publicado\n -- sem a ação que grava a data. A constraint recusaria; aqui a data de\n -- publicação vira a do próprio dia da escala, e o remendo fica escrito.\n IF v_status <> 'draft' AND v_published IS NULL THEN\n v_published := v_date::timestamptz;\n v_meta := migration._deep_set(v_meta, ARRAY['migration', 'published_at_inferred'], to_jsonb(true));\n END IF;\n\n IF NOT EXISTS (SELECT 1 FROM public.plg_workforce_schedules WHERE id = p_id) THEN\n INSERT INTO public.plg_workforce_schedules\n (id, tenant_id, unit_id, schedule_date, template_id, status, published_at,\n is_special_day, special_day_label, notes, metadata)\n VALUES (p_id, p_tenant, (p_row ->> 'unit_id')::uuid, v_date,\n (p_row ->> 'template_id')::uuid, v_status, v_published,\n coalesce((p_row ->> 'is_special_day')::boolean, false),\n p_row ->> 'special_day_label', p_row ->> 'notes', v_meta);\n v_created := true;\n ELSE\n UPDATE public.plg_workforce_schedules SET\n unit_id = CASE WHEN p_row ? 'unit_id' THEN (p_row ->> 'unit_id')::uuid ELSE unit_id END,\n schedule_date = v_date,\n template_id = CASE WHEN p_row ? 'template_id' THEN (p_row ->> 'template_id')::uuid ELSE template_id END,\n status = v_status,\n published_at = v_published,\n is_special_day = CASE WHEN p_row ? 'is_special_day' THEN coalesce((p_row ->> 'is_special_day')::boolean, false) ELSE is_special_day END,\n special_day_label = CASE WHEN p_row ? 'special_day_label' THEN p_row ->> 'special_day_label' ELSE special_day_label END,\n notes = CASE WHEN p_row ? 'notes' THEN p_row ->> 'notes' ELSE notes END,\n metadata = migration._merge_meta(metadata, v_meta)\n WHERE id = p_id;\n END IF;\n\n IF v_standalone THEN PERFORM migration._audit(p_tenant, 'public.plg_workforce_schedules', p_id, '{}'::jsonb); END IF;\n RETURN jsonb_build_object('status', 'migrated', 'target_id', p_id,\n 'reason', CASE WHEN v_created THEN 'created' ELSE 'updated' END);\nEND $function$;\n\nCREATE OR REPLACE FUNCTION migration.upsert_wf_schedule_assignment(\n p_tenant uuid, p_id uuid, p_row jsonb, p_args jsonb DEFAULT '{}'::jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $function$\nDECLARE\n v_meta jsonb := coalesce(p_row -> 'metadata', '{}'::jsonb);\n v_schedule uuid := (p_row ->> 'schedule_id')::uuid;\n v_role_v1 text := nullif(btrim(lower(coalesce(p_row ->> 'role', ''))), '');\n v_status_v1 text := nullif(btrim(lower(coalesce(p_row ->> 'status', ''))), '');\n v_role text;\n v_status text;\n v_person uuid;\n v_unit uuid;\n v_start time := (p_row ->> 'shift_start_time')::time;\n v_end time := (p_row ->> 'shift_end_time')::time;\n v_created boolean := false;\n v_standalone boolean := migration._standalone();\nBEGIN\n IF v_standalone THEN PERFORM migration._assert_fence(p_tenant); PERFORM set_config('migration.writer', 'on', true); END IF;\n IF p_id IS NULL OR v_schedule IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'state',\n 'reason', 'uma atribuição precisa de id e da escala a que pertence');\n END IF;\n SELECT unit_id INTO v_unit FROM public.plg_workforce_schedules\n WHERE id = v_schedule AND tenant_id = p_tenant;\n IF NOT FOUND THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'fk',\n 'reason', format('a escala %s não existe neste tenant', v_schedule));\n END IF;\n\n v_person := migration._wf_person(p_tenant,\n CASE WHEN (v_meta #>> '{v1,person_type}') IS NULL\n THEN migration._deep_set(v_meta, ARRAY['v1', 'person_type'], to_jsonb('professional'::text))\n ELSE v_meta END);\n IF v_person IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'fk',\n 'reason', format('atribuição de escala cuja pessoa ainda não migrou (%s #%s)',\n coalesce(v_meta #>> '{v1,person_type}', 'professional'),\n coalesce(v_meta #>> '{v1,person_id}', '<sem id>')));\n END IF;\n\n -- Stand-by NÃO é folga: é o substituto acionável, e a própria tela do V1 diz\n -- (\"Substitutos em caso de falta\"). Confundir os dois na tradução apagaria a\n -- fila de quem cobre a falta.\n v_role := CASE v_role_v1\n WHEN 'titular' THEN 'titular'\n WHEN 'standby' THEN 'standby'\n WHEN 'stand_by' THEN 'standby'\n WHEN 'stand-by' THEN 'standby'\n ELSE NULL END;\n IF v_role IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'value',\n 'reason', format('papel na vaga desconhecido: %L (o V2 conhece titular e standby)', v_role_v1));\n END IF;\n\n v_status := CASE v_status_v1\n WHEN 'pending' THEN 'pending'\n WHEN 'notified' THEN 'notified'\n WHEN 'confirmed' THEN 'confirmed'\n WHEN 'declined' THEN 'declined'\n WHEN 'realized' THEN 'realized'\n ELSE NULL END;\n IF v_status IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'value',\n 'reason', format('estado de atribuição desconhecido: %L', v_status_v1));\n END IF;\n\n IF NOT EXISTS (SELECT 1 FROM public.plg_workforce_schedule_assignments WHERE id = p_id) THEN\n INSERT INTO public.plg_workforce_schedule_assignments\n (id, tenant_id, unit_id, schedule_id, shift_id, shift_label, shift_start_time, shift_end_time,\n profession_name, person_id, role, priority, status, response_token, response_channel,\n notified_at, responded_at, metadata)\n VALUES (p_id, p_tenant, v_unit, v_schedule, (p_row ->> 'shift_id')::uuid,\n p_row ->> 'shift_label', v_start, v_end,\n p_row ->> 'profession_name', v_person, v_role,\n coalesce((p_row ->> 'priority')::integer, 0), v_status,\n -- O token do V1 é uma credencial viva de um canal que o V2 ainda não\n -- opera. Ele atravessa para não perder o rastro de quem foi chamado\n -- por link, mas quem emitir o próximo convite emite outro.\n p_row ->> 'response_token', p_row ->> 'response_channel',\n (p_row ->> 'notified_at')::timestamptz, (p_row ->> 'responded_at')::timestamptz,\n v_meta);\n v_created := true;\n ELSE\n UPDATE public.plg_workforce_schedule_assignments SET\n unit_id = v_unit,\n shift_id = CASE WHEN p_row ? 'shift_id' THEN (p_row ->> 'shift_id')::uuid ELSE shift_id END,\n shift_label = CASE WHEN p_row ? 'shift_label' THEN p_row ->> 'shift_label' ELSE shift_label END,\n shift_start_time = coalesce(v_start, shift_start_time),\n shift_end_time = coalesce(v_end, shift_end_time),\n profession_name = CASE WHEN p_row ? 'profession_name' THEN p_row ->> 'profession_name' ELSE profession_name END,\n person_id = v_person,\n role = v_role,\n priority = CASE WHEN p_row ? 'priority' THEN coalesce((p_row ->> 'priority')::integer, priority) ELSE priority END,\n status = v_status,\n response_token = CASE WHEN p_row ? 'response_token' THEN p_row ->> 'response_token' ELSE response_token END,\n response_channel = CASE WHEN p_row ? 'response_channel' THEN p_row ->> 'response_channel' ELSE response_channel END,\n notified_at = CASE WHEN p_row ? 'notified_at' THEN (p_row ->> 'notified_at')::timestamptz ELSE notified_at END,\n responded_at = CASE WHEN p_row ? 'responded_at' THEN (p_row ->> 'responded_at')::timestamptz ELSE responded_at END,\n metadata = migration._merge_meta(metadata, v_meta)\n WHERE id = p_id;\n END IF;\n\n IF v_standalone THEN PERFORM migration._audit(p_tenant, 'public.plg_workforce_schedule_assignments', p_id, '{}'::jsonb); END IF;\n RETURN jsonb_build_object('status', 'migrated', 'target_id', p_id, 'role', v_role,\n 'reason', CASE WHEN v_created THEN 'created' ELSE 'updated' END);\nEND $function$;\n\nCREATE OR REPLACE FUNCTION migration.upsert_wf_assignment_log(\n p_tenant uuid, p_id uuid, p_row jsonb, p_args jsonb DEFAULT '{}'::jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $function$\nDECLARE\n v_meta jsonb := coalesce(p_row -> 'metadata', '{}'::jsonb);\n v_assignment uuid := (p_row ->> 'assignment_id')::uuid;\n v_to text := nullif(btrim(lower(coalesce(p_row ->> 'to_status', ''))), '');\n v_unit uuid;\n v_standalone boolean := migration._standalone();\nBEGIN\n IF v_standalone THEN PERFORM migration._assert_fence(p_tenant); PERFORM set_config('migration.writer', 'on', true); END IF;\n IF p_id IS NULL OR v_assignment IS NULL OR v_to IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'state',\n 'reason', 'uma linha de histórico precisa de id, da atribuição e do estado para o qual foi');\n END IF;\n SELECT unit_id INTO v_unit FROM public.plg_workforce_schedule_assignments\n WHERE id = v_assignment AND tenant_id = p_tenant;\n IF NOT FOUND THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'fk',\n 'reason', format('a atribuição %s não existe neste tenant', v_assignment));\n END IF;\n\n -- O log é histórico: reoferecer a mesma linha é replay, e replay não reescreve\n -- o que já foi registrado.\n IF EXISTS (SELECT 1 FROM public.plg_workforce_assignment_logs WHERE id = p_id) THEN\n RETURN jsonb_build_object('status', 'migrated', 'target_id', p_id,\n 'reason', 'already in the ledger (append-only)');\n END IF;\n\n INSERT INTO public.plg_workforce_assignment_logs\n (id, tenant_id, unit_id, assignment_id, from_status, to_status, channel, note,\n changed_by_user_id, metadata, created_at)\n VALUES (p_id, p_tenant, v_unit, v_assignment,\n nullif(btrim(lower(coalesce(p_row ->> 'from_status', ''))), ''), v_to,\n p_row ->> 'channel', p_row ->> 'note',\n (p_row ->> 'changed_by_user_id')::uuid, v_meta,\n coalesce((p_row ->> 'created_at')::timestamptz, now()));\n\n IF v_standalone THEN PERFORM migration._audit(p_tenant, 'public.plg_workforce_assignment_logs', p_id, '{}'::jsonb); END IF;\n RETURN jsonb_build_object('status', 'migrated', 'target_id', p_id, 'reason', 'created');\nEND $function$;\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 9. O DE-PARA\n-- ═══════════════════════════════════════════════════════════════════════════\n\n-- \\`_allow\\` é o construtor oficial: a allowlist tem gatilho de congelamento, e um\n-- INSERT direto por cima de uma linha \\`frozen\\` seria recusado. São oito\n-- argumentos — (source, target, domain, writer, writer_args, financial[],\n-- columns, notes) — e \\`layer\\` é fixo em 'core-A' lá dentro.\n\n-- A allowlist é CONGELADA (\\`trg_allowlist_frozen\\`): mudança de core-A é\n-- arquivo de migration, não escrita solta — e este é o arquivo. Sem a\n-- escotilha, a PRIMEIRA passada passa (a linha ainda não existia) e a\n-- SEGUNDA falha: é assim que uma migration deixa de ser replay-safe sem\n-- ninguém ver. \\`true\\` no terceiro argumento: vale só nesta transação.\nSELECT set_config('migration.allowlist_unlock', 'on', true);\n\nSELECT migration._allow(\n 'time_clock_entries', 'public.plg_workforce_time_entries', 'workforce',\n 'wf_time_entry', '{}'::jsonb, ARRAY[]::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'unit_id', 'unit_id@companies:app.units',\n -- O par polimórfico. Nenhuma das duas vira coluna: juntas elas viram\n -- \\`person_id\\`, resolvido pelo ledger em migration._wf_person.\n 'person_type', 'jsonb:v1.person_type',\n 'person_id', 'jsonb:v1.person_id',\n 'person_name', 'person_name',\n 'checkin_at', 'checkin_at',\n 'checkout_at', 'checkout_at',\n 'checkin_photo_path', 'checkin_photo_path',\n 'checkin_lat', 'checkin_lat',\n 'checkin_lng', 'checkin_lng',\n 'checkin_accuracy_m', 'checkin_accuracy_m',\n 'checkin_ip', 'checkin_ip',\n 'checkin_user_agent', 'checkin_user_agent',\n 'checkin_face_score', 'checkin_face_score',\n 'checkout_photo_path', 'checkout_photo_path',\n 'checkout_lat', 'checkout_lat',\n 'checkout_lng', 'checkout_lng',\n 'checkout_accuracy_m', 'checkout_accuracy_m',\n 'checkout_ip', 'checkout_ip',\n 'checkout_user_agent', 'checkout_user_agent',\n 'checkout_face_score', 'checkout_face_score',\n 'schedule_assignment_id','assignment_id@schedule_assignments',\n -- O ajuste do V1 não vira coluna: vira LINHA em\n -- plg_workforce_time_adjustments, com autor e motivo.\n 'checkin_adjusted_at', 'checkin_adjusted_at',\n 'checkout_adjusted_at', 'checkout_adjusted_at',\n 'adjustment_reason', 'adjustment_reason',\n 'adjusted_by_user_id', 'adjusted_by_user_id',\n 'adjusted_by_name', 'adjusted_by_name',\n -- Derivadas e não portadas: \\`manually_adjusted\\` é a existência de um ajuste,\n -- \\`adjusted_by\\`/\\`adjusted_at\\` são redundantes com a linha do ajuste, e\n -- \\`outside_schedule\\` é o resultado do cruzamento — que no V1 é \\`true\\` em 325\n -- de 325 registros por um defeito de configuração, e que no V2 é a coluna\n -- \\`outside_schedule\\` da view v_workforce_day, calculada e não guardada.\n 'manually_adjusted', '-',\n 'adjusted_by', '-',\n 'adjusted_at', '-',\n 'outside_schedule', 'jsonb:v1.outside_schedule',\n 'notes', 'notes',\n -- NÃO vira FK: no V1 aponta para a tabela de títulos do V1, cuja contraparte\n -- no V2 não é a mesma coisa (mesma recusa da 046). A referência crua é o que\n -- TRAVA o ajuste da linha migrada — a trigger da seção 4 lê exatamente aqui.\n 'payable_invoice_id', 'jsonb:v1.payable_invoice_id'\n ),\n 'A batida. Uma linha do V1 (par entrada/saída + colunas de ajuste) vira até 4 do V2: dois eventos append-only e duas linhas de ajuste. checkout_at nulo atravessa como ausência de evento — é o ponto em aberto, 20 deles no tenant medido.'\n);\n\nSELECT migration._allow(\n 'schedule_templates', 'public.plg_workforce_schedule_templates', 'workforce',\n 'wf_schedule_template', '{}'::jsonb, ARRAY[]::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'unit_id', 'unit_id@companies:app.units',\n 'name', 'name',\n 'active', 'is_active'\n ),\n 'O molde da escala. Pré-requisito duro: sem template o V1 não deixa criar escala nenhuma.'\n);\n\nSELECT migration._allow(\n 'schedule_template_shifts', 'public.plg_workforce_schedule_shifts', 'workforce',\n 'wf_schedule_shift', '{}'::jsonb, ARRAY[]::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'template_id', 'template_id@schedule_templates',\n 'label', 'label',\n 'start_time', 'start_time',\n 'end_time', 'end_time',\n 'weekdays', 'weekdays',\n 'sort_order', 'sort_order'\n ),\n 'O turno do molde. weekdays é 0..6 (domingo..sábado); qualquer valor fora disso é quarentena, porque um turno que nunca acontece some sem erro.'\n);\n\nSELECT migration._allow(\n 'schedule_template_requirements', 'public.plg_workforce_schedule_requirements', 'workforce',\n 'wf_schedule_requirement', '{}'::jsonb, ARRAY[]::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'shift_id', 'shift_id@schedule_template_shifts',\n 'profession_name', 'profession_name',\n 'required_count', 'required_count'\n ),\n 'A lotação da função no turno — o \"(1/1)\" da tela, e o denominador que transforma posição em titular/stand-by.'\n);\n\nSELECT migration._allow(\n 'schedule_template_assignments', 'public.plg_workforce_schedule_template_assignments', 'workforce',\n 'wf_schedule_template_assignment', '{}'::jsonb, ARRAY[]::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'template_id', 'template_id@schedule_templates',\n 'shift_id', 'shift_id@schedule_template_shifts',\n 'profession_name', 'profession_name',\n 'professional_id', 'jsonb:v1.person_id',\n 'priority', 'priority'\n ),\n 'A alocação do molde. No V1 titular × stand-by é POSICIONAL (os primeiros required_count por priority) e vive só no código da tela; o writer faz a conta uma vez e grava em \\`role\\`.'\n);\n\nSELECT migration._allow(\n 'schedules', 'public.plg_workforce_schedules', 'workforce',\n 'wf_schedule', '{}'::jsonb, ARRAY[]::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'unit_id', 'unit_id@companies:app.units',\n 'schedule_date', 'schedule_date',\n 'template_id', 'template_id@schedule_templates',\n 'status', 'status',\n 'published_at', 'published_at',\n 'is_special_day', 'is_special_day',\n 'special_day_label', 'special_day_label',\n 'notes', 'notes'\n ),\n 'A escala do dia. Homônima da \\`public.schedules\\` do V2, que é OUTRA coisa (a oferta de horário do spine) — é a razão do prefixo plg_workforce_.'\n);\n\nSELECT migration._allow(\n 'schedule_assignments', 'public.plg_workforce_schedule_assignments', 'workforce',\n 'wf_schedule_assignment', '{}'::jsonb, ARRAY[]::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'schedule_id', 'schedule_id@schedules',\n 'shift_id', 'shift_id@schedule_template_shifts',\n -- O SNAPSHOT do V1 atravessa como snapshot. Reconstruí-lo a partir do turno\n -- atual do molde reescreveria a escala de anteontem quando o molde mudasse.\n 'shift_label', 'shift_label',\n 'shift_start_time', 'shift_start_time',\n 'shift_end_time', 'shift_end_time',\n 'profession_name', 'profession_name',\n 'professional_id', 'jsonb:v1.person_id',\n 'role', 'role',\n 'priority', 'priority',\n 'status', 'status',\n 'response_token', 'response_token',\n 'response_channel', 'response_channel',\n 'notified_at', 'notified_at',\n 'responded_at', 'responded_at'\n ),\n 'A atribuição do dia. Stand-by não é folga: é o substituto acionável (\"Substitutos em caso de falta\"), e confundir os dois apagaria a fila de quem cobre a falta.'\n);\n\nSELECT migration._allow(\n 'schedule_assignment_logs', 'public.plg_workforce_assignment_logs', 'workforce',\n 'wf_assignment_log', '{}'::jsonb, ARRAY[]::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'assignment_id', 'assignment_id@schedule_assignments',\n 'from_status', 'from_status',\n 'to_status', 'to_status',\n 'channel', 'channel',\n 'note', 'note',\n 'changed_by_user_id','changed_by_user_id',\n 'created_at', 'created_at'\n ),\n 'O histórico da atribuição: a única parte do modelo de escala do V1 que já nasceu append-only, e que atravessa como é.'\n);\n\n-- As duas que NÃO atravessam, e a razão escrita onde a próxima onda vai\n-- procurar. \"Grid\" aqui é grade de disponibilidade de AGENDAMENTO — quando um\n-- horário pode ser marcado —, não escala de trabalho. Portá-las para dentro do\n-- RH criaria a terceira tabela de horário do cluster e colocaria a agenda dentro\n-- do plugin que o D3 mandou justamente separar dela.\n-- \\`WHERE tenant_id IS NULL\\` no árbitro: a 073 da espinha trocou a PK de\n-- \\`migration.excluded_tables\\` por dois índices únicos PARCIAIS — um global e\n-- um por inquilino —, porque \"não trazer esta tabela\" passou a ser decisão de\n-- cliente e não do cluster. Índice parcial só serve de árbitro de ON CONFLICT\n-- quando o comando repete o mesmo recorte. Esta decisão é global.\nINSERT INTO migration.excluded_tables (source_table, reason) VALUES\n ('schedule_grids',\n 'Apesar do nome, é grade de disponibilidade de AGENDAMENTO (quando um horário pode ser marcado), não escala de trabalho. O destino natural é a agenda (public.schedules, kind working_hours), não o RH.'),\n ('schedule_grid_blocks',\n 'Bloco da grade de agendamento — mesma razão de schedule_grids. Escala de trabalho é plg_workforce_schedule_*.')\nON CONFLICT (source_table) WHERE tenant_id IS NULL DO UPDATE SET reason = EXCLUDED.reason;\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 10. A amarração com o financeiro, quando o financeiro existe\n-- ═══════════════════════════════════════════════════════════════════════════\n--\n-- Hora de trabalho vira dinheiro, e o V2 já tem onde: \\`plg_financial_invoices\\`\n-- para o título, \\`plg_financial_chart_of_accounts\\` e \\`plg_financial_cost_centers\\`\n-- para a classificação. O que a jornada NÃO pode fazer é exigir o financeiro:\n-- o plugin é instalável sozinho, e uma FK inline recusaria o arquivo inteiro num\n-- cluster que não ligou o módulo. Declarar a FK aqui, condicionada ao destino,\n-- é o que dá integridade onde ela é possível sem transformar preferência em\n-- dependência.\n--\n-- Todas ON DELETE SET NULL: apagar um centro de custo não pode apagar a batida\n-- de ninguém. O vínculo some, a hora fica.\nDO $$\nDECLARE\n r record;\nBEGIN\n FOR r IN\n SELECT * FROM (VALUES\n ('plg_workforce_time_entries', 'chart_account_id', 'plg_financial_chart_of_accounts'),\n ('plg_workforce_time_entries', 'cost_center_id', 'plg_financial_cost_centers'),\n ('plg_workforce_time_entries', 'payable_invoice_id', 'plg_financial_invoices'),\n ('plg_workforce_schedule_shifts', 'chart_account_id', 'plg_financial_chart_of_accounts'),\n ('plg_workforce_schedule_shifts', 'cost_center_id', 'plg_financial_cost_centers'),\n ('plg_workforce_periods', 'chart_account_id', 'plg_financial_chart_of_accounts'),\n ('plg_workforce_periods', 'cost_center_id', 'plg_financial_cost_centers'),\n ('plg_workforce_periods', 'payable_invoice_id', 'plg_financial_invoices')\n ) AS t(tbl, col, target)\n LOOP\n CONTINUE WHEN to_regclass('public.' || r.target) IS NULL;\n CONTINUE WHEN EXISTS (SELECT 1 FROM pg_constraint\n WHERE conname = r.tbl || '_' || r.col || '_fkey'\n AND conrelid = ('public.' || r.tbl)::regclass);\n EXECUTE format(\n 'ALTER TABLE public.%I ADD CONSTRAINT %I FOREIGN KEY (%I) REFERENCES public.%I(id) ON DELETE SET NULL',\n r.tbl, r.tbl || '_' || r.col || '_fkey', r.col, r.target);\n END LOOP;\nEND $$;\n\nSELECT set_config('migration.allowlist_unlock', 'off', true);\n`\n\nexport const MIGRATION_001_A_PROVA_DA_BATIDA_TEM_BYTES = `-- ---------------------------------------------------------------------------\n-- 001_a_prova_da_batida_tem_bytes.sql — a foto do ponto atravessa, e não só o\n-- caminho dela.\n--\n-- A 000 escreveu, no comentário de \\`evidence\\`:\n--\n-- \"O que não pode é perder: no V1 são \\`photo_path\\`, \\`lat\\`, \\`lng\\`,\n-- \\`accuracy_m\\`, \\`ip\\`, \\`user_agent\\` e \\`face_score\\`.\"\n--\n-- Sete campos. Seis atravessaram. O sétimo — o único que uma pessoa reconhece —\n-- atravessou como TEXTO: \\`8/2026-07-05/professional-15-1783278419303.jpg\\`,\n-- que é um objeto num bucket PRIVADO de outro projeto Supabase, o do V1.\n--\n-- Medido em 18/09/2026 no tenant Pertinho do Céu: 1.320 das 1.361 batidas têm\n-- esse caminho preenchido, e nenhuma das 1.320 imagens é alcançável daqui. No\n-- dia em que o V1 sair do ar elas deixam de existir em qualquer lugar.\n--\n-- É pior que uma coluna vazia, porque parece cheia. \\`evidence.photo_path\\` diz\n-- que houve captura e sugere que a captura está guardada. A tela de Registros de\n-- Ponto, por isso mesmo, escondia a seção de evidência inteira — o comentário\n-- dela dizia que a evidência estava \"hoje vazia\", o que já não era verdade.\n--\n-- Este arquivo declara para o motor de arquivos da 054 (\\`migration.asset_kinds\\`)\n-- que a foto de batida é uma espécie com bytes para transportar: de que bucket\n-- ela sai, para qual vai, o que falta atravessar, e quem reescreve o ponteiro.\n-- Mover os bytes é do fayz-etl (\\`fayz_etl/blobs.py\\`); a regra é daqui.\n--\n-- Idempotente e replay-safe.\n-- ---------------------------------------------------------------------------\n\n-- ─────────────────────────────────────────────────────────────────────────\n-- §1 O bucket, PRIVADO\n--\n-- Não é escolha de estilo: é biometria facial de um funcionário, com hora e\n-- coordenada ao lado. O V1 já a guarda em bucket privado e serve por URL\n-- assinada de curta duração (edge function \\`time-clock-photo-url\\`), e o V2 não\n-- pode rebaixar isso — um bucket público transformaria \"a cara e o horário de\n-- quem trabalha aqui\" em algo que basta um caminho para ver.\n--\n-- A leitura é por pasta de tenant, o mesmo escopo que o resto da plataforma usa.\n-- Com ele, \\`createSignedUrl\\` do lado do app funciona para quem é do tenant e\n-- falha para quem não é, sem RPC no meio.\n-- ─────────────────────────────────────────────────────────────────────────\n\nINSERT INTO storage.buckets (id, name, public, file_size_limit, allowed_mime_types)\nVALUES ('workforce-punch-photos', 'workforce-punch-photos', false, 5242880,\n ARRAY['image/jpeg', 'image/png', 'image/webp'])\nON CONFLICT (id) DO UPDATE SET\n public = EXCLUDED.public,\n file_size_limit = EXCLUDED.file_size_limit,\n allowed_mime_types = EXCLUDED.allowed_mime_types;\n\nDROP POLICY IF EXISTS plg_workforce_punch_photos_read ON storage.objects;\nDROP POLICY IF EXISTS plg_workforce_punch_photos_insert ON storage.objects;\nDROP POLICY IF EXISTS plg_workforce_punch_photos_update ON storage.objects;\nDROP POLICY IF EXISTS plg_workforce_punch_photos_delete ON storage.objects;\n\n-- Sem \\`anon\\`. A prova de uma jornada não se lê deslogado.\nCREATE POLICY plg_workforce_punch_photos_read ON storage.objects\n FOR SELECT TO authenticated\n USING (\n bucket_id = 'workforce-punch-photos'\n AND (storage.foldername(name))[1] IN (SELECT public.user_tenant_ids()::text)\n );\n\nCREATE POLICY plg_workforce_punch_photos_insert ON storage.objects\n FOR INSERT TO authenticated\n WITH CHECK (\n bucket_id = 'workforce-punch-photos'\n AND (storage.foldername(name))[1] IN (SELECT public.user_tenant_ids()::text)\n );\n\nCREATE POLICY plg_workforce_punch_photos_update ON storage.objects\n FOR UPDATE TO authenticated\n USING (\n bucket_id = 'workforce-punch-photos'\n AND (storage.foldername(name))[1] IN (SELECT public.user_tenant_ids()::text)\n )\n WITH CHECK (\n bucket_id = 'workforce-punch-photos'\n AND (storage.foldername(name))[1] IN (SELECT public.user_tenant_ids()::text)\n );\n\n-- DELETE fica de fora de propósito: apagar a foto de uma batida é apagar prova.\n-- Quem precisar (pedido de exclusão LGPD) passa pelo \\`service_role\\`, que é um\n-- ato deliberado e registrado, não um clique.\n\n-- ─────────────────────────────────────────────────────────────────────────\n-- §2 A espécie\n-- ─────────────────────────────────────────────────────────────────────────\n\nSELECT public.register_kind('document', 'punch_photo', 'workforce', ARRAY['active'], NULL,\n 'A foto que o totem capturou na batida — prova de quem bateu o ponto, junto com GPS e score facial');\n\n-- ─────────────────────────────────────────────────────────────────────────\n-- §3 O que falta, e o ponteiro\n--\n-- Todo o resto deste arquivo depende da 054 do base. Num pool que ainda não a\n-- aplicou, o plugin instala sem o transporte de bytes em vez de recusar a\n-- instalação: o ponto funciona sem foto, e a foto sem o ponto não é nada.\n-- ─────────────────────────────────────────────────────────────────────────\n\nDO $do$\nBEGIN\nIF to_regproc('migration.register_asset_kind(text,text,text,text,text,text)') IS NULL THEN\n RAISE NOTICE 'plugin-workforce 001: migration.register_asset_kind ausente (base < 054); a foto da batida fica sem transporte';\n RETURN;\nEND IF;\n\nCREATE OR REPLACE VIEW migration.v_asset_backlog_punch_photo AS\nSELECT e.tenant_id,\n 'time_entry'::text AS subject_type,\n e.id AS subject_id,\n e.person_id,\n e.evidence ->> 'photo_path' AS source_path,\n -- O bucket do V1 é privado: não há URL para baixar sem chave, e o\n -- transporte usa a chave de serviço da origem.\n NULL::text AS source_url,\n -- Uma foto por batida, nomeada pela batida. O caminho do V1 tem epoch no\n -- nome e não é reconstruível a partir do destino; o do V2 é derivável de\n -- qualquer lado, o que é o que faz o rerun sobrescrever em vez de dobrar.\n e.tenant_id::text || '/' || e.id::text || '.jpg' AS target_path,\n coalesce(e.person_name, 'sem nome') || ' · '\n || to_char(e.punched_at, 'DD/MM/YYYY HH24:MI') AS title\n FROM public.plg_workforce_time_entries e\n -- \\`photo_path\\` é a procedência (o caminho no V1, que fica); \\`photo\\` é o\n -- ponteiro do V2. Ter o primeiro e não o segundo É a definição de \"falta\n -- atravessar\", e escrever o segundo tira a linha desta lista.\n WHERE e.evidence ? 'photo_path'\n AND NOT (e.evidence ? 'photo');\n\nCOMMENT ON VIEW migration.v_asset_backlog_punch_photo IS\n 'Batidas cuja foto ainda só existe no bucket privado do V1 (001). A condição É o ponteiro: escrever evidence.photo apaga a linha desta lista.';\n\nCREATE OR REPLACE FUNCTION migration._point_punch_photo(p_tenant uuid, p_document uuid, p_row jsonb)\nRETURNS void\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = ''\nAS $fn$\nDECLARE v_entry uuid := (p_row ->> 'subject_id')::uuid;\nBEGIN\n IF v_entry IS NULL THEN\n RAISE EXCEPTION '_point_punch_photo: preciso de subject_id (a batida)' USING ERRCODE = '22023';\n END IF;\n -- UPDATE numa tabela append-only: passa porque \\`attach_asset\\` liga\n -- \\`migration.writer\\`, que é a mesma escotilha que o writer da batida usa.\n -- \\`photo_path\\` NÃO é tocado — ele é de onde a imagem veio, e continua sendo.\n UPDATE public.plg_workforce_time_entries\n SET evidence = migration._deep_set(coalesce(evidence, '{}'::jsonb), ARRAY['photo'],\n jsonb_build_object(\n 'bucket', p_row ->> 'bucket',\n 'path', p_row ->> 'target_path',\n 'document_id', p_document)),\n updated_at = now()\n WHERE id = v_entry AND tenant_id = p_tenant;\nEND $fn$;\n\nPERFORM migration.register_asset_kind(\n 'punch_photo', 'time-clock-photos', 'workforce-punch-photos',\n 'v_asset_backlog_punch_photo', 'migration._point_punch_photo',\n 'A foto do totem. Bucket privado nas duas pontas: é biometria facial com hora e coordenada ao lado, e o V1 já a tratava assim.');\nEND $do$;\n`\n\nexport const MIGRATION_002_O_GUARDA_DA_FOTO_OLHAVA_O_NOME_ERRADO = `-- ---------------------------------------------------------------------------\n-- 002_o_guarda_da_foto_olhava_o_nome_errado.sql — o §3 da 001 nunca rodou.\n--\n-- A 001 protege o próprio corpo com um guard, porque tudo nela depois do §2\n-- depende da 054 do base:\n--\n-- IF to_regproc('migration.register_asset_kind(text,text,text,text,text,text)')\n-- IS NULL THEN RETURN; END IF;\n--\n-- **\\`to_regproc\\` recebe um NOME, não uma assinatura.** Com a lista de tipos\n-- entre parênteses ela devolve NULL — e não levanta erro, que é exatamente o que\n-- torna isso invisível: \\`to_regproc\\` foi feita para responder \"não existe\" em vez\n-- de estourar. Quem lê a linha lê uma checagem; o Postgres lê uma pergunta\n-- malformada e responde \"não existe\" às duas.\n--\n-- Resultado medido no cluster em 19/09/2026, logo depois de aplicar a 001: o\n-- bucket \\`workforce-punch-photos\\` existe (§1, fora do bloco), a espécie\n-- \\`punch_photo\\` está registrada (§2, fora do bloco), e do §3 não existe NADA —\n-- nem a view de backlog, nem \\`_point_punch_photo\\`, nem a linha em\n-- \\`migration.asset_kinds\\`. A migration \"passou\". A foto continuou sem\n-- transporte, e o \\`mig-assets\\` teria relatado só os 63 avatares como se fosse o\n-- backlog inteiro.\n--\n-- Quem quer assinatura é \\`to_regprocedure\\`. É a única diferença deste arquivo.\n--\n-- ── Por que um arquivo novo, e não uma correção na 001 ─────────────────────\n--\n-- A 001 já está no ledger deste cluster. \\`fayz db apply\\` trata checksum\n-- diferente num arquivo aplicado como PARADA — e está certo: um app que já rodou\n-- a 001 não pode descobrir que os bytes dela mudaram. Corrigir para frente custa\n-- este arquivo; editar a 001 custaria o apply de todo app que já a tomou.\n--\n-- Idempotente e replay-safe.\n-- ---------------------------------------------------------------------------\n\nDO $do$\nBEGIN\n-- \\`to_regprocedure\\`, que é quem entende \\`(text,text,…)\\`. A mesma armadilha está\n-- na 152 do base (\\`to_regproc('app.scaffold_table(text,text,text,boolean,text)')\\`),\n-- e é por isso que a checagem aqui é pelo NOME quando basta o nome: um guard que\n-- mente é pior que nenhum guard, porque o arquivo sai dizendo que aplicou.\nIF to_regprocedure('migration.register_asset_kind(text,text,text,text,text,text)') IS NULL THEN\n RAISE NOTICE 'plugin-workforce 002: migration.register_asset_kind ausente (base < 054); a foto da batida fica sem transporte';\n RETURN;\nEND IF;\n\nCREATE OR REPLACE VIEW migration.v_asset_backlog_punch_photo AS\nSELECT e.tenant_id,\n 'time_entry'::text AS subject_type,\n e.id AS subject_id,\n e.person_id,\n e.evidence ->> 'photo_path' AS source_path,\n -- O bucket do V1 é privado: não há URL para baixar sem chave, e o\n -- transporte usa a chave de serviço da origem.\n NULL::text AS source_url,\n -- Uma foto por batida, nomeada pela batida. O caminho do V1 tem epoch no\n -- nome e não é reconstruível a partir do destino; o do V2 é derivável de\n -- qualquer lado, o que é o que faz o rerun sobrescrever em vez de dobrar.\n e.tenant_id::text || '/' || e.id::text || '.jpg' AS target_path,\n coalesce(e.person_name, 'sem nome') || ' · '\n || to_char(e.punched_at, 'DD/MM/YYYY HH24:MI') AS title\n FROM public.plg_workforce_time_entries e\n -- \\`photo_path\\` é a procedência (o caminho no V1, que fica); \\`photo\\` é o\n -- ponteiro do V2. Ter o primeiro e não o segundo É a definição de \"falta\n -- atravessar\", e escrever o segundo tira a linha desta lista.\n WHERE e.evidence ? 'photo_path'\n AND NOT (e.evidence ? 'photo');\n\nCOMMENT ON VIEW migration.v_asset_backlog_punch_photo IS\n 'Batidas cuja foto ainda só existe no bucket privado do V1 (001/002). A condição É o ponteiro: escrever evidence.photo apaga a linha desta lista.';\n\nCREATE OR REPLACE FUNCTION migration._point_punch_photo(p_tenant uuid, p_document uuid, p_row jsonb)\nRETURNS void\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = ''\nAS $fn$\nDECLARE v_entry uuid := (p_row ->> 'subject_id')::uuid;\nBEGIN\n IF v_entry IS NULL THEN\n RAISE EXCEPTION '_point_punch_photo: preciso de subject_id (a batida)' USING ERRCODE = '22023';\n END IF;\n -- UPDATE numa tabela append-only: passa porque \\`attach_asset\\` liga\n -- \\`migration.writer\\`, que é a mesma escotilha que o writer da batida usa.\n -- \\`photo_path\\` NÃO é tocado — ele é de onde a imagem veio, e continua sendo.\n UPDATE public.plg_workforce_time_entries\n SET evidence = migration._deep_set(coalesce(evidence, '{}'::jsonb), ARRAY['photo'],\n jsonb_build_object(\n 'bucket', p_row ->> 'bucket',\n 'path', p_row ->> 'target_path',\n 'document_id', p_document)),\n updated_at = now()\n WHERE id = v_entry AND tenant_id = p_tenant;\nEND $fn$;\n\nPERFORM migration.register_asset_kind(\n 'punch_photo', 'time-clock-photos', 'workforce-punch-photos',\n 'v_asset_backlog_punch_photo', 'migration._point_punch_photo',\n 'A foto do totem. Bucket privado nas duas pontas: é biometria facial com hora e coordenada ao lado, e o V1 já a tratava assim.');\nEND $do$;\n`\n\nexport const MIGRATION_003_O_PONTO_EM_ABERTO_PARA_DE_MENTIR_A_DURACAO = `-- ---------------------------------------------------------------------------\n-- 003_o_ponto_em_aberto_para_de_mentir_a_duracao.sql — \\`-497155h02\\`.\n--\n-- A tela de Registros de Ponto mostra isso na coluna Duração de todo ponto em\n-- aberto. Medido em 19/09/2026 no tenant Pertinho do Céu: **19 dias negativos,\n-- e os 19 estão abertos** — nenhum dia fechado dá negativo. O número não é\n-- aleatório e não é overflow.\n--\n-- ── De onde ele sai ────────────────────────────────────────────────────────\n--\n-- A 000 soma as horas com sinal, e o desenho é bom: \\`clock_out\\` e \\`break_start\\`\n-- FECHAM um trecho e entram positivos, \\`clock_in\\` e \\`break_end\\` ABREM e entram\n-- negativos. Quantos intervalos o dia tiver, a conta é a mesma — é isso que o\n-- par único do V1 não consegue fazer.\n--\n-- Ela só assume uma coisa que o dia em aberto não cumpre: que toda abertura tem\n-- o seu fechamento. Um dia com uma batida só —\n--\n-- clock_in 18:09\n--\n-- — soma \\`-extract(epoch FROM '2026-09-18 18:09')\\`, que é −1.789.790. segundos\n-- desde 1970. Dividido por 60 vira −29.829.302 minutos, e o formatador de horas\n-- faz o resto: \\`-497155h02\\`. O epoch vazou para a tela.\n--\n-- ── O conserto da conta ────────────────────────────────────────────────────\n--\n-- Devolver à soma a abertura que ficou sem par. O que sobra é exatamente a\n-- soma dos trechos FECHADOS, que é a única coisa que se pode afirmar de um dia\n-- que ainda não terminou:\n--\n-- entrada 09:00, saída 12:00, entrada 13:00 → 3h00 fechadas, aberto desde 13:00\n-- entrada 18:09 → 0h00 fechadas, aberto desde 18:09\n--\n-- Zero não é um defeito aqui: é a resposta certa para \"quanto já fechou?\" antes\n-- de qualquer fechamento. O que faltava para a tela era a OUTRA metade da\n-- pergunta, e é a coluna nova.\n--\n-- ── \\`open_since\\`, e por que uma coluna e não uma conta na tela ─────────────\n--\n-- Quem confere ponto quer saber há quanto tempo a pessoa está dentro. A tela\n-- não consegue descobrir isso sozinha: ela recebe o dia agregado, não as\n-- batidas, e \"a última abertura sem par\" é justamente o que a agregação sabe e\n-- ela não. Sem a coluna, a alternativa seria a tela buscar as batidas de cada\n-- linha — 299 consultas para desenhar uma tabela.\n--\n-- O relógio corre do lado de quem olha, não do banco: a coluna é o INSTANTE, e\n-- o \"6h58 em curso\" é calculado no render. Um intervalo calculado aqui\n-- envelheceria entre a consulta e a pintura, e envelheceria de novo a cada\n-- segundo que a aba ficasse aberta.\n--\n-- ── O que NÃO muda ────────────────────────────────────────────────────────\n--\n-- Dia em aberto continua **fora** do total do dia e do período. A regra é a do\n-- V1 e está certa: contar uma jornada que não terminou inventa hora que ninguém\n-- trabalhou. O que muda é que agora o número que ele não soma também não é\n-- absurdo quando alguém olha a linha.\n--\n-- Idempotente e replay-safe.\n-- ---------------------------------------------------------------------------\n\nCREATE OR REPLACE VIEW public.v_workforce_day\nWITH (security_invoker = 'true') AS\nWITH bruto AS (\n SELECT e.tenant_id,\n e.unit_id,\n e.person_id,\n e.work_date,\n min(e.effective_at) FILTER (WHERE e.kind = 'clock_in') AS first_in,\n max(e.effective_at) FILTER (WHERE e.kind = 'clock_out') AS last_out,\n count(*) FILTER (WHERE e.kind = 'break_start') AS break_count,\n count(*) FILTER (WHERE e.kind IN ('clock_in', 'break_end')) AS aberturas,\n count(*) FILTER (WHERE e.kind IN ('clock_out', 'break_start')) AS fechamentos,\n -- A última ABERTURA do dia. Quando as contagens não batem, é ela que\n -- ficou sem par — os eventos de um dia chegam em ordem, e uma abertura\n -- anterior já teria sido fechada pela seguinte.\n max(e.effective_at) FILTER (WHERE e.kind IN ('clock_in', 'break_end')) AS ultima_abertura,\n sum(CASE\n WHEN e.kind IN ('clock_out', 'break_start') THEN extract(epoch FROM e.effective_at)\n WHEN e.kind IN ('clock_in', 'break_end') THEN -extract(epoch FROM e.effective_at)\n END) AS soma_com_sinal\n FROM public.v_workforce_time_entries e\n WHERE NOT e.voided\n GROUP BY e.tenant_id, e.unit_id, e.person_id, e.work_date\n),\nrealized AS (\n SELECT b.tenant_id,\n b.unit_id,\n b.person_id,\n b.work_date,\n b.first_in,\n b.last_out,\n b.break_count,\n (b.aberturas <> b.fechamentos) AS is_open,\n CASE WHEN b.aberturas <> b.fechamentos THEN b.ultima_abertura END AS open_since,\n -- Devolve à soma a abertura sem par. Sem isto o que sobra é o epoch\n -- dela, com sinal trocado, e foi o que a tela vinha mostrando.\n (b.soma_com_sinal\n + CASE WHEN b.aberturas <> b.fechamentos\n THEN extract(epoch FROM b.ultima_abertura)\n ELSE 0 END) AS worked_seconds\n FROM bruto b\n),\nplanned AS (\n SELECT a.tenant_id,\n a.unit_id,\n a.person_id,\n s.schedule_date AS work_date,\n a.id AS assignment_id,\n a.role,\n a.status AS assignment_status,\n a.shift_label,\n a.shift_start_time,\n a.shift_end_time,\n -- O turno que vira o dia é normal aqui; sem o +24h a jornada da noite\n -- daria negativa.\n (extract(epoch FROM a.shift_end_time - a.shift_start_time)\n + CASE WHEN a.shift_end_time <= a.shift_start_time THEN 86400 ELSE 0 END) AS planned_seconds\n FROM public.plg_workforce_schedule_assignments a\n JOIN public.plg_workforce_schedules s ON s.id = a.schedule_id\n WHERE s.status IN ('published', 'closed')\n AND a.role = 'titular'\n AND a.shift_start_time IS NOT NULL\n AND a.shift_end_time IS NOT NULL\n)\nSELECT coalesce(p.tenant_id, r.tenant_id) AS tenant_id,\n coalesce(p.unit_id, r.unit_id) AS unit_id,\n coalesce(p.person_id, r.person_id) AS person_id,\n coalesce(p.work_date, r.work_date) AS work_date,\n p.assignment_id,\n p.shift_label,\n p.shift_start_time,\n p.shift_end_time,\n p.assignment_status,\n (p.planned_seconds / 60)::integer AS planned_minutes,\n (r.worked_seconds / 60)::integer AS worked_minutes,\n ((r.worked_seconds - p.planned_seconds) / 60)::integer AS variance_minutes,\n r.first_in,\n r.last_out,\n r.break_count,\n coalesce(r.is_open, false) AS is_open,\n (r.person_id IS NULL) AS absent,\n (p.assignment_id IS NULL) AS outside_schedule,\n -- Coluna nova, no fim: \\`CREATE OR REPLACE VIEW\\` só aceita acrescentar\n -- aqui, e é de propósito — quem lê por posição não se move.\n r.open_since\n FROM planned p\n FULL OUTER JOIN realized r\n ON r.tenant_id = p.tenant_id\n AND r.person_id = p.person_id\n AND r.work_date = p.work_date;\n\nCOMMENT ON VIEW public.v_workforce_day IS\n 'Jornada prevista × realizada por pessoa e dia. Previsto vem da escala publicada, realizado das batidas com ajuste aplicado. FULL OUTER JOIN: \\`absent\\` é escala sem ponto, \\`outside_schedule\\` é ponto sem escala. \\`worked_minutes\\` conta só os trechos FECHADOS; \\`open_since\\` é a abertura que ainda não tem par (003).';\n\nCOMMENT ON COLUMN public.v_workforce_day.open_since IS\n 'O instante da abertura sem par, quando o ponto está aberto (003). É o INSTANTE e não a duração: o relógio corre do lado de quem olha a tela, e um intervalo calculado aqui envelheceria entre a consulta e a pintura.';\n\nGRANT SELECT ON public.v_workforce_day TO authenticated, service_role;\n`\n\nexport const MIGRATION_004_A_JORNADA_IMPLAUSIVEL_NAO_SOMA = `-- ---------------------------------------------------------------------------\n-- 004_a_jornada_implausivel_nao_soma.sql — 45h45 num dia.\n--\n-- Medido em 19/09/2026 no tenant Pertinho do Céu, na tela de Registros de Ponto:\n--\n-- Steffany Fidelis da Costa 15:41 → 13:26 45h45\n-- CRISTIANE CARDOSO OLIVEIRA 17:14 → 09:23 16h10\n-- jannyne gomes dos santos 09:07 → 08:58 15h56\n--\n-- e o cabeçalho do dia somando **109h45** para oito pessoas.\n--\n-- Nenhum desses é erro de conta: a 003 já consertou a soma, e esses dias estão\n-- FECHADOS. Eles são a medição correta de um par errado — alguém entrou, foi\n-- embora sem bater a saída, e a saída caiu horas ou dias depois. O V1 grava\n-- \\`checkin_at\\` e \\`checkout_at\\` como um par só, então o buraco atravessou inteiro.\n--\n-- ── Por que não um teto de 8h ──────────────────────────────────────────────\n--\n-- Trocar 45h45 por 8h faria o total parecer certo. É o pior resultado possível:\n--\n-- · 8h ali é um número que ninguém trabalhou e ninguém digitou — é a regra\n-- \"nada de default inventado\" quebrada no lugar onde ela mais custa, que é\n-- base de cálculo de folha;\n-- · e o dia deixaria de parecer estranho, então a batida furada nunca seria\n-- corrigida. O erro sai da tela e fica no dado, que é o contrário de\n-- resolver.\n--\n-- ── O que esta migration faz ───────────────────────────────────────────────\n--\n-- Estende a regra que a tela JÁ tem. Ponto em aberto não soma, porque contar\n-- uma jornada que não terminou inventa hora. Um dia de 45h é o mesmo problema\n-- com outra cara — um par em que não se pode confiar —, então ele também não\n-- soma. O valor medido continua à vista, inteiro, com o motivo escrito ao lado.\n--\n-- \\`review_reason\\` nomeia por que o dia não entra na conta:\n--\n-- 'open' ainda não terminou\n-- 'span_too_long' fechou, e fechou com duração que não é uma jornada\n--\n-- NULL é o dia que conta. Uma coluna só, e quem soma filtra por ela — em vez de\n-- cada relatório redescobrir a regra e descobrir diferente.\n--\n-- ── O limite, e por que dezesseis horas ───────────────────────────────────\n--\n-- A jornada mais longa do vocabulário do V1 é a escala 12x36: doze horas. Com\n-- duas de extra, quatorze. Dezesseis deixa margem para o turno que vira a noite\n-- e ainda separa com folga o caso real, que não é uma jornada comprida e sim\n-- uma saída que ficou pendurada — os três medidos acima têm 16h, 16h e 46h.\n--\n-- É o MESMO dezesseis que a tela usa para dizer \"sem saída há 31h\" num ponto\n-- aberto, e é de propósito: um número, uma justificativa, os dois lados da\n-- mesma pergunta.\n--\n-- Idempotente e replay-safe.\n-- ---------------------------------------------------------------------------\n\nCREATE OR REPLACE FUNCTION public.workforce_max_shift_minutes()\nRETURNS integer LANGUAGE sql IMMUTABLE PARALLEL SAFE\nAS $$ SELECT 16 * 60 $$;\n\nCOMMENT ON FUNCTION public.workforce_max_shift_minutes() IS\n 'Acima disto uma jornada fechada deixa de ser jornada e vira saída não batida (004). 12x36 é a mais longa do vocabulário do V1; dezesseis dá margem ao turno que vira a noite. Função e não constante literal para que a tela, a view e um relatório futuro citem o mesmo número.';\n\nCREATE OR REPLACE VIEW public.v_workforce_day\nWITH (security_invoker = 'true') AS\nWITH bruto AS (\n SELECT e.tenant_id,\n e.unit_id,\n e.person_id,\n e.work_date,\n min(e.effective_at) FILTER (WHERE e.kind = 'clock_in') AS first_in,\n max(e.effective_at) FILTER (WHERE e.kind = 'clock_out') AS last_out,\n count(*) FILTER (WHERE e.kind = 'break_start') AS break_count,\n count(*) FILTER (WHERE e.kind IN ('clock_in', 'break_end')) AS aberturas,\n count(*) FILTER (WHERE e.kind IN ('clock_out', 'break_start')) AS fechamentos,\n -- A última ABERTURA do dia. Quando as contagens não batem, é ela que\n -- ficou sem par — os eventos de um dia chegam em ordem, e uma abertura\n -- anterior já teria sido fechada pela seguinte.\n max(e.effective_at) FILTER (WHERE e.kind IN ('clock_in', 'break_end')) AS ultima_abertura,\n sum(CASE\n WHEN e.kind IN ('clock_out', 'break_start') THEN extract(epoch FROM e.effective_at)\n WHEN e.kind IN ('clock_in', 'break_end') THEN -extract(epoch FROM e.effective_at)\n END) AS soma_com_sinal\n FROM public.v_workforce_time_entries e\n WHERE NOT e.voided\n GROUP BY e.tenant_id, e.unit_id, e.person_id, e.work_date\n),\nrealized AS (\n SELECT b.tenant_id,\n b.unit_id,\n b.person_id,\n b.work_date,\n b.first_in,\n b.last_out,\n b.break_count,\n (b.aberturas <> b.fechamentos) AS is_open,\n CASE WHEN b.aberturas <> b.fechamentos THEN b.ultima_abertura END AS open_since,\n -- Devolve à soma a abertura sem par (003). Sem isto o que sobra é o\n -- epoch dela, com sinal trocado.\n (b.soma_com_sinal\n + CASE WHEN b.aberturas <> b.fechamentos\n THEN extract(epoch FROM b.ultima_abertura)\n ELSE 0 END) AS worked_seconds\n FROM bruto b\n),\nplanned AS (\n SELECT a.tenant_id,\n a.unit_id,\n a.person_id,\n s.schedule_date AS work_date,\n a.id AS assignment_id,\n a.role,\n a.status AS assignment_status,\n a.shift_label,\n a.shift_start_time,\n a.shift_end_time,\n -- O turno que vira o dia é normal aqui; sem o +24h a jornada da noite\n -- daria negativa.\n (extract(epoch FROM a.shift_end_time - a.shift_start_time)\n + CASE WHEN a.shift_end_time <= a.shift_start_time THEN 86400 ELSE 0 END) AS planned_seconds\n FROM public.plg_workforce_schedule_assignments a\n JOIN public.plg_workforce_schedules s ON s.id = a.schedule_id\n WHERE s.status IN ('published', 'closed')\n AND a.role = 'titular'\n AND a.shift_start_time IS NOT NULL\n AND a.shift_end_time IS NOT NULL\n)\nSELECT coalesce(p.tenant_id, r.tenant_id) AS tenant_id,\n coalesce(p.unit_id, r.unit_id) AS unit_id,\n coalesce(p.person_id, r.person_id) AS person_id,\n coalesce(p.work_date, r.work_date) AS work_date,\n p.assignment_id,\n p.shift_label,\n p.shift_start_time,\n p.shift_end_time,\n p.assignment_status,\n (p.planned_seconds / 60)::integer AS planned_minutes,\n -- O MEDIDO, sempre. Não é aqui que se decide se ele conta — a coluna\n -- mente se for corrigida, e um número corrigido em silêncio é pior que\n -- um número estranho.\n (r.worked_seconds / 60)::integer AS worked_minutes,\n ((r.worked_seconds - p.planned_seconds) / 60)::integer AS variance_minutes,\n r.first_in,\n r.last_out,\n r.break_count,\n coalesce(r.is_open, false) AS is_open,\n (r.person_id IS NULL) AS absent,\n (p.assignment_id IS NULL) AS outside_schedule,\n r.open_since,\n -- Por que este dia não entra na soma. NULL = entra.\n CASE\n WHEN r.person_id IS NULL THEN NULL -- escala sem ponto: não há o que somar\n WHEN r.is_open THEN 'open'\n WHEN (r.worked_seconds / 60) > public.workforce_max_shift_minutes()\n THEN 'span_too_long'\n END AS review_reason\n FROM planned p\n FULL OUTER JOIN realized r\n ON r.tenant_id = p.tenant_id\n AND r.person_id = p.person_id\n AND r.work_date = p.work_date;\n\nCOMMENT ON VIEW public.v_workforce_day IS\n 'Jornada prevista × realizada por pessoa e dia. \\`worked_minutes\\` é sempre o MEDIDO; \\`review_reason\\` diz por que um dia não entra na soma — \\`open\\` (não terminou) ou \\`span_too_long\\` (fechou com duração que não é jornada, 004). Quem soma filtra por ela.';\n\nCOMMENT ON COLUMN public.v_workforce_day.review_reason IS\n 'NULL = o dia conta. \\`open\\` = ponto em aberto. \\`span_too_long\\` = acima de workforce_max_shift_minutes(), que na prática é saída não batida e não jornada longa (004).';\n\nGRANT SELECT ON public.v_workforce_day TO authenticated, service_role;\n`\n\nexport const MIGRATION_005_A_FICHA_TRABALHISTA_TEM_ONDE_MORAR = `-- ---------------------------------------------------------------------------\n-- 005_a_ficha_trabalhista_tem_onde_morar.sql — o RH do V1 ganha destino.\n--\n-- Escrito a partir de \\`~/dev/beautyplace/docs/v1-guide/rh\\`, que documenta o\n-- módulo do V1 andando nele: a Visão Geral (oito cartões, três listas) e a Ficha\n-- de RH da pessoa (dezesseis vistas). O FLOW de cada um diz \\`v2: status:\n-- missing\\` — e dizia certo: não havia nada disso aqui.\n--\n-- ── O que este arquivo NÃO traz, e por quê ────────────────────────────────\n--\n-- Não são as dezesseis vistas. Medido na origem em 19/09/2026, nas 886 pessoas\n-- dos três tenants em porte:\n--\n-- as 12 tabelas de lista da Ficha 0 linhas — no V1 INTEIRO, não só\n-- (férias, faltas, advertências, nesses tenants\n-- treinamentos, avaliações, exames,\n-- EPIs, pendências, dependentes,\n-- histórico salarial, 13º, benefícios)\n-- admission_date, dismissal_date, 0 preenchidos\n-- job_title, pis_pasep, CTPS, eSocial\n-- base_salary 25 de 422\n-- contract_type 2\n--\n-- O próprio FLOW da Visão Geral avisa: *\"Num tenant recém-migrado ele mostra\n-- headcount cheio e todo o resto zerado — e isso não é defeito, é ficha vazia.\"*\n-- Aqui TODO tenant é assim. Desenhar dezesseis vistas para portar zero linha\n-- seria construir um formulário de cada vez que alguém leu um FLOW.\n--\n-- Então vem o núcleo que sustenta o conceito e já é útil no primeiro dia:\n--\n-- employment o vínculo — é dele que saem headcount, admissões,\n-- demissões, turnover e experiência vencendo. Sem ele\n-- nenhum número de RH existe, e é a vista 1 do V1\n-- vacations férias. Obrigação legal, recorrente, e a única lista do\n-- V1 que alimenta um cartão\n-- absences faltas e afastamentos\n-- pending_items pendências — a outra lista que aparece no painel\n--\n-- As outras doze entram quando alguém for usá-las. O que elas precisam já está\n-- de pé: a forma da tabela, o escopo, a permissão e a view do painel.\n--\n-- ── A permissão, que o FLOW manda resolver ANTES ──────────────────────────\n--\n-- V1-069: no V1 **não há permissão separada para RH**. Quem edita cadastro vê\n-- salário, CPF, dependentes e CID de atestado. O FLOW da Ficha fecha dizendo que\n-- portar só vale \"desde que a questão da permissão separada seja resolvida\n-- antes\" — então ela é resolvida aqui, e não depois.\n--\n-- \\`workforce_hr.*\\` é uma família própria: quem tem \\`workforce.read\\` vê escala e\n-- ponto e NÃO vê salário. São duas perguntas diferentes e agora têm duas\n-- respostas.\n--\n-- ── O que o V2 faz e o V1 não ────────────────────────────────────────────\n--\n-- O FLOW da vista 10 registra, como defeito: *\"Não conversa com o ponto\n-- eletrônico nem com a escala: uma falta lançada aqui não aparece lá.\"* No V1\n-- são dois sistemas sobre a mesma pessoa que não se olham — alguém de atestado\n-- aparece como FALTA na folha de ponto, e quem confere precisa lembrar de cabeça.\n--\n-- A §7 conserta: \\`v_workforce_day\\` passa a saber do afastamento. Um dia coberto\n-- por atestado deixa de ser \"Falta\" e passa a dizer o que foi. É a razão de o RH\n-- morar no mesmo plugin do ponto, e não ao lado dele.\n--\n-- Idempotente e replay-safe.\n-- ---------------------------------------------------------------------------\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 1. A PERMISSÃO SEPARADA (V1-069)\n-- ═══════════════════════════════════════════════════════════════════════════\n\nINSERT INTO app.permissions (key, plugin, description) VALUES\n ('workforce_hr.read', 'workforce_hr', 'Ver a ficha trabalhista: vínculo, salário, férias, afastamentos e pendências.'),\n ('workforce_hr.create', 'workforce_hr', 'Lançar na ficha trabalhista.'),\n ('workforce_hr.edit', 'workforce_hr', 'Corrigir lançamento da ficha trabalhista.'),\n ('workforce_hr.delete', 'workforce_hr', 'Excluir lançamento da ficha trabalhista.')\nON CONFLICT (key) DO UPDATE SET plugin = EXCLUDED.plugin, description = EXCLUDED.description;\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 2. O VÍNCULO\n-- ═══════════════════════════════════════════════════════════════════════════\n--\n-- Uma linha por pessoa, e não colunas em \\`public.people\\`. Três razões, e a\n-- terceira é a que decide:\n--\n-- · \\`people\\` é do core e atende cliente, fornecedor e profissional; quarenta\n-- colunas de CLT ali seriam nulas para a esmagadora maioria das linhas;\n-- · o V1 tem DUAS tabelas (professionals, employees) com os mesmos campos, e\n-- o V2 tem uma pessoa só — a separação é papel, não cadastro;\n-- · e é a tabela que carrega o salário. Ela precisa de uma policy PRÓPRIA,\n-- e uma coluna não tem policy: RLS é por tabela. Guardar salário em\n-- \\`people\\` seria reproduzir o V1-069 no schema.\n\nCREATE TABLE IF NOT EXISTS public.plg_workforce_employment (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n unit_id uuid,\n person_id uuid NOT NULL REFERENCES public.people(id) ON DELETE CASCADE,\n\n -- ── vínculo (vista 1 do V1: Contrato) ────────────────────────────────────\n -- Vocabulário exato do FLOW. Lista fechada porque é ela que decide encargo, e\n -- \"CLT \" com espaço vira um tipo de contrato novo em silêncio.\n contract_kind text CHECK (contract_kind IN\n ('clt', 'pj', 'estagio', 'jovem_aprendiz', 'autonomo', 'socio', 'temporario', 'intermitente')),\n admission_date date,\n dismissal_date date,\n dismissal_reason text,\n -- O V1 tem os dois: o fim da PRIMEIRA experiência e o fim FINAL. É o segundo\n -- que alimenta o cartão \"Experiência vencendo\".\n probation_first_end date,\n probation_final_end date,\n job_title text,\n department text,\n schedule_regime text CHECK (schedule_regime IN\n ('mensalista', 'horista', 'diarista', 'escala_12x36', 'escala_6x1', 'escala_5x2')),\n weekly_hours numeric(5,2),\n monthly_hours numeric(6,2),\n esocial_registration text,\n\n -- ── remuneração (vista 2) ────────────────────────────────────────────────\n -- Valor de REFERÊNCIA, e o V1 diz isso com todas as letras: nada aqui vira\n -- conta a pagar, comissão ou desconto. O comentário fica porque a coluna\n -- chamada \\`base_salary\\` convida a supor o contrário.\n base_salary numeric(14,2),\n pay_frequency text CHECK (pay_frequency IN ('mensal', 'quinzenal', 'semanal', 'diario', 'por_hora')),\n -- Os quinze auxílios e adicionais da vista 2 em jsonb, e não em quinze\n -- colunas. Medido: ZERO deles preenchido nas 886 pessoas. Quinze colunas\n -- nulas seriam quinze decisões de schema tomadas sem um caso de uso; a chave\n -- que a casa usar aparece aqui e vira coluna quando pagar a passagem.\n allowances jsonb NOT NULL DEFAULT '{}'::jsonb,\n\n notes text,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n -- Um vínculo por pessoa. Recontratação reabre o mesmo, com a data nova — o\n -- histórico de quem saiu e voltou é uma vista de lista que ainda não existe,\n -- e inventar a segunda linha agora criaria dois headcounts para uma pessoa.\n CONSTRAINT plg_workforce_employment_person UNIQUE (tenant_id, person_id),\n -- Demissão antes da admissão não é dado ruim, é dado impossível.\n CONSTRAINT plg_workforce_employment_dates\n CHECK (dismissal_date IS NULL OR admission_date IS NULL OR dismissal_date >= admission_date)\n);\n\nCOMMENT ON TABLE public.plg_workforce_employment IS\n 'O vínculo trabalhista de uma pessoa (005). É dele que saem headcount, admissões, demissões, turnover e experiência vencendo. Tabela própria e não colunas em people: RLS é por tabela, e é o salário que precisa da policy.';\nCOMMENT ON COLUMN public.plg_workforce_employment.base_salary IS\n 'Valor de REFERÊNCIA. Não vira conta a pagar, comissão nem desconto — o V1 também não fazia isso, e o nome da coluna convida a supor que faz.';\nCOMMENT ON COLUMN public.plg_workforce_employment.allowances IS\n 'Auxílios e adicionais (VT, VR, VA, plano, creche, noturno, insalubridade…). Em jsonb porque os quinze campos da vista 2 do V1 estão vazios nas 886 pessoas medidas: vira coluna quando alguém pagar a passagem.';\n\nCREATE INDEX IF NOT EXISTS plg_workforce_employment_tenant_person\n ON public.plg_workforce_employment (tenant_id, person_id);\nCREATE INDEX IF NOT EXISTS plg_workforce_employment_ativo\n ON public.plg_workforce_employment (tenant_id) WHERE dismissal_date IS NULL;\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 3. FÉRIAS (vista 8)\n-- ═══════════════════════════════════════════════════════════════════════════\n\nCREATE TABLE IF NOT EXISTS public.plg_workforce_vacations (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n unit_id uuid,\n person_id uuid NOT NULL REFERENCES public.people(id) ON DELETE CASCADE,\n -- O período AQUISITIVO: o que a pessoa ganhou. É o \\`accrual_end\\` que alimenta\n -- \"Férias vencendo (60d)\".\n accrual_start date NOT NULL,\n accrual_end date NOT NULL,\n -- O período de GOZO: quando ela tirou. Nulo é o estado normal de quem ainda\n -- não programou.\n taken_start date,\n taken_end date,\n days_taken integer,\n days_sold integer,\n advance_13th boolean NOT NULL DEFAULT false,\n -- Digitado, como no V1. O sistema NÃO calcula o terço — e escrever isso aqui\n -- é o que impede alguém de supor que a coluna vazia é um bug.\n constitutional_third numeric(14,2),\n status text NOT NULL DEFAULT 'pendente'\n CHECK (status IN ('pendente', 'programada', 'em_gozo', 'concluida', 'vencida')),\n notes text,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n CONSTRAINT plg_workforce_vacations_accrual CHECK (accrual_end >= accrual_start),\n CONSTRAINT plg_workforce_vacations_taken\n CHECK (taken_end IS NULL OR taken_start IS NULL OR taken_end >= taken_start)\n);\n\nCOMMENT ON TABLE public.plg_workforce_vacations IS\n 'Período aquisitivo e de gozo de férias (005). Nada é calculado, inclusive o terço constitucional — é digitado, como no V1.';\n\nCREATE INDEX IF NOT EXISTS plg_workforce_vacations_vencendo\n ON public.plg_workforce_vacations (tenant_id, accrual_end) WHERE status <> 'concluida';\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 4. FALTAS E AFASTAMENTOS (vista 10)\n-- ═══════════════════════════════════════════════════════════════════════════\n\nCREATE TABLE IF NOT EXISTS public.plg_workforce_absences (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n unit_id uuid,\n person_id uuid NOT NULL REFERENCES public.people(id) ON DELETE CASCADE,\n kind text NOT NULL CHECK (kind IN\n ('falta_justificada', 'falta_injustificada', 'atestado', 'licenca_maternidade',\n 'licenca_paternidade', 'licenca_nao_remunerada', 'suspensao', 'ferias', 'afastamento_inss')),\n starts_on date NOT NULL,\n -- Nulo = afastamento em aberto, que é um estado real (INSS sem alta marcada).\n ends_on date,\n days integer,\n paid boolean NOT NULL DEFAULT true,\n -- Dado médico. Mora aqui e não em \\`people\\` pelo mesmo motivo do salário: é a\n -- policy de \\`workforce_hr\\` que o protege, e V1-069 é exatamente sobre isto.\n icd_code text,\n doctor text,\n notes text,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n CONSTRAINT plg_workforce_absences_span CHECK (ends_on IS NULL OR ends_on >= starts_on)\n);\n\nCOMMENT ON TABLE public.plg_workforce_absences IS\n 'Falta e afastamento (005). Diferente do V1, CONVERSA com o ponto: v_workforce_day lê daqui, e um dia coberto por atestado deixa de aparecer como falta.';\nCOMMENT ON COLUMN public.plg_workforce_absences.icd_code IS\n 'CID do atestado. Dado de saúde: é a policy de workforce_hr que o separa de quem edita cadastro — o V1 não separava (V1-069).';\n\nCREATE INDEX IF NOT EXISTS plg_workforce_absences_periodo\n ON public.plg_workforce_absences (tenant_id, person_id, starts_on, ends_on);\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 5. PENDÊNCIAS (vista 16)\n-- ═══════════════════════════════════════════════════════════════════════════\n\nCREATE TABLE IF NOT EXISTS public.plg_workforce_pending_items (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n unit_id uuid,\n person_id uuid NOT NULL REFERENCES public.people(id) ON DELETE CASCADE,\n title text NOT NULL,\n category text CHECK (category IN ('documento', 'exame', 'epi', 'treinamento', 'assinatura', 'outro')),\n priority text NOT NULL DEFAULT 'normal' CHECK (priority IN ('baixa', 'normal', 'alta', 'urgente')),\n due_on date,\n resolved_at timestamptz,\n description text,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now()\n);\n\nCOMMENT ON TABLE public.plg_workforce_pending_items IS\n 'O que falta na pasta de alguém: documento, exame, EPI, assinatura (005). É a lista que o painel cobra — \"Pendências críticas\" conta as não resolvidas de prioridade alta ou urgente.';\n\nCREATE INDEX IF NOT EXISTS plg_workforce_pending_abertas\n ON public.plg_workforce_pending_items (tenant_id, priority, due_on) WHERE resolved_at IS NULL;\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 6. ESCOPO, CARIMBO E PERMISSÃO\n-- ═══════════════════════════════════════════════════════════════════════════\n\nDO $$\nDECLARE r record;\nBEGIN\n FOR r IN SELECT * FROM (VALUES\n ('plg_workforce_employment', 'workforce_hr.employment'),\n ('plg_workforce_vacations', 'workforce_hr.vacation'),\n ('plg_workforce_absences', 'workforce_hr.absence'),\n ('plg_workforce_pending_items', 'workforce_hr.pending_item')\n ) AS t(tbl, resource)\n LOOP\n EXECUTE format('ALTER TABLE public.%I ENABLE ROW LEVEL SECURITY', r.tbl);\n EXECUTE format('ALTER TABLE public.%I FORCE ROW LEVEL SECURITY', r.tbl);\n EXECUTE format('DROP TRIGGER IF EXISTS %I ON public.%I', r.tbl || '_updated_at', r.tbl);\n EXECUTE format('CREATE TRIGGER %I BEFORE UPDATE ON public.%I FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at()',\n r.tbl || '_updated_at', r.tbl);\n -- \\`workforce_hr\\` e não \\`workforce\\`: é o nome do plugin que o scaffold usa\n -- para derivar \\`<plugin>.read/create/edit/delete\\`, então passar outro nome\n -- aqui É a separação de permissão. Quem tem workforce.read vê escala e\n -- ponto e não vê salário.\n PERFORM app.scaffold_table(format('public.%I', r.tbl)::regclass, r.resource, 'workforce_hr', false, 'enforce');\n END LOOP;\nEND $$;\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 7. O PONTO PASSA A SABER DO AFASTAMENTO\n-- ═══════════════════════════════════════════════════════════════════════════\n--\n-- O defeito que o FLOW da vista 10 registra: *\"Não conversa com o ponto\n-- eletrônico nem com a escala.\"* Duas telas sobre a mesma pessoa, no mesmo\n-- sistema, que não se olham — quem confere ponto vê FALTA em cima de um\n-- atestado que o RH lançou na semana passada, e precisa lembrar de cabeça.\n--\n-- A view não muda de forma: ganha uma coluna no fim. \\`absent\\` continua sendo\n-- escala sem ponto, porque é isso que ele é; o que muda é que agora dá para\n-- dizer POR QUE, quando alguém sabe.\n\nCREATE OR REPLACE VIEW public.v_workforce_day\nWITH (security_invoker = 'true') AS\nWITH bruto AS (\n SELECT e.tenant_id, e.unit_id, e.person_id, e.work_date,\n min(e.effective_at) FILTER (WHERE e.kind = 'clock_in') AS first_in,\n max(e.effective_at) FILTER (WHERE e.kind = 'clock_out') AS last_out,\n count(*) FILTER (WHERE e.kind = 'break_start') AS break_count,\n count(*) FILTER (WHERE e.kind IN ('clock_in', 'break_end')) AS aberturas,\n count(*) FILTER (WHERE e.kind IN ('clock_out', 'break_start')) AS fechamentos,\n max(e.effective_at) FILTER (WHERE e.kind IN ('clock_in', 'break_end')) AS ultima_abertura,\n sum(CASE\n WHEN e.kind IN ('clock_out', 'break_start') THEN extract(epoch FROM e.effective_at)\n WHEN e.kind IN ('clock_in', 'break_end') THEN -extract(epoch FROM e.effective_at)\n END) AS soma_com_sinal\n FROM public.v_workforce_time_entries e\n WHERE NOT e.voided\n GROUP BY e.tenant_id, e.unit_id, e.person_id, e.work_date\n),\nrealized AS (\n SELECT b.tenant_id, b.unit_id, b.person_id, b.work_date,\n b.first_in, b.last_out, b.break_count,\n (b.aberturas <> b.fechamentos) AS is_open,\n CASE WHEN b.aberturas <> b.fechamentos THEN b.ultima_abertura END AS open_since,\n -- Devolve à soma a abertura sem par (003).\n (b.soma_com_sinal\n + CASE WHEN b.aberturas <> b.fechamentos\n THEN extract(epoch FROM b.ultima_abertura)\n ELSE 0 END) AS worked_seconds\n FROM bruto b\n),\nplanned AS (\n SELECT a.tenant_id, a.unit_id, a.person_id,\n s.schedule_date AS work_date,\n a.id AS assignment_id, a.role, a.status AS assignment_status,\n a.shift_label, a.shift_start_time, a.shift_end_time,\n (extract(epoch FROM a.shift_end_time - a.shift_start_time)\n + CASE WHEN a.shift_end_time <= a.shift_start_time THEN 86400 ELSE 0 END) AS planned_seconds\n FROM public.plg_workforce_schedule_assignments a\n JOIN public.plg_workforce_schedules s ON s.id = a.schedule_id\n WHERE s.status IN ('published', 'closed')\n AND a.role = 'titular'\n AND a.shift_start_time IS NOT NULL\n AND a.shift_end_time IS NOT NULL\n)\nSELECT coalesce(p.tenant_id, r.tenant_id) AS tenant_id,\n coalesce(p.unit_id, r.unit_id) AS unit_id,\n coalesce(p.person_id, r.person_id) AS person_id,\n coalesce(p.work_date, r.work_date) AS work_date,\n p.assignment_id,\n p.shift_label,\n p.shift_start_time,\n p.shift_end_time,\n p.assignment_status,\n (p.planned_seconds / 60)::integer AS planned_minutes,\n (r.worked_seconds / 60)::integer AS worked_minutes,\n ((r.worked_seconds - p.planned_seconds) / 60)::integer AS variance_minutes,\n r.first_in,\n r.last_out,\n r.break_count,\n coalesce(r.is_open, false) AS is_open,\n (r.person_id IS NULL) AS absent,\n (p.assignment_id IS NULL) AS outside_schedule,\n r.open_since,\n CASE\n WHEN r.person_id IS NULL THEN NULL\n WHEN r.is_open THEN 'open'\n WHEN (r.worked_seconds / 60) > public.workforce_max_shift_minutes()\n THEN 'span_too_long'\n END AS review_reason,\n -- Coluna nova, no fim. \\`security_invoker\\` na view + a policy de\n -- \\`workforce_hr\\` na tabela: quem não tem a permissão simplesmente não\n -- enxerga o afastamento, e a coluna volta nula. A folha de ponto não\n -- vira a porta dos fundos do CID.\n (SELECT a.kind\n FROM public.plg_workforce_absences a\n WHERE a.tenant_id = coalesce(p.tenant_id, r.tenant_id)\n AND a.person_id = coalesce(p.person_id, r.person_id)\n AND coalesce(p.work_date, r.work_date) BETWEEN a.starts_on\n AND coalesce(a.ends_on, coalesce(p.work_date, r.work_date))\n ORDER BY a.starts_on DESC\n LIMIT 1) AS absence_kind\n FROM planned p\n FULL OUTER JOIN realized r\n ON r.tenant_id = p.tenant_id\n AND r.person_id = p.person_id\n AND r.work_date = p.work_date;\n\nCOMMENT ON COLUMN public.v_workforce_day.absence_kind IS\n 'O afastamento que cobre este dia, quando o RH lançou um (005). É o conserto do defeito que o V1 tem: lá a falta lançada no RH não aparece no ponto, e quem confere vê FALTA em cima de um atestado.';\n\nGRANT SELECT ON public.v_workforce_day TO authenticated, service_role;\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 8. A VISÃO GERAL — os oito números\n-- ═══════════════════════════════════════════════════════════════════════════\n--\n-- Os mesmos oito cartões do V1, com três diferenças, e as três são conserto de\n-- defeito registrado no FLOW:\n--\n-- V1-072 \"Experiência vencendo\" só olhava PROFISSIONAIS, porque o V1 tem\n-- duas tabelas. O V2 tem uma pessoa, então olha todo mundo.\n-- V1-073 \"Férias a vencer\" mostrava a data e NÃO o nome. Aqui a view devolve\n-- person_id e nome, e a tela linka para a ficha.\n-- V1-074 aniversariante do dia 1º caía no mês anterior, por comparação de\n-- data em UTC. \\`extract(month …)\\` não tem esse problema.\n\nCREATE OR REPLACE VIEW public.v_workforce_hr_overview\nWITH (security_invoker = 'true') AS\nWITH base AS (\n SELECT e.tenant_id, e.person_id, e.admission_date, e.dismissal_date, e.probation_final_end,\n p.name, p.date_of_birth, p.is_active\n FROM public.plg_workforce_employment e\n JOIN public.people p ON p.id = e.person_id\n)\nSELECT b.tenant_id,\n count(*) FILTER (WHERE b.dismissal_date IS NULL AND coalesce(b.is_active, true)) AS headcount,\n count(*) FILTER (WHERE b.admission_date >= current_date - 30) AS admissions_30d,\n count(*) FILTER (WHERE b.dismissal_date >= current_date - 30) AS dismissals_30d,\n count(*) FILTER (WHERE b.probation_final_end BETWEEN current_date AND current_date + 60) AS probation_ending,\n count(*) FILTER (WHERE b.dismissal_date IS NULL\n AND extract(month FROM b.date_of_birth) = extract(month FROM current_date)) AS birthdays_this_month,\n (SELECT count(*) FROM public.plg_workforce_vacations v\n WHERE v.tenant_id = b.tenant_id AND v.status <> 'concluida'\n AND v.accrual_end BETWEEN current_date AND current_date + 60) AS vacations_due_60d,\n (SELECT count(*) FROM public.plg_workforce_pending_items i\n WHERE i.tenant_id = b.tenant_id AND i.resolved_at IS NULL\n AND i.priority IN ('alta', 'urgente')) AS critical_pending\n FROM base b\n GROUP BY b.tenant_id;\n\nCOMMENT ON VIEW public.v_workforce_hr_overview IS\n 'Os oito números do painel de RH do V1 (005). Turnover não está aqui de propósito: é demissões ÷ headcount, e uma divisão que a tela faz é uma divisão que a tela pode formatar — a view devolve as duas parcelas.';\n\n-- Quem vence, COM NOME — o V1-073 é justamente a lista sem nome.\nCREATE OR REPLACE VIEW public.v_workforce_hr_upcoming\nWITH (security_invoker = 'true') AS\nSELECT v.tenant_id, 'vacation'::text AS kind, v.person_id, p.name AS person_name,\n v.accrual_end AS due_on, v.status AS detail\n FROM public.plg_workforce_vacations v\n JOIN public.people p ON p.id = v.person_id\n WHERE v.status <> 'concluida' AND v.accrual_end BETWEEN current_date AND current_date + 60\nUNION ALL\nSELECT e.tenant_id, 'probation', e.person_id, p.name,\n e.probation_final_end, e.job_title\n FROM public.plg_workforce_employment e\n JOIN public.people p ON p.id = e.person_id\n WHERE e.probation_final_end BETWEEN current_date AND current_date + 60\nUNION ALL\nSELECT i.tenant_id, 'pending', i.person_id, p.name, i.due_on, i.title\n FROM public.plg_workforce_pending_items i\n JOIN public.people p ON p.id = i.person_id\n WHERE i.resolved_at IS NULL AND i.priority IN ('alta', 'urgente');\n\nCOMMENT ON VIEW public.v_workforce_hr_upcoming IS\n 'O que vence nos próximos 60 dias, com o NOME de quem (005). O V1 lista férias a vencer só com a data — V1-073 —, o que obriga a procurar a pessoa em outra tela.';\n\nGRANT SELECT ON public.v_workforce_hr_overview TO authenticated, service_role;\nGRANT SELECT ON public.v_workforce_hr_upcoming TO authenticated, service_role;\n`\n\nexport const MIGRATION_006_O_CUSTO_DE_PESSOAL_E_UM_RAMO_DO_PLANO = `-- O custo de pessoal é um RAMO DO PLANO, e quem o aponta é a casa.\n--\n-- ── O defeito, medido ───────────────────────────────────────────────────────\n--\n-- A tela \"Encargos e honorários\" (RH → Custos) lê o razão do Financeiro e soma\n-- toda linha de conta a pagar que tenha conta contábil. Toda. Medido no cluster\n-- de Pertinho do Céu em 19/09/2026, o que ela chamava de custo de pessoal\n-- incluía:\n--\n-- 6.2.1 Aluguel R$ 21.061,99\n-- 6.2.3 IPTU R$ 26.613,73\n-- 6.5.5 ICMS R$ 30.964,92\n-- 6.4.1 Equipamentos R$ 82.595,87\n-- 6.3.1 Energia/Light R$ 27.185,62\n--\n-- — ao lado das que são, de fato, pessoal:\n--\n-- 5 DESPESAS COM PESSOAL (26 contas: Salário, FGTS, INSS, Comissão,\n-- Hora Extra, Adiantamento, IRRF Folha, Vale Alimentação, FREELANCER\n-- com oito filhas…)\n--\n-- Um total que soma aluguel e ICMS sob o título \"custo de pessoal\" não está\n-- impreciso: está errado, e erra para cima, que é o lado que faz alguém decidir\n-- contratar menos.\n--\n-- ── Por que uma configuração, e não uma regra ───────────────────────────────\n--\n-- Não existe como o código saber qual ramo é pessoal. O plano de contas é uma\n-- DECLARAÇÃO da casa (ver \\`040_o_demonstrativo_mostra_o_plano_inteiro\\`), e cada\n-- casa numera o dela: aqui pessoal é o ramo \\`5\\`; o template que o SDK semeia\n-- para um tenant novo põe folha em \\`4.03\\`. Deduzir pelo NOME da conta seria\n-- adivinhar em português — e \\`8.2.4 Rescisão\\` e \\`8.2.6 Pro-labore\\`, que também\n-- são gente, moram fora do ramo 5 neste mesmo plano, por escolha de quem montou.\n--\n-- Então a chave guarda a escolha, e a ausência dela é uma ausência honesta: sem\n-- nada escolhido a tela mostra TODAS as despesas classificadas e diz que é o que\n-- está fazendo. Um padrão inventado ('5') faria a tela mentir com convicção no\n-- primeiro tenant cujo plano não usa esse número.\n--\n-- ── A forma ────────────────────────────────────────────────────────────────\n--\n-- Um array de CÓDIGOS, não de ids. O código é o que carrega a hierarquia: quem\n-- escolhe '5' escolhe o ramo inteiro — '5.4' e '5.4.1' entram com ele, e uma\n-- conta nova criada amanhã dentro do ramo entra sozinha. Com id seria preciso\n-- re-marcar a configuração a cada conta nova, e ninguém lembra.\n--\n-- \\`tenant_setting_set\\` cobra \\`settings.manage\\` e recusa chave não registrada —\n-- é por isso que este arquivo existe. Idempotente: \\`seed_setting_keys\\` faz\n-- upsert por chave.\n\nSELECT app.seed_setting_keys($$[\n {\n \"key\": \"workforce.payroll_account_codes\", \"type\": \"array\", \"default\": null,\n \"reader\": \"plugin:workforce\",\n \"description\": \"Os ramos do plano de contas que são custo de pessoal, por código ('5', '8.2.4'). Um código traz toda a descendência dele. Vazio ou nulo = a tela mostra todas as despesas classificadas e avisa que não há ramo escolhido.\"\n }\n]$$::jsonb);\n`\n\nexport const MIGRATION_007_A_PORTA_DE_SERVICO_DO_PONTO_FECHA_TAMBEM = `-- ---------------------------------------------------------------------------\n-- 007_a_porta_de_servico_do_ponto_fecha_tambem.sql\n--\n-- ── o buraco, e por que ele estava invisível ────────────────────────────\n--\n-- As funções que este plugin cria em \\`migration\\` nasceram executáveis por\n-- PUBLIC — é o padrão do Postgres, e ninguém revogou. Elas são\n-- \\`SECURITY DEFINER\\` e escrevem dados de QUALQUER inquilino: uma delas\n-- alcançável pela chave anônima é a base inteira alcançável pela chave\n-- anônima.\n--\n-- Isto não aparecia porque a \\`000_baseline\\` falhava e levava junto os outros\n-- seis arquivos deste plugin — as funções nunca chegavam a existir na bancada.\n-- Com a baseline consertada (#443) o passo inteiro passou a aplicar, e as duas\n-- suítes que guardam esta fronteira ficaram vermelhas na hora:\n--\n-- 090_migration_ledger/001 \"no migration function is executable by anon\n-- or authenticated\" — have 9, want 0\n-- crm/009 \"nenhuma função do schema migration é chamável\n-- por anon\" — have 9, want 0\n--\n-- Ou seja: a regra sempre esteve escrita e medida; o que faltava era o plugin\n-- chegar ao banco para ser medido. É o argumento do #338 de novo — um plugin\n-- fora da corrente é um plugin cujas tabelas (e cujas portas) são coincidência.\n--\n-- ── por extenso, e não varrendo o catálogo ──────────────────────────────\n--\n-- A tentação é \\`REVOKE\\` num laço sobre \\`pg_proc\\`. Já foi tentado neste repo e\n-- derrubou 35 suítes: varrer revoga de funções que outros passos criaram e\n-- precisam de execução. Revogar em massa é fácil de escrever e impossível de\n-- revisar. A lista abaixo é a das funções DESTE plugin, nomeada uma a uma.\n-- ---------------------------------------------------------------------------\n\nDO $$\nDECLARE\n v_fn text;\n v_args text;\n v_n integer := 0;\nBEGIN\n -- Cada writer do de-para, com a assinatura que a corrente lhe deu. Nomear em\n -- vez de varrer é o que torna esta lista revisável.\n FOR v_fn, v_args IN\n SELECT p.proname, pg_get_function_identity_arguments(p.oid)\n FROM pg_proc p\n JOIN pg_namespace n ON n.oid = p.pronamespace\n WHERE n.nspname = 'migration'\n AND (p.proname LIKE 'upsert_wf\\\\_%' OR p.proname IN ('_wf_person', '_point_punch_photo'))\n LOOP\n EXECUTE format('REVOKE ALL ON FUNCTION migration.%I(%s) FROM PUBLIC, anon, authenticated', v_fn, v_args);\n -- \\`service_role\\` fica: é quem a importação usa, e é a única identidade que\n -- tem razão para atravessar inquilinos.\n EXECUTE format('GRANT EXECUTE ON FUNCTION migration.%I(%s) TO service_role', v_fn, v_args);\n v_n := v_n + 1;\n END LOOP;\n\n RAISE NOTICE 'workforce/007: % função(ões) de migration fechadas a anon e authenticated', v_n;\nEND $$;\n`\n\nexport const MIGRATIONS: Array<{ id: string; sql: string }> = [\n { id: \"000_baseline\", sql: MIGRATION_000_BASELINE },\n { id: \"001_a_prova_da_batida_tem_bytes\", sql: MIGRATION_001_A_PROVA_DA_BATIDA_TEM_BYTES },\n { id: \"002_o_guarda_da_foto_olhava_o_nome_errado\", sql: MIGRATION_002_O_GUARDA_DA_FOTO_OLHAVA_O_NOME_ERRADO },\n { id: \"003_o_ponto_em_aberto_para_de_mentir_a_duracao\", sql: MIGRATION_003_O_PONTO_EM_ABERTO_PARA_DE_MENTIR_A_DURACAO },\n { id: \"004_a_jornada_implausivel_nao_soma\", sql: MIGRATION_004_A_JORNADA_IMPLAUSIVEL_NAO_SOMA },\n { id: \"005_a_ficha_trabalhista_tem_onde_morar\", sql: MIGRATION_005_A_FICHA_TRABALHISTA_TEM_ONDE_MORAR },\n { id: \"006_o_custo_de_pessoal_e_um_ramo_do_plano\", sql: MIGRATION_006_O_CUSTO_DE_PESSOAL_E_UM_RAMO_DO_PLANO },\n { id: \"007_a_porta_de_servico_do_ponto_fecha_tambem\", sql: MIGRATION_007_A_PORTA_DE_SERVICO_DO_PONTO_FECHA_TAMBEM },\n]\n","import React from 'react'\nimport type { EntityDef, PluginManifest, PluginScope, VerticalId } from '@fayz-ai/core'\nimport { createSafeDataProvider } from '@fayz-ai/core'\nimport type { EntityLookup } from '@fayz-ai/admin'\nimport { registerEntityPath } from '@fayz-ai/admin'\nimport { WorkforcePage } from './views/WorkforcePage'\nimport type { ResolvedWorkforceConfig } from './context'\nimport type { WorkforceDataProvider } from './data/types'\nimport { createMockWorkforceProvider } from './data/mock'\nimport { createSupabaseWorkforceProvider } from './data/supabase'\nimport { createWorkforceStore } from './store'\nimport { MIGRATIONS } from './migrations'\n\n/**\n * O provider da jornada, resolvido tarde: Supabase quando há cliente, memória\n * quando não há. Público porque um app que queira compartilhar UM provider\n * entre o módulo e uma ponte (o totem de ponto, por exemplo) precisa do mesmo.\n */\nexport function createSafeWorkforceProvider(): WorkforceDataProvider {\n return createSafeDataProvider(\n () => createSupabaseWorkforceProvider(),\n () => createMockWorkforceProvider(),\n )\n}\n\n// ---------------------------------------------------------------------------\n// Tipos públicos\n// ---------------------------------------------------------------------------\n\nexport interface WorkforcePluginLabels {\n pageTitle: string\n pageSubtitle: string\n schedules: string\n templates: string\n timeEntries: string\n hr: string\n periods: string\n people: string\n payrollCosts: string\n}\n\nexport interface WorkforcePluginOptions {\n /** Onde a sub-navegação do módulo mora. Padrão: o que a shell decidir. */\n moduleNav?: 'rail' | 'tabs' | 'sidebar'\n modules?: {\n schedules?: boolean\n templates?: boolean\n timeEntries?: boolean\n hr?: boolean\n periods?: boolean\n people?: boolean\n payrollCosts?: boolean\n }\n labels?: Partial<WorkforcePluginLabels>\n currency?: { code?: string; locale?: string; symbol?: string }\n navPosition?: number\n navSection?: 'main' | 'secondary'\n scope?: PluginScope\n verticalId?: VerticalId\n\n /** Provider de dados. Padrão: Supabase-ou-memória. */\n dataProvider?: WorkforceDataProvider\n\n /**\n * Quanto vale a hora, para a folha mostrar valor.\n *\n * NÃO existe coluna de remuneração no SQL da jornada — nem na batida, nem no\n * turno, nem em `public.people`. Sem esta opção a tela mostra \"—\" em vez de\n * inventar um número, e o relatório do módulo diz isso.\n */\n hourlyRate?: number\n\n /** A entidade de pessoa que a aba \"Pessoas & Documentos\" edita. Padrão: o\n * recorte de `people` com papel de equipe (ver views/PeopleView). */\n staffEntity?: EntityDef\n\n /** Busca de pessoa, quando o app quiser oferecer uma para escalar. */\n staffLookup?: EntityLookup\n\n /**\n * Onde mora a página de UMA pessoa da equipe neste app — `'/staff'`.\n *\n * O nome na lista de Registros de Ponto é um `PersonLink`, e ele resolve a\n * rota pelo registro compartilhado de caminhos. O padrão daquele registro é\n * `/registry/staff`, que é herança do app veterinário: num app que monta a\n * equipe em `/staff` o nome viraria um link para uma rota inexistente — pior\n * que texto puro, porque parece clicável e não é.\n *\n * O plugin não adivinha: quem sabe onde a página está é o app que a montou.\n * Sem esta opção o registro fica como está, e o link cai onde o padrão\n * aponta.\n */\n staffRoute?: string\n\n /**\n * Qual link interno ESTE app cobra, como `id do item de nav → id da feature`.\n * Vazio por padrão: empacotamento é decisão do app, não do plugin.\n */\n navFeatureMap?: Record<string, string>\n}\n\n// ---------------------------------------------------------------------------\n// Padrões\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_LABELS: WorkforcePluginLabels = {\n pageTitle: 'RH',\n pageSubtitle: 'Escala, ponto e fechamento da equipe',\n schedules: 'Escalas',\n templates: 'Templates',\n timeEntries: 'Registros de Ponto',\n hr: 'Ficha de RH',\n periods: 'Fechamento',\n people: 'Pessoas & Documentos',\n payrollCosts: 'Encargos e Honorários',\n}\n\nconst DEFAULT_CURRENCY = { code: 'BRL', locale: 'pt-BR', symbol: 'R$' }\n\n/**\n * Preset OPCIONAL de ids de feature para as subtelas — uma convenção oferecida\n * aos apps, NÃO um padrão. Nada aqui vale sem `options.navFeatureMap`.\n */\nexport const WORKFORCE_NAV_FEATURES = {\n schedules: 'wf_schedules',\n templates: 'wf_templates',\n 'time-entries': 'wf_time_entries',\n hr: 'wf_hr',\n periods: 'wf_periods',\n people: 'wf_people',\n 'payroll-costs': 'wf_payroll_costs',\n} as const satisfies Record<string, string>\n\nfunction resolveConfig(options?: WorkforcePluginOptions): ResolvedWorkforceConfig {\n return {\n modules: {\n schedules: options?.modules?.schedules !== false,\n templates: options?.modules?.templates !== false,\n timeEntries: options?.modules?.timeEntries !== false,\n hr: options?.modules?.hr !== false,\n periods: options?.modules?.periods !== false,\n people: options?.modules?.people !== false,\n // Ligada como as outras: quando o Financeiro não está instalado a própria\n // tela diz isso, então o item de menu nunca leva a um beco.\n payrollCosts: options?.modules?.payrollCosts !== false,\n },\n labels: { ...DEFAULT_LABELS, ...options?.labels },\n currency: { ...DEFAULT_CURRENCY, ...options?.currency },\n moduleNav: options?.moduleNav,\n hourlyRate: options?.hourlyRate,\n staffLookup: options?.staffLookup,\n navFeatureMap: { ...options?.navFeatureMap },\n }\n}\n\n// ---------------------------------------------------------------------------\n// Fábrica\n// ---------------------------------------------------------------------------\n\nexport function createWorkforcePlugin(options?: WorkforcePluginOptions): PluginManifest {\n const config = resolveConfig(options)\n\n // Onde uma pessoa da equipe mora NESTE app, dito ao registro que o PersonLink\n // consulta. Ver `staffRoute` — o padrão do registro é veterinário.\n if (options?.staffRoute) registerEntityPath('staff', options.staffRoute)\n\n const provider = options?.dataProvider ?? createSafeWorkforceProvider()\n const store = createWorkforceStore(provider)\n\n const PageComponent: React.FC<unknown> = () =>\n React.createElement(WorkforcePage, {\n config,\n provider,\n store,\n staffEntity: options?.staffEntity,\n })\n\n return {\n id: 'workforce',\n name: config.labels.pageTitle,\n icon: 'UsersRound',\n version: '1.0.0',\n scope: options?.scope ?? 'universal',\n verticalId: options?.verticalId,\n defaultEnabled: true,\n dependencies: [],\n\n // O plugin é DONO de todo o seu SQL e diz isso: o que instalá-lo provisiona\n // é esta lista, byte a byte o que está em src/migrations (barrel gerado por\n // scripts/embed-migrations.mjs). SQL solto é a violação de contrato que a\n // regra existe para impedir.\n migrations: MIGRATIONS.map((m) => ({\n id: `workforce-${m.id}`,\n version: '1.0.0',\n sql: m.sql,\n description: m.id,\n })),\n\n declaredFeatures: [\n { id: 'workforce', label: config.labels.pageTitle, group: config.labels.pageTitle },\n ],\n\n queryEntities: [\n {\n key: 'workforce:days',\n entity: {\n name: 'Work day',\n namePlural: 'Jornadas (previsto × realizado)',\n icon: 'Clock',\n permission: { feature: 'workforce', action: 'read' },\n fields: [\n { key: 'work_date', label: 'Dia', type: 'text' },\n { key: 'shift_label', label: 'Turno', type: 'text' },\n { key: 'planned_minutes', label: 'Previsto (min)', type: 'number' },\n { key: 'worked_minutes', label: 'Realizado (min)', type: 'number' },\n { key: 'variance_minutes', label: 'Diferença (min)', type: 'number' },\n { key: 'absent', label: 'Falta', type: 'boolean' },\n { key: 'outside_schedule', label: 'Fora da escala', type: 'boolean' },\n { key: 'is_open', label: 'Em aberto', type: 'boolean' },\n ],\n data: { table: 'v_workforce_day', tenantScoped: true },\n },\n },\n {\n key: 'workforce:time-entries',\n entity: {\n name: 'Time entry',\n namePlural: 'Batidas de ponto (com a hora que vale)',\n icon: 'Clock3',\n permission: { feature: 'workforce', action: 'read' },\n fields: [\n { key: 'person_name', label: 'Pessoa', type: 'text', searchable: true },\n { key: 'kind', label: 'Evento', type: 'text' },\n { key: 'work_date', label: 'Dia da jornada', type: 'text' },\n { key: 'punched_at', label: 'Horário real', type: 'text' },\n { key: 'effective_at', label: 'Horário que vale', type: 'text' },\n { key: 'adjusted', label: 'Ajustada', type: 'boolean' },\n { key: 'voided', label: 'Anulada', type: 'boolean' },\n ],\n data: {\n table: 'v_workforce_time_entries',\n tenantScoped: true,\n searchColumns: ['person_name'],\n },\n },\n },\n ],\n\n declaredRpcs: [\n {\n name: 'workforce_period_close',\n kind: 'write' as const,\n description: 'Fecha a competência mensal da jornada. A partir daí nenhuma batida nem ajuste entra com data naquele mês.',\n audits: true,\n },\n {\n name: 'workforce_period_reopen',\n kind: 'write' as const,\n description: 'Reabre a competência mensal da jornada. Exige motivo, que fica registrado.',\n audits: true,\n },\n ],\n\n navigation: [\n {\n section: options?.navSection ?? 'main',\n position: options?.navPosition ?? 35,\n label: config.labels.pageTitle,\n route: '/workforce',\n icon: 'UsersRound',\n permission: { feature: 'workforce', action: 'read' as const },\n },\n ],\n\n routes: [\n {\n path: '/workforce',\n component: PageComponent as React.ComponentType<unknown>,\n permission: { feature: 'workforce', action: 'read' as const },\n },\n ],\n }\n}\n\n// ---------------------------------------------------------------------------\n// Reexportações\n// ---------------------------------------------------------------------------\n\nexport type { WorkforceDataProvider } from './data/types'\nexport type { ResolvedWorkforceConfig } from './context'\nexport type {\n TimeEntry, TimeEntryKind, TimeEntryQuery, TimeAdjustmentAction, TimeAdjustmentInput,\n WorkDay, WorkforcePeriod,\n ScheduleTemplate, ScheduleShift, ScheduleRequirement,\n DaySchedule, ScheduleAssignment, ScheduleQuery, CreateScheduleInput,\n WorkforcePerson, PayrollCostRow, PayrollCostQuery,\n} from './types'\nexport { createMockWorkforceProvider } from './data/mock'\nexport { createSupabaseWorkforceProvider, WORK_SHIFT_KIND } from './data/supabase'\nexport { DEFAULT_STAFF_ENTITY } from './views/PeopleView'\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/context.tsx","../src/views/SchedulesView.tsx","../src/views/TemplatesView.tsx","../src/views/TimeEntriesView.tsx","../src/views/PeriodsView.tsx","../src/views/PeopleView.tsx","../src/settings/usePayrollAccounts.ts","../src/views/PayrollCostsView.tsx","../src/views/HrView.tsx","../src/views/WorkforcePage.tsx","../src/data/mock.ts","../src/data/supabase.ts","../src/store.ts","../src/migrations/index.ts","../src/index.ts"],"names":["React","toast","jsxs","jsx","Button","Badge","Plus","Skeleton","Fragment","Modal","ModalContent","ModalHeader","ModalTitle","ModalBody","ModalFooter","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","Input","Users","Lock","client","monthLabel","resolveRangePreset","PageToolbar","DateRangeControl","AlertTriangle","PersonLink","getSupabaseClientOptional","hhmm"],"mappings":"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AA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA,CAAA;AA66D/B,IAAM,yCAAA,GAA4C,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAmKlD,IAAM,mDAAA,GAAsD,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAoG5D,IAAM,wDAAA,GAA2D,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA,CAAA;AAgKjE,IAAM,4CAAA,GAA+C,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA,CAAA;AA2KrD,IAAM,gDAAA,GAAmD,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA,CAAA;AAyczD,IAAM,mDAAA,GAAsD,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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","file":"index.js","sourcesContent":["import { createPluginContext, formatCurrency, type CurrencyConfig, type EntityLookup } from '@fayz-ai/admin'\nimport type { WorkforcePluginLabels } from './index'\nimport type { WorkforceDataProvider } from './data/types'\nimport type { WorkforceUIState } from './store'\n\n// ---------------------------------------------------------------------------\n// A configuração RESOLVIDA — nada opcional, tudo já mesclado com o padrão.\n// ---------------------------------------------------------------------------\n\nexport interface WorkforceModules {\n /** Escalas: o calendário mensal e o dia. */\n schedules: boolean\n /** Templates: o molde da escala. */\n templates: boolean\n /** Registros de Ponto: a folha, com ajuste auditado. */\n timeEntries: boolean\n /** Fechamento: a competência mensal. */\n periods: boolean\n /** Pessoas & Documentos: a ficha do colaborador. */\n people: boolean\n /** Encargos e Honorários: o custo de pessoal, lido do Financeiro. */\n payrollCosts: boolean\n /**\n * Ficha de RH: vínculo, férias, afastamentos e pendências.\n *\n * Passa pela permissão `workforce_hr.*`, separada de `workforce.*` — quem vê\n * escala e ponto não vê salário nem CID. É o conserto do V1-069, e o FLOW da\n * Ficha diz que ele tinha de ser resolvido ANTES de portar.\n */\n hr: boolean\n}\n\nexport type WorkforceCurrency = CurrencyConfig\n\nexport interface ResolvedWorkforceConfig {\n modules: WorkforceModules\n labels: WorkforcePluginLabels\n currency: WorkforceCurrency\n /** Ver WorkforcePluginOptions.moduleNav. */\n moduleNav?: 'rail' | 'tabs' | 'sidebar'\n /**\n * O valor da hora, quando o app souber dizer.\n *\n * O SQL da jornada NÃO guarda remuneração em lugar nenhum — nem na batida,\n * nem no turno, nem em `public.people`. Sem isto a coluna \"Valor\" da folha\n * não tem de onde sair, e a tela mostra \"—\" em vez de inventar um número.\n */\n hourlyRate?: number\n /** Busca de pessoa para escalar, quando o app quiser oferecer uma. */\n staffLookup?: EntityLookup\n /** Item de nav → feature de acesso, exatamente como o APP declarou. */\n navFeatureMap: Record<string, string>\n}\n\nconst ctx = createPluginContext<ResolvedWorkforceConfig, WorkforceDataProvider, WorkforceUIState>('WorkforcePage')\n\nexport const WorkforceContextProvider = ctx.ContextProvider\nexport const useWorkforceConfig = ctx.useConfig\nexport const useWorkforceProvider = ctx.useProvider\nexport const useWorkforceStore = ctx.useStore\n\nexport { formatCurrency }\n","import React from 'react'\nimport { CalendarDays, Users, Send, Plus } from 'lucide-react'\nimport { Badge, Button, FilterRail, MiniCalendar, RailWorkspace, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Skeleton, toLocalISODate, toast, type MiniCalendarMarker } from '@fayz-ai/ui'\nimport { ScheduleEditor } from '@fayz-ai/admin'\nimport { useWorkforceProvider, useWorkforceStore } from '../context'\nimport type { DaySchedule, ScheduleAssignment } from '../types'\n\n// ---------------------------------------------------------------------------\n// Escalas — o mês e o dia.\n//\n// O calendário é o índice, e o painel da direita é o dia. É a forma que o V1\n// tem e que funciona: ninguém procura uma escala por lista, procura por data.\n//\n// O PREVISTO desta tela é a escala publicada (plg_workforce_schedules +\n// assignments). A grade semanal de disponibilidade de UMA pessoa — que vive em\n// `public.schedules` e que a agenda também lê — é o `ScheduleEditor` do\n// @fayz-ai/admin, embaixo: o mesmo editor da ficha da pessoa, sem um segundo\n// jeito de dizer a mesma coisa.\n// ---------------------------------------------------------------------------\n\nfunction monthBounds(date: string): { from: string; to: string } {\n const d = new Date(`${date}T12:00:00`)\n const first = new Date(d.getFullYear(), d.getMonth(), 1)\n const last = new Date(d.getFullYear(), d.getMonth() + 1, 0)\n return { from: toLocalISODate(first), to: toLocalISODate(last) }\n}\n\nconst STATUS_LABEL: Record<string, string> = {\n draft: 'Rascunho',\n published: 'Publicada',\n closed: 'Fechada',\n}\n\nconst ASSIGNMENT_STATUS_LABEL: Record<string, string> = {\n pending: 'Pendente',\n notified: 'Avisado',\n confirmed: 'Confirmado',\n declined: 'Recusou',\n realized: 'Cumprido',\n}\n\n/** Uma vaga do dia: quem, em que turno, com que resposta. */\nfunction AssignmentRow({ assignment }: { assignment: ScheduleAssignment }) {\n return (\n <div className=\"flex items-center justify-between gap-3 rounded-lg border border-border px-3 py-2\">\n <div className=\"min-w-0\">\n <div className=\"truncate text-sm font-medium\">{assignment.personName ?? 'Sem nome'}</div>\n <div className=\"truncate text-xs text-muted-foreground\">\n {assignment.professionName ?? 'Sem função'}\n {assignment.shiftLabel ? ` · ${assignment.shiftLabel}` : ''}\n {assignment.shiftStartTime ? ` · ${assignment.shiftStartTime}–${assignment.shiftEndTime}` : ''}\n </div>\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n {assignment.role === 'standby' && <Badge variant=\"outline\">Reserva</Badge>}\n <Badge variant={assignment.status === 'confirmed' ? 'success' : assignment.status === 'declined' ? 'destructive' : 'secondary'}>\n {ASSIGNMENT_STATUS_LABEL[assignment.status] ?? assignment.status}\n </Badge>\n </div>\n </div>\n )\n}\n\nexport function SchedulesView() {\n const provider = useWorkforceProvider()\n const selectedDate = useWorkforceStore((s) => s.selectedDate)\n const setSelectedDate = useWorkforceStore((s) => s.setSelectedDate)\n const schedules = useWorkforceStore((s) => s.schedules)\n const loading = useWorkforceStore((s) => s.schedulesLoading)\n const fetchSchedules = useWorkforceStore((s) => s.fetchSchedules)\n const templates = useWorkforceStore((s) => s.templates)\n const fetchTemplates = useWorkforceStore((s) => s.fetchTemplates)\n const staff = useWorkforceStore((s) => s.staff)\n const fetchStaff = useWorkforceStore((s) => s.fetchStaff)\n\n const [month, setMonth] = React.useState(() => monthBounds(selectedDate))\n const [templateId, setTemplateId] = React.useState<string>('')\n const [busy, setBusy] = React.useState(false)\n const [personId, setPersonId] = React.useState<string>('')\n\n React.useEffect(() => { void fetchSchedules(month.from, month.to) }, [fetchSchedules, month.from, month.to])\n React.useEffect(() => { void fetchTemplates() }, [fetchTemplates])\n React.useEffect(() => { void fetchStaff() }, [fetchStaff])\n\n const day: DaySchedule | undefined = schedules.find((s) => s.scheduleDate === selectedDate)\n\n // Um ponto por dia que TEM escala, com a cor dizendo se ela já foi avisada.\n const markers = React.useMemo(() => {\n const out: Record<string, MiniCalendarMarker[]> = {}\n for (const s of schedules) {\n out[s.scheduleDate] = [{\n color: s.status === 'published' ? 'hsl(var(--success))' : 'hsl(var(--warning))',\n label: s.status === 'published' ? 'Escala publicada' : 'Escala em rascunho',\n }]\n }\n return out\n }, [schedules])\n\n async function createFromTemplate() {\n if (!templateId) return\n setBusy(true)\n try {\n await provider.createSchedule({ scheduleDate: selectedDate, templateId })\n await fetchSchedules(month.from, month.to)\n toast.success('Escala criada a partir do molde.')\n } catch (e: any) {\n toast.error(e?.message ?? 'Não foi possível criar a escala.')\n } finally {\n setBusy(false)\n }\n }\n\n async function publish() {\n if (!day) return\n setBusy(true)\n try {\n await provider.publishSchedule(day.id)\n await fetchSchedules(month.from, month.to)\n toast.success('Escala publicada — os titulares foram espelhados na agenda.')\n } catch (e: any) {\n toast.error(e?.message ?? 'Não foi possível publicar a escala.')\n } finally {\n setBusy(false)\n }\n }\n\n const titulares = day?.assignments.filter((a) => a.role === 'titular') ?? []\n const pendentes = titulares.filter((a) => a.status === 'pending' || a.status === 'notified')\n\n // A MESMA coluna da agenda e do check-in — ver FilterRail no design system.\n //\n // Esta tela tinha crescido a própria: um `grid` de 320px com o calendário e\n // um cartão solto embaixo. A largura era outra, a moldura era outra, e a\n // seção não colapsava — a grade semanal de uma pessoa ficava aberta o tempo\n // todo ocupando metade da coluna, mesmo para quem só queria ver o dia.\n //\n // O mini-calendário entra pelo slot `before`, no mesmo lugar em que a agenda\n // o põe: ele é o índice da tela, não um filtro entre outros.\n const rail = (\n <FilterRail\n before={\n <MiniCalendar\n selectedDate={new Date(`${selectedDate}T12:00:00`)}\n onDateSelect={(d) => setSelectedDate(toLocalISODate(d))}\n onMonthChange={(d) => setMonth(monthBounds(toLocalISODate(d)))}\n markers={markers}\n />\n }\n sections={[\n {\n id: 'fixed-hours',\n title: 'Horário fixo da pessoa',\n content: (\n <>\n {/* A grade semanal de UMA pessoa, em `public.schedules`. É o\n editor que a ficha da pessoa já usa — reaproveitado, e não\n reescrito. */}\n <Select value={personId} onValueChange={setPersonId}>\n <SelectTrigger><SelectValue placeholder=\"Escolha quem\" /></SelectTrigger>\n <SelectContent>\n {staff.map((p) => <SelectItem key={p.id} value={p.id}>{p.name}</SelectItem>)}\n </SelectContent>\n </Select>\n {personId && (\n <div className=\"mt-4\">\n <ScheduleEditor assigneeId={personId} />\n </div>\n )}\n </>\n ),\n },\n ]}\n />\n )\n\n return (\n <RailWorkspace rail={rail} className=\"p-6\">\n <div className=\"space-y-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div>\n <h2 className=\"text-lg font-semibold\">\n {new Date(`${selectedDate}T12:00:00`).toLocaleDateString('pt-BR', {\n weekday: 'long', day: '2-digit', month: 'long',\n })}\n </h2>\n {day && (\n <div className=\"mt-1 flex items-center gap-2 text-xs text-muted-foreground\">\n <Badge variant={day.status === 'published' ? 'success' : 'warning'}>\n {STATUS_LABEL[day.status] ?? day.status}\n </Badge>\n <span>{titulares.length} titular(es) · {pendentes.length} pendente(s)</span>\n </div>\n )}\n </div>\n {day && day.status === 'draft' && (\n <Button onClick={publish} disabled={busy}>\n <Send className=\"mr-2 h-4 w-4\" aria-hidden />\n Publicar escala\n </Button>\n )}\n </div>\n\n {loading ? (\n <div className=\"space-y-2\">\n <Skeleton className=\"h-12 w-full\" />\n <Skeleton className=\"h-12 w-full\" />\n </div>\n ) : day ? (\n <div className=\"space-y-2\">\n {day.assignments.length === 0\n ? <p className=\"text-sm text-muted-foreground\">Nenhuma vaga preenchida neste dia.</p>\n : day.assignments.map((a) => <AssignmentRow key={a.id} assignment={a} />)}\n </div>\n ) : (\n // O pré-requisito duro do V1, dito na tela em vez de escondido: sem\n // molde não existe escala.\n <div className=\"rounded-xl border border-dashed border-border p-8 text-center\">\n <CalendarDays className=\"mx-auto mb-3 h-8 w-8 text-muted-foreground\" aria-hidden />\n <p className=\"mb-4 text-sm text-muted-foreground\">\n {templates.length === 0\n ? 'Nenhum molde de escala cadastrado. Crie um em Templates para começar.'\n : 'Ainda não há escala neste dia. Escolha um molde para montá-la.'}\n </p>\n {templates.length > 0 && (\n <div className=\"mx-auto flex max-w-sm items-center gap-2\">\n <Select value={templateId} onValueChange={setTemplateId}>\n <SelectTrigger><SelectValue placeholder=\"Molde de escala\" /></SelectTrigger>\n <SelectContent>\n {templates.map((t) => <SelectItem key={t.id} value={t.id}>{t.name}</SelectItem>)}\n </SelectContent>\n </Select>\n <Button onClick={createFromTemplate} disabled={!templateId || busy}>\n <Plus className=\"mr-2 h-4 w-4\" aria-hidden />\n Criar\n </Button>\n </div>\n )}\n </div>\n )}\n </div>\n </RailWorkspace>\n )\n}\n","import React from 'react'\nimport { LayoutTemplate, Plus, Trash2 } from 'lucide-react'\nimport { Badge, Button, Input, Modal, ModalContent, ModalHeader, ModalTitle, ModalBody, ModalFooter, Skeleton, toast } from '@fayz-ai/ui'\nimport { useWorkforceProvider, useWorkforceStore } from '../context'\nimport type { ScheduleShift, ScheduleTemplate } from '../types'\n\n// ---------------------------------------------------------------------------\n// Templates — o molde da escala.\n//\n// Três níveis, e nesta ordem porque é a ordem em que a casa pensa: o MOLDE\n// (\"Almoço Seg. a Sex.\"), os TURNOS dentro dele (11:00–15:00, seg a sex), e a\n// LOTAÇÃO de cada função no turno (\"Garçom (2)\", \"Cozinha (3)\") — que é o\n// denominador do \"1/1\" que a escala do dia mostra.\n// ---------------------------------------------------------------------------\n\nconst WEEKDAYS = ['D', 'S', 'T', 'Q', 'Q', 'S', 'S']\n\nfunction ShiftCard({ shift, onChanged }: { shift: ScheduleShift; onChanged: () => void }) {\n const provider = useWorkforceProvider()\n const [profession, setProfession] = React.useState('')\n const [count, setCount] = React.useState('1')\n\n async function addRequirement() {\n if (!profession.trim()) return\n try {\n await provider.saveRequirement({\n shiftId: shift.id,\n professionName: profession.trim(),\n requiredCount: Math.max(1, Number(count) || 1),\n })\n setProfession('')\n setCount('1')\n onChanged()\n } catch (e: any) {\n toast.error(e?.message ?? 'Não foi possível salvar a função.')\n }\n }\n\n async function removeRequirement(id: string) {\n try {\n await provider.deleteRequirement(id)\n onChanged()\n } catch (e: any) {\n toast.error(e?.message ?? 'Não foi possível remover a função.')\n }\n }\n\n async function removeShift() {\n try {\n await provider.deleteShift(shift.id)\n onChanged()\n } catch (e: any) {\n toast.error(e?.message ?? 'Não foi possível remover o turno.')\n }\n }\n\n return (\n <div className=\"rounded-lg border border-border p-3\">\n <div className=\"flex items-start justify-between gap-3\">\n <div>\n <div className=\"text-sm font-medium\">{shift.label}</div>\n <div className=\"text-xs text-muted-foreground\">\n {shift.startTime}–{shift.endTime}\n {/* Turno que vira o dia é normal em restaurante — e é dito, não escondido. */}\n {shift.crossesMidnight ? ' · vira o dia' : ''}\n </div>\n <div className=\"mt-1 flex gap-1\">\n {WEEKDAYS.map((d, i) => (\n <span\n key={i}\n className={`inline-flex h-5 w-5 items-center justify-center rounded text-[10px] ${\n shift.weekdays.includes(i) ? 'bg-primary/15 text-primary' : 'bg-muted text-muted-foreground'\n }`}\n >\n {d}\n </span>\n ))}\n </div>\n </div>\n <Button variant=\"ghost\" size=\"sm\" onClick={removeShift} aria-label=\"Remover turno\">\n <Trash2 className=\"h-4 w-4\" aria-hidden />\n </Button>\n </div>\n\n <div className=\"mt-3 flex flex-wrap gap-2\">\n {shift.requirements.map((r) => (\n <Badge key={r.id} variant=\"outline\" className=\"gap-1\">\n {r.professionName} ({r.requiredCount})\n <button onClick={() => removeRequirement(r.id)} aria-label={`Remover ${r.professionName}`}>\n <Trash2 className=\"h-3 w-3\" aria-hidden />\n </button>\n </Badge>\n ))}\n </div>\n\n <div className=\"mt-3 flex items-center gap-2\">\n <Input\n value={profession}\n onChange={(e) => setProfession(e.target.value)}\n placeholder=\"Função (ex.: Garçom)\"\n className=\"h-8\"\n />\n <Input\n value={count}\n onChange={(e) => setCount(e.target.value)}\n type=\"number\"\n min={1}\n className=\"h-8 w-20\"\n aria-label=\"Vagas\"\n />\n <Button size=\"sm\" variant=\"secondary\" onClick={addRequirement}>Adicionar</Button>\n </div>\n </div>\n )\n}\n\nfunction TemplateCard({ template, onChanged }: { template: ScheduleTemplate; onChanged: () => void }) {\n const provider = useWorkforceProvider()\n const [open, setOpen] = React.useState(false)\n const [label, setLabel] = React.useState('')\n const [start, setStart] = React.useState('11:00')\n const [end, setEnd] = React.useState('15:00')\n const [weekdays, setWeekdays] = React.useState<number[]>([1, 2, 3, 4, 5])\n\n async function addShift() {\n if (!label.trim()) return\n try {\n await provider.saveShift({\n templateId: template.id,\n label: label.trim(),\n startTime: start,\n endTime: end,\n weekdays,\n sortOrder: template.shifts.length,\n })\n setOpen(false)\n setLabel('')\n onChanged()\n } catch (e: any) {\n toast.error(e?.message ?? 'Não foi possível salvar o turno.')\n }\n }\n\n async function removeTemplate() {\n try {\n await provider.deleteTemplate(template.id)\n onChanged()\n } catch (e: any) {\n toast.error(e?.message ?? 'Não foi possível remover o molde.')\n }\n }\n\n return (\n <div className=\"rounded-xl border border-border p-4\">\n <div className=\"mb-3 flex items-center justify-between gap-3\">\n <div>\n <div className=\"font-medium\">{template.name}</div>\n <div className=\"text-xs text-muted-foreground\">{template.shifts.length} turno(s)</div>\n </div>\n <div className=\"flex items-center gap-2\">\n <Button size=\"sm\" variant=\"secondary\" onClick={() => setOpen(true)}>\n <Plus className=\"mr-1 h-4 w-4\" aria-hidden /> Turno\n </Button>\n <Button size=\"sm\" variant=\"ghost\" onClick={removeTemplate} aria-label=\"Remover molde\">\n <Trash2 className=\"h-4 w-4\" aria-hidden />\n </Button>\n </div>\n </div>\n\n <div className=\"space-y-2\">\n {template.shifts.length === 0\n ? <p className=\"text-sm text-muted-foreground\">Nenhum turno neste molde ainda.</p>\n : template.shifts.map((s) => <ShiftCard key={s.id} shift={s} onChanged={onChanged} />)}\n </div>\n\n <Modal open={open} onOpenChange={setOpen}>\n <ModalContent size=\"sm\">\n <ModalHeader><ModalTitle>Novo turno</ModalTitle></ModalHeader>\n <ModalBody className=\"space-y-3\">\n <Input value={label} onChange={(e) => setLabel(e.target.value)} placeholder=\"Nome do turno (ex.: Almoço)\" />\n <div className=\"flex items-center gap-2\">\n <Input type=\"time\" value={start} onChange={(e) => setStart(e.target.value)} aria-label=\"Início\" />\n <span className=\"text-muted-foreground\">até</span>\n <Input type=\"time\" value={end} onChange={(e) => setEnd(e.target.value)} aria-label=\"Fim\" />\n </div>\n <div className=\"flex gap-1\">\n {WEEKDAYS.map((d, i) => (\n <button\n key={i}\n type=\"button\"\n onClick={() => setWeekdays((w) => (w.includes(i) ? w.filter((x) => x !== i) : [...w, i]))}\n className={`h-8 w-8 rounded text-xs ${\n weekdays.includes(i) ? 'bg-primary text-primary-foreground' : 'bg-muted text-muted-foreground'\n }`}\n >\n {d}\n </button>\n ))}\n </div>\n </ModalBody>\n <ModalFooter>\n <Button variant=\"ghost\" onClick={() => setOpen(false)}>Cancelar</Button>\n <Button onClick={addShift}>Salvar turno</Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n </div>\n )\n}\n\nexport function TemplatesView() {\n const provider = useWorkforceProvider()\n const templates = useWorkforceStore((s) => s.templates)\n const loading = useWorkforceStore((s) => s.templatesLoading)\n const fetchTemplates = useWorkforceStore((s) => s.fetchTemplates)\n const [open, setOpen] = React.useState(false)\n const [name, setName] = React.useState('')\n\n React.useEffect(() => { void fetchTemplates() }, [fetchTemplates])\n\n async function createTemplate() {\n if (!name.trim()) return\n try {\n await provider.saveTemplate({ name: name.trim() })\n setName('')\n setOpen(false)\n await fetchTemplates()\n } catch (e: any) {\n toast.error(e?.message ?? 'Não foi possível criar o molde.')\n }\n }\n\n return (\n <div className=\"space-y-4 p-6\">\n <div className=\"flex items-center justify-between gap-3\">\n <div>\n <h2 className=\"text-lg font-semibold\">Templates de escala</h2>\n <p className=\"text-sm text-muted-foreground\">\n O molde vem primeiro: sem ele não se cria escala nenhuma.\n </p>\n </div>\n <Button onClick={() => setOpen(true)}>\n <Plus className=\"mr-2 h-4 w-4\" aria-hidden /> Novo molde\n </Button>\n </div>\n\n {loading ? (\n <div className=\"space-y-2\"><Skeleton className=\"h-24 w-full\" /><Skeleton className=\"h-24 w-full\" /></div>\n ) : templates.length === 0 ? (\n <div className=\"rounded-xl border border-dashed border-border p-8 text-center\">\n <LayoutTemplate className=\"mx-auto mb-3 h-8 w-8 text-muted-foreground\" aria-hidden />\n <p className=\"text-sm text-muted-foreground\">Nenhum molde cadastrado.</p>\n </div>\n ) : (\n <div className=\"grid gap-4 md:grid-cols-2\">\n {templates.map((t) => <TemplateCard key={t.id} template={t} onChanged={() => void fetchTemplates()} />)}\n </div>\n )}\n\n <Modal open={open} onOpenChange={setOpen}>\n <ModalContent size=\"sm\">\n <ModalHeader><ModalTitle>Novo molde de escala</ModalTitle></ModalHeader>\n <ModalBody>\n <Input value={name} onChange={(e) => setName(e.target.value)} placeholder=\"Nome (ex.: Almoço Seg. a Sex.)\" />\n </ModalBody>\n <ModalFooter>\n <Button variant=\"ghost\" onClick={() => setOpen(false)}>Cancelar</Button>\n <Button onClick={createTemplate}>Criar</Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n </div>\n )\n}\n","import React from 'react'\nimport { Clock, AlertTriangle, Pencil, Lock, Eye, Users, MapPin, ScanFace, ImageOff } from 'lucide-react'\nimport { Avatar, AvatarFallback, AvatarImage, Badge, Button, DateRangeControl, Input, Modal, PageToolbar, ModalContent, ModalHeader, ModalTitle, ModalBody, ModalFooter, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Skeleton, toast } from '@fayz-ai/ui'\nimport { PersonLink } from '@fayz-ai/admin'\nimport { formatCurrency, useWorkforceConfig, useWorkforceProvider, useWorkforceStore } from '../context'\nimport type { AnalyticsDateRange } from '@fayz-ai/core'\nimport { resolveRangePreset, type AnalyticsRangePreset } from '@fayz-ai/ui'\nimport type { PunchPhoto, TimeAdjustmentAction, TimeEntry, WorkDay } from '../types'\n\n// ---------------------------------------------------------------------------\n// Registros de Ponto.\n//\n// A FORMA desta tela é deliberadamente a do V1, e não uma reinvenção: uma\n// tabela por dia, uma linha por pessoa, com Nome · Unidade · Entrada · Saída ·\n// Duração · Valor · Escala · Ações. Quem confere ponto já conferiu mil vezes\n// nessa grade, lendo as colunas na mesma ordem; mudar o arranjo obrigaria a\n// pessoa a reaprender a própria rotina para ganhar nada.\n//\n// Um cartão por pessoa-dia, que era o desenho anterior, empilha 299 cartões num\n// mês e some com a comparação lado a lado — que é o gesto da conferência.\n//\n// O que MUDA em relação ao V1, e muda porque lá está errado:\n//\n// · o V1 marca 325 de 325 batidas como \"Fora da escala\", porque cruza só para\n// profissional e com a data em UTC. Aqui o selo vem de `v_workforce_day`,\n// que cruza de verdade e sabe dizer FALTA (escala sem ponto) de FORA DA\n// ESCALA (ponto sem escala) — duas assimetrias que o V1 não distingue.\n//\n// · Ajustar não edita a batida. Grava uma linha em\n// `plg_workforce_time_adjustments` com motivo obrigatório, e o horário real\n// continua à vista, riscado. É o que torna o ponto prova em vez de um campo\n// que alguém mexeu.\n// ---------------------------------------------------------------------------\n\nconst KIND_LABEL: Record<string, string> = {\n clock_in: 'Entrada',\n break_start: 'Saída p/ intervalo',\n break_end: 'Volta do intervalo',\n clock_out: 'Saída',\n}\n\nfunction firstOfMonth(): string {\n const d = new Date()\n return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-01`\n}\n\nfunction todayISO(): string {\n const d = new Date()\n return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`\n}\n\nfunction hhmm(iso?: string | null): string {\n if (!iso) return '—'\n return new Date(iso).toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' })\n}\n\n/** Minutos em '7h30'. Quem confere folha lê horas, não decimais. */\nfunction hours(minutes?: number | null): string {\n if (minutes == null) return '—'\n const sign = minutes < 0 ? '-' : ''\n const abs = Math.abs(minutes)\n return `${sign}${Math.floor(abs / 60)}h${String(abs % 60).padStart(2, '0')}`\n}\n\n/** Iniciais para o avatar. Duas letras: mais que isso vira sopa em 32px. */\nfunction iniciais(nome?: string | null): string {\n const partes = (nome ?? '').trim().split(/\\s+/).filter(Boolean)\n if (!partes.length) return '—'\n return (partes[0][0] + (partes.length > 1 ? partes[partes.length - 1][0] : '')).toUpperCase()\n}\n\n/**\n * As URLs assinadas da PÁGINA, num mapa só.\n *\n * O bucket é privado, então toda URL tem prazo — cinco minutos, o mesmo do V1 —\n * e por isso ela não pode ser guardada na linha nem num cache de dados: uma URL\n * assinada vencida em cache é uma imagem quebrada que ninguém sabe explicar.\n *\n * O que mudou foi ONDE se assina. Assinar dentro de cada avatar custava uma\n * requisição por linha: trinta dias do Pertinho do Céu são 261 linhas, e a\n * primeira cara só aparecia depois de 261 idas ao storage. Aqui a página inteira\n * vai numa chamada, e as linhas leem o resultado.\n */\nconst FotosContext = React.createContext<Record<string, string>>({})\n\nfunction usePunchPhotoUrl(photo?: PunchPhoto | null): string | null {\n const mapa = React.useContext(FotosContext)\n if (!photo) return null\n return mapa[`${photo.bucket}/${photo.path}`] ?? null\n}\n\n/** Assina, de uma vez, as fotos das batidas que a página vai desenhar. */\nfunction useFotosDaPagina(entries: TimeEntry[]): Record<string, string> {\n const provider = useWorkforceProvider()\n const [mapa, setMapa] = React.useState<Record<string, string>>({})\n // A chave é a LISTA de fotos, não o array de batidas: paginar não muda as\n // batidas carregadas, muda quais delas estão à vista, e reassinar as mesmas\n // fotos a cada troca de página seria a ida ao storage que este código existe\n // para evitar.\n const chave = React.useMemo(\n () => entries.map((e) => (e.photo ? `${e.photo.bucket}/${e.photo.path}` : '')).filter(Boolean).sort().join('|'),\n [entries],\n )\n React.useEffect(() => {\n const fotos = entries.map((e) => e.photo).filter(Boolean) as PunchPhoto[]\n if (!fotos.length) { setMapa({}); return }\n let vivo = true\n provider.signPunchPhotos(fotos)\n .then((m) => { if (vivo) setMapa(m) })\n .catch(() => { if (vivo) setMapa({}) })\n return () => { vivo = false }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [provider, chave])\n return mapa\n}\n\n/** A leitura tipada do que o totem gravou. Ausente é uma resposta legítima. */\nfunction provaDe(entry: TimeEntry): {\n lat?: number; lng?: number; accuracy?: number; faceScore?: number; naoMigrada: boolean\n} {\n const e = (entry.evidence ?? {}) as Record<string, unknown>\n const num = (v: unknown) => (typeof v === 'number' ? v : typeof v === 'string' ? Number(v) : undefined)\n return {\n lat: num(e.lat),\n lng: num(e.lng),\n accuracy: num(e.accuracy_m),\n faceScore: num(e.face_score),\n // Houve captura E a imagem não atravessou. É o estado que a tela precisa\n // distinguir de \"não houve captura\" — dizer \"sem foto\" nos dois casos\n // esconderia 1.320 imagens que existem e não chegaram.\n naoMigrada: !!e.photo_path && !entry.photo,\n }\n}\n\nfunction diasAtras(n: number): string {\n const d = new Date(Date.now() - n * 86400000)\n return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`\n}\n\n/** A cara de quem bateu, quando os bytes atravessaram. */\nfunction FotoDaBatida({ entry, className }: { entry: TimeEntry; className?: string }) {\n const url = usePunchPhotoUrl(entry.photo)\n return (\n <Avatar className={className ?? 'h-8 w-8 shrink-0'}>\n {url && <AvatarImage src={url} alt={`Foto da batida de ${entry.personName ?? 'quem bateu'}`} />}\n <AvatarFallback>{iniciais(entry.personName)}</AvatarFallback>\n </Avatar>\n )\n}\n\n/**\n * A prova que o totem produziu, numa linha: a foto, a coordenada com precisão e\n * o score facial — os quatro campos que o V1 mostra e que fazem uma batida\n * contestada ter defesa.\n *\n * Os três últimos chegaram pelo porte desde a primeira onda. A FOTO não: até a\n * migration 054 do base e a 001 deste plugin, `evidence.photo_path` guardava o\n * caminho de um bucket privado de OUTRO projeto Supabase — 1.320 imagens\n * referenciadas e nenhuma alcançável. Por isso o estado \"não migrada\" é DITO em\n * vez de virar um espaço vazio: espaço vazio lê-se como \"não houve captura\", que\n * é uma afirmação diferente e falsa.\n */\nfunction ProvaDoTotem({ entry }: { entry: TimeEntry }) {\n const p = provaDe(entry)\n const temAlgo = entry.photo || p.naoMigrada || p.lat != null || p.faceScore != null\n if (!temAlgo) return null\n return (\n <div className=\"flex items-center gap-3 pt-1\">\n {entry.photo ? (\n <FotoDaBatida entry={entry} className=\"h-12 w-12 shrink-0 rounded-md\" />\n ) : p.naoMigrada ? (\n <span\n className=\"flex h-12 w-12 shrink-0 items-center justify-center rounded-md border border-dashed border-border text-muted-foreground\"\n title=\"O totem capturou a foto; a imagem ainda não atravessou do V1\"\n >\n <ImageOff className=\"h-4 w-4\" aria-hidden />\n </span>\n ) : null}\n <div className=\"flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground\">\n {p.lat != null && p.lng != null && (\n <span className=\"flex items-center gap-1\">\n <MapPin className=\"h-3.5 w-3.5\" aria-hidden />\n {p.lat.toFixed(5)}, {p.lng.toFixed(5)}\n {p.accuracy != null && <> · ± {Math.round(p.accuracy)}m</>}\n </span>\n )}\n {p.faceScore != null && (\n <span className=\"flex items-center gap-1\">\n <ScanFace className=\"h-3.5 w-3.5\" aria-hidden />\n Match facial {(p.faceScore * 100).toFixed(1)}%\n </span>\n )}\n {p.naoMigrada && <span>Foto capturada no V1, ainda não migrada</span>}\n </div>\n </div>\n )\n}\n\n/**\n * O dossiê do dia: cada batida, o horário REAL ao lado do ajustado, quem\n * ajustou, e a prova que o totem produziu.\n */\nfunction DetalhesDoDia({ day, entries, onClose }: {\n day: WorkDay\n entries: TimeEntry[]\n onClose: () => void\n}) {\n return (\n <Modal open onOpenChange={(o) => { if (!o) onClose() }}>\n <ModalContent>\n <ModalHeader>\n <ModalTitle>{day.personName ?? 'Sem nome'} · {day.workDate}</ModalTitle>\n </ModalHeader>\n <ModalBody className=\"space-y-3\">\n <div className=\"flex flex-wrap gap-4 text-sm\">\n <span>Previsto <b>{hours(day.plannedMinutes)}</b></span>\n <span>Realizado <b>{hours(day.workedMinutes)}</b></span>\n {day.varianceMinutes != null && (\n <span>Saldo <b>{day.varianceMinutes >= 0 ? '+' : ''}{hours(day.varianceMinutes)}</b></span>\n )}\n {day.shiftLabel && (\n <span className=\"text-muted-foreground\">\n Turno {day.shiftLabel} {day.shiftStartTime}–{day.shiftEndTime}\n </span>\n )}\n </div>\n <div className=\"divide-y divide-border rounded-lg border border-border\">\n {entries.length === 0 ? (\n <p className=\"px-3 py-2 text-sm text-muted-foreground\">Nenhuma batida neste dia.</p>\n ) : entries.map((e) => (\n <div key={e.id} className=\"px-3 py-2 text-sm\">\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"flex items-center gap-2\">\n <Clock className=\"h-3.5 w-3.5 text-muted-foreground\" aria-hidden />\n <span className={e.voided ? 'text-muted-foreground line-through' : ''}>\n {KIND_LABEL[e.kind] ?? e.kind} · {hhmm(e.effectiveAt)}\n </span>\n {e.adjusted && (\n // O real fica à vista, riscado. Esconder o horário original\n // transformaria o ajuste numa edição, que é justamente o que\n // o modelo append-only existe para impedir.\n <span className=\"text-xs text-muted-foreground\">\n (real <s>{hhmm(e.punchedAt)}</s>)\n </span>\n )}\n </span>\n {e.adjusted && (\n <span className=\"text-xs text-muted-foreground\">\n {e.adjustedByName ?? 'alguém'}: {e.adjustmentReason}\n </span>\n )}\n </div>\n <ProvaDoTotem entry={e} />\n </div>\n ))}\n </div>\n </ModalBody>\n <ModalFooter>\n <Button variant=\"outline\" onClick={onClose}>Fechar</Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n )\n}\n\n/** O diálogo de ajuste. Motivo obrigatório — o banco recusa em branco. */\nfunction AdjustDialog({ entry, onClose, onSaved }: {\n entry: TimeEntry\n onClose: () => void\n onSaved: () => void\n}) {\n const provider = useWorkforceProvider()\n const [action, setAction] = React.useState<TimeAdjustmentAction>('correct')\n const [time, setTime] = React.useState(() => new Date(entry.effectiveAt).toTimeString().slice(0, 5))\n const [reason, setReason] = React.useState('')\n const [busy, setBusy] = React.useState(false)\n\n async function save() {\n if (!reason.trim()) {\n toast.error('O motivo é obrigatório.')\n return\n }\n setBusy(true)\n try {\n await provider.adjustTimeEntry({\n timeEntryId: entry.id,\n action,\n effectiveAt: action === 'void' ? undefined : new Date(`${entry.workDate}T${time}:00`).toISOString(),\n reason: reason.trim(),\n })\n toast.success('Ajuste registrado. O horário real foi preservado.')\n onSaved()\n onClose()\n } catch (e: any) {\n toast.error(e?.message ?? 'Não foi possível registrar o ajuste.')\n } finally {\n setBusy(false)\n }\n }\n\n return (\n <Modal open onOpenChange={(o) => { if (!o) onClose() }}>\n <ModalContent size=\"sm\">\n <ModalHeader><ModalTitle>Ajustar batida</ModalTitle></ModalHeader>\n <ModalBody className=\"space-y-3\">\n <p className=\"text-xs text-muted-foreground\">\n {entry.personName ?? 'Sem nome'} · {KIND_LABEL[entry.kind] ?? entry.kind} ·\n {' '}registrado às {hhmm(entry.punchedAt)}\n </p>\n <Select value={action} onValueChange={(v) => setAction(v as TimeAdjustmentAction)}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n <SelectItem value=\"correct\">Corrigir o horário</SelectItem>\n <SelectItem value=\"insert\">Inserir a batida que faltou</SelectItem>\n <SelectItem value=\"void\">Anular esta batida</SelectItem>\n </SelectContent>\n </Select>\n {action !== 'void' && (\n <Input type=\"time\" value={time} onChange={(e) => setTime(e.target.value)} aria-label=\"Horário que passa a valer\" />\n )}\n <Input\n value={reason}\n onChange={(e) => setReason(e.target.value)}\n placeholder=\"Motivo (obrigatório)\"\n />\n </ModalBody>\n <ModalFooter>\n <Button variant=\"ghost\" onClick={onClose}>Cancelar</Button>\n <Button onClick={save} disabled={busy}>Registrar ajuste</Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n )\n}\n\n/**\n * Um relógio que anda de minuto em minuto.\n *\n * \"Está dentro há 6h58\" é uma frase que envelhece, e envelhecer em silêncio é o\n * que a tornaria pior que não dizer nada. De minuto e não de segundo porque a\n * folha de ponto se lê em minutos — um tique por segundo repintaria 299 linhas\n * para mover um dígito que ninguém acompanha.\n */\nfunction useAgora(ativo: boolean): number {\n const [agora, setAgora] = React.useState(() => Date.now())\n React.useEffect(() => {\n if (!ativo) return\n const id = setInterval(() => setAgora(Date.now()), 60_000)\n return () => clearInterval(id)\n }, [ativo])\n return agora\n}\n\n// Acima disto, \"em curso\" deixa de ser a explicação provável. A jornada mais\n// longa do vocabulário do V1 é a 12x36 — doze horas —, então dezesseis dá\n// margem para o turno que vira a noite e ainda separa com folga o caso real:\n// alguém que foi embora e não bateu a saída. Chamar as duas coisas de \"em\n// curso\" faria a tela afirmar que a pessoa está no local há dois dias.\nconst LIMITE_EM_CURSO_MIN = 16 * 60\n\n/**\n * A coluna Duração.\n *\n * Até a migration 003 ela mostrava `-497155h02` em todo ponto em aberto — o\n * epoch da entrada, com o sinal trocado, vazando para a tela. A conta foi\n * corrigida lá; o que ficou para cá é a pergunta que o número sozinho não\n * responde: um dia em aberto tem DUAS quantidades, o que já fechou e o que está\n * correndo, e mostrar só a primeira com um \"(parcial)\" ao lado obrigava quem\n * confere a abrir os detalhes para saber desde quando.\n */\nfunction Duracao({ day, agora }: { day: WorkDay; agora: number }) {\n // Fechou, e fechou com uma duração que não é jornada. O número MEDIDO fica à\n // vista — é ele que faz a pessoa procurar a batida — e o motivo fica escrito\n // ao lado, com quantos dias separam a entrada da saída, que é a pista.\n if (day.reviewReason === 'span_too_long') {\n const dias = day.firstIn && day.lastOut\n ? Math.round((new Date(day.lastOut).getTime() - new Date(day.firstIn).getTime()) / 86400000)\n : 0\n return (\n <>\n <span className=\"text-destructive\">{hours(day.workedMinutes)}</span>\n <span\n className=\"block text-xs text-destructive\"\n title=\"Fora da soma: acima de 16h num dia é saída não batida, não jornada. Corrija pelo botão Ajustar.\"\n >\n revisar · {dias > 0 ? `saída ${dias}d depois` : 'saída no dia seguinte'}\n </span>\n </>\n )\n }\n if (!day.isOpen) {\n return <>{hours(day.workedMinutes)}</>\n }\n const fechadas = day.workedMinutes ?? 0\n const correndo = day.openSince\n ? Math.max(0, Math.round((agora - new Date(day.openSince).getTime()) / 60000))\n : null\n const esquecido = correndo != null && correndo > LIMITE_EM_CURSO_MIN\n\n const correndoTexto = correndo == null\n ? 'em aberto'\n : esquecido\n ? `sem saída há ${hours(correndo)}`\n : `${hours(correndo)} em curso`\n const cor = esquecido ? 'text-destructive' : 'text-muted-foreground'\n const desde = day.openSince\n ? `Aberto desde ${new Date(day.openSince).toLocaleString('pt-BR')}`\n : undefined\n\n // Nada fechado ainda: o \"em curso\" vira a linha principal. Um travessão em\n // cima dele seria duas linhas para dizer uma coisa só, e a primeira das duas\n // diria \"sem duração\" ao lado de uma duração.\n if (fechadas === 0) {\n return <span className={cor} title={desde}>{correndoTexto}</span>\n }\n return (\n <>\n {hours(fechadas)}\n <span className={`block text-xs ${cor}`} title={desde}>+ {correndoTexto}</span>\n </>\n )\n}\n\n/** O selo da coluna Escala. Três estados, na precedência do V1. */\nfunction SeloEscala({ day }: { day: WorkDay }) {\n if (day.absent) return <Badge variant=\"destructive\">Falta</Badge>\n if (day.outsideSchedule) return <Badge variant=\"destructive\">Fora da escala</Badge>\n return <Badge variant=\"success\">Na escala</Badge>\n}\n\n/** Uma pessoa numa linha da tabela do dia. */\nfunction LinhaPessoa({ day, entries, unitName, agora, onAdjust, onDetails }: {\n day: WorkDay\n entries: TimeEntry[]\n unitName: string\n /** O relógio vem de cima: um `setInterval` por linha seriam 299 deles. */\n agora: number\n onAdjust: (entry: TimeEntry) => void\n onDetails: (day: WorkDay) => void\n}) {\n const { currency, hourlyRate, staffLookup } = useWorkforceConfig()\n // Valor só sai de hora que conta. Precificar um dia de 45h que ninguém\n // trabalhou seria levar o erro da tela para dentro do dinheiro.\n const value = hourlyRate != null && day.workedMinutes != null && !day.reviewReason\n ? (day.workedMinutes / 60) * hourlyRate\n : null\n // Ajustar age sobre a ÚLTIMA batida do dia: é a que está aberta quando o\n // ponto está aberto, e é a que alguém corrige quando esqueceu de bater a saída.\n const alvo = entries.length ? entries[entries.length - 1] : null\n const travado = entries.some((e) => e.payableInvoiceId)\n // A cara do dia é a da ENTRADA, e não a foto do cadastro: quem confere ponto\n // está conferindo se quem bateu é quem devia bater, e o retrato do cadastro\n // responde a outra pergunta. Sem foto de entrada, qualquer batida com foto\n // serve — a saída também é a pessoa. Sem nenhuma, as iniciais.\n const retrato = entries.find((e) => e.kind === 'clock_in' && e.photo)\n ?? entries.find((e) => e.photo)\n ?? null\n\n return (\n <tr className=\"border-b border-border last:border-0 hover:bg-muted/40\">\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-3\">\n {retrato ? (\n <FotoDaBatida entry={retrato} />\n ) : (\n <Avatar className=\"h-8 w-8 shrink-0\">\n <AvatarFallback>{iniciais(day.personName)}</AvatarFallback>\n </Avatar>\n )}\n <div className=\"min-w-0\">\n <PersonLink\n personId={day.personId}\n name={day.personName ?? 'Sem nome'}\n kind=\"staff\"\n lookup={staffLookup}\n size=\"sm\"\n className=\"text-sm\"\n />\n <div className=\"text-xs text-muted-foreground\">Profissional</div>\n </div>\n </div>\n </td>\n <td className=\"px-4 py-3 text-sm text-muted-foreground\">{unitName}</td>\n <td className=\"px-4 py-3 text-sm tabular-nums\">{hhmm(day.firstIn)}</td>\n <td className=\"px-4 py-3 text-sm tabular-nums\">\n {day.isOpen\n ? <Badge variant=\"outline\">Em aberto</Badge>\n : hhmm(day.lastOut)}\n </td>\n <td className=\"px-4 py-3 text-sm tabular-nums\"><Duracao day={day} agora={agora} /></td>\n <td className=\"px-4 py-3 text-sm tabular-nums\">\n {value != null ? formatCurrency(value, currency) : '—'}\n </td>\n <td className=\"px-4 py-3\"><SeloEscala day={day} /></td>\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-1\">\n {travado ? (\n // A trava do banco, dita na tela: hora já paga não se corrige sem\n // reabrir a competência.\n <span className=\"flex items-center gap-1 px-2 text-xs text-muted-foreground\">\n <Lock className=\"h-3.5 w-3.5\" aria-hidden /> já paga\n </span>\n ) : alvo ? (\n <Button size=\"sm\" variant=\"ghost\" onClick={() => onAdjust(alvo)}>\n <Pencil className=\"mr-1 h-3.5 w-3.5\" aria-hidden /> Ajustar\n </Button>\n ) : null}\n <Button size=\"sm\" variant=\"ghost\" onClick={() => onDetails(day)}>\n <Eye className=\"mr-1 h-3.5 w-3.5\" aria-hidden /> Detalhes\n </Button>\n </div>\n </td>\n </tr>\n )\n}\n\n/** \"Hoje, sexta-feira, 18 de setembro de 2026\" — como o V1 escreve. */\nfunction tituloDoDia(workDate: string): string {\n const d = new Date(`${workDate}T12:00:00`)\n const hoje = new Date()\n const iso = (x: Date) => `${x.getFullYear()}-${String(x.getMonth() + 1).padStart(2, '0')}-${String(x.getDate()).padStart(2, '0')}`\n const ontem = new Date(hoje.getTime() - 86400000)\n const extenso = d.toLocaleDateString('pt-BR', { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' })\n if (workDate === iso(hoje)) return `Hoje, ${extenso}`\n if (workDate === iso(ontem)) return `Ontem, ${extenso}`\n return extenso.charAt(0).toUpperCase() + extenso.slice(1)\n}\n\n/** Um dia: a faixa de cabeçalho com os totais, e a tabela das pessoas. */\nfunction GrupoDoDia({ workDate, days, entriesByPerson, unitNames, agora, onAdjust, onDetails }: {\n workDate: string\n days: WorkDay[]\n entriesByPerson: Map<string, TimeEntry[]>\n unitNames: Map<string, string>\n agora: number\n onAdjust: (entry: TimeEntry) => void\n onDetails: (day: WorkDay) => void\n}) {\n const { currency, hourlyRate } = useWorkforceConfig()\n const pessoas = new Set(days.map((d) => d.personId)).size\n const abertos = days.filter((d) => d.isOpen).length\n const revisar = days.filter((d) => d.reviewReason === 'span_too_long').length\n // UMA regra: dia que o banco marcou com motivo não soma. Era só \"ponto\n // aberto\" até a 004 — contar uma jornada que não terminou inventa hora que\n // ninguém trabalhou —, e um dia de 45h é o mesmo problema com outra cara. Por\n // isso os contadores ficam ao lado: o total é honesto E incompleto, e a tela\n // diz as duas coisas em vez de escolher uma.\n const minutos = days.reduce((sum, d) => sum + (d.reviewReason ? 0 : (d.workedMinutes ?? 0)), 0)\n const valor = hourlyRate != null ? (minutos / 60) * hourlyRate : null\n\n return (\n <div className=\"overflow-hidden rounded-xl border border-border\">\n <div className=\"flex flex-wrap items-center gap-4 border-l-2 border-l-primary bg-muted/40 px-4 py-3\">\n <span className=\"text-sm font-semibold\">{tituloDoDia(workDate)}</span>\n <span className=\"flex items-center gap-1 text-xs text-muted-foreground\">\n <Users className=\"h-3.5 w-3.5\" aria-hidden /> {pessoas} pessoa{pessoas === 1 ? '' : 's'}\n </span>\n {abertos > 0 && (\n <span className=\"flex items-center gap-1 text-xs font-medium text-warning\">\n <AlertTriangle className=\"h-3.5 w-3.5\" aria-hidden /> {abertos} em aberto\n </span>\n )}\n {revisar > 0 && (\n <span\n className=\"flex items-center gap-1 text-xs font-medium text-destructive\"\n title=\"Dias acima de 16h — saída não batida. Fora do total até serem ajustados.\"\n >\n <AlertTriangle className=\"h-3.5 w-3.5\" aria-hidden /> {revisar} a revisar\n </span>\n )}\n <span className=\"flex items-center gap-1 text-xs text-muted-foreground\">\n <Clock className=\"h-3.5 w-3.5\" aria-hidden /> {hours(minutos)}\n </span>\n {valor != null && valor > 0 && (\n <span className=\"text-xs font-medium text-success\">{formatCurrency(valor, currency)}</span>\n )}\n </div>\n\n <div className=\"overflow-x-auto\">\n <table className=\"w-full min-w-[860px] border-collapse text-left\">\n <thead>\n <tr className=\"border-b border-border text-xs font-medium text-muted-foreground\">\n <th scope=\"col\" className=\"px-4 py-2\">Nome</th>\n <th scope=\"col\" className=\"px-4 py-2\">Unidade</th>\n <th scope=\"col\" className=\"px-4 py-2\">Entrada</th>\n <th scope=\"col\" className=\"px-4 py-2\">Saída</th>\n <th scope=\"col\" className=\"px-4 py-2\">Duração</th>\n <th scope=\"col\" className=\"px-4 py-2\">Valor</th>\n <th scope=\"col\" className=\"px-4 py-2\">Escala</th>\n <th scope=\"col\" className=\"px-4 py-2\">Ações</th>\n </tr>\n </thead>\n <tbody>\n {days.map((d) => (\n <LinhaPessoa\n key={`${d.personId}|${d.workDate}`}\n day={d}\n entries={entriesByPerson.get(`${d.personId}|${d.workDate}`) ?? []}\n unitName={(d.unitId && unitNames.get(d.unitId)) || '—'}\n agora={agora}\n onAdjust={onAdjust}\n onDetails={onDetails}\n />\n ))}\n </tbody>\n </table>\n </div>\n </div>\n )\n}\n\nexport function TimeEntriesView() {\n const { currency, hourlyRate } = useWorkforceConfig()\n const entries = useWorkforceStore((s) => s.entries)\n const days = useWorkforceStore((s) => s.days)\n const loading = useWorkforceStore((s) => s.timeLoading)\n const fetchTime = useWorkforceStore((s) => s.fetchTime)\n\n // O MESMO controle de período do /analytics — extraído para @fayz-ai/ui\n // justamente para isto. Dois `<input type=date>` crus não têm preset, não\n // escrevem a janela resolvida e deixam marcar início depois do fim.\n // Sete dias, e não trinta. Conferir ponto é rotina de semana — o gesto é\n // \"o que aconteceu desde a última vez que olhei\", não \"o mês inteiro\". Trinta\n // dias no Pertinho do Céu são 261 linhas-pessoa-dia antes de a tela desenhar\n // a primeira; sete são cerca de sessenta. Quem precisa do mês tem o preset\n // ao lado, e ele é um clique.\n const [preset, setPreset] = React.useState<AnalyticsRangePreset | 'custom'>('last_7_days')\n const [range, setRange] = React.useState<AnalyticsDateRange>(() => resolveRangePreset('last_7_days'))\n const from = range.from\n const to = range.to\n const [adjusting, setAdjusting] = React.useState<TimeEntry | null>(null)\n const [details, setDetails] = React.useState<WorkDay | null>(null)\n\n React.useEffect(() => { void fetchTime(from, to) }, [fetchTime, from, to])\n\n // O relógio só anda quando há ponto em aberto na tela. Num período fechado\n // não há nada correndo, e um timer que repinta a tabela de minuto em minuto\n // para não mudar nada é só uma aba que não deixa a máquina dormir.\n const temAberto = React.useMemo(() => days.some((d) => d.isOpen), [days])\n const agora = useAgora(temAberto)\n\n const entriesByPerson = React.useMemo(() => {\n const map = new Map<string, TimeEntry[]>()\n for (const e of entries) {\n const key = `${e.personId}|${e.workDate}`\n const list = map.get(key) ?? []\n list.push(e)\n map.set(key, list)\n }\n // A última batida é o alvo do ajuste — ordenar aqui evita que a linha\n // dependa da ordem em que o provider devolveu.\n for (const list of map.values()) list.sort((a, b) => a.seq - b.seq)\n return map\n }, [entries])\n\n /** Por dia, mais recente primeiro — como o V1 lista. */\n const porDia = React.useMemo(() => {\n const map = new Map<string, WorkDay[]>()\n for (const d of days) {\n const list = map.get(d.workDate) ?? []\n list.push(d)\n map.set(d.workDate, list)\n }\n for (const list of map.values()) {\n list.sort((a, b) => (a.personName ?? '').localeCompare(b.personName ?? ''))\n }\n return [...map.entries()].sort(([a], [b]) => b.localeCompare(a))\n }, [days])\n\n // A unidade da paginação é o DIA, não a linha: a tela é uma tabela por dia, e\n // cortar no meio de um dia partiria o cabeçalho de totais do dia da gente que\n // ele conta. Sete cabem numa semana inteira sem botão nenhum aparecer.\n const DIAS_POR_PAGINA = 7\n const [pagina, setPagina] = React.useState(0)\n // Período novo, página zero. Sem isto, trocar de intervalo pode cair numa\n // página que não existe mais e a tela fica vazia sem dizer por quê.\n React.useEffect(() => { setPagina(0) }, [from, to])\n const totalPaginas = Math.max(1, Math.ceil(porDia.length / DIAS_POR_PAGINA))\n const paginaAtual = Math.min(pagina, totalPaginas - 1)\n const diasVisiveis = React.useMemo(\n () => porDia.slice(paginaAtual * DIAS_POR_PAGINA, (paginaAtual + 1) * DIAS_POR_PAGINA),\n [porDia, paginaAtual],\n )\n\n // Só as batidas dos dias À VISTA vão para a assinatura. É o que torna a\n // paginação uma economia de rede e não só de pixels.\n const entradasVisiveis = React.useMemo(() => {\n const chaves = new Set<string>()\n for (const [, lista] of diasVisiveis) for (const d of lista) chaves.add(`${d.personId}|${d.workDate}`)\n return entries.filter((e) => chaves.has(`${e.personId}|${e.workDate}`))\n }, [diasVisiveis, entries])\n const fotos = useFotosDaPagina(entradasVisiveis)\n\n const unitNames = React.useMemo(() => {\n const map = new Map<string, string>()\n for (const d of days) if (d.unitId) map.set(d.unitId, d.unitName ?? '—')\n return map\n }, [days])\n\n const totais = React.useMemo(() => {\n const minutos = days.reduce((sum, d) => sum + (d.reviewReason ? 0 : (d.workedMinutes ?? 0)), 0)\n return {\n registros: days.length,\n minutos,\n abertos: days.filter((d) => d.isOpen).length,\n revisar: days.filter((d) => d.reviewReason === 'span_too_long').length,\n valor: hourlyRate != null ? (minutos / 60) * hourlyRate : null,\n }\n }, [days, hourlyRate])\n\n return (\n <div className=\"space-y-4 p-6\">\n {/* A MESMA banda do /analytics e dos Encargos: PageToolbar, presa ao topo\n da página, com o período à esquerda e os controles à direita.\n NÃO flutua mais — a pílula de vidro arrastável cobria a lista e era\n uma quarta gramática de filtro no produto. Ver PageToolbar. */}\n <PageToolbar\n range={\n <DateRangeControl\n value={range}\n onChange={setRange}\n preset={preset}\n onPresetChange={setPreset}\n />\n }\n onRefresh={() => void fetchTime(from, to)}\n />\n\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <h2 className=\"text-lg font-semibold\">Resultados</h2>\n <div className=\"flex flex-wrap items-center gap-4 text-sm text-muted-foreground\">\n <span>{totais.registros} registro(s)</span>\n <span>\n Total: <b className=\"text-foreground\">{hours(totais.minutos)}</b>\n {/* O total é honesto E incompleto, e dizer só a primeira metade é o\n que faz alguém tomar 14.969h por verdade quando 11.197 delas são\n saída não batida. O que ficou de fora fica escrito aqui, com o\n número — não um asterisco que manda procurar a legenda. */}\n {(totais.abertos > 0 || totais.revisar > 0) && (\n <span className=\"ml-1 text-xs\">\n (fora:{' '}\n {[\n totais.abertos > 0 ? `${totais.abertos} em aberto` : null,\n totais.revisar > 0 ? `${totais.revisar} a revisar` : null,\n ].filter(Boolean).join(' · ')})\n </span>\n )}\n </span>\n <span>Valor: <b className=\"text-foreground\">\n {totais.valor != null ? formatCurrency(totais.valor, currency) : '—'}\n </b></span>\n </div>\n </div>\n\n {hourlyRate == null && (\n // Honestidade em vez de um número inventado: o SQL da jornada não guarda\n // remuneração em lugar nenhum, então a coluna Valor só existe quando o\n // app diz quanto vale a hora.\n <p className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <AlertTriangle className=\"h-3.5 w-3.5\" aria-hidden />\n O valor da hora não está configurado — informe <code>hourlyRate</code> no plugin para ver a coluna Valor.\n </p>\n )}\n\n {loading ? (\n <div className=\"space-y-2\"><Skeleton className=\"h-40 w-full\" /><Skeleton className=\"h-40 w-full\" /></div>\n ) : porDia.length === 0 ? (\n <div className=\"rounded-xl border border-dashed border-border p-8 text-center\">\n <Clock className=\"mx-auto mb-3 h-8 w-8 text-muted-foreground\" aria-hidden />\n <p className=\"text-sm text-muted-foreground\">Nenhum registro no período.</p>\n </div>\n ) : (\n <FotosContext.Provider value={fotos}>\n <div className=\"space-y-3\">\n {diasVisiveis.map(([workDate, list]) => (\n <GrupoDoDia\n key={workDate}\n workDate={workDate}\n days={list}\n entriesByPerson={entriesByPerson}\n unitNames={unitNames}\n agora={agora}\n onAdjust={setAdjusting}\n onDetails={setDetails}\n />\n ))}\n {totalPaginas > 1 && (\n <div className=\"flex items-center justify-between gap-3 rounded-xl border border-border px-4 py-3 text-sm\">\n {/* O que a página mostra, em DIAS — é a unidade que a tela usa, e\n dizer \"1 a 7 de 23 registros\" mentiria sobre o que foi\n cortado. */}\n <span className=\"text-muted-foreground\">\n Dias {paginaAtual * DIAS_POR_PAGINA + 1}–\n {Math.min((paginaAtual + 1) * DIAS_POR_PAGINA, porDia.length)} de {porDia.length}\n </span>\n <span className=\"flex items-center gap-2\">\n <Button\n size=\"sm\" variant=\"outline\"\n disabled={paginaAtual === 0}\n onClick={() => setPagina((n) => Math.max(0, n - 1))}\n >\n Mais recentes\n </Button>\n <span className=\"text-xs text-muted-foreground tabular-nums\">\n {paginaAtual + 1} / {totalPaginas}\n </span>\n <Button\n size=\"sm\" variant=\"outline\"\n disabled={paginaAtual >= totalPaginas - 1}\n onClick={() => setPagina((n) => Math.min(totalPaginas - 1, n + 1))}\n >\n Mais antigos\n </Button>\n </span>\n </div>\n )}\n </div>\n </FotosContext.Provider>\n )}\n\n {adjusting && (\n <AdjustDialog\n entry={adjusting}\n onClose={() => setAdjusting(null)}\n onSaved={() => void fetchTime(from, to)}\n />\n )}\n {details && (\n <DetalhesDoDia\n day={details}\n entries={entriesByPerson.get(`${details.personId}|${details.workDate}`) ?? []}\n onClose={() => setDetails(null)}\n />\n )}\n </div>\n )\n}\n","import React from 'react'\nimport { Lock, Unlock, CalendarCheck } from 'lucide-react'\nimport { Badge, Button, Input, Modal, ModalContent, ModalHeader, ModalTitle, ModalBody, ModalFooter, Skeleton, toast } from '@fayz-ai/ui'\nimport { useWorkforceProvider, useWorkforceStore } from '../context'\nimport type { WorkforcePeriod } from '../types'\n\n// ---------------------------------------------------------------------------\n// Fechamento — a competência.\n//\n// Fechar o mês é um ATO, não a edição de uma linha: as duas escritas passam por\n// RPC (`workforce_period_close` / `workforce_period_reopen`), que é onde a\n// permissão e o registro de QUEM moram. Reabrir exige motivo — reabrir sem\n// dizer por quê é como não ter fechado.\n//\n// Fechado significa que nenhuma batida nem ajuste entra com data naquele mês; a\n// trava é de banco (trigger), não de tela.\n// ---------------------------------------------------------------------------\n\nfunction monthLabel(iso: string): string {\n return new Date(`${iso}T12:00:00`).toLocaleDateString('pt-BR', { month: 'long', year: 'numeric' })\n}\n\n/** Os últimos doze meses, do mais recente para trás. É o horizonte que o RH usa. */\nfunction lastMonths(count: number): string[] {\n const out: string[] = []\n const d = new Date()\n d.setDate(1)\n for (let i = 0; i < count; i++) {\n out.push(`${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-01`)\n d.setMonth(d.getMonth() - 1)\n }\n return out\n}\n\nexport function PeriodsView() {\n const provider = useWorkforceProvider()\n const periods = useWorkforceStore((s) => s.periods)\n const loading = useWorkforceStore((s) => s.periodsLoading)\n const fetchPeriods = useWorkforceStore((s) => s.fetchPeriods)\n\n const [dialog, setDialog] = React.useState<{ month: string; mode: 'close' | 'reopen' } | null>(null)\n const [text, setText] = React.useState('')\n const [busy, setBusy] = React.useState(false)\n\n React.useEffect(() => { void fetchPeriods() }, [fetchPeriods])\n\n const byMonth = React.useMemo(() => {\n const map = new Map<string, WorkforcePeriod>()\n for (const p of periods) map.set(p.competenceMonth, p)\n return map\n }, [periods])\n\n async function confirm() {\n if (!dialog) return\n if (dialog.mode === 'reopen' && !text.trim()) {\n toast.error('O motivo da reabertura é obrigatório.')\n return\n }\n setBusy(true)\n try {\n if (dialog.mode === 'close') await provider.closePeriod(dialog.month, text.trim() || undefined)\n else await provider.reopenPeriod(dialog.month, text.trim())\n await fetchPeriods()\n toast.success(dialog.mode === 'close' ? 'Competência fechada.' : 'Competência reaberta.')\n setDialog(null)\n setText('')\n } catch (e: any) {\n toast.error(e?.message ?? 'Não foi possível concluir.')\n } finally {\n setBusy(false)\n }\n }\n\n return (\n <div className=\"space-y-4 p-6\">\n <div>\n <h2 className=\"text-lg font-semibold\">Fechamento de competência</h2>\n <p className=\"text-sm text-muted-foreground\">\n Mês fechado não aceita batida nem ajuste com data dentro dele. A trava é do banco.\n </p>\n </div>\n\n {loading ? (\n <div className=\"space-y-2\"><Skeleton className=\"h-14 w-full\" /><Skeleton className=\"h-14 w-full\" /></div>\n ) : (\n <div className=\"divide-y divide-border rounded-xl border border-border\">\n {lastMonths(12).map((month) => {\n const period = byMonth.get(month)\n const closed = period?.status === 'closed'\n return (\n <div key={month} className=\"flex flex-wrap items-center justify-between gap-3 px-4 py-3\">\n <div className=\"flex items-center gap-3\">\n <CalendarCheck className=\"h-4 w-4 text-muted-foreground\" aria-hidden />\n <div>\n <div className=\"text-sm font-medium capitalize\">{monthLabel(month)}</div>\n <div className=\"text-xs text-muted-foreground\">\n {closed\n ? `Fechada em ${period?.closedAt ? new Date(period.closedAt).toLocaleDateString('pt-BR') : '—'}`\n : period?.reopenReason\n ? `Reaberta: ${period.reopenReason}`\n : 'Aberta'}\n </div>\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n <Badge variant={closed ? 'success' : 'secondary'}>{closed ? 'Fechada' : 'Aberta'}</Badge>\n <Button\n size=\"sm\"\n variant={closed ? 'ghost' : 'secondary'}\n onClick={() => { setText(''); setDialog({ month, mode: closed ? 'reopen' : 'close' }) }}\n >\n {closed\n ? <><Unlock className=\"mr-1 h-3.5 w-3.5\" aria-hidden /> Reabrir</>\n : <><Lock className=\"mr-1 h-3.5 w-3.5\" aria-hidden /> Fechar</>}\n </Button>\n </div>\n </div>\n )\n })}\n </div>\n )}\n\n {dialog && (\n <Modal open onOpenChange={(o) => { if (!o) setDialog(null) }}>\n <ModalContent size=\"sm\">\n <ModalHeader>\n <ModalTitle>\n {dialog.mode === 'close' ? 'Fechar' : 'Reabrir'} {monthLabel(dialog.month)}\n </ModalTitle>\n </ModalHeader>\n <ModalBody>\n <Input\n value={text}\n onChange={(e) => setText(e.target.value)}\n placeholder={dialog.mode === 'close' ? 'Observação (opcional)' : 'Motivo da reabertura (obrigatório)'}\n />\n </ModalBody>\n <ModalFooter>\n <Button variant=\"ghost\" onClick={() => setDialog(null)}>Cancelar</Button>\n <Button onClick={confirm} disabled={busy}>Confirmar</Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n )}\n </div>\n )\n}\n","import React from 'react'\nimport { createCrudPage } from '@fayz-ai/admin'\nimport type { EntityDef } from '@fayz-ai/core'\n\n// ---------------------------------------------------------------------------\n// Pessoas & Documentos — a ficha do colaborador.\n//\n// NADA novo aqui, e é de propósito: o colaborador já é `public.people` com\n// papel de equipe, e o arquétipo de pessoa do @fayz-ai/admin já desenha a ficha\n// inteira — acesso, unidades, horário, endereços, DOCUMENTOS, extrato e\n// atividade — para qualquer entidade declarada com `layout: 'person'`.\n//\n// Uma segunda tela de cadastro de gente aqui dentro seria um segundo lugar para\n// o mesmo nome ficar desatualizado. O que este módulo faz é trazer a ficha para\n// dentro dele, não refazê-la.\n// ---------------------------------------------------------------------------\n\n/** O recorte de `public.people` que o RH edita. O app pode substituir. */\nexport const DEFAULT_STAFF_ENTITY: EntityDef = {\n name: 'Colaborador',\n namePlural: 'Pessoas',\n icon: 'UserCog',\n layout: 'person',\n displayField: 'name',\n defaultSort: 'name',\n fields: [\n { key: 'name', label: 'Nome', type: 'text', required: true, showInTable: true, searchable: true },\n { key: 'phone', label: 'Telefone', type: 'phone', showInTable: true },\n { key: 'email', label: 'E-mail', type: 'email', showInTable: false },\n { key: 'documentNumber', label: 'CPF', type: 'text', showInTable: true },\n { key: 'isActive', label: 'Ativo', type: 'boolean', showInTable: true, defaultValue: true, inlineToggle: true },\n ],\n data: {\n table: 'people',\n tenantScoped: true,\n archetype: 'person',\n archetypeKind: 'staff',\n searchColumns: ['name', 'email', 'phone'],\n },\n}\n\n/** Memoizado por entidade: `createCrudPage` monta um store, e remontá-lo a cada\n * render zeraria a lista sempre que a aba repintasse. */\nconst cache = new Map<EntityDef, React.ComponentType>()\n\nexport function PeopleView({ entity }: { entity?: EntityDef }) {\n const def = entity ?? DEFAULT_STAFF_ENTITY\n const Page = React.useMemo(() => {\n const cached = cache.get(def)\n if (cached) return cached\n const created = createCrudPage(def as never)\n cache.set(def, created)\n return created\n }, [def])\n return <Page />\n}\n","import React from 'react'\nimport { getSupabaseClientOptional } from '@fayz-ai/core'\n\n// ---------------------------------------------------------------------------\n// usePayrollAccounts — quais ramos do plano de contas são custo de pessoal\n// ---------------------------------------------------------------------------\n// Mesma forma do `useDeliverySettings` do plugin-orders, e pela mesma razão: é\n// UMA decisão da casa, guardada em `tenants.settings` pelas RPCs do spine\n// (`tenant_settings` para ler tudo, `tenant_setting_set` para gravar). A função\n// recusa chave não registrada e cobra `settings.manage` — a chave está\n// registrada em workforce/006.\n//\n// Sem escolha gravada o valor é `null`, e é DIFERENTE de `[]`: nulo é \"a casa\n// não disse\", e a tela mostra todas as despesas avisando que é o que está\n// fazendo. Um array vazio seria \"a casa disse que nada é pessoal\", que é uma\n// afirmação — e mostraria a tela vazia.\n\nconst KEY = 'workforce.payroll_account_codes'\n\nexport interface PayrollAccountsHandle {\n /** Os códigos escolhidos, ou null quando a casa nunca escolheu. */\n codes: string[] | null\n /** Grava (ou apaga, com null). */\n save: (next: string[] | null) => Promise<void>\n loading: boolean\n saving: boolean\n /** A gravação foi recusada — em geral falta `settings.manage`. */\n error: string | null\n /** Sem backend montado (mock/standalone): a tela não oferece o controle. */\n supported: boolean\n}\n\nfunction message(e: unknown): string {\n if (e instanceof Error) return e.message\n if (typeof e === 'object' && e && 'message' in e) return String((e as { message: unknown }).message)\n return String(e)\n}\n\nfunction normalize(value: unknown): string[] | null {\n if (!Array.isArray(value)) return null\n const codes = value.map((v) => String(v).trim()).filter(Boolean)\n return codes.length ? codes : null\n}\n\nexport function usePayrollAccounts(): PayrollAccountsHandle {\n const client = React.useMemo(() => getSupabaseClientOptional() as any, [])\n const supported = !!client\n\n const [codes, setCodes] = React.useState<string[] | null>(null)\n const [loading, setLoading] = React.useState(supported)\n const [saving, setSaving] = React.useState(false)\n const [error, setError] = React.useState<string | null>(null)\n\n React.useEffect(() => {\n if (!client) return\n let cancelled = false\n setLoading(true)\n void client\n .rpc('tenant_settings')\n .then(({ data, error: e }: { data: Record<string, unknown> | null; error: unknown }) => {\n if (cancelled || e) return\n setCodes(normalize((data ?? {})[KEY]))\n })\n // Leitura falhada cai em \"não escolheu\": a tela então mostra tudo e diz\n // isso, que é o mesmo comportamento seguro de uma casa sem escolha.\n .catch(() => {})\n .finally(() => { if (!cancelled) setLoading(false) })\n return () => { cancelled = true }\n }, [client])\n\n const save = React.useCallback(async (next: string[] | null) => {\n const value = next && next.length ? next : null\n setCodes(value)\n if (!client) return\n setError(null)\n setSaving(true)\n try {\n const { error: e } = await client.rpc('tenant_setting_set', { p_key: KEY, p_value: value })\n if (e) throw e\n } catch (e) {\n setError(message(e))\n } finally {\n setSaving(false)\n }\n }, [client])\n\n return { codes, save, loading, saving, error, supported }\n}\n","import React from 'react'\nimport { HandCoins, ExternalLink, ListTree, AlertTriangle } from 'lucide-react'\nimport type { AnalyticsDateRange, AnalyticsRow, AnalyticsStatementDef } from '@fayz-ai/core'\nimport {\n Button, Checkbox, DateRangeControl, PageToolbar, Popover, PopoverContent, PopoverTrigger,\n StatTiles, StatementTable, compareCodes, resolveRangePreset, type AnalyticsRangePreset,\n} from '@fayz-ai/ui'\nimport { adminNavigateTo, usePermissionOptional } from '@fayz-ai/admin'\nimport { formatCurrency, useWorkforceConfig, useWorkforceProvider } from '../context'\nimport { usePayrollAccounts } from '../settings/usePayrollAccounts'\nimport type { PayrollCostRow } from '../types'\n\n// ---------------------------------------------------------------------------\n// Encargos e Honorários — o custo de pessoal, LIDO, e desenhado como\n// demonstrativo.\n//\n// Este módulo não cria tabela de folha, e não escreve nada aqui. Quem lança\n// salário, encargo e honorário é o Financeiro, e o demonstrativo dele já sabe\n// onde cada despesa cai — `plg_financial_rep_dre`, a MESMA view do relatório de\n// DRE, agregada por conta × mês.\n//\n// Duplicar a escrita aqui daria dois livros para a mesma despesa, e a pergunta\n// \"quanto custou a equipe em março?\" passaria a ter duas respostas. Ler uma\n// segunda fonte daria o mesmo estrago mais devagar: era assim até 19/09/2026 —\n// esta tela somava `v_financial_invoice_lines` linha a linha, e as duas contas\n// podiam divergir sem que nada avisasse.\n//\n// ── Por que demonstrativo e não lista ──────────────────────────────────────\n//\n// A tela mostrava uma lista chapada por mês: `5.4.1 Freela Cozinha · R$ 57.289`\n// ao lado de `5 DESPESAS COM PESSOAL`, sem hierarquia, sem as mães e sem\n// comparação entre meses. O mesmo dado é um DEMONSTRATIVO — a árvore do plano de\n// contas, uma coluna por mês, o valor do pai somado dos filhos — e o SDK já tem\n// o componente que o desenha: `StatementTable`, o mesmo do relatório de DRE.\n// Aqui ele recebe uma seção só (despesa) e o recorte de pessoal.\n//\n// ── O recorte é uma DECLARAÇÃO da casa ─────────────────────────────────────\n//\n// Sem recorte esta tela somava aluguel, IPTU, ICMS e equipamentos sob o título\n// \"custo de pessoal\": no cluster onde isto foi medido, R$ 2.036.706 de despesa\n// classificada em 2026 contra R$ 511.131 do ramo de pessoal — quatro quintos do\n// total não eram gente. Qual ramo é pessoal só a casa sabe (aqui é `5`; o template\n// que o SDK semeia põe folha em `4.03`), então mora em `tenants.settings`:\n// `workforce.payroll_account_codes`, registrada em workforce/006.\n//\n// Nulo é \"não escolheu\", e a tela então mostra TODAS as despesas classificadas\n// AVISANDO que é o que está fazendo. Um padrão inventado ('5') mentiria com\n// convicção no primeiro plano que usa outro número.\n// ---------------------------------------------------------------------------\n\n/** A conta pertence ao recorte? `null` = sem recorte, tudo pertence. */\nfunction noEscopo(code: string, escopo: string[] | null): boolean {\n if (!escopo) return true\n return escopo.some((c) => code === c || code.startsWith(`${c}.`))\n}\n\n/** Um ancestral já escolhido cobre este código — o filho não precisa ser marcado. */\nfunction cobertoPorAncestral(code: string, escopo: string[]): boolean {\n return escopo.some((c) => c !== code && code.startsWith(`${c}.`))\n}\n\n/** Todo 1º de mês entre duas datas, inclusive — as colunas do demonstrativo.\n * É ela que diz qual COMPETÊNCIA está na tela — o seletor de período fala em\n * dias, e o demonstrativo responde em meses. */\nfunction mesesEntre(de: string, ate: string): string[] {\n const out: string[] = []\n const fim = new Date(`${ate.slice(0, 10)}T12:00:00`)\n const cursor = new Date(`${de.slice(0, 7)}-01T12:00:00`)\n while (cursor <= fim && out.length < 120) {\n out.push(`${cursor.getFullYear()}-${String(cursor.getMonth() + 1).padStart(2, '0')}-01`)\n cursor.setMonth(cursor.getMonth() + 1)\n }\n return out\n}\n\nconst MESES = ['jan', 'fev', 'mar', 'abr', 'mai', 'jun', 'jul', 'ago', 'set', 'out', 'nov', 'dez']\n\n/** '2026-09-01' → 'set/26'. Escrito à mão porque o `Intl` do pt-BR devolve\n * 'set. de 26', que num cabeçalho de coluna ocupa o triplo do espaço. */\nfunction monthLabel(iso: string): string {\n const [ano, mes] = iso.slice(0, 7).split('-')\n return `${MESES[Number(mes) - 1] ?? mes}/${ano.slice(2)}`\n}\n\n\n// Uma seção só: esta tela é o ramo de DESPESA do demonstrativo, não o resultado\n// do exercício. As linhas de total do DRE (\"= RESULTADO OPERACIONAL\") não têm\n// sentido aqui — não há receita para subtrair de nada.\nconst DEF: AnalyticsStatementDef = {\n codeKey: 'statement_code',\n labelKey: 'statement_name',\n periodKey: 'competence_month',\n valueKey: 'amount',\n sectionKey: 'direction',\n sections: [\n {\n value: 'payable',\n label: 'Despesas',\n // A linha sem conta é uma linha de verdade. Escondê-la faria a soma da\n // árvore não fechar com o total do rodapé.\n unclassifiedLabel: 'Sem classificação',\n },\n ],\n lines: [\n { kind: 'section', section: 'payable' },\n { kind: 'total', label: 'TOTAL NO PERÍODO', of: { payable: 1 }, emphasis: 'rule' },\n ],\n defaultDepth: 1,\n}\n\nexport function PayrollCostsView() {\n const provider = useWorkforceProvider()\n const { currency } = useWorkforceConfig()\n const can = usePermissionOptional()\n const podeConfigurar = can('settings', 'manage')\n const escopoStore = usePayrollAccounts()\n\n // O mesmo controle de período das outras telas — ver TimeEntriesView.\n const [preset, setPreset] = React.useState<AnalyticsRangePreset | 'custom'>('this_month')\n const [range, setRange] = React.useState<AnalyticsDateRange>(() => resolveRangePreset('this_month'))\n const from = range.from\n const to = range.to\n const [rows, setRows] = React.useState<PayrollCostRow[] | null>(null)\n const [unavailable, setUnavailable] = React.useState(false)\n const [loading, setLoading] = React.useState(true)\n // O \"atualizar\" da barra refaz a MESMA leitura sem trocar o período. Um\n // contador é o gatilho mais honesto: o efeito abaixo é quem sabe carregar,\n // e duplicar essa lógica num handler é como as duas se separam.\n const [recarga, setRecarga] = React.useState(0)\n\n React.useEffect(() => {\n let cancelled = false\n setLoading(true)\n const load = provider.getPayrollCosts\n if (!load) {\n setUnavailable(true)\n setLoading(false)\n return\n }\n // Estrutura e movimento vêm na MESMA resposta: a linha sem mês é a conta do\n // plano (\"existe, não teve movimento\"), a linha com mês é o lançamento.\n load({ from, to })\n .then((r) => {\n if (cancelled) return\n setRows(r)\n setUnavailable(false)\n })\n // Cluster sem o Financeiro instalado: a tela se explica em vez de quebrar.\n .catch(() => { if (!cancelled) setUnavailable(true) })\n .finally(() => { if (!cancelled) setLoading(false) })\n return () => { cancelled = true }\n }, [provider, from, to, recarga])\n\n const escopo = escopoStore.codes\n\n /** O plano de despesa, para o seletor: as linhas de estrutura da resposta. */\n const despesas = React.useMemo(\n () => (rows ?? [])\n .filter((r) => r.competenceMonth === null && r.chartAccountCode)\n .map((r) => ({ code: r.chartAccountCode as string, name: r.chartAccountName }))\n .sort((a, b) => compareCodes(a.code, b.code)),\n [rows],\n )\n\n /** O que o período mediu, dentro do recorte. A linha SEM conta não pertence a\n * ramo nenhum: ela entra quando não há recorte (a tela mostra tudo e avisa) e\n * fica de fora quando a casa declarou quais ramos são pessoal. */\n const movimento = React.useMemo(\n () => (rows ?? []).filter((r) => r.competenceMonth !== null\n && (r.chartAccountCode ? noEscopo(r.chartAccountCode, escopo) : !escopo)),\n [rows, escopo],\n )\n\n const analyticsRows = React.useMemo<AnalyticsRow[]>(() => {\n const out: AnalyticsRow[] = []\n // ESTRUTURA: a conta existe e pode não ter tido movimento. Sem mês, de\n // propósito — cria o nó na árvore e não cria coluna (ver `buildStatement`).\n for (const a of despesas) {\n if (!noEscopo(a.code, escopo)) continue\n out.push({\n direction: 'payable',\n statement_code: a.code,\n statement_name: a.name,\n competence_month: null,\n amount: 0,\n })\n }\n // MOVIMENTO. Sem código é a linha \"sem classificação\" do demonstrativo —\n // uma despesa lançada em conta que não é de despesa. Fica à vista e dentro\n // do total: escondê-la faria a árvore não fechar com o rodapé.\n for (const r of movimento) {\n out.push({\n direction: 'payable',\n statement_code: r.chartAccountCode ?? '',\n statement_name: r.chartAccountName,\n competence_month: r.competenceMonth,\n amount: r.total,\n })\n }\n return out\n }, [despesas, movimento, escopo])\n\n const total = movimento.reduce((s, r) => s + r.total, 0)\n const meses = new Set(movimento.map((r) => r.competenceMonth)).size\n\n // O que a tela REALMENTE mediu. O demonstrativo é por competência mensal, e o\n // seletor de período fala em dias: \"últimos 7 dias\" traz o mês inteiro. Dizer\n // qual competência está na tela custa uma linha e evita que alguém leia o\n // total de setembro como o total de uma semana.\n const competencia = React.useMemo(() => {\n const ms = mesesEntre(from, to)\n if (ms.length === 0) return null\n return ms.length === 1\n ? monthLabel(ms[0])\n : `${monthLabel(ms[0])} a ${monthLabel(ms[ms.length - 1])}`\n }, [from, to])\n\n return (\n <div className=\"space-y-4 p-6\">\n {/* A MESMA banda dos Registros de Ponto, com os MESMOS controles: sem o\n \"atualizar\" aqui, a única forma de refazer a leitura era trocar o\n período e voltar — duas telas irmãs do mesmo módulo respondendo\n diferente ao mesmo gesto. */}\n <PageToolbar\n range={\n <DateRangeControl value={range} onChange={setRange} preset={preset} onPresetChange={setPreset} />\n }\n onRefresh={() => setRecarga((n) => n + 1)}\n />\n <div className=\"flex flex-wrap items-end justify-between gap-3\">\n <div>\n <h2 className=\"text-lg font-semibold\">Encargos e honorários</h2>\n <p className=\"text-sm text-muted-foreground\">\n O custo de pessoal como o Financeiro o registrou, na árvore do plano de contas.\n Esta tela só lê — o lançamento continua sendo lá.\n </p>\n {competencia ? (\n <p className=\"mt-0.5 text-xs text-muted-foreground\">\n Competência <span className=\"font-medium\">{competencia}</span> — o\n demonstrativo é mensal, e o período escolhido vira meses inteiros.\n </p>\n ) : null}\n </div>\n <div className=\"flex items-center gap-2\">\n {unavailable ? null : (\n <EscopoPopover\n contas={despesas}\n escopo={escopo}\n podeConfigurar={podeConfigurar}\n store={escopoStore}\n />\n )}\n <Button variant=\"secondary\" onClick={() => adminNavigateTo('/financial')}>\n <ExternalLink className=\"mr-1 h-4 w-4\" aria-hidden /> Abrir Financeiro\n </Button>\n </div>\n </div>\n\n {unavailable ? (\n <div className=\"rounded-xl border border-dashed border-border p-8 text-center\">\n <HandCoins className=\"mx-auto mb-3 h-8 w-8 text-muted-foreground\" aria-hidden />\n <p className=\"text-sm text-muted-foreground\">\n O razão do Financeiro não está disponível neste ambiente — instale o módulo Financeiro\n para ver o custo de pessoal aqui.\n </p>\n </div>\n ) : (\n <>\n {/* O aviso é a parte não-cosmética da tela: sem recorte o total inclui\n aluguel e imposto, e quem lê precisa saber disso ANTES do número. */}\n {!escopoStore.loading && !escopo ? (\n <div className=\"flex items-start gap-3 rounded-xl border border-warning/40 bg-warning/5 p-4\">\n <AlertTriangle className=\"mt-0.5 h-4 w-4 shrink-0 text-warning\" aria-hidden />\n <div className=\"space-y-1 text-sm\">\n <p className=\"font-medium\">Nenhum ramo de pessoal escolhido.</p>\n <p className=\"text-muted-foreground\">\n O demonstrativo abaixo soma <strong>todas</strong> as despesas classificadas em\n conta contábil — inclusive aluguel, imposto e equipamento. Escolha em{' '}\n <span className=\"whitespace-nowrap font-medium\">Contas de pessoal</span> os ramos\n do seu plano que são gente, e o total passa a valer como custo de equipe.\n </p>\n </div>\n </div>\n ) : null}\n\n <StatTiles\n loading={loading}\n tiles={[\n { id: 'total', label: 'Total no período', value: formatCurrency(total, currency) },\n { id: 'months', label: 'Competências', value: String(meses) },\n {\n id: 'avg',\n label: 'Média mensal',\n value: meses > 0 ? formatCurrency(total / meses, currency) : formatCurrency(0, currency),\n },\n ]}\n />\n\n <StatementTable\n rows={analyticsRows}\n def={DEF}\n currency={currency}\n formatPeriod={monthLabel}\n accountLabel=\"Conta\"\n totalLabel=\"Período\"\n emptyMessage=\"Nenhuma despesa classificada em conta contábil no período.\"\n loading={loading}\n />\n </>\n )}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// O recorte, escolhido na árvore\n// ---------------------------------------------------------------------------\n\nfunction EscopoPopover({\n contas, escopo, podeConfigurar, store,\n}: {\n contas: { code: string; name: string }[]\n escopo: string[] | null\n podeConfigurar: boolean\n store: ReturnType<typeof usePayrollAccounts>\n}) {\n const marcados = React.useMemo(() => new Set(escopo ?? []), [escopo])\n\n const alterna = (code: string) => {\n const next = new Set(marcados)\n if (next.has(code)) next.delete(code)\n else {\n // Marcar um pai dispensa os filhos: o código carrega a descendência, e\n // guardar as duas coisas faria a configuração envelhecer a cada conta\n // nova criada dentro do ramo.\n for (const c of [...next]) if (c.startsWith(`${code}.`)) next.delete(c)\n next.add(code)\n }\n void store.save([...next].sort(compareCodes))\n }\n\n const rotulo = escopo\n ? `${escopo.length} ${escopo.length === 1 ? 'ramo' : 'ramos'} de pessoal`\n : 'Contas de pessoal'\n\n return (\n <Popover>\n <PopoverTrigger asChild>\n <Button variant={escopo ? 'secondary' : 'default'}>\n <ListTree className=\"mr-1 h-4 w-4\" aria-hidden /> {rotulo}\n </Button>\n </PopoverTrigger>\n <PopoverContent align=\"end\" className=\"w-[26rem] p-0\">\n <div className=\"border-b p-3\">\n <p className=\"text-sm font-medium\">O que é custo de pessoal</p>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n Marque os ramos do seu plano de contas. Um ramo marcado traz toda a descendência —\n inclusive contas criadas depois.\n </p>\n </div>\n <div className=\"max-h-80 overflow-y-auto py-1\">\n {contas.length === 0 ? (\n <p className=\"p-3 text-xs text-muted-foreground\">\n Nenhuma conta de despesa ativa no plano.\n </p>\n ) : (\n contas.map((c) => {\n const depth = c.code.split('.').length - 1\n const herdado = cobertoPorAncestral(c.code, [...marcados])\n const checked = marcados.has(c.code) || herdado\n return (\n <label\n key={c.code}\n className=\"flex cursor-pointer items-center gap-2 px-3 py-1.5 text-sm hover:bg-muted/50\"\n style={{ paddingLeft: `${12 + depth * 14}px` }}\n >\n <Checkbox\n checked={checked}\n // Herdado do pai: desmarcar aqui não faria nada, então o\n // controle diz que a escolha é lá em cima.\n disabled={!podeConfigurar || store.saving || herdado}\n onChange={() => alterna(c.code)}\n />\n <span className=\"w-16 shrink-0 font-mono text-xs text-muted-foreground\">{c.code}</span>\n <span className=\"truncate\">{c.name}</span>\n </label>\n )\n })\n )}\n </div>\n <div className=\"flex items-center justify-between gap-2 border-t p-3\">\n <span className=\"text-xs text-muted-foreground\">\n {!podeConfigurar\n ? 'Só quem tem settings.manage pode mudar isto.'\n : store.error\n ? store.error\n : store.saving\n ? 'Salvando…'\n : 'Salva sozinho, para toda a casa.'}\n </span>\n {escopo && podeConfigurar ? (\n <Button variant=\"ghost\" size=\"sm\" onClick={() => void store.save(null)}>\n Limpar\n </Button>\n ) : null}\n </div>\n </PopoverContent>\n </Popover>\n )\n}\n","import React from 'react'\nimport { CalendarClock, CakeSlice, UserMinus, UserPlus, Users, AlertTriangle, ShieldAlert, Plane, Stethoscope, ClipboardList, Plus } from 'lucide-react'\nimport {\n Badge, Button, Input, Modal, ModalContent, ModalHeader, ModalTitle, ModalBody, ModalFooter,\n Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Skeleton, toast,\n} from '@fayz-ai/ui'\nimport { PersonLink } from '@fayz-ai/admin'\nimport { useWorkforceConfig, useWorkforceProvider } from '../context'\nimport type {\n Absence, AbsenceKind, ContractKind, Employment, HrOverview, HrUpcoming, WorkforcePerson,\n PayFrequency, PendingItem, PendingPriority, ScheduleRegime, Vacation, VacationStatus,\n} from '../types'\n\n// ---------------------------------------------------------------------------\n// Recursos Humanos.\n//\n// Portado de `~/dev/beautyplace/docs/v1-guide/rh`, e é o NÚCLEO do módulo do V1,\n// não a cópia dele. O V1 tem dezesseis vistas na ficha; doze estão vazias no\n// banco inteiro — não \"vazias nesses tenants\", vazias em produção — e portar\n// formulário para zero linha é construir tela por leitura de documento.\n//\n// Ficam as quatro que sustentam os números e a rotina:\n//\n// Vínculo de onde saem headcount, admissões, demissões, turnover e\n// experiência vencendo. Sem ele nenhum número de RH existe\n// Férias obrigação legal, recorrente, e a única lista do V1 que\n// alimenta um cartão do painel\n// Afastamentos e aqui o V2 faz o que o V1 não faz: ver o comentário em\n// `v_workforce_day` da migration 005\n// Pendências a outra lista que o painel cobra\n//\n// A TELA É UMA SÓ, e isso é decisão. O V1 separa o painel (`/rh`) da ficha\n// (dentro do cadastro da pessoa), e o próprio FLOW anota que nenhum cartão e\n// nenhuma linha do painel é clicável — \"daqui não se chega à ficha da pessoa\".\n// Ler que três pessoas têm férias vencendo e ter de procurar cada uma noutra\n// tela é o gesto que a divisão custa. Aqui o painel é a porta: clicar no nome\n// abre a ficha embaixo.\n// ---------------------------------------------------------------------------\n\nconst CONTRATO: Record<ContractKind, string> = {\n clt: 'CLT', pj: 'PJ', estagio: 'Estágio', jovem_aprendiz: 'Jovem Aprendiz',\n autonomo: 'Autônomo', socio: 'Sócio', temporario: 'Temporário', intermitente: 'Intermitente',\n}\nconst REGIME: Record<ScheduleRegime, string> = {\n mensalista: 'Mensalista', horista: 'Horista', diarista: 'Diarista',\n escala_12x36: 'Escala 12x36', escala_6x1: 'Escala 6x1', escala_5x2: 'Escala 5x2',\n}\nconst PAGAMENTO: Record<PayFrequency, string> = {\n mensal: 'Mensal', quinzenal: 'Quinzenal', semanal: 'Semanal', diario: 'Diário', por_hora: 'Por hora',\n}\nconst FERIAS: Record<VacationStatus, string> = {\n pendente: 'Pendente', programada: 'Programada', em_gozo: 'Em gozo',\n concluida: 'Concluída', vencida: 'Vencida',\n}\nexport const AFASTAMENTO: Record<AbsenceKind, string> = {\n falta_justificada: 'Falta justificada', falta_injustificada: 'Falta injustificada',\n atestado: 'Atestado médico', licenca_maternidade: 'Licença maternidade',\n licenca_paternidade: 'Licença paternidade', licenca_nao_remunerada: 'Licença não remunerada',\n suspensao: 'Suspensão', ferias: 'Férias', afastamento_inss: 'Afastamento INSS',\n}\nconst PRIORIDADE: Record<PendingPriority, string> = {\n baixa: 'Baixa', normal: 'Normal', alta: 'Alta', urgente: 'Urgente',\n}\n\nfunction dm(iso?: string | null): string {\n if (!iso) return '—'\n const [a, m, d] = iso.slice(0, 10).split('-')\n return `${d}/${m}/${a}`\n}\n\n/** Um cartão de número. Zero é resposta, não ausência — ver o comentário abaixo. */\nfunction Cartao({ icon: Icon, label, value, alerta }: {\n icon: React.ComponentType<{ className?: string }>\n label: string\n value: React.ReactNode\n alerta?: boolean\n}) {\n return (\n <div className=\"rounded-xl border border-border p-4\">\n <div className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <Icon className=\"h-3.5 w-3.5\" aria-hidden /> {label}\n </div>\n <div className={`mt-1 text-2xl font-semibold tabular-nums ${alerta ? 'text-destructive' : ''}`}>\n {value}\n </div>\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// O painel\n// ---------------------------------------------------------------------------\n\nfunction Painel({ overview, upcoming, onPessoa }: {\n overview: HrOverview\n upcoming: HrUpcoming[]\n onPessoa: (id: string) => void\n}) {\n // Turnover é conta de tela de propósito: a view devolve as duas parcelas, e\n // dividir aqui evita uma coluna que mente quando o headcount é zero.\n const turnover = overview.headcount > 0\n ? ((overview.dismissals30d / overview.headcount) * 100).toFixed(1)\n : null\n\n const porEspecie = (k: HrUpcoming['kind']) => upcoming.filter((u) => u.kind === k).slice(0, 10)\n\n const listas: Array<{ kind: HrUpcoming['kind']; titulo: string; vazio: string }> = [\n { kind: 'vacation', titulo: 'Férias a vencer', vazio: 'Nenhuma.' },\n { kind: 'probation', titulo: 'Experiência vencendo', vazio: 'Nenhuma.' },\n { kind: 'pending', titulo: 'Pendências críticas', vazio: 'Nenhuma.' },\n ]\n\n return (\n <div className=\"space-y-4\">\n <div className=\"grid gap-3 sm:grid-cols-2 lg:grid-cols-4\">\n <Cartao icon={Users} label=\"Headcount ativo\" value={overview.headcount} />\n <Cartao icon={UserPlus} label=\"Admissões (30d)\" value={overview.admissions30d} />\n <Cartao icon={UserMinus} label=\"Demissões (30d)\" value={overview.dismissals30d} />\n <Cartao icon={AlertTriangle} label=\"Turnover (30d)\" value={turnover != null ? `${turnover}%` : '—'} />\n <Cartao icon={CakeSlice} label=\"Aniversariantes do mês\" value={overview.birthdaysThisMonth} />\n <Cartao icon={Plane} label=\"Férias vencendo (60d)\" value={overview.vacationsDue60d}\n alerta={overview.vacationsDue60d > 0} />\n <Cartao icon={CalendarClock} label=\"Experiência vencendo\" value={overview.probationEnding}\n alerta={overview.probationEnding > 0} />\n <Cartao icon={ShieldAlert} label=\"Pendências críticas\" value={overview.criticalPending}\n alerta={overview.criticalPending > 0} />\n </div>\n\n <div className=\"grid gap-3 lg:grid-cols-3\">\n {listas.map(({ kind, titulo, vazio }) => {\n const itens = porEspecie(kind)\n return (\n <div key={kind} className=\"overflow-hidden rounded-xl border border-border\">\n <div className=\"border-b border-border bg-muted/40 px-4 py-2 text-sm font-medium\">{titulo}</div>\n {itens.length === 0 ? (\n <p className=\"px-4 py-3 text-sm text-muted-foreground\">{vazio}</p>\n ) : (\n <ul className=\"divide-y divide-border\">\n {itens.map((u, i) => (\n <li key={`${u.personId}|${u.dueOn}|${i}`} className=\"flex items-center justify-between gap-2 px-4 py-2 text-sm\">\n {/* O NOME, que o V1 não mostra nesta lista (V1-073) — lá\n são só datas, e descobrir de quem é exige outra tela. */}\n <button type=\"button\" onClick={() => onPessoa(u.personId)}\n className=\"truncate text-left underline decoration-dashed decoration-muted-foreground/40 underline-offset-2 hover:text-primary\">\n {u.personName ?? 'Sem nome'}\n </button>\n <span className=\"shrink-0 text-xs tabular-nums text-muted-foreground\">{dm(u.dueOn)}</span>\n </li>\n ))}\n </ul>\n )}\n </div>\n )\n })}\n </div>\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// A ficha de uma pessoa\n// ---------------------------------------------------------------------------\n\nfunction CampoData({ label, value, onChange }: { label: string; value?: string | null; onChange: (v: string) => void }) {\n return (\n <label className=\"block\">\n <span className=\"mb-1 block text-xs text-muted-foreground\">{label}</span>\n <Input type=\"date\" value={value ?? ''} onChange={(e) => onChange(e.target.value)} />\n </label>\n )\n}\n\nfunction Vinculo({ personId }: { personId: string }) {\n const provider = useWorkforceProvider()\n const { currency } = useWorkforceConfig()\n const [form, setForm] = React.useState<Employment>({ personId })\n const [busy, setBusy] = React.useState(false)\n const [carregando, setCarregando] = React.useState(true)\n\n React.useEffect(() => {\n let vivo = true\n setCarregando(true)\n provider.getEmployment(personId)\n .then((e) => { if (vivo) { setForm(e ?? { personId }); setCarregando(false) } })\n .catch(() => { if (vivo) { setForm({ personId }); setCarregando(false) } })\n return () => { vivo = false }\n }, [provider, personId])\n\n const set = <K extends keyof Employment>(k: K, v: Employment[K]) => setForm((f) => ({ ...f, [k]: v }))\n\n async function salvar() {\n setBusy(true)\n try {\n await provider.saveEmployment({ ...form, personId })\n toast.success('Vínculo salvo.')\n } catch (e: any) {\n toast.error('Não deu para salvar', { description: e?.message })\n } finally {\n setBusy(false)\n }\n }\n\n if (carregando) return <Skeleton className=\"h-48 w-full\" />\n\n return (\n <div className=\"space-y-3 rounded-xl border border-border p-4\">\n <h4 className=\"text-sm font-semibold\">Vínculo</h4>\n <div className=\"grid gap-3 sm:grid-cols-2 lg:grid-cols-4\">\n <label className=\"block\">\n <span className=\"mb-1 block text-xs text-muted-foreground\">Tipo de contrato</span>\n <Select value={form.contractKind ?? ''} onValueChange={(v) => set('contractKind', v as ContractKind)}>\n <SelectTrigger><SelectValue placeholder=\"—\" /></SelectTrigger>\n <SelectContent>\n {Object.entries(CONTRATO).map(([k, r]) => <SelectItem key={k} value={k}>{r}</SelectItem>)}\n </SelectContent>\n </Select>\n </label>\n <CampoData label=\"Admissão\" value={form.admissionDate} onChange={(v) => set('admissionDate', v)} />\n <CampoData label=\"Demissão\" value={form.dismissalDate} onChange={(v) => set('dismissalDate', v)} />\n <CampoData label=\"Fim da experiência\" value={form.probationFinalEnd} onChange={(v) => set('probationFinalEnd', v)} />\n <label className=\"block\">\n <span className=\"mb-1 block text-xs text-muted-foreground\">Cargo</span>\n <Input value={form.jobTitle ?? ''} onChange={(e) => set('jobTitle', e.target.value)} />\n </label>\n <label className=\"block\">\n <span className=\"mb-1 block text-xs text-muted-foreground\">Setor</span>\n <Input value={form.department ?? ''} onChange={(e) => set('department', e.target.value)} />\n </label>\n <label className=\"block\">\n <span className=\"mb-1 block text-xs text-muted-foreground\">Regime de jornada</span>\n <Select value={form.scheduleRegime ?? ''} onValueChange={(v) => set('scheduleRegime', v as ScheduleRegime)}>\n <SelectTrigger><SelectValue placeholder=\"—\" /></SelectTrigger>\n <SelectContent>\n {Object.entries(REGIME).map(([k, r]) => <SelectItem key={k} value={k}>{r}</SelectItem>)}\n </SelectContent>\n </Select>\n </label>\n <label className=\"block\">\n <span className=\"mb-1 block text-xs text-muted-foreground\">Horas semanais</span>\n <Input type=\"number\" value={form.weeklyHours ?? ''} onChange={(e) => set('weeklyHours', e.target.value ? Number(e.target.value) : null)} />\n </label>\n <label className=\"block\">\n <span className=\"mb-1 block text-xs text-muted-foreground\">Salário base ({currency.symbol})</span>\n <Input type=\"number\" step=\"0.01\" value={form.baseSalary ?? ''} onChange={(e) => set('baseSalary', e.target.value ? Number(e.target.value) : null)} />\n </label>\n <label className=\"block\">\n <span className=\"mb-1 block text-xs text-muted-foreground\">Forma de pagamento</span>\n <Select value={form.payFrequency ?? ''} onValueChange={(v) => set('payFrequency', v as PayFrequency)}>\n <SelectTrigger><SelectValue placeholder=\"—\" /></SelectTrigger>\n <SelectContent>\n {Object.entries(PAGAMENTO).map(([k, r]) => <SelectItem key={k} value={k}>{r}</SelectItem>)}\n </SelectContent>\n </Select>\n </label>\n </div>\n {/* A frase que o V1 não escreve e que o FLOW teve de transcrever: estes\n valores não viram lançamento. Sem ela alguém espera o salário na conta\n a pagar do mês seguinte. */}\n <p className=\"text-xs text-muted-foreground\">\n Salário e auxílios são <b>valores de referência</b>: não viram conta a pagar, comissão nem desconto.\n </p>\n <div className=\"flex justify-end\">\n <Button onClick={salvar} disabled={busy}>Salvar vínculo</Button>\n </div>\n </div>\n )\n}\n\n/** Uma lista da ficha: cabeçalho, linhas e o diálogo de lançamento. */\nfunction Lista({ titulo, icon: Icon, itens, vazio, onNovo, children }: {\n titulo: string\n icon: React.ComponentType<{ className?: string }>\n itens: unknown[]\n vazio: string\n onNovo: () => void\n children: React.ReactNode\n}) {\n return (\n <div className=\"overflow-hidden rounded-xl border border-border\">\n <div className=\"flex items-center justify-between gap-2 border-b border-border bg-muted/40 px-4 py-2\">\n <span className=\"flex items-center gap-2 text-sm font-medium\">\n <Icon className=\"h-4 w-4 text-muted-foreground\" aria-hidden /> {titulo}\n </span>\n <Button size=\"sm\" variant=\"outline\" onClick={onNovo}>\n <Plus className=\"mr-1 h-3.5 w-3.5\" aria-hidden /> Novo\n </Button>\n </div>\n {itens.length === 0\n ? <p className=\"px-4 py-3 text-sm text-muted-foreground\">{vazio}</p>\n : <ul className=\"divide-y divide-border\">{children}</ul>}\n </div>\n )\n}\n\nfunction Ficha({ personId, personName }: { personId: string; personName?: string | null }) {\n const provider = useWorkforceProvider()\n const [ferias, setFerias] = React.useState<Vacation[]>([])\n const [faltas, setFaltas] = React.useState<Absence[]>([])\n const [pendencias, setPendencias] = React.useState<PendingItem[]>([])\n const [dialogo, setDialogo] = React.useState<'ferias' | 'falta' | 'pendencia' | null>(null)\n\n const recarregar = React.useCallback(() => {\n provider.getVacations(personId).then(setFerias).catch(() => setFerias([]))\n provider.getAbsences(personId).then(setFaltas).catch(() => setFaltas([]))\n provider.getPendingItems(personId).then(setPendencias).catch(() => setPendencias([]))\n }, [provider, personId])\n\n React.useEffect(() => { recarregar() }, [recarregar])\n\n return (\n <div className=\"space-y-3\">\n <h3 className=\"text-base font-semibold\">{personName ?? 'Ficha'}</h3>\n <Vinculo personId={personId} />\n\n <div className=\"grid gap-3 lg:grid-cols-3\">\n <Lista titulo=\"Férias\" icon={Plane} itens={ferias} vazio=\"Nenhum registro.\"\n onNovo={() => setDialogo('ferias')}>\n {ferias.map((v) => (\n <li key={v.id} className=\"flex items-center justify-between gap-2 px-4 py-2 text-sm\">\n <span className=\"truncate\">{dm(v.accrualStart)} – {dm(v.accrualEnd)}</span>\n <Badge variant={v.status === 'concluida' ? 'secondary' : v.status === 'vencida' ? 'destructive' : 'outline'}>\n {FERIAS[v.status]}\n </Badge>\n </li>\n ))}\n </Lista>\n\n <Lista titulo=\"Afastamentos\" icon={Stethoscope} itens={faltas} vazio=\"Nenhum registro.\"\n onNovo={() => setDialogo('falta')}>\n {faltas.map((a) => (\n <li key={a.id} className=\"flex items-center justify-between gap-2 px-4 py-2 text-sm\">\n <span className=\"truncate\">{AFASTAMENTO[a.kind]}</span>\n <span className=\"shrink-0 text-xs tabular-nums text-muted-foreground\">\n {dm(a.startsOn)}{a.endsOn ? ` – ${dm(a.endsOn)}` : ''}\n </span>\n </li>\n ))}\n </Lista>\n\n <Lista titulo=\"Pendências\" icon={ClipboardList} itens={pendencias} vazio=\"Nenhum registro.\"\n onNovo={() => setDialogo('pendencia')}>\n {pendencias.map((p) => (\n <li key={p.id} className=\"flex items-center justify-between gap-2 px-4 py-2 text-sm\">\n <label className=\"flex min-w-0 items-center gap-2\">\n <input\n type=\"checkbox\"\n checked={!!p.resolvedAt}\n onChange={(e) => provider.resolvePendingItem(p.id!, e.target.checked).then(recarregar)}\n />\n <span className={`truncate ${p.resolvedAt ? 'text-muted-foreground line-through' : ''}`}>{p.title}</span>\n </label>\n {!p.resolvedAt && (p.priority === 'alta' || p.priority === 'urgente') && (\n <Badge variant=\"destructive\">{PRIORIDADE[p.priority]}</Badge>\n )}\n </li>\n ))}\n </Lista>\n </div>\n\n {dialogo && (\n <DialogoLancamento\n tipo={dialogo}\n personId={personId}\n onClose={() => setDialogo(null)}\n onSaved={() => { setDialogo(null); recarregar() }}\n />\n )}\n </div>\n )\n}\n\n/** Um diálogo para as três listas. As três têm a mesma forma: datas e um tipo. */\nfunction DialogoLancamento({ tipo, personId, onClose, onSaved }: {\n tipo: 'ferias' | 'falta' | 'pendencia'\n personId: string\n onClose: () => void\n onSaved: () => void\n}) {\n const provider = useWorkforceProvider()\n const [busy, setBusy] = React.useState(false)\n const [de, setDe] = React.useState('')\n const [ate, setAte] = React.useState('')\n const [kind, setKind] = React.useState<AbsenceKind>('atestado')\n const [titulo, setTitulo] = React.useState('')\n const [prioridade, setPrioridade] = React.useState<PendingPriority>('normal')\n\n const rotulo = tipo === 'ferias' ? 'Período de férias'\n : tipo === 'falta' ? 'Afastamento' : 'Pendência'\n\n async function salvar() {\n setBusy(true)\n try {\n if (tipo === 'ferias') {\n if (!de || !ate) { toast.error('O período aquisitivo é obrigatório.'); return }\n await provider.saveVacation({ personId, accrualStart: de, accrualEnd: ate, status: 'pendente' })\n } else if (tipo === 'falta') {\n if (!de) { toast.error('A data de início é obrigatória.'); return }\n await provider.saveAbsence({ personId, kind, startsOn: de, endsOn: ate || null, paid: true })\n } else {\n if (!titulo.trim()) { toast.error('A pendência precisa de um título.'); return }\n await provider.savePendingItem({ personId, title: titulo.trim(), priority: prioridade, dueOn: de || null })\n }\n toast.success(`${rotulo} lançado.`)\n onSaved()\n } catch (e: any) {\n toast.error('Não deu para salvar', { description: e?.message })\n } finally {\n setBusy(false)\n }\n }\n\n return (\n <Modal open onOpenChange={(o) => { if (!o) onClose() }}>\n <ModalContent>\n {/* \"Novo período de férias\", e não \"Novo Férias\". O V1 monta este título\n por concatenação e sai com a concordância errada — V1-076. */}\n <ModalHeader><ModalTitle>Novo {rotulo.toLowerCase()}</ModalTitle></ModalHeader>\n <ModalBody className=\"space-y-3\">\n {tipo === 'falta' && (\n <Select value={kind} onValueChange={(v) => setKind(v as AbsenceKind)}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n {Object.entries(AFASTAMENTO).map(([k, r]) => <SelectItem key={k} value={k}>{r}</SelectItem>)}\n </SelectContent>\n </Select>\n )}\n {tipo === 'pendencia' && (\n <>\n <Input value={titulo} onChange={(e) => setTitulo(e.target.value)} placeholder=\"O que falta (obrigatório)\" />\n <Select value={prioridade} onValueChange={(v) => setPrioridade(v as PendingPriority)}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n {Object.entries(PRIORIDADE).map(([k, r]) => <SelectItem key={k} value={k}>{r}</SelectItem>)}\n </SelectContent>\n </Select>\n </>\n )}\n <CampoData\n label={tipo === 'ferias' ? 'Início aquisitivo' : tipo === 'falta' ? 'Início' : 'Prazo'}\n value={de} onChange={setDe}\n />\n {tipo !== 'pendencia' && (\n <CampoData label={tipo === 'ferias' ? 'Fim aquisitivo' : 'Fim'} value={ate} onChange={setAte} />\n )}\n </ModalBody>\n <ModalFooter>\n <Button variant=\"ghost\" onClick={onClose}>Cancelar</Button>\n <Button onClick={salvar} disabled={busy}>Salvar</Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n )\n}\n\n// ---------------------------------------------------------------------------\n\nexport function HrView() {\n const provider = useWorkforceProvider()\n const { staffLookup } = useWorkforceConfig()\n const [overview, setOverview] = React.useState<HrOverview | null>(null)\n const [upcoming, setUpcoming] = React.useState<HrUpcoming[]>([])\n const [equipe, setEquipe] = React.useState<WorkforcePerson[]>([])\n const [loading, setLoading] = React.useState(true)\n const [pessoa, setPessoa] = React.useState<{ id: string; name?: string | null } | null>(null)\n\n React.useEffect(() => {\n let vivo = true\n Promise.all([provider.getHrOverview(), provider.getHrUpcoming(), provider.getStaff()])\n .then(([o, u, e]) => { if (vivo) { setOverview(o); setUpcoming(u); setEquipe(e); setLoading(false) } })\n .catch(() => { if (vivo) { setOverview(null); setUpcoming([]); setEquipe([]); setLoading(false) } })\n return () => { vivo = false }\n }, [provider])\n\n const nomeDe = React.useCallback(\n (id: string) => upcoming.find((u) => u.personId === id)?.personName ?? null,\n [upcoming],\n )\n\n if (loading) return <div className=\"space-y-3\"><Skeleton className=\"h-28 w-full\" /><Skeleton className=\"h-40 w-full\" /></div>\n\n return (\n <div className=\"space-y-4\">\n {/* O seletor fica em cima, sempre — inclusive quando há painel.\n Sem ele a tela vazia é um beco: ela manda abrir a ficha \"pelo\n cadastro\" e não diz como, que é literalmente a crítica que o FLOW faz\n ao V1 (\"daqui não se chega à ficha da pessoa\"). Uma ficha nasce aqui. */}\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"text-sm text-muted-foreground\">Abrir a ficha de</span>\n <Select value={pessoa?.id ?? ''} onValueChange={(id) => {\n const p = equipe.find((x) => x.id === id)\n setPessoa({ id, name: p?.name ?? nomeDe(id) })\n }}>\n <SelectTrigger className=\"w-72\">\n <SelectValue placeholder={equipe.length ? 'Escolha alguém da equipe…' : 'Nenhuma pessoa cadastrada'} />\n </SelectTrigger>\n <SelectContent>\n {equipe.map((p) => <SelectItem key={p.id} value={p.id}>{p.name ?? 'Sem nome'}</SelectItem>)}\n </SelectContent>\n </Select>\n </div>\n\n {overview\n ? <Painel overview={overview} upcoming={upcoming} onPessoa={(id) => setPessoa({ id, name: nomeDe(id) })} />\n : (\n // `null` aqui não é erro: `v_workforce_hr_overview` agrupa por tenant e\n // só devolve linha quando existe ao menos um VÍNCULO. Ninguém com\n // vínculo = nada para agrupar. Dizer \"nenhuma ficha ainda\" é a leitura\n // certa; um painel de zeros diria que o time tem zero pessoas.\n <div className=\"rounded-xl border border-dashed border-border p-8 text-center\">\n <Users className=\"mx-auto mb-3 h-8 w-8 text-muted-foreground\" aria-hidden />\n <p className=\"text-sm text-muted-foreground\">\n Nenhuma ficha trabalhista ainda. Escolha alguém acima e preencha o vínculo —\n é dele que saem headcount, admissões e experiência vencendo.\n </p>\n </div>\n )}\n\n {pessoa && (\n <div className=\"rounded-xl border border-border p-4\">\n <div className=\"mb-3 flex items-center justify-between gap-2\">\n <PersonLink personId={pessoa.id} name={pessoa.name ?? 'Pessoa'} kind=\"staff\" lookup={staffLookup} />\n <Button size=\"sm\" variant=\"ghost\" onClick={() => setPessoa(null)}>Fechar</Button>\n </div>\n <Ficha personId={pessoa.id} personName={pessoa.name} />\n </div>\n )}\n </div>\n )\n}\n","import React from 'react'\nimport type { StoreApi } from 'zustand/vanilla'\nimport { ModulePage, type ModuleNavItem } from '@fayz-ai/ui'\nimport {\n useModuleNavigation, parseViewId, useModuleNavAccess,\n EntitlementGate, UpgradePrompt,\n} from '@fayz-ai/admin'\nimport type { EntityDef } from '@fayz-ai/core'\nimport { WorkforceContextProvider, type ResolvedWorkforceConfig } from '../context'\nimport type { WorkforceDataProvider } from '../data/types'\nimport type { WorkforceUIState } from '../store'\nimport { SchedulesView } from './SchedulesView'\nimport { TemplatesView } from './TemplatesView'\nimport { TimeEntriesView } from './TimeEntriesView'\nimport { PeriodsView } from './PeriodsView'\nimport { PeopleView } from './PeopleView'\nimport { PayrollCostsView } from './PayrollCostsView'\nimport { HrView } from './HrView'\n\n// ---------------------------------------------------------------------------\n// A intenção: que subtela, em que modo.\n// ---------------------------------------------------------------------------\n\nexport interface ViewIntent {\n view: string\n mode?: 'list' | 'new' | 'edit' | 'detail'\n editId?: string\n}\n\nfunction parseIntent(activeView: string): ViewIntent {\n // `parseViewId` recolhe '<base>-detail:<id>' / '<base>-edit:<id>' — a forma\n // que `useModuleNavigation` produz a partir da rota.\n const { base, id } = parseViewId(activeView)\n const m = base.match(/^(people)-(new|list|detail|edit)$/)\n if (m) return { view: m[1], mode: m[2] as ViewIntent['mode'], editId: id }\n return { view: base }\n}\n\n// ---------------------------------------------------------------------------\n// A sub-navegação do módulo.\n// ---------------------------------------------------------------------------\n\nfunction buildNav(config: ResolvedWorkforceConfig, activeView: string, navigate: (view: string) => void): ModuleNavItem[] {\n const items: ModuleNavItem[] = []\n\n if (config.modules.schedules) {\n items.push({\n id: 'schedules',\n label: config.labels.schedules,\n icon: 'CalendarDays',\n active: activeView === 'schedules',\n onClick: () => navigate('schedules'),\n })\n }\n\n if (config.modules.templates) {\n items.push({\n id: 'templates',\n label: config.labels.templates,\n icon: 'LayoutTemplate',\n active: activeView === 'templates',\n onClick: () => navigate('templates'),\n })\n }\n\n if (config.modules.timeEntries) {\n items.push({\n id: 'time-entries',\n label: config.labels.timeEntries,\n icon: 'Clock',\n active: activeView === 'time-entries',\n onClick: () => navigate('time-entries'),\n })\n }\n\n if (config.modules.periods) {\n items.push({\n id: 'periods',\n label: config.labels.periods,\n icon: 'Lock',\n active: activeView === 'periods',\n onClick: () => navigate('periods'),\n })\n }\n\n if (config.modules.people) {\n items.push({\n id: 'people',\n label: config.labels.people,\n icon: 'UserCog',\n active: activeView.startsWith('people'),\n onClick: () => navigate('people'),\n })\n }\n\n // Depois do ponto e antes do fechamento: a ficha é o que explica o que a\n // folha de ponto mostra — quem está de atestado, quem está em férias.\n if (config.modules.hr) {\n items.push({\n id: 'hr',\n label: config.labels.hr,\n icon: 'BriefcaseBusiness',\n active: activeView === 'hr',\n onClick: () => navigate('hr'),\n })\n }\n\n if (config.modules.payrollCosts) {\n items.push({\n id: 'payroll-costs',\n label: config.labels.payrollCosts,\n icon: 'HandCoins',\n active: activeView === 'payroll-costs',\n onClick: () => navigate('payroll-costs'),\n })\n }\n\n // Cada item carrega a feature de acesso que o APP mapeou. `useModuleNavAccess`\n // esconde o que o papel nega e coroa o que o plano nega; id fora do mapa fica\n // aberto — o plugin não tem opinião sobre o que é pago.\n for (const item of items) {\n const feature = config.navFeatureMap[item.id]\n if (feature) item.feature = feature\n }\n\n return items\n}\n\n// ---------------------------------------------------------------------------\n// A página\n// ---------------------------------------------------------------------------\n\nexport function WorkforcePage({ config, provider, store, staffEntity }: {\n config: ResolvedWorkforceConfig\n provider: WorkforceDataProvider\n store: StoreApi<WorkforceUIState>\n staffEntity?: EntityDef\n}) {\n // A casa do módulo é Escalas: é a tela que se abre todo dia, e é onde o RH\n // decide alguma coisa. Fechamento é mensal e Templates é anual.\n const { view, direction, navigate } = useModuleNavigation(\n '/workforce',\n {\n schedules: 0, templates: 0, 'time-entries': 0, periods: 0,\n people: 0, 'people-detail': 1, 'people-edit': 2,\n 'payroll-costs': 0,\n },\n 'schedules',\n )\n\n const intent = parseIntent(view)\n const nav = useModuleNavAccess(buildNav(config, view, navigate))\n\n function renderView() {\n // Módulo desligado é desligado também pela URL: tirar o link sem fechar a\n // rota deixaria /workforce/periods inteiro de pé para quem digitar.\n const off =\n (intent.view === 'schedules' && !config.modules.schedules) ||\n (intent.view === 'templates' && !config.modules.templates) ||\n (intent.view === 'time-entries' && !config.modules.timeEntries) ||\n (intent.view === 'periods' && !config.modules.periods) ||\n (intent.view === 'people' && !config.modules.people) ||\n (intent.view === 'hr' && !config.modules.hr) ||\n (intent.view === 'payroll-costs' && !config.modules.payrollCosts)\n if (off) return <SchedulesView />\n\n switch (intent.view) {\n case 'templates': return <TemplatesView />\n case 'time-entries': return <TimeEntriesView />\n case 'periods': return <PeriodsView />\n case 'people': return <PeopleView entity={staffEntity} />\n case 'hr': return <HrView />\n case 'payroll-costs': return <PayrollCostsView />\n case 'schedules':\n default: return <SchedulesView />\n }\n }\n\n // O paywall da subtela vive AQUI porque uma aba interna não é rota do shell —\n // o guarda de rota nunca a vê. Mesmo mapa que coroa o link acima, para que um\n // link de graça nunca fique sobre conteúdo trancado.\n function renderGatedView() {\n const feature = config.navFeatureMap[intent.view]\n if (!feature) return renderView()\n return (\n <EntitlementGate feature={feature} fallback={<UpgradePrompt feature={feature} />}>\n {renderView()}\n </EntitlementGate>\n )\n }\n\n return (\n <WorkforceContextProvider config={config} provider={provider} store={store}>\n <ModulePage\n title={config.labels.pageTitle}\n subtitle={config.labels.pageSubtitle}\n nav={nav}\n navVariant={config.moduleNav}\n showHeader={intent.view === 'schedules'}\n viewKey={view}\n direction={direction}\n >\n {renderGatedView()}\n </ModulePage>\n </WorkforceContextProvider>\n )\n}\n","import type { WorkforceDataProvider } from './types'\nimport type {\n TimeEntry, TimeEntryQuery, TimeAdjustmentInput,\n WorkDay,\n WorkforcePeriod,\n ScheduleTemplate, SaveTemplateInput, SaveShiftInput, SaveRequirementInput,\n DaySchedule, ScheduleQuery, CreateScheduleInput,\n WorkforcePerson,\n PayrollCostRow, PayrollCostQuery,\n} from '../types'\n\n// ---------------------------------------------------------------------------\n// O provider de memória.\n//\n// Serve para montar o app sem banco nenhum: a mesma superfície do Supabase, com\n// uma semente pequena o bastante para caber na cabeça e grande o bastante para\n// a tela mostrar os três estados que importam — o dia certo, a FALTA e o ponto\n// FORA DA ESCALA.\n// ---------------------------------------------------------------------------\n\nlet seq = 1\nconst uid = () => `mock-${seq++}`\n\nfunction isoDate(offsetDays: number): string {\n const d = new Date()\n d.setDate(d.getDate() + offsetDays)\n return d.toISOString().slice(0, 10)\n}\n\nfunction at(date: string, time: string): string {\n return new Date(`${date}T${time}:00`).toISOString()\n}\n\nexport function createMockWorkforceProvider(): WorkforceDataProvider {\n const people: WorkforcePerson[] = [\n { id: 'p1', name: 'Ana Ribeiro', isActive: true },\n { id: 'p2', name: 'Carlos Menezes', isActive: true },\n { id: 'p3', name: 'Júlia Prado', isActive: true },\n ]\n\n const yesterday = isoDate(-1)\n const today = isoDate(0)\n\n const entries: TimeEntry[] = [\n {\n id: uid(), personId: 'p1', personName: 'Ana Ribeiro', kind: 'clock_in',\n workDate: yesterday, seq: 1, origin: 'totem',\n punchedAt: at(yesterday, '08:03'), effectiveAt: at(yesterday, '08:00'),\n adjusted: true, voided: false, adjustmentReason: 'Totem fora de hora',\n adjustedByName: 'Gerente', evidence: {},\n },\n {\n id: uid(), personId: 'p1', personName: 'Ana Ribeiro', kind: 'break_start',\n workDate: yesterday, seq: 2, origin: 'totem',\n punchedAt: at(yesterday, '12:00'), effectiveAt: at(yesterday, '12:00'),\n adjusted: false, voided: false, evidence: {},\n },\n {\n id: uid(), personId: 'p1', personName: 'Ana Ribeiro', kind: 'break_end',\n workDate: yesterday, seq: 3, origin: 'totem',\n punchedAt: at(yesterday, '13:00'), effectiveAt: at(yesterday, '13:00'),\n adjusted: false, voided: false, evidence: {},\n },\n {\n id: uid(), personId: 'p1', personName: 'Ana Ribeiro', kind: 'clock_out',\n workDate: yesterday, seq: 4, origin: 'totem',\n punchedAt: at(yesterday, '17:00'), effectiveAt: at(yesterday, '17:00'),\n adjusted: false, voided: false, evidence: {},\n },\n // Ponto em aberto: entrou e não saiu. É o caso que o V1 nunca soma.\n {\n id: uid(), personId: 'p2', personName: 'Carlos Menezes', kind: 'clock_in',\n workDate: today, seq: 1, origin: 'totem',\n punchedAt: at(today, '09:12'), effectiveAt: at(today, '09:12'),\n adjusted: false, voided: false, evidence: {},\n },\n ]\n\n const days: WorkDay[] = [\n {\n personId: 'p1', personName: 'Ana Ribeiro', workDate: yesterday,\n assignmentId: 'a1', shiftLabel: 'Almoço', shiftStartTime: '08:00', shiftEndTime: '17:00',\n assignmentStatus: 'confirmed', plannedMinutes: 540, workedMinutes: 480, varianceMinutes: -60,\n firstIn: at(yesterday, '08:00'), lastOut: at(yesterday, '17:00'), breakCount: 1,\n isOpen: false, absent: false, outsideSchedule: false,\n },\n // FALTA: escala publicada e nenhuma batida.\n {\n personId: 'p3', personName: 'Júlia Prado', workDate: yesterday,\n assignmentId: 'a2', shiftLabel: 'Jantar', shiftStartTime: '17:00', shiftEndTime: '23:00',\n assignmentStatus: 'notified', plannedMinutes: 360, workedMinutes: null, varianceMinutes: null,\n isOpen: false, absent: true, outsideSchedule: false,\n },\n // FORA DA ESCALA: batida sem previsto.\n {\n personId: 'p2', personName: 'Carlos Menezes', workDate: today,\n plannedMinutes: null, workedMinutes: null, varianceMinutes: null,\n firstIn: at(today, '09:12'), breakCount: 0,\n isOpen: true, absent: false, outsideSchedule: true,\n },\n ]\n\n const periods: WorkforcePeriod[] = [\n { id: uid(), competenceMonth: isoDate(0).slice(0, 7) + '-01', status: 'open' },\n ]\n\n const templates: ScheduleTemplate[] = [\n {\n id: 't1', name: 'Almoço Seg. a Sex.', isActive: true, shifts: [\n {\n id: 's1', templateId: 't1', label: 'Almoço',\n startTime: '11:00', endTime: '15:00', weekdays: [1, 2, 3, 4, 5],\n crossesMidnight: false, sortOrder: 0,\n requirements: [\n { id: 'r1', shiftId: 's1', professionName: 'Garçom', requiredCount: 2 },\n { id: 'r2', shiftId: 's1', professionName: 'Cozinha', requiredCount: 3 },\n ],\n },\n ],\n },\n ]\n\n const schedules: DaySchedule[] = [\n {\n id: 'sc1', scheduleDate: yesterday, templateId: 't1', status: 'published',\n publishedAt: at(yesterday, '07:00'), isSpecialDay: false,\n assignments: [\n {\n id: 'a1', scheduleId: 'sc1', shiftId: 's1', shiftLabel: 'Almoço',\n shiftStartTime: '08:00', shiftEndTime: '17:00', professionName: 'Garçom',\n personId: 'p1', personName: 'Ana Ribeiro', role: 'titular', priority: 0, status: 'confirmed',\n },\n {\n id: 'a2', scheduleId: 'sc1', shiftId: 's1', shiftLabel: 'Jantar',\n shiftStartTime: '17:00', shiftEndTime: '23:00', professionName: 'Cozinha',\n personId: 'p3', personName: 'Júlia Prado', role: 'titular', priority: 1, status: 'notified',\n },\n ],\n },\n ]\n\n function inRange(date: string, from: string, to: string) {\n return date >= from && date <= to\n }\n\n return {\n async getTimeEntries(query: TimeEntryQuery) {\n return entries.filter(\n (e) => inRange(e.workDate, query.from, query.to)\n && (!query.personId || e.personId === query.personId),\n )\n },\n async getWorkDays(query: TimeEntryQuery) {\n return days.filter(\n (d) => inRange(d.workDate, query.from, query.to)\n && (!query.personId || d.personId === query.personId),\n )\n },\n // Sem storage não há foto. `null` e não uma imagem de exemplo: o mock existe\n // para montar a tela sem banco, e um rosto inventado aqui esconderia\n // justamente o estado que a tela precisa saber desenhar.\n async signPunchPhotos() {\n return {}\n },\n\n // ── A ficha trabalhista, em memória ──────────────────────────────────\n //\n // Vazia, e não semeada. O mock existe para montar a tela sem banco, e um\n // salário de exemplo aqui apareceria numa ficha de RH — que é o lugar onde\n // dado inventado é mais caro de distinguir do real.\n async getHrOverview() { return null },\n async getHrUpcoming() { return [] },\n async getEmployment() { return null },\n async saveEmployment() { /* sem banco, nada persiste */ },\n async getVacations() { return [] },\n async saveVacation() { },\n async getAbsences() { return [] },\n async saveAbsence() { },\n async getPendingItems() { return [] },\n async savePendingItem() { },\n async resolvePendingItem() { },\n async adjustTimeEntry(input: TimeAdjustmentInput) {\n const entry = entries.find((e) => e.id === input.timeEntryId)\n if (!entry) return\n if (input.action === 'void') {\n entry.voided = true\n } else if (input.effectiveAt) {\n entry.effectiveAt = input.effectiveAt\n entry.adjusted = true\n }\n entry.adjustmentReason = input.reason\n },\n\n async getPeriods() { return [...periods] },\n async closePeriod(competenceMonth: string, notes?: string) {\n const found = periods.find((p) => p.competenceMonth === competenceMonth)\n if (found) {\n found.status = 'closed'\n found.closedAt = new Date().toISOString()\n found.notes = notes ?? null\n } else {\n periods.unshift({\n id: uid(), competenceMonth, status: 'closed',\n closedAt: new Date().toISOString(), notes: notes ?? null,\n })\n }\n },\n async reopenPeriod(competenceMonth: string, reason: string) {\n const found = periods.find((p) => p.competenceMonth === competenceMonth)\n if (!found) return\n found.status = 'open'\n found.reopenedAt = new Date().toISOString()\n found.reopenReason = reason\n },\n\n async getTemplates() { return templates },\n async saveTemplate(input: SaveTemplateInput) {\n if (input.id) {\n const found = templates.find((t) => t.id === input.id)\n if (found) Object.assign(found, { name: input.name, isActive: input.isActive ?? true, notes: input.notes ?? null })\n return input.id\n }\n const id = uid()\n templates.push({ id, name: input.name, isActive: input.isActive ?? true, notes: input.notes ?? null, shifts: [] })\n return id\n },\n async deleteTemplate(id: string) {\n const i = templates.findIndex((t) => t.id === id)\n if (i >= 0) templates.splice(i, 1)\n },\n async saveShift(input: SaveShiftInput) {\n const template = templates.find((t) => t.id === input.templateId)\n if (!template) return ''\n if (input.id) {\n const found = template.shifts.find((s) => s.id === input.id)\n if (found) Object.assign(found, {\n label: input.label, startTime: input.startTime, endTime: input.endTime, weekdays: input.weekdays,\n })\n return input.id\n }\n const id = uid()\n template.shifts.push({\n id, templateId: template.id, label: input.label,\n startTime: input.startTime, endTime: input.endTime, weekdays: input.weekdays,\n crossesMidnight: input.endTime <= input.startTime,\n sortOrder: input.sortOrder ?? template.shifts.length,\n requirements: [],\n })\n return id\n },\n async deleteShift(id: string) {\n for (const t of templates) {\n const i = t.shifts.findIndex((s) => s.id === id)\n if (i >= 0) t.shifts.splice(i, 1)\n }\n },\n async saveRequirement(input: SaveRequirementInput) {\n for (const t of templates) {\n const shift = t.shifts.find((s) => s.id === input.shiftId)\n if (!shift) continue\n if (input.id) {\n const found = shift.requirements.find((r) => r.id === input.id)\n if (found) Object.assign(found, { professionName: input.professionName, requiredCount: input.requiredCount })\n return input.id\n }\n const id = uid()\n shift.requirements.push({ id, shiftId: shift.id, professionName: input.professionName, requiredCount: input.requiredCount })\n return id\n }\n return ''\n },\n async deleteRequirement(id: string) {\n for (const t of templates) {\n for (const s of t.shifts) {\n const i = s.requirements.findIndex((r) => r.id === id)\n if (i >= 0) s.requirements.splice(i, 1)\n }\n }\n },\n\n async getSchedules(query: ScheduleQuery) {\n return schedules.filter((s) => inRange(s.scheduleDate, query.from, query.to))\n },\n async createSchedule(input: CreateScheduleInput) {\n const id = uid()\n schedules.push({\n id, scheduleDate: input.scheduleDate, templateId: input.templateId,\n status: 'draft', isSpecialDay: false, notes: input.notes ?? null, assignments: [],\n })\n return id\n },\n async publishSchedule(scheduleId: string) {\n const found = schedules.find((s) => s.id === scheduleId)\n if (!found) return\n found.status = 'published'\n found.publishedAt = new Date().toISOString()\n },\n\n async getStaff() { return people },\n\n // Mesma forma do provider real: ESTRUTURA (sem mês) + MOVIMENTO, com uma\n // conta zerada e uma linha sem classificação, que são os dois casos que a\n // tela desenha de um jeito próprio.\n async getPayrollCosts(query: PayrollCostQuery): Promise<PayrollCostRow[]> {\n const month = query.from.slice(0, 7) + '-01'\n return [\n { chartAccountId: 'r3', chartAccountCode: '3', chartAccountName: 'DESPESAS COM PESSOAL', competenceMonth: null, total: 0 },\n { chartAccountId: 'r31', chartAccountCode: '3.1', chartAccountName: 'Folha de pagamento', competenceMonth: null, total: 0 },\n { chartAccountId: 'c1', chartAccountCode: '3.1.01', chartAccountName: 'Salários', competenceMonth: null, total: 0 },\n { chartAccountId: 'c2', chartAccountCode: '3.1.02', chartAccountName: 'Encargos sociais', competenceMonth: null, total: 0 },\n { chartAccountId: 'c3', chartAccountCode: '3.1.03', chartAccountName: 'Honorários', competenceMonth: null, total: 0 },\n { chartAccountId: 'c4', chartAccountCode: '3.1.04', chartAccountName: 'Vale-transporte', competenceMonth: null, total: 0 },\n { chartAccountId: 'r4', chartAccountCode: '4', chartAccountName: 'DESPESAS ADMINISTRATIVAS', competenceMonth: null, total: 0 },\n { chartAccountId: 'c5', chartAccountCode: '4.1', chartAccountName: 'Aluguel', competenceMonth: null, total: 0 },\n { chartAccountId: 'c1', chartAccountCode: '3.1.01', chartAccountName: 'Salários', competenceMonth: month, total: 42800 },\n { chartAccountId: 'c2', chartAccountCode: '3.1.02', chartAccountName: 'Encargos sociais', competenceMonth: month, total: 13640 },\n { chartAccountId: 'c3', chartAccountCode: '3.1.03', chartAccountName: 'Honorários', competenceMonth: month, total: 5200 },\n { chartAccountId: null, chartAccountCode: null, chartAccountName: '', competenceMonth: month, total: 980 },\n ]\n },\n }\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { getSupabaseClientOptional, getActiveTenantId } from '@fayz-ai/core'\nimport { saveSchedule } from '@fayz-ai/admin'\nimport type { WorkforceDataProvider } from './types'\nimport type {\n TimeEntry, TimeEntryQuery, TimeAdjustmentInput, PunchPhoto,\n WorkDay,\n WorkforcePeriod,\n ScheduleTemplate, ScheduleShift, SaveTemplateInput, SaveShiftInput, SaveRequirementInput,\n DaySchedule, ScheduleAssignment, ScheduleQuery, CreateScheduleInput,\n WorkforcePerson,\n PayrollCostRow, PayrollCostQuery,\n Employment, Vacation, Absence, PendingItem, HrOverview, HrUpcoming,\n} from '../types'\n\n/** A espécie de horário que o RH oferta. Semeada pela migration 000. */\nexport const WORK_SHIFT_KIND = 'work_shift'\n\nfunction client(): any {\n const supabase = getSupabaseClientOptional() as any\n if (!supabase) throw new Error('Supabase not initialized')\n return supabase\n}\n\nfunction tenantId(): string | undefined {\n return getActiveTenantId() ?? undefined\n}\n\n// ---------------------------------------------------------------------------\n// O teto de uma resposta\n//\n// O PostgREST devolve no máximo 1000 linhas e NÃO avisa que cortou. Para uma\n// lista isso é paginação; para uma SOMA é um número menor que o real entregue\n// com cara de total — foi assim que esta tela mostrou R$ 140.406 onde o razão\n// dizia R$ 511.131, com quatro meses de folha ausentes da árvore. Quem soma\n// confere o tamanho do que voltou.\nconst PAGINA = 1000\n\n/** 'HH:MM:SS' → 'HH:MM'. O Postgres devolve segundos que nenhuma tela mostra. */\nfunction hhmm(t?: string | null): string | null {\n if (!t) return null\n return t.slice(0, 5)\n}\n\n// ---------------------------------------------------------------------------\n// Leituras\n// ---------------------------------------------------------------------------\n\nfunction mapTimeEntry(r: any): TimeEntry {\n return {\n id: r.id,\n unitId: r.unit_id,\n personId: r.person_id,\n personName: r.person_name,\n kind: r.kind,\n workDate: r.work_date,\n seq: r.seq,\n origin: r.origin,\n punchedAt: r.punched_at,\n effectiveAt: r.effective_at,\n adjusted: !!r.adjusted,\n voided: !!r.voided,\n adjustmentReason: r.adjustment_reason,\n adjustedByName: r.adjusted_by_name,\n assignmentId: r.assignment_id,\n payableInvoiceId: r.payable_invoice_id,\n evidence: r.evidence ?? {},\n photo: readPhoto(r.evidence),\n }\n}\n\n/**\n * `evidence.photo` → PunchPhoto, e nada além disso.\n *\n * `evidence.photo_path` NÃO serve: ele é o caminho no bucket privado do V1, de\n * outro projeto Supabase. Tratá-lo como ponteiro daria uma URL assinada que\n * sempre falha, e o erro apareceria como \"foto quebrada\" em vez de\n * \"foto não migrada\".\n */\nfunction readPhoto(evidence: any): PunchPhoto | null {\n const p = evidence?.photo\n if (!p || typeof p !== 'object' || !p.bucket || !p.path) return null\n return { bucket: String(p.bucket), path: String(p.path), documentId: p.document_id ?? null }\n}\n\nfunction mapWorkDay(r: any): WorkDay {\n return {\n personId: r.person_id,\n unitId: r.unit_id,\n workDate: r.work_date,\n assignmentId: r.assignment_id,\n shiftLabel: r.shift_label,\n shiftStartTime: hhmm(r.shift_start_time),\n shiftEndTime: hhmm(r.shift_end_time),\n assignmentStatus: r.assignment_status,\n plannedMinutes: r.planned_minutes,\n workedMinutes: r.worked_minutes,\n varianceMinutes: r.variance_minutes,\n firstIn: r.first_in,\n lastOut: r.last_out,\n breakCount: r.break_count,\n openSince: r.open_since,\n reviewReason: r.review_reason ?? null,\n isOpen: !!r.is_open,\n absent: !!r.absent,\n outsideSchedule: !!r.outside_schedule,\n }\n}\n\nexport function createSupabaseWorkforceProvider(): WorkforceDataProvider {\n /** Nome de gente por id, resolvido uma vez por consulta. A view do dia não\n * traz nome — ela agrupa por id, e inventar um join lá dentro custaria a\n * todo leitor. Aqui é uma consulta a mais e a tela ganha um rótulo. */\n /** Nome das unidades em lote. Vazio entra e sai vazio, sem ida ao banco. */\n async function unitNamesOf(ids: string[]): Promise<Map<string, string>> {\n const unique = [...new Set(ids)]\n if (!unique.length) return new Map()\n // `v_units`, não `app.units`: o PostgREST só expõe `public`, e a view é a\n // porta que o resto do SDK já usa (packages/admin/src/units/data.ts).\n const { data } = await client().from('v_units').select('id,name').in('id', unique)\n return new Map(((data ?? []) as any[]).map((u) => [u.id as string, u.name as string]))\n }\n\n async function namesOf(ids: string[]): Promise<Map<string, string>> {\n const out = new Map<string, string>()\n const unique = [...new Set(ids.filter(Boolean))]\n if (unique.length === 0) return out\n const { data } = await client().from('people').select('id,name').in('id', unique)\n for (const p of (data ?? []) as any[]) out.set(p.id, p.name)\n return out\n }\n\n // ── A ficha trabalhista (005) ───────────────────────────────────────────\n //\n // Sem `try/catch` por cima: a RLS de `workforce_hr` não devolve erro para quem\n // não tem a permissão, devolve ZERO LINHAS. Transformar isso num toast de erro\n // diria \"deu problema\" onde o certo é \"isto não é seu\".\n const hr = {\n async getHrOverview(): Promise<HrOverview | null> {\n const { data } = await client().from('v_workforce_hr_overview').select('*').maybeSingle()\n if (!data) return null\n const r = data as any\n return {\n headcount: r.headcount ?? 0,\n admissions30d: r.admissions_30d ?? 0,\n dismissals30d: r.dismissals_30d ?? 0,\n probationEnding: r.probation_ending ?? 0,\n birthdaysThisMonth: r.birthdays_this_month ?? 0,\n vacationsDue60d: r.vacations_due_60d ?? 0,\n criticalPending: r.critical_pending ?? 0,\n }\n },\n\n async getHrUpcoming(): Promise<HrUpcoming[]> {\n const { data } = await client().from('v_workforce_hr_upcoming').select('*').order('due_on')\n return ((data ?? []) as any[]).map((r) => ({\n kind: r.kind, personId: r.person_id, personName: r.person_name,\n dueOn: r.due_on, detail: r.detail,\n }))\n },\n\n async getEmployment(personId: string): Promise<Employment | null> {\n const { data } = await client().from('plg_workforce_employment')\n .select('*').eq('person_id', personId).maybeSingle()\n if (!data) return null\n const r = data as any\n return {\n id: r.id, personId: r.person_id,\n contractKind: r.contract_kind, admissionDate: r.admission_date,\n dismissalDate: r.dismissal_date, dismissalReason: r.dismissal_reason,\n probationFirstEnd: r.probation_first_end, probationFinalEnd: r.probation_final_end,\n jobTitle: r.job_title, department: r.department,\n scheduleRegime: r.schedule_regime,\n weeklyHours: r.weekly_hours, monthlyHours: r.monthly_hours,\n esocialRegistration: r.esocial_registration,\n baseSalary: r.base_salary, payFrequency: r.pay_frequency, notes: r.notes,\n }\n },\n\n async saveEmployment(input: Employment): Promise<void> {\n // `onConflict` no par (tenant, pessoa): é a UNIQUE da 005, e é ela que faz\n // \"salvar\" ser idempotente em vez de criar o segundo vínculo da mesma\n // pessoa — dois vínculos seriam dois headcounts para uma cabeça.\n const { error } = await client().from('plg_workforce_employment').upsert({\n tenant_id: tenantId(),\n person_id: input.personId,\n contract_kind: input.contractKind || null,\n admission_date: input.admissionDate || null,\n dismissal_date: input.dismissalDate || null,\n dismissal_reason: input.dismissalReason || null,\n probation_first_end: input.probationFirstEnd || null,\n probation_final_end: input.probationFinalEnd || null,\n job_title: input.jobTitle || null,\n department: input.department || null,\n schedule_regime: input.scheduleRegime || null,\n weekly_hours: input.weeklyHours ?? null,\n monthly_hours: input.monthlyHours ?? null,\n esocial_registration: input.esocialRegistration || null,\n base_salary: input.baseSalary ?? null,\n pay_frequency: input.payFrequency || null,\n notes: input.notes || null,\n }, { onConflict: 'tenant_id,person_id' })\n if (error) throw error\n },\n\n async getVacations(personId: string): Promise<Vacation[]> {\n const { data } = await client().from('plg_workforce_vacations')\n .select('*').eq('person_id', personId).order('accrual_end', { ascending: false })\n return ((data ?? []) as any[]).map((r) => ({\n id: r.id, personId: r.person_id,\n accrualStart: r.accrual_start, accrualEnd: r.accrual_end,\n takenStart: r.taken_start, takenEnd: r.taken_end,\n daysTaken: r.days_taken, daysSold: r.days_sold,\n status: r.status, notes: r.notes,\n }))\n },\n\n async saveVacation(input: Vacation): Promise<void> {\n const row = {\n tenant_id: tenantId(), person_id: input.personId,\n accrual_start: input.accrualStart, accrual_end: input.accrualEnd,\n taken_start: input.takenStart || null, taken_end: input.takenEnd || null,\n days_taken: input.daysTaken ?? null, days_sold: input.daysSold ?? null,\n status: input.status, notes: input.notes || null,\n }\n const q = client().from('plg_workforce_vacations')\n const { error } = input.id ? await q.update(row).eq('id', input.id) : await q.insert(row)\n if (error) throw error\n },\n\n async getAbsences(personId: string): Promise<Absence[]> {\n const { data } = await client().from('plg_workforce_absences')\n .select('*').eq('person_id', personId).order('starts_on', { ascending: false })\n return ((data ?? []) as any[]).map((r) => ({\n id: r.id, personId: r.person_id, kind: r.kind,\n startsOn: r.starts_on, endsOn: r.ends_on, days: r.days,\n paid: !!r.paid, icdCode: r.icd_code, doctor: r.doctor, notes: r.notes,\n }))\n },\n\n async saveAbsence(input: Absence): Promise<void> {\n const row = {\n tenant_id: tenantId(), person_id: input.personId, kind: input.kind,\n starts_on: input.startsOn, ends_on: input.endsOn || null,\n days: input.days ?? null, paid: input.paid,\n icd_code: input.icdCode || null, doctor: input.doctor || null,\n notes: input.notes || null,\n }\n const q = client().from('plg_workforce_absences')\n const { error } = input.id ? await q.update(row).eq('id', input.id) : await q.insert(row)\n if (error) throw error\n },\n\n async getPendingItems(personId: string): Promise<PendingItem[]> {\n const { data } = await client().from('plg_workforce_pending_items')\n .select('*').eq('person_id', personId)\n .order('resolved_at', { ascending: true, nullsFirst: true })\n .order('due_on', { ascending: true })\n return ((data ?? []) as any[]).map((r) => ({\n id: r.id, personId: r.person_id, title: r.title,\n category: r.category, priority: r.priority,\n dueOn: r.due_on, resolvedAt: r.resolved_at, description: r.description,\n }))\n },\n\n async savePendingItem(input: PendingItem): Promise<void> {\n const row = {\n tenant_id: tenantId(), person_id: input.personId, title: input.title,\n category: input.category || null, priority: input.priority,\n due_on: input.dueOn || null, description: input.description || null,\n }\n const q = client().from('plg_workforce_pending_items')\n const { error } = input.id ? await q.update(row).eq('id', input.id) : await q.insert(row)\n if (error) throw error\n },\n\n async resolvePendingItem(id: string, resolved: boolean): Promise<void> {\n const { error } = await client().from('plg_workforce_pending_items')\n .update({ resolved_at: resolved ? new Date().toISOString() : null }).eq('id', id)\n if (error) throw error\n },\n }\n\n return {\n ...hr,\n // --- O realizado -------------------------------------------------------\n async getTimeEntries(query: TimeEntryQuery): Promise<TimeEntry[]> {\n let q = client()\n .from('v_workforce_time_entries')\n .select('*')\n .gte('work_date', query.from)\n .lte('work_date', query.to)\n .order('work_date', { ascending: false })\n .order('seq', { ascending: true })\n if (query.personId) q = q.eq('person_id', query.personId)\n if (query.unitId) q = q.eq('unit_id', query.unitId)\n const { data, error } = await q\n if (error) throw error\n return ((data ?? []) as any[]).map(mapTimeEntry)\n },\n\n async getWorkDays(query: TimeEntryQuery): Promise<WorkDay[]> {\n let q = client()\n .from('v_workforce_day')\n .select('*')\n .gte('work_date', query.from)\n .lte('work_date', query.to)\n .order('work_date', { ascending: false })\n if (query.personId) q = q.eq('person_id', query.personId)\n if (query.unitId) q = q.eq('unit_id', query.unitId)\n const { data, error } = await q\n if (error) throw error\n const rows = ((data ?? []) as any[]).map(mapWorkDay)\n // Nome da pessoa E da unidade em duas consultas, não uma por linha: a\n // view agrupa por id, e a tabela mostra nome. Resolver aqui, em lote, é a\n // diferença entre duas idas ao banco e trezentas.\n const [names, units] = await Promise.all([\n namesOf(rows.map((r) => r.personId)),\n unitNamesOf(rows.map((r) => r.unitId).filter(Boolean) as string[]),\n ])\n return rows.map((r) => ({\n ...r,\n personName: names.get(r.personId) ?? null,\n unitName: (r.unitId && units.get(r.unitId)) ?? null,\n }))\n },\n\n async signPunchPhotos(photos: PunchPhoto[], expiresInSeconds = 300): Promise<Record<string, string>> {\n const out: Record<string, string> = {}\n if (!photos.length) return out\n // Agrupado por bucket porque `createSignedUrls` assina uma lista DENTRO de\n // um bucket. Hoje é sempre o mesmo; agrupar agora é o que evita que a\n // segunda espécie de foto vire um caso especial mais tarde.\n const porBucket = new Map<string, string[]>()\n for (const p of photos) {\n const lista = porBucket.get(p.bucket) ?? []\n if (!lista.includes(p.path)) lista.push(p.path)\n porBucket.set(p.bucket, lista)\n }\n await Promise.all([...porBucket.entries()].map(async ([bucket, paths]) => {\n // A leitura de `storage.objects` é escopada por pasta de tenant pela\n // policy da migration 001: quem não é do tenant recebe erro aqui, e não\n // uma imagem.\n const { data, error } = await client().storage.from(bucket).createSignedUrls(paths, expiresInSeconds)\n if (error || !data) return\n for (const item of data as any[]) {\n // O item traz `path` (o que foi pedido) e `signedUrl`, ou `error`\n // quando aquele objeto específico não existe — um arquivo que o V1\n // perdeu não pode derrubar a assinatura dos outros 260.\n if (item?.signedUrl && item?.path) out[`${bucket}/${item.path}`] = item.signedUrl\n }\n }))\n return out\n },\n\n async adjustTimeEntry(input: TimeAdjustmentInput): Promise<void> {\n // INSERT, e só INSERT. A batida é append-only por trigger; o ajuste é\n // uma linha nova com autor e motivo, e o histórico fica.\n const { error } = await client()\n .from('plg_workforce_time_adjustments')\n .insert({\n tenant_id: tenantId(),\n time_entry_id: input.timeEntryId,\n action: input.action,\n effective_at: input.action === 'void' ? null : input.effectiveAt,\n reason: input.reason,\n })\n if (error) throw error\n },\n\n // --- A competência -----------------------------------------------------\n async getPeriods(): Promise<WorkforcePeriod[]> {\n const { data, error } = await client()\n .from('plg_workforce_periods')\n .select('*')\n .order('competence_month', { ascending: false })\n if (error) throw error\n return ((data ?? []) as any[]).map((r) => ({\n id: r.id,\n competenceMonth: r.competence_month,\n status: r.status,\n closedAt: r.closed_at,\n reopenedAt: r.reopened_at,\n reopenReason: r.reopen_reason,\n notes: r.notes,\n }))\n },\n\n async closePeriod(competenceMonth: string, notes?: string): Promise<void> {\n const { error } = await client().rpc('workforce_period_close', {\n p_month: competenceMonth,\n p_notes: notes ?? null,\n })\n if (error) throw error\n },\n\n async reopenPeriod(competenceMonth: string, reason: string): Promise<void> {\n const { error } = await client().rpc('workforce_period_reopen', {\n p_month: competenceMonth,\n p_reason: reason,\n })\n if (error) throw error\n },\n\n // --- O molde -----------------------------------------------------------\n async getTemplates(): Promise<ScheduleTemplate[]> {\n const { data: templates, error } = await client()\n .from('plg_workforce_schedule_templates')\n .select('*')\n .order('name')\n if (error) throw error\n const ids = ((templates ?? []) as any[]).map((t) => t.id)\n if (ids.length === 0) return []\n\n const { data: shifts } = await client()\n .from('plg_workforce_schedule_shifts')\n .select('*')\n .in('template_id', ids)\n .order('sort_order')\n const shiftIds = ((shifts ?? []) as any[]).map((s) => s.id)\n const { data: reqs } = shiftIds.length\n ? await client()\n .from('plg_workforce_schedule_requirements')\n .select('*')\n .in('shift_id', shiftIds)\n : { data: [] as any[] }\n\n const reqsByShift = new Map<string, any[]>()\n for (const r of (reqs ?? []) as any[]) {\n const list = reqsByShift.get(r.shift_id) ?? []\n list.push(r)\n reqsByShift.set(r.shift_id, list)\n }\n const shiftsByTemplate = new Map<string, ScheduleShift[]>()\n for (const s of (shifts ?? []) as any[]) {\n const list = shiftsByTemplate.get(s.template_id) ?? []\n list.push({\n id: s.id,\n templateId: s.template_id,\n label: s.label,\n startTime: hhmm(s.start_time) ?? '',\n endTime: hhmm(s.end_time) ?? '',\n weekdays: s.weekdays ?? [],\n crossesMidnight: !!s.crosses_midnight,\n sortOrder: s.sort_order ?? 0,\n requirements: (reqsByShift.get(s.id) ?? []).map((r) => ({\n id: r.id,\n shiftId: r.shift_id,\n professionName: r.profession_name,\n requiredCount: r.required_count,\n })),\n })\n shiftsByTemplate.set(s.template_id, list)\n }\n\n return ((templates ?? []) as any[]).map((t) => ({\n id: t.id,\n unitId: t.unit_id,\n name: t.name,\n isActive: !!t.is_active,\n notes: t.notes,\n shifts: shiftsByTemplate.get(t.id) ?? [],\n }))\n },\n\n async saveTemplate(input: SaveTemplateInput): Promise<string> {\n const row = {\n tenant_id: tenantId(),\n name: input.name,\n unit_id: input.unitId ?? null,\n is_active: input.isActive ?? true,\n notes: input.notes ?? null,\n }\n const table = client().from('plg_workforce_schedule_templates')\n const { data, error } = input.id\n ? await table.update(row).eq('id', input.id).select('id').single()\n : await table.insert(row).select('id').single()\n if (error) throw error\n return (data as any).id\n },\n\n async deleteTemplate(id: string): Promise<void> {\n const { error } = await client().from('plg_workforce_schedule_templates').delete().eq('id', id)\n if (error) throw error\n },\n\n async saveShift(input: SaveShiftInput): Promise<string> {\n const row = {\n tenant_id: tenantId(),\n template_id: input.templateId,\n label: input.label,\n start_time: input.startTime,\n end_time: input.endTime,\n weekdays: input.weekdays,\n sort_order: input.sortOrder ?? 0,\n }\n const table = client().from('plg_workforce_schedule_shifts')\n const { data, error } = input.id\n ? await table.update(row).eq('id', input.id).select('id').single()\n : await table.insert(row).select('id').single()\n if (error) throw error\n return (data as any).id\n },\n\n async deleteShift(id: string): Promise<void> {\n const { error } = await client().from('plg_workforce_schedule_shifts').delete().eq('id', id)\n if (error) throw error\n },\n\n async saveRequirement(input: SaveRequirementInput): Promise<string> {\n const row = {\n tenant_id: tenantId(),\n shift_id: input.shiftId,\n profession_name: input.professionName,\n required_count: input.requiredCount,\n }\n const table = client().from('plg_workforce_schedule_requirements')\n const { data, error } = input.id\n ? await table.update(row).eq('id', input.id).select('id').single()\n : await table.insert(row).select('id').single()\n if (error) throw error\n return (data as any).id\n },\n\n async deleteRequirement(id: string): Promise<void> {\n const { error } = await client().from('plg_workforce_schedule_requirements').delete().eq('id', id)\n if (error) throw error\n },\n\n // --- A instância do dia ------------------------------------------------\n async getSchedules(query: ScheduleQuery): Promise<DaySchedule[]> {\n let q = client()\n .from('plg_workforce_schedules')\n .select('*')\n .gte('schedule_date', query.from)\n .lte('schedule_date', query.to)\n .order('schedule_date')\n if (query.unitId) q = q.eq('unit_id', query.unitId)\n const { data: schedules, error } = await q\n if (error) throw error\n const ids = ((schedules ?? []) as any[]).map((s) => s.id)\n if (ids.length === 0) return []\n\n const { data: assignments } = await client()\n .from('plg_workforce_schedule_assignments')\n .select('*')\n .in('schedule_id', ids)\n .order('priority')\n const names = await namesOf(((assignments ?? []) as any[]).map((a) => a.person_id))\n\n const bySchedule = new Map<string, ScheduleAssignment[]>()\n for (const a of (assignments ?? []) as any[]) {\n const list = bySchedule.get(a.schedule_id) ?? []\n list.push({\n id: a.id,\n scheduleId: a.schedule_id,\n shiftId: a.shift_id,\n shiftLabel: a.shift_label,\n shiftStartTime: hhmm(a.shift_start_time),\n shiftEndTime: hhmm(a.shift_end_time),\n professionName: a.profession_name,\n personId: a.person_id,\n personName: names.get(a.person_id) ?? null,\n role: a.role,\n priority: a.priority ?? 0,\n status: a.status,\n scheduleRowId: a.schedule_row_id,\n })\n bySchedule.set(a.schedule_id, list)\n }\n\n return ((schedules ?? []) as any[]).map((s) => ({\n id: s.id,\n scheduleDate: s.schedule_date,\n templateId: s.template_id,\n unitId: s.unit_id,\n status: s.status,\n publishedAt: s.published_at,\n isSpecialDay: !!s.is_special_day,\n specialDayLabel: s.special_day_label,\n notes: s.notes,\n assignments: bySchedule.get(s.id) ?? [],\n }))\n },\n\n async createSchedule(input: CreateScheduleInput): Promise<string> {\n const tid = tenantId()\n const { data: created, error } = await client()\n .from('plg_workforce_schedules')\n .insert({\n tenant_id: tid,\n unit_id: input.unitId ?? null,\n schedule_date: input.scheduleDate,\n template_id: input.templateId,\n status: 'draft',\n notes: input.notes ?? null,\n })\n .select('id')\n .single()\n if (error) throw error\n const scheduleId = (created as any).id\n\n // O SNAPSHOT. O turno é copiado AGORA para dentro da atribuição: é o que\n // faz a escala de terça passada sobreviver a uma edição do molde hoje.\n const { data: shifts } = await client()\n .from('plg_workforce_schedule_shifts')\n .select('id,label,start_time,end_time,weekdays')\n .eq('template_id', input.templateId)\n const shiftById = new Map<string, any>()\n for (const s of (shifts ?? []) as any[]) shiftById.set(s.id, s)\n\n // Só os turnos que acontecem NESTE dia da semana. Copiar o molde inteiro\n // escalaria gente para um turno que não existe na terça.\n const dow = new Date(`${input.scheduleDate}T12:00:00`).getDay()\n const shiftIds = [...shiftById.values()]\n .filter((s) => (s.weekdays ?? []).includes(dow))\n .map((s) => s.id)\n if (shiftIds.length === 0) return scheduleId\n\n const { data: templateAssignments } = await client()\n .from('plg_workforce_schedule_template_assignments')\n .select('*')\n .in('shift_id', shiftIds)\n const rows = ((templateAssignments ?? []) as any[]).map((a) => {\n const shift = shiftById.get(a.shift_id)\n return {\n tenant_id: tid,\n unit_id: input.unitId ?? null,\n schedule_id: scheduleId,\n shift_id: a.shift_id,\n shift_label: shift?.label ?? null,\n shift_start_time: shift?.start_time ?? null,\n shift_end_time: shift?.end_time ?? null,\n profession_name: a.profession_name,\n person_id: a.person_id,\n role: a.role,\n priority: a.priority ?? 0,\n status: 'pending',\n }\n })\n if (rows.length > 0) {\n const { error: insErr } = await client()\n .from('plg_workforce_schedule_assignments')\n .insert(rows)\n if (insErr) throw insErr\n }\n return scheduleId\n },\n\n async publishSchedule(scheduleId: string): Promise<void> {\n const { data: schedule, error } = await client()\n .from('plg_workforce_schedules')\n .select('id,schedule_date,unit_id')\n .eq('id', scheduleId)\n .single()\n if (error) throw error\n\n const { data: assignments } = await client()\n .from('plg_workforce_schedule_assignments')\n .select('*')\n .eq('schedule_id', scheduleId)\n .eq('role', 'titular')\n .is('schedule_row_id', null)\n\n // A PONTE. Cada titular vira uma linha de `public.schedules` com\n // kind 'work_shift' — escrita pelo MESMO serviço que a agenda usa\n // (schedule-service do @fayz-ai/admin), e não por um segundo writer.\n for (const a of (assignments ?? []) as any[]) {\n if (!a.shift_start_time || !a.shift_end_time) continue\n try {\n const row = await saveSchedule({\n kind: WORK_SHIFT_KIND,\n assigneeId: a.person_id,\n locationId: (schedule as any).unit_id ?? undefined,\n specificDate: (schedule as any).schedule_date,\n startsAt: a.shift_start_time,\n endsAt: a.shift_end_time,\n })\n await client()\n .from('plg_workforce_schedule_assignments')\n .update({ schedule_row_id: row.id })\n .eq('id', a.id)\n } catch {\n // Uma atribuição que não materializa não pode impedir a publicação\n // das outras: a escala publicada é o aviso, e o espelho na agenda é\n // consequência dele.\n }\n }\n\n const { error: upErr } = await client()\n .from('plg_workforce_schedules')\n .update({ status: 'published', published_at: new Date().toISOString() })\n .eq('id', scheduleId)\n if (upErr) throw upErr\n },\n\n // --- Gente -------------------------------------------------------------\n async getStaff(): Promise<WorkforcePerson[]> {\n const { data, error } = await client()\n .from('people')\n .select('id,name,is_active')\n .eq('kind', 'staff')\n .order('name')\n if (error) throw error\n return ((data ?? []) as any[]).map((p) => ({\n id: p.id,\n name: p.name,\n isActive: p.is_active !== false,\n }))\n },\n\n // --- Encargos e honorários --------------------------------------------\n //\n // LEITURA do demonstrativo do Financeiro — `plg_financial_rep_dre`, a MESMA\n // view que o relatório de DRE desenha. Foram duas fontes por um tempo: esta\n // tela somava `v_financial_invoice_lines` linha a linha, e as duas podiam\n // discordar sem que nada avisasse. Conferido no cluster de Pertinho do Céu\n // em 19/09/2026, mês a mês: R$ 511.131,08 nos dois caminhos, nos cinco meses\n // com movimento.\n //\n // A view já faz três coisas que esta tela precisaria refazer:\n //\n // · AGREGA por conta × mês — a resposta cabe numa página em vez das 5.409\n // linhas do ano, que o PostgREST cortava em mil sem avisar;\n // · traz a ESTRUTURA do plano (linha com `competence_month` nulo), que é o\n // que põe a conta-mãe e a conta zerada na árvore;\n // · aplica a regra do demonstrativo: `statement_code` só classifica quando\n // a NATUREZA da conta casa com o sentido do título. Uma conta a pagar\n // lançada em conta de receita não vira um ramo de receita no meio das\n // despesas — vira \"sem classificação\", e continua no total.\n //\n // Um pedido por mês, em paralelo: a view devolve uma linha por conta × mês ×\n // unidade, e um ano inteiro de uma vez passaria de mil linhas num plano\n // grande. Somar as unidades é daqui — a tela mostra a casa inteira.\n async getPayrollCosts(query: PayrollCostQuery): Promise<PayrollCostRow[]> {\n // UM pedido, e não um por mês. A view varre fatura × pedido × item do\n // tenant inteiro e agrega; fria, uma varredura custa ~6s neste cluster e\n // meia dúzia em paralelo estoura o tempo do PostgREST — seis respostas\n // 500 e a tela dizendo que o Financeiro não está instalado. Uma varredura\n // só devolve tudo: 550 linhas para o ano inteiro, medido em 19/09/2026.\n const deMes = `${query.from.slice(0, 7)}-01`\n const { data, error } = await client()\n .from('plg_financial_rep_dre')\n .select('account_id,statement_code,statement_name,competence_month,amount')\n .eq('direction', 'payable')\n // A linha de ESTRUTURA não tem mês e precisa vir junto — é ela que põe\n // a conta-mãe e a conta zerada na árvore.\n .or(`competence_month.is.null,and(competence_month.gte.${deMes},competence_month.lte.${query.to})`)\n .limit(PAGINA)\n if (error) throw error\n\n const lote = (data ?? []) as any[]\n // Página cheia é suspeita de corte, e uma soma cortada é um número menor\n // que o real com cara de total.\n if (lote.length >= PAGINA) {\n throw new Error(`plg_financial_rep_dre: resposta no limite de ${PAGINA} `\n + 'linhas — o total não pode ser confiado')\n }\n\n // A view devolve uma linha por conta × mês × UNIDADE. A tela mostra a casa\n // inteira, então as unidades somam aqui.\n const out = new Map<string, PayrollCostRow>()\n for (const r of lote) {\n const code = (r.statement_code as string | null) ?? null\n const month = (r.competence_month as string | null) ?? null\n const key = `${code ?? ''}|${month ?? ''}`\n const atual = out.get(key) ?? {\n chartAccountId: (r.account_id as string | null) ?? null,\n chartAccountCode: code,\n chartAccountName: (r.statement_name as string | null) ?? '',\n competenceMonth: month,\n total: 0,\n }\n atual.total += Number(r.amount ?? 0)\n out.set(key, atual)\n }\n return [...out.values()]\n },\n }\n}\n\n","import { createStore, type StoreApi } from 'zustand/vanilla'\nimport type { WorkforceDataProvider } from './data/types'\nimport type { DaySchedule, ScheduleTemplate, TimeEntry, WorkDay, WorkforcePeriod, WorkforcePerson } from './types'\n\n/**\n * O estado que mais de uma tela do módulo lê.\n *\n * O que é só de uma tela (o formulário de turno, o diálogo de ajuste) fica na\n * própria tela — um store que guarda rascunho de formulário é um store que\n * ninguém consegue limpar.\n */\nexport interface WorkforceUIState {\n /** O dia selecionado no calendário de Escalas, em 'YYYY-MM-DD'. */\n selectedDate: string\n setSelectedDate: (date: string) => void\n\n schedules: DaySchedule[]\n schedulesLoading: boolean\n fetchSchedules: (from: string, to: string) => Promise<void>\n\n templates: ScheduleTemplate[]\n templatesLoading: boolean\n fetchTemplates: () => Promise<void>\n\n entries: TimeEntry[]\n days: WorkDay[]\n timeLoading: boolean\n fetchTime: (from: string, to: string) => Promise<void>\n\n periods: WorkforcePeriod[]\n periodsLoading: boolean\n fetchPeriods: () => Promise<void>\n\n staff: WorkforcePerson[]\n fetchStaff: () => Promise<void>\n}\n\nfunction todayISO(): string {\n const d = new Date()\n return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`\n}\n\nexport function createWorkforceStore(provider: WorkforceDataProvider): StoreApi<WorkforceUIState> {\n return createStore<WorkforceUIState>((set) => ({\n selectedDate: todayISO(),\n setSelectedDate: (date) => set({ selectedDate: date }),\n\n schedules: [],\n schedulesLoading: false,\n fetchSchedules: async (from, to) => {\n set({ schedulesLoading: true })\n try {\n set({ schedules: await provider.getSchedules({ from, to }) })\n } catch {\n set({ schedules: [] })\n } finally {\n set({ schedulesLoading: false })\n }\n },\n\n templates: [],\n templatesLoading: false,\n fetchTemplates: async () => {\n set({ templatesLoading: true })\n try {\n set({ templates: await provider.getTemplates() })\n } catch {\n set({ templates: [] })\n } finally {\n set({ templatesLoading: false })\n }\n },\n\n entries: [],\n days: [],\n timeLoading: false,\n fetchTime: async (from, to) => {\n set({ timeLoading: true })\n try {\n // As duas juntas de propósito: a lista de batidas sem o cruzamento é\n // uma folha de ponto que não sabe dizer quem faltou.\n const [entries, days] = await Promise.all([\n provider.getTimeEntries({ from, to }),\n provider.getWorkDays({ from, to }),\n ])\n set({ entries, days })\n } catch {\n set({ entries: [], days: [] })\n } finally {\n set({ timeLoading: false })\n }\n },\n\n periods: [],\n periodsLoading: false,\n fetchPeriods: async () => {\n set({ periodsLoading: true })\n try {\n set({ periods: await provider.getPeriods() })\n } catch {\n set({ periods: [] })\n } finally {\n set({ periodsLoading: false })\n }\n },\n\n staff: [],\n fetchStaff: async () => {\n try {\n set({ staff: await provider.getStaff() })\n } catch {\n set({ staff: [] })\n }\n },\n }))\n}\n","// AUTO-GENERATED from 000_baseline.sql, 001_a_prova_da_batida_tem_bytes.sql, 002_o_guarda_da_foto_olhava_o_nome_errado.sql, 003_o_ponto_em_aberto_para_de_mentir_a_duracao.sql, 004_a_jornada_implausivel_nao_soma.sql, 005_a_ficha_trabalhista_tem_onde_morar.sql, 006_o_custo_de_pessoal_e_um_ramo_do_plano.sql, 007_a_porta_de_servico_do_ponto_fecha_tambem.sql — regenerate with scripts/embed-migrations.mjs\n// SQL files are the source of truth; this inline copy lets the manifest declare\n// migrations as data. Do not edit by hand — run the embed script instead.\n\nexport const MIGRATION_000_BASELINE = `-- O RH ganha ponto e escala.\n--\n-- D9 · Gente & Jornada de trabalho é o último domínio inteiro do V1 sem NENHUMA\n-- contraparte no V2. O registro de features do app diz isso feature por feature:\n-- \\`sch.templates\\` P0 missing, \\`sch.calendar\\` P0 missing (\"Nenhum módulo do SDK é\n-- dono disso hoje — precisa de uma decisão antes de código\"), \\`sch.clock\\` P1\n-- missing (\"O que existe é o horário PREVISTO de trabalho. A batida realizada,\n-- com ajuste auditado, não existe\"), \\`sch.clock.adjust\\` P1 missing. O host\n-- previsto para os quatro é o mesmo: **plugin-workforce**. Este arquivo é a\n-- camada de dados dele.\n--\n-- ── O que foi medido na origem (Pertinho do Céu, licença 8, 07/09/2026) ──────\n--\n-- Da documentação do V1 (\\`docs/v1-guide/restaurante/escalas/FLOW.md\\` e\n-- \\`docs/v1-guide/agenda/ponto-eletronico/FLOW.md\\`), tudo verificado na tela:\n--\n-- 325 registros de ponto no período — e TODOS os 325 marcados\n-- \"Fora da escala\" (V1-043). A coluna existe justamente para cruzar\n-- ponto × escala e nunca varia: o ponto está ativo em \\`PC Serviços\\`\n-- enquanto a operação e as escalas são de \\`Pertinho do Céu\\`.\n-- 20 batimentos EM ABERTO, incluindo 5 de 5 hoje e 8 de 16 ontem; um\n-- deles com entrada às 23:29 e \"13h07 (parcial)\".\n-- R$ 47.747 o valor do período — SUBESTIMADO, porque o V1 só calcula valor no\n-- fechamento do par, e 20 pares nunca fecharam.\n-- 103 profissionais habilitados para arrastar numa vaga de template.\n-- 7 templates de escala no tenant.\n--\n-- Três dos números acima são sintoma do MESMO defeito de modelo, e é ele que\n-- este arquivo existe para não repetir: no V1 a batida é um par entrada/saída\n-- numa única linha, com o ajuste como colunas \\`*_adjusted_at\\` por cima. Um par\n-- que nunca fecha não tem duração, não tem valor e não tem como ser conferido\n-- contra nada.\n--\n-- ── Duas decisões de arquitetura que o repositório já tomou ─────────────────\n--\n-- 1. *\"Ponto é razão append-only, como todo saldo — nunca uma coluna que alguém\n-- edita.\"* (\\`docs/migration/how-to-port.json\\`, mv.sch.clock: *\"Batida é\n-- append-only e ajuste é registro separado com autor e motivo — apagar\n-- batida é o que a lei não permite.\"*)\n--\n-- Por isso \\`plg_workforce_time_entries\\` é append-only de verdade — trigger\n-- que recusa UPDATE e DELETE, e as policies de UPDATE/DELETE derrubadas\n-- depois do scaffold — e o ajuste do V1 (\\`checkin_adjusted_at\\`,\n-- \\`checkout_adjusted_at\\`, \\`adjustment_reason\\`, \\`adjusted_by_*\\`) vira LINHA em\n-- \\`plg_workforce_time_adjustments\\`, com autor, motivo e carimbo. A própria\n-- tela do V1 já enuncia a regra que o V2 passa a garantir no banco: *\"Os\n-- horários reais dos batimentos são preservados.\"*\n--\n-- 2. *\"Escala de funcionário NÃO mora na agenda — quem oferta horário é o RH, a\n-- agenda só consome.\"* (registro de features, domínio D3.)\n--\n-- Por isso a escala é deste plugin, e a ponte com a agenda é UMA coluna:\n-- \\`plg_workforce_schedule_assignments.schedule_row_id\\`, que aponta para a\n-- linha de \\`public.schedules\\` que a publicação materializa.\n--\n-- ── O que este arquivo NÃO cria, porque já existe ───────────────────────────\n--\n-- O PREVISTO já está no V2. \\`public.schedules\\` (spine) tem exatamente a forma\n-- de uma oferta de horário — \\`kind\\`, \\`assignee_id\\` → \\`public.people\\`,\n-- \\`day_of_week\\`, \\`specific_date\\`, \\`starts_at\\`, \\`ends_at\\`, \\`unit_id\\` — e\n-- \\`public.schedule_kinds\\` é o registro de espécies dela (hoje: working_hours,\n-- exception, block, unclassified). Criar uma tabela de escala prevista aqui\n-- seria a segunda tabela de horário do cluster, que diverge da primeira na\n-- próxima mudança. Em vez disso este arquivo **semeia a espécie \\`work_shift\\`** e\n-- usa \\`public.schedules\\`.\n--\n-- \\`public.people\\` também já resolve sozinha o pior defeito do modelo do V1: lá o\n-- ponto aponta para \\`person_type ENUM('professional','employee')\\` + \\`person_id\\`,\n-- uma FK polimórfica para duas tabelas de cadastro que a própria tela mistura\n-- (\"A aba mistura Profissional e Funcionário no mesmo filtro e na mesma lista, e\n-- a diferença entre os dois cadastros não é explicada em lugar nenhum\"). No V2\n-- os dois já são \\`public.people\\` com papel em \\`public.person_roles\\`, então o par\n-- vira UMA FK \\`person_id uuid → public.people(id)\\`.\n--\n-- NÃO porta \\`schedule_grids\\` / \\`schedule_grid_blocks\\`: apesar do nome são grade\n-- de disponibilidade de AGENDAMENTO, não escala de trabalho. Ficam registradas\n-- em \\`migration.excluded_tables\\` com o motivo, que é mais barato que descobrir\n-- isso de novo daqui a seis meses.\n--\n-- ── As três lacunas do V1 que o V2 resolve aqui ─────────────────────────────\n--\n-- (a) FECHAMENTO DE COMPETÊNCIA. O V1 não tem nenhum. Qualquer ajuste pode\n-- mudar, em silêncio, um mês de horas já entregue ao contador e já pago —\n-- e a única trava que existe é de tela: \\`payable_invoice_id\\` preenchido\n-- esconde o botão \"Ajustar\". Uma trava de tela é uma trava até a primeira\n-- chamada de API.\n-- → \\`plg_workforce_periods\\`, no MESMO padrão que o financeiro já provou em\n-- \\`plugin-financial/src/migrations/006\\`: competência é o MÊS (data no dia\n-- 1º, por constraint), é do TENANT e não da unidade (um mês meio fechado é\n-- a pior resposta possível para quem precisa dizer que acabou), a escrita\n-- é só por RPC (\\`workforce_period_close\\` / \\`workforce_period_reopen\\`, sem\n-- policy de INSERT/UPDATE — uma policy de UPDATE seria a porta dos fundos\n-- da trava), reabrir exige motivo, e a permissão de fechar é própria\n-- (\\`workforce.close_period\\`): quem bate ponto não é quem fecha o mês.\n-- A trava vira trigger sobre a batida E sobre o ajuste, e o ajuste ganha\n-- a segunda trava do V1, agora no banco: batida já vinculada a um título\n-- a pagar não aceita ajuste.\n--\n-- (b) JORNADA PREVISTA × REALIZADA. No V1 elas nunca se encontram: a coluna\n-- \"Escala\" da lista de ponto existe para isso e marcou 325 de 325 registros\n-- como \"Fora da escala\".\n-- → O PREVISTO mora em \\`public.schedules\\` com \\`kind = 'work_shift'\\` (não em\n-- tabela nova — ver acima); o REALIZADO mora em\n-- \\`plg_workforce_time_entries\\`; e o cruzamento é a view\n-- \\`public.v_workforce_day\\`, um FULL OUTER JOIN de propósito, para que as\n-- duas assimetrias apareçam em vez de sumirem: previsto sem realizado é\n-- FALTA, realizado sem previsto é FORA DA ESCALA. A publicação da escala\n-- materializa a linha de \\`public.schedules\\` e guarda o id em\n-- \\`plg_workforce_schedule_assignments.schedule_row_id\\`, que é o que torna\n-- o cruzamento uma chave e não uma heurística de nome e horário.\n--\n-- (c) INTERVALO / ALMOÇO. O V1 tem UM par entrada/saída por ciclo. Quem sai para\n-- almoçar e volta ou não registra o intervalo, ou bate a saída e a entrada e\n-- o dia vira dois registros que ninguém soma. Num restaurante com turno\n-- partido isso é a jornada inteira.\n-- → A batida deixa de ser um PAR numa linha e passa a ser um EVENTO:\n-- \\`kind ∈ (clock_in, break_start, break_end, clock_out)\\`, N por dia,\n-- agrupados por \\`(person_id, work_date)\\` e ordenados por \\`seq\\`. A mesma\n-- decisão que satisfaz o append-only resolve o intervalo de graça, e ainda\n-- responde \"quais pontos estão em aberto?\" sem coluna derivada: em aberto\n-- é o dia cujos eventos de abertura (clock_in, break_end) não empatam com\n-- os de fechamento (clock_out, break_start).\n-- \\`work_date\\` é coluna, e não \\`punched_at::date\\`, porque o V1 já convive\n-- com o turno que cruza a meia-noite — a própria caixa de ajuste avisa:\n-- *\"útil quando o funcionário esqueceu de bater a saída e o registro\n-- cruzou para o dia seguinte\"*. A jornada da noite de sábado é de sábado.\n--\n-- ── Uma decisão a mais, tomada na fronteira da migração ─────────────────────\n--\n-- No molde do V1, titular vs stand-by é POSICIONAL: são titulares os primeiros\n-- \\`required_count\\` de \\`schedule_template_assignments\\` por \\`priority\\`, e o resto\n-- é reserva. Ninguém grava isso; é uma regra que vive no código da tela. Na\n-- instância o V1 já tem \\`role\\` como coluna de verdade. Aqui o molde também tem:\n-- \\`plg_workforce_schedule_template_assignments.role\\` é coluna, e o writer da\n-- migração CALCULA a posição uma vez, contra o \\`required_count\\` da função,\n-- em vez de deixar a regra escondida em cada leitor que vier depois.\n--\n-- Idempotente. Nada aqui apaga dado.\n\n-- A RPC de fechamento consulta a view de cruzamento, que nasce três seções\n-- depois dela — as duas moram onde o assunto está, não onde o carregador\n-- preferiria. Sessão, e é o que os baselines gerados do cluster já fazem.\nSET check_function_bodies = false;\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 0. O plugin existe: as permissões\n-- ═══════════════════════════════════════════════════════════════════════════\n--\n-- O scaffold desenha as policies em cima de \\`<plugin>.read/create/edit/delete\\`\n-- e \\`<plugin>.read_all\\`. Sem essas chaves no catálogo, a policy compila e nega\n-- tudo para todo mundo — uma tabela protegida por não existir para ninguém.\n--\n-- Duas chaves são separadas de propósito, e as duas são segregação de função:\n-- \\`workforce.adjust_time\\` porque corrigir a batida de outra pessoa é outra\n-- ordem de decisão que editar uma escala, e \\`workforce.close_period\\` porque\n-- quem aponta não é quem fecha o mês.\nSELECT app.seed_permissions('[\n {\"key\": \"workforce.read\", \"plugin\": \"workforce\", \"description\": \"Ver escala, ponto e competência.\"},\n {\"key\": \"workforce.create\", \"plugin\": \"workforce\", \"description\": \"Criar escala, template e batida.\"},\n {\"key\": \"workforce.edit\", \"plugin\": \"workforce\", \"description\": \"Editar escala e template.\"},\n {\"key\": \"workforce.delete\", \"plugin\": \"workforce\", \"description\": \"Excluir escala e template.\"},\n {\"key\": \"workforce.manage\", \"plugin\": \"workforce\", \"description\": \"Administrar o módulo de jornada.\"},\n {\"key\": \"workforce.read_all\", \"plugin\": \"workforce\", \"description\": \"Ver a jornada de todo mundo, e não só a própria.\"},\n {\"key\": \"workforce.adjust_time\", \"plugin\": \"workforce\", \"description\": \"Ajustar batida de ponto. Separada de workforce.edit: corrigir a hora de outra pessoa é prova, não edição.\"},\n {\"key\": \"workforce.close_period\", \"plugin\": \"workforce\", \"description\": \"Fechar e reabrir a competência de jornada. Separada de workforce.edit: quem aponta não é quem fecha.\"}\n]'::jsonb);\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 1. O PREVISTO já existe — só falta a espécie\n-- ═══════════════════════════════════════════════════════════════════════════\n--\n-- \\`working_hours\\` é a semana recorrente do PROFISSIONAL, para a agenda saber que\n-- um horário pode existir. \\`work_shift\\` é outra coisa: é o turno de trabalho que\n-- o RH ofertou para uma pessoa num dia, e é contra ele que o ponto é conferido.\n-- Reaproveitar \\`working_hours\\` misturaria \"posso ser agendado\" com \"estou\n-- escalado\", que é justamente a confusão que o D3 mandou não fazer.\nINSERT INTO public.schedule_kinds (kind, plugin, description, status)\nVALUES ('work_shift', 'workforce',\n 'O turno de trabalho que o RH escalou para uma pessoa — o PREVISTO contra o qual o ponto é conferido. Distinto de working_hours, que diz apenas quando um horário PODE existir na agenda.',\n 'declared')\nON CONFLICT (kind) DO UPDATE\n SET plugin = EXCLUDED.plugin, description = EXCLUDED.description, updated_at = now();\n\n-- \\`public.schedules\\` foi scaffoldada em modo \\`shadow\\` (065): as policies de\n-- autorização existem, mas as anteriores nunca foram derrubadas, e RLS soma\n-- policies em OR — uma policy legada sobrevivente alarga tudo silenciosamente.\n-- A partir do momento em que a escala do RH mora aqui dentro, sombra não serve:\n-- \\`scaffold_set_mode\\` reemite com os MESMOS resource_type/plugin já registrados\n-- (\\`agenda.schedule\\` / \\`agenda\\`) e derruba o que sobrou. Não é \\`scaffold_table\\`:\n-- repetir o scaffold aqui reclassificaria uma tabela do spine para dentro deste\n-- plugin, e a agenda perderia a própria mesa.\nDO $$\nBEGIN\n IF to_regclass('public.schedules') IS NOT NULL\n AND EXISTS (SELECT 1 FROM app.scaffold_registry\n WHERE table_schema = 'public' AND table_name = 'schedules' AND mode = 'shadow') THEN\n PERFORM app.scaffold_set_mode('public.schedules'::regclass, 'enforce');\n END IF;\nEND $$;\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 2. O REALIZADO: a batida, append-only\n-- ═══════════════════════════════════════════════════════════════════════════\n\nCREATE TABLE IF NOT EXISTS public.plg_workforce_time_entries (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n unit_id uuid REFERENCES app.units(id),\n -- UMA fk, onde o V1 tem person_type + person_id. \\`public.people\\` já é o\n -- cadastro único; profissional e funcionário são papéis em person_roles.\n person_id uuid NOT NULL REFERENCES public.people(id) ON DELETE RESTRICT,\n -- O nome COMO ESTAVA na hora da batida. Não é desnormalização por preguiça: a\n -- folha de ponto é prova, e prova não pode mudar porque alguém corrigiu um\n -- cadastro dois anos depois.\n person_name text,\n -- O evento, não o par. É esta coluna que resolve o intervalo (c): o almoço é\n -- break_start + break_end, e o dia aceita quantos pares de intervalo houver.\n kind text NOT NULL\n CHECK (kind IN ('clock_in', 'break_start', 'break_end', 'clock_out')),\n punched_at timestamptz NOT NULL,\n -- O DIA DA JORNADA, que não é \\`punched_at::date\\`. O turno da noite de sábado\n -- que sai às 02:10 é jornada de sábado; o V1 já convive com isso e a própria\n -- caixa de ajuste dele avisa que o registro \"cruzou para o dia seguinte\".\n work_date date NOT NULL,\n -- Ordena os eventos do dia quando dois caem no mesmo instante (totem com\n -- clique duplo, importação em lote). Sem ele o \"último evento do dia\" é\n -- indeterminado, e é ele que diz se o ponto está em aberto.\n seq integer NOT NULL DEFAULT 1,\n origin text NOT NULL DEFAULT 'totem'\n CHECK (origin IN ('totem', 'device', 'manual', 'import', 'migration')),\n -- A prova que o totem produz: foto, coordenada com precisão, semelhança\n -- facial, IP e aparelho. Fica em jsonb e não em dez colunas porque é um\n -- conjunto de evidência de UM canal de captura — o totem com AWS Rekognition\n -- do V1 — e o próximo canal (crachá, biometria local) traz outro conjunto.\n -- O que não pode é perder: no V1 são \\`photo_path\\`, \\`lat\\`, \\`lng\\`, \\`accuracy_m\\`,\n -- \\`ip\\`, \\`user_agent\\` e \\`face_score\\`, medidos em campo como\n -- \"-22.89342, -43.39140 · ± 14m\" e \"Match facial 100.0%\".\n evidence jsonb NOT NULL DEFAULT '{}'::jsonb,\n -- O turno que esta batida cumpre, quando há um. Nulo é uma resposta legítima\n -- e frequente — é literalmente 325 de 325 no tenant medido — e o V2 prefere\n -- o nulo honesto a um vínculo inventado.\n assignment_id uuid,\n -- Onde esta hora custa. O turno traz o padrão (ver plg_workforce_schedule_shifts);\n -- a batida carrega o que de fato foi classificado, porque a hora do cozinheiro\n -- e a do garçom caem em centros de custo diferentes no mesmo dia.\n -- Sem FK inline: as três colunas abaixo apontam para tabelas de OUTRO plugin,\n -- e a jornada tem de poder ser instalada num cluster que não ligou o\n -- financeiro. A FK é declarada no fim do arquivo, condicionada à existência do\n -- destino — presente vira integridade, ausente vira só um uuid guardado.\n chart_account_id uuid,\n cost_center_id uuid,\n -- O \\`payable_invoice_id\\` do V1. No V1 ele é uma trava DE TELA (preenchido,\n -- o botão \"Ajustar\" some); aqui ele é uma trava de banco, pela trigger da\n -- seção 4. Hora já paga não se corrige sem reabrir a competência.\n payable_invoice_id uuid,\n notes text,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n -- A mesma pessoa não bate o mesmo evento duas vezes no mesmo instante. É o\n -- que torna o replay da migração e o clique duplo no totem inofensivos.\n UNIQUE (tenant_id, person_id, work_date, kind, punched_at, seq)\n);\n\nCOMMENT ON TABLE public.plg_workforce_time_entries IS\n 'A batida, append-only: um EVENTO (entrada, início/fim de intervalo, saída), nunca um par editável. '\n 'UPDATE e DELETE são recusados por trigger; a correção é uma linha em plg_workforce_time_adjustments.';\n\n-- \"O que foi batido neste período, nesta unidade?\" — a pergunta da aba Registros\n-- de Ponto, que o V1 responde com filtros De/Até/Unidade/Pessoa.\nCREATE INDEX IF NOT EXISTS plg_workforce_time_entries_period_idx\n ON public.plg_workforce_time_entries (tenant_id, unit_id, work_date, punched_at);\n\n-- \"Quais pontos estão em aberto?\" — 20 no tenant medido. Em aberto não é coluna\n-- (seria estado derivado numa tabela append-only): é o dia em que os eventos de\n-- ABERTURA não empatam com os de fechamento. Este índice serve a metade que a\n-- view varre, e responde sozinho \"quem entrou hoje e onde\".\nCREATE INDEX IF NOT EXISTS plg_workforce_time_entries_open_idx\n ON public.plg_workforce_time_entries (tenant_id, person_id, work_date, seq)\n WHERE kind IN ('clock_in', 'break_end');\n\n-- \"O que esta pessoa bateu?\" — a folha individual, e o que a folha de pagamento\n-- soma no fim do mês.\nCREATE INDEX IF NOT EXISTS plg_workforce_time_entries_person_idx\n ON public.plg_workforce_time_entries (tenant_id, person_id, work_date DESC);\n\nDROP TRIGGER IF EXISTS plg_workforce_time_entries_updated_at ON public.plg_workforce_time_entries;\nCREATE TRIGGER plg_workforce_time_entries_updated_at\n BEFORE UPDATE ON public.plg_workforce_time_entries\n FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();\n\nGRANT SELECT, INSERT ON public.plg_workforce_time_entries TO authenticated;\nGRANT SELECT, INSERT, UPDATE, DELETE ON public.plg_workforce_time_entries TO service_role;\n\n-- O scaffold é quem sabe desenhar a política deste cluster (tenant, unidade,\n-- permissão do plugin, escotilhas de compartilhamento). Escrever a policy à mão\n-- criaria a segunda regra de autorização da jornada, que diverge da primeira na\n-- próxima mudança do scaffold.\n--\n-- \\`p_owner_scoping = false\\`: a batida não tem dono no sentido de \"criada por\n-- mim\". Quem enxerga ponto de quem é \\`workforce.read\\` por unidade.\nSELECT app.scaffold_table('public.plg_workforce_time_entries'::regclass,\n 'workforce.time_entry', 'workforce', false, 'enforce');\n\n-- ── append-only, das duas formas ────────────────────────────────────────────\n--\n-- O scaffold acabou de criar policies de UPDATE e DELETE, porque é isso que ele\n-- faz em toda tabela. Aqui elas não deveriam existir: apagar batida é o que a\n-- lei não permite. As duas defesas são deliberadamente redundantes — a policy\n-- some para quem entra por \\`authenticated\\`, e a trigger pega também service_role\n-- e qualquer SECURITY DEFINER esquecido.\nDROP POLICY IF EXISTS plg_workforce_time_entries_authz_update ON public.plg_workforce_time_entries;\nDROP POLICY IF EXISTS plg_workforce_time_entries_authz_delete ON public.plg_workforce_time_entries;\n\nCREATE OR REPLACE FUNCTION public.plg_workforce_time_entries_append_only()\n RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $$\nBEGIN\n -- A escotilha é a mesma que o resto do cluster usa: durante uma onda de\n -- migração o motor marca a sessão, e só ela pode reescrever a linha que ela\n -- mesma acabou de trazer. Fora disso não há caminho.\n IF coalesce(current_setting('migration.writer', true), '') = 'on' THEN\n RETURN CASE TG_OP WHEN 'DELETE' THEN OLD ELSE NEW END;\n END IF;\n RAISE EXCEPTION 'plg_workforce_time_entries é append-only (% recusado) — corrija pelo ajuste, que é uma linha com autor e motivo', TG_OP\n USING ERRCODE = '42501',\n HINT = 'INSERT em plg_workforce_time_adjustments (action correct|insert|void) exige workforce.adjust_time.';\nEND $$;\n\nDROP TRIGGER IF EXISTS plg_workforce_time_entries_append_only ON public.plg_workforce_time_entries;\nCREATE TRIGGER plg_workforce_time_entries_append_only\n BEFORE UPDATE OR DELETE ON public.plg_workforce_time_entries\n FOR EACH ROW EXECUTE FUNCTION public.plg_workforce_time_entries_append_only();\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 3. O AJUSTE é uma linha, não uma coluna\n-- ═══════════════════════════════════════════════════════════════════════════\n--\n-- O V1 guarda o ajuste como quatro colunas na própria batida\n-- (\\`checkin_adjusted_at\\`, \\`checkout_adjusted_at\\`, \\`adjustment_reason\\`,\n-- \\`adjusted_by_*\\`) — o que já é melhor que sobrescrever, e é a parte boa do\n-- modelo dele: *\"Os horários reais dos batimentos são preservados.\"* O que ele\n-- não tem é HISTÓRICO: o segundo ajuste apaga o primeiro, e ninguém consegue\n-- dizer quantas vezes aquela hora mudou nem por quem.\n--\n-- Três ações, porque o V1 faz as três e chama todas de \"ajustar\":\n-- correct — a hora é outra (o caso comum)\n-- insert — faltou a batida (o \"esqueceu de bater a saída\" do V1; a batida\n-- nova entra em plg_workforce_time_entries com origin 'manual' e\n-- esta linha é quem carrega o autor e o motivo dela)\n-- void — esta batida não conta (o clique duplo, o totem testado). Não é\n-- DELETE: a linha fica, marcada, porque sumir com prova é o que o\n-- append-only existe para impedir.\nCREATE TABLE IF NOT EXISTS public.plg_workforce_time_adjustments (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n unit_id uuid REFERENCES app.units(id),\n time_entry_id uuid NOT NULL\n REFERENCES public.plg_workforce_time_entries(id) ON DELETE CASCADE,\n action text NOT NULL CHECK (action IN ('correct', 'insert', 'void')),\n -- A hora que passa a valer. Obrigatória em correct/insert e sem sentido em\n -- void — a constraint diz isso em vez de deixar para a tela lembrar.\n effective_at timestamptz,\n -- No V1 o motivo é OPCIONAL (\"Motivo (opcional)\"), e é por isso que ninguém\n -- sabe por que 20 pontos foram mexidos. Aqui é NOT NULL: um ajuste sem motivo\n -- registrado é indistinguível de uma fraude bem-educada.\n reason text NOT NULL,\n adjusted_by_user_id uuid,\n -- O nome de quem ajustou, congelado — mesma razão de \\`person_name\\`.\n adjusted_by_name text,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n CONSTRAINT plg_workforce_time_adjustments_effective_check\n CHECK ((action = 'void' AND effective_at IS NULL) OR (action <> 'void' AND effective_at IS NOT NULL)),\n CONSTRAINT plg_workforce_time_adjustments_reason_check\n CHECK (btrim(reason) <> '')\n);\n\nCOMMENT ON TABLE public.plg_workforce_time_adjustments IS\n 'O ajuste de ponto como LINHA, com autor e motivo obrigatório. O V1 guarda isso em colunas da própria batida e perde o histórico no segundo ajuste; aqui cada correção fica, e a hora que vale é a da última não anulada.';\n\n-- \"Qual a hora que vale nesta batida?\" — a view da seção 7 pergunta isso uma vez\n-- por batida, e é o caminho quente da folha de ponto inteira.\nCREATE INDEX IF NOT EXISTS plg_workforce_time_adjustments_entry_idx\n ON public.plg_workforce_time_adjustments (time_entry_id, created_at DESC);\n\nDROP TRIGGER IF EXISTS plg_workforce_time_adjustments_updated_at ON public.plg_workforce_time_adjustments;\nCREATE TRIGGER plg_workforce_time_adjustments_updated_at\n BEFORE UPDATE ON public.plg_workforce_time_adjustments\n FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();\n\nGRANT SELECT, INSERT, UPDATE, DELETE ON public.plg_workforce_time_adjustments TO authenticated, service_role;\n\nSELECT app.scaffold_table('public.plg_workforce_time_adjustments'::regclass,\n 'workforce.time_adjustment', 'workforce', false, 'enforce');\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 4. A COMPETÊNCIA (lacuna a)\n-- ═══════════════════════════════════════════════════════════════════════════\n--\n-- Mesmo desenho de \\`plg_financial_periods\\` (plugin-financial/006), de\n-- propósito: a empresa fecha UM mês, e ter dois calendários de fechamento com\n-- regras diferentes — um do dinheiro e outro das horas — é como não ter\n-- fechamento nenhum, porque a pergunta \"fevereiro está fechado?\" passa a ter\n-- duas respostas.\nCREATE TABLE IF NOT EXISTS public.plg_workforce_periods (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n -- A competência é do TENANT, não da unidade: fechar o mês é um ato de\n -- empresa, e um mês meio fechado é a pior resposta para quem precisa dizer ao\n -- contador que acabou. A coluna existe porque o scaffold precisa dela.\n unit_id uuid REFERENCES app.units(id),\n -- Sempre o dia 1º, por constraint e não por convenção de quem escreve.\n competence_month date NOT NULL,\n status text NOT NULL DEFAULT 'open' CHECK (status IN ('open', 'closed')),\n closed_at timestamptz,\n closed_by_user_id uuid,\n reopened_at timestamptz,\n reopened_by_user_id uuid,\n -- Reabrir sem dizer por quê é como não ter fechado. Obrigatório na RPC; a\n -- coluna aceita nulo porque um período nunca reaberto não tem um.\n reopen_reason text,\n -- O que o fechamento virou no financeiro, quando virou. A folha é uma conta a\n -- pagar como outra qualquer, e a classificação dela mora aqui porque é o\n -- fechamento — não a batida — que produz o lançamento.\n payable_invoice_id uuid,\n chart_account_id uuid,\n cost_center_id uuid,\n notes text,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n CONSTRAINT plg_workforce_periods_first_of_month_check\n CHECK (competence_month = date_trunc('month', competence_month)::date),\n CONSTRAINT plg_workforce_periods_tenant_month_key UNIQUE (tenant_id, competence_month)\n);\n\nCOMMENT ON TABLE public.plg_workforce_periods IS\n 'Competência mensal da jornada e seu estado. Fechada = nenhuma batida nem ajuste entra com data naquele mês. Escrita só por workforce_period_close/reopen.';\n\n-- A trava consulta \"este mês está fechado?\" a cada batida: índice parcial.\nCREATE INDEX IF NOT EXISTS plg_workforce_periods_closed_idx\n ON public.plg_workforce_periods (tenant_id, competence_month) WHERE status = 'closed';\n\nDROP TRIGGER IF EXISTS plg_workforce_periods_updated_at ON public.plg_workforce_periods;\nCREATE TRIGGER plg_workforce_periods_updated_at\n BEFORE UPDATE ON public.plg_workforce_periods\n FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at();\n\nGRANT SELECT ON public.plg_workforce_periods TO authenticated;\nGRANT SELECT, INSERT, UPDATE, DELETE ON public.plg_workforce_periods TO service_role;\n\nSELECT app.scaffold_table('public.plg_workforce_periods'::regclass,\n 'workforce.period', 'workforce', false, 'enforce');\n\n-- ESCREVER É SÓ PELA RPC. Fechar e reabrir são ATOS, não edições de linha, e o\n-- ato é onde a permissão e o registro de QUEM moram. Uma policy de UPDATE aqui\n-- seria a porta dos fundos da trava — é a mesma decisão do financeiro/006.\nDROP POLICY IF EXISTS plg_workforce_periods_authz_insert ON public.plg_workforce_periods;\nDROP POLICY IF EXISTS plg_workforce_periods_authz_update ON public.plg_workforce_periods;\nDROP POLICY IF EXISTS plg_workforce_periods_authz_delete ON public.plg_workforce_periods;\n\nCREATE OR REPLACE FUNCTION public.plg_workforce_period_is_closed(p_tenant uuid, p_date date)\n RETURNS boolean LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO ''\nAS $$\n SELECT EXISTS (\n SELECT 1 FROM public.plg_workforce_periods p\n WHERE p.tenant_id = p_tenant\n AND p.status = 'closed'\n AND p.competence_month = date_trunc('month', p_date)::date);\n$$;\n\nCOMMENT ON FUNCTION public.plg_workforce_period_is_closed(uuid, date) IS\n 'O mês desta data está fechado para a jornada deste tenant?';\n\n-- ── a trava sobre a batida ──────────────────────────────────────────────────\nCREATE OR REPLACE FUNCTION public.trg_workforce_refuse_closed_period()\n RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $$\nDECLARE\n v_date date;\nBEGIN\n -- Uma onda de migração traz o passado inteiro, e o passado inteiro está em\n -- meses que o V1 já tratou como encerrados. Fechar por cima do que ainda está\n -- chegando seria fechar antes de existir.\n IF coalesce(current_setting('migration.writer', true), '') = 'on' THEN\n RETURN NEW;\n END IF;\n\n -- A data que conta é a da JORNADA, não a de criação da linha.\n IF TG_TABLE_NAME = 'plg_workforce_time_entries' THEN\n v_date := NEW.work_date;\n ELSE\n SELECT e.work_date INTO v_date\n FROM public.plg_workforce_time_entries e WHERE e.id = NEW.time_entry_id;\n END IF;\n\n IF v_date IS NOT NULL AND public.plg_workforce_period_is_closed(NEW.tenant_id, v_date) THEN\n RAISE EXCEPTION 'a competência de % está fechada — reabra o período para lançar nela', to_char(v_date, 'MM/YYYY')\n USING ERRCODE = '23514',\n HINT = 'workforce_period_reopen(date_trunc(''month'', data)::date, ''motivo'') exige workforce.close_period.';\n END IF;\n\n RETURN NEW;\nEND $$;\n\nDROP TRIGGER IF EXISTS plg_workforce_time_entries_refuse_closed_period ON public.plg_workforce_time_entries;\nCREATE TRIGGER plg_workforce_time_entries_refuse_closed_period\n BEFORE INSERT ON public.plg_workforce_time_entries\n FOR EACH ROW EXECUTE FUNCTION public.trg_workforce_refuse_closed_period();\n\nDROP TRIGGER IF EXISTS plg_workforce_time_adjustments_refuse_closed_period ON public.plg_workforce_time_adjustments;\nCREATE TRIGGER plg_workforce_time_adjustments_refuse_closed_period\n BEFORE INSERT OR UPDATE ON public.plg_workforce_time_adjustments\n FOR EACH ROW EXECUTE FUNCTION public.trg_workforce_refuse_closed_period();\n\n-- ── a segunda trava do V1, agora no banco ───────────────────────────────────\n--\n-- No V1, batida com \\`payable_invoice_id\\` preenchido não pode ser ajustada — e a\n-- regra vive no componente que esconde o botão. Aqui ela vive onde não dá para\n-- contornar. A linha migrada é coberta pela mesma trava: o V1 aponta para uma\n-- tabela de títulos cuja contraparte no V2 não é a mesma coisa (ver a nota do\n-- de-para), então a referência crua fica em \\`metadata.v1.payable_invoice_id\\` — e\n-- basta ela existir para a hora estar travada.\nCREATE OR REPLACE FUNCTION public.trg_workforce_refuse_settled_adjustment()\n RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $$\nDECLARE\n v_entry public.plg_workforce_time_entries%ROWTYPE;\nBEGIN\n IF coalesce(current_setting('migration.writer', true), '') = 'on' THEN\n RETURN NEW;\n END IF;\n SELECT * INTO v_entry FROM public.plg_workforce_time_entries WHERE id = NEW.time_entry_id;\n IF v_entry.payable_invoice_id IS NOT NULL\n OR (v_entry.metadata #>> '{v1,payable_invoice_id}') IS NOT NULL THEN\n RAISE EXCEPTION 'esta batida já virou título a pagar — a hora paga não se corrige sem estornar o título'\n USING ERRCODE = '23514';\n END IF;\n IF NOT app.has_permission('workforce.adjust_time', v_entry.unit_id) THEN\n RAISE EXCEPTION 'ajustar ponto exige workforce.adjust_time' USING ERRCODE = '42501';\n END IF;\n RETURN NEW;\nEND $$;\n\nDROP TRIGGER IF EXISTS plg_workforce_time_adjustments_refuse_settled ON public.plg_workforce_time_adjustments;\nCREATE TRIGGER plg_workforce_time_adjustments_refuse_settled\n BEFORE INSERT ON public.plg_workforce_time_adjustments\n FOR EACH ROW EXECUTE FUNCTION public.trg_workforce_refuse_settled_adjustment();\n\n-- ── fechar e reabrir ────────────────────────────────────────────────────────\nCREATE OR REPLACE FUNCTION public.workforce_period_close(p_month date, p_notes text DEFAULT NULL)\n RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $$\nDECLARE\n v_tenant uuid := app.current_tenant_id();\n v_month date := date_trunc('month', p_month)::date;\n v_open bigint;\n v_row public.plg_workforce_periods%ROWTYPE;\nBEGIN\n IF v_tenant IS NULL THEN\n RAISE EXCEPTION 'workforce_period_close: sem tenant na sessão' USING ERRCODE = '42501';\n END IF;\n IF NOT app.has_permission('workforce.close_period', NULL) THEN\n RAISE EXCEPTION 'workforce_period_close: exige workforce.close_period' USING ERRCODE = '42501';\n END IF;\n IF v_month > date_trunc('month', current_date)::date THEN\n RAISE EXCEPTION 'workforce_period_close: % ainda não terminou', to_char(v_month, 'MM/YYYY')\n USING ERRCODE = '22023';\n END IF;\n\n -- Ponto em aberto é jornada que ainda vai mudar. Fechar por cima produz um\n -- total de horas que muda depois de fechado, que é exatamente o que a trava\n -- existe para impedir — e é o defeito medido no V1: 20 batimentos em aberto\n -- fazem o valor do período (R$ 47.747) ser um número menor que o real.\n SELECT count(*) INTO v_open\n FROM public.v_workforce_day d\n WHERE d.tenant_id = v_tenant\n AND d.is_open\n AND date_trunc('month', d.work_date)::date <= v_month;\n IF v_open > 0 THEN\n RAISE EXCEPTION 'workforce_period_close: % ponto(s) em aberto em % ou antes — feche ou ajuste antes', v_open, to_char(v_month, 'MM/YYYY')\n USING ERRCODE = '23514',\n HINT = 'SELECT * FROM public.v_workforce_day WHERE is_open;';\n END IF;\n\n INSERT INTO public.plg_workforce_periods (tenant_id, competence_month, status, closed_at, closed_by_user_id, notes)\n VALUES (v_tenant, v_month, 'closed', now(), auth.uid(), p_notes)\n ON CONFLICT (tenant_id, competence_month) DO UPDATE\n SET status = 'closed', closed_at = now(), closed_by_user_id = auth.uid(),\n notes = coalesce(EXCLUDED.notes, public.plg_workforce_periods.notes), updated_at = now()\n RETURNING * INTO v_row;\n\n RETURN jsonb_build_object('period_id', v_row.id, 'competence_month', v_month,\n 'status', 'closed', 'closed_at', v_row.closed_at);\nEND $$;\n\nCREATE OR REPLACE FUNCTION public.workforce_period_reopen(p_month date, p_reason text)\n RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $$\nDECLARE\n v_tenant uuid := app.current_tenant_id();\n v_month date := date_trunc('month', p_month)::date;\n v_row public.plg_workforce_periods%ROWTYPE;\nBEGIN\n IF v_tenant IS NULL THEN\n RAISE EXCEPTION 'workforce_period_reopen: sem tenant na sessão' USING ERRCODE = '42501';\n END IF;\n IF NOT app.has_permission('workforce.close_period', NULL) THEN\n RAISE EXCEPTION 'workforce_period_reopen: exige workforce.close_period' USING ERRCODE = '42501';\n END IF;\n IF nullif(btrim(coalesce(p_reason, '')), '') IS NULL THEN\n RAISE EXCEPTION 'workforce_period_reopen: o motivo é obrigatório' USING ERRCODE = '22023';\n END IF;\n\n UPDATE public.plg_workforce_periods SET\n status = 'open', reopened_at = now(), reopened_by_user_id = auth.uid(),\n reopen_reason = p_reason, updated_at = now()\n WHERE tenant_id = v_tenant AND competence_month = v_month\n RETURNING * INTO v_row;\n\n IF v_row.id IS NULL THEN\n RAISE EXCEPTION 'workforce_period_reopen: % nunca foi fechado', to_char(v_month, 'MM/YYYY')\n USING ERRCODE = 'P0002';\n END IF;\n\n RETURN jsonb_build_object('period_id', v_row.id, 'competence_month', v_month,\n 'status', 'open', 'reopened_at', v_row.reopened_at, 'reason', p_reason);\nEND $$;\n\nREVOKE ALL ON FUNCTION public.workforce_period_close(date, text) FROM PUBLIC;\nREVOKE ALL ON FUNCTION public.workforce_period_reopen(date, text) FROM PUBLIC;\nGRANT EXECUTE ON FUNCTION public.workforce_period_close(date, text) TO authenticated;\nGRANT EXECUTE ON FUNCTION public.workforce_period_reopen(date, text) TO authenticated;\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 5. A ESCALA: o molde\n-- ═══════════════════════════════════════════════════════════════════════════\n\nCREATE TABLE IF NOT EXISTS public.plg_workforce_schedule_templates (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n -- No V1 o template é POR UNIDADE (o editor abre com um seletor de Unidade), e\n -- aqui também: \"Almoço Seg. a Sex.\" da matriz não é o da filial.\n unit_id uuid REFERENCES app.units(id),\n name text NOT NULL,\n is_active boolean NOT NULL DEFAULT true,\n notes text,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now()\n);\n\nCOMMENT ON TABLE public.plg_workforce_schedule_templates IS\n 'O molde da escala. Pré-requisito duro no V1: sem template não se cria escala nenhuma — \"Selecione um template de escala acima para começar.\"';\n\nCREATE TABLE IF NOT EXISTS public.plg_workforce_schedule_shifts (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n unit_id uuid REFERENCES app.units(id),\n template_id uuid NOT NULL\n REFERENCES public.plg_workforce_schedule_templates(id) ON DELETE CASCADE,\n label text NOT NULL,\n start_time time NOT NULL,\n end_time time NOT NULL,\n -- 0 = domingo, como \\`extract(dow)\\` e como \\`public.schedules.day_of_week\\`.\n -- A constraint existe porque um 7 solto num array é um turno que nunca\n -- acontece e que ninguém percebe faltando.\n weekdays smallint[] NOT NULL DEFAULT '{}'::smallint[],\n -- Turno que vira o dia (16:00–02:00) é normal em restaurante, e é a razão de\n -- \\`work_date\\` ser coluna na batida. Guardar a travessia aqui evita que cada\n -- leitor redescubra \\`end_time < start_time\\` à sua maneira.\n crosses_midnight boolean NOT NULL GENERATED ALWAYS AS (end_time <= start_time) STORED,\n sort_order integer NOT NULL DEFAULT 0,\n -- O padrão de onde a hora deste turno custa. A batida copia e pode divergir.\n -- FK condicional no fim do arquivo, como nas outras duas tabelas.\n chart_account_id uuid,\n cost_center_id uuid,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n CONSTRAINT plg_workforce_schedule_shifts_weekdays_check\n CHECK (weekdays <@ ARRAY[0,1,2,3,4,5,6]::smallint[])\n);\n\nCREATE TABLE IF NOT EXISTS public.plg_workforce_schedule_requirements (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n unit_id uuid REFERENCES app.units(id),\n shift_id uuid NOT NULL\n REFERENCES public.plg_workforce_schedule_shifts(id) ON DELETE CASCADE,\n -- Texto, e não FK para um cadastro de profissão: no V1 isto é o nome livre que\n -- a tela mostra (\"Garçom (1/1)\", \"Cozinha (0/3)\"), e o V2 ainda não tem o\n -- cadastro de profissão que seria o destino honesto. Inventar a FK agora seria\n -- criar um cadastro a partir de dado sujo; o texto atravessa e fica auditável.\n profession_name text NOT NULL,\n required_count integer NOT NULL DEFAULT 1 CHECK (required_count > 0),\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n UNIQUE (shift_id, profession_name)\n);\n\nCOMMENT ON COLUMN public.plg_workforce_schedule_requirements.required_count IS\n 'A lotação da função no turno — o denominador do \"Garçom (1/1)\" da tela. É contra ele que a posição por prioridade vira titular ou stand-by.';\n\nCREATE TABLE IF NOT EXISTS public.plg_workforce_schedule_template_assignments (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n unit_id uuid REFERENCES app.units(id),\n template_id uuid NOT NULL\n REFERENCES public.plg_workforce_schedule_templates(id) ON DELETE CASCADE,\n shift_id uuid NOT NULL\n REFERENCES public.plg_workforce_schedule_shifts(id) ON DELETE CASCADE,\n profession_name text NOT NULL,\n person_id uuid NOT NULL REFERENCES public.people(id) ON DELETE CASCADE,\n -- COLUNA, e não posição. No V1 titular vs stand-by no molde é implícito — são\n -- titulares os primeiros \\`required_count\\` por \\`priority\\` — e essa regra só\n -- existe no código da tela. Aqui ela é calculada uma vez, na entrada, e fica\n -- escrita: a mesma verdade que a instância já grava.\n role text NOT NULL DEFAULT 'titular' CHECK (role IN ('titular', 'standby')),\n priority integer NOT NULL DEFAULT 0,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n UNIQUE (shift_id, profession_name, person_id)\n);\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 6. A ESCALA: a instância do dia\n-- ═══════════════════════════════════════════════════════════════════════════\n\nCREATE TABLE IF NOT EXISTS public.plg_workforce_schedules (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n unit_id uuid REFERENCES app.units(id),\n schedule_date date NOT NULL,\n -- SET NULL e não CASCADE: apagar o molde não pode apagar a escala de terça\n -- passada, que é registro de quem trabalhou. A cópia do turno já está no\n -- snapshot da atribuição, então a escala sobrevive sozinha ao molde.\n template_id uuid REFERENCES public.plg_workforce_schedule_templates(id) ON DELETE SET NULL,\n status text NOT NULL DEFAULT 'draft'\n CHECK (status IN ('draft', 'published', 'closed')),\n published_at timestamptz,\n published_by_user_id uuid,\n is_special_day boolean NOT NULL DEFAULT false,\n special_day_label text,\n notes text,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n -- Publicada sem carimbo de quando é uma escala que ninguém consegue provar\n -- ter avisado — e avisar é a única coisa que a publicação faz.\n CONSTRAINT plg_workforce_schedules_published_check\n CHECK (status <> 'published' OR published_at IS NOT NULL)\n);\n\n-- \"Qual a escala deste dia?\" — é o clique do calendário, e é a consulta que a\n-- tela faz primeiro em toda sessão.\nCREATE INDEX IF NOT EXISTS plg_workforce_schedules_day_idx\n ON public.plg_workforce_schedules (tenant_id, unit_id, schedule_date DESC, status);\n\nCREATE TABLE IF NOT EXISTS public.plg_workforce_schedule_assignments (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n unit_id uuid REFERENCES app.units(id),\n schedule_id uuid NOT NULL\n REFERENCES public.plg_workforce_schedules(id) ON DELETE CASCADE,\n -- A referência ao turno do molde é conveniência, não dependência: o snapshot\n -- abaixo é quem manda. Por isso SET NULL.\n shift_id uuid REFERENCES public.plg_workforce_schedule_shifts(id) ON DELETE SET NULL,\n -- SNAPSHOT, copiado na criação da escala, exatamente como o V1 faz. Mudar o\n -- molde não pode reescrever a escala de anteontem: o que a pessoa foi chamada\n -- para cumprir é um fato daquele dia, e é contra ESTE horário que o ponto dela\n -- é conferido.\n shift_label text,\n shift_start_time time,\n shift_end_time time,\n profession_name text,\n person_id uuid NOT NULL REFERENCES public.people(id) ON DELETE RESTRICT,\n role text NOT NULL DEFAULT 'titular' CHECK (role IN ('titular', 'standby')),\n priority integer NOT NULL DEFAULT 0,\n status text NOT NULL DEFAULT 'pending'\n CHECK (status IN ('pending', 'notified', 'confirmed', 'declined', 'realized')),\n -- O convite que sai por link, sem sessão. Único no tenant porque é uma\n -- credencial: dois convites com o mesmo token são duas pessoas confirmando\n -- pelo mesmo endereço.\n response_token text,\n response_channel text,\n notified_at timestamptz,\n responded_at timestamptz,\n -- A PONTE COM A AGENDA, e a razão de a escala não morar lá. O RH oferta; ao\n -- publicar, a atribuição materializa uma linha de \\`public.schedules\\` com\n -- kind 'work_shift' e a agenda consome. A coluna é o que torna o cruzamento\n -- previsto × realizado uma chave em vez de um casamento por nome e hora.\n schedule_row_id uuid REFERENCES public.schedules(id) ON DELETE SET NULL,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n -- A mesma pessoa não ocupa a mesma vaga duas vezes no mesmo dia. No V1 nada\n -- impede, e o resultado é a lotação \"2/1\" que a tela não sabe desenhar.\n UNIQUE (schedule_id, shift_id, profession_name, person_id)\n);\n\nCREATE UNIQUE INDEX IF NOT EXISTS plg_workforce_schedule_assignments_token_uq\n ON public.plg_workforce_schedule_assignments (tenant_id, response_token)\n WHERE response_token IS NOT NULL;\n\n-- \"Quem está escalado hoje, e quem ainda não respondeu?\" — os contadores\n-- \"N titulares · N pendentes\" do cartão da escala.\nCREATE INDEX IF NOT EXISTS plg_workforce_schedule_assignments_schedule_idx\n ON public.plg_workforce_schedule_assignments (schedule_id, role, status);\n\n-- \"O que ESTA pessoa tem pela frente?\" — a folha individual e o convite.\nCREATE INDEX IF NOT EXISTS plg_workforce_schedule_assignments_person_idx\n ON public.plg_workforce_schedule_assignments (tenant_id, person_id, status);\n\n-- O log da atribuição: quem mudou o quê, por qual canal. No V1 é\n-- \\`schedule_assignment_logs\\`, e é a única parte do modelo de escala dele que já\n-- nasceu append-only.\nCREATE TABLE IF NOT EXISTS public.plg_workforce_assignment_logs (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n unit_id uuid REFERENCES app.units(id),\n assignment_id uuid NOT NULL\n REFERENCES public.plg_workforce_schedule_assignments(id) ON DELETE CASCADE,\n from_status text,\n to_status text NOT NULL,\n channel text,\n note text,\n changed_by_user_id uuid,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now()\n);\n\nCREATE INDEX IF NOT EXISTS plg_workforce_assignment_logs_assignment_idx\n ON public.plg_workforce_assignment_logs (assignment_id, created_at DESC);\n\n-- ── triggers, grants e scaffold das seis tabelas de escala ──────────────────\n--\n-- Em laço porque são seis vezes a mesma disciplina: o gatilho de updated_at, o\n-- GRANT para os dois papéis que existem, e o scaffold desenhando a policy. Seis\n-- blocos copiados divergiriam no primeiro dia em que alguém editasse um só.\nDO $$\nDECLARE\n r record;\nBEGIN\n FOR r IN\n SELECT * FROM (VALUES\n ('plg_workforce_schedule_templates', 'workforce.schedule_template'),\n ('plg_workforce_schedule_shifts', 'workforce.schedule_shift'),\n ('plg_workforce_schedule_requirements', 'workforce.schedule_requirement'),\n ('plg_workforce_schedule_template_assignments', 'workforce.schedule_template_assignment'),\n ('plg_workforce_schedules', 'workforce.schedule'),\n ('plg_workforce_schedule_assignments', 'workforce.schedule_assignment'),\n ('plg_workforce_assignment_logs', 'workforce.assignment_log')\n ) AS t(tbl, resource)\n LOOP\n EXECUTE format('DROP TRIGGER IF EXISTS %I ON public.%I', r.tbl || '_updated_at', r.tbl);\n EXECUTE format('CREATE TRIGGER %I BEFORE UPDATE ON public.%I FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at()',\n r.tbl || '_updated_at', r.tbl);\n EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE ON public.%I TO authenticated, service_role', r.tbl);\n PERFORM app.scaffold_table(format('public.%I', r.tbl)::regclass, r.resource, 'workforce', false, 'enforce');\n END LOOP;\nEND $$;\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 7. O CRUZAMENTO previsto × realizado (lacuna b)\n-- ═══════════════════════════════════════════════════════════════════════════\n\n-- A hora que VALE em cada batida: a última correção não anulada, ou o horário\n-- real. É a leitura que substitui as colunas \\`*_adjusted_at\\` do V1 sem perder a\n-- propriedade que o V1 acertou — o horário real continua ali, intocado.\n--\n-- \\`security_invoker\\` em todas as views desta seção: uma folha de ponto que\n-- ignora escopo é um vazamento com totais.\n-- REPLAY: \\`DROP\\` e depois \\`CREATE\\`, e não \\`CREATE OR REPLACE\\`.\n--\n-- As migrations 003/004/005 ACRESCENTAM colunas a esta view. Acrescentar,\n-- \\`CREATE OR REPLACE\\` faz; TIRAR, não faz — e é o que a baseline faria numa\n-- segunda passada, porque a versão dela é a estreita. O cluster devolve\n-- \\`42P16: cannot drop columns from view\\` e a corrente para aqui.\n--\n-- Conferido em \\`pg_depend\\` antes de derrubar: nada pende destas duas views,\n-- então o \\`DROP\\` é sem \\`CASCADE\\` — de propósito. Sem ele, o dia em que\n-- alguém construir sobre elas o \\`DROP\\` falha alto em vez de levar junto.\n-- Na ordem da dependência: \\`v_workforce_day\\` é construída SOBRE esta, então\n-- sai primeiro. Sem isso o \\`DROP\\` de baixo recusa — e recusar é o certo,\n-- foi assim que esta dependência apareceu.\nDROP VIEW IF EXISTS public.v_workforce_day;\nDROP VIEW IF EXISTS public.v_workforce_time_entries;\nCREATE VIEW public.v_workforce_time_entries\nWITH (security_invoker = 'true') AS\nSELECT e.id,\n e.tenant_id,\n e.unit_id,\n e.person_id,\n e.person_name,\n e.kind,\n e.work_date,\n e.seq,\n e.origin,\n e.punched_at,\n coalesce(c.effective_at, e.punched_at) AS effective_at,\n (c.id IS NOT NULL) AS adjusted,\n (v.id IS NOT NULL) AS voided,\n c.reason AS adjustment_reason,\n c.adjusted_by_name,\n e.assignment_id,\n e.payable_invoice_id,\n e.evidence,\n e.metadata\n FROM public.plg_workforce_time_entries e\n LEFT JOIN LATERAL (\n SELECT a.id, a.effective_at, a.reason, a.adjusted_by_name\n FROM public.plg_workforce_time_adjustments a\n WHERE a.time_entry_id = e.id AND a.action IN ('correct', 'insert')\n ORDER BY a.created_at DESC, a.id DESC\n LIMIT 1) c ON true\n LEFT JOIN LATERAL (\n SELECT a.id FROM public.plg_workforce_time_adjustments a\n WHERE a.time_entry_id = e.id AND a.action = 'void'\n LIMIT 1) v ON true;\n\nCOMMENT ON VIEW public.v_workforce_time_entries IS\n 'A batida com a hora que vale: a última correção não anulada, ou o horário real. O real (punched_at) nunca some — é o que torna o ponto auditável.';\n\n-- O dia de trabalho de uma pessoa, previsto ao lado de realizado.\n--\n-- FULL OUTER JOIN de propósito. As duas assimetrias são exatamente o que o V1\n-- não consegue mostrar, e são as duas perguntas do RH: previsto sem realizado é\n-- FALTA; realizado sem previsto é FORA DA ESCALA (que no tenant medido é o\n-- estado de 325 de 325 registros — não porque as pessoas trabalhem fora da\n-- escala, mas porque o ponto está ligado numa unidade e a escala em outra).\n--\n-- As horas trabalhadas saem de uma soma com sinal: clock_out e break_start\n-- FECHAM um trecho, clock_in e break_end ABREM. Quantos intervalos houver no\n-- dia, a conta é a mesma — é isso que o par único do V1 não consegue fazer.\n-- REPLAY: \\`DROP\\` e depois \\`CREATE\\`, e não \\`CREATE OR REPLACE\\`.\n--\n-- As migrations 003/004/005 ACRESCENTAM colunas a esta view. Acrescentar,\n-- \\`CREATE OR REPLACE\\` faz; TIRAR, não faz — e é o que a baseline faria numa\n-- segunda passada, porque a versão dela é a estreita. O cluster devolve\n-- \\`42P16: cannot drop columns from view\\` e a corrente para aqui.\n--\n-- Conferido em \\`pg_depend\\` antes de derrubar: nada pende destas duas views,\n-- então o \\`DROP\\` é sem \\`CASCADE\\` — de propósito. Sem ele, o dia em que\n-- alguém construir sobre elas o \\`DROP\\` falha alto em vez de levar junto.\nDROP VIEW IF EXISTS public.v_workforce_day;\nCREATE VIEW public.v_workforce_day\nWITH (security_invoker = 'true') AS\nWITH realized AS (\n SELECT e.tenant_id,\n e.unit_id,\n e.person_id,\n e.work_date,\n min(e.effective_at) FILTER (WHERE e.kind = 'clock_in') AS first_in,\n max(e.effective_at) FILTER (WHERE e.kind = 'clock_out') AS last_out,\n count(*) FILTER (WHERE e.kind = 'break_start') AS break_count,\n count(*) FILTER (WHERE e.kind IN ('clock_in', 'break_end'))\n <> count(*) FILTER (WHERE e.kind IN ('clock_out', 'break_start')) AS is_open,\n sum(CASE\n WHEN e.kind IN ('clock_out', 'break_start') THEN extract(epoch FROM e.effective_at)\n WHEN e.kind IN ('clock_in', 'break_end') THEN -extract(epoch FROM e.effective_at)\n END) AS worked_seconds\n FROM public.v_workforce_time_entries e\n WHERE NOT e.voided\n GROUP BY e.tenant_id, e.unit_id, e.person_id, e.work_date\n),\nplanned AS (\n SELECT a.tenant_id,\n a.unit_id,\n a.person_id,\n s.schedule_date AS work_date,\n a.id AS assignment_id,\n a.role,\n a.status AS assignment_status,\n a.shift_label,\n a.shift_start_time,\n a.shift_end_time,\n -- O turno que vira o dia é normal aqui; sem o +24h a jornada da noite\n -- daria negativa.\n (extract(epoch FROM a.shift_end_time - a.shift_start_time)\n + CASE WHEN a.shift_end_time <= a.shift_start_time THEN 86400 ELSE 0 END) AS planned_seconds\n FROM public.plg_workforce_schedule_assignments a\n JOIN public.plg_workforce_schedules s ON s.id = a.schedule_id\n WHERE s.status IN ('published', 'closed')\n AND a.role = 'titular'\n AND a.shift_start_time IS NOT NULL\n AND a.shift_end_time IS NOT NULL\n)\nSELECT coalesce(p.tenant_id, r.tenant_id) AS tenant_id,\n coalesce(p.unit_id, r.unit_id) AS unit_id,\n coalesce(p.person_id, r.person_id) AS person_id,\n coalesce(p.work_date, r.work_date) AS work_date,\n p.assignment_id,\n p.shift_label,\n p.shift_start_time,\n p.shift_end_time,\n p.assignment_status,\n (p.planned_seconds / 60)::integer AS planned_minutes,\n (r.worked_seconds / 60)::integer AS worked_minutes,\n ((r.worked_seconds - p.planned_seconds) / 60)::integer AS variance_minutes,\n r.first_in,\n r.last_out,\n r.break_count,\n coalesce(r.is_open, false) AS is_open,\n -- As duas assimetrias, nomeadas. São as perguntas do RH, e nenhuma delas\n -- tem resposta no V1.\n (r.person_id IS NULL) AS absent,\n (p.assignment_id IS NULL) AS outside_schedule\n FROM planned p\n FULL OUTER JOIN realized r\n ON r.tenant_id = p.tenant_id\n AND r.person_id = p.person_id\n AND r.work_date = p.work_date;\n\nCOMMENT ON VIEW public.v_workforce_day IS\n 'Jornada prevista × realizada por pessoa e dia. Previsto vem da escala publicada, realizado das batidas com ajuste aplicado. FULL OUTER JOIN: \\`absent\\` é escala sem ponto, \\`outside_schedule\\` é ponto sem escala — as duas perguntas que o V1 não responde.';\n\nGRANT SELECT ON public.v_workforce_time_entries TO authenticated, service_role;\nGRANT SELECT ON public.v_workforce_day TO authenticated, service_role;\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 8. OS WRITERS da migração\n-- ═══════════════════════════════════════════════════════════════════════════\n\n-- O vocabulário do de-para é lista fechada de propósito: uma linha que nomeia um\n-- writer inexistente falha na hora, não na terceira hora da onda.\n--\n-- ACRÉSCIMO, e não reemissão. A versão anterior reescrevia a lista INTEIRA —\n-- \"a lista até aqui (046) mais os oito da jornada\". Uma lista escrita por\n-- extenso é um retrato: ela apaga todo writer que outro passo registrou e que\n-- o retrato não viu. Medido no cluster vivo, re-aplicar esta baseline dava\n--\n-- 23514: check constraint \"allowlist_writer_check\" is violated by some row\n--\n-- porque lá já havia writers que esta lista não nomeia. É o mesmo defeito que\n-- \\`agenda/008\\` e \\`financial/072\\` já pagaram, e a forma abaixo é a de\n-- \\`inventory/004\\`: leia o que existe, acrescente o que falta, nunca reemita.\nDO $$\nDECLARE\n v_def text;\n v_falta text[];\n v_meus text[] := ARRAY[\n 'wf_time_entry', 'wf_schedule_template', 'wf_schedule_shift',\n 'wf_schedule_requirement', 'wf_schedule_template_assignment',\n 'wf_schedule', 'wf_schedule_assignment', 'wf_assignment_log'];\nBEGIN\n SELECT pg_get_constraintdef(oid) INTO v_def\n FROM pg_constraint WHERE conname = 'allowlist_writer_check';\n\n IF v_def IS NULL THEN\n -- Ninguém escreveu a regra ainda: aqui ela nasce, com os writers desta\n -- jornada e os que a corrente já registrou até este ponto.\n ALTER TABLE migration.allowlist ADD CONSTRAINT allowlist_writer_check\n CHECK (writer IS NULL OR writer = ANY (ARRAY[\n 'person', 'unit', 'category', 'product', 'order', 'invoice', 'price_table',\n 'price_table_item', 'package', 'package_item', 'field_rule', 'holiday', 'facet',\n 'fin_account', 'fin_payment_method_type', 'fin_payment_method', 'fin_card_brand',\n 'fin_chart_account', 'fin_cost_center', 'inv_measurement_unit', 'inv_unit_conversion',\n 'inv_location', 'inv_movement', 'order_item', 'fin_movement', 'authz_role',\n 'authz_role_permission', 'person_registration',\n 'fin_recurring_bill', 'fin_recurring_bill_item', 'fin_recurring_bill_occurrence',\n 'wf_time_entry', 'wf_schedule_template', 'wf_schedule_shift', 'wf_schedule_requirement',\n 'wf_schedule_template_assignment', 'wf_schedule', 'wf_schedule_assignment',\n 'wf_assignment_log']));\n RETURN;\n END IF;\n\n SELECT array_agg(w) INTO v_falta\n FROM unnest(v_meus) AS w\n WHERE strpos(v_def, '''' || w || '''') = 0;\n\n IF v_falta IS NULL THEN RETURN; END IF;\n\n -- Entram na frente do primeiro elemento: a posição não importa para um\n -- \\`= ANY\\`, e ancorar em \\`ARRAY[\\` dispensa conhecer qualquer valor da lista\n -- — que é justamente o que não se pode presumir.\n ALTER TABLE migration.allowlist DROP CONSTRAINT allowlist_writer_check;\n EXECUTE 'ALTER TABLE migration.allowlist ADD CONSTRAINT allowlist_writer_check '\n || replace(v_def, 'ARRAY[',\n 'ARRAY[' || (SELECT string_agg(quote_literal(w) || '::text, ', '')\n FROM unnest(v_falta) AS w));\nEND $$;\n\n-- ── o de-para da pessoa polimórfica ─────────────────────────────────────────\n--\n-- Este helper é a tradução de \\`person_type\\` + \\`person_id\\` para a FK única do V2,\n-- e existe uma vez porque quatro writers precisam dela. O ledger é a única fonte\n-- que sabe o de-para, e ele guarda a TABELA de origem — então 'professional' e\n-- 'employee' resolvem pelo mesmo caminho, e o writer não precisa conhecer\n-- nenhuma das duas.\nCREATE OR REPLACE FUNCTION migration._wf_person(p_tenant uuid, p_meta jsonb)\n RETURNS uuid LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO ''\nAS $$\n SELECT l.target_id\n FROM migration.ledger l\n WHERE l.tenant_id = p_tenant\n AND l.source_table = CASE WHEN (p_meta #>> '{v1,person_type}') = 'professional'\n THEN 'professionals' ELSE 'employees' END\n AND l.source_numeric_id = nullif(p_meta #>> '{v1,person_id}', '')::bigint\n AND l.target_table = 'public.people'\n AND l.status = 'migrated'\n LIMIT 1;\n$$;\n\nCOMMENT ON FUNCTION migration._wf_person(uuid, jsonb) IS\n 'person_type + person_id do V1 → o uuid de public.people. Duas tabelas de cadastro no V1, um cadastro só no V2.';\n\n-- Helper de migração lê o ledger inteiro do tenant: não é função de aplicação.\nREVOKE ALL ON FUNCTION migration._wf_person(uuid, jsonb) FROM PUBLIC, anon, authenticated;\n\n-- ── a batida ────────────────────────────────────────────────────────────────\n--\n-- UMA linha do V1 vira ATÉ QUATRO linhas do V2: a entrada, a saída (quando\n-- existe), e o ajuste de cada uma (quando \\`*_adjusted_at\\` está preenchido). É a\n-- tradução do par-com-colunas-de-ajuste para eventos-com-ajuste-em-linha.\n--\n-- Os ids derivados são determinísticos (md5 do id de origem + o sufixo do papel)\n-- para que reoferecer a mesma linha numa segunda passada ATUALIZE em vez de\n-- duplicar o dia de trabalho de alguém. \\`target_id\\` devolvido é o da ENTRADA:\n-- é a linha do V1 que ela representa.\nCREATE OR REPLACE FUNCTION migration.upsert_wf_time_entry(\n p_tenant uuid, p_id uuid, p_row jsonb, p_args jsonb DEFAULT '{}'::jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $function$\nDECLARE\n v_meta jsonb := coalesce(p_row -> 'metadata', '{}'::jsonb);\n v_person uuid;\n v_unit uuid := (p_row ->> 'unit_id')::uuid;\n v_in timestamptz := (p_row ->> 'checkin_at')::timestamptz;\n v_out timestamptz := (p_row ->> 'checkout_at')::timestamptz;\n v_in_adj timestamptz := (p_row ->> 'checkin_adjusted_at')::timestamptz;\n v_out_adj timestamptz := (p_row ->> 'checkout_adjusted_at')::timestamptz;\n v_work_date date;\n v_out_id uuid;\n v_reason text := coalesce(nullif(btrim(coalesce(p_row ->> 'adjustment_reason', '')), ''),\n 'ajuste importado do V1 sem motivo registrado');\n v_evidence jsonb;\n v_created boolean := false;\n v_standalone boolean := migration._standalone();\nBEGIN\n IF v_standalone THEN PERFORM migration._assert_fence(p_tenant); PERFORM set_config('migration.writer', 'on', true); END IF;\n\n IF p_id IS NULL OR v_in IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'state',\n 'reason', 'uma batida precisa de id e de hora de entrada');\n END IF;\n\n -- Recusar é o certo, e é temporário: a pessoa entra na mesma onda, e a segunda\n -- passada oferece a batida de novo. Inventar a pessoa aqui seria pendurar\n -- horas de trabalho — e portanto dinheiro — em quem não existe.\n v_person := migration._wf_person(p_tenant, v_meta);\n IF v_person IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'fk',\n 'reason', format('batida de %s #%s cuja pessoa ainda não migrou',\n coalesce(v_meta #>> '{v1,person_type}', '<sem tipo>'),\n coalesce(v_meta #>> '{v1,person_id}', '<sem id>')));\n END IF;\n\n -- A jornada é do dia da ENTRADA, sempre — mesmo quando a saída é do dia\n -- seguinte. É a regra que o V1 admite na caixa de ajuste e nunca grava.\n v_work_date := coalesce((p_row ->> 'work_date')::date, v_in::date);\n v_out_id := md5(p_id::text || ':clock_out')::uuid;\n\n -- Todo o conjunto de prova do totem numa chave só. Perder qualquer um destes\n -- campos é perder a defesa de uma batida contestada.\n v_evidence := jsonb_strip_nulls(jsonb_build_object(\n 'photo_path', p_row ->> 'checkin_photo_path',\n 'lat', (p_row ->> 'checkin_lat')::numeric,\n 'lng', (p_row ->> 'checkin_lng')::numeric,\n 'accuracy_m', (p_row ->> 'checkin_accuracy_m')::numeric,\n 'ip', p_row ->> 'checkin_ip',\n 'user_agent', p_row ->> 'checkin_user_agent',\n 'face_score', (p_row ->> 'checkin_face_score')::numeric));\n\n IF NOT EXISTS (SELECT 1 FROM public.plg_workforce_time_entries WHERE id = p_id) THEN\n INSERT INTO public.plg_workforce_time_entries\n (id, tenant_id, unit_id, person_id, person_name, kind, punched_at, work_date, seq,\n origin, evidence, assignment_id, notes, metadata)\n VALUES (p_id, p_tenant, v_unit, v_person, p_row ->> 'person_name', 'clock_in', v_in,\n v_work_date, 1, 'migration', v_evidence,\n (p_row ->> 'assignment_id')::uuid, p_row ->> 'notes', v_meta);\n v_created := true;\n ELSE\n UPDATE public.plg_workforce_time_entries SET\n unit_id = coalesce(v_unit, unit_id),\n person_id = v_person,\n person_name = coalesce(p_row ->> 'person_name', person_name),\n punched_at = v_in,\n work_date = v_work_date,\n evidence = migration._merge_meta(evidence, v_evidence),\n assignment_id = coalesce((p_row ->> 'assignment_id')::uuid, assignment_id),\n notes = CASE WHEN p_row ? 'notes' THEN p_row ->> 'notes' ELSE notes END,\n metadata = migration._merge_meta(metadata, v_meta)\n WHERE id = p_id;\n END IF;\n\n -- A saída só existe quando existe. \\`checkout_at IS NULL\\` é o \"ponto em aberto\"\n -- do V1 — 20 deles no tenant medido — e ele atravessa como ausência de evento,\n -- que é o que ele é. Fabricar uma saída para \"fechar\" o registro inventaria\n -- horas trabalhadas.\n IF v_out IS NOT NULL THEN\n IF NOT EXISTS (SELECT 1 FROM public.plg_workforce_time_entries WHERE id = v_out_id) THEN\n INSERT INTO public.plg_workforce_time_entries\n (id, tenant_id, unit_id, person_id, person_name, kind, punched_at, work_date, seq,\n origin, evidence, assignment_id, metadata)\n VALUES (v_out_id, p_tenant, v_unit, v_person, p_row ->> 'person_name', 'clock_out', v_out,\n v_work_date, 2, 'migration',\n jsonb_strip_nulls(jsonb_build_object(\n 'photo_path', p_row ->> 'checkout_photo_path',\n 'lat', (p_row ->> 'checkout_lat')::numeric,\n 'lng', (p_row ->> 'checkout_lng')::numeric,\n 'accuracy_m', (p_row ->> 'checkout_accuracy_m')::numeric,\n 'ip', p_row ->> 'checkout_ip',\n 'user_agent', p_row ->> 'checkout_user_agent',\n 'face_score', (p_row ->> 'checkout_face_score')::numeric)),\n (p_row ->> 'assignment_id')::uuid,\n migration._deep_set(v_meta, ARRAY['migration', 'derived_from'], to_jsonb(p_id::text)));\n ELSE\n UPDATE public.plg_workforce_time_entries SET\n punched_at = v_out, work_date = v_work_date, person_id = v_person\n WHERE id = v_out_id;\n END IF;\n END IF;\n\n -- O ajuste vira LINHA. No V1 ele é um par de colunas por cima da batida, e o\n -- histórico morre no segundo ajuste; aqui cada correção fica, com autor e\n -- motivo. O motivo é opcional no V1 e obrigatório aqui — quando vem vazio, o\n -- texto diz exatamente isso, em vez de fingir que alguém justificou.\n IF v_in_adj IS NOT NULL THEN\n INSERT INTO public.plg_workforce_time_adjustments\n (id, tenant_id, unit_id, time_entry_id, action, effective_at, reason,\n adjusted_by_user_id, adjusted_by_name, metadata)\n VALUES (md5(p_id::text || ':adjust_in')::uuid, p_tenant, v_unit, p_id, 'correct',\n v_in_adj, v_reason,\n (p_row ->> 'adjusted_by_user_id')::uuid, p_row ->> 'adjusted_by_name',\n migration._deep_set(v_meta, ARRAY['migration', 'from'], to_jsonb('checkin_adjusted_at'::text)))\n ON CONFLICT (id) DO UPDATE\n SET effective_at = EXCLUDED.effective_at, reason = EXCLUDED.reason,\n adjusted_by_name = EXCLUDED.adjusted_by_name, updated_at = now();\n END IF;\n\n IF v_out_adj IS NOT NULL AND v_out IS NOT NULL THEN\n INSERT INTO public.plg_workforce_time_adjustments\n (id, tenant_id, unit_id, time_entry_id, action, effective_at, reason,\n adjusted_by_user_id, adjusted_by_name, metadata)\n VALUES (md5(p_id::text || ':adjust_out')::uuid, p_tenant, v_unit, v_out_id, 'correct',\n v_out_adj, v_reason,\n (p_row ->> 'adjusted_by_user_id')::uuid, p_row ->> 'adjusted_by_name',\n migration._deep_set(v_meta, ARRAY['migration', 'from'], to_jsonb('checkout_adjusted_at'::text)))\n ON CONFLICT (id) DO UPDATE\n SET effective_at = EXCLUDED.effective_at, reason = EXCLUDED.reason,\n adjusted_by_name = EXCLUDED.adjusted_by_name, updated_at = now();\n END IF;\n\n IF v_standalone THEN PERFORM migration._audit(p_tenant, 'public.plg_workforce_time_entries', p_id, '{}'::jsonb); END IF;\n RETURN jsonb_build_object('status', 'migrated', 'target_id', p_id,\n 'reason', CASE WHEN v_created THEN 'created' ELSE 'updated' END,\n 'entries', CASE WHEN v_out IS NULL THEN 1 ELSE 2 END,\n 'open', v_out IS NULL);\nEND $function$;\n\n-- ── o molde ─────────────────────────────────────────────────────────────────\nCREATE OR REPLACE FUNCTION migration.upsert_wf_schedule_template(\n p_tenant uuid, p_id uuid, p_row jsonb, p_args jsonb DEFAULT '{}'::jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $function$\nDECLARE\n v_meta jsonb := coalesce(p_row -> 'metadata', '{}'::jsonb);\n v_name text := nullif(btrim(coalesce(p_row ->> 'name', '')), '');\n v_created boolean := false;\n v_standalone boolean := migration._standalone();\nBEGIN\n IF v_standalone THEN PERFORM migration._assert_fence(p_tenant); PERFORM set_config('migration.writer', 'on', true); END IF;\n IF p_id IS NULL OR v_name IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'state',\n 'reason', 'um template de escala precisa de id e de nome — é por ele que a tela o oferece');\n END IF;\n\n IF NOT EXISTS (SELECT 1 FROM public.plg_workforce_schedule_templates WHERE id = p_id) THEN\n INSERT INTO public.plg_workforce_schedule_templates (id, tenant_id, unit_id, name, is_active, notes, metadata)\n VALUES (p_id, p_tenant, (p_row ->> 'unit_id')::uuid, v_name,\n coalesce((p_row ->> 'is_active')::boolean, true), p_row ->> 'notes', v_meta);\n v_created := true;\n ELSE\n UPDATE public.plg_workforce_schedule_templates SET\n unit_id = CASE WHEN p_row ? 'unit_id' THEN (p_row ->> 'unit_id')::uuid ELSE unit_id END,\n name = v_name,\n is_active = CASE WHEN p_row ? 'is_active' THEN coalesce((p_row ->> 'is_active')::boolean, true) ELSE is_active END,\n notes = CASE WHEN p_row ? 'notes' THEN p_row ->> 'notes' ELSE notes END,\n metadata = migration._merge_meta(metadata, v_meta)\n WHERE id = p_id;\n END IF;\n\n IF v_standalone THEN PERFORM migration._audit(p_tenant, 'public.plg_workforce_schedule_templates', p_id, '{}'::jsonb); END IF;\n RETURN jsonb_build_object('status', 'migrated', 'target_id', p_id,\n 'reason', CASE WHEN v_created THEN 'created' ELSE 'updated' END);\nEND $function$;\n\nCREATE OR REPLACE FUNCTION migration.upsert_wf_schedule_shift(\n p_tenant uuid, p_id uuid, p_row jsonb, p_args jsonb DEFAULT '{}'::jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $function$\nDECLARE\n v_meta jsonb := coalesce(p_row -> 'metadata', '{}'::jsonb);\n v_template uuid := (p_row ->> 'template_id')::uuid;\n v_start time := (p_row ->> 'start_time')::time;\n v_end time := (p_row ->> 'end_time')::time;\n v_days smallint[];\n v_bad smallint[];\n v_unit uuid;\n v_created boolean := false;\n v_standalone boolean := migration._standalone();\nBEGIN\n IF v_standalone THEN PERFORM migration._assert_fence(p_tenant); PERFORM set_config('migration.writer', 'on', true); END IF;\n IF p_id IS NULL OR v_template IS NULL OR v_start IS NULL OR v_end IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'state',\n 'reason', 'um turno precisa de id, do template, de início e de fim');\n END IF;\n SELECT unit_id INTO v_unit FROM public.plg_workforce_schedule_templates\n WHERE id = v_template AND tenant_id = p_tenant;\n IF NOT FOUND THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'fk',\n 'reason', format('o template %s não existe neste tenant', v_template));\n END IF;\n\n -- Sem correção silenciosa nos dias da semana. Um 7 solto (ou um 1..7 em vez de\n -- 0..6) é um turno que nunca acontece, e um turno que nunca acontece é uma\n -- pessoa que ninguém chamou — some sem erro nenhum.\n SELECT coalesce(array_agg(x::smallint ORDER BY x), '{}'::smallint[])\n INTO v_days\n FROM jsonb_array_elements_text(coalesce(p_row -> 'weekdays', '[]'::jsonb)) AS t(x);\n SELECT coalesce(array_agg(d), '{}'::smallint[]) INTO v_bad\n FROM unnest(v_days) AS d WHERE d < 0 OR d > 6;\n IF array_length(v_bad, 1) > 0 THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'value',\n 'reason', format('dia da semana fora de 0..6 (domingo..sábado): %s', v_bad::text));\n END IF;\n\n IF NOT EXISTS (SELECT 1 FROM public.plg_workforce_schedule_shifts WHERE id = p_id) THEN\n INSERT INTO public.plg_workforce_schedule_shifts\n (id, tenant_id, unit_id, template_id, label, start_time, end_time, weekdays, sort_order, metadata)\n VALUES (p_id, p_tenant, v_unit, v_template,\n coalesce(nullif(btrim(coalesce(p_row ->> 'label', '')), ''), 'Turno'),\n v_start, v_end, v_days, coalesce((p_row ->> 'sort_order')::integer, 0), v_meta);\n v_created := true;\n ELSE\n UPDATE public.plg_workforce_schedule_shifts SET\n unit_id = v_unit,\n label = coalesce(nullif(btrim(coalesce(p_row ->> 'label', '')), ''), label),\n start_time = v_start,\n end_time = v_end,\n weekdays = v_days,\n sort_order = CASE WHEN p_row ? 'sort_order' THEN coalesce((p_row ->> 'sort_order')::integer, sort_order) ELSE sort_order END,\n metadata = migration._merge_meta(metadata, v_meta)\n WHERE id = p_id;\n END IF;\n\n IF v_standalone THEN PERFORM migration._audit(p_tenant, 'public.plg_workforce_schedule_shifts', p_id, '{}'::jsonb); END IF;\n RETURN jsonb_build_object('status', 'migrated', 'target_id', p_id,\n 'reason', CASE WHEN v_created THEN 'created' ELSE 'updated' END,\n 'crosses_midnight', v_end <= v_start);\nEND $function$;\n\nCREATE OR REPLACE FUNCTION migration.upsert_wf_schedule_requirement(\n p_tenant uuid, p_id uuid, p_row jsonb, p_args jsonb DEFAULT '{}'::jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $function$\nDECLARE\n v_meta jsonb := coalesce(p_row -> 'metadata', '{}'::jsonb);\n v_shift uuid := (p_row ->> 'shift_id')::uuid;\n v_prof text := nullif(btrim(coalesce(p_row ->> 'profession_name', '')), '');\n v_count integer := coalesce((p_row ->> 'required_count')::integer, 1);\n v_unit uuid;\n v_id uuid;\n v_standalone boolean := migration._standalone();\nBEGIN\n IF v_standalone THEN PERFORM migration._assert_fence(p_tenant); PERFORM set_config('migration.writer', 'on', true); END IF;\n IF p_id IS NULL OR v_shift IS NULL OR v_prof IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'state',\n 'reason', 'uma vaga precisa de id, do turno e do nome da função');\n END IF;\n SELECT unit_id INTO v_unit FROM public.plg_workforce_schedule_shifts\n WHERE id = v_shift AND tenant_id = p_tenant;\n IF NOT FOUND THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'fk',\n 'reason', format('o turno %s não existe neste tenant', v_shift));\n END IF;\n -- Lotação zero ou negativa é vaga que não existe; e a constraint recusaria a\n -- linha inteira mais tarde, sem dizer qual era.\n IF v_count <= 0 THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'value',\n 'reason', format('lotação de %L é %s — uma vaga precisa de pelo menos uma pessoa', v_prof, v_count));\n END IF;\n\n -- Devolve o id da linha que de fato ficou: quando duas vagas do V1 nomeiam a\n -- mesma função no mesmo turno, a segunda funde na primeira, e o ledger tem de\n -- apontar para onde o dado foi parar — não para o id que ela trazia.\n INSERT INTO public.plg_workforce_schedule_requirements\n (id, tenant_id, unit_id, shift_id, profession_name, required_count, metadata)\n VALUES (p_id, p_tenant, v_unit, v_shift, v_prof, v_count, v_meta)\n ON CONFLICT (shift_id, profession_name) DO UPDATE\n SET required_count = EXCLUDED.required_count,\n metadata = migration._merge_meta(public.plg_workforce_schedule_requirements.metadata, EXCLUDED.metadata),\n updated_at = now()\n RETURNING id INTO v_id;\n\n IF v_standalone THEN PERFORM migration._audit(p_tenant, 'public.plg_workforce_schedule_requirements', v_id, '{}'::jsonb); END IF;\n RETURN jsonb_build_object('status', 'migrated', 'target_id', v_id,\n 'reason', CASE WHEN v_id = p_id THEN 'upserted' ELSE 'fundida na vaga que já existia para esta função neste turno' END);\nEND $function$;\n\n-- No molde do V1, titular vs stand-by é POSICIONAL — os primeiros\n-- \\`required_count\\` por \\`priority\\`. Este writer faz essa conta UMA vez, na\n-- entrada, e grava o resultado em \\`role\\`. Deixar a regra implícita no V2 seria\n-- repor um comportamento que só existe no código de uma tela, e que a próxima\n-- tela a ler a mesma tabela erraria em silêncio.\nCREATE OR REPLACE FUNCTION migration.upsert_wf_schedule_template_assignment(\n p_tenant uuid, p_id uuid, p_row jsonb, p_args jsonb DEFAULT '{}'::jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $function$\nDECLARE\n v_meta jsonb := coalesce(p_row -> 'metadata', '{}'::jsonb);\n v_shift uuid := (p_row ->> 'shift_id')::uuid;\n v_prof text := nullif(btrim(coalesce(p_row ->> 'profession_name', '')), '');\n v_priority integer := coalesce((p_row ->> 'priority')::integer, 0);\n v_person uuid;\n v_template uuid;\n v_unit uuid;\n v_required integer;\n v_rank integer;\n v_role text;\n v_standalone boolean := migration._standalone();\nBEGIN\n IF v_standalone THEN PERFORM migration._assert_fence(p_tenant); PERFORM set_config('migration.writer', 'on', true); END IF;\n IF p_id IS NULL OR v_shift IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'state',\n 'reason', 'uma alocação de molde precisa de id e do turno');\n END IF;\n\n -- No molde a pessoa é sempre \\`professionals\\` — o V1 não escala funcionário\n -- pelo template — mas o helper resolve pelo que o metadata disser, e não pelo\n -- que este writer supõe.\n v_person := migration._wf_person(p_tenant,\n CASE WHEN (v_meta #>> '{v1,person_type}') IS NULL\n THEN migration._deep_set(v_meta, ARRAY['v1', 'person_type'], to_jsonb('professional'::text))\n ELSE v_meta END);\n IF v_person IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'fk',\n 'reason', format('alocação de molde cuja pessoa ainda não migrou (%s #%s)',\n coalesce(v_meta #>> '{v1,person_type}', 'professional'),\n coalesce(v_meta #>> '{v1,person_id}', '<sem id>')));\n END IF;\n\n SELECT s.template_id, s.unit_id INTO v_template, v_unit\n FROM public.plg_workforce_schedule_shifts s\n WHERE s.id = v_shift AND s.tenant_id = p_tenant;\n IF NOT FOUND THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'fk',\n 'reason', format('o turno %s não existe neste tenant', v_shift));\n END IF;\n\n INSERT INTO public.plg_workforce_schedule_template_assignments\n (id, tenant_id, unit_id, template_id, shift_id, profession_name, person_id, role, priority, metadata)\n VALUES (p_id, p_tenant, v_unit, v_template, v_shift, coalesce(v_prof, '—'), v_person,\n 'titular', v_priority, v_meta)\n ON CONFLICT (shift_id, profession_name, person_id) DO UPDATE\n SET priority = EXCLUDED.priority,\n metadata = migration._merge_meta(public.plg_workforce_schedule_template_assignments.metadata, EXCLUDED.metadata),\n updated_at = now();\n\n -- A POSIÇÃO vira PAPEL. Recalculada a cada linha porque a ordem muda quando a\n -- próxima chega: a quarta pessoa de uma vaga de três rebaixa ninguém, mas\n -- entra como reserva, e a sétima também.\n SELECT r.required_count INTO v_required\n FROM public.plg_workforce_schedule_requirements r\n WHERE r.shift_id = v_shift AND r.profession_name = coalesce(v_prof, '—');\n\n SELECT rank INTO v_rank FROM (\n SELECT a.id, row_number() OVER (ORDER BY a.priority, a.created_at, a.id) AS rank\n FROM public.plg_workforce_schedule_template_assignments a\n WHERE a.shift_id = v_shift AND a.profession_name = coalesce(v_prof, '—')) s\n WHERE s.id = p_id;\n\n -- Sem vaga declarada não há denominador, e chutar um faria a pessoa virar\n -- titular ou reserva por acaso. \\`titular\\` é o que o V1 mostra nesse caso.\n v_role := CASE WHEN v_required IS NULL THEN 'titular'\n WHEN v_rank <= v_required THEN 'titular'\n ELSE 'standby' END;\n UPDATE public.plg_workforce_schedule_template_assignments SET role = v_role WHERE id = p_id;\n\n IF v_standalone THEN PERFORM migration._audit(p_tenant, 'public.plg_workforce_schedule_template_assignments', p_id, '{}'::jsonb); END IF;\n RETURN jsonb_build_object('status', 'migrated', 'target_id', p_id, 'role', v_role,\n 'reason', format('posição %s de %s vaga(s) → %s', v_rank, coalesce(v_required::text, 'sem lotação declarada'), v_role));\nEND $function$;\n\n-- ── a instância ─────────────────────────────────────────────────────────────\nCREATE OR REPLACE FUNCTION migration.upsert_wf_schedule(\n p_tenant uuid, p_id uuid, p_row jsonb, p_args jsonb DEFAULT '{}'::jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $function$\nDECLARE\n v_meta jsonb := coalesce(p_row -> 'metadata', '{}'::jsonb);\n v_date date := (p_row ->> 'schedule_date')::date;\n v_status_v1 text := nullif(btrim(lower(coalesce(p_row ->> 'status', ''))), '');\n v_status text;\n v_published timestamptz := (p_row ->> 'published_at')::timestamptz;\n v_created boolean := false;\n v_standalone boolean := migration._standalone();\nBEGIN\n IF v_standalone THEN PERFORM migration._assert_fence(p_tenant); PERFORM set_config('migration.writer', 'on', true); END IF;\n IF p_id IS NULL OR v_date IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'state',\n 'reason', 'uma escala precisa de id e do dia a que pertence');\n END IF;\n\n v_status := CASE v_status_v1\n WHEN 'draft' THEN 'draft'\n WHEN 'published' THEN 'published'\n WHEN 'closed' THEN 'closed'\n ELSE NULL END;\n IF v_status IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'value',\n 'reason', format('estado de escala desconhecido: %L (o V2 conhece draft, published e closed)', v_status_v1));\n END IF;\n\n -- Publicada sem carimbo é o rascunho do V1 que alguém marcou como publicado\n -- sem a ação que grava a data. A constraint recusaria; aqui a data de\n -- publicação vira a do próprio dia da escala, e o remendo fica escrito.\n IF v_status <> 'draft' AND v_published IS NULL THEN\n v_published := v_date::timestamptz;\n v_meta := migration._deep_set(v_meta, ARRAY['migration', 'published_at_inferred'], to_jsonb(true));\n END IF;\n\n IF NOT EXISTS (SELECT 1 FROM public.plg_workforce_schedules WHERE id = p_id) THEN\n INSERT INTO public.plg_workforce_schedules\n (id, tenant_id, unit_id, schedule_date, template_id, status, published_at,\n is_special_day, special_day_label, notes, metadata)\n VALUES (p_id, p_tenant, (p_row ->> 'unit_id')::uuid, v_date,\n (p_row ->> 'template_id')::uuid, v_status, v_published,\n coalesce((p_row ->> 'is_special_day')::boolean, false),\n p_row ->> 'special_day_label', p_row ->> 'notes', v_meta);\n v_created := true;\n ELSE\n UPDATE public.plg_workforce_schedules SET\n unit_id = CASE WHEN p_row ? 'unit_id' THEN (p_row ->> 'unit_id')::uuid ELSE unit_id END,\n schedule_date = v_date,\n template_id = CASE WHEN p_row ? 'template_id' THEN (p_row ->> 'template_id')::uuid ELSE template_id END,\n status = v_status,\n published_at = v_published,\n is_special_day = CASE WHEN p_row ? 'is_special_day' THEN coalesce((p_row ->> 'is_special_day')::boolean, false) ELSE is_special_day END,\n special_day_label = CASE WHEN p_row ? 'special_day_label' THEN p_row ->> 'special_day_label' ELSE special_day_label END,\n notes = CASE WHEN p_row ? 'notes' THEN p_row ->> 'notes' ELSE notes END,\n metadata = migration._merge_meta(metadata, v_meta)\n WHERE id = p_id;\n END IF;\n\n IF v_standalone THEN PERFORM migration._audit(p_tenant, 'public.plg_workforce_schedules', p_id, '{}'::jsonb); END IF;\n RETURN jsonb_build_object('status', 'migrated', 'target_id', p_id,\n 'reason', CASE WHEN v_created THEN 'created' ELSE 'updated' END);\nEND $function$;\n\nCREATE OR REPLACE FUNCTION migration.upsert_wf_schedule_assignment(\n p_tenant uuid, p_id uuid, p_row jsonb, p_args jsonb DEFAULT '{}'::jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $function$\nDECLARE\n v_meta jsonb := coalesce(p_row -> 'metadata', '{}'::jsonb);\n v_schedule uuid := (p_row ->> 'schedule_id')::uuid;\n v_role_v1 text := nullif(btrim(lower(coalesce(p_row ->> 'role', ''))), '');\n v_status_v1 text := nullif(btrim(lower(coalesce(p_row ->> 'status', ''))), '');\n v_role text;\n v_status text;\n v_person uuid;\n v_unit uuid;\n v_start time := (p_row ->> 'shift_start_time')::time;\n v_end time := (p_row ->> 'shift_end_time')::time;\n v_created boolean := false;\n v_standalone boolean := migration._standalone();\nBEGIN\n IF v_standalone THEN PERFORM migration._assert_fence(p_tenant); PERFORM set_config('migration.writer', 'on', true); END IF;\n IF p_id IS NULL OR v_schedule IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'state',\n 'reason', 'uma atribuição precisa de id e da escala a que pertence');\n END IF;\n SELECT unit_id INTO v_unit FROM public.plg_workforce_schedules\n WHERE id = v_schedule AND tenant_id = p_tenant;\n IF NOT FOUND THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'fk',\n 'reason', format('a escala %s não existe neste tenant', v_schedule));\n END IF;\n\n v_person := migration._wf_person(p_tenant,\n CASE WHEN (v_meta #>> '{v1,person_type}') IS NULL\n THEN migration._deep_set(v_meta, ARRAY['v1', 'person_type'], to_jsonb('professional'::text))\n ELSE v_meta END);\n IF v_person IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'fk',\n 'reason', format('atribuição de escala cuja pessoa ainda não migrou (%s #%s)',\n coalesce(v_meta #>> '{v1,person_type}', 'professional'),\n coalesce(v_meta #>> '{v1,person_id}', '<sem id>')));\n END IF;\n\n -- Stand-by NÃO é folga: é o substituto acionável, e a própria tela do V1 diz\n -- (\"Substitutos em caso de falta\"). Confundir os dois na tradução apagaria a\n -- fila de quem cobre a falta.\n v_role := CASE v_role_v1\n WHEN 'titular' THEN 'titular'\n WHEN 'standby' THEN 'standby'\n WHEN 'stand_by' THEN 'standby'\n WHEN 'stand-by' THEN 'standby'\n ELSE NULL END;\n IF v_role IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'value',\n 'reason', format('papel na vaga desconhecido: %L (o V2 conhece titular e standby)', v_role_v1));\n END IF;\n\n v_status := CASE v_status_v1\n WHEN 'pending' THEN 'pending'\n WHEN 'notified' THEN 'notified'\n WHEN 'confirmed' THEN 'confirmed'\n WHEN 'declined' THEN 'declined'\n WHEN 'realized' THEN 'realized'\n ELSE NULL END;\n IF v_status IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'value',\n 'reason', format('estado de atribuição desconhecido: %L', v_status_v1));\n END IF;\n\n IF NOT EXISTS (SELECT 1 FROM public.plg_workforce_schedule_assignments WHERE id = p_id) THEN\n INSERT INTO public.plg_workforce_schedule_assignments\n (id, tenant_id, unit_id, schedule_id, shift_id, shift_label, shift_start_time, shift_end_time,\n profession_name, person_id, role, priority, status, response_token, response_channel,\n notified_at, responded_at, metadata)\n VALUES (p_id, p_tenant, v_unit, v_schedule, (p_row ->> 'shift_id')::uuid,\n p_row ->> 'shift_label', v_start, v_end,\n p_row ->> 'profession_name', v_person, v_role,\n coalesce((p_row ->> 'priority')::integer, 0), v_status,\n -- O token do V1 é uma credencial viva de um canal que o V2 ainda não\n -- opera. Ele atravessa para não perder o rastro de quem foi chamado\n -- por link, mas quem emitir o próximo convite emite outro.\n p_row ->> 'response_token', p_row ->> 'response_channel',\n (p_row ->> 'notified_at')::timestamptz, (p_row ->> 'responded_at')::timestamptz,\n v_meta);\n v_created := true;\n ELSE\n UPDATE public.plg_workforce_schedule_assignments SET\n unit_id = v_unit,\n shift_id = CASE WHEN p_row ? 'shift_id' THEN (p_row ->> 'shift_id')::uuid ELSE shift_id END,\n shift_label = CASE WHEN p_row ? 'shift_label' THEN p_row ->> 'shift_label' ELSE shift_label END,\n shift_start_time = coalesce(v_start, shift_start_time),\n shift_end_time = coalesce(v_end, shift_end_time),\n profession_name = CASE WHEN p_row ? 'profession_name' THEN p_row ->> 'profession_name' ELSE profession_name END,\n person_id = v_person,\n role = v_role,\n priority = CASE WHEN p_row ? 'priority' THEN coalesce((p_row ->> 'priority')::integer, priority) ELSE priority END,\n status = v_status,\n response_token = CASE WHEN p_row ? 'response_token' THEN p_row ->> 'response_token' ELSE response_token END,\n response_channel = CASE WHEN p_row ? 'response_channel' THEN p_row ->> 'response_channel' ELSE response_channel END,\n notified_at = CASE WHEN p_row ? 'notified_at' THEN (p_row ->> 'notified_at')::timestamptz ELSE notified_at END,\n responded_at = CASE WHEN p_row ? 'responded_at' THEN (p_row ->> 'responded_at')::timestamptz ELSE responded_at END,\n metadata = migration._merge_meta(metadata, v_meta)\n WHERE id = p_id;\n END IF;\n\n IF v_standalone THEN PERFORM migration._audit(p_tenant, 'public.plg_workforce_schedule_assignments', p_id, '{}'::jsonb); END IF;\n RETURN jsonb_build_object('status', 'migrated', 'target_id', p_id, 'role', v_role,\n 'reason', CASE WHEN v_created THEN 'created' ELSE 'updated' END);\nEND $function$;\n\nCREATE OR REPLACE FUNCTION migration.upsert_wf_assignment_log(\n p_tenant uuid, p_id uuid, p_row jsonb, p_args jsonb DEFAULT '{}'::jsonb\n) RETURNS jsonb\nLANGUAGE plpgsql SECURITY DEFINER SET search_path TO ''\nAS $function$\nDECLARE\n v_meta jsonb := coalesce(p_row -> 'metadata', '{}'::jsonb);\n v_assignment uuid := (p_row ->> 'assignment_id')::uuid;\n v_to text := nullif(btrim(lower(coalesce(p_row ->> 'to_status', ''))), '');\n v_unit uuid;\n v_standalone boolean := migration._standalone();\nBEGIN\n IF v_standalone THEN PERFORM migration._assert_fence(p_tenant); PERFORM set_config('migration.writer', 'on', true); END IF;\n IF p_id IS NULL OR v_assignment IS NULL OR v_to IS NULL THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'state',\n 'reason', 'uma linha de histórico precisa de id, da atribuição e do estado para o qual foi');\n END IF;\n SELECT unit_id INTO v_unit FROM public.plg_workforce_schedule_assignments\n WHERE id = v_assignment AND tenant_id = p_tenant;\n IF NOT FOUND THEN\n RETURN jsonb_build_object('status', 'quarantined', 'kind', 'fk',\n 'reason', format('a atribuição %s não existe neste tenant', v_assignment));\n END IF;\n\n -- O log é histórico: reoferecer a mesma linha é replay, e replay não reescreve\n -- o que já foi registrado.\n IF EXISTS (SELECT 1 FROM public.plg_workforce_assignment_logs WHERE id = p_id) THEN\n RETURN jsonb_build_object('status', 'migrated', 'target_id', p_id,\n 'reason', 'already in the ledger (append-only)');\n END IF;\n\n INSERT INTO public.plg_workforce_assignment_logs\n (id, tenant_id, unit_id, assignment_id, from_status, to_status, channel, note,\n changed_by_user_id, metadata, created_at)\n VALUES (p_id, p_tenant, v_unit, v_assignment,\n nullif(btrim(lower(coalesce(p_row ->> 'from_status', ''))), ''), v_to,\n p_row ->> 'channel', p_row ->> 'note',\n (p_row ->> 'changed_by_user_id')::uuid, v_meta,\n coalesce((p_row ->> 'created_at')::timestamptz, now()));\n\n IF v_standalone THEN PERFORM migration._audit(p_tenant, 'public.plg_workforce_assignment_logs', p_id, '{}'::jsonb); END IF;\n RETURN jsonb_build_object('status', 'migrated', 'target_id', p_id, 'reason', 'created');\nEND $function$;\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 9. O DE-PARA\n-- ═══════════════════════════════════════════════════════════════════════════\n\n-- \\`_allow\\` é o construtor oficial: a allowlist tem gatilho de congelamento, e um\n-- INSERT direto por cima de uma linha \\`frozen\\` seria recusado. São oito\n-- argumentos — (source, target, domain, writer, writer_args, financial[],\n-- columns, notes) — e \\`layer\\` é fixo em 'core-A' lá dentro.\n\n-- A allowlist é CONGELADA (\\`trg_allowlist_frozen\\`): mudança de core-A é\n-- arquivo de migration, não escrita solta — e este é o arquivo. Sem a\n-- escotilha, a PRIMEIRA passada passa (a linha ainda não existia) e a\n-- SEGUNDA falha: é assim que uma migration deixa de ser replay-safe sem\n-- ninguém ver. \\`true\\` no terceiro argumento: vale só nesta transação.\nSELECT set_config('migration.allowlist_unlock', 'on', true);\n\nSELECT migration._allow(\n 'time_clock_entries', 'public.plg_workforce_time_entries', 'workforce',\n 'wf_time_entry', '{}'::jsonb, ARRAY[]::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'unit_id', 'unit_id@companies:app.units',\n -- O par polimórfico. Nenhuma das duas vira coluna: juntas elas viram\n -- \\`person_id\\`, resolvido pelo ledger em migration._wf_person.\n 'person_type', 'jsonb:v1.person_type',\n 'person_id', 'jsonb:v1.person_id',\n 'person_name', 'person_name',\n 'checkin_at', 'checkin_at',\n 'checkout_at', 'checkout_at',\n 'checkin_photo_path', 'checkin_photo_path',\n 'checkin_lat', 'checkin_lat',\n 'checkin_lng', 'checkin_lng',\n 'checkin_accuracy_m', 'checkin_accuracy_m',\n 'checkin_ip', 'checkin_ip',\n 'checkin_user_agent', 'checkin_user_agent',\n 'checkin_face_score', 'checkin_face_score',\n 'checkout_photo_path', 'checkout_photo_path',\n 'checkout_lat', 'checkout_lat',\n 'checkout_lng', 'checkout_lng',\n 'checkout_accuracy_m', 'checkout_accuracy_m',\n 'checkout_ip', 'checkout_ip',\n 'checkout_user_agent', 'checkout_user_agent',\n 'checkout_face_score', 'checkout_face_score',\n 'schedule_assignment_id','assignment_id@schedule_assignments',\n -- O ajuste do V1 não vira coluna: vira LINHA em\n -- plg_workforce_time_adjustments, com autor e motivo.\n 'checkin_adjusted_at', 'checkin_adjusted_at',\n 'checkout_adjusted_at', 'checkout_adjusted_at',\n 'adjustment_reason', 'adjustment_reason',\n 'adjusted_by_user_id', 'adjusted_by_user_id',\n 'adjusted_by_name', 'adjusted_by_name',\n -- Derivadas e não portadas: \\`manually_adjusted\\` é a existência de um ajuste,\n -- \\`adjusted_by\\`/\\`adjusted_at\\` são redundantes com a linha do ajuste, e\n -- \\`outside_schedule\\` é o resultado do cruzamento — que no V1 é \\`true\\` em 325\n -- de 325 registros por um defeito de configuração, e que no V2 é a coluna\n -- \\`outside_schedule\\` da view v_workforce_day, calculada e não guardada.\n 'manually_adjusted', '-',\n 'adjusted_by', '-',\n 'adjusted_at', '-',\n 'outside_schedule', 'jsonb:v1.outside_schedule',\n 'notes', 'notes',\n -- NÃO vira FK: no V1 aponta para a tabela de títulos do V1, cuja contraparte\n -- no V2 não é a mesma coisa (mesma recusa da 046). A referência crua é o que\n -- TRAVA o ajuste da linha migrada — a trigger da seção 4 lê exatamente aqui.\n 'payable_invoice_id', 'jsonb:v1.payable_invoice_id'\n ),\n 'A batida. Uma linha do V1 (par entrada/saída + colunas de ajuste) vira até 4 do V2: dois eventos append-only e duas linhas de ajuste. checkout_at nulo atravessa como ausência de evento — é o ponto em aberto, 20 deles no tenant medido.'\n);\n\nSELECT migration._allow(\n 'schedule_templates', 'public.plg_workforce_schedule_templates', 'workforce',\n 'wf_schedule_template', '{}'::jsonb, ARRAY[]::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'unit_id', 'unit_id@companies:app.units',\n 'name', 'name',\n 'active', 'is_active'\n ),\n 'O molde da escala. Pré-requisito duro: sem template o V1 não deixa criar escala nenhuma.'\n);\n\nSELECT migration._allow(\n 'schedule_template_shifts', 'public.plg_workforce_schedule_shifts', 'workforce',\n 'wf_schedule_shift', '{}'::jsonb, ARRAY[]::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'template_id', 'template_id@schedule_templates',\n 'label', 'label',\n 'start_time', 'start_time',\n 'end_time', 'end_time',\n 'weekdays', 'weekdays',\n 'sort_order', 'sort_order'\n ),\n 'O turno do molde. weekdays é 0..6 (domingo..sábado); qualquer valor fora disso é quarentena, porque um turno que nunca acontece some sem erro.'\n);\n\nSELECT migration._allow(\n 'schedule_template_requirements', 'public.plg_workforce_schedule_requirements', 'workforce',\n 'wf_schedule_requirement', '{}'::jsonb, ARRAY[]::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'shift_id', 'shift_id@schedule_template_shifts',\n 'profession_name', 'profession_name',\n 'required_count', 'required_count'\n ),\n 'A lotação da função no turno — o \"(1/1)\" da tela, e o denominador que transforma posição em titular/stand-by.'\n);\n\nSELECT migration._allow(\n 'schedule_template_assignments', 'public.plg_workforce_schedule_template_assignments', 'workforce',\n 'wf_schedule_template_assignment', '{}'::jsonb, ARRAY[]::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'template_id', 'template_id@schedule_templates',\n 'shift_id', 'shift_id@schedule_template_shifts',\n 'profession_name', 'profession_name',\n 'professional_id', 'jsonb:v1.person_id',\n 'priority', 'priority'\n ),\n 'A alocação do molde. No V1 titular × stand-by é POSICIONAL (os primeiros required_count por priority) e vive só no código da tela; o writer faz a conta uma vez e grava em \\`role\\`.'\n);\n\nSELECT migration._allow(\n 'schedules', 'public.plg_workforce_schedules', 'workforce',\n 'wf_schedule', '{}'::jsonb, ARRAY[]::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'unit_id', 'unit_id@companies:app.units',\n 'schedule_date', 'schedule_date',\n 'template_id', 'template_id@schedule_templates',\n 'status', 'status',\n 'published_at', 'published_at',\n 'is_special_day', 'is_special_day',\n 'special_day_label', 'special_day_label',\n 'notes', 'notes'\n ),\n 'A escala do dia. Homônima da \\`public.schedules\\` do V2, que é OUTRA coisa (a oferta de horário do spine) — é a razão do prefixo plg_workforce_.'\n);\n\nSELECT migration._allow(\n 'schedule_assignments', 'public.plg_workforce_schedule_assignments', 'workforce',\n 'wf_schedule_assignment', '{}'::jsonb, ARRAY[]::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'schedule_id', 'schedule_id@schedules',\n 'shift_id', 'shift_id@schedule_template_shifts',\n -- O SNAPSHOT do V1 atravessa como snapshot. Reconstruí-lo a partir do turno\n -- atual do molde reescreveria a escala de anteontem quando o molde mudasse.\n 'shift_label', 'shift_label',\n 'shift_start_time', 'shift_start_time',\n 'shift_end_time', 'shift_end_time',\n 'profession_name', 'profession_name',\n 'professional_id', 'jsonb:v1.person_id',\n 'role', 'role',\n 'priority', 'priority',\n 'status', 'status',\n 'response_token', 'response_token',\n 'response_channel', 'response_channel',\n 'notified_at', 'notified_at',\n 'responded_at', 'responded_at'\n ),\n 'A atribuição do dia. Stand-by não é folga: é o substituto acionável (\"Substitutos em caso de falta\"), e confundir os dois apagaria a fila de quem cobre a falta.'\n);\n\nSELECT migration._allow(\n 'schedule_assignment_logs', 'public.plg_workforce_assignment_logs', 'workforce',\n 'wf_assignment_log', '{}'::jsonb, ARRAY[]::text[],\n jsonb_build_object(\n 'uuid', 'id',\n 'assignment_id', 'assignment_id@schedule_assignments',\n 'from_status', 'from_status',\n 'to_status', 'to_status',\n 'channel', 'channel',\n 'note', 'note',\n 'changed_by_user_id','changed_by_user_id',\n 'created_at', 'created_at'\n ),\n 'O histórico da atribuição: a única parte do modelo de escala do V1 que já nasceu append-only, e que atravessa como é.'\n);\n\n-- As duas que NÃO atravessam, e a razão escrita onde a próxima onda vai\n-- procurar. \"Grid\" aqui é grade de disponibilidade de AGENDAMENTO — quando um\n-- horário pode ser marcado —, não escala de trabalho. Portá-las para dentro do\n-- RH criaria a terceira tabela de horário do cluster e colocaria a agenda dentro\n-- do plugin que o D3 mandou justamente separar dela.\n-- \\`WHERE tenant_id IS NULL\\` no árbitro: a 073 da espinha trocou a PK de\n-- \\`migration.excluded_tables\\` por dois índices únicos PARCIAIS — um global e\n-- um por inquilino —, porque \"não trazer esta tabela\" passou a ser decisão de\n-- cliente e não do cluster. Índice parcial só serve de árbitro de ON CONFLICT\n-- quando o comando repete o mesmo recorte. Esta decisão é global.\nINSERT INTO migration.excluded_tables (source_table, reason) VALUES\n ('schedule_grids',\n 'Apesar do nome, é grade de disponibilidade de AGENDAMENTO (quando um horário pode ser marcado), não escala de trabalho. O destino natural é a agenda (public.schedules, kind working_hours), não o RH.'),\n ('schedule_grid_blocks',\n 'Bloco da grade de agendamento — mesma razão de schedule_grids. Escala de trabalho é plg_workforce_schedule_*.')\nON CONFLICT (source_table) WHERE tenant_id IS NULL DO UPDATE SET reason = EXCLUDED.reason;\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 10. A amarração com o financeiro, quando o financeiro existe\n-- ═══════════════════════════════════════════════════════════════════════════\n--\n-- Hora de trabalho vira dinheiro, e o V2 já tem onde: \\`plg_financial_invoices\\`\n-- para o título, \\`plg_financial_chart_of_accounts\\` e \\`plg_financial_cost_centers\\`\n-- para a classificação. O que a jornada NÃO pode fazer é exigir o financeiro:\n-- o plugin é instalável sozinho, e uma FK inline recusaria o arquivo inteiro num\n-- cluster que não ligou o módulo. Declarar a FK aqui, condicionada ao destino,\n-- é o que dá integridade onde ela é possível sem transformar preferência em\n-- dependência.\n--\n-- Todas ON DELETE SET NULL: apagar um centro de custo não pode apagar a batida\n-- de ninguém. O vínculo some, a hora fica.\nDO $$\nDECLARE\n r record;\nBEGIN\n FOR r IN\n SELECT * FROM (VALUES\n ('plg_workforce_time_entries', 'chart_account_id', 'plg_financial_chart_of_accounts'),\n ('plg_workforce_time_entries', 'cost_center_id', 'plg_financial_cost_centers'),\n ('plg_workforce_time_entries', 'payable_invoice_id', 'plg_financial_invoices'),\n ('plg_workforce_schedule_shifts', 'chart_account_id', 'plg_financial_chart_of_accounts'),\n ('plg_workforce_schedule_shifts', 'cost_center_id', 'plg_financial_cost_centers'),\n ('plg_workforce_periods', 'chart_account_id', 'plg_financial_chart_of_accounts'),\n ('plg_workforce_periods', 'cost_center_id', 'plg_financial_cost_centers'),\n ('plg_workforce_periods', 'payable_invoice_id', 'plg_financial_invoices')\n ) AS t(tbl, col, target)\n LOOP\n CONTINUE WHEN to_regclass('public.' || r.target) IS NULL;\n CONTINUE WHEN EXISTS (SELECT 1 FROM pg_constraint\n WHERE conname = r.tbl || '_' || r.col || '_fkey'\n AND conrelid = ('public.' || r.tbl)::regclass);\n EXECUTE format(\n 'ALTER TABLE public.%I ADD CONSTRAINT %I FOREIGN KEY (%I) REFERENCES public.%I(id) ON DELETE SET NULL',\n r.tbl, r.tbl || '_' || r.col || '_fkey', r.col, r.target);\n END LOOP;\nEND $$;\n\nSELECT set_config('migration.allowlist_unlock', 'off', true);\n`\n\nexport const MIGRATION_001_A_PROVA_DA_BATIDA_TEM_BYTES = `-- ---------------------------------------------------------------------------\n-- 001_a_prova_da_batida_tem_bytes.sql — a foto do ponto atravessa, e não só o\n-- caminho dela.\n--\n-- A 000 escreveu, no comentário de \\`evidence\\`:\n--\n-- \"O que não pode é perder: no V1 são \\`photo_path\\`, \\`lat\\`, \\`lng\\`,\n-- \\`accuracy_m\\`, \\`ip\\`, \\`user_agent\\` e \\`face_score\\`.\"\n--\n-- Sete campos. Seis atravessaram. O sétimo — o único que uma pessoa reconhece —\n-- atravessou como TEXTO: \\`8/2026-07-05/professional-15-1783278419303.jpg\\`,\n-- que é um objeto num bucket PRIVADO de outro projeto Supabase, o do V1.\n--\n-- Medido em 18/09/2026 no tenant Pertinho do Céu: 1.320 das 1.361 batidas têm\n-- esse caminho preenchido, e nenhuma das 1.320 imagens é alcançável daqui. No\n-- dia em que o V1 sair do ar elas deixam de existir em qualquer lugar.\n--\n-- É pior que uma coluna vazia, porque parece cheia. \\`evidence.photo_path\\` diz\n-- que houve captura e sugere que a captura está guardada. A tela de Registros de\n-- Ponto, por isso mesmo, escondia a seção de evidência inteira — o comentário\n-- dela dizia que a evidência estava \"hoje vazia\", o que já não era verdade.\n--\n-- Este arquivo declara para o motor de arquivos da 054 (\\`migration.asset_kinds\\`)\n-- que a foto de batida é uma espécie com bytes para transportar: de que bucket\n-- ela sai, para qual vai, o que falta atravessar, e quem reescreve o ponteiro.\n-- Mover os bytes é do fayz-etl (\\`fayz_etl/blobs.py\\`); a regra é daqui.\n--\n-- Idempotente e replay-safe.\n-- ---------------------------------------------------------------------------\n\n-- ─────────────────────────────────────────────────────────────────────────\n-- §1 O bucket, PRIVADO\n--\n-- Não é escolha de estilo: é biometria facial de um funcionário, com hora e\n-- coordenada ao lado. O V1 já a guarda em bucket privado e serve por URL\n-- assinada de curta duração (edge function \\`time-clock-photo-url\\`), e o V2 não\n-- pode rebaixar isso — um bucket público transformaria \"a cara e o horário de\n-- quem trabalha aqui\" em algo que basta um caminho para ver.\n--\n-- A leitura é por pasta de tenant, o mesmo escopo que o resto da plataforma usa.\n-- Com ele, \\`createSignedUrl\\` do lado do app funciona para quem é do tenant e\n-- falha para quem não é, sem RPC no meio.\n-- ─────────────────────────────────────────────────────────────────────────\n\nINSERT INTO storage.buckets (id, name, public, file_size_limit, allowed_mime_types)\nVALUES ('workforce-punch-photos', 'workforce-punch-photos', false, 5242880,\n ARRAY['image/jpeg', 'image/png', 'image/webp'])\nON CONFLICT (id) DO UPDATE SET\n public = EXCLUDED.public,\n file_size_limit = EXCLUDED.file_size_limit,\n allowed_mime_types = EXCLUDED.allowed_mime_types;\n\nDROP POLICY IF EXISTS plg_workforce_punch_photos_read ON storage.objects;\nDROP POLICY IF EXISTS plg_workforce_punch_photos_insert ON storage.objects;\nDROP POLICY IF EXISTS plg_workforce_punch_photos_update ON storage.objects;\nDROP POLICY IF EXISTS plg_workforce_punch_photos_delete ON storage.objects;\n\n-- Sem \\`anon\\`. A prova de uma jornada não se lê deslogado.\nCREATE POLICY plg_workforce_punch_photos_read ON storage.objects\n FOR SELECT TO authenticated\n USING (\n bucket_id = 'workforce-punch-photos'\n AND (storage.foldername(name))[1] IN (SELECT public.user_tenant_ids()::text)\n );\n\nCREATE POLICY plg_workforce_punch_photos_insert ON storage.objects\n FOR INSERT TO authenticated\n WITH CHECK (\n bucket_id = 'workforce-punch-photos'\n AND (storage.foldername(name))[1] IN (SELECT public.user_tenant_ids()::text)\n );\n\nCREATE POLICY plg_workforce_punch_photos_update ON storage.objects\n FOR UPDATE TO authenticated\n USING (\n bucket_id = 'workforce-punch-photos'\n AND (storage.foldername(name))[1] IN (SELECT public.user_tenant_ids()::text)\n )\n WITH CHECK (\n bucket_id = 'workforce-punch-photos'\n AND (storage.foldername(name))[1] IN (SELECT public.user_tenant_ids()::text)\n );\n\n-- DELETE fica de fora de propósito: apagar a foto de uma batida é apagar prova.\n-- Quem precisar (pedido de exclusão LGPD) passa pelo \\`service_role\\`, que é um\n-- ato deliberado e registrado, não um clique.\n\n-- ─────────────────────────────────────────────────────────────────────────\n-- §2 A espécie\n-- ─────────────────────────────────────────────────────────────────────────\n\nSELECT public.register_kind('document', 'punch_photo', 'workforce', ARRAY['active'], NULL,\n 'A foto que o totem capturou na batida — prova de quem bateu o ponto, junto com GPS e score facial');\n\n-- ─────────────────────────────────────────────────────────────────────────\n-- §3 O que falta, e o ponteiro\n--\n-- Todo o resto deste arquivo depende da 054 do base. Num pool que ainda não a\n-- aplicou, o plugin instala sem o transporte de bytes em vez de recusar a\n-- instalação: o ponto funciona sem foto, e a foto sem o ponto não é nada.\n-- ─────────────────────────────────────────────────────────────────────────\n\nDO $do$\nBEGIN\nIF to_regproc('migration.register_asset_kind(text,text,text,text,text,text)') IS NULL THEN\n RAISE NOTICE 'plugin-workforce 001: migration.register_asset_kind ausente (base < 054); a foto da batida fica sem transporte';\n RETURN;\nEND IF;\n\nCREATE OR REPLACE VIEW migration.v_asset_backlog_punch_photo AS\nSELECT e.tenant_id,\n 'time_entry'::text AS subject_type,\n e.id AS subject_id,\n e.person_id,\n e.evidence ->> 'photo_path' AS source_path,\n -- O bucket do V1 é privado: não há URL para baixar sem chave, e o\n -- transporte usa a chave de serviço da origem.\n NULL::text AS source_url,\n -- Uma foto por batida, nomeada pela batida. O caminho do V1 tem epoch no\n -- nome e não é reconstruível a partir do destino; o do V2 é derivável de\n -- qualquer lado, o que é o que faz o rerun sobrescrever em vez de dobrar.\n e.tenant_id::text || '/' || e.id::text || '.jpg' AS target_path,\n coalesce(e.person_name, 'sem nome') || ' · '\n || to_char(e.punched_at, 'DD/MM/YYYY HH24:MI') AS title\n FROM public.plg_workforce_time_entries e\n -- \\`photo_path\\` é a procedência (o caminho no V1, que fica); \\`photo\\` é o\n -- ponteiro do V2. Ter o primeiro e não o segundo É a definição de \"falta\n -- atravessar\", e escrever o segundo tira a linha desta lista.\n WHERE e.evidence ? 'photo_path'\n AND NOT (e.evidence ? 'photo');\n\nCOMMENT ON VIEW migration.v_asset_backlog_punch_photo IS\n 'Batidas cuja foto ainda só existe no bucket privado do V1 (001). A condição É o ponteiro: escrever evidence.photo apaga a linha desta lista.';\n\nCREATE OR REPLACE FUNCTION migration._point_punch_photo(p_tenant uuid, p_document uuid, p_row jsonb)\nRETURNS void\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = ''\nAS $fn$\nDECLARE v_entry uuid := (p_row ->> 'subject_id')::uuid;\nBEGIN\n IF v_entry IS NULL THEN\n RAISE EXCEPTION '_point_punch_photo: preciso de subject_id (a batida)' USING ERRCODE = '22023';\n END IF;\n -- UPDATE numa tabela append-only: passa porque \\`attach_asset\\` liga\n -- \\`migration.writer\\`, que é a mesma escotilha que o writer da batida usa.\n -- \\`photo_path\\` NÃO é tocado — ele é de onde a imagem veio, e continua sendo.\n UPDATE public.plg_workforce_time_entries\n SET evidence = migration._deep_set(coalesce(evidence, '{}'::jsonb), ARRAY['photo'],\n jsonb_build_object(\n 'bucket', p_row ->> 'bucket',\n 'path', p_row ->> 'target_path',\n 'document_id', p_document)),\n updated_at = now()\n WHERE id = v_entry AND tenant_id = p_tenant;\nEND $fn$;\n\nPERFORM migration.register_asset_kind(\n 'punch_photo', 'time-clock-photos', 'workforce-punch-photos',\n 'v_asset_backlog_punch_photo', 'migration._point_punch_photo',\n 'A foto do totem. Bucket privado nas duas pontas: é biometria facial com hora e coordenada ao lado, e o V1 já a tratava assim.');\nEND $do$;\n`\n\nexport const MIGRATION_002_O_GUARDA_DA_FOTO_OLHAVA_O_NOME_ERRADO = `-- ---------------------------------------------------------------------------\n-- 002_o_guarda_da_foto_olhava_o_nome_errado.sql — o §3 da 001 nunca rodou.\n--\n-- A 001 protege o próprio corpo com um guard, porque tudo nela depois do §2\n-- depende da 054 do base:\n--\n-- IF to_regproc('migration.register_asset_kind(text,text,text,text,text,text)')\n-- IS NULL THEN RETURN; END IF;\n--\n-- **\\`to_regproc\\` recebe um NOME, não uma assinatura.** Com a lista de tipos\n-- entre parênteses ela devolve NULL — e não levanta erro, que é exatamente o que\n-- torna isso invisível: \\`to_regproc\\` foi feita para responder \"não existe\" em vez\n-- de estourar. Quem lê a linha lê uma checagem; o Postgres lê uma pergunta\n-- malformada e responde \"não existe\" às duas.\n--\n-- Resultado medido no cluster em 19/09/2026, logo depois de aplicar a 001: o\n-- bucket \\`workforce-punch-photos\\` existe (§1, fora do bloco), a espécie\n-- \\`punch_photo\\` está registrada (§2, fora do bloco), e do §3 não existe NADA —\n-- nem a view de backlog, nem \\`_point_punch_photo\\`, nem a linha em\n-- \\`migration.asset_kinds\\`. A migration \"passou\". A foto continuou sem\n-- transporte, e o \\`mig-assets\\` teria relatado só os 63 avatares como se fosse o\n-- backlog inteiro.\n--\n-- Quem quer assinatura é \\`to_regprocedure\\`. É a única diferença deste arquivo.\n--\n-- ── Por que um arquivo novo, e não uma correção na 001 ─────────────────────\n--\n-- A 001 já está no ledger deste cluster. \\`fayz db apply\\` trata checksum\n-- diferente num arquivo aplicado como PARADA — e está certo: um app que já rodou\n-- a 001 não pode descobrir que os bytes dela mudaram. Corrigir para frente custa\n-- este arquivo; editar a 001 custaria o apply de todo app que já a tomou.\n--\n-- Idempotente e replay-safe.\n-- ---------------------------------------------------------------------------\n\nDO $do$\nBEGIN\n-- \\`to_regprocedure\\`, que é quem entende \\`(text,text,…)\\`. A mesma armadilha está\n-- na 152 do base (\\`to_regproc('app.scaffold_table(text,text,text,boolean,text)')\\`),\n-- e é por isso que a checagem aqui é pelo NOME quando basta o nome: um guard que\n-- mente é pior que nenhum guard, porque o arquivo sai dizendo que aplicou.\nIF to_regprocedure('migration.register_asset_kind(text,text,text,text,text,text)') IS NULL THEN\n RAISE NOTICE 'plugin-workforce 002: migration.register_asset_kind ausente (base < 054); a foto da batida fica sem transporte';\n RETURN;\nEND IF;\n\nCREATE OR REPLACE VIEW migration.v_asset_backlog_punch_photo AS\nSELECT e.tenant_id,\n 'time_entry'::text AS subject_type,\n e.id AS subject_id,\n e.person_id,\n e.evidence ->> 'photo_path' AS source_path,\n -- O bucket do V1 é privado: não há URL para baixar sem chave, e o\n -- transporte usa a chave de serviço da origem.\n NULL::text AS source_url,\n -- Uma foto por batida, nomeada pela batida. O caminho do V1 tem epoch no\n -- nome e não é reconstruível a partir do destino; o do V2 é derivável de\n -- qualquer lado, o que é o que faz o rerun sobrescrever em vez de dobrar.\n e.tenant_id::text || '/' || e.id::text || '.jpg' AS target_path,\n coalesce(e.person_name, 'sem nome') || ' · '\n || to_char(e.punched_at, 'DD/MM/YYYY HH24:MI') AS title\n FROM public.plg_workforce_time_entries e\n -- \\`photo_path\\` é a procedência (o caminho no V1, que fica); \\`photo\\` é o\n -- ponteiro do V2. Ter o primeiro e não o segundo É a definição de \"falta\n -- atravessar\", e escrever o segundo tira a linha desta lista.\n WHERE e.evidence ? 'photo_path'\n AND NOT (e.evidence ? 'photo');\n\nCOMMENT ON VIEW migration.v_asset_backlog_punch_photo IS\n 'Batidas cuja foto ainda só existe no bucket privado do V1 (001/002). A condição É o ponteiro: escrever evidence.photo apaga a linha desta lista.';\n\nCREATE OR REPLACE FUNCTION migration._point_punch_photo(p_tenant uuid, p_document uuid, p_row jsonb)\nRETURNS void\nLANGUAGE plpgsql SECURITY DEFINER SET search_path = ''\nAS $fn$\nDECLARE v_entry uuid := (p_row ->> 'subject_id')::uuid;\nBEGIN\n IF v_entry IS NULL THEN\n RAISE EXCEPTION '_point_punch_photo: preciso de subject_id (a batida)' USING ERRCODE = '22023';\n END IF;\n -- UPDATE numa tabela append-only: passa porque \\`attach_asset\\` liga\n -- \\`migration.writer\\`, que é a mesma escotilha que o writer da batida usa.\n -- \\`photo_path\\` NÃO é tocado — ele é de onde a imagem veio, e continua sendo.\n UPDATE public.plg_workforce_time_entries\n SET evidence = migration._deep_set(coalesce(evidence, '{}'::jsonb), ARRAY['photo'],\n jsonb_build_object(\n 'bucket', p_row ->> 'bucket',\n 'path', p_row ->> 'target_path',\n 'document_id', p_document)),\n updated_at = now()\n WHERE id = v_entry AND tenant_id = p_tenant;\nEND $fn$;\n\nPERFORM migration.register_asset_kind(\n 'punch_photo', 'time-clock-photos', 'workforce-punch-photos',\n 'v_asset_backlog_punch_photo', 'migration._point_punch_photo',\n 'A foto do totem. Bucket privado nas duas pontas: é biometria facial com hora e coordenada ao lado, e o V1 já a tratava assim.');\nEND $do$;\n`\n\nexport const MIGRATION_003_O_PONTO_EM_ABERTO_PARA_DE_MENTIR_A_DURACAO = `-- ---------------------------------------------------------------------------\n-- 003_o_ponto_em_aberto_para_de_mentir_a_duracao.sql — \\`-497155h02\\`.\n--\n-- A tela de Registros de Ponto mostra isso na coluna Duração de todo ponto em\n-- aberto. Medido em 19/09/2026 no tenant Pertinho do Céu: **19 dias negativos,\n-- e os 19 estão abertos** — nenhum dia fechado dá negativo. O número não é\n-- aleatório e não é overflow.\n--\n-- ── De onde ele sai ────────────────────────────────────────────────────────\n--\n-- A 000 soma as horas com sinal, e o desenho é bom: \\`clock_out\\` e \\`break_start\\`\n-- FECHAM um trecho e entram positivos, \\`clock_in\\` e \\`break_end\\` ABREM e entram\n-- negativos. Quantos intervalos o dia tiver, a conta é a mesma — é isso que o\n-- par único do V1 não consegue fazer.\n--\n-- Ela só assume uma coisa que o dia em aberto não cumpre: que toda abertura tem\n-- o seu fechamento. Um dia com uma batida só —\n--\n-- clock_in 18:09\n--\n-- — soma \\`-extract(epoch FROM '2026-09-18 18:09')\\`, que é −1.789.790. segundos\n-- desde 1970. Dividido por 60 vira −29.829.302 minutos, e o formatador de horas\n-- faz o resto: \\`-497155h02\\`. O epoch vazou para a tela.\n--\n-- ── O conserto da conta ────────────────────────────────────────────────────\n--\n-- Devolver à soma a abertura que ficou sem par. O que sobra é exatamente a\n-- soma dos trechos FECHADOS, que é a única coisa que se pode afirmar de um dia\n-- que ainda não terminou:\n--\n-- entrada 09:00, saída 12:00, entrada 13:00 → 3h00 fechadas, aberto desde 13:00\n-- entrada 18:09 → 0h00 fechadas, aberto desde 18:09\n--\n-- Zero não é um defeito aqui: é a resposta certa para \"quanto já fechou?\" antes\n-- de qualquer fechamento. O que faltava para a tela era a OUTRA metade da\n-- pergunta, e é a coluna nova.\n--\n-- ── \\`open_since\\`, e por que uma coluna e não uma conta na tela ─────────────\n--\n-- Quem confere ponto quer saber há quanto tempo a pessoa está dentro. A tela\n-- não consegue descobrir isso sozinha: ela recebe o dia agregado, não as\n-- batidas, e \"a última abertura sem par\" é justamente o que a agregação sabe e\n-- ela não. Sem a coluna, a alternativa seria a tela buscar as batidas de cada\n-- linha — 299 consultas para desenhar uma tabela.\n--\n-- O relógio corre do lado de quem olha, não do banco: a coluna é o INSTANTE, e\n-- o \"6h58 em curso\" é calculado no render. Um intervalo calculado aqui\n-- envelheceria entre a consulta e a pintura, e envelheceria de novo a cada\n-- segundo que a aba ficasse aberta.\n--\n-- ── O que NÃO muda ────────────────────────────────────────────────────────\n--\n-- Dia em aberto continua **fora** do total do dia e do período. A regra é a do\n-- V1 e está certa: contar uma jornada que não terminou inventa hora que ninguém\n-- trabalhou. O que muda é que agora o número que ele não soma também não é\n-- absurdo quando alguém olha a linha.\n--\n-- Idempotente e replay-safe.\n-- ---------------------------------------------------------------------------\n\nCREATE OR REPLACE VIEW public.v_workforce_day\nWITH (security_invoker = 'true') AS\nWITH bruto AS (\n SELECT e.tenant_id,\n e.unit_id,\n e.person_id,\n e.work_date,\n min(e.effective_at) FILTER (WHERE e.kind = 'clock_in') AS first_in,\n max(e.effective_at) FILTER (WHERE e.kind = 'clock_out') AS last_out,\n count(*) FILTER (WHERE e.kind = 'break_start') AS break_count,\n count(*) FILTER (WHERE e.kind IN ('clock_in', 'break_end')) AS aberturas,\n count(*) FILTER (WHERE e.kind IN ('clock_out', 'break_start')) AS fechamentos,\n -- A última ABERTURA do dia. Quando as contagens não batem, é ela que\n -- ficou sem par — os eventos de um dia chegam em ordem, e uma abertura\n -- anterior já teria sido fechada pela seguinte.\n max(e.effective_at) FILTER (WHERE e.kind IN ('clock_in', 'break_end')) AS ultima_abertura,\n sum(CASE\n WHEN e.kind IN ('clock_out', 'break_start') THEN extract(epoch FROM e.effective_at)\n WHEN e.kind IN ('clock_in', 'break_end') THEN -extract(epoch FROM e.effective_at)\n END) AS soma_com_sinal\n FROM public.v_workforce_time_entries e\n WHERE NOT e.voided\n GROUP BY e.tenant_id, e.unit_id, e.person_id, e.work_date\n),\nrealized AS (\n SELECT b.tenant_id,\n b.unit_id,\n b.person_id,\n b.work_date,\n b.first_in,\n b.last_out,\n b.break_count,\n (b.aberturas <> b.fechamentos) AS is_open,\n CASE WHEN b.aberturas <> b.fechamentos THEN b.ultima_abertura END AS open_since,\n -- Devolve à soma a abertura sem par. Sem isto o que sobra é o epoch\n -- dela, com sinal trocado, e foi o que a tela vinha mostrando.\n (b.soma_com_sinal\n + CASE WHEN b.aberturas <> b.fechamentos\n THEN extract(epoch FROM b.ultima_abertura)\n ELSE 0 END) AS worked_seconds\n FROM bruto b\n),\nplanned AS (\n SELECT a.tenant_id,\n a.unit_id,\n a.person_id,\n s.schedule_date AS work_date,\n a.id AS assignment_id,\n a.role,\n a.status AS assignment_status,\n a.shift_label,\n a.shift_start_time,\n a.shift_end_time,\n -- O turno que vira o dia é normal aqui; sem o +24h a jornada da noite\n -- daria negativa.\n (extract(epoch FROM a.shift_end_time - a.shift_start_time)\n + CASE WHEN a.shift_end_time <= a.shift_start_time THEN 86400 ELSE 0 END) AS planned_seconds\n FROM public.plg_workforce_schedule_assignments a\n JOIN public.plg_workforce_schedules s ON s.id = a.schedule_id\n WHERE s.status IN ('published', 'closed')\n AND a.role = 'titular'\n AND a.shift_start_time IS NOT NULL\n AND a.shift_end_time IS NOT NULL\n)\nSELECT coalesce(p.tenant_id, r.tenant_id) AS tenant_id,\n coalesce(p.unit_id, r.unit_id) AS unit_id,\n coalesce(p.person_id, r.person_id) AS person_id,\n coalesce(p.work_date, r.work_date) AS work_date,\n p.assignment_id,\n p.shift_label,\n p.shift_start_time,\n p.shift_end_time,\n p.assignment_status,\n (p.planned_seconds / 60)::integer AS planned_minutes,\n (r.worked_seconds / 60)::integer AS worked_minutes,\n ((r.worked_seconds - p.planned_seconds) / 60)::integer AS variance_minutes,\n r.first_in,\n r.last_out,\n r.break_count,\n coalesce(r.is_open, false) AS is_open,\n (r.person_id IS NULL) AS absent,\n (p.assignment_id IS NULL) AS outside_schedule,\n -- Coluna nova, no fim: \\`CREATE OR REPLACE VIEW\\` só aceita acrescentar\n -- aqui, e é de propósito — quem lê por posição não se move.\n r.open_since\n FROM planned p\n FULL OUTER JOIN realized r\n ON r.tenant_id = p.tenant_id\n AND r.person_id = p.person_id\n AND r.work_date = p.work_date;\n\nCOMMENT ON VIEW public.v_workforce_day IS\n 'Jornada prevista × realizada por pessoa e dia. Previsto vem da escala publicada, realizado das batidas com ajuste aplicado. FULL OUTER JOIN: \\`absent\\` é escala sem ponto, \\`outside_schedule\\` é ponto sem escala. \\`worked_minutes\\` conta só os trechos FECHADOS; \\`open_since\\` é a abertura que ainda não tem par (003).';\n\nCOMMENT ON COLUMN public.v_workforce_day.open_since IS\n 'O instante da abertura sem par, quando o ponto está aberto (003). É o INSTANTE e não a duração: o relógio corre do lado de quem olha a tela, e um intervalo calculado aqui envelheceria entre a consulta e a pintura.';\n\nGRANT SELECT ON public.v_workforce_day TO authenticated, service_role;\n`\n\nexport const MIGRATION_004_A_JORNADA_IMPLAUSIVEL_NAO_SOMA = `-- ---------------------------------------------------------------------------\n-- 004_a_jornada_implausivel_nao_soma.sql — 45h45 num dia.\n--\n-- Medido em 19/09/2026 no tenant Pertinho do Céu, na tela de Registros de Ponto:\n--\n-- Steffany Fidelis da Costa 15:41 → 13:26 45h45\n-- CRISTIANE CARDOSO OLIVEIRA 17:14 → 09:23 16h10\n-- jannyne gomes dos santos 09:07 → 08:58 15h56\n--\n-- e o cabeçalho do dia somando **109h45** para oito pessoas.\n--\n-- Nenhum desses é erro de conta: a 003 já consertou a soma, e esses dias estão\n-- FECHADOS. Eles são a medição correta de um par errado — alguém entrou, foi\n-- embora sem bater a saída, e a saída caiu horas ou dias depois. O V1 grava\n-- \\`checkin_at\\` e \\`checkout_at\\` como um par só, então o buraco atravessou inteiro.\n--\n-- ── Por que não um teto de 8h ──────────────────────────────────────────────\n--\n-- Trocar 45h45 por 8h faria o total parecer certo. É o pior resultado possível:\n--\n-- · 8h ali é um número que ninguém trabalhou e ninguém digitou — é a regra\n-- \"nada de default inventado\" quebrada no lugar onde ela mais custa, que é\n-- base de cálculo de folha;\n-- · e o dia deixaria de parecer estranho, então a batida furada nunca seria\n-- corrigida. O erro sai da tela e fica no dado, que é o contrário de\n-- resolver.\n--\n-- ── O que esta migration faz ───────────────────────────────────────────────\n--\n-- Estende a regra que a tela JÁ tem. Ponto em aberto não soma, porque contar\n-- uma jornada que não terminou inventa hora. Um dia de 45h é o mesmo problema\n-- com outra cara — um par em que não se pode confiar —, então ele também não\n-- soma. O valor medido continua à vista, inteiro, com o motivo escrito ao lado.\n--\n-- \\`review_reason\\` nomeia por que o dia não entra na conta:\n--\n-- 'open' ainda não terminou\n-- 'span_too_long' fechou, e fechou com duração que não é uma jornada\n--\n-- NULL é o dia que conta. Uma coluna só, e quem soma filtra por ela — em vez de\n-- cada relatório redescobrir a regra e descobrir diferente.\n--\n-- ── O limite, e por que dezesseis horas ───────────────────────────────────\n--\n-- A jornada mais longa do vocabulário do V1 é a escala 12x36: doze horas. Com\n-- duas de extra, quatorze. Dezesseis deixa margem para o turno que vira a noite\n-- e ainda separa com folga o caso real, que não é uma jornada comprida e sim\n-- uma saída que ficou pendurada — os três medidos acima têm 16h, 16h e 46h.\n--\n-- É o MESMO dezesseis que a tela usa para dizer \"sem saída há 31h\" num ponto\n-- aberto, e é de propósito: um número, uma justificativa, os dois lados da\n-- mesma pergunta.\n--\n-- Idempotente e replay-safe.\n-- ---------------------------------------------------------------------------\n\nCREATE OR REPLACE FUNCTION public.workforce_max_shift_minutes()\nRETURNS integer LANGUAGE sql IMMUTABLE PARALLEL SAFE\nAS $$ SELECT 16 * 60 $$;\n\nCOMMENT ON FUNCTION public.workforce_max_shift_minutes() IS\n 'Acima disto uma jornada fechada deixa de ser jornada e vira saída não batida (004). 12x36 é a mais longa do vocabulário do V1; dezesseis dá margem ao turno que vira a noite. Função e não constante literal para que a tela, a view e um relatório futuro citem o mesmo número.';\n\nCREATE OR REPLACE VIEW public.v_workforce_day\nWITH (security_invoker = 'true') AS\nWITH bruto AS (\n SELECT e.tenant_id,\n e.unit_id,\n e.person_id,\n e.work_date,\n min(e.effective_at) FILTER (WHERE e.kind = 'clock_in') AS first_in,\n max(e.effective_at) FILTER (WHERE e.kind = 'clock_out') AS last_out,\n count(*) FILTER (WHERE e.kind = 'break_start') AS break_count,\n count(*) FILTER (WHERE e.kind IN ('clock_in', 'break_end')) AS aberturas,\n count(*) FILTER (WHERE e.kind IN ('clock_out', 'break_start')) AS fechamentos,\n -- A última ABERTURA do dia. Quando as contagens não batem, é ela que\n -- ficou sem par — os eventos de um dia chegam em ordem, e uma abertura\n -- anterior já teria sido fechada pela seguinte.\n max(e.effective_at) FILTER (WHERE e.kind IN ('clock_in', 'break_end')) AS ultima_abertura,\n sum(CASE\n WHEN e.kind IN ('clock_out', 'break_start') THEN extract(epoch FROM e.effective_at)\n WHEN e.kind IN ('clock_in', 'break_end') THEN -extract(epoch FROM e.effective_at)\n END) AS soma_com_sinal\n FROM public.v_workforce_time_entries e\n WHERE NOT e.voided\n GROUP BY e.tenant_id, e.unit_id, e.person_id, e.work_date\n),\nrealized AS (\n SELECT b.tenant_id,\n b.unit_id,\n b.person_id,\n b.work_date,\n b.first_in,\n b.last_out,\n b.break_count,\n (b.aberturas <> b.fechamentos) AS is_open,\n CASE WHEN b.aberturas <> b.fechamentos THEN b.ultima_abertura END AS open_since,\n -- Devolve à soma a abertura sem par (003). Sem isto o que sobra é o\n -- epoch dela, com sinal trocado.\n (b.soma_com_sinal\n + CASE WHEN b.aberturas <> b.fechamentos\n THEN extract(epoch FROM b.ultima_abertura)\n ELSE 0 END) AS worked_seconds\n FROM bruto b\n),\nplanned AS (\n SELECT a.tenant_id,\n a.unit_id,\n a.person_id,\n s.schedule_date AS work_date,\n a.id AS assignment_id,\n a.role,\n a.status AS assignment_status,\n a.shift_label,\n a.shift_start_time,\n a.shift_end_time,\n -- O turno que vira o dia é normal aqui; sem o +24h a jornada da noite\n -- daria negativa.\n (extract(epoch FROM a.shift_end_time - a.shift_start_time)\n + CASE WHEN a.shift_end_time <= a.shift_start_time THEN 86400 ELSE 0 END) AS planned_seconds\n FROM public.plg_workforce_schedule_assignments a\n JOIN public.plg_workforce_schedules s ON s.id = a.schedule_id\n WHERE s.status IN ('published', 'closed')\n AND a.role = 'titular'\n AND a.shift_start_time IS NOT NULL\n AND a.shift_end_time IS NOT NULL\n)\nSELECT coalesce(p.tenant_id, r.tenant_id) AS tenant_id,\n coalesce(p.unit_id, r.unit_id) AS unit_id,\n coalesce(p.person_id, r.person_id) AS person_id,\n coalesce(p.work_date, r.work_date) AS work_date,\n p.assignment_id,\n p.shift_label,\n p.shift_start_time,\n p.shift_end_time,\n p.assignment_status,\n (p.planned_seconds / 60)::integer AS planned_minutes,\n -- O MEDIDO, sempre. Não é aqui que se decide se ele conta — a coluna\n -- mente se for corrigida, e um número corrigido em silêncio é pior que\n -- um número estranho.\n (r.worked_seconds / 60)::integer AS worked_minutes,\n ((r.worked_seconds - p.planned_seconds) / 60)::integer AS variance_minutes,\n r.first_in,\n r.last_out,\n r.break_count,\n coalesce(r.is_open, false) AS is_open,\n (r.person_id IS NULL) AS absent,\n (p.assignment_id IS NULL) AS outside_schedule,\n r.open_since,\n -- Por que este dia não entra na soma. NULL = entra.\n CASE\n WHEN r.person_id IS NULL THEN NULL -- escala sem ponto: não há o que somar\n WHEN r.is_open THEN 'open'\n WHEN (r.worked_seconds / 60) > public.workforce_max_shift_minutes()\n THEN 'span_too_long'\n END AS review_reason\n FROM planned p\n FULL OUTER JOIN realized r\n ON r.tenant_id = p.tenant_id\n AND r.person_id = p.person_id\n AND r.work_date = p.work_date;\n\nCOMMENT ON VIEW public.v_workforce_day IS\n 'Jornada prevista × realizada por pessoa e dia. \\`worked_minutes\\` é sempre o MEDIDO; \\`review_reason\\` diz por que um dia não entra na soma — \\`open\\` (não terminou) ou \\`span_too_long\\` (fechou com duração que não é jornada, 004). Quem soma filtra por ela.';\n\nCOMMENT ON COLUMN public.v_workforce_day.review_reason IS\n 'NULL = o dia conta. \\`open\\` = ponto em aberto. \\`span_too_long\\` = acima de workforce_max_shift_minutes(), que na prática é saída não batida e não jornada longa (004).';\n\nGRANT SELECT ON public.v_workforce_day TO authenticated, service_role;\n`\n\nexport const MIGRATION_005_A_FICHA_TRABALHISTA_TEM_ONDE_MORAR = `-- ---------------------------------------------------------------------------\n-- 005_a_ficha_trabalhista_tem_onde_morar.sql — o RH do V1 ganha destino.\n--\n-- Escrito a partir de \\`~/dev/beautyplace/docs/v1-guide/rh\\`, que documenta o\n-- módulo do V1 andando nele: a Visão Geral (oito cartões, três listas) e a Ficha\n-- de RH da pessoa (dezesseis vistas). O FLOW de cada um diz \\`v2: status:\n-- missing\\` — e dizia certo: não havia nada disso aqui.\n--\n-- ── O que este arquivo NÃO traz, e por quê ────────────────────────────────\n--\n-- Não são as dezesseis vistas. Medido na origem em 19/09/2026, nas 886 pessoas\n-- dos três tenants em porte:\n--\n-- as 12 tabelas de lista da Ficha 0 linhas — no V1 INTEIRO, não só\n-- (férias, faltas, advertências, nesses tenants\n-- treinamentos, avaliações, exames,\n-- EPIs, pendências, dependentes,\n-- histórico salarial, 13º, benefícios)\n-- admission_date, dismissal_date, 0 preenchidos\n-- job_title, pis_pasep, CTPS, eSocial\n-- base_salary 25 de 422\n-- contract_type 2\n--\n-- O próprio FLOW da Visão Geral avisa: *\"Num tenant recém-migrado ele mostra\n-- headcount cheio e todo o resto zerado — e isso não é defeito, é ficha vazia.\"*\n-- Aqui TODO tenant é assim. Desenhar dezesseis vistas para portar zero linha\n-- seria construir um formulário de cada vez que alguém leu um FLOW.\n--\n-- Então vem o núcleo que sustenta o conceito e já é útil no primeiro dia:\n--\n-- employment o vínculo — é dele que saem headcount, admissões,\n-- demissões, turnover e experiência vencendo. Sem ele\n-- nenhum número de RH existe, e é a vista 1 do V1\n-- vacations férias. Obrigação legal, recorrente, e a única lista do\n-- V1 que alimenta um cartão\n-- absences faltas e afastamentos\n-- pending_items pendências — a outra lista que aparece no painel\n--\n-- As outras doze entram quando alguém for usá-las. O que elas precisam já está\n-- de pé: a forma da tabela, o escopo, a permissão e a view do painel.\n--\n-- ── A permissão, que o FLOW manda resolver ANTES ──────────────────────────\n--\n-- V1-069: no V1 **não há permissão separada para RH**. Quem edita cadastro vê\n-- salário, CPF, dependentes e CID de atestado. O FLOW da Ficha fecha dizendo que\n-- portar só vale \"desde que a questão da permissão separada seja resolvida\n-- antes\" — então ela é resolvida aqui, e não depois.\n--\n-- \\`workforce_hr.*\\` é uma família própria: quem tem \\`workforce.read\\` vê escala e\n-- ponto e NÃO vê salário. São duas perguntas diferentes e agora têm duas\n-- respostas.\n--\n-- ── O que o V2 faz e o V1 não ────────────────────────────────────────────\n--\n-- O FLOW da vista 10 registra, como defeito: *\"Não conversa com o ponto\n-- eletrônico nem com a escala: uma falta lançada aqui não aparece lá.\"* No V1\n-- são dois sistemas sobre a mesma pessoa que não se olham — alguém de atestado\n-- aparece como FALTA na folha de ponto, e quem confere precisa lembrar de cabeça.\n--\n-- A §7 conserta: \\`v_workforce_day\\` passa a saber do afastamento. Um dia coberto\n-- por atestado deixa de ser \"Falta\" e passa a dizer o que foi. É a razão de o RH\n-- morar no mesmo plugin do ponto, e não ao lado dele.\n--\n-- Idempotente e replay-safe.\n-- ---------------------------------------------------------------------------\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 1. A PERMISSÃO SEPARADA (V1-069)\n-- ═══════════════════════════════════════════════════════════════════════════\n\nINSERT INTO app.permissions (key, plugin, description) VALUES\n ('workforce_hr.read', 'workforce_hr', 'Ver a ficha trabalhista: vínculo, salário, férias, afastamentos e pendências.'),\n ('workforce_hr.create', 'workforce_hr', 'Lançar na ficha trabalhista.'),\n ('workforce_hr.edit', 'workforce_hr', 'Corrigir lançamento da ficha trabalhista.'),\n ('workforce_hr.delete', 'workforce_hr', 'Excluir lançamento da ficha trabalhista.')\nON CONFLICT (key) DO UPDATE SET plugin = EXCLUDED.plugin, description = EXCLUDED.description;\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 2. O VÍNCULO\n-- ═══════════════════════════════════════════════════════════════════════════\n--\n-- Uma linha por pessoa, e não colunas em \\`public.people\\`. Três razões, e a\n-- terceira é a que decide:\n--\n-- · \\`people\\` é do core e atende cliente, fornecedor e profissional; quarenta\n-- colunas de CLT ali seriam nulas para a esmagadora maioria das linhas;\n-- · o V1 tem DUAS tabelas (professionals, employees) com os mesmos campos, e\n-- o V2 tem uma pessoa só — a separação é papel, não cadastro;\n-- · e é a tabela que carrega o salário. Ela precisa de uma policy PRÓPRIA,\n-- e uma coluna não tem policy: RLS é por tabela. Guardar salário em\n-- \\`people\\` seria reproduzir o V1-069 no schema.\n\nCREATE TABLE IF NOT EXISTS public.plg_workforce_employment (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n unit_id uuid,\n person_id uuid NOT NULL REFERENCES public.people(id) ON DELETE CASCADE,\n\n -- ── vínculo (vista 1 do V1: Contrato) ────────────────────────────────────\n -- Vocabulário exato do FLOW. Lista fechada porque é ela que decide encargo, e\n -- \"CLT \" com espaço vira um tipo de contrato novo em silêncio.\n contract_kind text CHECK (contract_kind IN\n ('clt', 'pj', 'estagio', 'jovem_aprendiz', 'autonomo', 'socio', 'temporario', 'intermitente')),\n admission_date date,\n dismissal_date date,\n dismissal_reason text,\n -- O V1 tem os dois: o fim da PRIMEIRA experiência e o fim FINAL. É o segundo\n -- que alimenta o cartão \"Experiência vencendo\".\n probation_first_end date,\n probation_final_end date,\n job_title text,\n department text,\n schedule_regime text CHECK (schedule_regime IN\n ('mensalista', 'horista', 'diarista', 'escala_12x36', 'escala_6x1', 'escala_5x2')),\n weekly_hours numeric(5,2),\n monthly_hours numeric(6,2),\n esocial_registration text,\n\n -- ── remuneração (vista 2) ────────────────────────────────────────────────\n -- Valor de REFERÊNCIA, e o V1 diz isso com todas as letras: nada aqui vira\n -- conta a pagar, comissão ou desconto. O comentário fica porque a coluna\n -- chamada \\`base_salary\\` convida a supor o contrário.\n base_salary numeric(14,2),\n pay_frequency text CHECK (pay_frequency IN ('mensal', 'quinzenal', 'semanal', 'diario', 'por_hora')),\n -- Os quinze auxílios e adicionais da vista 2 em jsonb, e não em quinze\n -- colunas. Medido: ZERO deles preenchido nas 886 pessoas. Quinze colunas\n -- nulas seriam quinze decisões de schema tomadas sem um caso de uso; a chave\n -- que a casa usar aparece aqui e vira coluna quando pagar a passagem.\n allowances jsonb NOT NULL DEFAULT '{}'::jsonb,\n\n notes text,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n -- Um vínculo por pessoa. Recontratação reabre o mesmo, com a data nova — o\n -- histórico de quem saiu e voltou é uma vista de lista que ainda não existe,\n -- e inventar a segunda linha agora criaria dois headcounts para uma pessoa.\n CONSTRAINT plg_workforce_employment_person UNIQUE (tenant_id, person_id),\n -- Demissão antes da admissão não é dado ruim, é dado impossível.\n CONSTRAINT plg_workforce_employment_dates\n CHECK (dismissal_date IS NULL OR admission_date IS NULL OR dismissal_date >= admission_date)\n);\n\nCOMMENT ON TABLE public.plg_workforce_employment IS\n 'O vínculo trabalhista de uma pessoa (005). É dele que saem headcount, admissões, demissões, turnover e experiência vencendo. Tabela própria e não colunas em people: RLS é por tabela, e é o salário que precisa da policy.';\nCOMMENT ON COLUMN public.plg_workforce_employment.base_salary IS\n 'Valor de REFERÊNCIA. Não vira conta a pagar, comissão nem desconto — o V1 também não fazia isso, e o nome da coluna convida a supor que faz.';\nCOMMENT ON COLUMN public.plg_workforce_employment.allowances IS\n 'Auxílios e adicionais (VT, VR, VA, plano, creche, noturno, insalubridade…). Em jsonb porque os quinze campos da vista 2 do V1 estão vazios nas 886 pessoas medidas: vira coluna quando alguém pagar a passagem.';\n\nCREATE INDEX IF NOT EXISTS plg_workforce_employment_tenant_person\n ON public.plg_workforce_employment (tenant_id, person_id);\nCREATE INDEX IF NOT EXISTS plg_workforce_employment_ativo\n ON public.plg_workforce_employment (tenant_id) WHERE dismissal_date IS NULL;\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 3. FÉRIAS (vista 8)\n-- ═══════════════════════════════════════════════════════════════════════════\n\nCREATE TABLE IF NOT EXISTS public.plg_workforce_vacations (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n unit_id uuid,\n person_id uuid NOT NULL REFERENCES public.people(id) ON DELETE CASCADE,\n -- O período AQUISITIVO: o que a pessoa ganhou. É o \\`accrual_end\\` que alimenta\n -- \"Férias vencendo (60d)\".\n accrual_start date NOT NULL,\n accrual_end date NOT NULL,\n -- O período de GOZO: quando ela tirou. Nulo é o estado normal de quem ainda\n -- não programou.\n taken_start date,\n taken_end date,\n days_taken integer,\n days_sold integer,\n advance_13th boolean NOT NULL DEFAULT false,\n -- Digitado, como no V1. O sistema NÃO calcula o terço — e escrever isso aqui\n -- é o que impede alguém de supor que a coluna vazia é um bug.\n constitutional_third numeric(14,2),\n status text NOT NULL DEFAULT 'pendente'\n CHECK (status IN ('pendente', 'programada', 'em_gozo', 'concluida', 'vencida')),\n notes text,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n CONSTRAINT plg_workforce_vacations_accrual CHECK (accrual_end >= accrual_start),\n CONSTRAINT plg_workforce_vacations_taken\n CHECK (taken_end IS NULL OR taken_start IS NULL OR taken_end >= taken_start)\n);\n\nCOMMENT ON TABLE public.plg_workforce_vacations IS\n 'Período aquisitivo e de gozo de férias (005). Nada é calculado, inclusive o terço constitucional — é digitado, como no V1.';\n\nCREATE INDEX IF NOT EXISTS plg_workforce_vacations_vencendo\n ON public.plg_workforce_vacations (tenant_id, accrual_end) WHERE status <> 'concluida';\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 4. FALTAS E AFASTAMENTOS (vista 10)\n-- ═══════════════════════════════════════════════════════════════════════════\n\nCREATE TABLE IF NOT EXISTS public.plg_workforce_absences (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n unit_id uuid,\n person_id uuid NOT NULL REFERENCES public.people(id) ON DELETE CASCADE,\n kind text NOT NULL CHECK (kind IN\n ('falta_justificada', 'falta_injustificada', 'atestado', 'licenca_maternidade',\n 'licenca_paternidade', 'licenca_nao_remunerada', 'suspensao', 'ferias', 'afastamento_inss')),\n starts_on date NOT NULL,\n -- Nulo = afastamento em aberto, que é um estado real (INSS sem alta marcada).\n ends_on date,\n days integer,\n paid boolean NOT NULL DEFAULT true,\n -- Dado médico. Mora aqui e não em \\`people\\` pelo mesmo motivo do salário: é a\n -- policy de \\`workforce_hr\\` que o protege, e V1-069 é exatamente sobre isto.\n icd_code text,\n doctor text,\n notes text,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n CONSTRAINT plg_workforce_absences_span CHECK (ends_on IS NULL OR ends_on >= starts_on)\n);\n\nCOMMENT ON TABLE public.plg_workforce_absences IS\n 'Falta e afastamento (005). Diferente do V1, CONVERSA com o ponto: v_workforce_day lê daqui, e um dia coberto por atestado deixa de aparecer como falta.';\nCOMMENT ON COLUMN public.plg_workforce_absences.icd_code IS\n 'CID do atestado. Dado de saúde: é a policy de workforce_hr que o separa de quem edita cadastro — o V1 não separava (V1-069).';\n\nCREATE INDEX IF NOT EXISTS plg_workforce_absences_periodo\n ON public.plg_workforce_absences (tenant_id, person_id, starts_on, ends_on);\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 5. PENDÊNCIAS (vista 16)\n-- ═══════════════════════════════════════════════════════════════════════════\n\nCREATE TABLE IF NOT EXISTS public.plg_workforce_pending_items (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,\n unit_id uuid,\n person_id uuid NOT NULL REFERENCES public.people(id) ON DELETE CASCADE,\n title text NOT NULL,\n category text CHECK (category IN ('documento', 'exame', 'epi', 'treinamento', 'assinatura', 'outro')),\n priority text NOT NULL DEFAULT 'normal' CHECK (priority IN ('baixa', 'normal', 'alta', 'urgente')),\n due_on date,\n resolved_at timestamptz,\n description text,\n metadata jsonb NOT NULL DEFAULT '{}'::jsonb,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now()\n);\n\nCOMMENT ON TABLE public.plg_workforce_pending_items IS\n 'O que falta na pasta de alguém: documento, exame, EPI, assinatura (005). É a lista que o painel cobra — \"Pendências críticas\" conta as não resolvidas de prioridade alta ou urgente.';\n\nCREATE INDEX IF NOT EXISTS plg_workforce_pending_abertas\n ON public.plg_workforce_pending_items (tenant_id, priority, due_on) WHERE resolved_at IS NULL;\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 6. ESCOPO, CARIMBO E PERMISSÃO\n-- ═══════════════════════════════════════════════════════════════════════════\n\nDO $$\nDECLARE r record;\nBEGIN\n FOR r IN SELECT * FROM (VALUES\n ('plg_workforce_employment', 'workforce_hr.employment'),\n ('plg_workforce_vacations', 'workforce_hr.vacation'),\n ('plg_workforce_absences', 'workforce_hr.absence'),\n ('plg_workforce_pending_items', 'workforce_hr.pending_item')\n ) AS t(tbl, resource)\n LOOP\n EXECUTE format('ALTER TABLE public.%I ENABLE ROW LEVEL SECURITY', r.tbl);\n EXECUTE format('ALTER TABLE public.%I FORCE ROW LEVEL SECURITY', r.tbl);\n EXECUTE format('DROP TRIGGER IF EXISTS %I ON public.%I', r.tbl || '_updated_at', r.tbl);\n EXECUTE format('CREATE TRIGGER %I BEFORE UPDATE ON public.%I FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at()',\n r.tbl || '_updated_at', r.tbl);\n -- \\`workforce_hr\\` e não \\`workforce\\`: é o nome do plugin que o scaffold usa\n -- para derivar \\`<plugin>.read/create/edit/delete\\`, então passar outro nome\n -- aqui É a separação de permissão. Quem tem workforce.read vê escala e\n -- ponto e não vê salário.\n PERFORM app.scaffold_table(format('public.%I', r.tbl)::regclass, r.resource, 'workforce_hr', false, 'enforce');\n END LOOP;\nEND $$;\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 7. O PONTO PASSA A SABER DO AFASTAMENTO\n-- ═══════════════════════════════════════════════════════════════════════════\n--\n-- O defeito que o FLOW da vista 10 registra: *\"Não conversa com o ponto\n-- eletrônico nem com a escala.\"* Duas telas sobre a mesma pessoa, no mesmo\n-- sistema, que não se olham — quem confere ponto vê FALTA em cima de um\n-- atestado que o RH lançou na semana passada, e precisa lembrar de cabeça.\n--\n-- A view não muda de forma: ganha uma coluna no fim. \\`absent\\` continua sendo\n-- escala sem ponto, porque é isso que ele é; o que muda é que agora dá para\n-- dizer POR QUE, quando alguém sabe.\n\nCREATE OR REPLACE VIEW public.v_workforce_day\nWITH (security_invoker = 'true') AS\nWITH bruto AS (\n SELECT e.tenant_id, e.unit_id, e.person_id, e.work_date,\n min(e.effective_at) FILTER (WHERE e.kind = 'clock_in') AS first_in,\n max(e.effective_at) FILTER (WHERE e.kind = 'clock_out') AS last_out,\n count(*) FILTER (WHERE e.kind = 'break_start') AS break_count,\n count(*) FILTER (WHERE e.kind IN ('clock_in', 'break_end')) AS aberturas,\n count(*) FILTER (WHERE e.kind IN ('clock_out', 'break_start')) AS fechamentos,\n max(e.effective_at) FILTER (WHERE e.kind IN ('clock_in', 'break_end')) AS ultima_abertura,\n sum(CASE\n WHEN e.kind IN ('clock_out', 'break_start') THEN extract(epoch FROM e.effective_at)\n WHEN e.kind IN ('clock_in', 'break_end') THEN -extract(epoch FROM e.effective_at)\n END) AS soma_com_sinal\n FROM public.v_workforce_time_entries e\n WHERE NOT e.voided\n GROUP BY e.tenant_id, e.unit_id, e.person_id, e.work_date\n),\nrealized AS (\n SELECT b.tenant_id, b.unit_id, b.person_id, b.work_date,\n b.first_in, b.last_out, b.break_count,\n (b.aberturas <> b.fechamentos) AS is_open,\n CASE WHEN b.aberturas <> b.fechamentos THEN b.ultima_abertura END AS open_since,\n -- Devolve à soma a abertura sem par (003).\n (b.soma_com_sinal\n + CASE WHEN b.aberturas <> b.fechamentos\n THEN extract(epoch FROM b.ultima_abertura)\n ELSE 0 END) AS worked_seconds\n FROM bruto b\n),\nplanned AS (\n SELECT a.tenant_id, a.unit_id, a.person_id,\n s.schedule_date AS work_date,\n a.id AS assignment_id, a.role, a.status AS assignment_status,\n a.shift_label, a.shift_start_time, a.shift_end_time,\n (extract(epoch FROM a.shift_end_time - a.shift_start_time)\n + CASE WHEN a.shift_end_time <= a.shift_start_time THEN 86400 ELSE 0 END) AS planned_seconds\n FROM public.plg_workforce_schedule_assignments a\n JOIN public.plg_workforce_schedules s ON s.id = a.schedule_id\n WHERE s.status IN ('published', 'closed')\n AND a.role = 'titular'\n AND a.shift_start_time IS NOT NULL\n AND a.shift_end_time IS NOT NULL\n)\nSELECT coalesce(p.tenant_id, r.tenant_id) AS tenant_id,\n coalesce(p.unit_id, r.unit_id) AS unit_id,\n coalesce(p.person_id, r.person_id) AS person_id,\n coalesce(p.work_date, r.work_date) AS work_date,\n p.assignment_id,\n p.shift_label,\n p.shift_start_time,\n p.shift_end_time,\n p.assignment_status,\n (p.planned_seconds / 60)::integer AS planned_minutes,\n (r.worked_seconds / 60)::integer AS worked_minutes,\n ((r.worked_seconds - p.planned_seconds) / 60)::integer AS variance_minutes,\n r.first_in,\n r.last_out,\n r.break_count,\n coalesce(r.is_open, false) AS is_open,\n (r.person_id IS NULL) AS absent,\n (p.assignment_id IS NULL) AS outside_schedule,\n r.open_since,\n CASE\n WHEN r.person_id IS NULL THEN NULL\n WHEN r.is_open THEN 'open'\n WHEN (r.worked_seconds / 60) > public.workforce_max_shift_minutes()\n THEN 'span_too_long'\n END AS review_reason,\n -- Coluna nova, no fim. \\`security_invoker\\` na view + a policy de\n -- \\`workforce_hr\\` na tabela: quem não tem a permissão simplesmente não\n -- enxerga o afastamento, e a coluna volta nula. A folha de ponto não\n -- vira a porta dos fundos do CID.\n (SELECT a.kind\n FROM public.plg_workforce_absences a\n WHERE a.tenant_id = coalesce(p.tenant_id, r.tenant_id)\n AND a.person_id = coalesce(p.person_id, r.person_id)\n AND coalesce(p.work_date, r.work_date) BETWEEN a.starts_on\n AND coalesce(a.ends_on, coalesce(p.work_date, r.work_date))\n ORDER BY a.starts_on DESC\n LIMIT 1) AS absence_kind\n FROM planned p\n FULL OUTER JOIN realized r\n ON r.tenant_id = p.tenant_id\n AND r.person_id = p.person_id\n AND r.work_date = p.work_date;\n\nCOMMENT ON COLUMN public.v_workforce_day.absence_kind IS\n 'O afastamento que cobre este dia, quando o RH lançou um (005). É o conserto do defeito que o V1 tem: lá a falta lançada no RH não aparece no ponto, e quem confere vê FALTA em cima de um atestado.';\n\nGRANT SELECT ON public.v_workforce_day TO authenticated, service_role;\n\n-- ═══════════════════════════════════════════════════════════════════════════\n-- 8. A VISÃO GERAL — os oito números\n-- ═══════════════════════════════════════════════════════════════════════════\n--\n-- Os mesmos oito cartões do V1, com três diferenças, e as três são conserto de\n-- defeito registrado no FLOW:\n--\n-- V1-072 \"Experiência vencendo\" só olhava PROFISSIONAIS, porque o V1 tem\n-- duas tabelas. O V2 tem uma pessoa, então olha todo mundo.\n-- V1-073 \"Férias a vencer\" mostrava a data e NÃO o nome. Aqui a view devolve\n-- person_id e nome, e a tela linka para a ficha.\n-- V1-074 aniversariante do dia 1º caía no mês anterior, por comparação de\n-- data em UTC. \\`extract(month …)\\` não tem esse problema.\n\nCREATE OR REPLACE VIEW public.v_workforce_hr_overview\nWITH (security_invoker = 'true') AS\nWITH base AS (\n SELECT e.tenant_id, e.person_id, e.admission_date, e.dismissal_date, e.probation_final_end,\n p.name, p.date_of_birth, p.is_active\n FROM public.plg_workforce_employment e\n JOIN public.people p ON p.id = e.person_id\n)\nSELECT b.tenant_id,\n count(*) FILTER (WHERE b.dismissal_date IS NULL AND coalesce(b.is_active, true)) AS headcount,\n count(*) FILTER (WHERE b.admission_date >= current_date - 30) AS admissions_30d,\n count(*) FILTER (WHERE b.dismissal_date >= current_date - 30) AS dismissals_30d,\n count(*) FILTER (WHERE b.probation_final_end BETWEEN current_date AND current_date + 60) AS probation_ending,\n count(*) FILTER (WHERE b.dismissal_date IS NULL\n AND extract(month FROM b.date_of_birth) = extract(month FROM current_date)) AS birthdays_this_month,\n (SELECT count(*) FROM public.plg_workforce_vacations v\n WHERE v.tenant_id = b.tenant_id AND v.status <> 'concluida'\n AND v.accrual_end BETWEEN current_date AND current_date + 60) AS vacations_due_60d,\n (SELECT count(*) FROM public.plg_workforce_pending_items i\n WHERE i.tenant_id = b.tenant_id AND i.resolved_at IS NULL\n AND i.priority IN ('alta', 'urgente')) AS critical_pending\n FROM base b\n GROUP BY b.tenant_id;\n\nCOMMENT ON VIEW public.v_workforce_hr_overview IS\n 'Os oito números do painel de RH do V1 (005). Turnover não está aqui de propósito: é demissões ÷ headcount, e uma divisão que a tela faz é uma divisão que a tela pode formatar — a view devolve as duas parcelas.';\n\n-- Quem vence, COM NOME — o V1-073 é justamente a lista sem nome.\nCREATE OR REPLACE VIEW public.v_workforce_hr_upcoming\nWITH (security_invoker = 'true') AS\nSELECT v.tenant_id, 'vacation'::text AS kind, v.person_id, p.name AS person_name,\n v.accrual_end AS due_on, v.status AS detail\n FROM public.plg_workforce_vacations v\n JOIN public.people p ON p.id = v.person_id\n WHERE v.status <> 'concluida' AND v.accrual_end BETWEEN current_date AND current_date + 60\nUNION ALL\nSELECT e.tenant_id, 'probation', e.person_id, p.name,\n e.probation_final_end, e.job_title\n FROM public.plg_workforce_employment e\n JOIN public.people p ON p.id = e.person_id\n WHERE e.probation_final_end BETWEEN current_date AND current_date + 60\nUNION ALL\nSELECT i.tenant_id, 'pending', i.person_id, p.name, i.due_on, i.title\n FROM public.plg_workforce_pending_items i\n JOIN public.people p ON p.id = i.person_id\n WHERE i.resolved_at IS NULL AND i.priority IN ('alta', 'urgente');\n\nCOMMENT ON VIEW public.v_workforce_hr_upcoming IS\n 'O que vence nos próximos 60 dias, com o NOME de quem (005). O V1 lista férias a vencer só com a data — V1-073 —, o que obriga a procurar a pessoa em outra tela.';\n\nGRANT SELECT ON public.v_workforce_hr_overview TO authenticated, service_role;\nGRANT SELECT ON public.v_workforce_hr_upcoming TO authenticated, service_role;\n`\n\nexport const MIGRATION_006_O_CUSTO_DE_PESSOAL_E_UM_RAMO_DO_PLANO = `-- O custo de pessoal é um RAMO DO PLANO, e quem o aponta é a casa.\n--\n-- ── O defeito, medido ───────────────────────────────────────────────────────\n--\n-- A tela \"Encargos e honorários\" (RH → Custos) lê o razão do Financeiro e soma\n-- toda linha de conta a pagar que tenha conta contábil. Toda. Medido no cluster\n-- de Pertinho do Céu em 19/09/2026, o que ela chamava de custo de pessoal\n-- incluía:\n--\n-- 6.2.1 Aluguel R$ 21.061,99\n-- 6.2.3 IPTU R$ 26.613,73\n-- 6.5.5 ICMS R$ 30.964,92\n-- 6.4.1 Equipamentos R$ 82.595,87\n-- 6.3.1 Energia/Light R$ 27.185,62\n--\n-- — ao lado das que são, de fato, pessoal:\n--\n-- 5 DESPESAS COM PESSOAL (26 contas: Salário, FGTS, INSS, Comissão,\n-- Hora Extra, Adiantamento, IRRF Folha, Vale Alimentação, FREELANCER\n-- com oito filhas…)\n--\n-- Um total que soma aluguel e ICMS sob o título \"custo de pessoal\" não está\n-- impreciso: está errado, e erra para cima, que é o lado que faz alguém decidir\n-- contratar menos.\n--\n-- ── Por que uma configuração, e não uma regra ───────────────────────────────\n--\n-- Não existe como o código saber qual ramo é pessoal. O plano de contas é uma\n-- DECLARAÇÃO da casa (ver \\`040_o_demonstrativo_mostra_o_plano_inteiro\\`), e cada\n-- casa numera o dela: aqui pessoal é o ramo \\`5\\`; o template que o SDK semeia\n-- para um tenant novo põe folha em \\`4.03\\`. Deduzir pelo NOME da conta seria\n-- adivinhar em português — e \\`8.2.4 Rescisão\\` e \\`8.2.6 Pro-labore\\`, que também\n-- são gente, moram fora do ramo 5 neste mesmo plano, por escolha de quem montou.\n--\n-- Então a chave guarda a escolha, e a ausência dela é uma ausência honesta: sem\n-- nada escolhido a tela mostra TODAS as despesas classificadas e diz que é o que\n-- está fazendo. Um padrão inventado ('5') faria a tela mentir com convicção no\n-- primeiro tenant cujo plano não usa esse número.\n--\n-- ── A forma ────────────────────────────────────────────────────────────────\n--\n-- Um array de CÓDIGOS, não de ids. O código é o que carrega a hierarquia: quem\n-- escolhe '5' escolhe o ramo inteiro — '5.4' e '5.4.1' entram com ele, e uma\n-- conta nova criada amanhã dentro do ramo entra sozinha. Com id seria preciso\n-- re-marcar a configuração a cada conta nova, e ninguém lembra.\n--\n-- \\`tenant_setting_set\\` cobra \\`settings.manage\\` e recusa chave não registrada —\n-- é por isso que este arquivo existe. Idempotente: \\`seed_setting_keys\\` faz\n-- upsert por chave.\n\nSELECT app.seed_setting_keys($$[\n {\n \"key\": \"workforce.payroll_account_codes\", \"type\": \"array\", \"default\": null,\n \"reader\": \"plugin:workforce\",\n \"description\": \"Os ramos do plano de contas que são custo de pessoal, por código ('5', '8.2.4'). Um código traz toda a descendência dele. Vazio ou nulo = a tela mostra todas as despesas classificadas e avisa que não há ramo escolhido.\"\n }\n]$$::jsonb);\n`\n\nexport const MIGRATION_007_A_PORTA_DE_SERVICO_DO_PONTO_FECHA_TAMBEM = `-- ---------------------------------------------------------------------------\n-- 007_a_porta_de_servico_do_ponto_fecha_tambem.sql\n--\n-- ── o buraco, e por que ele estava invisível ────────────────────────────\n--\n-- As funções que este plugin cria em \\`migration\\` nasceram executáveis por\n-- PUBLIC — é o padrão do Postgres, e ninguém revogou. Elas são\n-- \\`SECURITY DEFINER\\` e escrevem dados de QUALQUER inquilino: uma delas\n-- alcançável pela chave anônima é a base inteira alcançável pela chave\n-- anônima.\n--\n-- Isto não aparecia porque a \\`000_baseline\\` falhava e levava junto os outros\n-- seis arquivos deste plugin — as funções nunca chegavam a existir na bancada.\n-- Com a baseline consertada (#443) o passo inteiro passou a aplicar, e as duas\n-- suítes que guardam esta fronteira ficaram vermelhas na hora:\n--\n-- 090_migration_ledger/001 \"no migration function is executable by anon\n-- or authenticated\" — have 9, want 0\n-- crm/009 \"nenhuma função do schema migration é chamável\n-- por anon\" — have 9, want 0\n--\n-- Ou seja: a regra sempre esteve escrita e medida; o que faltava era o plugin\n-- chegar ao banco para ser medido. É o argumento do #338 de novo — um plugin\n-- fora da corrente é um plugin cujas tabelas (e cujas portas) são coincidência.\n--\n-- ── por extenso, e não varrendo o catálogo ──────────────────────────────\n--\n-- A tentação é \\`REVOKE\\` num laço sobre \\`pg_proc\\`. Já foi tentado neste repo e\n-- derrubou 35 suítes: varrer revoga de funções que outros passos criaram e\n-- precisam de execução. Revogar em massa é fácil de escrever e impossível de\n-- revisar. A lista abaixo é a das funções DESTE plugin, nomeada uma a uma.\n-- ---------------------------------------------------------------------------\n\nDO $$\nDECLARE\n v_fn text;\n v_args text;\n v_n integer := 0;\nBEGIN\n -- Cada writer do de-para, com a assinatura que a corrente lhe deu. Nomear em\n -- vez de varrer é o que torna esta lista revisável.\n FOR v_fn, v_args IN\n SELECT p.proname, pg_get_function_identity_arguments(p.oid)\n FROM pg_proc p\n JOIN pg_namespace n ON n.oid = p.pronamespace\n WHERE n.nspname = 'migration'\n AND (p.proname LIKE 'upsert_wf\\\\_%' OR p.proname IN ('_wf_person', '_point_punch_photo'))\n LOOP\n EXECUTE format('REVOKE ALL ON FUNCTION migration.%I(%s) FROM PUBLIC, anon, authenticated', v_fn, v_args);\n -- \\`service_role\\` fica: é quem a importação usa, e é a única identidade que\n -- tem razão para atravessar inquilinos.\n EXECUTE format('GRANT EXECUTE ON FUNCTION migration.%I(%s) TO service_role', v_fn, v_args);\n v_n := v_n + 1;\n END LOOP;\n\n RAISE NOTICE 'workforce/007: % função(ões) de migration fechadas a anon e authenticated', v_n;\nEND $$;\n`\n\nexport const MIGRATIONS: Array<{ id: string; sql: string }> = [\n { id: \"000_baseline\", sql: MIGRATION_000_BASELINE },\n { id: \"001_a_prova_da_batida_tem_bytes\", sql: MIGRATION_001_A_PROVA_DA_BATIDA_TEM_BYTES },\n { id: \"002_o_guarda_da_foto_olhava_o_nome_errado\", sql: MIGRATION_002_O_GUARDA_DA_FOTO_OLHAVA_O_NOME_ERRADO },\n { id: \"003_o_ponto_em_aberto_para_de_mentir_a_duracao\", sql: MIGRATION_003_O_PONTO_EM_ABERTO_PARA_DE_MENTIR_A_DURACAO },\n { id: \"004_a_jornada_implausivel_nao_soma\", sql: MIGRATION_004_A_JORNADA_IMPLAUSIVEL_NAO_SOMA },\n { id: \"005_a_ficha_trabalhista_tem_onde_morar\", sql: MIGRATION_005_A_FICHA_TRABALHISTA_TEM_ONDE_MORAR },\n { id: \"006_o_custo_de_pessoal_e_um_ramo_do_plano\", sql: MIGRATION_006_O_CUSTO_DE_PESSOAL_E_UM_RAMO_DO_PLANO },\n { id: \"007_a_porta_de_servico_do_ponto_fecha_tambem\", sql: MIGRATION_007_A_PORTA_DE_SERVICO_DO_PONTO_FECHA_TAMBEM },\n]\n","import React from 'react'\nimport type { EntityDef, PluginManifest, PluginScope, VerticalId } from '@fayz-ai/core'\nimport { createSafeDataProvider } from '@fayz-ai/core'\nimport type { EntityLookup } from '@fayz-ai/admin'\nimport { registerEntityPath } from '@fayz-ai/admin'\nimport { WorkforcePage } from './views/WorkforcePage'\nimport type { ResolvedWorkforceConfig } from './context'\nimport type { WorkforceDataProvider } from './data/types'\nimport { createMockWorkforceProvider } from './data/mock'\nimport { createSupabaseWorkforceProvider } from './data/supabase'\nimport { createWorkforceStore } from './store'\nimport { MIGRATIONS } from './migrations'\n\n/**\n * O provider da jornada, resolvido tarde: Supabase quando há cliente, memória\n * quando não há. Público porque um app que queira compartilhar UM provider\n * entre o módulo e uma ponte (o totem de ponto, por exemplo) precisa do mesmo.\n */\nexport function createSafeWorkforceProvider(): WorkforceDataProvider {\n return createSafeDataProvider(\n () => createSupabaseWorkforceProvider(),\n () => createMockWorkforceProvider(),\n )\n}\n\n// ---------------------------------------------------------------------------\n// Tipos públicos\n// ---------------------------------------------------------------------------\n\nexport interface WorkforcePluginLabels {\n pageTitle: string\n pageSubtitle: string\n schedules: string\n templates: string\n timeEntries: string\n hr: string\n periods: string\n people: string\n payrollCosts: string\n}\n\nexport interface WorkforcePluginOptions {\n /** Onde a sub-navegação do módulo mora. Padrão: o que a shell decidir. */\n moduleNav?: 'rail' | 'tabs' | 'sidebar'\n modules?: {\n schedules?: boolean\n templates?: boolean\n timeEntries?: boolean\n hr?: boolean\n periods?: boolean\n people?: boolean\n payrollCosts?: boolean\n }\n labels?: Partial<WorkforcePluginLabels>\n currency?: { code?: string; locale?: string; symbol?: string }\n navPosition?: number\n navSection?: 'main' | 'secondary'\n scope?: PluginScope\n verticalId?: VerticalId\n\n /** Provider de dados. Padrão: Supabase-ou-memória. */\n dataProvider?: WorkforceDataProvider\n\n /**\n * Quanto vale a hora, para a folha mostrar valor.\n *\n * NÃO existe coluna de remuneração no SQL da jornada — nem na batida, nem no\n * turno, nem em `public.people`. Sem esta opção a tela mostra \"—\" em vez de\n * inventar um número, e o relatório do módulo diz isso.\n */\n hourlyRate?: number\n\n /** A entidade de pessoa que a aba \"Pessoas & Documentos\" edita. Padrão: o\n * recorte de `people` com papel de equipe (ver views/PeopleView). */\n staffEntity?: EntityDef\n\n /** Busca de pessoa, quando o app quiser oferecer uma para escalar. */\n staffLookup?: EntityLookup\n\n /**\n * Onde mora a página de UMA pessoa da equipe neste app — `'/staff'`.\n *\n * O nome na lista de Registros de Ponto é um `PersonLink`, e ele resolve a\n * rota pelo registro compartilhado de caminhos. O padrão daquele registro é\n * `/registry/staff`, que é herança do app veterinário: num app que monta a\n * equipe em `/staff` o nome viraria um link para uma rota inexistente — pior\n * que texto puro, porque parece clicável e não é.\n *\n * O plugin não adivinha: quem sabe onde a página está é o app que a montou.\n * Sem esta opção o registro fica como está, e o link cai onde o padrão\n * aponta.\n */\n staffRoute?: string\n\n /**\n * Qual link interno ESTE app cobra, como `id do item de nav → id da feature`.\n * Vazio por padrão: empacotamento é decisão do app, não do plugin.\n */\n navFeatureMap?: Record<string, string>\n}\n\n// ---------------------------------------------------------------------------\n// Padrões\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_LABELS: WorkforcePluginLabels = {\n pageTitle: 'RH',\n pageSubtitle: 'Escala, ponto e fechamento da equipe',\n schedules: 'Escalas',\n templates: 'Templates',\n timeEntries: 'Registros de Ponto',\n hr: 'Ficha de RH',\n periods: 'Fechamento',\n people: 'Pessoas & Documentos',\n payrollCosts: 'Encargos e Honorários',\n}\n\nconst DEFAULT_CURRENCY = { code: 'BRL', locale: 'pt-BR', symbol: 'R$' }\n\n/**\n * Preset OPCIONAL de ids de feature para as subtelas — uma convenção oferecida\n * aos apps, NÃO um padrão. Nada aqui vale sem `options.navFeatureMap`.\n */\nexport const WORKFORCE_NAV_FEATURES = {\n schedules: 'wf_schedules',\n templates: 'wf_templates',\n 'time-entries': 'wf_time_entries',\n hr: 'wf_hr',\n periods: 'wf_periods',\n people: 'wf_people',\n 'payroll-costs': 'wf_payroll_costs',\n} as const satisfies Record<string, string>\n\nfunction resolveConfig(options?: WorkforcePluginOptions): ResolvedWorkforceConfig {\n return {\n modules: {\n schedules: options?.modules?.schedules !== false,\n templates: options?.modules?.templates !== false,\n timeEntries: options?.modules?.timeEntries !== false,\n hr: options?.modules?.hr !== false,\n periods: options?.modules?.periods !== false,\n people: options?.modules?.people !== false,\n // Ligada como as outras: quando o Financeiro não está instalado a própria\n // tela diz isso, então o item de menu nunca leva a um beco.\n payrollCosts: options?.modules?.payrollCosts !== false,\n },\n labels: { ...DEFAULT_LABELS, ...options?.labels },\n currency: { ...DEFAULT_CURRENCY, ...options?.currency },\n moduleNav: options?.moduleNav,\n hourlyRate: options?.hourlyRate,\n staffLookup: options?.staffLookup,\n navFeatureMap: { ...options?.navFeatureMap },\n }\n}\n\n// ---------------------------------------------------------------------------\n// Fábrica\n// ---------------------------------------------------------------------------\n\nexport function createWorkforcePlugin(options?: WorkforcePluginOptions): PluginManifest {\n const config = resolveConfig(options)\n\n // Onde uma pessoa da equipe mora NESTE app, dito ao registro que o PersonLink\n // consulta. Ver `staffRoute` — o padrão do registro é veterinário.\n if (options?.staffRoute) registerEntityPath('staff', options.staffRoute)\n\n const provider = options?.dataProvider ?? createSafeWorkforceProvider()\n const store = createWorkforceStore(provider)\n\n const PageComponent: React.FC<unknown> = () =>\n React.createElement(WorkforcePage, {\n config,\n provider,\n store,\n staffEntity: options?.staffEntity,\n })\n\n return {\n id: 'workforce',\n name: config.labels.pageTitle,\n icon: 'UsersRound',\n version: '1.0.0',\n scope: options?.scope ?? 'universal',\n verticalId: options?.verticalId,\n defaultEnabled: true,\n dependencies: [],\n\n // O plugin é DONO de todo o seu SQL e diz isso: o que instalá-lo provisiona\n // é esta lista, byte a byte o que está em src/migrations (barrel gerado por\n // scripts/embed-migrations.mjs). SQL solto é a violação de contrato que a\n // regra existe para impedir.\n migrations: MIGRATIONS.map((m) => ({\n id: `workforce-${m.id}`,\n version: '1.0.0',\n sql: m.sql,\n description: m.id,\n })),\n\n declaredFeatures: [\n { id: 'workforce', label: config.labels.pageTitle, group: config.labels.pageTitle },\n ],\n\n queryEntities: [\n {\n key: 'workforce:days',\n entity: {\n name: 'Work day',\n namePlural: 'Jornadas (previsto × realizado)',\n icon: 'Clock',\n permission: { feature: 'workforce', action: 'read' },\n fields: [\n { key: 'work_date', label: 'Dia', type: 'text' },\n { key: 'shift_label', label: 'Turno', type: 'text' },\n { key: 'planned_minutes', label: 'Previsto (min)', type: 'number' },\n { key: 'worked_minutes', label: 'Realizado (min)', type: 'number' },\n { key: 'variance_minutes', label: 'Diferença (min)', type: 'number' },\n { key: 'absent', label: 'Falta', type: 'boolean' },\n { key: 'outside_schedule', label: 'Fora da escala', type: 'boolean' },\n { key: 'is_open', label: 'Em aberto', type: 'boolean' },\n ],\n data: { table: 'v_workforce_day', tenantScoped: true },\n },\n },\n {\n key: 'workforce:time-entries',\n entity: {\n name: 'Time entry',\n namePlural: 'Batidas de ponto (com a hora que vale)',\n icon: 'Clock3',\n permission: { feature: 'workforce', action: 'read' },\n fields: [\n { key: 'person_name', label: 'Pessoa', type: 'text', searchable: true },\n { key: 'kind', label: 'Evento', type: 'text' },\n { key: 'work_date', label: 'Dia da jornada', type: 'text' },\n { key: 'punched_at', label: 'Horário real', type: 'text' },\n { key: 'effective_at', label: 'Horário que vale', type: 'text' },\n { key: 'adjusted', label: 'Ajustada', type: 'boolean' },\n { key: 'voided', label: 'Anulada', type: 'boolean' },\n ],\n data: {\n table: 'v_workforce_time_entries',\n tenantScoped: true,\n searchColumns: ['person_name'],\n },\n },\n },\n ],\n\n declaredRpcs: [\n {\n name: 'workforce_period_close',\n kind: 'write' as const,\n description: 'Fecha a competência mensal da jornada. A partir daí nenhuma batida nem ajuste entra com data naquele mês.',\n audits: true,\n },\n {\n name: 'workforce_period_reopen',\n kind: 'write' as const,\n description: 'Reabre a competência mensal da jornada. Exige motivo, que fica registrado.',\n audits: true,\n },\n ],\n\n navigation: [\n {\n section: options?.navSection ?? 'main',\n position: options?.navPosition ?? 35,\n label: config.labels.pageTitle,\n route: '/workforce',\n icon: 'UsersRound',\n permission: { feature: 'workforce', action: 'read' as const },\n },\n ],\n\n routes: [\n {\n path: '/workforce',\n component: PageComponent as React.ComponentType<unknown>,\n permission: { feature: 'workforce', action: 'read' as const },\n },\n ],\n }\n}\n\n// ---------------------------------------------------------------------------\n// Reexportações\n// ---------------------------------------------------------------------------\n\nexport type { WorkforceDataProvider } from './data/types'\nexport type { ResolvedWorkforceConfig } from './context'\nexport type {\n TimeEntry, TimeEntryKind, TimeEntryQuery, TimeAdjustmentAction, TimeAdjustmentInput,\n WorkDay, WorkforcePeriod,\n ScheduleTemplate, ScheduleShift, ScheduleRequirement,\n DaySchedule, ScheduleAssignment, ScheduleQuery, CreateScheduleInput,\n WorkforcePerson, PayrollCostRow, PayrollCostQuery,\n} from './types'\nexport { createMockWorkforceProvider } from './data/mock'\nexport { createSupabaseWorkforceProvider, WORK_SHIFT_KIND } from './data/supabase'\nexport { DEFAULT_STAFF_ENTITY } from './views/PeopleView'\n"]}
|