{
  "info": {
    "name": "ACME Kitchen & Bar: Faux POS",
    "description": "Runs the ACME guided demo through the API, in order. Set baseUrl, and set visitorId to the X-Visitor-Id shown in Present mode to work on that visit. Requests made this way also complete the Verify in Postman step.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "event": [
    {
      "listen": "prerequest",
      "script": {
        "type": "text/javascript",
        "exec": [
          "if (!pm.collectionVariables.get('visitorId')) pm.collectionVariables.set('visitorId', pm.variables.replaceIn('{{$guid}}'));"
        ]
      }
    }
  ],
  "variable": [
    {
      "key": "baseUrl",
      "value": "https://fauxpos.bradenevans.dev"
    },
    {
      "key": "visitorId",
      "value": ""
    },
    {
      "key": "table",
      "value": ""
    },
    {
      "key": "checkId",
      "value": ""
    },
    {
      "key": "balanceDue",
      "value": ""
    },
    {
      "key": "idempotencyKey",
      "value": ""
    },
    {
      "key": "paymentId",
      "value": ""
    }
  ],
  "item": [
    {
      "name": "Check the API is up",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('returns 200', () => pm.response.to.have.status(200));"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "X-Visitor-Id",
            "value": "{{visitorId}}"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/api/health",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "health"
          ]
        }
      }
    },
    {
      "name": "Find Sarah Miller",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('returns 200', () => pm.response.to.have.status(200));",
              "pm.test('finds Sarah', () => pm.expect(pm.response.json()[0].id).to.eql('guest_sarah_miller'));"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "X-Visitor-Id",
            "value": "{{visitorId}}"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/api/guests?q=sarah%20miller",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "guests"
          ],
          "query": [
            {
              "key": "q",
              "value": "sarah%20miller"
            }
          ]
        }
      }
    },
    {
      "name": "Review her loyalty and allergy",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('returns 200', () => pm.response.to.have.status(200));",
              "const guest = pm.response.json();",
              "pm.test('has Table Club points', () => pm.expect(guest.loyalty.points_balance).to.be.at.least(500));",
              "pm.test('has a peanut allergy', () => pm.expect(guest.restrictions.map((r) => r.label)).to.include('Peanut allergy'));"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "X-Visitor-Id",
            "value": "{{visitorId}}"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/api/guests/guest_sarah_miller",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "guests",
            "guest_sarah_miller"
          ]
        }
      }
    },
    {
      "name": "Open table 9",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('returns 201', () => pm.response.to.have.status(201));",
              "pm.collectionVariables.set('checkId', pm.response.json().id);"
            ]
          }
        },
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.collectionVariables.set('table', `P${Math.floor(Math.random() * 100000)}`);"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "X-Visitor-Id",
            "value": "{{visitorId}}"
          },
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/api/checks",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "checks"
          ]
        },
        "body": {
          "mode": "raw",
          "raw": "{\n  \"location_id\": \"loc_downtown\",\n  \"employee_id\": \"emp_jasmine_brooks\",\n  \"table_label\": \"{{table}}\"\n}"
        }
      }
    },
    {
      "name": "Add Sarah to the check",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('returns 200', () => pm.response.to.have.status(200));"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "X-Visitor-Id",
            "value": "{{visitorId}}"
          },
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/api/checks/{{checkId}}/guest",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "checks",
            "{{checkId}}",
            "guest"
          ]
        },
        "body": {
          "mode": "raw",
          "raw": "{\n  \"guest_id\": \"guest_sarah_miller\"\n}"
        }
      }
    },
    {
      "name": "Add a peanut item: refused with the ingredients",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('returns 409', () => pm.response.to.have.status(409));",
              "const { error } = pm.response.json();",
              "pm.test('is an allergy conflict', () => pm.expect(error.code).to.eql('allergy_conflict'));",
              "pm.test('names the ingredients', () => pm.expect(error.conflict.conflicts[0].ingredients).to.include('Crushed peanuts'));",
              "pm.test('offers a replacement', () => pm.expect(error.conflict.alternatives.map((a) => a.id)).to.include('item_ginger_bowl'));"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "X-Visitor-Id",
            "value": "{{visitorId}}"
          },
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/api/checks/{{checkId}}/items",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "checks",
            "{{checkId}}",
            "items"
          ]
        },
        "body": {
          "mode": "raw",
          "raw": "{\n  \"menu_item_id\": \"item_bangkok_bowl\"\n}"
        }
      }
    },
    {
      "name": "Add the safe replacement",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('returns 201', () => pm.response.to.have.status(201));"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "X-Visitor-Id",
            "value": "{{visitorId}}"
          },
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/api/checks/{{checkId}}/items",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "checks",
            "{{checkId}}",
            "items"
          ]
        },
        "body": {
          "mode": "raw",
          "raw": "{\n  \"menu_item_id\": \"item_ginger_bowl\"\n}"
        }
      }
    },
    {
      "name": "Redeem $5 Off",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('returns 200', () => pm.response.to.have.status(200));",
              "pm.test('takes $5 off', () => pm.expect(pm.response.json().discount_cents).to.eql(500));"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "X-Visitor-Id",
            "value": "{{visitorId}}"
          },
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/api/checks/{{checkId}}/reward",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "checks",
            "{{checkId}}",
            "reward"
          ]
        },
        "body": {
          "mode": "raw",
          "raw": "{\n  \"reward_id\": \"reward_five_off\"\n}"
        }
      }
    },
    {
      "name": "Fire to the kitchen",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('returns 200', () => pm.response.to.have.status(200));",
              "const { check, ticket } = pm.response.json();",
              "pm.test('creates a ticket', () => pm.expect(ticket.ticket_number).to.be.a('number'));",
              "pm.collectionVariables.set('balanceDue', check.balance_due_cents);",
              "pm.collectionVariables.set('idempotencyKey', pm.variables.replaceIn('{{$guid}}'));"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "X-Visitor-Id",
            "value": "{{visitorId}}"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/api/checks/{{checkId}}/send",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "checks",
            "{{checkId}}",
            "send"
          ]
        }
      }
    },
    {
      "name": "See the ticket on the kitchen board",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('returns 200', () => pm.response.to.have.status(200));",
              "const checkNumber = pm.response.json().tickets.some((t) => t.guest_name === 'Sarah Miller');",
              "pm.test('shows Sarah on the board', () => pm.expect(checkNumber).to.eql(true));"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "X-Visitor-Id",
            "value": "{{visitorId}}"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/api/kitchen/tickets?location_id=loc_downtown",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "kitchen",
            "tickets"
          ],
          "query": [
            {
              "key": "location_id",
              "value": "loc_downtown"
            }
          ]
        }
      }
    },
    {
      "name": "Charge the card",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('returns 201', () => pm.response.to.have.status(201));",
              "const { payment, check } = pm.response.json();",
              "pm.test('is approved', () => pm.expect(payment.status).to.eql('approved'));",
              "pm.test('closes the check', () => pm.expect(check.status).to.eql('paid'));",
              "pm.collectionVariables.set('paymentId', payment.id);"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "X-Visitor-Id",
            "value": "{{visitorId}}"
          },
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/api/checks/{{checkId}}/payments",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "checks",
            "{{checkId}}",
            "payments"
          ]
        },
        "body": {
          "mode": "raw",
          "raw": "{\n  \"idempotency_key\": \"{{idempotencyKey}}\",\n  \"method\": \"card\",\n  \"amount_cents\": {{balanceDue}},\n  \"tip_cents\": 0\n}"
        }
      }
    },
    {
      "name": "Repeat the charge: same outcome, no second charge",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('returns 200', () => pm.response.to.have.status(200));",
              "pm.test('returns the first payment', () => {",
              "\tpm.expect(pm.response.json().replayed).to.eql(true);",
              "\tpm.expect(pm.response.json().payment.id).to.eql(pm.collectionVariables.get('paymentId'));",
              "});"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "X-Visitor-Id",
            "value": "{{visitorId}}"
          },
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/api/checks/{{checkId}}/payments",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "checks",
            "{{checkId}}",
            "payments"
          ]
        },
        "body": {
          "mode": "raw",
          "raw": "{\n  \"idempotency_key\": \"{{idempotencyKey}}\",\n  \"method\": \"card\",\n  \"amount_cents\": {{balanceDue}},\n  \"tip_cents\": 0\n}"
        }
      }
    },
    {
      "name": "Read the receipt",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('returns 200', () => pm.response.to.have.status(200));",
              "pm.test('earned points', () => pm.expect(pm.response.json().points_earned).to.be.above(0));"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "X-Visitor-Id",
            "value": "{{visitorId}}"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/api/checks/{{checkId}}/receipt",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "checks",
            "{{checkId}}",
            "receipt"
          ]
        }
      }
    },
    {
      "name": "Check the webhook was delivered",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('returns 200', () => pm.response.to.have.status(200));",
              "const delivery = pm.response.json().find((d) => d.payment_id === pm.collectionVariables.get('paymentId'));",
              "pm.test('delivered payment.approved', () => {",
              "\tpm.expect(delivery.event_type).to.eql('payment.approved');",
              "\tpm.expect(delivery.status).to.eql('delivered');",
              "});"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "X-Visitor-Id",
            "value": "{{visitorId}}"
          }
        ],
        "url": {
          "raw": "{{baseUrl}}/api/webhooks/deliveries",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "api",
            "webhooks",
            "deliveries"
          ]
        }
      }
    }
  ]
}
