diff --git a/example/src/Onboarding.tsx b/example/src/Onboarding.tsx index 1104c2237..c944a8819 100644 --- a/example/src/Onboarding.tsx +++ b/example/src/Onboarding.tsx @@ -90,6 +90,7 @@ const MultiStepForm = ({ components, onboardingBag }: MultiStepFormProps) => { BackButton, SelectCountryStep, EngagementAgreementDetailsStep, + PreviewEmploymentAgreementStep, } = components; const [errors, setErrors] = useState<{ apiError: string; @@ -268,6 +269,27 @@ const MultiStepForm = ({ components, onboardingBag }: MultiStepFormProps) => { ); } + case 'employment_agreement_preview': { + return ( + <> + +
+ setErrors({ apiError: '', fieldErrors: [] })} + > + Previous Step + + setErrors({ apiError: '', fieldErrors: [] })} + > + Continue + +
+ + ); + } case 'review': return ( ( + options?: Options, +) => + (options?.client ?? client).get< + GetV1EmployeeBankAccountResponses, + GetV1EmployeeBankAccountErrors, + ThrowOnError + >({ + security: [{ scheme: 'bearer', type: 'http' }], + url: '/v1/employee/bank-account', + ...options, + }); + +/** + * Update employee bank account + * + * Upserts the authenticated employee's bank account details. + * + * This endpoint requires and returns country-specific data. The exact fields vary depending on which + * country the authenticated employee's employment is in. Query the + * [Show form schema](#tag/Countries/operation/get_show_form_country) endpoint with `bank_account_details` + * as the form name to discover the schema for a given country. + * + * + * + * ## Scopes + * + * | Category | Read only Scope | Write only Scope (read access implicit) | + * |---|---|---| + * | Manage employments (`employments`) | - | Manage bank accounts (`bank_account:write`) | + * + */ +export const putV1EmployeeBankAccount = ( + options?: Options, +) => + (options?.client ?? client).put< + PutV1EmployeeBankAccountResponses, + PutV1EmployeeBankAccountErrors, + ThrowOnError + >({ + security: [{ scheme: 'bearer', type: 'http' }], + url: '/v1/employee/bank-account', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options?.headers, + }, + }); + /** * Get Help Center Article * @@ -1802,7 +1897,7 @@ export const getV1ContractorsEmploymentsEmploymentIdContractorSubscriptions = < * * | Category | Read only Scope | Write only Scope (read access implicit) | * |---|---|---| - * | Manage payroll runs (`payroll`) | View payslips (`payslip:read`) | - | + * | Manage employment documents (`employment_documents`) | View payslips (`payslip:read`) | - | * */ export const getV1EmployeePayslips = ( @@ -1818,6 +1913,38 @@ export const getV1EmployeePayslips = ( ...options, }); +/** + * List contractor of record (COR) termination requests + * + * Lists Contractor of Record termination requests for your company, + * optionally filtered by employment and status. + * + * + * ## Scopes + * + * | Category | Read only Scope | Write only Scope (read access implicit) | + * |---|---|---| + * | Manage employments (`employments`) | View employments (`employment:read`) | Manage employments (`employment:write`) | + * + */ +export const getV1ContractorsCorTerminationRequests = < + ThrowOnError extends boolean = false, +>( + options?: Options, +) => + (options?.client ?? client).get< + GetV1ContractorsCorTerminationRequestsResponses, + GetV1ContractorsCorTerminationRequestsErrors, + ThrowOnError + >({ + security: [ + { scheme: 'bearer', type: 'http' }, + { scheme: 'bearer', type: 'http' }, + ], + url: '/v1/contractors/cor-termination-requests', + ...options, + }); + /** * List Webhook Events * @@ -2707,6 +2834,57 @@ export const postV1MagicLink = ( }, }); +/** + * Get basic information + * + * Returns the employment's basic information. + * + * This endpoint requires and returns country-specific data. The exact required and returned fields will + * vary depending on which country the employment is in. To see the list of parameters for each country, + * see the **Show form schema** endpoint under the [Countries](#tag/Countries) category. + * + * Please note that the compliance requirements for each country are subject to change according to local + * laws. Given its continual updates, using Remote's [json-schema-form](https://developer.remote.com/docs/how-json-schemas-work) should be considered in order to avoid + * compliance issues and to have the latest version of a country requirements. + * + * If you are using this endpoint to build an integration, make sure you are dynamically collecting or + * displaying the latest parameters for each country by querying the _"Show form schema"_ endpoint. + * + * For more information on JSON Schemas, see the **How JSON Schemas work** documentation. + * + * To learn how you can dynamically generate forms to display in your UI, see the documentation for + * the [json-schema-form](https://developer.remote.com/docs/how-json-schemas-work) tool. + * + * + * + * ## Scopes + * + * | Category | Read only Scope | Write only Scope (read access implicit) | + * |---|---|---| + * | Manage employments (`employments`) | View employments (`employment:read`) | Manage employments (`employment:write`) | + * + */ +export const getV2EmploymentsEmploymentIdBasicInformation = < + ThrowOnError extends boolean = false, +>( + options: Options< + GetV2EmploymentsEmploymentIdBasicInformationData, + ThrowOnError + >, +) => + (options.client ?? client).get< + GetV2EmploymentsEmploymentIdBasicInformationResponses, + GetV2EmploymentsEmploymentIdBasicInformationErrors, + ThrowOnError + >({ + security: [ + { scheme: 'bearer', type: 'http' }, + { scheme: 'bearer', type: 'http' }, + ], + url: '/v2/employments/{employment_id}/basic_information', + ...options, + }); + /** * Update basic information * @@ -3921,6 +4099,44 @@ export const postV1ContractAmendments = ( }, }); +/** + * Download the Employment Agreement for an employment + * + * Downloads a PDF of the auto-generated Employment Agreement for an employment. + * + * The document is rendered as a draft (no signatures) and is not persisted. EA preview is only + * available for countries that have a published Employment Agreement automation template — see the + * `employment_agreement_preview_available` flag on the [Countries](#tag/Countries) endpoint. + * + * + * ## Scopes + * + * | Category | Read only Scope | Write only Scope (read access implicit) | + * |---|---|---| + * | Manage employment documents (`employment_documents`) | View documents (`document:read`) | Manage documents (`document:write`) | + * + */ +export const getV1EmploymentsEmploymentIdEmploymentAgreementDownload = < + ThrowOnError extends boolean = false, +>( + options: Options< + GetV1EmploymentsEmploymentIdEmploymentAgreementDownloadData, + ThrowOnError + >, +) => + (options.client ?? client).get< + GetV1EmploymentsEmploymentIdEmploymentAgreementDownloadResponses, + GetV1EmploymentsEmploymentIdEmploymentAgreementDownloadErrors, + ThrowOnError + >({ + security: [ + { scheme: 'bearer', type: 'http' }, + { scheme: 'bearer', type: 'http' }, + ], + url: '/v1/employments/{employment_id}/employment-agreement/download', + ...options, + }); + /** * Show Company Payroll Runs * @@ -4250,9 +4466,11 @@ export const postV1EmployeeTimeoffIdCancel = < * - pricing_plan_details * - company_basic_information * - global_payroll_administrative_details + * - global_payroll_bank_account_details * - global_payroll_basic_information * - global_payroll_contract_details * - global_payroll_federal_taxes + * - global_payroll_state_taxes * - global_payroll_personal_details * - benefit_renewal_request * - hris_personal_details @@ -4935,7 +5153,7 @@ export const postV1TimesheetsTimesheetIdApprove = < * * | Category | Read only Scope | Write only Scope (read access implicit) | * |---|---|---| - * | Manage payroll runs (`payroll`) | View payslips (`payslip:read`) | - | + * | Manage employment documents (`employment_documents`) | View payslips (`payslip:read`) | - | * */ export const getV1PayslipsId = ( @@ -5072,6 +5290,36 @@ export const postV1CompanyDepartments = ( }, }); +/** + * List Offboardings for Employment + * + * Lists Offboarding requests for a specific employment. + * + * ## Scopes + * + * | Category | Read only Scope | Write only Scope (read access implicit) | + * |---|---|---| + * | Manage employments (`employments`) | View offboarding requests (`offboarding:read`) | Manage offboarding (`offboarding:write`) | + * + */ +export const getV1OffboardingsEmploymentsEmploymentId = < + ThrowOnError extends boolean = false, +>( + options: Options, +) => + (options.client ?? client).get< + GetV1OffboardingsEmploymentsEmploymentIdResponses, + GetV1OffboardingsEmploymentsEmploymentIdErrors, + ThrowOnError + >({ + security: [ + { scheme: 'bearer', type: 'http' }, + { scheme: 'bearer', type: 'http' }, + ], + url: '/v1/offboardings/employments/{employment_id}', + ...options, + }); + /** * Decline a time off cancellation request * @@ -6020,7 +6268,7 @@ export const getV1Countries = ( * * | Category | Read only Scope | Write only Scope (read access implicit) | * |---|---|---| - * | Manage payroll runs (`payroll`) | View payslips (`payslip:read`) | - | + * | Manage employment documents (`employment_documents`) | View payslips (`payslip:read`) | - | * */ export const getV1EmployeePayslipFiles = ( @@ -6258,6 +6506,39 @@ export const postV1CostCalculatorEstimationCsv = < }, }); +/** + * Activate Global Payroll for a legal entity + * + * Enables the Global Payroll product on a legal entity so that GP employees can be created against it. + * + * Performs three idempotent steps: + * * Adds the Global Payroll product to the company. + * * Flips `global_payroll_enabled` on the legal entity's settings. + * * Ensures a Global Payroll pricing plan exists for the legal entity's country. + * + * This endpoint is only available in Sandbox, otherwise it will respond with a 404. + * + */ +export const postV1SandboxCompaniesCompanyIdLegalEntitiesLegalEntityIdActivateGlobalPayroll = + ( + options: Options< + PostV1SandboxCompaniesCompanyIdLegalEntitiesLegalEntityIdActivateGlobalPayrollData, + ThrowOnError + >, + ) => + (options.client ?? client).post< + PostV1SandboxCompaniesCompanyIdLegalEntitiesLegalEntityIdActivateGlobalPayrollResponses, + PostV1SandboxCompaniesCompanyIdLegalEntitiesLegalEntityIdActivateGlobalPayrollErrors, + ThrowOnError + >({ + security: [ + { scheme: 'bearer', type: 'http' }, + { scheme: 'bearer', type: 'http' }, + ], + url: '/v1/sandbox/companies/{company_id}/legal-entities/{legal_entity_id}/activate-global-payroll', + ...options, + }); + /** * Show employee personal details * @@ -6426,7 +6707,7 @@ export const postV1SandboxWebhookCallbacksTrigger = < * * | Category | Read only Scope | Write only Scope (read access implicit) | * |---|---|---| - * | Manage payroll runs (`payroll`) | View payslips (`payslip:read`) | - | + * | Manage employment documents (`employment_documents`) | View payslips (`payslip:read`) | - | * */ export const getV1PayslipsPayslipIdPdf = ( @@ -8168,7 +8449,7 @@ export const getV1ProbationExtensionsId = < * * | Category | Read only Scope | Write only Scope (read access implicit) | * |---|---|---| - * | Manage payroll runs (`payroll`) | View payslips (`payslip:read`) | - | + * | Manage employment documents (`employment_documents`) | View payslips (`payslip:read`) | - | * */ export const getV1Payslips = ( @@ -9050,6 +9331,47 @@ export const postV1ContractorInvoiceSchedules = < }, }); +/** + * Submit employee state taxes + * + * Submits the authenticated employee's US state tax withholding answers for a + * single jurisdiction (e.g. `NY`). + * + * Available for US Global Payroll employees once they reach the post-enrollment + * state, at which point the per-jurisdiction state tax task exists. + * + * This endpoint requires country/jurisdiction-specific data. Query the + * [Show form schema](#tag/Countries/operation/get_show_form_country) endpoint with `global_payroll_state_taxes` + * as the form name to discover the schema for a given country. + * + * + * + * ## Scopes + * + * | Category | Read only Scope | Write only Scope (read access implicit) | + * |---|---|---| + * | Manage employments (`employments`) | - | Manage personal details (`personal_detail:write`) | + * + */ +export const putV1EmployeeStateTaxesJurisdiction = < + ThrowOnError extends boolean = false, +>( + options: Options, +) => + (options.client ?? client).put< + PutV1EmployeeStateTaxesJurisdictionResponses, + PutV1EmployeeStateTaxesJurisdictionErrors, + ThrowOnError + >({ + security: [{ scheme: 'bearer', type: 'http' }], + url: '/v1/employee/state-taxes/{jurisdiction}', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers, + }, + }); + /** * Get engagement agreement details * @@ -9163,6 +9485,44 @@ export const getV1BillingDocumentsBillingDocumentIdBreakdown = < ...options, }); +/** + * Preview the Employment Agreement for an employment + * + * Returns a base64-encoded PDF preview of the auto-generated Employment Agreement for an employment. + * + * The document is rendered as a draft (no signatures) and is not persisted. EA preview is only + * available for countries that have a published Employment Agreement automation template — see the + * `employment_agreement_preview_available` flag on the [Countries](#tag/Countries) endpoint. + * + * + * ## Scopes + * + * | Category | Read only Scope | Write only Scope (read access implicit) | + * |---|---|---| + * | Manage employment documents (`employment_documents`) | View documents (`document:read`) | Manage documents (`document:write`) | + * + */ +export const getV1EmploymentsEmploymentIdEmploymentAgreementPreview = < + ThrowOnError extends boolean = false, +>( + options: Options< + GetV1EmploymentsEmploymentIdEmploymentAgreementPreviewData, + ThrowOnError + >, +) => + (options.client ?? client).get< + GetV1EmploymentsEmploymentIdEmploymentAgreementPreviewResponses, + GetV1EmploymentsEmploymentIdEmploymentAgreementPreviewErrors, + ThrowOnError + >({ + security: [ + { scheme: 'bearer', type: 'http' }, + { scheme: 'bearer', type: 'http' }, + ], + url: '/v1/employments/{employment_id}/employment-agreement/preview', + ...options, + }); + /** * Indexes all the documents for the employee * diff --git a/src/client/types.gen.ts b/src/client/types.gen.ts index d72313340..2edfbd6ba 100644 --- a/src/client/types.gen.ts +++ b/src/client/types.gen.ts @@ -674,6 +674,48 @@ export type CompanyComplianceProfile = { | 'unresponsive'; }; +/** + * CorTerminationRequest + */ +export type CorTerminationRequest = { + /** + * Timestamp of when the termination was cancelled. Null if not cancelled. + */ + cancelled_at: string | null; + /** + * The date on which the contractor employment will be deactivated. + */ + employment_deactivation_date: string | null; + /** + * UuidSlug + * + * Identifier of the employment being terminated. + */ + employment_id: string; + /** + * Timestamp of when the termination was executed. Null if not yet executed. + */ + executed_at: string | null; + /** + * UuidSlug + * + * Unique identifier of the termination request. + */ + id: string; + /** + * Timestamp of when the termination request was initiated. + */ + initiated_at: string | null; + /** + * Current status of the termination request. + */ + status: 'initiated' | 'executed' | 'cancelled'; + /** + * The date when the termination was initiated. + */ + termination_date: string | null; +}; + /** * ResignationOrTerminationOffboarding */ @@ -2354,6 +2396,10 @@ export type Country = { * Administrative subdivisions of the country (e.g., states, provinces, districts). Null if the country has no subdivisions relevant to Remote's services. */ country_subdivisions?: Array | null; + /** + * Whether an Employment Agreement preview is available for this country. + */ + employment_agreement_preview_available?: boolean; /** * Whether EOR (Employer of Record) onboarding is available in this country. */ @@ -3452,9 +3498,13 @@ export type CostCalculatorCountryLevelRegion = { /** * CreateWebhookCallbackParams * - * Webhook callback creation params + * Webhook callback creation params. Provide either `subscribed_events` or `subscribe_to_all_events: true` (they are mutually exclusive). */ export type CreateWebhookCallbackParams = { + /** + * When true, subscribe this callback to all current and future event types. Cannot be combined with `subscribed_events`. + */ + subscribe_to_all_events?: boolean; subscribed_events?: Array< | 'background_check.status.updated' | 'benefit_renewal_request.created' @@ -5803,8 +5853,8 @@ export type ResourceErrorResponse = { | 'parameter_value_unknown' | 'request_body_empty' | 'request_internal_server_error' - | 'parameter_required_missing' | 'parameter_one_of_required_missing' + | 'parameter_required_missing' | 'parameter_too_many' | 'parameter_unknown' | 'parameter_map_empty' @@ -6782,6 +6832,10 @@ export type NullableCountry = { * Administrative subdivisions of the country (e.g., states, provinces, districts). Null if the country has no subdivisions relevant to Remote's services. */ country_subdivisions?: Array | null; + /** + * Whether an Employment Agreement preview is available for this country. + */ + employment_agreement_preview_available?: boolean; /** * Whether EOR (Employer of Record) onboarding is available in this country. */ @@ -7554,7 +7608,7 @@ export type ListCompanyPricingPlansResponse = { /** * UuidSlug * - * Unique identifier of the termination request. + * Identifier of the employment being terminated. */ export type UuidSlug = string; @@ -7717,6 +7771,20 @@ export type Timesheet = { weekend_hours: HoursAndMinutes; }; +/** + * EmploymentAgreementPreviewResponse + * + * Return a base64 encoded Employment Agreement preview document + */ +export type EmploymentAgreementPreviewResponse = { + data: { + employment_agreement: { + content: Blob | File; + name: string; + }; + }; +}; + /** * Benefit * @@ -9052,6 +9120,10 @@ export type WebhookCallback = { * */ signing_key?: string; + /** + * When true, this callback is subscribed to all current and future event types. `subscribed_events` then lists every currently supported event. + */ + subscribe_to_all_events?: boolean; subscribed_events?: Array< | 'background_check.status.updated' | 'benefit_renewal_request.created' @@ -9382,6 +9454,29 @@ export type UnauthorizedResponse = { message: string; }; +/** + * IndexCorTerminationRequestsResponse + * + * Response schema listing many termination_requests + */ +export type IndexCorTerminationRequestsResponse = { + data?: { + /** + * The current page among all of the total_pages + */ + current_page?: number; + termination_requests?: Array; + /** + * The total number of records in the result + */ + total_count?: number; + /** + * The total number of pages the user can go through + */ + total_pages?: number; + }; +}; + /** * PricingPlanDetails * @@ -10785,10 +10880,14 @@ export type CreateContractEligibilityParams = { /** * UpdateWebhookCallbackParams * - * Webhook callback update params + * Webhook callback update params. Provide either `subscribed_events` or `subscribe_to_all_events` (they are mutually exclusive). Omitting `subscribe_to_all_events` leaves the current subscription mode unchanged, so resending an event list does not disable all-events delivery. Setting `subscribe_to_all_events: false` requires a non-empty `subscribed_events`. */ export type UpdateWebhookCallbackParams = { - subscribed_events: Array< + /** + * When true, subscribe this callback to all current and future event types. Cannot be combined with `subscribed_events`. + */ + subscribe_to_all_events?: boolean; + subscribed_events?: Array< | 'background_check.status.updated' | 'benefit_renewal_request.created' | 'billing_document.issued' @@ -11238,6 +11337,24 @@ export type CompanyNotEligibleForCreationErrorResponse = { resource_type?: string; }; +/** + * EmploymentStateTaxesParams + * + * State taxes schema compatible params, submitted one jurisdiction at a time. + * + */ +export type EmploymentStateTaxesParams = { + /** + * State taxes params for the jurisdiction in the path. As its properties vary depending + * on the country and jurisdiction, you must query the + * [Show form schema](#tag/Countries/operation/get_show_form_country) endpoint passing the country code + * and `global_payroll_state_taxes` as path parameters. + */ + state_taxes: { + [key: string]: unknown; + }; +}; + /** * MinimalContractAmendment * @@ -11910,6 +12027,13 @@ export type EmploymentDetailsOnlyResponse = { contract_details?: { [key: string]: unknown; }; + /** + * Origin of the employment contract. Returned by the basic information endpoint. + */ + contract_origin?: + | 'remote_contract' + | 'custom_remote_contract' + | 'provided_by_customer'; /** * Emergency contact information. Its properties may vary depending on the country. Null if the employee has not submitted their emergency contact yet. */ @@ -12123,38 +12247,7 @@ export type PayDifference = { * CorTerminationRequestResponse */ export type CorTerminationRequestResponse = { - data: { - /** - * Timestamp of when the termination was cancelled. Null if not cancelled. - */ - cancelled_at: string | null; - /** - * The date on which the contractor employment will be deactivated. - */ - employment_deactivation_date: string | null; - /** - * Timestamp of when the termination was executed. Null if not yet executed. - */ - executed_at: string | null; - /** - * UuidSlug - * - * Unique identifier of the termination request. - */ - id: string; - /** - * Timestamp of when the termination request was initiated. - */ - initiated_at: string | null; - /** - * Current status of the termination request. - */ - status: 'initiated' | 'executed' | 'cancelled'; - /** - * The date when the termination was initiated. - */ - termination_date: string | null; - }; + data: CorTerminationRequest; }; /** @@ -13300,6 +13393,109 @@ export type GetV1CompaniesCompanyIdEmploymentsEmploymentIdOnboardingReservesStat export type GetV1CompaniesCompanyIdEmploymentsEmploymentIdOnboardingReservesStatusResponse = GetV1CompaniesCompanyIdEmploymentsEmploymentIdOnboardingReservesStatusResponses[keyof GetV1CompaniesCompanyIdEmploymentsEmploymentIdOnboardingReservesStatusResponses]; +export type GetV1EmployeeBankAccountData = { + body?: never; + path?: never; + query?: { + /** + * Version of the bank_account_details form schema + */ + bank_account_details_json_schema_version?: number | 'latest'; + }; + url: '/v1/employee/bank-account'; +}; + +export type GetV1EmployeeBankAccountErrors = { + /** + * Bad Request + */ + 400: BadRequestResponse; + /** + * Unauthorized + */ + 401: UnauthorizedResponse; + /** + * Forbidden + */ + 403: ForbiddenResponse; + /** + * Not Found + */ + 404: NotFoundResponse; + /** + * Unprocessable Entity + */ + 429: TooManyRequestsResponse; +}; + +export type GetV1EmployeeBankAccountError = + GetV1EmployeeBankAccountErrors[keyof GetV1EmployeeBankAccountErrors]; + +export type GetV1EmployeeBankAccountResponses = { + /** + * Success + */ + 200: EmploymentDetailsOnlyResponse; +}; + +export type GetV1EmployeeBankAccountResponse = + GetV1EmployeeBankAccountResponses[keyof GetV1EmployeeBankAccountResponses]; + +export type PutV1EmployeeBankAccountData = { + /** + * Employee bank account details params + */ + body?: EmploymentBankAccountDetailsParams; + path?: never; + query?: { + /** + * Version of the bank_account_details form schema + */ + bank_account_details_json_schema_version?: number | 'latest'; + }; + url: '/v1/employee/bank-account'; +}; + +export type PutV1EmployeeBankAccountErrors = { + /** + * Bad Request + */ + 400: BadRequestResponse; + /** + * Unauthorized + */ + 401: UnauthorizedResponse; + /** + * Forbidden + */ + 403: ForbiddenResponse; + /** + * Not Found + */ + 404: NotFoundResponse; + /** + * Unprocessable Entity + */ + 422: UnprocessableEntityResponse; + /** + * Unprocessable Entity + */ + 429: TooManyRequestsResponse; +}; + +export type PutV1EmployeeBankAccountError = + PutV1EmployeeBankAccountErrors[keyof PutV1EmployeeBankAccountErrors]; + +export type PutV1EmployeeBankAccountResponses = { + /** + * Success + */ + 200: EmploymentDetailsOnlyResponse; +}; + +export type PutV1EmployeeBankAccountResponse = + PutV1EmployeeBankAccountResponses[keyof PutV1EmployeeBankAccountResponses]; + export type GetV1HelpCenterArticlesIdData = { body?: never; path: { @@ -13995,6 +14191,54 @@ export type GetV1EmployeePayslipsResponses = { export type GetV1EmployeePayslipsResponse = GetV1EmployeePayslipsResponses[keyof GetV1EmployeePayslipsResponses]; +export type GetV1ContractorsCorTerminationRequestsData = { + body?: never; + path?: never; + query?: { + /** + * Filter termination requests by employment ID. + */ + employment_id?: UuidSlug; + /** + * Filter termination requests by status. + */ + status?: 'initiated' | 'executed' | 'cancelled'; + /** + * Starts fetching records after the given page + */ + page?: number; + /** + * Number of items per page + */ + page_size?: number; + }; + url: '/v1/contractors/cor-termination-requests'; +}; + +export type GetV1ContractorsCorTerminationRequestsErrors = { + /** + * Forbidden + */ + 403: ForbiddenResponse; + /** + * Not Found + */ + 404: NotFoundResponse; +}; + +export type GetV1ContractorsCorTerminationRequestsError = + GetV1ContractorsCorTerminationRequestsErrors[keyof GetV1ContractorsCorTerminationRequestsErrors]; + +export type GetV1ContractorsCorTerminationRequestsResponses = { + /** + * Success + */ + 200: IndexCorTerminationRequestsResponse; +}; + +export type GetV1ContractorsCorTerminationRequestsResponse = + GetV1ContractorsCorTerminationRequestsResponses[keyof GetV1ContractorsCorTerminationRequestsResponses]; + export type GetV1WebhookEventsData = { body?: never; path?: never; @@ -15430,6 +15674,59 @@ export type PostV1MagicLinkResponses = { export type PostV1MagicLinkResponse = PostV1MagicLinkResponses[keyof PostV1MagicLinkResponses]; +export type GetV2EmploymentsEmploymentIdBasicInformationData = { + body?: never; + path: { + /** + * Employment ID + */ + employment_id: string; + }; + query?: { + /** + * Version of the employment_basic_information form schema + */ + employment_basic_information_json_schema_version?: number | 'latest'; + }; + url: '/v2/employments/{employment_id}/basic_information'; +}; + +export type GetV2EmploymentsEmploymentIdBasicInformationErrors = { + /** + * Bad Request + */ + 400: BadRequestResponse; + /** + * Forbidden + */ + 403: ForbiddenResponse; + /** + * Not Found + */ + 404: NotFoundResponse; + /** + * Unprocessable Entity + */ + 422: UnprocessableEntityResponse; + /** + * Unprocessable Entity + */ + 429: TooManyRequestsResponse; +}; + +export type GetV2EmploymentsEmploymentIdBasicInformationError = + GetV2EmploymentsEmploymentIdBasicInformationErrors[keyof GetV2EmploymentsEmploymentIdBasicInformationErrors]; + +export type GetV2EmploymentsEmploymentIdBasicInformationResponses = { + /** + * Success + */ + 200: EmploymentDetailsOnlyResponse; +}; + +export type GetV2EmploymentsEmploymentIdBasicInformationResponse = + GetV2EmploymentsEmploymentIdBasicInformationResponses[keyof GetV2EmploymentsEmploymentIdBasicInformationResponses]; + export type PutV2EmploymentsEmploymentIdBasicInformationData = { /** * Employment basic information params @@ -17053,6 +17350,46 @@ export type PostV1ContractAmendmentsResponses = { export type PostV1ContractAmendmentsResponse = PostV1ContractAmendmentsResponses[keyof PostV1ContractAmendmentsResponses]; +export type GetV1EmploymentsEmploymentIdEmploymentAgreementDownloadData = { + body?: never; + path: { + /** + * Employment ID + */ + employment_id: string; + }; + query?: never; + url: '/v1/employments/{employment_id}/employment-agreement/download'; +}; + +export type GetV1EmploymentsEmploymentIdEmploymentAgreementDownloadErrors = { + /** + * Unauthorized + */ + 401: UnauthorizedResponse; + /** + * Not Found + */ + 404: NotFoundResponse; + /** + * Unprocessable Entity + */ + 422: UnprocessableEntityResponse; +}; + +export type GetV1EmploymentsEmploymentIdEmploymentAgreementDownloadError = + GetV1EmploymentsEmploymentIdEmploymentAgreementDownloadErrors[keyof GetV1EmploymentsEmploymentIdEmploymentAgreementDownloadErrors]; + +export type GetV1EmploymentsEmploymentIdEmploymentAgreementDownloadResponses = { + /** + * Success + */ + 200: GenericFile; +}; + +export type GetV1EmploymentsEmploymentIdEmploymentAgreementDownloadResponse = + GetV1EmploymentsEmploymentIdEmploymentAgreementDownloadResponses[keyof GetV1EmploymentsEmploymentIdEmploymentAgreementDownloadResponses]; + export type GetV1PayrollRunsPayrollRunIdData = { body?: never; path: { @@ -17513,9 +17850,13 @@ export type GetV1CountriesCountryCodeFormData = { }; query?: { /** - * Required for `contract_amendment` form + * Required for `contract_amendment` and `global_payroll_state_taxes` forms */ employment_id?: string; + /** + * Two-letter US state code. Required for `global_payroll_state_taxes` (e.g. `NY`). + */ + jurisdiction?: string; /** * FOR TESTING PURPOSES ONLY: Include scheduled benefit groups. */ @@ -18736,6 +19077,63 @@ export type PostV1CompanyDepartmentsResponses = { export type PostV1CompanyDepartmentsResponse = PostV1CompanyDepartmentsResponses[keyof PostV1CompanyDepartmentsResponses]; +export type GetV1OffboardingsEmploymentsEmploymentIdData = { + body?: never; + path: { + /** + * Employment ID + */ + employment_id: string; + }; + query?: { + /** + * Starts fetching records after the given page + */ + page?: number; + /** + * Change the amount of records returned per page, defaults to 20, limited to 100 + */ + page_size?: number; + }; + url: '/v1/offboardings/employments/{employment_id}'; +}; + +export type GetV1OffboardingsEmploymentsEmploymentIdErrors = { + /** + * Bad Request + */ + 400: BadRequestResponse; + /** + * Unauthorized + */ + 401: UnauthorizedResponse; + /** + * Not Found + */ + 404: NotFoundResponse; + /** + * Unprocessable Entity + */ + 422: UnprocessableEntityResponse; + /** + * Too many requests + */ + 429: TooManyRequestsResponse; +}; + +export type GetV1OffboardingsEmploymentsEmploymentIdError = + GetV1OffboardingsEmploymentsEmploymentIdErrors[keyof GetV1OffboardingsEmploymentsEmploymentIdErrors]; + +export type GetV1OffboardingsEmploymentsEmploymentIdResponses = { + /** + * Success + */ + 200: ListOffboardingResponse; +}; + +export type GetV1OffboardingsEmploymentsEmploymentIdResponse = + GetV1OffboardingsEmploymentsEmploymentIdResponses[keyof GetV1OffboardingsEmploymentsEmploymentIdResponses]; + export type PostV1TimeoffTimeoffIdCancelRequestDeclineData = { /** * Timeoff @@ -20485,6 +20883,61 @@ export type PostV1CostCalculatorEstimationCsvResponses = { export type PostV1CostCalculatorEstimationCsvResponse = PostV1CostCalculatorEstimationCsvResponses[keyof PostV1CostCalculatorEstimationCsvResponses]; +export type PostV1SandboxCompaniesCompanyIdLegalEntitiesLegalEntityIdActivateGlobalPayrollData = + { + body?: never; + path: { + /** + * Company ID + */ + company_id: string; + /** + * Legal Entity ID to activate Global Payroll on + */ + legal_entity_id: string; + }; + query?: never; + url: '/v1/sandbox/companies/{company_id}/legal-entities/{legal_entity_id}/activate-global-payroll'; + }; + +export type PostV1SandboxCompaniesCompanyIdLegalEntitiesLegalEntityIdActivateGlobalPayrollErrors = + { + /** + * Bad Request + */ + 400: BadRequestResponse; + /** + * Unauthorized + */ + 401: UnauthorizedResponse; + /** + * Not Found + */ + 404: NotFoundResponse; + /** + * Unprocessable Entity + */ + 422: UnprocessableEntityResponse; + /** + * Too many requests + */ + 429: TooManyRequestsResponse; + }; + +export type PostV1SandboxCompaniesCompanyIdLegalEntitiesLegalEntityIdActivateGlobalPayrollError = + PostV1SandboxCompaniesCompanyIdLegalEntitiesLegalEntityIdActivateGlobalPayrollErrors[keyof PostV1SandboxCompaniesCompanyIdLegalEntitiesLegalEntityIdActivateGlobalPayrollErrors]; + +export type PostV1SandboxCompaniesCompanyIdLegalEntitiesLegalEntityIdActivateGlobalPayrollResponses = + { + /** + * Success + */ + 200: SuccessResponse; + }; + +export type PostV1SandboxCompaniesCompanyIdLegalEntitiesLegalEntityIdActivateGlobalPayrollResponse = + PostV1SandboxCompaniesCompanyIdLegalEntitiesLegalEntityIdActivateGlobalPayrollResponses[keyof PostV1SandboxCompaniesCompanyIdLegalEntitiesLegalEntityIdActivateGlobalPayrollResponses]; + export type GetV1EmployeePersonalDetailsData = { body?: never; path?: never; @@ -24896,6 +25349,61 @@ export type PostV1ContractorInvoiceSchedulesResponses = { export type PostV1ContractorInvoiceSchedulesResponse = PostV1ContractorInvoiceSchedulesResponses[keyof PostV1ContractorInvoiceSchedulesResponses]; +export type PutV1EmployeeStateTaxesJurisdictionData = { + /** + * Employee state taxes params + */ + body?: EmploymentStateTaxesParams; + path: { + /** + * Two-letter US state/jurisdiction code + */ + jurisdiction: string; + }; + query?: never; + url: '/v1/employee/state-taxes/{jurisdiction}'; +}; + +export type PutV1EmployeeStateTaxesJurisdictionErrors = { + /** + * Bad Request + */ + 400: BadRequestResponse; + /** + * Unauthorized + */ + 401: UnauthorizedResponse; + /** + * Forbidden + */ + 403: ForbiddenResponse; + /** + * Not Found + */ + 404: NotFoundResponse; + /** + * Unprocessable Entity + */ + 422: UnprocessableEntityResponse; + /** + * Unprocessable Entity + */ + 429: TooManyRequestsResponse; +}; + +export type PutV1EmployeeStateTaxesJurisdictionError = + PutV1EmployeeStateTaxesJurisdictionErrors[keyof PutV1EmployeeStateTaxesJurisdictionErrors]; + +export type PutV1EmployeeStateTaxesJurisdictionResponses = { + /** + * Success + */ + 200: SuccessResponse; +}; + +export type PutV1EmployeeStateTaxesJurisdictionResponse = + PutV1EmployeeStateTaxesJurisdictionResponses[keyof PutV1EmployeeStateTaxesJurisdictionResponses]; + export type GetV1EmploymentsEmploymentIdEngagementAgreementDetailsData = { body?: never; path: { @@ -25052,6 +25560,46 @@ export type GetV1BillingDocumentsBillingDocumentIdBreakdownResponses = { export type GetV1BillingDocumentsBillingDocumentIdBreakdownResponse = GetV1BillingDocumentsBillingDocumentIdBreakdownResponses[keyof GetV1BillingDocumentsBillingDocumentIdBreakdownResponses]; +export type GetV1EmploymentsEmploymentIdEmploymentAgreementPreviewData = { + body?: never; + path: { + /** + * Employment ID + */ + employment_id: string; + }; + query?: never; + url: '/v1/employments/{employment_id}/employment-agreement/preview'; +}; + +export type GetV1EmploymentsEmploymentIdEmploymentAgreementPreviewErrors = { + /** + * Unauthorized + */ + 401: UnauthorizedResponse; + /** + * Not Found + */ + 404: NotFoundResponse; + /** + * Unprocessable Entity + */ + 422: UnprocessableEntityResponse; +}; + +export type GetV1EmploymentsEmploymentIdEmploymentAgreementPreviewError = + GetV1EmploymentsEmploymentIdEmploymentAgreementPreviewErrors[keyof GetV1EmploymentsEmploymentIdEmploymentAgreementPreviewErrors]; + +export type GetV1EmploymentsEmploymentIdEmploymentAgreementPreviewResponses = { + /** + * Success + */ + 200: EmploymentAgreementPreviewResponse; +}; + +export type GetV1EmploymentsEmploymentIdEmploymentAgreementPreviewResponse = + GetV1EmploymentsEmploymentIdEmploymentAgreementPreviewResponses[keyof GetV1EmploymentsEmploymentIdEmploymentAgreementPreviewResponses]; + export type GetV1EmployeeDocumentsData = { body?: never; path?: never; diff --git a/src/flows/Onboarding/OnboardingFlow.tsx b/src/flows/Onboarding/OnboardingFlow.tsx index fdcfab949..6c1b28361 100644 --- a/src/flows/Onboarding/OnboardingFlow.tsx +++ b/src/flows/Onboarding/OnboardingFlow.tsx @@ -13,6 +13,7 @@ import { ReviewStep } from '@/src/flows/Onboarding/components/ReviewStep'; import { SaveDraftButton } from '@/src/flows/Onboarding/components/SaveDraftButton'; import { EngagementAgreementDetailsStep } from '@/src/flows/Onboarding/components/EngagementAgreementDetailsStep'; import { PreOnboardingRequirements } from '@/src/flows/Onboarding/components/PreOnboardingRequirements'; +import { PreviewEmploymentAgreementStep } from '@/src/flows/Onboarding/components/PreviewEmploymentAgreementStep'; export const OnboardingFlow = ({ employmentId, @@ -68,6 +69,7 @@ export const OnboardingFlow = ({ SelectCountryStep: SelectCountryStep, ReviewStep: ReviewStep, PreOnboardingRequirements: PreOnboardingRequirements, + PreviewEmploymentAgreementStep: PreviewEmploymentAgreementStep, }, })} diff --git a/src/flows/Onboarding/api.ts b/src/flows/Onboarding/api.ts index 19db49c8b..d81de3e64 100644 --- a/src/flows/Onboarding/api.ts +++ b/src/flows/Onboarding/api.ts @@ -415,6 +415,8 @@ export const useCountriesSchemaField = ( return { label: country.name, value: country.code, + employment_agreement_preview_available: + country.employment_agreement_preview_available, }; }) || [] ); @@ -440,6 +442,7 @@ export const useCountriesSchemaField = ( return { isLoading, selectCountryForm, + countries, }; }; diff --git a/src/flows/Onboarding/components/PreviewEmploymentAgreementStep.tsx b/src/flows/Onboarding/components/PreviewEmploymentAgreementStep.tsx new file mode 100644 index 000000000..d6cd728bb --- /dev/null +++ b/src/flows/Onboarding/components/PreviewEmploymentAgreementStep.tsx @@ -0,0 +1,14 @@ +import { useOnboardingContext } from '@/src/flows/Onboarding/context'; +import { OnboardingForm } from '@/src/flows/Onboarding/components/OnboardingForm'; + +export function PreviewEmploymentAgreementStep() { + const { onboardingBag } = useOnboardingContext(); + + const handleSubmit = async () => { + onboardingBag?.next(); + }; + + // this step in theory shouldn't be a form, not sure yet... + + return ; +} diff --git a/src/flows/Onboarding/hooks.tsx b/src/flows/Onboarding/hooks.tsx index e796c908b..06c03ccc1 100644 --- a/src/flows/Onboarding/hooks.tsx +++ b/src/flows/Onboarding/hooks.tsx @@ -63,6 +63,7 @@ const stepToFormSchemaMap: Record = { engagement_agreement_details: null, contract_details: 'contract_details', benefits: null, + employment_agreement_preview: null, review: null, }; @@ -165,12 +166,21 @@ export const useOnboarding = ({ const [internalCountryCode, setInternalCountryCode] = useState( countryCode || null, ); + const [ includeEngagementAgreementDetails, setIncludeEngagementAgreementDetails, ] = useState(false); + const [ + includeEmploymentAgreementPreview, + setIncludeEmploymentAgreementPreview, + ] = useState(false); + const useDynamicSteps = options?.features?.includes('dynamic_steps') ?? false; + const useEAPreview = + options?.features?.includes('ea_preview') && + includeEmploymentAgreementPreview; const { steps, stepsArray } = useMemo( () => @@ -178,8 +188,14 @@ export const useOnboarding = ({ includeSelectCountry: !skipSteps?.includes('select_country'), includeEngagementAgreementDetails, useDynamicSteps, + useEAPreview, }), - [includeEngagementAgreementDetails, skipSteps, useDynamicSteps], + [ + includeEngagementAgreementDetails, + skipSteps, + useDynamicSteps, + useEAPreview, + ], ); const onStepChange = useCallback( @@ -260,12 +276,14 @@ export const useOnboarding = ({ contract_details: NestedMeta; benefits: NestedMeta; engagement_agreement_details: NestedMeta; + employment_agreement_preview: NestedMeta; }>({ select_country: {}, basic_information: {}, contract_details: {}, benefits: {}, engagement_agreement_details: {}, + employment_agreement_preview: {}, }); const { @@ -331,13 +349,27 @@ export const useOnboarding = ({ isErrorPreOnboardingRequirements, ]); - const { selectCountryForm, isLoading: isLoadingCountries } = - useCountriesSchemaField({ - jsfModify: options?.jsfModify?.select_country, - queryOptions: { - enabled: stepState.currentStep.name === 'select_country', - }, - }); + const { + selectCountryForm, + isLoading: isLoadingCountries, + countries, + } = useCountriesSchemaField({ + jsfModify: options?.jsfModify?.select_country, + queryOptions: { + enabled: stepState.currentStep.name === 'select_country', + }, + }); + + const isEmploymentAgreementPreviewAvailable = useMemo(() => { + return Boolean( + countries?.find((country) => country.value === internalCountryCode) + ?.employment_agreement_preview_available, + ); + }, [countries, internalCountryCode]); + + useEffect(() => { + setIncludeEmploymentAgreementPreview(isEmploymentAgreementPreviewAvailable); + }, [isEmploymentAgreementPreviewAvailable]); const createEmploymentMutation = useCreateEmployment(options); const updateEmploymentMutation = useUpdateEmployment( @@ -577,6 +609,7 @@ export const useOnboarding = ({ engagementAgreementDetailsSchema?.fields || [], contract_details: contractDetailsForm?.fields || [], benefits: benefitOffersSchema?.fields || [], + employment_agreement_preview: [], review: [], }), [ @@ -598,6 +631,7 @@ export const useOnboarding = ({ engagementAgreementDetailsSchema?.meta['x-jsf-fieldsets'], contract_details: contractDetailsForm?.meta['x-jsf-fieldsets'], benefits: null, + employment_agreement_preview: null, review: null, }; @@ -611,6 +645,7 @@ export const useOnboarding = ({ engagementAgreementDetailsSchema?.meta?.['x-jsf-presentation'], contract_details: contractDetailsForm?.meta?.['x-jsf-presentation'], benefits: benefitOffersSchema?.meta?.['x-jsf-presentation'], + employment_agreement_preview: null, review: null, }; @@ -707,6 +742,7 @@ export const useOnboarding = ({ ) : contractDetailsInitialValues, benefits: benefitsInitialValues, + employment_agreement_preview: {}, }; } return { @@ -714,6 +750,7 @@ export const useOnboarding = ({ basic_information: basicInformationInitialValues, contract_details: contractDetailsInitialValues, benefits: benefitsInitialValues, + employment_agreement_preview: {}, }; }, [ selectCountryInitialValues, @@ -792,6 +829,7 @@ export const useOnboarding = ({ stepFields.benefits, { skipMoneyConversion: true }, ), + employment_agreement_preview: {}, }; setStepValues({ @@ -800,6 +838,7 @@ export const useOnboarding = ({ contract_details: contractDetailsInitialValues, benefits: benefitsInitialValues, engagement_agreement_details: engagementAgreementDetailsInitialValues, + employment_agreement_preview: {}, review: {}, }); diff --git a/src/flows/Onboarding/tests/utils.test.ts b/src/flows/Onboarding/tests/utils.test.ts index 6d5c2302e..0acb07466 100644 --- a/src/flows/Onboarding/tests/utils.test.ts +++ b/src/flows/Onboarding/tests/utils.test.ts @@ -147,14 +147,11 @@ describe('buildSteps', () => { describe('new dynamic behavior (useDynamicSteps: true)', () => { it('should preserve original indices for all steps including hidden ones', () => { - const { steps, stepsArray } = buildSteps({ + const { stepsArray } = buildSteps({ includeSelectCountry: false, useDynamicSteps: true, }); - // All steps should be present, including hidden ones - expect(stepsArray).toHaveLength(6); - // Hidden step should still be in the array with original index expect(stepsArray[0]).toMatchObject({ name: 'select_country', @@ -181,11 +178,23 @@ describe('buildSteps', () => { visible: true, }); - // Steps object should preserve original indices - expect(steps.select_country.index).toBe(0); - expect(steps.basic_information.index).toBe(1); - expect(steps.contract_details.index).toBe(3); - expect(steps.review.index).toBe(5); + expect(stepsArray[4]).toMatchObject({ + name: 'benefits', + index: 4, + visible: true, + }); + + expect(stepsArray[5]).toMatchObject({ + name: 'employment_agreement_preview', + index: 5, + visible: false, + }); + + expect(stepsArray[6]).toMatchObject({ + name: 'review', + index: 6, + visible: true, + }); }); it('should include engagement_agreement_details when enabled', () => { @@ -195,13 +204,26 @@ describe('buildSteps', () => { useDynamicSteps: true, }); - expect(stepsArray).toHaveLength(6); expect(stepsArray[2]).toMatchObject({ name: 'engagement_agreement_details', index: 2, visible: true, }); }); + + it('should include employment_agreement_preview when enabled', () => { + const { stepsArray } = buildSteps({ + includeSelectCountry: true, + useEAPreview: true, + useDynamicSteps: true, + }); + + expect(stepsArray[5]).toMatchObject({ + name: 'employment_agreement_preview', + index: 5, + visible: true, + }); + }); }); describe('backwards compatibility', () => { diff --git a/src/flows/Onboarding/types.ts b/src/flows/Onboarding/types.ts index 0a4fe4f81..5084e0150 100644 --- a/src/flows/Onboarding/types.ts +++ b/src/flows/Onboarding/types.ts @@ -16,6 +16,7 @@ import { ReviewStep } from '@/src/flows/Onboarding/components/ReviewStep'; import { SaveDraftButton } from '@/src/flows/Onboarding/components/SaveDraftButton'; import { EngagementAgreementDetailsStep } from '@/src/flows/Onboarding/components/EngagementAgreementDetailsStep'; import { PreOnboardingRequirements } from '@/src/flows/Onboarding/components/PreOnboardingRequirements'; +import { PreviewEmploymentAgreementStep } from '@/src/flows/Onboarding/components/PreviewEmploymentAgreementStep'; export type OnboardingRenderProps = { /** @@ -40,6 +41,7 @@ export type OnboardingRenderProps = { * @see {@link ReviewStep} * @see {@link SaveDraftButton} * @see {@link PreOnboardingRequirements} + * @see {@link PreviewEmploymentAgreementStep} */ components: { SubmitButton: typeof OnboardingSubmit; @@ -53,10 +55,14 @@ export type OnboardingRenderProps = { ReviewStep: typeof ReviewStep; SaveDraftButton: typeof SaveDraftButton; PreOnboardingRequirements: typeof PreOnboardingRequirements; + PreviewEmploymentAgreementStep: typeof PreviewEmploymentAgreementStep; }; }; -type OnboardingFeatures = 'onboarding_reserves' | 'dynamic_steps'; +type OnboardingFeatures = + | 'onboarding_reserves' + | 'dynamic_steps' + | 'ea_preview'; /** * JSON schema version configuration for a specific country diff --git a/src/flows/Onboarding/utils.ts b/src/flows/Onboarding/utils.ts index 69b4057bf..0cdeeee45 100644 --- a/src/flows/Onboarding/utils.ts +++ b/src/flows/Onboarding/utils.ts @@ -7,12 +7,14 @@ export type StepKeys = | 'engagement_agreement_details' | 'contract_details' | 'benefits' + | 'employment_agreement_preview' | 'review'; type StepConfig = { includeSelectCountry?: boolean; includeEngagementAgreementDetails?: boolean; useDynamicSteps?: boolean; + useEAPreview?: boolean; }; export function buildSteps(config: StepConfig = {}) { @@ -46,6 +48,11 @@ export function buildSteps(config: StepConfig = {}) { label: 'Benefits', visible: true, }, + { + name: 'employment_agreement_preview', + label: 'Preview Employment Agreement', + visible: Boolean(config?.useEAPreview), + }, { name: 'review', label: 'Review',