Client¶
sonnys_backoffice.SonnysBackofficeClient
¶
Programmatic access to Sonny's Backoffice user management.
Caches are populated lazily on first use and reused for subsequent calls.
Pass refresh=True to discovery methods to force a re-fetch.
__init__(*, subdomain, username, password, timeout=30.0, user_agent=None)
¶
Create a new client for a single Sonny's Backoffice tenant.
Login is deferred until the first request that needs the session (lazy). Use as a context manager to guarantee session cleanup:
with SonnysBackofficeClient(...) as client:
...
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
subdomain
|
str
|
Tenant subdomain, e.g. |
required |
username
|
str
|
Backoffice bot user username. |
required |
password
|
str
|
Backoffice bot user password. |
required |
timeout
|
float
|
Per-request HTTP timeout in seconds. Defaults to 30. |
30.0
|
user_agent
|
str | None
|
Optional custom User-Agent header. |
None
|
__enter__()
¶
__exit__(*exc)
¶
close()
¶
Close the underlying HTTP session.
Called automatically by __exit__ when used as a context manager.
create_employee(*, first_name, last_name, phone, email, pos_user_id, wage_rate, start_date, available_sites, permission, pos_pin=None, overtime_wage_rate=None, departments=None, adp_employee_id=None, emergency_contact_name=None, emergency_contact_phone=None, requires_backoffice=False, backoffice_username=None, backoffice_password=None)
¶
Create a new POS employee, optionally with a linked Backoffice user.
The call goes through a two-step flow:
POST /employee/insertwith personal, wage, department, and site fields.POST /employee/permissions/updatewith the full permission matrix for the resolved template.
If requires_backoffice=True, a third step creates the linked BO
user via POST /user/insert. Note that in Milestone 1 the BO user's
permission template is not applied automatically and must be
assigned manually via the Backoffice UI — see the
Creating a Backoffice user guide.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
first_name
|
str
|
Employee first name. Leading/trailing whitespace is stripped. |
required |
last_name
|
str
|
Employee last name. |
required |
phone
|
str
|
Phone number. 9 or 10 digits after non-digit characters are stripped. |
required |
email
|
str
|
Email address. Must contain a valid |
required |
pos_user_id
|
int
|
Caller-assigned unique POS login ID. Must be unique
per tenant. Pre-flight with |
required |
wage_rate
|
Decimal | float
|
Hourly wage in dollars. Prefer |
required |
start_date
|
datetime
|
Employment start date. |
required |
available_sites
|
list[str] | Literal['all']
|
List of site names or the literal |
required |
permission
|
str
|
POS template name. Matched case-insensitively; unknown
names fall back to |
required |
pos_pin
|
int | None
|
5-digit POS PIN integer (10000-99999). If |
None
|
overtime_wage_rate
|
Decimal | float | None
|
Overtime hourly wage. Defaults to
|
None
|
departments
|
list[str] | None
|
Department names. |
None
|
adp_employee_id
|
str | None
|
ADP payroll employee ID, if applicable. |
None
|
emergency_contact_name
|
str | None
|
Optional emergency contact name. |
None
|
emergency_contact_phone
|
str | None
|
Optional emergency contact phone (same
validation as |
None
|
requires_backoffice
|
bool
|
If True, also creates a linked BO user. |
False
|
backoffice_username
|
str | None
|
BO username. Required when
|
None
|
backoffice_password
|
str | None
|
BO password. If |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
EmployeeCreated |
EmployeeCreated
|
The created record including the auto-generated |
EmployeeCreated
|
POS PIN, resolved permission, wage attribution site, and any |
|
EmployeeCreated
|
warnings (permission fallbacks, BO M1 deferral, etc.). |
Raises:
| Type | Description |
|---|---|
ValidationError
|
If any input fails validation or Backoffice rejects the form. |
DuplicateError
|
If pos_user_id, email, or phone already exists on the tenant (pre-flight or server-side). |
AuthenticationError
|
If login or re-authentication fails. |
BackofficeServerError
|
If Backoffice returns an unexpected response (HTTP 5xx, unparseable HTML, etc.). |
LookupError
|
If |
disable_employee(*, pos_user_id=None, email=None)
¶
Disable an employee looked up by POS User ID or email.
Disable uses a full-form round-trip: fetch the employee list to
resolve the internal employee_id, GET the edit form, parse every
field, re-POST with employee[isActive] omitted (Symfony binds
checkbox presence as true regardless of value), and re-GET to verify
the change took effect.
Exactly one of pos_user_id or email is required.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pos_user_id
|
int | None
|
POS User ID to look up. |
None
|
email
|
str | None
|
Email to look up. Note: the employee list page does not
usually contain an email column, so email lookup may fail
with |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
EmployeeDisabled |
EmployeeDisabled
|
The internal employee_id, echoed lookup key, |
EmployeeDisabled
|
and the UTC timestamp of the disable. |
Raises:
| Type | Description |
|---|---|
ValidationError
|
If neither or both lookup keys are provided. |
NotFoundError
|
If no employee matches the lookup key. |
BackofficeServerError
|
If the disable POST is accepted but the verification GET shows the employee is still active (the full-form round-trip didn't take effect — usually means the form structure has changed). |
AuthenticationError
|
If login or re-authentication fails. |
create_backoffice_user(*, username, email, permission, password=None, link_to_employee_pos_user_id=None, link_to_employee_email=None, first_name=None, last_name=None, available_sites='all')
¶
Create a Backoffice user — standalone or linked to an employee.
In linked mode the user inherits site access from the employee
(pass link_to_employee_pos_user_id or link_to_employee_email).
The linked employee must currently be active.
In standalone mode the user gets its own profile (pass
first_name and last_name, no link fields).
Milestone 1 limitation
The account is created successfully but the permission template is
not assigned automatically. Click the shield icon next to the
new user in the Backoffice /user list, pick a template, and
save. A reminder is included in the returned warnings list.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
username
|
str
|
New BO username. Must match the pattern
|
required |
email
|
str
|
New user email. |
required |
permission
|
str
|
BO template name for documentation and future use. Currently stored in the result but not applied to the server. |
required |
password
|
str | None
|
BO password. If |
None
|
link_to_employee_pos_user_id
|
str | None
|
Link mode — look up the employee by POS User ID. |
None
|
link_to_employee_email
|
str | None
|
Link mode — look up the employee by email. |
None
|
first_name
|
str | None
|
Standalone mode — first name. |
None
|
last_name
|
str | None
|
Standalone mode — last name. |
None
|
available_sites
|
list[str] | Literal['all']
|
Documented in the result but not applied in M1
BO-permission path. Defaults to |
'all'
|
Returns:
| Name | Type | Description |
|---|---|---|
BackofficeUserCreated |
BackofficeUserCreated
|
The new user record, including the |
BackofficeUserCreated
|
auto-generated password and a warning about the M1 deferral. |
Raises:
| Type | Description |
|---|---|
ValidationError
|
If neither linked nor standalone mode fields are provided (or both are provided). |
NotFoundError
|
In linked mode, if the linked employee cannot be resolved. |
DuplicateError
|
If the username or email already exists. |
BackofficeServerError
|
If Backoffice rejects the insert (e.g., linked employee is inactive) or returns an unexpected response. |
AuthenticationError
|
If login or re-authentication fails. |
list_sites(*, refresh=False)
¶
List all sites the bot user can see on the tenant.
The result is cached on the client after the first call. Pass
refresh=True to re-fetch.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
refresh
|
bool
|
If True, bypass the cache and re-fetch. |
False
|
Returns:
| Type | Description |
|---|---|
list[Site]
|
list[Site]: Every site visible to the bot user. On a hierarchical |
list[Site]
|
tenant the returned |
list[Site]
|
|
list_departments(*, refresh=False)
¶
List the department options configured on the tenant.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
refresh
|
bool
|
If True, bypass the cache and re-fetch. |
False
|
Returns:
| Type | Description |
|---|---|
list[Department]
|
list[Department]: Every department option, e.g. Cashier, Greeter, |
list[Department]
|
Line, Management. |
list_permissions(*, scope, refresh=False)
¶
List the role templates available on the tenant for a given scope.
POS templates come from /employee/permissions/<id> on an existing
employee; Backoffice templates come from /user/permissions/<id>
on an existing BO user. Both lookups are cached per scope.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scope
|
Literal['pos', 'backoffice']
|
|
required |
refresh
|
bool
|
If True, bypass the cache and re-fetch. |
False
|
Returns:
| Type | Description |
|---|---|
list[Permission]
|
list[Permission]: Every template on the tenant for the requested |
list[Permission]
|
scope. POS templates carry |
list[Permission]
|
Backoffice templates are name-only in Milestone 1. |
Raises:
| Type | Description |
|---|---|
NotFoundError
|
If the tenant has no existing records from which to extract templates (e.g., an empty tenant with no employees). |
is_pos_user_id_available(pos_user_id, *, refresh=False)
¶
Return True if no existing employee uses this POS User ID.
The check uses a cached per-tenant employee index built lazily from
/employee?limit=10000&active=all and /user/create.
is_email_available(email, *, refresh=False)
¶
Return True if no existing employee uses this email (case-insensitive).
is_phone_available(phone, *, refresh=False)
¶
Return True if no existing employee uses this phone number.
The phone argument is normalized to digits-only before comparison.