{
  "info": {
    "name": "ControlPOS · Integración de terminales",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
    "description": "Configura baseUrl con tu instancia de pruebas. El alta consume un código y la emisión crea tickets reales. Guarda el token localmente sin compartirlo. Usa la misma operationKey y cuerpo en reintentos; cambia la clave solo para una operación nueva."
  },
  "variable": [
    {
      "key": "baseUrl",
      "value": ""
    },
    {
      "key": "enrollmentCode",
      "value": ""
    },
    {
      "key": "terminalSerial",
      "value": "MARCA-MODELO-0001"
    },
    {
      "key": "terminalToken",
      "value": ""
    },
    {
      "key": "operationKey",
      "value": ""
    },
    {
      "key": "ticketId",
      "value": ""
    }
  ],
  "item": [
    {
      "name": "1 · Alta (una sola vez)",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": "{{baseUrl}}/api/terminals/enroll",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"enrollmentCode\": \"{{enrollmentCode}}\",\n  \"serial\": \"{{terminalSerial}}\",\n  \"tokenLabel\": \"Integración de pruebas\"\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        }
      }
    },
    {
      "name": "2a · Ticket en efectivo / reintentar",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          },
          {
            "key": "X-Terminal-Token",
            "value": "{{terminalToken}}"
          },
          {
            "key": "Idempotency-Key",
            "value": "{{operationKey}}"
          }
        ],
        "url": "{{baseUrl}}/api/tickets",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"terminalSerial\": \"{{terminalSerial}}\",\n  \"currency\": \"MXN\",\n  \"items\": [\n    {\n      \"name\": \"Consumo\",\n      \"qty\": 1,\n      \"price\": 100\n    }\n  ],\n  \"tip\": 10,\n  \"transactionType\": \"venta\",\n  \"capture\": {\n    \"orderReference\": \"ORDEN-0001\",\n    \"paymentMethod\": \"efectivo\"\n  }\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        }
      },
      "event": [
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "if (!pm.variables.get('baseUrl') || !pm.variables.get('terminalToken') || !pm.variables.get('operationKey')) {",
              "  pm.execution.skipRequest();",
              "  throw new Error('Configura baseUrl, terminalToken y operationKey antes de emitir. Conserva la clave para reintentos.');",
              "}"
            ]
          }
        },
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('Emisión nueva o reintento correcto', () => pm.expect(pm.response.code).to.be.oneOf([200, 201]));",
              "if ([200,201].includes(pm.response.code)) {",
              "  const ticket = pm.response.json();",
              "  pm.test('La respuesta tiene id', () => pm.expect(ticket.id).to.be.a('string'));",
              "  pm.collectionVariables.set('ticketId', ticket.id);",
              "}"
            ]
          }
        }
      ]
    },
    {
      "name": "2b · Ticket con tarjeta (otra operación)",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          },
          {
            "key": "X-Terminal-Token",
            "value": "{{terminalToken}}"
          },
          {
            "key": "Idempotency-Key",
            "value": "{{operationKey}}"
          }
        ],
        "url": "{{baseUrl}}/api/tickets",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"terminalSerial\": \"{{terminalSerial}}\",\n  \"currency\": \"MXN\",\n  \"items\": [\n    {\n      \"name\": \"Café americano\",\n      \"qty\": 2,\n      \"price\": 45\n    },\n    {\n      \"name\": \"Sándwich\",\n      \"qty\": 1,\n      \"price\": 80\n    }\n  ],\n  \"tip\": 17,\n  \"transactionType\": \"venta\",\n  \"card\": {\n    \"brand\": \"visa\",\n    \"type\": \"debito\",\n    \"last4\": \"1234\",\n    \"entryMode\": \"contactless\"\n  },\n  \"capture\": {\n    \"orderReference\": \"ORDEN-0002\",\n    \"cashier\": \"CAJA-01\",\n    \"operationNumber\": \"000123\",\n    \"batchNumber\": \"001\",\n    \"affiliation\": \"AFILIACION-DE-PRUEBA\",\n    \"paymentMethod\": \"tarjeta\",\n    \"capturedAt\": \"2026-09-04T18:00:00Z\",\n    \"transaccionId\": \"3f2a9c1e-7b4d-4e8f-9a6b-1c2d3e4f5a6b\",\n    \"rrn\": \"000012345678\"\n  },\n  \"receiptTemplate\": \"consumo-restaurante\"\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        }
      },
      "event": [
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "if (!pm.variables.get('baseUrl') || !pm.variables.get('terminalToken') || !pm.variables.get('operationKey')) {",
              "  pm.execution.skipRequest();",
              "  throw new Error('Configura baseUrl, terminalToken y operationKey antes de emitir. Conserva la clave para reintentos.');",
              "}"
            ]
          }
        },
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('Emisión nueva o reintento correcto', () => pm.expect(pm.response.code).to.be.oneOf([200, 201]));",
              "if ([200,201].includes(pm.response.code)) {",
              "  const ticket = pm.response.json();",
              "  pm.test('La respuesta tiene id', () => pm.expect(ticket.id).to.be.a('string'));",
              "  pm.collectionVariables.set('ticketId', ticket.id);",
              "}"
            ]
          }
        }
      ]
    },
    {
      "name": "3 · Ver comprobante",
      "request": {
        "method": "GET",
        "url": "{{baseUrl}}/t/{{ticketId}}"
      }
    },
    {
      "name": "4 · PDF",
      "request": {
        "method": "GET",
        "url": "{{baseUrl}}/t/{{ticketId}}/pdf"
      }
    }
  ]
}
