# How To / Externally Ticket

# How-To: Integrate Shelf Ticketing

> [We presume you've already authenticated your application before reading this document.](/documentation/How-To/Authenticate)

## Overview

Shelf ticketing in Shopfront is designed to be highly flexible, allowing for automatic queueing of tickets based on
item changes, customisable templates, and direct browser-based printing.

> Currently Shopfront supports ticketing Products, Promotions and Future Prices

This guide explores how Shopfront's internal ticketing system works and provides recommendations for developers looking
to integrate their own ticketing solutions or extend Shopfront's existing functionality.

## How Ticketing Works

Shopfront maintains a *Ticket Queue* which stores items that need to be printed. Items are typically added to this 
queue automatically based on the context of changes and the templates currently existing and connected in their store.

These changes can include:

- Price changes (both manual and scheduled)
- Product name or detail updates
- Manual additions by users from the product list or ticket management screens

Once items are in the queue, users can select a *Ticket Template* and a *Page Layout* to print them. Printing is 
handled directly in the browser using Shopfront's custom template system, which renders tickets as HTML/CSS before
sending them to the printer.

If you have a ticketing system that supports HTML/CSS rendering, you can use Shopfront's *Ticket Templates* directly
and allow the user to retain control over styling and layout without having to implement your own system.

## Page Layouts

Page layouts define the physical characteristics of the surface you are displaying templates on and how tickets are 
arranged on that surface. In the GraphQL API, these are represented by the 
[`TicketTemplatePage`](/documentation/Objects/Shelf-Tickets#TicketTemplatePage) type.

Key properties include:

- *Dimensions*: `pageWidth` and `pageHeight` (in millimeters),
- *Grid Layout*: `horizontalPanels` and `verticalPanels` define how many tickets fit on a single page,
- *Margins & Spacing*: `pageMargin`, `horizontalPanelSpacing`, and `verticalPanelSpacing` control the positioning of
  the ticket grid,
- *Cutting Lines*: `cuttingWidth` can be used to display guides for manual cutting

## Ticket Templates

Ticket templates define the visual appearance and data transformation for individual tickets. They are represented by
the [`TicketTemplate`](/documentation/Objects/Shelf-Tickets#TicketTemplate) type.

A template consists of:

- *Dimensions*: `width` and `height` of the individual ticket panel,
- *Fonts*: A list of custom fonts required by the template
- *Styles*: Custom CSS used to style the ticket,
- *Transformation Script*: A JavaScript snippet that takes raw product data and transforms it into fields usable by
  the template,

To render these in the browser we create a custom HTML element which transforms the raw object (e.g. the product or 
promotion) into a usable ticket by using the user-provided transformation script. We then render this transformed data
by placing each `key` into its own div. The `styles` are then injected via CSS to position the content.

## Integrating Your Own System

If you are building an integration that provides its own ticketing system (such as electronic shelf labels), we suggest
one of the following two routes depending on where you want the "source of truth" for the print queue to reside.

> There are other ways to integrate your own system with Shopfront, but these two routes are the most common.

### Managing Your Own Queue

This route is best if you're already managing your own queue or if you want full control over the ticketing process. 
This has the downside that you can't leverage Shopfront's contextual knowledge of tickets without reimplementing it 
yourself.

To build your integration this way, you'll typically want to do the following:

1. *Perform an Initial Sync*: Similar to an [eCommerce integration](/documentation/How-To/eCommerce#fullSync), 
   perform a full sync of products to your system, you'll also want to make this possible to call at other times in case
   your system becomes out of date with Shopfront,
2. *Stay Up-to-Date*: Listen to standard product webhooks like `PRODUCT_UPDATED` to determine when a ticket update is 
   needed,
3. *Handle Printing*: Manage the queue and printing process entirely within your own application

### Using Shopfront's Queue

This route allows you to leverage Shopfront's built-in logic for queueing tickets while using your own system for the 
actual printing or display of tickets.

1. *Query the Queue*: Use the `ticketQueue` query to retrieve items currently waiting to be printed,
    - We also suggest keeping this available to use manually in case a change is missed
2. *Monitor Changes*: Listen to ticket-specific webhooks to get real-time updates:
    - `THIN_TICKET_QUEUED`: Triggered when an item is added to the queue,
    - `THIN_TICKET_PRINTED`: Triggered when an item is marked as printed,
    - `THIN_TICKET_DELETED`: Triggered when an item is removed from the queue
3. *Mark as Printed*: After your system has successfully printed / displayed the tickets, use the `markTicketsAsPrinted`
   mutation to remove them from Shopfront's active queue
    - this also enables the queue to provide functionality like automatically activating future prices after they're 
      marked as printed

**Querying the Ticket Queue**

```javascript
const response = await shopfront.graphql(`
    query GetTicketQueue($cursor: Cursor, $outlets: [ID!]) {
        ticketQueue(after: $cursor, outlets: $outlets) {
            edges {
                node {
                    id,
                    user {
                        name,
                    },
                    queuedAt,
                    item {
                        id,
                        __typename,
                    },
                },
            },
            pageInfo {
                endCursor,
                hasNextPage,
            },
        }
    }
`, {
    outlets: [ "11e6..." ]
});

const tickets = response.ticketQueue.edges.map(edge => edge.node);
```

**Querying the Ticket Queue**

```php
<?php

global $shopfront;

$data = $shopfront->graphql('
    query GetTicketQueue($cursor: Cursor, $outlets: [ID!]) {
        ticketQueue(after: $cursor, outlets: $outlets) {
            edges {
                node {
                    id,
                    user {
                        name,
                    },
                    queuedAt,
                    item {
                        id,
                        __typename,
                    },
                },
            },
            pageInfo {
                endCursor,
                hasNextPage,
            },
        }
    }
', [
    'outlets' => [ '11e6...' ],
]);

$tickets = array_map(fn($edge) => $edge->node, $data->ticketQueue->edges);
```

**Marking Tickets as Printed**

```javascript
await shopfront.graphql(`
    mutation MarkTicketsAsPrinted($tickets: [ID!]!) {
        markTicketsAsPrinted(tickets: $tickets)
    }
`, {
    tickets: [ "11e6..." ],
});
```

**Marking Tickets as Printed**

```php
<?php

global $shopfront;

$shopfront->graphql('
    mutation MarkTicketsAsPrinted($tickets: [ID!]!) {
        markTicketsAsPrinted(tickets: $tickets)
    }
', [
    'tickets' => [ '11e6...' ],
]);
```