Bar and Shop data
There is a simple read-only interface to the till system running the
bar, Null Sector bar, and shop. It’s available via HTTP GET from
bar.emf.camp
and returns JSON, except when you request an object
that does not exist when it will return HTTP 404.
The web service that implements this API is here: https://github.com/emfcamp/quicktill-tillweb
Data types
All these data types are represented as JSON objects. Integers are represented as JSON numbers, Decimals are represented as JSON strings, times are local times in ISO 8601 format.
Session
A time period that the bar is planned to be open.
Properties:
opening_time
: opening timeclosing_time
: closing time
Example:
{
"opening_time": "2022-06-02T11:00:00",
"closing_time": "2022-06-03T01:00:00"
}
Department
Everything sold through the till has a “department”, which is a general classification by type (real ale, keg, wine, etc.)
Properties:
id
: an integer uniquely identifying the departmentdescription
: a string describing the departmentnotes
: an optional string giving more information
Example:
{
"id": 90,
"description": "Wine (bottles)",
"notes": "Available in 125ml, 175ml and 250ml"
}
Stock type
Properties:
id
: an integer uniquely identifying the stock typedepartment
: the Department object associated with the stock typemanufacturer
: a string naming the manufacturername
: a string describing this type of stock; unique per manufacturerabv
: an optional Decimal giving the alcohol by volumefullname
: manufacturer, name and abv combined into a single stringsale_unit
: a string giving the unit in which we sell this type of stock, eg. “bottle” or “pint”price
: the sale price as a Decimal, including VAT where appropriate, for asale_unit
of this type of stockbase_unit
: a string giving the unit in which we count how much of this stock we have bought and sold, eg. “pint” or “ml”base_units_bought
: the amount of stock bought in base units as a Decimalbase_units_remaining
: the amount of stock remaining in base units as a Decimalbase_units_per_sale_unit
: the number of base units per sale unit as a Decimal
Examples:
{
"id": 1,
"department": {
"id": 35,
"description": "Keg cider",
"notes": null
},
"manufacturer": "Westons",
"name": "Stowford Press",
"abv": "4.5",
"fullname": "Westons Stowford Press (4.5% ABV)",
"price": "4.00",
"base_units_bought": "616.0",
"base_units_remaining": "616.0",
"base_unit": "pint",
"sale_unit": "pint",
"base_units_per_sale_unit": "568.0"
}
{
"id": 10,
"department": {
"id": 70,
"description": "Soft Drinks",
"notes": null
},
"manufacturer": "Sunpride",
"name": "Orange Juice",
"abv": null,
"fullname": "Sunpride Orange Juice",
"price": "1.20",
"base_units_bought": "120000.0",
"base_units_remaining": "120000.0",
"base_unit": "ml",
"sale_unit": "pint",
"base_units_per_sale_unit": "568.0"
}
Stock item
Some types of stock are divided into “items”, for example we may have three casks of a particular type of beer. When they are put on sale on the bar, the amount remaining is counted for each item as well as for the type of stock as a whole.
Properties:
id
: an integer uniquely identifying the stock itemstocktype_id
: an integer identifying the type of stockmanufacturer
: a string naming the manufacturername
: a string describing this type of stock; unique per manufacturerabv
: an optional Decimal giving the alcohol by volumefullname
: manufacturer, name and abv combined into a single stringprice
: the sale price as a Decimal, including VAT where appropriate, for a unit of this type of stockremaining_pct
: a Decimal representing the percentage of this item that is remaining
Example:
{
"id": 128,
"stocktype_id": 25,
"manufacturer": "Milton",
"name": "Nero",
"abv": "5.0",
"fullname": "Milton Nero (5.0% ABV)",
"price": "4.40",
"remaining_pct": "100.00000000000000000000"
}
Price lookup
We are not counting items of stock at the shop; the till system only knows how much we are selling each item for.
Properties:
id
: an integer uniquely identifying the price lookupdepartment
: the Department object associated with the stock typedescription
: a string describing the itemnote
: an optional string describing the item furtherdepartment
: the Department object associated with the price lookupprice
: the amount we sell one of these items for as a Decimal
Example:
{
"id": 1,
"description": "USB A-C",
"note": "",
"department": {
"id": 210,
"description": "Shop (20% VAT)",
"notes": null
},
"price": "2.20"
}
Endpoints
All endpoints return JSON objects; where an endpoint needs to return a list, it returns an object with the list as the value of a key.
Sessions
/api/sessions.json
returns a list of current and future bar
Sessions.
Example (N.B. the times in this example are not final and may change during the event based on available volunteers, etc.):
{
"sessions": [
{
"opening_time": "2022-06-02T11:00:00",
"closing_time": "2022-06-03T01:00:00"
},
{
"opening_time": "2022-06-03T11:00:00",
"closing_time": "2022-06-04T01:00:00"
},
{
"opening_time": "2022-06-04T11:00:00",
"closing_time": "2022-06-05T01:00:00"
},
{
"opening_time": "2022-06-05T11:00:00",
"closing_time": "2022-06-06T00:30:00"
}
]
}
Event progress
/api/progress.json
returns general information about bar progress.
Although this drives a couple of graphs on the bar web site it is not intended to be scientifically accurate!
Properties (all Decimal percentages):
licensed_time_pct
: how far through the sessions are we at the moment?expected_consumption_pct
: how far through the sessions are we at the moment, with a weighting applied per session based on experience at previous events?actual_consumption_pct
: how much of the booze have we used? “Booze” is any stock type with a non-null abv, including those with an abv of “0.0”.
Departments
/api/departments.json
returns the complete list of Departments.
Example:
{
"departments": [
{
"id": 10,
"description": "Real Ale",
"notes": null
},
/* many departments omitted */
{
"id": 310,
"description": "Red Cross donations",
"notes": null
}
]
}
Beers and ciders on tap
/api/on-tap.json
returns lists of Stock items on sale on the bar at
the moment. The list is divided in to real ales (on handpumps), keg
beers (on taps) and real ciders (sold from boxes on the bar).
Properties:
ales
: list of real ale Stock itemskegs
: list of keg beer/cider Stock itemsciders
: list of real cider Stock items
Example:
{
"ales": [
{
"id": 128,
"stocktype_id": 25,
"manufacturer": "Milton",
"name": "Nero",
"abv": "5.0",
"fullname": "Milton Nero (5.0% ABV)",
"price": "4.40",
"remaining_pct": "100.00000000000000000000"
}
],
"kegs": [],
"ciders": []
}
Null Sector bar / “Cybar”
/api/cybar.json
lists stock types on sale at the bar in Null
Sector. (Null Sector sells pre-packaged drinks out of fridges.)
Example:
{
"cybar": [
{
"id": 59,
"department": {
"id": 60,
"description": "Cans >0.5%",
"notes": null
},
"manufacturer": "Arbor",
"name": "Citrus Maxima 568ml",
"abv": "4.0",
"fullname": "Arbor Citrus Maxima 568ml (4.0% ABV)",
"price": "5.70",
"base_units_bought": "48.0",
"base_units_remaining": "48.0",
"base_unit": "can",
"sale_unit": "can",
"base_units_per_sale_unit": "1.0"
},
/* many stock types omitted */
{
"id": 30,
"department": {
"id": 95,
"description": "Wine (cans)",
"notes": null
},
"manufacturer": "Copper Crew",
"name": "Sauvignon Blanc 250ml",
"abv": "13.0",
"fullname": "Copper Crew Sauvignon Blanc 250ml (13.0% ABV)",
"price": "5.00",
"base_units_bought": "48.0",
"base_units_remaining": "48.0",
"base_unit": "can",
"sale_unit": "can",
"base_units_per_sale_unit": "1.0"
}
]
}
All stock types
/api/stocktypes.json
lists all the types of stock remaining at the
bar and cybar.
Example:
{
"stocktypes": [
{
"id": 23,
"department": {
"id": 10,
"description": "Real Ale",
"notes": null
},
"manufacturer": "Milton",
"name": "Justinian",
"abv": "3.9",
"fullname": "Milton Justinian (3.9% ABV)",
"price": "3.80",
"base_units_bought": "432.0",
"base_units_remaining": "432.0",
"base_unit": "pint",
"sale_unit": "pint",
"base_units_per_sale_unit": "1.0"
},
/* many, many stock types omitted! */
{
"id": 30,
"department": {
"id": 95,
"description": "Wine (cans)",
"notes": null
},
"manufacturer": "Copper Crew",
"name": "Sauvignon Blanc 250ml",
"abv": "13.0",
"fullname": "Copper Crew Sauvignon Blanc 250ml (13.0% ABV)",
"price": "5.00",
"base_units_bought": "48.0",
"base_units_remaining": "48.0",
"base_unit": "can",
"sale_unit": "can",
"base_units_per_sale_unit": "1.0"
}
]
}
The shop
We are not counting items of stock at the shop; the till system only knows how much we are selling each item for.
/api/shop.json
returns a list of all price lookups defined at the
shop. N.B. this is not a guarantee that any of these items remain in
stock!
Example:
{
"shop": [
{
"id": 1,
"description": "USB A-C",
"note": "",
"department": {
"id": 210,
"description": "Shop (20% VAT)",
"notes": null
},
"price": "2.20"
}
]
}
All stock types in a department
You can retrieve all stock types in a department using
/api/department/<int:dept_id>.json
. If you know the department ID,
this is more efficient than retrieving everything from
/api/stocktypes.json
and filtering locally.
For example, to retrieve the Club Mate stock levels you can fetch from
/api/department/75.json
:
{
"stocktypes": [
{
"id": 32,
"department": {
"id": 75,
"description": "Club Mate",
"notes": null
},
"manufacturer": "Club Mate",
"name": "Granat 500ml",
"abv": null,
"fullname": "Club Mate Granat 500ml",
"price": "2.50",
"base_units_bought": "800.0",
"base_units_remaining": "800.0",
"base_unit": "bottle",
"sale_unit": "bottle",
"base_units_per_sale_unit": "1.0"
},
{
"id": 31,
"department": {
"id": 75,
"description": "Club Mate",
"notes": null
},
"manufacturer": "Club Mate",
"name": "Regular 500ml",
"abv": null,
"fullname": "Club Mate Regular 500ml",
"price": "2.50",
"base_units_bought": "1600.0",
"base_units_remaining": "1600.0",
"base_unit": "bottle",
"sale_unit": "bottle",
"base_units_per_sale_unit": "1.0"
}
]
}
Retrieve a specific stock type
If you know the stock type ID you can fetch the Stock type object for
that directly from /api/stocktype/<int:stocktype_id>.json
.
For example, to fetch the record for ChariTea Mate
Tea you can fetch
from /api/stocktype/48.json
:
{
"id": 48,
"department": {
"id": 70,
"description": "Soft Drinks",
"notes": null
},
"manufacturer": "ChariTea",
"name": "Mate 330ml",
"abv": null,
"fullname": "ChariTea Mate 330ml",
"price": "3.40",
"base_units_bought": "120.0",
"base_units_remaining": "120.0",
"base_unit": "bottle",
"sale_unit": "bottle",
"base_units_per_sale_unit": "1.0"
}