Full-Sheet Submission in Journyx 10.1m1 and Above
This page is about the legacy SOAP-based jxAPI that is no longer updated or recommended for use in new projects. The documentation in this section may be outdated or inaccurate, and is provided for reference purposes only.
Journyx recommends using the REST-based API for new projects in most cases. However, at the current time, there are certain object types that are not available through the REST API.
Starting with Journyx 10.1m1, a new set of API methods focusing on full-sheet submission is available. These methods provide an API workflow that is similar to the way the Journyx web interface handles sheet editing and submission, rather than the low-level, record-based access required in previous versions of the jxAPI. If your usage of the jxAPI involves modifying, submitting, and approving sheets, this new API may be beneficial to you.
The advantages of using the sheet-based API include:
- Data is structured in the familiar "rows of cells" arrangement used in the web UI
- A single API transaction can add or modify entries for multiple rows at once
- Corrections and correction notes are handled for audit levels that require them
- In/out times are supported for users with allocation entry screens
- DVT and many customer-specific customizations are supported including returning errors to the client and blocking submission
- No need to understand the structure and semantics of the Journyx database
Workflow
The basic full-sheet workflow consists of retrieving column data (if needed) and storing it for later use, retrieving a period, modifying one of the sheets in that period, saving and submitting the sheet, displaying the results to the user, and repeating.
First, for clients that need to allow a user to enter time or expenses, call the
getDisplaySettings
,
getAllColumnRecords
,
getAllProjectDependencies
, and
getAllColumnDependencies
methods to get the data you will need to properly display an entry screen to the
user, populate and filter column data, and the like. Since this data tends to
change much less frequently than sheet entries, you can cache it on the client
side with a fairly long refresh interval.
Then, fetch a particular day's sheets with the
getPeriodForDate
method. Use the
dates
field of the sheet to determine the exact dates covered by the user's
current period, as well as when the previous period ended and when the next one
starts. (The DisplaySettings
structure obtained in the previous step has
fields that determine whether you should allow an interactive user to navigate
between periods.) Note that creating a sheet yourself isn't supported -- always
fetch a period with getPeriodForDate
or an existing sheet with
getSheet
and modify that, otherwise the results
may be unpredictable.
Modify existing rows or add new ones as you like. Don't reorder existing rows,
and make sure to preserve the column_data
field of the sheet, otherwise the
server may duplicate existing rows or add new ones that you didn't intend. If
the audit level requires correction notes, make sure to add one to any cell you
have modified if the sheet has been submitted before. (See the audit_settings
field of the sheet for the flags governing this.)
Save the sheet with save_sheet
. Issues raised
by the Data Validation Tool and other business logic will be reflected in the
SheetSaveResult
structure returned from this method. Check the success
flag,
and the status
and errors
arrays for messages describing what happened. If
you have a cached copy of the sheet, replace it with the one returned in the
sheet
field of the SheetSaveResult
, in case business logic on the server
modified it.
Sheet-Based jxAPI Methods
The primary interface to full sheet submission is the save_sheet
method:
save_sheet
save_sheet(sheet: Sheet, submit: boolean) -> SheetSaveResult
This method saves, and optionally submits for approval, a sheet to the server. It is functionally similar to modifying some data in the web user interface then pressing the Save or Submit button.
It returns a SheetSaveResult
structure:
Field | Type | Description |
---|---|---|
sheet | Sheet | The current contents of the sheet after the save/submit operation has completed. |
success | boolean | True if the operation was successful. |
status | string[] | A list of status messages from the operation, if any. |
errors | string[] | A list of error messages from the operation, if any. |
punch_sheet
punch_sheet(sheet_id: string, inout: boolean) -> SheetSaveResult
For use when the user's default time sheet user interface is punch-only, this
method is equivalent to clicking the punch in/out button in the web browser.
Like save_sheet
, it returns a SheetSaveResult
containing the updated
contents of the sheet.
getPeriodForDate
getPeriodForDate(date: string, full_sheets: boolean) -> Period
This method returns all three of a user's sheets for a specified date. (Note that they may not cover the same date range if the period lengths and starting dates are different!) The return is a Period structure:
Field | Type | Description |
---|---|---|
time_sheet | Sheet | The user's time sheet for the specified date |
expense_sheet | Sheet | The user's expense sheet for the specified date |
custom_sheet | Sheet | The user's custom sheet for the specified date |
getSheet
getSheet(sheet_type: string, sheet_id: string) -> Sheet
This method returns a single sheet, given its ID. The sheet_type
parameter
should be one of "time", "expense", or "custom", and the sheet_id
parameter is
the sheet's ID.
The Sheet Structure
Sheet
The Sheet
structure includes almost all of the information that is displayed
in the user's web browser while using Journyx, as well as metadata useful to
clients. The "Save?" column of the table below indicates whether that field is
used when saving a sheet; fields marked with "no" cannot be modified by
save_sheet
but will be ignored if sent back to the server.
Field | Type | Save? | Description |
---|---|---|---|
id | string | no | The sheet's ID. |
user | string | no | The user's ID. |
user_login | string | no | The user's login. |
user_name | string | no | The user's full name. |
type | string | no | The sheet type ("time", "expense", or "mileage".) |
dates | string[] | no | All dates in the sheet, in YYYYMMDD format. |
state | string | no | One of "open", "submitted", "approved", "rejected", or "other". |
status | string | no | A message describing the sheet status. |
approver | string | no | The user ID of the next approver. |
level | int | no | The level of the next approver. |
reason | string | no | A message describing the reason the sheet was rejected. |
total | double | no | The total of the hours, expenses, etc. in the sheet. |
modified_at | string | no | An ISO8601 date describing when certain parts of the sheet were last modified. |
audit_settings | SheetAuditSettings | no | The current audit level settings for this sheet. |
rows | SheetRow[] | yes* | A SheetRow structure representing each row in the sheet. |
punchlists | SheetPunchList[] | yes | A SheetPunchList structure for each date in the sheet (corresponding to the date's position in dates ). |
column_data | string | yes | A binary value which you must preserve and include when saving a modified sheet. |
can_be_submitted | boolean | no | Indicates whether the sheet can be submitted. May be useful in deciding whether to show a submit button. |
Note that you must preserve and send back the column_data
field of the sheet,
along with preserving the order of existing rows, for modifications to work
properly. Failure to do this will likely result in rows being duplicated or
added erroneously, especially if you have changed any of the combo
(project/code/comment) data.
The modified_at
date may be used to help determine when you should
automatically refresh a sheet from the server, but because not all possible
modifications are tracked by the server database it is possible for this date
not to be updated for certain changes (punch times, for example). Watch out for
false negatives and if you are building a user facing client, consider providing
a manual refresh option for users who also use the web interface.
SheetRow
A SheetRow
represents one row of the sheet. That is, it has a single
project/code/comment combo and a cell for each date in the sheet. Note that
which column corresponds to "code0", "code1", and "code2" is dependent on the
order specified in the user's display settings.
Field | Type | Save? | Description |
---|---|---|---|
project | string | yes | The project ID. |
project_name | string | no | The project displayed name. |
code0 | string | yes | The first code ID (in order of display settings). |
code0_name | string | no | The first code displayed name. |
code1 | string | yes | The second code ID. |
code1_name | string | no | The second code displayed name. |
code2 | string | yes | The third code ID. |
code2_name | string | no | The third code displayed name. |
comment | string | yes | The comment. |
cells | SheetCell[] | yes* | One SheetCell structure per date in the sheet. |
SheetCell
A SheetCell
represents one "box" on the sheet:
Field | Type | Save? | Description |
---|---|---|---|
amount | double | yes | The amount in the cell (hours, dollars, etc.). |
reason | string | no | (Currently unused.) An error message if there is a problem with this cell. |
error | boolean | no | (Currently unused.) True if there is a problem with this cell. |
notes | CellNote[] | yes* | A list of notes attached to this cell. |
attachments | string[] | no | The encoded IDs of all file attachments on this cell. |
Attachments are not included in their entirety due to size. Use the attachment-related jxAPI methods to retrieve, add, or delete them.
CellNote
A cell can have zero or more notes, each of which is represented by a
CellNote
:
Field | Type | Save? | Description |
---|---|---|---|
id | string | yes | The note's ID (empty when creating a new note). |
modified | boolean | yes* | Set to true on save if modifying an existing note. |
correction | boolean | yes* | True if this is a correction note required by audit level. |
text | string | yes | The note text. |
When modifying an existing note, set the modified
flag to true. For a new
note, leave id
empty and set modified
to true. Set the correction
flag to
true if this note was entered as a requirement of the audit level; this flag
triggers special correction behavior on the server that will not be performed if
you add a regular note.
SheetPunchList
Allocation times are represented by one SheetPunchList
structure per date in
the sheet:
Field | Type | Save? | Description |
---|---|---|---|
punches | SheetPunch[] | yes | A list of punch times. |
SheetPunch
A SheetPunch
holds a single pair of in/out times:
Field | Type | Save? | Description |
---|---|---|---|
time_in | string | yes | The punch in time, in HHMMSS format. |
time_out | string | yes | The punch out time, in HHMMSS format. |
Note that punch times do not have an associated time zone. In the manual
allocation entry UI format this doesn't make much difference, but note that
punching in or out (with the punch_sheet
or punch
jxAPI methods, or the
punch button in the web interface), the time recorded will be in the server
timezone. Likewise, the behavior for punches that cross into a new day will be
based on the server's idea of midnight.
SheetAuditSettings
The audit level settings of the sheet are provided in a SheetAuditSettings
structure:
Field | Type | Save? | Description |
---|---|---|---|
requires_new_entries | boolean | no | True if sheets with new entries must be resubmitted. |
has_ever_been_submitted | boolean | no | True if the sheet has ever been submitted for approval. |
requires_correction_recs | boolean | no | True if correction notes are required with any change to a cell. |
audit_level_setting | string | no | The audit level. |
Other Useful Methods
A few other jxAPI methods are useful for a full-sheet workflow:
getAllColumnRecords
getAllColumnRecords(loggableOnly: boolean) -> AllColumnRecords
Returns all column records usable by the current user. This is a single-call way to get a complete list of the projects and codes that can be used to populate popups or completion menus on a client. The return value is a structure:
Field | Type | Description |
---|---|---|
projects | ProjectRecord[] | Projects. |
projects_extra | ProjectExtra[] | Project extra fields. |
codes_tasks | CodeRecord[] | Tasks (time code 0). |
codes_pay_types | SubcodeRecord[] | Pay types (time code 1). |
codes_bill_types | SubsubcodeRecord[] | Bill types (time code 2). |
codes_expenses | ExpenseCodeRecord[] | Expense codes (expense code 0). |
codes_expense_sources | ExpenseSourceRecord[] | Sources (expense code 1). |
codes_currencies | ExpenseCurrencyRecord[] | Currencies (expense code 2). |
codes_mileage_reasons | MileageReasonRecord[] | Reasons (mileage/custom code 0). |
codes_mileage_vehicles | MileageVehicleRecord[] | Vehicles (mileage/custom code 1). |
codes_mileage_measurements | MileageMeasurementRecord[] | Measurements (mileage/custom code 2). |
The ProjectExtra
structure has extra fields for each project:
Field | Type | Description |
---|---|---|
project_id | string | The project ID. |
allow_time | int | If non-zero, can report time on this project. |
allow_expense | int | If non-zero, can report expenses on this project. |
allow_custom | int | If non-zero, can report mileage/custom on this project. |
allow_leave | int | If non-zero, can make leave requests on this project. |
allow_holiday | int | If non-zero, can report holiday time on this project. |
getAllProjectDependencies
getAllProjectDependencies(loggableOnly: boolean) -> ProjectDependencies[]
Returns all project dependencies for the current user. This is a single-call way to get dependency information used for filtering column data as the user selects it in a client. The return value is a list of structures:
Field | Type | Description |
---|---|---|
project_id | string | The project ID. |
project_name | string | The project name. |
project_description | string | The project description. |
codes_tasks | string[] | IDs of dependent codes (time code 0). |
codes_pay_types | string[] | ... (time code 1) |
codes_bill_types | string[] | ... (time code 2) |
codes_expenses | string[] | ... (expense code 0) |
codes_expense_sources | string[] | ... (expense code 1) |
codes_currencies | string[] | ... (expense code 2) |
codes_mileage_reasons | string[] | ... (mileage/custom code 0) |
codes_mileage_vehicles | string[] | ... (mileage/custom code 1) |
codes_mileage_measurements | string[] | ... (mileage/custom code 2) |
getAllColumnDependencies
getAllColumnDependencies() -> ColumnDependency[]
Returns all code column dependencies for the current user. This is a single-call way to get dependency information used for filtering column data as the user selects it in a client. The return value is a list of structures:
Field | Type | Description |
---|---|---|
parent_table | string | The parent table (eg. "codes_tasks"). |
parent_id | string | The parent code ID. |
child_table | string | The child table. |
child_id | string | The child code ID. |
getDisplaySettings
getDisplaySettings() -> DisplaySettings
Returns the user's display settings. Some parts of the sheet structure depend on information found here, in particular the order and visibility of combo columns. The return value is a structure:
Field | Type | Description |
---|---|---|
time_label | string | The label for time screens. |
time_column_names | string[] | Names of time columns. (See below.) |
time_column_priority | int[] | Order of time columns. (See below.) |
time_column_defaults | string[] | Default values for time columns. (See below.) |
expense_label | string | The label for expense screens. |
expense_column_names | string[] | (See below.) |
expense_column_priority | int[] | (See below.) |
custom_label | string | The label for custom/mileage screens. |
custom_column_names | string[] | (See below.) |
custom_column_priority | int[] | (See below.) |
allow_blank_comments | boolean | Are blank comments allowed? |
time_grid | string | The time entry type: "plain", "inout" (allocation), or "punch" (punch-based allocation). |
time_view_future | boolean | Can the user view future time sheets? |
time_view_past | boolean | Can the user view past time sheets? |
expense_view_future | boolean | Can the user view future expense sheets? |
expense_view_past | boolean | Can the user view past expense sheets? |
custom_view_future | boolean | Can the user view future custom/mileage sheets? |
custom_view_past | boolean | Can the user view past custom/mileage sheets? |
The column names, priority, and defaults are always in the same order: project, code0, code1, code2, comment. The priority list determines what order they should be displayed in on a client; a priority of zero means the column is not displayed. The specific tables that correspond to codes 0, 1, and 2 are always the same:
Type | Code0 | Code1 | Code2 |
---|---|---|---|
Time | tasks | pay_types | bill_types |
Expense | expenses | expense_sources | currencies |
Custom | mileage_reasons | mileage_vehicles | mileage_measurements |
timezone
timezone() -> int
This method does not require a session key.
Returns the offset from UTC of the Journyx server's timezone.