@gusto/embedded-react-sdk 0.56.7 → 0.57.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/CHANGELOG.md +37 -0
- package/README.md +1 -1
- package/dist/components/Company/AssignSignatory/CreateSignatory/useCreateSignatory.js +5 -4
- package/dist/components/Company/AssignSignatory/CreateSignatory/useCreateSignatory.js.map +1 -1
- package/dist/components/Company/AssignSignatory/InviteSignatory/useInviteSignatory.js +5 -4
- package/dist/components/Company/AssignSignatory/InviteSignatory/useInviteSignatory.js.map +1 -1
- package/dist/components/Company/AssignSignatory/useAssignSignatory.js +7 -6
- package/dist/components/Company/AssignSignatory/useAssignSignatory.js.map +1 -1
- package/dist/components/Company/BankAccount/BankAccountForm/context.js +5 -4
- package/dist/components/Company/BankAccount/BankAccountForm/context.js.map +1 -1
- package/dist/components/Company/DocumentSigner/DocumentList/useDocumentList.js +5 -4
- package/dist/components/Company/DocumentSigner/DocumentList/useDocumentList.js.map +1 -1
- package/dist/components/Company/FederalTaxes/useFederalTaxes.js +10 -9
- package/dist/components/Company/FederalTaxes/useFederalTaxes.js.map +1 -1
- package/dist/components/Company/Industry/Context.js +8 -7
- package/dist/components/Company/Industry/Context.js.map +1 -1
- package/dist/components/Company/Locations/LocationForm/useLocationForm.js +5 -4
- package/dist/components/Company/Locations/LocationForm/useLocationForm.js.map +1 -1
- package/dist/components/Company/Locations/LocationsList/useLocationsList.js +5 -4
- package/dist/components/Company/Locations/LocationsList/useLocationsList.js.map +1 -1
- package/dist/components/Company/OnboardingOverview/context.js +5 -4
- package/dist/components/Company/OnboardingOverview/context.js.map +1 -1
- package/dist/components/Company/PaySchedule/management/PayScheduleAssignment/AssignmentCompensationStepPresentation.js +70 -0
- package/dist/components/Company/PaySchedule/management/PayScheduleAssignment/AssignmentCompensationStepPresentation.js.map +1 -0
- package/dist/components/Company/PaySchedule/management/PayScheduleAssignment/AssignmentScheduleStepPresentation.js +30 -32
- package/dist/components/Company/PaySchedule/management/PayScheduleAssignment/AssignmentScheduleStepPresentation.js.map +1 -1
- package/dist/components/Company/PaySchedule/management/PayScheduleAssignment/AssignmentTypeStepPresentation.js +35 -27
- package/dist/components/Company/PaySchedule/management/PayScheduleAssignment/AssignmentTypeStepPresentation.js.map +1 -1
- package/dist/components/Company/PaySchedule/management/PayScheduleAssignment/PayScheduleAssignment.js +52 -31
- package/dist/components/Company/PaySchedule/management/PayScheduleAssignment/PayScheduleAssignment.js.map +1 -1
- package/dist/components/Company/PaySchedule/management/PayScheduleAssignment/PayScheduleAssignmentComponents.js +106 -66
- package/dist/components/Company/PaySchedule/management/PayScheduleAssignment/PayScheduleAssignmentComponents.js.map +1 -1
- package/dist/components/Company/PaySchedule/management/PayScheduleAssignment/payScheduleAssignmentStateMachine.js +36 -30
- package/dist/components/Company/PaySchedule/management/PayScheduleAssignment/payScheduleAssignmentStateMachine.js.map +1 -1
- package/dist/components/Company/PaySchedule/management/PayScheduleAssignment/scheduleLabel.js +7 -0
- package/dist/components/Company/PaySchedule/management/PayScheduleAssignment/scheduleLabel.js.map +1 -0
- package/dist/components/Company/PaySchedule/management/PayScheduleCompensationOverviewPresentation.js +81 -0
- package/dist/components/Company/PaySchedule/management/PayScheduleCompensationOverviewPresentation.js.map +1 -0
- package/dist/components/Company/PaySchedule/management/PayScheduleOverview.js +46 -18
- package/dist/components/Company/PaySchedule/management/PayScheduleOverview.js.map +1 -1
- package/dist/components/Company/StateTaxes/StateTaxesForm/context.js +5 -4
- package/dist/components/Company/StateTaxes/StateTaxesForm/context.js.map +1 -1
- package/dist/components/Company/StateTaxes/StateTaxesList/context.js +5 -4
- package/dist/components/Company/StateTaxes/StateTaxesList/context.js.map +1 -1
- package/dist/components/Company/StateTaxes/TaxRateManagement/context.js +5 -4
- package/dist/components/Company/StateTaxes/TaxRateManagement/context.js.map +1 -1
- package/dist/components/Employee/Documents/onboarding/DocumentSigner/DocumentList/useDocumentList.js +5 -4
- package/dist/components/Employee/Documents/onboarding/DocumentSigner/DocumentList/useDocumentList.js.map +1 -1
- package/dist/components/Employee/Profile/shared/useEmployeeDetailsForm/employeeDetailsSchema.js +13 -13
- package/dist/components/Employee/Profile/shared/useEmployeeDetailsForm/employeeDetailsSchema.js.map +1 -1
- package/dist/components/Payroll/GrossUpModal/GrossUpModal.js +2 -3
- package/dist/components/Payroll/GrossUpModal/GrossUpModal.js.map +1 -1
- package/dist/components/Payroll/PayrollEditEmployee/shared/usePayrollEditEmployeeForm/payrollEditEmployeeHelpers.js +113 -111
- package/dist/components/Payroll/PayrollEditEmployee/shared/usePayrollEditEmployeeForm/payrollEditEmployeeHelpers.js.map +1 -1
- package/dist/components/Payroll/PayrollHistory/PayrollHistory.js +27 -31
- package/dist/components/Payroll/PayrollHistory/PayrollHistory.js.map +1 -1
- package/dist/components/Payroll/PayrollList/PayrollList.js +31 -35
- package/dist/components/Payroll/PayrollList/PayrollList.js.map +1 -1
- package/dist/components/Payroll/TransitionPayroll/useResolveTransitionPayroll.js +5 -9
- package/dist/components/Payroll/TransitionPayroll/useResolveTransitionPayroll.js.map +1 -1
- package/dist/components/Payroll/usePreparedPayrollData.js +4 -3
- package/dist/components/Payroll/usePreparedPayrollData.js.map +1 -1
- package/dist/contexts/ApiProvider/createSdkQueryClient.js +4 -3
- package/dist/contexts/ApiProvider/createSdkQueryClient.js.map +1 -1
- package/dist/contexts/ObservabilityProvider/sanitization.js +98 -47
- package/dist/contexts/ObservabilityProvider/sanitization.js.map +1 -1
- package/dist/helpers/validations.js +1 -1
- package/dist/helpers/validations.js.map +1 -1
- package/dist/i18n/en/Company.AssignSignatory.json.js +1 -1
- package/dist/i18n/en/Company.Management.PaySchedule.json.js +24 -14
- package/dist/i18n/en/Company.Management.PaySchedule.json.js.map +1 -1
- package/dist/i18n/en/Company.Management.PayScheduleAssignment.json.js +12 -10
- package/dist/i18n/en/Company.Management.PayScheduleAssignment.json.js.map +1 -1
- package/dist/package.json.js +1 -1
- package/dist/src/components/Company/PaySchedule/management/PayScheduleAssignment/AssignmentCompensationStepPresentation.d.ts +15 -0
- package/dist/src/components/Company/PaySchedule/management/PayScheduleAssignment/AssignmentTypeStepPresentation.d.ts +3 -3
- package/dist/src/components/Company/PaySchedule/management/PayScheduleAssignment/PayScheduleAssignment.d.ts +7 -3
- package/dist/src/components/Company/PaySchedule/management/PayScheduleAssignment/PayScheduleAssignmentComponents.d.ts +20 -4
- package/dist/src/components/Company/PaySchedule/management/PayScheduleAssignment/scheduleLabel.d.ts +3 -0
- package/dist/src/components/Company/PaySchedule/management/PayScheduleAssignment/usePayScheduleAssignment.d.ts +10 -1
- package/dist/src/components/Company/PaySchedule/management/PayScheduleCompensationOverviewPresentation.d.ts +25 -0
- package/dist/src/components/Employee/Profile/shared/useEmployeeDetailsForm/employeeDetailsSchema.test.d.ts +1 -0
- package/dist/src/contexts/ApiProvider/createSdkQueryClient.d.ts +2 -0
- package/dist/src/contexts/ApiProvider/createSdkQueryClient.test.d.ts +1 -0
- package/dist/src/contexts/ObservabilityProvider/sanitization.d.ts +8 -17
- package/dist/src/contexts/ObservabilityProvider/useSanitizedObservability.test.d.ts +1 -0
- package/dist/src/helpers/validations.test.d.ts +1 -0
- package/dist/src/i18n/types.d.ts +38 -2
- package/dist/src/models/external.d.ts +7 -6
- package/dist/src/types/observability.d.ts +59 -20
- package/docs/guides/endpoint-inventory.json +15 -0
- package/package.json +12 -12
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GrossUpModal.js","sources":["../../../../src/components/Payroll/GrossUpModal/GrossUpModal.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react'\nimport { FormProvider, useForm } from 'react-hook-form'\nimport { useTranslation } from 'react-i18next'\nimport { z } from 'zod'\nimport { zodResolver } from '@hookform/resolvers/zod'\nimport type { GrossUpModalProps } from './GrossUpModalTypes'\nimport styles from './GrossUpModal.module.scss'\nimport { ActionsLayout, Flex, NumberInputField } from '@/components/Common'\nimport { useBase } from '@/components/Base'\nimport { useComponentContext } from '@/contexts/ComponentAdapter/useComponentContext'\nimport { useI18n } from '@/i18n'\nimport { formatNumberAsCurrency } from '@/helpers/formattedStrings'\n\nconst GrossUpFormSchema = z.object({\n netPay: z.number().positive(),\n})\n\ntype GrossUpFormValues = z.infer<typeof GrossUpFormSchema>\n\n/** @internal */\nexport function GrossUpModal({ isOpen, onCalculateGrossUp, onApply, onCancel }: GrossUpModalProps) {\n useI18n('Payroll.GrossUpModal')\n const { t } = useTranslation('Payroll.GrossUpModal')\n const { Modal, Heading, Text, Button, Alert } = useComponentContext()\n const { baseSubmitHandler } = useBase()\n const modalContainerRef = useRef<HTMLDivElement>(null)\n\n const [calculatedGrossUp, setCalculatedGrossUp] = useState<string | null>(null)\n const [errorMessage, setErrorMessage] = useState<string | null>(null)\n const [isCalculating, setIsCalculating] = useState(false)\n const [isApplying, setIsApplying] = useState(false)\n\n const formHandlers = useForm<GrossUpFormValues>({\n resolver: zodResolver(GrossUpFormSchema),\n // Start blank rather than 0: 0 is not a valid net amount, and a leading 0\n // in the field means typing an amount produces values like \"0350\".\n defaultValues: {},\n })\n\n useEffect(() => {\n if (!isOpen) {\n formHandlers.reset()\n setCalculatedGrossUp(null)\n setErrorMessage(null)\n }\n }, [isOpen, formHandlers.reset])\n\n const handleCalculate = async (data: GrossUpFormValues) => {\n setErrorMessage(null)\n setCalculatedGrossUp(null)\n setIsCalculating(true)\n\n await baseSubmitHandler(null, async () => {\n try {\n const result = await onCalculateGrossUp(data.netPay)\n\n if (result) {\n setCalculatedGrossUp(result)\n } else {\n setErrorMessage(t('errorMessage'))\n }\n } finally {\n setIsCalculating(false)\n }\n })\n }\n\n const handleApply = async () => {\n if (calculatedGrossUp) {\n setIsApplying(true)\n await baseSubmitHandler(null, async () => {\n try {\n await onApply(calculatedGrossUp)\n } finally {\n setIsApplying(false)\n }\n })\n }\n }\n\n return (\n <Modal\n isOpen={isOpen}\n onClose={onCancel}\n containerRef={modalContainerRef}\n footer={\n <ActionsLayout>\n <Button\n variant=\"primary\"\n isDisabled={!calculatedGrossUp}\n onClick={handleApply}\n isLoading={isApplying}\n >\n {t('applyCta')}\n </Button>\n <Button variant=\"secondary\" onClick={onCancel}>\n {t('cancelCta')}\n </Button>\n </ActionsLayout>\n }\n >\n <FormProvider {...formHandlers}>\n <div className={styles.header}>\n <Heading as=\"h2\" styledAs=\"h3\">\n {t('title')}\n </Heading>\n <Text variant=\"supporting\" as=\"p\">\n {t('description')}\n </Text>\n </div>\n\n <div className={styles.content}>\n {errorMessage && (\n <div className={styles.alert}>\n <Alert label={errorMessage} status=\"error\" disableScrollIntoView />\n </div>\n )}\n\n <div className={styles.alert}>\n <Alert label={t('warning')} status=\"warning\" disableScrollIntoView />\n </div>\n\n {/* Bottom-align on the row itself: the .calculateButton align-self\n rule below only targets the default (react-aria) adapter, so in\n other adapters the button otherwise falls back to flex-start. */}\n <Flex flexDirection=\"row\" gap={8} alignItems=\"flex-end\">\n <NumberInputField\n name=\"netPay\"\n label={t('netPayLabel')}\n format=\"currency\"\n adornmentStart=\"$\"\n errorMessage={t('validations.netPay')}\n min={0}\n isRequired\n />\n <Button\n variant=\"secondary\"\n className={styles.calculateButton}\n isLoading={isCalculating}\n onClick={formHandlers.handleSubmit(handleCalculate)}\n >\n {t('calculateCta')}\n </Button>\n </Flex>\n\n {calculatedGrossUp ? (\n <div className={styles.result}>\n <Text size=\"sm\" variant=\"supporting\" weight=\"semibold\">\n {t('grossPayResult')}\n </Text>\n <Heading as=\"h3\">{formatNumberAsCurrency(parseFloat(calculatedGrossUp))}</Heading>\n </div>\n ) : (\n <Text size=\"sm\" variant=\"supporting\">\n {t('applyHint')}\n </Text>\n )}\n </div>\n </FormProvider>\n </Modal>\n )\n}\n"],"names":["GrossUpFormSchema","z","GrossUpModal","isOpen","onCalculateGrossUp","onApply","onCancel","useI18n","t","useTranslation","Modal","Heading","Text","Button","Alert","useComponentContext","baseSubmitHandler","useBase","modalContainerRef","useRef","calculatedGrossUp","setCalculatedGrossUp","useState","errorMessage","setErrorMessage","isCalculating","setIsCalculating","isApplying","setIsApplying","formHandlers","useForm","zodResolver","useEffect","handleCalculate","data","result","jsx","ActionsLayout","jsxs","FormProvider","styles","Flex","NumberInputField"],"mappings":"
|
|
1
|
+
{"version":3,"file":"GrossUpModal.js","sources":["../../../../src/components/Payroll/GrossUpModal/GrossUpModal.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react'\nimport { FormProvider, useForm } from 'react-hook-form'\nimport { useTranslation } from 'react-i18next'\nimport { z } from 'zod'\nimport { zodResolver } from '@hookform/resolvers/zod'\nimport type { GrossUpModalProps } from './GrossUpModalTypes'\nimport styles from './GrossUpModal.module.scss'\nimport { ActionsLayout, Flex, NumberInputField } from '@/components/Common'\nimport { useBase } from '@/components/Base'\nimport { useComponentContext } from '@/contexts/ComponentAdapter/useComponentContext'\nimport { useI18n } from '@/i18n'\nimport { formatNumberAsCurrency } from '@/helpers/formattedStrings'\n\nconst GrossUpFormSchema = z.object({\n netPay: z.number().positive(),\n})\n\ntype GrossUpFormValues = z.infer<typeof GrossUpFormSchema>\n\n/** @internal */\nexport function GrossUpModal({ isOpen, onCalculateGrossUp, onApply, onCancel }: GrossUpModalProps) {\n useI18n('Payroll.GrossUpModal')\n const { t } = useTranslation('Payroll.GrossUpModal')\n const { Modal, Heading, Text, Button, Alert } = useComponentContext()\n const { baseSubmitHandler } = useBase()\n const modalContainerRef = useRef<HTMLDivElement>(null)\n\n const [calculatedGrossUp, setCalculatedGrossUp] = useState<string | null>(null)\n const [errorMessage, setErrorMessage] = useState<string | null>(null)\n const [isCalculating, setIsCalculating] = useState(false)\n const [isApplying, setIsApplying] = useState(false)\n\n const formHandlers = useForm<GrossUpFormValues>({\n resolver: zodResolver(GrossUpFormSchema),\n // Start blank rather than 0: 0 is not a valid net amount, and a leading 0\n // in the field means typing an amount produces values like \"0350\".\n defaultValues: {},\n })\n\n useEffect(() => {\n if (!isOpen) {\n formHandlers.reset()\n setCalculatedGrossUp(null)\n setErrorMessage(null)\n }\n }, [isOpen, formHandlers.reset])\n\n const handleCalculate = async (data: GrossUpFormValues) => {\n setErrorMessage(null)\n setCalculatedGrossUp(null)\n setIsCalculating(true)\n\n await baseSubmitHandler(null, async () => {\n try {\n const result = await onCalculateGrossUp(data.netPay)\n\n if (result) {\n setCalculatedGrossUp(result)\n } else {\n setErrorMessage(t('errorMessage'))\n }\n } finally {\n setIsCalculating(false)\n }\n })\n }\n\n const handleApply = async () => {\n if (calculatedGrossUp) {\n setIsApplying(true)\n await baseSubmitHandler(null, async () => {\n try {\n await onApply(calculatedGrossUp)\n } finally {\n setIsApplying(false)\n }\n })\n }\n }\n\n return (\n <Modal\n isOpen={isOpen}\n onClose={onCancel}\n containerRef={modalContainerRef}\n footer={\n <ActionsLayout>\n <Button\n variant=\"primary\"\n isDisabled={!calculatedGrossUp}\n onClick={handleApply}\n isLoading={isApplying}\n >\n {t('applyCta')}\n </Button>\n <Button variant=\"secondary\" onClick={onCancel}>\n {t('cancelCta')}\n </Button>\n </ActionsLayout>\n }\n >\n <FormProvider {...formHandlers}>\n <div className={styles.header}>\n <Heading as=\"h2\" styledAs=\"h3\">\n {t('title')}\n </Heading>\n <Text variant=\"supporting\" as=\"p\">\n {t('description')}\n </Text>\n </div>\n\n <div className={styles.content}>\n {errorMessage && (\n <div className={styles.alert}>\n <Alert label={errorMessage} status=\"error\" disableScrollIntoView />\n </div>\n )}\n\n <div className={styles.alert}>\n <Alert label={t('warning')} status=\"warning\" disableScrollIntoView />\n </div>\n\n {/* Bottom-align on the row itself: the .calculateButton align-self\n rule below only targets the default (react-aria) adapter, so in\n other adapters the button otherwise falls back to flex-start. */}\n <Flex flexDirection=\"row\" gap={8} alignItems=\"flex-end\">\n <NumberInputField\n name=\"netPay\"\n label={t('netPayLabel')}\n format=\"currency\"\n adornmentStart=\"$\"\n errorMessage={t('validations.netPay')}\n min={0}\n isRequired\n />\n <Button\n variant=\"secondary\"\n className={styles.calculateButton}\n isLoading={isCalculating}\n onClick={formHandlers.handleSubmit(handleCalculate)}\n >\n {t('calculateCta')}\n </Button>\n </Flex>\n\n {calculatedGrossUp ? (\n <div className={styles.result}>\n <Text size=\"sm\" variant=\"supporting\" weight=\"semibold\">\n {t('grossPayResult')}\n </Text>\n <Heading as=\"h3\">{formatNumberAsCurrency(parseFloat(calculatedGrossUp))}</Heading>\n </div>\n ) : (\n <Text size=\"sm\" variant=\"supporting\">\n {t('applyHint')}\n </Text>\n )}\n </div>\n </FormProvider>\n </Modal>\n )\n}\n"],"names":["GrossUpFormSchema","z","GrossUpModal","isOpen","onCalculateGrossUp","onApply","onCancel","useI18n","t","useTranslation","Modal","Heading","Text","Button","Alert","useComponentContext","baseSubmitHandler","useBase","modalContainerRef","useRef","calculatedGrossUp","setCalculatedGrossUp","useState","errorMessage","setErrorMessage","isCalculating","setIsCalculating","isApplying","setIsApplying","formHandlers","useForm","zodResolver","useEffect","handleCalculate","data","result","jsx","ActionsLayout","jsxs","FormProvider","styles","Flex","NumberInputField"],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { PayrollUpdatePaymentMethod as
|
|
1
|
+
import { PayrollUpdatePaymentMethod as O } from "@gusto/embedded-api/models/components/payrollupdate";
|
|
2
2
|
import { RFCDate as I } from "@gusto/embedded-api/types/rfcdate";
|
|
3
|
-
import { PayrollCategory as
|
|
4
|
-
import { cleanupReimbursements as
|
|
5
|
-
import { SDKInternalError as
|
|
6
|
-
import { COMPENSATION_NAME_OVERTIME as
|
|
3
|
+
import { PayrollCategory as R, isOffCyclePayroll as W } from "../../../payrollTypes.js";
|
|
4
|
+
import { cleanupReimbursements as _ } from "../../../helpers.js";
|
|
5
|
+
import { SDKInternalError as L } from "../../../../../types/sdkError.js";
|
|
6
|
+
import { COMPENSATION_NAME_OVERTIME as $, COMPENSATION_NAME_DOUBLE_OVERTIME as z, FlsaStatus as H, EXCLUDED_ADDITIONAL_EARNINGS as N } from "../../../../../shared/constants.js";
|
|
7
7
|
function Z(t, n) {
|
|
8
8
|
const e = (t ?? []).flatMap(
|
|
9
9
|
(r) => r.startDate && r.endDate ? [{ startDate: r.startDate.toString(), endDate: r.endDate.toString() }] : []
|
|
@@ -12,9 +12,9 @@ function Z(t, n) {
|
|
|
12
12
|
return e;
|
|
13
13
|
if (n?.startDate && n.endDate)
|
|
14
14
|
return [{ startDate: n.startDate, endDate: n.endDate }];
|
|
15
|
-
throw new
|
|
15
|
+
throw new L("Prepared payroll has no workweeks or pay period to derive from");
|
|
16
16
|
}
|
|
17
|
-
function
|
|
17
|
+
function w(t) {
|
|
18
18
|
const n = /* @__PURE__ */ new Set();
|
|
19
19
|
for (const e of [
|
|
20
20
|
...t?.default ?? [],
|
|
@@ -24,138 +24,140 @@ function J(t) {
|
|
|
24
24
|
return n;
|
|
25
25
|
}
|
|
26
26
|
function k(t, n, e, r) {
|
|
27
|
-
const
|
|
28
|
-
if (r !==
|
|
29
|
-
for (const
|
|
30
|
-
const
|
|
31
|
-
if (!
|
|
32
|
-
|
|
27
|
+
const u = [...t ?? []];
|
|
28
|
+
if (r !== H.OWNER && e)
|
|
29
|
+
for (const a of n ?? []) {
|
|
30
|
+
const i = a.name;
|
|
31
|
+
if (!i || N.includes(i)) continue;
|
|
32
|
+
u.some((m) => m.name?.toLowerCase() === i.toLowerCase()) || u.push({ name: i, jobUuid: e });
|
|
33
33
|
}
|
|
34
|
-
return
|
|
34
|
+
return u.filter((a) => a.name && !N.includes(a.name)).sort((a, i) => (a.name ?? "").localeCompare(i.name ?? ""));
|
|
35
35
|
}
|
|
36
|
-
function
|
|
36
|
+
function tt(t) {
|
|
37
37
|
return (t ?? []).some(
|
|
38
|
-
(n) => (n.name ===
|
|
38
|
+
(n) => (n.name === $ || n.name === z) && parseFloat(n.hours ?? "0") > 0
|
|
39
39
|
);
|
|
40
40
|
}
|
|
41
|
-
function
|
|
41
|
+
function T(t, n) {
|
|
42
42
|
return !t || t.length === 0 ? !1 : n.every(
|
|
43
43
|
(e) => t.some(
|
|
44
44
|
(r) => r.startDate?.toString() === e.startDate && r.endDate?.toString() === e.endDate
|
|
45
45
|
)
|
|
46
46
|
);
|
|
47
47
|
}
|
|
48
|
-
function
|
|
48
|
+
function nt(t, n) {
|
|
49
49
|
return (t ?? []).some(
|
|
50
|
-
(e) =>
|
|
50
|
+
(e) => T(e.breakdowns, n)
|
|
51
51
|
);
|
|
52
52
|
}
|
|
53
|
-
function
|
|
53
|
+
function b(t) {
|
|
54
54
|
if (t == null || t === "") return "";
|
|
55
55
|
const n = parseFloat(t);
|
|
56
56
|
return Number.isNaN(n) ? "" : n.toString();
|
|
57
57
|
}
|
|
58
|
-
function
|
|
59
|
-
const n =
|
|
58
|
+
function x(t) {
|
|
59
|
+
const n = b(t);
|
|
60
60
|
return n === "0" ? "" : n;
|
|
61
61
|
}
|
|
62
|
-
function
|
|
63
|
-
const
|
|
62
|
+
function C(t, n, e, r) {
|
|
63
|
+
const u = t[0]?.startDate ?? "";
|
|
64
64
|
if (!r)
|
|
65
|
-
return { [
|
|
66
|
-
const
|
|
67
|
-
return
|
|
68
|
-
const
|
|
69
|
-
(m) => m.startDate?.toString() ===
|
|
70
|
-
);
|
|
71
|
-
i[a.startDate] = M(u?.hours ?? u?.amount);
|
|
72
|
-
}) : t.forEach((a, u) => {
|
|
73
|
-
i[a.startDate] = u === 0 ? j(n) : "";
|
|
74
|
-
}), i;
|
|
75
|
-
}
|
|
76
|
-
function nt(t, n, e, r, c, i, a = t?.fixedCompensations ?? []) {
|
|
77
|
-
const u = n.length > 1 && c && i, m = {};
|
|
78
|
-
for (const o of t?.hourlyCompensations ?? []) {
|
|
79
|
-
if (!o.jobUuid || !o.name) continue;
|
|
80
|
-
const O = m[o.jobUuid] ??= {};
|
|
81
|
-
O[o.name] = y(
|
|
82
|
-
n,
|
|
83
|
-
o.hours,
|
|
84
|
-
o.breakdowns,
|
|
85
|
-
u
|
|
65
|
+
return { [u]: x(n) };
|
|
66
|
+
const a = {};
|
|
67
|
+
return T(e, t) ? t.forEach((i) => {
|
|
68
|
+
const c = e?.find(
|
|
69
|
+
(m) => m.startDate?.toString() === i.startDate
|
|
86
70
|
);
|
|
71
|
+
a[i.startDate] = b(c?.hours ?? c?.amount);
|
|
72
|
+
}) : t.forEach((i, c) => {
|
|
73
|
+
a[i.startDate] = c === 0 ? x(n) : "";
|
|
74
|
+
}), a;
|
|
75
|
+
}
|
|
76
|
+
function j(t) {
|
|
77
|
+
const n = /* @__PURE__ */ new Map();
|
|
78
|
+
for (const [e, r, u] of t) {
|
|
79
|
+
const a = n.get(e);
|
|
80
|
+
a ? a.push([r, u]) : n.set(e, [[r, u]]);
|
|
87
81
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
82
|
+
return Object.fromEntries(
|
|
83
|
+
Array.from(n, ([e, r]) => [e, Object.fromEntries(r)])
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
function et(t, n, e, r, u, a, i = t?.fixedCompensations ?? []) {
|
|
87
|
+
const c = n.length > 1 && u && a, m = [];
|
|
88
|
+
for (const o of t?.hourlyCompensations ?? [])
|
|
89
|
+
!o.jobUuid || !o.name || m.push([
|
|
90
|
+
o.jobUuid,
|
|
91
|
+
o.name,
|
|
92
|
+
C(n, o.hours, o.breakdowns, c)
|
|
93
|
+
]);
|
|
94
|
+
const D = j(m), p = [], E = [];
|
|
95
|
+
for (const o of i)
|
|
96
|
+
!o.jobUuid || !o.name || (r.has(o.name) ? p.push([
|
|
97
|
+
o.jobUuid,
|
|
98
|
+
o.name,
|
|
99
|
+
C(n, o.amount, o.breakdowns, c)
|
|
100
|
+
]) : E.push([
|
|
101
|
+
o.jobUuid,
|
|
102
|
+
o.name,
|
|
103
|
+
b(o.amount)
|
|
104
|
+
]));
|
|
105
|
+
const g = j(p), S = j(E), M = {}, v = {};
|
|
104
106
|
for (const o of t?.paidTimeOff ?? [])
|
|
105
|
-
o.name && (
|
|
106
|
-
const
|
|
107
|
+
o.name && (M[o.name] = b(o.hours), v[o.name] = b(o.finalPayoutUnusedHoursInput));
|
|
108
|
+
const y = (t?.reimbursements ?? []).map((o) => ({
|
|
107
109
|
uuid: o.uuid ?? null,
|
|
108
110
|
description: o.description ?? "",
|
|
109
111
|
amount: o.amount,
|
|
110
112
|
recurring: o.recurring ?? !1
|
|
111
113
|
}));
|
|
112
114
|
return {
|
|
113
|
-
hours:
|
|
114
|
-
overtimeIncludedEarnings:
|
|
115
|
-
overtimeExcludedEarnings:
|
|
116
|
-
timeOff:
|
|
117
|
-
finalPayout:
|
|
118
|
-
reimbursements:
|
|
115
|
+
hours: D,
|
|
116
|
+
overtimeIncludedEarnings: g,
|
|
117
|
+
overtimeExcludedEarnings: S,
|
|
118
|
+
timeOff: M,
|
|
119
|
+
finalPayout: v,
|
|
120
|
+
reimbursements: y,
|
|
119
121
|
reimbursementDraft: { description: "", amount: "" },
|
|
120
|
-
paymentMethod:
|
|
122
|
+
paymentMethod: V(t?.paymentMethod, e)
|
|
121
123
|
};
|
|
122
124
|
}
|
|
123
|
-
function
|
|
124
|
-
return t ===
|
|
125
|
+
function V(t, n) {
|
|
126
|
+
return t === O.Check ? O.Check : t === O.DirectDeposit && n ? O.DirectDeposit : n ? O.DirectDeposit : O.Check;
|
|
125
127
|
}
|
|
126
|
-
function
|
|
128
|
+
function U(t, n) {
|
|
127
129
|
const e = /* @__PURE__ */ new Map();
|
|
128
130
|
for (const r of t ?? [])
|
|
129
131
|
!r.jobUuid || !r.name || e.set(`${r.jobUuid}|${r.name}`, n(r) ?? "");
|
|
130
132
|
return e;
|
|
131
133
|
}
|
|
132
|
-
const
|
|
133
|
-
function
|
|
134
|
-
const r = 10 ** e,
|
|
135
|
-
const
|
|
136
|
-
return
|
|
134
|
+
const B = 2, G = 6;
|
|
135
|
+
function A(t, n, e) {
|
|
136
|
+
const r = 10 ** e, u = n.reduce((a, i) => {
|
|
137
|
+
const c = parseFloat(t[i.startDate] ?? "0") || 0;
|
|
138
|
+
return a + Math.round(c * r);
|
|
137
139
|
}, 0);
|
|
138
|
-
return String(
|
|
140
|
+
return String(u / r);
|
|
139
141
|
}
|
|
140
|
-
function
|
|
142
|
+
function P(t, n) {
|
|
141
143
|
let e = !1;
|
|
142
144
|
const r = {};
|
|
143
|
-
for (const [
|
|
144
|
-
const
|
|
145
|
-
for (const [
|
|
145
|
+
for (const [u, a] of Object.entries(t)) {
|
|
146
|
+
const i = {};
|
|
147
|
+
for (const [c, m] of Object.entries(a)) {
|
|
146
148
|
const D = {};
|
|
147
149
|
for (const [p, E] of Object.entries(m)) {
|
|
148
|
-
const g = n[
|
|
150
|
+
const g = n[u]?.[c]?.[p];
|
|
149
151
|
E === "" && g != null && g !== "" ? (D[p] = "0", e = !0) : D[p] = E;
|
|
150
152
|
}
|
|
151
|
-
|
|
153
|
+
i[c] = D;
|
|
152
154
|
}
|
|
153
|
-
r[
|
|
155
|
+
r[u] = i;
|
|
154
156
|
}
|
|
155
157
|
return e ? r : null;
|
|
156
158
|
}
|
|
157
|
-
function
|
|
158
|
-
const e =
|
|
159
|
+
function rt(t, n) {
|
|
160
|
+
const e = P(t.hours, n.hours), r = P(
|
|
159
161
|
t.overtimeIncludedEarnings,
|
|
160
162
|
n.overtimeIncludedEarnings
|
|
161
163
|
);
|
|
@@ -164,22 +166,22 @@ function et(t, n) {
|
|
|
164
166
|
...r ? { overtimeIncludedEarnings: r } : {}
|
|
165
167
|
};
|
|
166
168
|
}
|
|
167
|
-
function
|
|
168
|
-
const
|
|
169
|
+
function ot(t, n, e, r, u, a) {
|
|
170
|
+
const i = e.length > 1 && u && a, c = (s) => s != null && s !== "", m = U(
|
|
169
171
|
n?.hourlyCompensations,
|
|
170
172
|
(s) => s.hours
|
|
171
|
-
), D =
|
|
173
|
+
), D = U(
|
|
172
174
|
n?.fixedCompensations,
|
|
173
175
|
(s) => s.amount
|
|
174
|
-
), p = (s) => e.every((d) =>
|
|
176
|
+
), p = (s) => e.every((d) => c(s[d.startDate])), E = (s, d, f, l) => {
|
|
175
177
|
const h = f[e[0]?.startDate ?? ""];
|
|
176
|
-
return
|
|
178
|
+
return c(h) ? h : l.get(`${s}|${d}`) ?? "0";
|
|
177
179
|
}, g = Object.entries(t.hours).flatMap(
|
|
178
|
-
([s, d]) => Object.entries(d).flatMap(([f, l]) =>
|
|
180
|
+
([s, d]) => Object.entries(d).flatMap(([f, l]) => i ? p(l) ? [
|
|
179
181
|
{
|
|
180
182
|
jobUuid: s,
|
|
181
183
|
name: f,
|
|
182
|
-
hours:
|
|
184
|
+
hours: A(l, e, G),
|
|
183
185
|
breakdowns: e.map((h) => ({
|
|
184
186
|
startDate: new I(h.startDate),
|
|
185
187
|
endDate: new I(h.endDate),
|
|
@@ -188,11 +190,11 @@ function rt(t, n, e, r, c, i) {
|
|
|
188
190
|
}
|
|
189
191
|
] : [] : [{ jobUuid: s, name: f, hours: E(s, f, l, m) }])
|
|
190
192
|
), S = Object.entries(t.overtimeIncludedEarnings).flatMap(
|
|
191
|
-
([s, d]) => Object.entries(d).flatMap(([f, l]) =>
|
|
193
|
+
([s, d]) => Object.entries(d).flatMap(([f, l]) => i ? p(l) ? [
|
|
192
194
|
{
|
|
193
195
|
jobUuid: s,
|
|
194
196
|
name: f,
|
|
195
|
-
amount:
|
|
197
|
+
amount: A(l, e, B),
|
|
196
198
|
breakdowns: e.map((h) => ({
|
|
197
199
|
startDate: new I(h.startDate),
|
|
198
200
|
endDate: new I(h.endDate),
|
|
@@ -202,17 +204,17 @@ function rt(t, n, e, r, c, i) {
|
|
|
202
204
|
] : [] : [
|
|
203
205
|
{ jobUuid: s, name: f, amount: E(s, f, l, D) }
|
|
204
206
|
])
|
|
205
|
-
),
|
|
207
|
+
), M = Object.entries(t.overtimeExcludedEarnings).flatMap(
|
|
206
208
|
([s, d]) => Object.entries(d).map(([f, l]) => ({
|
|
207
209
|
jobUuid: s,
|
|
208
210
|
name: f,
|
|
209
|
-
amount:
|
|
211
|
+
amount: c(l) ? l : D.get(`${s}|${f}`) ?? "0"
|
|
210
212
|
}))
|
|
211
|
-
),
|
|
213
|
+
), v = [...S, ...M], y = r === R.Dismissal, o = Object.entries(t.timeOff).map(([s, d]) => ({
|
|
212
214
|
name: s,
|
|
213
215
|
hours: d || "0",
|
|
214
|
-
...
|
|
215
|
-
})),
|
|
216
|
+
...y && t.finalPayout[s] != null ? { finalPayoutUnusedHoursInput: t.finalPayout[s] || "0" } : {}
|
|
217
|
+
})), F = !W(r);
|
|
216
218
|
return {
|
|
217
219
|
employeeUuid: n?.employeeUuid,
|
|
218
220
|
version: n?.version,
|
|
@@ -220,19 +222,19 @@ function rt(t, n, e, r, c, i) {
|
|
|
220
222
|
memo: n?.memo || void 0,
|
|
221
223
|
...t.paymentMethod ? { paymentMethod: t.paymentMethod } : {},
|
|
222
224
|
hourlyCompensations: g,
|
|
223
|
-
fixedCompensations:
|
|
224
|
-
paidTimeOff:
|
|
225
|
-
...
|
|
225
|
+
fixedCompensations: v,
|
|
226
|
+
paidTimeOff: o,
|
|
227
|
+
...F ? { reimbursements: _(t.reimbursements) } : {}
|
|
226
228
|
};
|
|
227
229
|
}
|
|
228
230
|
export {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
231
|
+
ot as buildPayrollUpdateEmployeeCompensation,
|
|
232
|
+
w as collectOvertimeEarningNames,
|
|
233
|
+
et as derivePayrollEditEmployeeDefaults,
|
|
234
|
+
nt as hasBreakdownsMatchingWorkweeks,
|
|
235
|
+
tt as hasExistingOvertimeHours,
|
|
234
236
|
Z as normalizeWorkweeks,
|
|
235
237
|
k as resolveEditableFixedCompensations,
|
|
236
|
-
|
|
238
|
+
rt as zeroFillClearedWorkweekCells
|
|
237
239
|
};
|
|
238
240
|
//# sourceMappingURL=payrollEditEmployeeHelpers.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"payrollEditEmployeeHelpers.js","sources":["../../../../../../src/components/Payroll/PayrollEditEmployee/shared/usePayrollEditEmployeeForm/payrollEditEmployeeHelpers.ts"],"sourcesContent":["import type { PayrollEmployeeCompensationsType } from '@gusto/embedded-api/models/components/payrollemployeecompensationstype'\nimport type { EarningTypeList } from '@gusto/embedded-api/models/components/earningtypelist'\nimport {\n PayrollUpdatePaymentMethod,\n type PayrollUpdateEmployeeCompensations,\n} from '@gusto/embedded-api/models/components/payrollupdate'\nimport { RFCDate } from '@gusto/embedded-api/types/rfcdate'\nimport type {\n PayrollEditEmployeeFormData,\n PayrollEditEmployeeFormOutputs,\n} from './payrollEditEmployeeSchema'\nimport { PayrollCategory, isOffCyclePayroll } from '@/components/Payroll/payrollTypes'\nimport { cleanupReimbursements } from '@/components/Payroll/helpers'\nimport { SDKInternalError } from '@/types/sdkError'\nimport {\n COMPENSATION_NAME_DOUBLE_OVERTIME,\n COMPENSATION_NAME_OVERTIME,\n EXCLUDED_ADDITIONAL_EARNINGS,\n FlsaStatus,\n} from '@/shared/constants'\n\n/** One fixed-compensation line off the prepared compensation. */\ntype FixedCompensationEntry = NonNullable<\n PayrollEmployeeCompensationsType['fixedCompensations']\n>[number]\n\n/**\n * Normalized form of a workweek: the API exposes\n * `{ startDate?: RFCDate; endDate?: RFCDate }`, but the hook keys week-maps by\n * `YYYY-MM-DD` strings and builds breakdowns from them, so both boundaries are\n * required strings here. Surfaced on the hook's `data.workweeks` so the UI can\n * label each per-workweek column without re-parsing the raw API workweeks.\n *\n * @internal\n */\nexport interface NormalizedWorkweek {\n startDate: string\n endDate: string\n}\n\n/**\n * Normalizes the prepared payroll's top-level `workweeks` into\n * {@link NormalizedWorkweek} boundary strings, falling back to a single\n * pay-period-spanning workweek when the API returns no workweek boundaries.\n *\n * @param workweeks - The prepared payroll's top-level `workweeks` (RFCDate boundaries), possibly `null`.\n * @param payPeriod - The prepared payroll's `payPeriod`, used as the single-workweek fallback.\n * @returns One entry per workweek; a single entry spanning the pay period when none are supplied.\n * @throws SDKInternalError when neither workweeks nor a pay period are present (a malformed prepared payroll).\n * @internal\n */\nexport function normalizeWorkweeks(\n workweeks: Array<{ startDate?: RFCDate; endDate?: RFCDate }> | null | undefined,\n payPeriod: { startDate?: string | null; endDate?: string | null } | undefined,\n): NormalizedWorkweek[] {\n const normalized = (workweeks ?? []).flatMap(week =>\n week.startDate && week.endDate\n ? [{ startDate: week.startDate.toString(), endDate: week.endDate.toString() }]\n : [],\n )\n\n if (normalized.length > 0) {\n return normalized\n }\n\n if (payPeriod?.startDate && payPeriod.endDate) {\n return [{ startDate: payPeriod.startDate, endDate: payPeriod.endDate }]\n }\n\n // A prepared payroll always carries a pay period, so reaching here means the\n // response was malformed. Fail loud rather than build an empty, mis-keyed form\n // that could submit an employee's pay against a blank workweek.\n throw new SDKInternalError('Prepared payroll has no workweeks or pay period to derive from')\n}\n\n/**\n * Collects the names of earning types included in the regular-rate-of-pay\n * overtime calculation. These earnings render in the workweek-breakdown\n * additional-earnings section; all others fall into the flat `overtimeExcludedEarnings` section.\n *\n * @param earningTypeList - The company's default and custom earning types.\n * @returns A set of earning-type names with `includedInOvertimePay` set.\n * @internal\n */\nexport function collectOvertimeEarningNames(\n earningTypeList: EarningTypeList | undefined,\n): Set<string> {\n const names = new Set<string>()\n for (const earningType of [\n ...(earningTypeList?.default ?? []),\n ...(earningTypeList?.custom ?? []),\n ]) {\n if (earningType.name && earningType.includedInOvertimePay) {\n names.add(earningType.name)\n }\n }\n return names\n}\n\n/**\n * Merges the employee's existing fixed compensations with a blank placeholder for\n * every payroll fixed-compensation type they don't yet have, mirroring the stable editor\n * (`getAdditionalEarningsCompensations`). This is what lets the editor surface an\n * empty input for Bonus, Commission, etc. even when the prepared payroll carries\n * no fixed compensations. Placeholders attach to the primary job and carry no\n * amount (blank), so an untouched earning submits as zero without altering pay.\n *\n * @remarks\n * Owners (FLSA status `Owner`) never receive placeholders. Earning types that are\n * handled elsewhere or never shown as additional earnings\n * ({@link EXCLUDED_ADDITIONAL_EARNINGS}) and inactive types are skipped. The\n * result is sorted alphabetically by name. The regular-rate-of-pay split between\n * additional earnings and `overtimeExcludedEarnings` happens downstream via `overtimeEarningNames`;\n * this helper only decides which earning lines exist.\n *\n * @param existingFixedCompensations - The prepared compensation's fixed compensations.\n * @param fixedCompensationTypes - The prepared payroll's `fixedCompensationTypes` (the same source the stable editor uses).\n * @param primaryJobUuid - The employee's primary job UUID; placeholders attach here.\n * @param flsaStatus - The employee's FLSA status; owners get no placeholders.\n * @returns The merged, filtered, alphabetically sorted fixed-compensation lines.\n * @internal\n */\nexport function resolveEditableFixedCompensations(\n existingFixedCompensations: FixedCompensationEntry[] | undefined,\n fixedCompensationTypes: Array<{ name?: string | null }> | undefined,\n primaryJobUuid: string | undefined,\n flsaStatus: string | undefined,\n): FixedCompensationEntry[] {\n const merged: FixedCompensationEntry[] = [...(existingFixedCompensations ?? [])]\n\n if (flsaStatus !== FlsaStatus.OWNER && primaryJobUuid) {\n for (const compensationType of fixedCompensationTypes ?? []) {\n const name = compensationType.name\n if (!name) continue\n if (EXCLUDED_ADDITIONAL_EARNINGS.includes(name)) continue\n const exists = merged.some(entry => entry.name?.toLowerCase() === name.toLowerCase())\n if (!exists) merged.push({ name, jobUuid: primaryJobUuid })\n }\n }\n\n return merged\n .filter(entry => entry.name && !EXCLUDED_ADDITIONAL_EARNINGS.includes(entry.name))\n .sort((a, b) => (a.name ?? '').localeCompare(b.name ?? ''))\n}\n\n/**\n * Whether the employee's prepared compensation already carries non-zero\n * Overtime or Double-overtime hours.\n *\n * @remarks\n * Used to default the single `withOvertime` flag: an employee who already\n * has real overtime hours starts with the workweek split shown rather than\n * requiring an extra click to see data that's already there.\n *\n * @param hourlyCompensations - The prepared compensation's hourly lines.\n * @returns `true` when any Overtime or Double-overtime line has hours greater than zero.\n * @internal\n */\nexport function hasExistingOvertimeHours(\n hourlyCompensations: PayrollEmployeeCompensationsType['hourlyCompensations'] | undefined,\n): boolean {\n return (hourlyCompensations ?? []).some(\n compensation =>\n (compensation.name === COMPENSATION_NAME_OVERTIME ||\n compensation.name === COMPENSATION_NAME_DOUBLE_OVERTIME) &&\n parseFloat(compensation.hours ?? '0') > 0,\n )\n}\n\n/**\n * Whether a line's `breakdowns` exactly cover every workweek in `workweeks`\n * (each workweek has a breakdown entry matching both its start and end date).\n */\nfunction lineBreakdownsMatchWorkweeks(\n breakdowns: Array<{ startDate?: RFCDate; endDate?: RFCDate }> | undefined,\n workweeks: NormalizedWorkweek[],\n): boolean {\n if (!breakdowns || breakdowns.length === 0) return false\n return workweeks.every(workweek =>\n breakdowns.some(\n breakdown =>\n breakdown.startDate?.toString() === workweek.startDate &&\n breakdown.endDate?.toString() === workweek.endDate,\n ),\n )\n}\n\n/**\n * Whether any of the employee's hourly-compensation lines already carries a\n * real, per-workweek `breakdowns` array that exactly tiles the current pay\n * period's workweeks.\n *\n * @remarks\n * Used alongside {@link hasExistingOvertimeHours} to default the single\n * `withOvertime` flag: an employee whose hours are already broken down by\n * workweek (e.g. a previous edit entered real per-week values) starts with the\n * workweek split shown, seeded from those breakdowns rather than from a blank\n * or first-cell-only guess. See {@link buildWeekMap}, which applies the same\n * per-line check to decide each line's population mode.\n *\n * @param hourlyCompensations - The prepared compensation's hourly lines.\n * @param workweeks - Normalized workweeks for the pay period.\n * @returns `true` when at least one hourly line's breakdowns cover every workweek.\n * @internal\n */\nexport function hasBreakdownsMatchingWorkweeks(\n hourlyCompensations: PayrollEmployeeCompensationsType['hourlyCompensations'] | undefined,\n workweeks: NormalizedWorkweek[],\n): boolean {\n return (hourlyCompensations ?? []).some(compensation =>\n lineBreakdownsMatchWorkweeks(compensation.breakdowns, workweeks),\n )\n}\n\n/**\n * Trims an API decimal string (e.g. `\"40.000\"`, `\"500.00\"`) to a clean editable\n * value (`\"40\"`, `\"500\"`), preserving real fractional parts (`\"40.5\"`). A blank\n * or non-numeric value returns `''` (meaning \"not provided\").\n */\nfunction formatAmountInput(value: string | null | undefined): string {\n if (value == null || value === '') return ''\n const parsed = parseFloat(value)\n return Number.isNaN(parsed) ? '' : parsed.toString()\n}\n\n/**\n * Seeds a cell from a line's total: same as {@link formatAmountInput} except a\n * zero total yields `''` rather than `\"0\"`. A line whose total is zero (e.g. an\n * Overtime line with no overtime) should render as a blank cell the user can\n * fill in, not a pre-filled `0` — and a pre-filled `0` would also count as a\n * filled cell, tripping the per-row \"fill every workweek\" check for a line the\n * user never actually touched. Only used for total-seeded cells, never for real\n * per-week breakdown values (a genuine `0` breakdown must survive to keep a\n * matched split's tiling intact).\n */\nfunction formatSeededTotal(value: string | null | undefined): string {\n const formatted = formatAmountInput(value)\n return formatted === '0' ? '' : formatted\n}\n\n/**\n * Builds one job+name line's week map in one of three shapes, gated by\n * `isSplit` (`workweeks.length > 1 && isOvertimeEligible && withOvertime`):\n *\n * - Collapsed (`isSplit` false): a single key — the first workweek's start —\n * holding the total. No key is emitted for any other workweek, which is what\n * keeps a collapsed row's per-row validation a no-op (see\n * {@link createPayrollEditEmployeeSchema}).\n * - Split, breakdowns match ({@link hasBreakdownsMatchingWorkweeks} true for\n * this line): one key per workweek, each seeded from its real breakdown value.\n * - Split, no matching breakdowns: one key per workweek, with only the first\n * seeded (from the total) and the rest left blank — never auto-distributed,\n * so the user must fill them in (enforced by the schema's per-row check).\n */\nfunction buildWeekMap(\n workweeks: NormalizedWorkweek[],\n total: string | undefined,\n breakdowns:\n Array<{ startDate?: RFCDate; endDate?: RFCDate; hours?: string; amount?: string }> | undefined,\n isSplit: boolean,\n): Record<string, string> {\n const firstWorkweekStart = workweeks[0]?.startDate ?? ''\n\n if (!isSplit) {\n return { [firstWorkweekStart]: formatSeededTotal(total) }\n }\n\n const weekMap: Record<string, string> = {}\n if (lineBreakdownsMatchWorkweeks(breakdowns, workweeks)) {\n workweeks.forEach(workweek => {\n const breakdown = breakdowns?.find(\n entry => entry.startDate?.toString() === workweek.startDate,\n )\n weekMap[workweek.startDate] = formatAmountInput(breakdown?.hours ?? breakdown?.amount)\n })\n } else {\n workweeks.forEach((workweek, index) => {\n weekMap[workweek.startDate] = index === 0 ? formatSeededTotal(total) : ''\n })\n }\n return weekMap\n}\n\n/**\n * Derives the form's default values from the employee's prepared compensation.\n *\n * @remarks\n * Hourly and additional earnings are expanded into per-workweek maps via\n * {@link buildWeekMap}: collapsed to the total when not split, seeded from real\n * breakdowns or first-cell-only otherwise. Time off, final payout,\n * reimbursements, and payment method are read straight off the compensation.\n *\n * @param employeeCompensation - The employee's prepared compensation, if loaded.\n * @param workweeks - Normalized workweeks for the pay period.\n * @param withOvertime - The single, form-wide overtime-mode flag (see {@link hasExistingOvertimeHours}, {@link hasBreakdownsMatchingWorkweeks}, `actions.addOvertime`). Gates splitting alongside `isOvertimeEligible`.\n * @returns Default {@link PayrollEditEmployeeFormData} for `useForm`.\n * @internal\n */\nexport function derivePayrollEditEmployeeDefaults(\n employeeCompensation: PayrollEmployeeCompensationsType | undefined,\n workweeks: NormalizedWorkweek[],\n hasDirectDepositSetup: boolean,\n overtimeEarningNames: Set<string>,\n isOvertimeEligible: boolean,\n withOvertime: boolean,\n fixedCompensations: FixedCompensationEntry[] = employeeCompensation?.fixedCompensations ?? [],\n): PayrollEditEmployeeFormData {\n // Only overtime-eligible employees split hours/earnings by workweek, and only\n // while the single `withOvertime` flag is on; everyone else renders (and\n // seeds) flat, even on a multi-workweek payroll.\n const isSplit = workweeks.length > 1 && isOvertimeEligible && withOvertime\n\n const hours: PayrollEditEmployeeFormData['hours'] = {}\n for (const compensation of employeeCompensation?.hourlyCompensations ?? []) {\n if (!compensation.jobUuid || !compensation.name) continue\n const jobHours = (hours[compensation.jobUuid] ??= {})\n jobHours[compensation.name] = buildWeekMap(\n workweeks,\n compensation.hours,\n compensation.breakdowns,\n isSplit,\n )\n }\n\n // Earnings whose earning type is included in the regular-rate-of-pay overtime\n // calculation stay workweek-breakdown; the rest are flat and land in `overtimeExcludedEarnings`.\n // The hook owns this bucketing so the UI just renders each section.\n const overtimeIncludedEarnings: PayrollEditEmployeeFormData['overtimeIncludedEarnings'] = {}\n const overtimeExcludedEarnings: PayrollEditEmployeeFormData['overtimeExcludedEarnings'] = {}\n for (const compensation of fixedCompensations) {\n if (!compensation.jobUuid || !compensation.name) continue\n if (overtimeEarningNames.has(compensation.name)) {\n const jobEarnings = (overtimeIncludedEarnings[compensation.jobUuid] ??= {})\n jobEarnings[compensation.name] = buildWeekMap(\n workweeks,\n compensation.amount,\n compensation.breakdowns,\n isSplit,\n )\n } else {\n const jobOther = (overtimeExcludedEarnings[compensation.jobUuid] ??= {})\n jobOther[compensation.name] = formatAmountInput(compensation.amount)\n }\n }\n\n const timeOff: PayrollEditEmployeeFormData['timeOff'] = {}\n const finalPayout: PayrollEditEmployeeFormData['finalPayout'] = {}\n for (const entry of employeeCompensation?.paidTimeOff ?? []) {\n if (!entry.name) continue\n timeOff[entry.name] = formatAmountInput(entry.hours)\n finalPayout[entry.name] = formatAmountInput(entry.finalPayoutUnusedHoursInput)\n }\n\n const reimbursements: PayrollEditEmployeeFormData['reimbursements'] = (\n employeeCompensation?.reimbursements ?? []\n ).map(reimbursement => ({\n uuid: reimbursement.uuid ?? null,\n description: reimbursement.description ?? '',\n amount: reimbursement.amount,\n recurring: reimbursement.recurring ?? false,\n }))\n\n return {\n hours,\n overtimeIncludedEarnings,\n overtimeExcludedEarnings,\n timeOff,\n finalPayout,\n reimbursements,\n reimbursementDraft: { description: '', amount: '' },\n paymentMethod: resolvePaymentMethod(employeeCompensation?.paymentMethod, hasDirectDepositSetup),\n }\n}\n\n/**\n * Resolves the default payment method, mirroring the stable component (#2683):\n * an employee with no direct deposit set up defaults to (and is forced to)\n * `Check`, even when the prepared payroll carried `Direct Deposit` or nothing.\n * `Historical` is treated as unset. The result is always `Direct Deposit` or\n * `Check` — never `Historical` — since those are the only values the update\n * endpoint accepts.\n */\nfunction resolvePaymentMethod(\n paymentMethod: string | null | undefined,\n hasDirectDepositSetup: boolean,\n): PayrollUpdatePaymentMethod {\n if (paymentMethod === PayrollUpdatePaymentMethod.Check) return PayrollUpdatePaymentMethod.Check\n if (paymentMethod === PayrollUpdatePaymentMethod.DirectDeposit && hasDirectDepositSetup) {\n return PayrollUpdatePaymentMethod.DirectDeposit\n }\n return hasDirectDepositSetup\n ? PayrollUpdatePaymentMethod.DirectDeposit\n : PayrollUpdatePaymentMethod.Check\n}\n\nfunction originalTotals<T extends { jobUuid?: string; name?: string }>(\n compensations: T[] | undefined,\n selectTotal: (compensation: T) => string | null | undefined,\n): Map<string, string> {\n const totals = new Map<string, string>()\n for (const compensation of compensations ?? []) {\n if (!compensation.jobUuid || !compensation.name) continue\n totals.set(`${compensation.jobUuid}|${compensation.name}`, selectTotal(compensation) ?? '')\n }\n return totals\n}\n\n// Precision of the per-workweek values being summed: dollar amounts carry cents,\n// hours up to six places.\nconst AMOUNT_DECIMALS = 2\nconst HOURS_DECIMALS = 6\n\n/**\n * Sums per-workweek input values in integer minor units, then scales back.\n *\n * @remarks\n * Each value is already bounded to `decimals` places, so scaling it to an\n * integer (cents for amounts, millionths for hours) and summing those integers\n * is exact. Float-accumulating the decimals directly and rounding at the end\n * would instead leak binary error into the wire value (e.g. `0.1 + 0.2` →\n * `\"0.30000000000000004\"`), which the payroll API should never receive.\n */\nfunction sumWeekValues(\n weekMap: Record<string, string>,\n workweeks: NormalizedWorkweek[],\n decimals: number,\n): string {\n const factor = 10 ** decimals\n const totalMinorUnits = workweeks.reduce((total, workweek) => {\n const value = parseFloat(weekMap[workweek.startDate] ?? '0') || 0\n return total + Math.round(value * factor)\n }, 0)\n return String(totalMinorUnits / factor)\n}\n\n/**\n * Returns a copy of one week-mapped section (`hours` or `overtimeIncludedEarnings`)\n * with every cell that loaded with a value but is now empty coerced to `\"0\"`, so a\n * user who clears a pre-filled workweek input submits an explicit zero for it rather\n * than leaving it blank. \"Loaded with a value\" means the matching cell in `defaults`\n * is non-empty; a cell that was blank at load is left untouched (it stays subject to\n * the per-row \"fill every workweek\" validation). Returns `null` when nothing changed,\n * so the caller can skip a redundant form update.\n */\nfunction zeroFillClearedSection(\n current: Record<string, Record<string, Record<string, string>>>,\n defaults: Record<string, Record<string, Record<string, string>>>,\n): Record<string, Record<string, Record<string, string>>> | null {\n let changed = false\n const next: Record<string, Record<string, Record<string, string>>> = {}\n for (const [jobUuid, names] of Object.entries(current)) {\n const nextNames: Record<string, Record<string, string>> = {}\n for (const [name, weekMap] of Object.entries(names)) {\n const nextWeekMap: Record<string, string> = {}\n for (const [week, value] of Object.entries(weekMap)) {\n const loaded = defaults[jobUuid]?.[name]?.[week]\n if (value === '' && loaded != null && loaded !== '') {\n nextWeekMap[week] = '0'\n changed = true\n } else {\n nextWeekMap[week] = value\n }\n }\n nextNames[name] = nextWeekMap\n }\n next[jobUuid] = nextNames\n }\n return changed ? next : null\n}\n\n/**\n * Coerces cleared-from-loaded workweek cells to `\"0\"` across both week-mapped\n * sections (`hours`, `overtimeIncludedEarnings`).\n *\n * @remarks\n * Run just before submit: a workweek input that loaded with a value and was\n * cleared by the user should submit an explicit `0` for that cell (whether split\n * by workweek or collapsed to a single box), instead of falling back to the\n * original value or being blocked by the per-row completeness check. Cells that\n * were blank at load are untouched. Each returned section is present only when it\n * actually changed, so the caller can `setValue` selectively.\n *\n * @param current - The live form values.\n * @param defaults - The form's loaded defaults (the API-seeded baseline for the current split mode).\n * @returns The coerced `hours` and/or `overtimeIncludedEarnings` sections, each omitted when unchanged.\n * @internal\n */\nexport function zeroFillClearedWorkweekCells(\n current: Pick<PayrollEditEmployeeFormData, 'hours' | 'overtimeIncludedEarnings'>,\n defaults: Pick<PayrollEditEmployeeFormData, 'hours' | 'overtimeIncludedEarnings'>,\n): Partial<Pick<PayrollEditEmployeeFormData, 'hours' | 'overtimeIncludedEarnings'>> {\n const hours = zeroFillClearedSection(current.hours, defaults.hours)\n const overtimeIncludedEarnings = zeroFillClearedSection(\n current.overtimeIncludedEarnings,\n defaults.overtimeIncludedEarnings,\n )\n return {\n ...(hours ? { hours } : {}),\n ...(overtimeIncludedEarnings ? { overtimeIncludedEarnings } : {}),\n }\n}\n\n/**\n * Builds the `PayrollUpdate` employee-compensation payload from form values.\n *\n * @remarks\n * When the pay period spans a single workweek (or the employee isn't split by\n * workweek), totals are sent without `breakdowns`. When split, each hourly and\n * additional-earning line is decided independently — per line, not per job\n * (the API models breakdowns on each compensation line, not as a per-job\n * all-or-nothing unit):\n *\n * - A fully-filled line (every workweek cell has a value) sends `breakdowns`\n * tiling every workweek exactly, with the total equal to the sum of the\n * per-week values.\n * - An entirely blank line sends nothing for it — no `breakdowns`, no\n * fabricated `0`, no fabricated total — leaving it as the flat, untouched\n * value it already was.\n * - A partial line (some but not all cells filled) can never reach this\n * function: {@link createPayrollEditEmployeeSchema}'s per-row check blocks\n * submit until every cell in a touched row is filled.\n *\n * @param formData - Current parsed form values.\n * @param employeeCompensation - The prepared compensation, for identifying metadata (`version`, `employeeUuid`).\n * @param workweeks - Normalized workweeks for the pay period.\n * @param payrollCategory - The payroll category, gating itemized vs. off-cycle reimbursements.\n * @param isOvertimeEligible - Whether the employee is overtime-eligible (nonexempt family).\n * @param withOvertime - The single, form-wide overtime-mode flag. Gates splitting alongside `isOvertimeEligible` and `workweeks.length > 1`; when `false`, every line submits its flat (collapsed) value regardless of eligibility.\n * @returns The employee-compensation entry for the `PayrollUpdate` request body.\n * @internal\n */\nexport function buildPayrollUpdateEmployeeCompensation(\n formData: PayrollEditEmployeeFormOutputs,\n employeeCompensation: PayrollEmployeeCompensationsType | undefined,\n workweeks: NormalizedWorkweek[],\n payrollCategory: PayrollCategory,\n isOvertimeEligible: boolean,\n withOvertime: boolean,\n): PayrollUpdateEmployeeCompensations {\n // Breakdowns are emitted only when the line is actually split by workweek:\n // multiple workweeks, an overtime-eligible employee, and `withOvertime` on.\n // This must match the field builder's gate so what renders and what submits\n // never drift.\n const isSplit = workweeks.length > 1 && isOvertimeEligible && withOvertime\n const hasValue = (value: string | undefined) => value != null && value !== ''\n const originalHours = originalTotals(\n employeeCompensation?.hourlyCompensations,\n comp => comp.hours,\n )\n const originalAmounts = originalTotals(\n employeeCompensation?.fixedCompensations,\n comp => comp.amount,\n )\n const isRowFilled = (weekMap: Record<string, string>) =>\n workweeks.every(workweek => hasValue(weekMap[workweek.startDate]))\n const collapsedValue = (\n jobUuid: string,\n name: string,\n weekMap: Record<string, string>,\n originals: Map<string, string>,\n ) => {\n const single = weekMap[workweeks[0]?.startDate ?? '']\n return hasValue(single) ? single! : (originals.get(`${jobUuid}|${name}`) ?? '0')\n }\n\n const hourlyCompensations = Object.entries(formData.hours).flatMap(([jobUuid, names]) =>\n Object.entries(names).flatMap(([name, weekMap]) => {\n if (!isSplit) {\n return [{ jobUuid, name, hours: collapsedValue(jobUuid, name, weekMap, originalHours) }]\n }\n if (!isRowFilled(weekMap)) return []\n return [\n {\n jobUuid,\n name,\n hours: sumWeekValues(weekMap, workweeks, HOURS_DECIMALS),\n breakdowns: workweeks.map(workweek => ({\n startDate: new RFCDate(workweek.startDate),\n endDate: new RFCDate(workweek.endDate),\n hours: weekMap[workweek.startDate]!,\n })),\n },\n ]\n }),\n )\n\n const breakdownEarnings = Object.entries(formData.overtimeIncludedEarnings).flatMap(\n ([jobUuid, names]) =>\n Object.entries(names).flatMap(([name, weekMap]) => {\n if (!isSplit) {\n return [\n { jobUuid, name, amount: collapsedValue(jobUuid, name, weekMap, originalAmounts) },\n ]\n }\n if (!isRowFilled(weekMap)) return []\n return [\n {\n jobUuid,\n name,\n amount: sumWeekValues(weekMap, workweeks, AMOUNT_DECIMALS),\n breakdowns: workweeks.map(workweek => ({\n startDate: new RFCDate(workweek.startDate),\n endDate: new RFCDate(workweek.endDate),\n amount: weekMap[workweek.startDate]!,\n })),\n },\n ]\n }),\n )\n\n // Non-overtime earnings never carry breakdowns; they are sent as flat totals.\n const flatEarnings = Object.entries(formData.overtimeExcludedEarnings).flatMap(\n ([jobUuid, names]) =>\n Object.entries(names).map(([name, amount]) => ({\n jobUuid,\n name,\n amount: hasValue(amount) ? amount : (originalAmounts.get(`${jobUuid}|${name}`) ?? '0'),\n })),\n )\n\n const fixedCompensations = [...breakdownEarnings, ...flatEarnings]\n\n const isDismissal = payrollCategory === PayrollCategory.Dismissal\n const paidTimeOff = Object.entries(formData.timeOff).map(([name, value]) => ({\n name,\n hours: value || '0',\n ...(isDismissal && formData.finalPayout[name] != null\n ? { finalPayoutUnusedHoursInput: formData.finalPayout[name] || '0' }\n : {}),\n }))\n\n const usesItemizedReimbursements = !isOffCyclePayroll(payrollCategory)\n\n return {\n employeeUuid: employeeCompensation?.employeeUuid,\n version: employeeCompensation?.version as string | undefined,\n excluded: employeeCompensation?.excluded,\n memo: employeeCompensation?.memo || undefined,\n ...(formData.paymentMethod ? { paymentMethod: formData.paymentMethod } : {}),\n hourlyCompensations,\n fixedCompensations,\n paidTimeOff,\n ...(usesItemizedReimbursements\n ? { reimbursements: cleanupReimbursements(formData.reimbursements) }\n : {}),\n }\n}\n"],"names":["normalizeWorkweeks","workweeks","payPeriod","normalized","week","SDKInternalError","collectOvertimeEarningNames","earningTypeList","names","earningType","resolveEditableFixedCompensations","existingFixedCompensations","fixedCompensationTypes","primaryJobUuid","flsaStatus","merged","FlsaStatus","compensationType","name","EXCLUDED_ADDITIONAL_EARNINGS","entry","a","b","hasExistingOvertimeHours","hourlyCompensations","compensation","COMPENSATION_NAME_OVERTIME","COMPENSATION_NAME_DOUBLE_OVERTIME","lineBreakdownsMatchWorkweeks","breakdowns","breakdown","workweek","hasBreakdownsMatchingWorkweeks","formatAmountInput","value","parsed","formatSeededTotal","formatted","buildWeekMap","total","isSplit","firstWorkweekStart","weekMap","index","derivePayrollEditEmployeeDefaults","employeeCompensation","hasDirectDepositSetup","overtimeEarningNames","isOvertimeEligible","withOvertime","fixedCompensations","hours","jobHours","overtimeIncludedEarnings","overtimeExcludedEarnings","jobEarnings","jobOther","timeOff","finalPayout","reimbursements","reimbursement","resolvePaymentMethod","paymentMethod","PayrollUpdatePaymentMethod","originalTotals","compensations","selectTotal","totals","AMOUNT_DECIMALS","HOURS_DECIMALS","sumWeekValues","decimals","factor","totalMinorUnits","zeroFillClearedSection","current","defaults","changed","next","jobUuid","nextNames","nextWeekMap","loaded","zeroFillClearedWorkweekCells","buildPayrollUpdateEmployeeCompensation","formData","payrollCategory","hasValue","originalHours","comp","originalAmounts","isRowFilled","collapsedValue","originals","single","RFCDate","breakdownEarnings","flatEarnings","amount","isDismissal","PayrollCategory","paidTimeOff","usesItemizedReimbursements","isOffCyclePayroll","cleanupReimbursements"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"payrollEditEmployeeHelpers.js","sources":["../../../../../../src/components/Payroll/PayrollEditEmployee/shared/usePayrollEditEmployeeForm/payrollEditEmployeeHelpers.ts"],"sourcesContent":["import type { PayrollEmployeeCompensationsType } from '@gusto/embedded-api/models/components/payrollemployeecompensationstype'\nimport type { EarningTypeList } from '@gusto/embedded-api/models/components/earningtypelist'\nimport {\n PayrollUpdatePaymentMethod,\n type PayrollUpdateEmployeeCompensations,\n} from '@gusto/embedded-api/models/components/payrollupdate'\nimport { RFCDate } from '@gusto/embedded-api/types/rfcdate'\nimport type {\n PayrollEditEmployeeFormData,\n PayrollEditEmployeeFormOutputs,\n} from './payrollEditEmployeeSchema'\nimport { PayrollCategory, isOffCyclePayroll } from '@/components/Payroll/payrollTypes'\nimport { cleanupReimbursements } from '@/components/Payroll/helpers'\nimport { SDKInternalError } from '@/types/sdkError'\nimport {\n COMPENSATION_NAME_DOUBLE_OVERTIME,\n COMPENSATION_NAME_OVERTIME,\n EXCLUDED_ADDITIONAL_EARNINGS,\n FlsaStatus,\n} from '@/shared/constants'\n\n/** One fixed-compensation line off the prepared compensation. */\ntype FixedCompensationEntry = NonNullable<\n PayrollEmployeeCompensationsType['fixedCompensations']\n>[number]\n\n/**\n * Normalized form of a workweek: the API exposes\n * `{ startDate?: RFCDate; endDate?: RFCDate }`, but the hook keys week-maps by\n * `YYYY-MM-DD` strings and builds breakdowns from them, so both boundaries are\n * required strings here. Surfaced on the hook's `data.workweeks` so the UI can\n * label each per-workweek column without re-parsing the raw API workweeks.\n *\n * @internal\n */\nexport interface NormalizedWorkweek {\n startDate: string\n endDate: string\n}\n\n/**\n * Normalizes the prepared payroll's top-level `workweeks` into\n * {@link NormalizedWorkweek} boundary strings, falling back to a single\n * pay-period-spanning workweek when the API returns no workweek boundaries.\n *\n * @param workweeks - The prepared payroll's top-level `workweeks` (RFCDate boundaries), possibly `null`.\n * @param payPeriod - The prepared payroll's `payPeriod`, used as the single-workweek fallback.\n * @returns One entry per workweek; a single entry spanning the pay period when none are supplied.\n * @throws SDKInternalError when neither workweeks nor a pay period are present (a malformed prepared payroll).\n * @internal\n */\nexport function normalizeWorkweeks(\n workweeks: Array<{ startDate?: RFCDate; endDate?: RFCDate }> | null | undefined,\n payPeriod: { startDate?: string | null; endDate?: string | null } | undefined,\n): NormalizedWorkweek[] {\n const normalized = (workweeks ?? []).flatMap(week =>\n week.startDate && week.endDate\n ? [{ startDate: week.startDate.toString(), endDate: week.endDate.toString() }]\n : [],\n )\n\n if (normalized.length > 0) {\n return normalized\n }\n\n if (payPeriod?.startDate && payPeriod.endDate) {\n return [{ startDate: payPeriod.startDate, endDate: payPeriod.endDate }]\n }\n\n // A prepared payroll always carries a pay period, so reaching here means the\n // response was malformed. Fail loud rather than build an empty, mis-keyed form\n // that could submit an employee's pay against a blank workweek.\n throw new SDKInternalError('Prepared payroll has no workweeks or pay period to derive from')\n}\n\n/**\n * Collects the names of earning types included in the regular-rate-of-pay\n * overtime calculation. These earnings render in the workweek-breakdown\n * additional-earnings section; all others fall into the flat `overtimeExcludedEarnings` section.\n *\n * @param earningTypeList - The company's default and custom earning types.\n * @returns A set of earning-type names with `includedInOvertimePay` set.\n * @internal\n */\nexport function collectOvertimeEarningNames(\n earningTypeList: EarningTypeList | undefined,\n): Set<string> {\n const names = new Set<string>()\n for (const earningType of [\n ...(earningTypeList?.default ?? []),\n ...(earningTypeList?.custom ?? []),\n ]) {\n if (earningType.name && earningType.includedInOvertimePay) {\n names.add(earningType.name)\n }\n }\n return names\n}\n\n/**\n * Merges the employee's existing fixed compensations with a blank placeholder for\n * every payroll fixed-compensation type they don't yet have, mirroring the stable editor\n * (`getAdditionalEarningsCompensations`). This is what lets the editor surface an\n * empty input for Bonus, Commission, etc. even when the prepared payroll carries\n * no fixed compensations. Placeholders attach to the primary job and carry no\n * amount (blank), so an untouched earning submits as zero without altering pay.\n *\n * @remarks\n * Owners (FLSA status `Owner`) never receive placeholders. Earning types that are\n * handled elsewhere or never shown as additional earnings\n * ({@link EXCLUDED_ADDITIONAL_EARNINGS}) and inactive types are skipped. The\n * result is sorted alphabetically by name. The regular-rate-of-pay split between\n * additional earnings and `overtimeExcludedEarnings` happens downstream via `overtimeEarningNames`;\n * this helper only decides which earning lines exist.\n *\n * @param existingFixedCompensations - The prepared compensation's fixed compensations.\n * @param fixedCompensationTypes - The prepared payroll's `fixedCompensationTypes` (the same source the stable editor uses).\n * @param primaryJobUuid - The employee's primary job UUID; placeholders attach here.\n * @param flsaStatus - The employee's FLSA status; owners get no placeholders.\n * @returns The merged, filtered, alphabetically sorted fixed-compensation lines.\n * @internal\n */\nexport function resolveEditableFixedCompensations(\n existingFixedCompensations: FixedCompensationEntry[] | undefined,\n fixedCompensationTypes: Array<{ name?: string | null }> | undefined,\n primaryJobUuid: string | undefined,\n flsaStatus: string | undefined,\n): FixedCompensationEntry[] {\n const merged: FixedCompensationEntry[] = [...(existingFixedCompensations ?? [])]\n\n if (flsaStatus !== FlsaStatus.OWNER && primaryJobUuid) {\n for (const compensationType of fixedCompensationTypes ?? []) {\n const name = compensationType.name\n if (!name) continue\n if (EXCLUDED_ADDITIONAL_EARNINGS.includes(name)) continue\n const exists = merged.some(entry => entry.name?.toLowerCase() === name.toLowerCase())\n if (!exists) merged.push({ name, jobUuid: primaryJobUuid })\n }\n }\n\n return merged\n .filter(entry => entry.name && !EXCLUDED_ADDITIONAL_EARNINGS.includes(entry.name))\n .sort((a, b) => (a.name ?? '').localeCompare(b.name ?? ''))\n}\n\n/**\n * Whether the employee's prepared compensation already carries non-zero\n * Overtime or Double-overtime hours.\n *\n * @remarks\n * Used to default the single `withOvertime` flag: an employee who already\n * has real overtime hours starts with the workweek split shown rather than\n * requiring an extra click to see data that's already there.\n *\n * @param hourlyCompensations - The prepared compensation's hourly lines.\n * @returns `true` when any Overtime or Double-overtime line has hours greater than zero.\n * @internal\n */\nexport function hasExistingOvertimeHours(\n hourlyCompensations: PayrollEmployeeCompensationsType['hourlyCompensations'] | undefined,\n): boolean {\n return (hourlyCompensations ?? []).some(\n compensation =>\n (compensation.name === COMPENSATION_NAME_OVERTIME ||\n compensation.name === COMPENSATION_NAME_DOUBLE_OVERTIME) &&\n parseFloat(compensation.hours ?? '0') > 0,\n )\n}\n\n/**\n * Whether a line's `breakdowns` exactly cover every workweek in `workweeks`\n * (each workweek has a breakdown entry matching both its start and end date).\n */\nfunction lineBreakdownsMatchWorkweeks(\n breakdowns: Array<{ startDate?: RFCDate; endDate?: RFCDate }> | undefined,\n workweeks: NormalizedWorkweek[],\n): boolean {\n if (!breakdowns || breakdowns.length === 0) return false\n return workweeks.every(workweek =>\n breakdowns.some(\n breakdown =>\n breakdown.startDate?.toString() === workweek.startDate &&\n breakdown.endDate?.toString() === workweek.endDate,\n ),\n )\n}\n\n/**\n * Whether any of the employee's hourly-compensation lines already carries a\n * real, per-workweek `breakdowns` array that exactly tiles the current pay\n * period's workweeks.\n *\n * @remarks\n * Used alongside {@link hasExistingOvertimeHours} to default the single\n * `withOvertime` flag: an employee whose hours are already broken down by\n * workweek (e.g. a previous edit entered real per-week values) starts with the\n * workweek split shown, seeded from those breakdowns rather than from a blank\n * or first-cell-only guess. See {@link buildWeekMap}, which applies the same\n * per-line check to decide each line's population mode.\n *\n * @param hourlyCompensations - The prepared compensation's hourly lines.\n * @param workweeks - Normalized workweeks for the pay period.\n * @returns `true` when at least one hourly line's breakdowns cover every workweek.\n * @internal\n */\nexport function hasBreakdownsMatchingWorkweeks(\n hourlyCompensations: PayrollEmployeeCompensationsType['hourlyCompensations'] | undefined,\n workweeks: NormalizedWorkweek[],\n): boolean {\n return (hourlyCompensations ?? []).some(compensation =>\n lineBreakdownsMatchWorkweeks(compensation.breakdowns, workweeks),\n )\n}\n\n/**\n * Trims an API decimal string (e.g. `\"40.000\"`, `\"500.00\"`) to a clean editable\n * value (`\"40\"`, `\"500\"`), preserving real fractional parts (`\"40.5\"`). A blank\n * or non-numeric value returns `''` (meaning \"not provided\").\n */\nfunction formatAmountInput(value: string | null | undefined): string {\n if (value == null || value === '') return ''\n const parsed = parseFloat(value)\n return Number.isNaN(parsed) ? '' : parsed.toString()\n}\n\n/**\n * Seeds a cell from a line's total: same as {@link formatAmountInput} except a\n * zero total yields `''` rather than `\"0\"`. A line whose total is zero (e.g. an\n * Overtime line with no overtime) should render as a blank cell the user can\n * fill in, not a pre-filled `0` — and a pre-filled `0` would also count as a\n * filled cell, tripping the per-row \"fill every workweek\" check for a line the\n * user never actually touched. Only used for total-seeded cells, never for real\n * per-week breakdown values (a genuine `0` breakdown must survive to keep a\n * matched split's tiling intact).\n */\nfunction formatSeededTotal(value: string | null | undefined): string {\n const formatted = formatAmountInput(value)\n return formatted === '0' ? '' : formatted\n}\n\n/**\n * Builds one job+name line's week map in one of three shapes, gated by\n * `isSplit` (`workweeks.length > 1 && isOvertimeEligible && withOvertime`):\n *\n * - Collapsed (`isSplit` false): a single key — the first workweek's start —\n * holding the total. No key is emitted for any other workweek, which is what\n * keeps a collapsed row's per-row validation a no-op (see\n * {@link createPayrollEditEmployeeSchema}).\n * - Split, breakdowns match ({@link hasBreakdownsMatchingWorkweeks} true for\n * this line): one key per workweek, each seeded from its real breakdown value.\n * - Split, no matching breakdowns: one key per workweek, with only the first\n * seeded (from the total) and the rest left blank — never auto-distributed,\n * so the user must fill them in (enforced by the schema's per-row check).\n */\nfunction buildWeekMap(\n workweeks: NormalizedWorkweek[],\n total: string | undefined,\n breakdowns:\n Array<{ startDate?: RFCDate; endDate?: RFCDate; hours?: string; amount?: string }> | undefined,\n isSplit: boolean,\n): Record<string, string> {\n const firstWorkweekStart = workweeks[0]?.startDate ?? ''\n\n if (!isSplit) {\n return { [firstWorkweekStart]: formatSeededTotal(total) }\n }\n\n const weekMap: Record<string, string> = {}\n if (lineBreakdownsMatchWorkweeks(breakdowns, workweeks)) {\n workweeks.forEach(workweek => {\n const breakdown = breakdowns?.find(\n entry => entry.startDate?.toString() === workweek.startDate,\n )\n weekMap[workweek.startDate] = formatAmountInput(breakdown?.hours ?? breakdown?.amount)\n })\n } else {\n workweeks.forEach((workweek, index) => {\n weekMap[workweek.startDate] = index === 0 ? formatSeededTotal(total) : ''\n })\n }\n return weekMap\n}\n\n/**\n * Builds a job-UUID → compensation-name → value dictionary from flat entries.\n * `Object.fromEntries` defines each key as a normal data property rather than\n * going through `[[Set]]`, so an API-supplied `__proto__`/`constructor`/\n * `prototype` key lands as an ordinary own property instead of touching\n * `Object.prototype` — unlike building the dictionary via `dict[key] = value`\n * assignment, this needs no null-prototype intermediate.\n */\nfunction buildNestedDictionary<T>(\n entries: ReadonlyArray<readonly [jobUuid: string, name: string, value: T]>,\n): Record<string, Record<string, T>> {\n const byJob = new Map<string, Array<readonly [string, T]>>()\n for (const [jobUuid, name, value] of entries) {\n const pairs = byJob.get(jobUuid)\n if (pairs) {\n pairs.push([name, value])\n } else {\n byJob.set(jobUuid, [[name, value]])\n }\n }\n return Object.fromEntries(\n Array.from(byJob, ([jobUuid, pairs]) => [jobUuid, Object.fromEntries(pairs)]),\n )\n}\n\n/**\n * Derives the form's default values from the employee's prepared compensation.\n *\n * @remarks\n * Hourly and additional earnings are expanded into per-workweek maps via\n * {@link buildWeekMap}: collapsed to the total when not split, seeded from real\n * breakdowns or first-cell-only otherwise. Time off, final payout,\n * reimbursements, and payment method are read straight off the compensation.\n *\n * @param employeeCompensation - The employee's prepared compensation, if loaded.\n * @param workweeks - Normalized workweeks for the pay period.\n * @param withOvertime - The single, form-wide overtime-mode flag (see {@link hasExistingOvertimeHours}, {@link hasBreakdownsMatchingWorkweeks}, `actions.addOvertime`). Gates splitting alongside `isOvertimeEligible`.\n * @returns Default {@link PayrollEditEmployeeFormData} for `useForm`.\n * @internal\n */\nexport function derivePayrollEditEmployeeDefaults(\n employeeCompensation: PayrollEmployeeCompensationsType | undefined,\n workweeks: NormalizedWorkweek[],\n hasDirectDepositSetup: boolean,\n overtimeEarningNames: Set<string>,\n isOvertimeEligible: boolean,\n withOvertime: boolean,\n fixedCompensations: FixedCompensationEntry[] = employeeCompensation?.fixedCompensations ?? [],\n): PayrollEditEmployeeFormData {\n // Only overtime-eligible employees split hours/earnings by workweek, and only\n // while the single `withOvertime` flag is on; everyone else renders (and\n // seeds) flat, even on a multi-workweek payroll.\n const isSplit = workweeks.length > 1 && isOvertimeEligible && withOvertime\n\n const hourEntries: Array<readonly [string, string, Record<string, string>]> = []\n for (const compensation of employeeCompensation?.hourlyCompensations ?? []) {\n if (!compensation.jobUuid || !compensation.name) continue\n hourEntries.push([\n compensation.jobUuid,\n compensation.name,\n buildWeekMap(workweeks, compensation.hours, compensation.breakdowns, isSplit),\n ])\n }\n const hours = buildNestedDictionary(hourEntries)\n\n // Earnings whose earning type is included in the regular-rate-of-pay overtime\n // calculation stay workweek-breakdown; the rest are flat and land in `overtimeExcludedEarnings`.\n // The hook owns this bucketing so the UI just renders each section.\n const overtimeIncludedEntries: Array<readonly [string, string, Record<string, string>]> = []\n const overtimeExcludedEntries: Array<readonly [string, string, string]> = []\n for (const compensation of fixedCompensations) {\n if (!compensation.jobUuid || !compensation.name) continue\n if (overtimeEarningNames.has(compensation.name)) {\n overtimeIncludedEntries.push([\n compensation.jobUuid,\n compensation.name,\n buildWeekMap(workweeks, compensation.amount, compensation.breakdowns, isSplit),\n ])\n } else {\n overtimeExcludedEntries.push([\n compensation.jobUuid,\n compensation.name,\n formatAmountInput(compensation.amount),\n ])\n }\n }\n const overtimeIncludedEarnings = buildNestedDictionary(overtimeIncludedEntries)\n const overtimeExcludedEarnings = buildNestedDictionary(overtimeExcludedEntries)\n\n const timeOff: PayrollEditEmployeeFormData['timeOff'] = {}\n const finalPayout: PayrollEditEmployeeFormData['finalPayout'] = {}\n for (const entry of employeeCompensation?.paidTimeOff ?? []) {\n if (!entry.name) continue\n timeOff[entry.name] = formatAmountInput(entry.hours)\n finalPayout[entry.name] = formatAmountInput(entry.finalPayoutUnusedHoursInput)\n }\n\n const reimbursements: PayrollEditEmployeeFormData['reimbursements'] = (\n employeeCompensation?.reimbursements ?? []\n ).map(reimbursement => ({\n uuid: reimbursement.uuid ?? null,\n description: reimbursement.description ?? '',\n amount: reimbursement.amount,\n recurring: reimbursement.recurring ?? false,\n }))\n\n return {\n hours,\n overtimeIncludedEarnings,\n overtimeExcludedEarnings,\n timeOff,\n finalPayout,\n reimbursements,\n reimbursementDraft: { description: '', amount: '' },\n paymentMethod: resolvePaymentMethod(employeeCompensation?.paymentMethod, hasDirectDepositSetup),\n }\n}\n\n/**\n * Resolves the default payment method, mirroring the stable component (#2683):\n * an employee with no direct deposit set up defaults to (and is forced to)\n * `Check`, even when the prepared payroll carried `Direct Deposit` or nothing.\n * `Historical` is treated as unset. The result is always `Direct Deposit` or\n * `Check` — never `Historical` — since those are the only values the update\n * endpoint accepts.\n */\nfunction resolvePaymentMethod(\n paymentMethod: string | null | undefined,\n hasDirectDepositSetup: boolean,\n): PayrollUpdatePaymentMethod {\n if (paymentMethod === PayrollUpdatePaymentMethod.Check) return PayrollUpdatePaymentMethod.Check\n if (paymentMethod === PayrollUpdatePaymentMethod.DirectDeposit && hasDirectDepositSetup) {\n return PayrollUpdatePaymentMethod.DirectDeposit\n }\n return hasDirectDepositSetup\n ? PayrollUpdatePaymentMethod.DirectDeposit\n : PayrollUpdatePaymentMethod.Check\n}\n\nfunction originalTotals<T extends { jobUuid?: string; name?: string }>(\n compensations: T[] | undefined,\n selectTotal: (compensation: T) => string | null | undefined,\n): Map<string, string> {\n const totals = new Map<string, string>()\n for (const compensation of compensations ?? []) {\n if (!compensation.jobUuid || !compensation.name) continue\n totals.set(`${compensation.jobUuid}|${compensation.name}`, selectTotal(compensation) ?? '')\n }\n return totals\n}\n\n// Precision of the per-workweek values being summed: dollar amounts carry cents,\n// hours up to six places.\nconst AMOUNT_DECIMALS = 2\nconst HOURS_DECIMALS = 6\n\n/**\n * Sums per-workweek input values in integer minor units, then scales back.\n *\n * @remarks\n * Each value is already bounded to `decimals` places, so scaling it to an\n * integer (cents for amounts, millionths for hours) and summing those integers\n * is exact. Float-accumulating the decimals directly and rounding at the end\n * would instead leak binary error into the wire value (e.g. `0.1 + 0.2` →\n * `\"0.30000000000000004\"`), which the payroll API should never receive.\n */\nfunction sumWeekValues(\n weekMap: Record<string, string>,\n workweeks: NormalizedWorkweek[],\n decimals: number,\n): string {\n const factor = 10 ** decimals\n const totalMinorUnits = workweeks.reduce((total, workweek) => {\n const value = parseFloat(weekMap[workweek.startDate] ?? '0') || 0\n return total + Math.round(value * factor)\n }, 0)\n return String(totalMinorUnits / factor)\n}\n\n/**\n * Returns a copy of one week-mapped section (`hours` or `overtimeIncludedEarnings`)\n * with every cell that loaded with a value but is now empty coerced to `\"0\"`, so a\n * user who clears a pre-filled workweek input submits an explicit zero for it rather\n * than leaving it blank. \"Loaded with a value\" means the matching cell in `defaults`\n * is non-empty; a cell that was blank at load is left untouched (it stays subject to\n * the per-row \"fill every workweek\" validation). Returns `null` when nothing changed,\n * so the caller can skip a redundant form update.\n */\nfunction zeroFillClearedSection(\n current: Record<string, Record<string, Record<string, string>>>,\n defaults: Record<string, Record<string, Record<string, string>>>,\n): Record<string, Record<string, Record<string, string>>> | null {\n let changed = false\n const next: Record<string, Record<string, Record<string, string>>> = {}\n for (const [jobUuid, names] of Object.entries(current)) {\n const nextNames: Record<string, Record<string, string>> = {}\n for (const [name, weekMap] of Object.entries(names)) {\n const nextWeekMap: Record<string, string> = {}\n for (const [week, value] of Object.entries(weekMap)) {\n const loaded = defaults[jobUuid]?.[name]?.[week]\n if (value === '' && loaded != null && loaded !== '') {\n nextWeekMap[week] = '0'\n changed = true\n } else {\n nextWeekMap[week] = value\n }\n }\n nextNames[name] = nextWeekMap\n }\n next[jobUuid] = nextNames\n }\n return changed ? next : null\n}\n\n/**\n * Coerces cleared-from-loaded workweek cells to `\"0\"` across both week-mapped\n * sections (`hours`, `overtimeIncludedEarnings`).\n *\n * @remarks\n * Run just before submit: a workweek input that loaded with a value and was\n * cleared by the user should submit an explicit `0` for that cell (whether split\n * by workweek or collapsed to a single box), instead of falling back to the\n * original value or being blocked by the per-row completeness check. Cells that\n * were blank at load are untouched. Each returned section is present only when it\n * actually changed, so the caller can `setValue` selectively.\n *\n * @param current - The live form values.\n * @param defaults - The form's loaded defaults (the API-seeded baseline for the current split mode).\n * @returns The coerced `hours` and/or `overtimeIncludedEarnings` sections, each omitted when unchanged.\n * @internal\n */\nexport function zeroFillClearedWorkweekCells(\n current: Pick<PayrollEditEmployeeFormData, 'hours' | 'overtimeIncludedEarnings'>,\n defaults: Pick<PayrollEditEmployeeFormData, 'hours' | 'overtimeIncludedEarnings'>,\n): Partial<Pick<PayrollEditEmployeeFormData, 'hours' | 'overtimeIncludedEarnings'>> {\n const hours = zeroFillClearedSection(current.hours, defaults.hours)\n const overtimeIncludedEarnings = zeroFillClearedSection(\n current.overtimeIncludedEarnings,\n defaults.overtimeIncludedEarnings,\n )\n return {\n ...(hours ? { hours } : {}),\n ...(overtimeIncludedEarnings ? { overtimeIncludedEarnings } : {}),\n }\n}\n\n/**\n * Builds the `PayrollUpdate` employee-compensation payload from form values.\n *\n * @remarks\n * When the pay period spans a single workweek (or the employee isn't split by\n * workweek), totals are sent without `breakdowns`. When split, each hourly and\n * additional-earning line is decided independently — per line, not per job\n * (the API models breakdowns on each compensation line, not as a per-job\n * all-or-nothing unit):\n *\n * - A fully-filled line (every workweek cell has a value) sends `breakdowns`\n * tiling every workweek exactly, with the total equal to the sum of the\n * per-week values.\n * - An entirely blank line sends nothing for it — no `breakdowns`, no\n * fabricated `0`, no fabricated total — leaving it as the flat, untouched\n * value it already was.\n * - A partial line (some but not all cells filled) can never reach this\n * function: {@link createPayrollEditEmployeeSchema}'s per-row check blocks\n * submit until every cell in a touched row is filled.\n *\n * @param formData - Current parsed form values.\n * @param employeeCompensation - The prepared compensation, for identifying metadata (`version`, `employeeUuid`).\n * @param workweeks - Normalized workweeks for the pay period.\n * @param payrollCategory - The payroll category, gating itemized vs. off-cycle reimbursements.\n * @param isOvertimeEligible - Whether the employee is overtime-eligible (nonexempt family).\n * @param withOvertime - The single, form-wide overtime-mode flag. Gates splitting alongside `isOvertimeEligible` and `workweeks.length > 1`; when `false`, every line submits its flat (collapsed) value regardless of eligibility.\n * @returns The employee-compensation entry for the `PayrollUpdate` request body.\n * @internal\n */\nexport function buildPayrollUpdateEmployeeCompensation(\n formData: PayrollEditEmployeeFormOutputs,\n employeeCompensation: PayrollEmployeeCompensationsType | undefined,\n workweeks: NormalizedWorkweek[],\n payrollCategory: PayrollCategory,\n isOvertimeEligible: boolean,\n withOvertime: boolean,\n): PayrollUpdateEmployeeCompensations {\n // Breakdowns are emitted only when the line is actually split by workweek:\n // multiple workweeks, an overtime-eligible employee, and `withOvertime` on.\n // This must match the field builder's gate so what renders and what submits\n // never drift.\n const isSplit = workweeks.length > 1 && isOvertimeEligible && withOvertime\n const hasValue = (value: string | undefined) => value != null && value !== ''\n const originalHours = originalTotals(\n employeeCompensation?.hourlyCompensations,\n comp => comp.hours,\n )\n const originalAmounts = originalTotals(\n employeeCompensation?.fixedCompensations,\n comp => comp.amount,\n )\n const isRowFilled = (weekMap: Record<string, string>) =>\n workweeks.every(workweek => hasValue(weekMap[workweek.startDate]))\n const collapsedValue = (\n jobUuid: string,\n name: string,\n weekMap: Record<string, string>,\n originals: Map<string, string>,\n ) => {\n const single = weekMap[workweeks[0]?.startDate ?? '']\n return hasValue(single) ? single! : (originals.get(`${jobUuid}|${name}`) ?? '0')\n }\n\n const hourlyCompensations = Object.entries(formData.hours).flatMap(([jobUuid, names]) =>\n Object.entries(names).flatMap(([name, weekMap]) => {\n if (!isSplit) {\n return [{ jobUuid, name, hours: collapsedValue(jobUuid, name, weekMap, originalHours) }]\n }\n if (!isRowFilled(weekMap)) return []\n return [\n {\n jobUuid,\n name,\n hours: sumWeekValues(weekMap, workweeks, HOURS_DECIMALS),\n breakdowns: workweeks.map(workweek => ({\n startDate: new RFCDate(workweek.startDate),\n endDate: new RFCDate(workweek.endDate),\n hours: weekMap[workweek.startDate]!,\n })),\n },\n ]\n }),\n )\n\n const breakdownEarnings = Object.entries(formData.overtimeIncludedEarnings).flatMap(\n ([jobUuid, names]) =>\n Object.entries(names).flatMap(([name, weekMap]) => {\n if (!isSplit) {\n return [\n { jobUuid, name, amount: collapsedValue(jobUuid, name, weekMap, originalAmounts) },\n ]\n }\n if (!isRowFilled(weekMap)) return []\n return [\n {\n jobUuid,\n name,\n amount: sumWeekValues(weekMap, workweeks, AMOUNT_DECIMALS),\n breakdowns: workweeks.map(workweek => ({\n startDate: new RFCDate(workweek.startDate),\n endDate: new RFCDate(workweek.endDate),\n amount: weekMap[workweek.startDate]!,\n })),\n },\n ]\n }),\n )\n\n // Non-overtime earnings never carry breakdowns; they are sent as flat totals.\n const flatEarnings = Object.entries(formData.overtimeExcludedEarnings).flatMap(\n ([jobUuid, names]) =>\n Object.entries(names).map(([name, amount]) => ({\n jobUuid,\n name,\n amount: hasValue(amount) ? amount : (originalAmounts.get(`${jobUuid}|${name}`) ?? '0'),\n })),\n )\n\n const fixedCompensations = [...breakdownEarnings, ...flatEarnings]\n\n const isDismissal = payrollCategory === PayrollCategory.Dismissal\n const paidTimeOff = Object.entries(formData.timeOff).map(([name, value]) => ({\n name,\n hours: value || '0',\n ...(isDismissal && formData.finalPayout[name] != null\n ? { finalPayoutUnusedHoursInput: formData.finalPayout[name] || '0' }\n : {}),\n }))\n\n const usesItemizedReimbursements = !isOffCyclePayroll(payrollCategory)\n\n return {\n employeeUuid: employeeCompensation?.employeeUuid,\n version: employeeCompensation?.version as string | undefined,\n excluded: employeeCompensation?.excluded,\n memo: employeeCompensation?.memo || undefined,\n ...(formData.paymentMethod ? { paymentMethod: formData.paymentMethod } : {}),\n hourlyCompensations,\n fixedCompensations,\n paidTimeOff,\n ...(usesItemizedReimbursements\n ? { reimbursements: cleanupReimbursements(formData.reimbursements) }\n : {}),\n }\n}\n"],"names":["normalizeWorkweeks","workweeks","payPeriod","normalized","week","SDKInternalError","collectOvertimeEarningNames","earningTypeList","names","earningType","resolveEditableFixedCompensations","existingFixedCompensations","fixedCompensationTypes","primaryJobUuid","flsaStatus","merged","FlsaStatus","compensationType","name","EXCLUDED_ADDITIONAL_EARNINGS","entry","b","hasExistingOvertimeHours","hourlyCompensations","compensation","COMPENSATION_NAME_OVERTIME","COMPENSATION_NAME_DOUBLE_OVERTIME","lineBreakdownsMatchWorkweeks","breakdowns","breakdown","workweek","hasBreakdownsMatchingWorkweeks","formatAmountInput","value","parsed","formatSeededTotal","formatted","buildWeekMap","total","isSplit","firstWorkweekStart","weekMap","index","buildNestedDictionary","entries","byJob","jobUuid","pairs","derivePayrollEditEmployeeDefaults","employeeCompensation","hasDirectDepositSetup","overtimeEarningNames","isOvertimeEligible","withOvertime","fixedCompensations","hourEntries","hours","overtimeIncludedEntries","overtimeExcludedEntries","overtimeIncludedEarnings","overtimeExcludedEarnings","timeOff","finalPayout","reimbursements","reimbursement","resolvePaymentMethod","paymentMethod","PayrollUpdatePaymentMethod","originalTotals","compensations","selectTotal","totals","AMOUNT_DECIMALS","HOURS_DECIMALS","sumWeekValues","decimals","factor","totalMinorUnits","zeroFillClearedSection","current","defaults","changed","next","nextNames","nextWeekMap","loaded","zeroFillClearedWorkweekCells","buildPayrollUpdateEmployeeCompensation","formData","payrollCategory","hasValue","originalHours","comp","originalAmounts","isRowFilled","collapsedValue","originals","single","RFCDate","breakdownEarnings","flatEarnings","amount","isDismissal","PayrollCategory","paidTimeOff","usesItemizedReimbursements","isOffCyclePayroll","cleanupReimbursements"],"mappings":"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"}
|