Skip to main content

Petstore: Orders

The Orders page, served at /console/orders, is the petstore's workflow table. Orders move through PLACED, APPROVED and DELIVERED; each row offers only the transitions that are legal for its status, and creating an order is a two-step dialog. It shows what row actions, dialogs, confirmations and a ribbon dialog button look like when they are wired to real state changes.

What this page shows​

  • Server mode with BeanQuery, like the Pets page, plus two URL-state directives, day and window. The query endpoint accepts ?day=yyyy-mm-dd, or ?start= and ?end= for a date window (both ends inclusive, either may be omitted), and applies them before the column filters. A missing or malformed value is ignored. The Store page's trend chart links here with ?state=day({day}).
  • Row actions with visibleWhen. Approve appears only on PLACED rows and Deliver only on APPROVED rows. Each posts to /console/orders/{id}/approve or /console/orders/{id}/deliver; an illegal transition is a 409.
  • A dialog from an action. Cancel opens a form (GET /console/orders/{id}/cancel-form, with a reason and a notify checkbox) and submits a DELETE to /console/orders/{id}. The reason is recorded in the audit trail.
  • A typed confirmation. Delete uses confirmRenderer: 'typed', so the user must type to confirm. The row action's tone is danger.
  • A two-step wizard. The ribbon's "+ New order" button opens a ModalDef: step one picks an available pet and an optional ship date; its child action "Review order" stacks a second dialog, carrying the first step's inputs as drafts, and Confirm posts to /console/orders. Only pets that are for sale are offered.

Template​

The template is orders.ftlh. The excerpt keeps the URL state and two of the row actions.

<@card type="datatables" id="orders" title="Orders">
{
rowType: 'Order',
dataMode: 'server',
dataUrl: '/console/orders/query',
urlState: { day: {}, window: {} },
rowActions: [
{ id: 'approve', label: 'Approve', endpoint: '/console/orders/{id}/approve', method: 'POST', onSuccess: 'redraw',
visibleWhen: [ { field: 'status', op: 'eq', value: 'PLACED' } ] },
{ id: 'cancel', label: 'Cancel', form: '/console/orders/{id}/cancel-form', present: 'dialog',
endpoint: '/console/orders/{id}', method: 'DELETE', onSuccess: 'redraw' }
]
}
</@card>

The ribbon also carries a "+ New order" dialog item whose form is /console/orders/new-form; see the wizard above.

Builder twin​

OrdersPageBuilders.orders builds the same table. Request /console/orders?builder to render it.

TableSpec.create("orders").rowType("Order").dataMode(DataMode.SERVER).dataUrl("/console/orders/query")
.urlState("day", "window")
.rowActions(
RowAction.create("approve").label("Approve").endpoint("/console/orders/{id}/approve").method(Method.POST)
.onSuccess(OnSuccess.REDRAW).visibleWhen(VisibilityRule.when("status").eq("PLACED")),
RowAction.create("delete").label("Delete").endpoint("/console/orders/{id}").method(Method.DELETE)
.confirm("Delete order '{id}'?").tone(Tone.DANGER).confirmRenderer("typed").onSuccess(OnSuccess.REDRAW));

The wizard is not part of the template or the builder: both pages point the ribbon button at the same two form endpoints on OrdersRest, which return ModalDef beans (newForm and reviewForm).

Source and tests​

Source: juneau-petstore/juneau-petstore-core, classes OrdersRest (in the orders package) and OrdersPageBuilders (in the pages package), and the template orders.ftlh.

Tests: OrdersRest_Test (query, day and window, transitions and their 409s, cancel, the wizard steps and order placement), PetstorePages_ContractTest and PetstoreTwins_Test.

See also​