Skip to main content
Version: Current

Process · medium — approve timesheets

The case. The manager chooses the timesheets to approve, then confirms. The HR tool expects a list of identifiers.

What the example shows. A part that is a set (countable: false), lines sent as identifiers (line_shape: ref), a write separated from the reads, the manager's confirmation as the act.

examples/actuelle/process-medium.yaml
# Process · medium — a manager approves timesheets. A SET, not a basket: each timesheet once,
# sent to the tool as a list of ids. The manager's confirmation is the act.
station:
id: validation-heures
name: Validation des heures

global:
language: fr
currency: EUR
locale: fr-FR

domain:
domain_type: saas
entity_name: feuille d'heures
entity_name_plural: feuilles d'heures


agent:
tone: professional
name: Validation des heures
persona: "un assistant qui prépare les validations du manager, sans jamais décider à sa place"
rules:
- "Ne jamais valider une feuille que le manager n'a pas choisie."
emoji: false
portals:
web:
widget:
origins: [https://heures.example.fr]

apis:
- name: rh-lecture
openapi_url: https://rh-api.example.fr/openapi.json
base_url: https://rh-api.example.fr
operations:
- {id: getTimesheets, access: read}
- {id: getOvertimeReport, access: read}
auth: {type: api_key, key_name: X-RH-Key, key_location: header, key_env: RH_READ_KEY}
- name: rh-ecriture # the write, separated so the boundary is visible
openapi_url: https://rh-api.example.fr/openapi.json
base_url: https://rh-api.example.fr
operations:
- {id: approveTimesheets, access: write}
auth: {type: api_key, key_name: X-RH-Key, key_location: header, key_env: RH_WRITE_KEY}

skills:
- name: feuilles
cognitive:
objective: "lister les feuilles d'heures en attente pour que le manager choisisse celles à valider"
diagnose: [l'équipe, la semaine]
invoke: {method: getTimesheets}
kinds: {feuille: {}}
present: # no price: nothing is sold here
fields:
name: {from: name, type: text, role: title}
countable: false # "3 × the week of Awa" is not a thing
submit:
- name: approve
mode: request
tool: approveTimesheets
line_shape: ref # the tool takes timesheet_ids: list[str]
args:
body.timesheet_ids: "$selection[kind=feuille]"
body.idempotency_key: "$action.key"
render: {component: cards}

- name: rapport-heures-sup
invoke: {method: getOvertimeReport}
render:
component: report
report:
headline: total_overtime_hours
headline_label: "heures supplémentaires"
unit: h

submit_guard:
confirm: true # the manager's own click files the approval

What happens​

stepCoreresult
"my team's pending timesheets"feuilles → getTimesheetscards, one per timesheet
three timesheets chosenset: no quantitythree lines, no −/+ button
"Approve" + confirmationapproveTimesheets with timesheet_ids: [...]receipt in the room
the agent tries to approve on its ownconfirm: truerefused without the manager's click

Key points​

  • countable: false is about the selection; line_shape: ref is about the tenant. Both are needed, and Core refuses ref on a part that has quantities.
  • Limit today: the RH_WRITE_KEY key is the station's. Two managers approve under the same identity, for the HR tool. Only deploy this case if a single manager uses it, or wait for per-person identity (target version).