Availability and leave
Import availability rows from a mapped spreadsheet
/a/Availability_import
Import availability rows from a mapped spreadsheet
When to use this endpoint
Bulk-create or update availability events from positional spreadsheet rows. The CRM2 import widget parses the file and sends JSON row data; the endpoint does not upload or parse a spreadsheet file itself.
Authentication and permissions
Authenticate with signed API-key fields or a logged-in CRM session. Uses the authenticated tenant’s data. Requires pageAvailability_add for inserted rows and pageAvailability_edit for updated rows; the whole batch’s required actions are checked before any row writes. Client administrators and full-access roles are allowed. Other roleless users are denied; signed API keys use the key owner’s role. These are page/action permissions, not an employee-ownership or HR-profile approver-list restriction.
Management calls reject accounts with features2.disableHREnhancements=1, returning HR enhancements are disabled. The helper reads the account’s current global feature value before falling back to session values. Browser permission checks are not server-side authorization.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
v | Integer | Yes | Integer-converted value at least 2. Lower/missing values fail before authentication. |
map | JSON array text | Yes | Each entry is an object with to. Its array index selects the corresponding row cell; the decorative from header is not used to find cells. Mapping must include obj_type, event_type, start_e and end_e, even for updates. Allowed destinations: id, obj_type, obj_id, event_type, availability, status, name, start_e, end_e, all_day, paid, requested_by, notes. Unknown/blank destinations are ignored; later duplicate destinations overwrite earlier ones. |
rows | JSON array text | Yes | Array of positional row arrays. Empty [] is accepted with Add permission and still produces an import-log entry. For a mapped ID >0, update an existing non-deleted tenant row; missing/nonpositive mapped IDs create. Row validation failures are accumulated while later rows continue. |
filename | String | No | Nonblank original file label is stored in import-log metadata. It does not locate/open a server file. |
Example request
$result = FM_api('Availability_import', [
'v' => '2',
'map' => json_encode([
['from' => 'Target', 'to' => 'obj_type'],
['from' => 'User ID', 'to' => 'obj_id'],
['from' => 'Type', 'to' => 'event_type'],
['from' => 'Start', 'to' => 'start_e'],
['from' => 'End', 'to' => 'end_e'],
['from' => 'Status', 'to' => 'status'],
]),
'rows' => json_encode([
['user', '71', 'Annual Leave', '1793005200', '1793034000', 'Approved'],
]),
'filename' => 'availability.csv',
]);
Example response
{"ok":1,"inserts":1,"updates":0}
Returns inserts/updates counters, optionally errors. No inserted ID list or import token is returned. Row failures look like {"ok":1,"inserts":0,"updates":0,"errors":[[0,[{"msg":"invalid event_type","val":"Bad row"}]]]}; the first value is the input row’s zero-based index for ordinary row arrays. Check errors even when ok=1.
Counters increment only after confirmed successful primary writes. Failed rows add an error and do not run row recalculation; later rows continue. Import-history or post-save recalculation failures add saved=1 and a warning. Accepted rows remain committed when others fail; do not blindly replay a partially accepted import.
Errors and unusual responses
| Response | Condition |
|---|---|
{"error":"not logged in"} | No authenticated tenant context is available. Invalid signed credentials can be rejected by the dispatcher before the handler runs. |
{"error":"permission denied"} | The authenticated actor lacks the required page/action permission. |
{"error":"missing or invalid parameter: v"} | Integer-converted version below 2, before login. |
{"error":"missing or invalid parameter: map"} | Missing map before login, or map does not decode to a PHP array after login. |
{"error":"missing or invalid parameter: rows"} | Missing rows before login, or rows does not decode to an array after login. |
{"error":"HR enhancements are disabled"} | The account has disabled HR enhancements. |
{"error":"The import map is missing the \"FIELD\" field."} | First missing destination among obj_type, event_type, start_e, end_e. FIELD is replaced with that actual name. Event/payload validation errors are instead returned inside errors for individual rows. |
{"ok":1,"inserts":0,"updates":0,"errors":[[0,[{"msg":"Unable to save availability event","val":1}]]]} | The first inserted row’s primary write failed. Failed writes are excluded from the counters. |
Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.
Behaviour and edge cases
- Cell values are trimmed strings. Target/event keys are lower-cased, spaces/hyphens replaced with underscores, and non-alphanumeric/underscore characters removed. For example Annual Leave becomes annual_leave.
- Only exactly ten decimal digits are directly recognized as Unix seconds. Empty/"0" becomes zero; other time text uses PHP strtotime in the server’s current timezone, so use explicit timezone-bearing ISO text or ten-digit epochs. All-day normalization subsequently uses the account timezone.
- all_day/paid are true only for 1, yes, y, true, on (case-insensitive). availability is true only for 1, available, yes, y, true; on is not in that allowlist. Status names pending/approved/rejected/cancelled/canceled map to 0/1/2/3; unrecognized status text uses intval and can become pending rather than an error.
- An existing event supplies omitted destination defaults. A mapped blank cell is a supplied value and may clear text or fail validation rather than inherit. Existing metadata is preserved, with edited_by_import_id added; new rows receive created_by_import_id. Metadata is not an import destination.
- The import saves content directly, not through mapped create/update. It does not recompute meta.leave_days or send legacy/configured transition notifications. Approved annual-leave balance recalculation is still called for old/new rows. No transaction spans the batch, primary writes, balances, or import history.
- The primary write is checked before dependent work. After saving, failed recalculation or notification work retains the normal success fields and adds
saved=1andwarning. Do not repeat the write to repair a follow-up; re-read the event and investigate balances/notification history. The event, history, balances and external queues are not one atomic transaction.
Side effects
- Attempts per-row inserts/updates, sets last_edited, and on insert cdate/created_by; newly approved rows get current actor/time as approval attribution. Invalidates availability_events cache for attempted row writes.
- When an old or new event is approved annual leave, the helper recalculates affected users’ stored annual-leave usage for touched years, using current company/department/role/user membership. Each account-local date touched counts as one whole day except dates in
week-days-off(0 Sunday through 6 Saturday). Partial dates count as full days, year boundaries are split, and calendar arithmetic preserves DST dates. Overlapping leave events contribute separately; balances may become negative. Supported recalculation years are the server’s current year minus five through plus ten. - Adds a tenant imports_log row with import_type=46, token-derived cdate, creation/edit counts, actor ID and optional filename metadata. Individual events receive created_by_import_id or edited_by_import_id. This is import history, not a Core_log row audit or tenant deletion audit.
See it in Fieldmotion
CRM1
No direct CRM1 caller for Availability_import was found in the source search. The implemented management screen is CRM2’s Availability page.
CRM2
In Availability, choose Import. The widget uses map type 46, sends v=2, and checks the four required mapping destinations before calling Availability_import. Follow the row-error report rather than relying only on the UI’s Import Successful message.
Related endpoints
Availability_getExportData: export fields before editing spreadsheet values.Availability_getDataTable: inspect imported records and filters.Availability_createData: single-event CRM2 creation with configured notifications.