developer.emfcamp.org

Developer documentation for EMF APIs

View on GitHub

2022 Bar and Shop

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.

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:

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:

Example:

{
  "id": 90,
  "description": "Wine (bottles)",
  "notes": "Available in 125ml, 175ml and 250ml"
}

Stock type

Properties:

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:

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:

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):

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:

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"
}