{
  "info": {
    "_postman_id": "e4f8d1a2-3b4c-4d5e-9f8a-1b2c3d4e5f6a",
    "name": "TKS Suite - API Órdenes Externas (Medsys)",
    "description": "Colección oficial y determinista para pruebas de integración de órdenes externas de compra de medios hacia TKS Suite.\n\n### Entorno de Pruebas:\n- **Token por defecto:** `tks_sandbox_omd_7b3a9e1f5d2c4b8e` (entorno Sandbox aislado, seguro para pruebas automatizadas sin afectar producción).\n\n### Características de la Colección:\n- **Determinismo y Repetibilidad:** Utiliza variables dinámicas por corrida (`ORD-{{timestamp}}`) para garantizar que la suite se pueda ejecutar de forma ilimitada mediante el Collection Runner de Postman sin falsos positivos.\n- **Separación de Estados:** Distingue rigurosamente la creación nueva (201 Created / status: created, applied: true), el reintento idempotente (200 OK / status: duplicate), la actualización (200 OK / status: updated, applied: true) y la anulación (200 OK / status: updated, applied: true).\n- **Preservación Integral de Datos:** La solicitud 5 verifica por GET que los datos de cliente, RUC, gross_cost y total sobreviven íntegramente tras la actualización y la anulación.\n- **Cobertura de Errores:** Incluye pruebas específicas para 400 Bad Request, 401 Unauthorized, 403 Forbidden y 404 Not Found con validación exacta de mensajes y cabeceras de rate limiting.\n\n### Criterios de Aceptación para Sandbox (UAT):\n- **Escenario 413 (Payload Too Large):** El límite de transporte es 10 MB. Se verifica en sandbox transmitiendo una carga superior a 10 MB para confirmar que el gateway rechaza la transacción sin procesarla.\n- **Escenario 429 (Rate Limit Exceeded con Retry-After):** La cuota es de 120 req/min por compañía. Se prueba en sandbox mediante un script de saturación controlada de 130 peticiones consecutivas.\n- **Escenario 503 (Service Unavailable):** Se evalúa ante interrupciones de conectividad o mantenimiento en el cluster de base de datos.\n- **Escenario Orden Bloqueada (locked: true):** Cuando un usuario de TKS Suite emite una factura fiscal vinculada en Sage 50, la orden pasa a `locked: true`. Las actualizaciones posteriores quedan registradas como revisiones históricas sin pisar los valores facturados.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{tks_api_token}}",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "base_url",
      "value": "https://saas.tks.com.pa/functions/v1/external-orders",
      "type": "string",
      "description": "URL base del endpoint de ingesta de TKS Suite"
    },
    {
      "key": "tks_api_token",
      "value": "tks_sandbox_omd_7b3a9e1f5d2c4b8e",
      "type": "string",
      "description": "Bearer Token de Sandbox para OMD Centroamérica"
    },
    {
      "key": "test_order_num",
      "value": "50230",
      "type": "string"
    },
    {
      "key": "test_idem_created",
      "value": "50230-0-ORDER_CREATED",
      "type": "string"
    },
    {
      "key": "test_idem_updated",
      "value": "50230-1-ORDER_UPDATED",
      "type": "string"
    },
    {
      "key": "test_idem_cancelled",
      "value": "50230-2-ORDER_CANCELLED",
      "type": "string"
    },
    {
      "key": "test_multi_order_num",
      "value": "50231",
      "type": "string"
    },
    {
      "key": "test_pdf_order_num",
      "value": "50232",
      "type": "string"
    },
    {
      "key": "test_nopdf_order_num",
      "value": "50233",
      "type": "string"
    }
  ],
  "item": [
    {
      "name": "1. Ingesta de Orden Nueva - Servicio Único (POST 201 Created)",
      "event": [
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "var ts = Date.now();",
              "pm.collectionVariables.set('test_order_num', 'ORD-' + ts);",
              "pm.collectionVariables.set('test_idem_created', 'ORD-' + ts + '-0-CREATED');",
              "pm.collectionVariables.set('test_idem_updated', 'ORD-' + ts + '-1-UPDATED');",
              "pm.collectionVariables.set('test_idem_cancelled', 'ORD-' + ts + '-2-CANCELLED');"
            ]
          }
        },
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('Código HTTP 201 Created', function () {",
              "    pm.response.to.have.status(201);",
              "});",
              "pm.test('Orden creada en staging con status: created y applied: true', function () {",
              "    var json = pm.response.json();",
              "    pm.expect(json.status).to.eql('created');",
              "    pm.expect(json.order_number).to.eql(pm.collectionVariables.get('test_order_num'));",
              "    pm.expect(json.rev).to.eql(0);",
              "    pm.expect(json.applied).to.eql(true);",
              "    pm.expect(json.locked).to.eql(false);",
              "    pm.expect(json).to.have.property('id');",
              "});",
              "pm.test('Cabeceras de Rate Limiting presentes', function () {",
              "    pm.expect(pm.response.headers.has('X-RateLimit-Limit')).to.be.true;",
              "    pm.expect(pm.response.headers.has('X-RateLimit-Remaining')).to.be.true;",
              "});"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          },
          {
            "key": "Idempotency-Key",
            "value": "{{test_idem_created}}",
            "type": "text"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"event\": \"ORDER_CREATED\",\n  \"agency\": {\n    \"code\": \"OMD\",\n    \"name\": \"OMD Centroamérica\"\n  },\n  \"budget\": {\n    \"code\": \"BUD-2026-OMD-009\",\n    \"rev\": 0,\n    \"date\": \"2026-10-20\",\n    \"campaign\": \"Campaña Navideña McCafé 2026\",\n    \"brand\": \"McCafé\",\n    \"period\": {\n      \"start\": \"2026-11-01\",\n      \"end\": \"2026-12-31\"\n    }\n  },\n  \"client\": {\n    \"code\": \"CLI-MCD-01\",\n    \"name\": \"Arcos Dorados Panamá S.A.\",\n    \"ruc\": \"155667788-2-2020\",\n    \"dv\": \"45\",\n    \"email\": \"facturas.panama@arcosdorados.com\",\n    \"payment_terms_days\": 30\n  },\n  \"order\": {\n    \"order_number\": \"{{test_order_num}}\",\n    \"status\": \"ACTIVA\",\n    \"concept\": \"Compra\",\n    \"media_type\": \"TELEVISION\",\n    \"submedia_type\": \"SPOT PRIME TIME\",\n    \"provider\": {\n      \"code\": \"PROV-MEDCOM\",\n      \"name\": \"Corporación Medcom Panamá S.A.\",\n      \"ruc\": \"45678-1-123456\",\n      \"dv\": \"08\"\n    },\n    \"item_detail\": {\n      \"service_description\": \"Transmisión 20 Spots 30s Prime Time - McCafé\",\n      \"purchase_format\": \"ROTATIVO\",\n      \"version\": \"Spot Navidad 30s V1\",\n      \"ad_units\": 20,\n      \"unit_cost\": 250.00\n    },\n    \"financials\": {\n      \"currency\": \"USD\",\n      \"gross_cost\": 5000.00,\n      \"agency_fee\": 0.00,\n      \"itbms_pct\": 7.00,\n      \"itbms_amount\": 350.00,\n      \"total\": 5350.00\n    },\n    \"personnel\": {\n      \"planner\": \"Carlos Medina\",\n      \"buyer\": \"Valeria Rios\"\n    }\n  }\n}"
        },
        "url": {
          "raw": "{{base_url}}",
          "host": [
            "{{base_url}}"
          ]
        },
        "description": "Envía una nueva orden de compra a staging en TKS Suite. Valida código HTTP 201 Created y status: created determinista con applied: true."
      },
      "response": []
    },
    {
      "name": "2. Verificación de Idempotencia - Reintento Idéntico (POST 200 OK)",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('Código HTTP 200 OK en reintento idempotente', function () {",
              "    pm.response.to.have.status(200);",
              "});",
              "pm.test('No se duplica la orden: status duplicate e idempotency_key coincide', function () {",
              "    var json = pm.response.json();",
              "    pm.expect(json.status).to.eql('duplicate');",
              "    pm.expect(json.order_number).to.eql(pm.collectionVariables.get('test_order_num'));",
              "    pm.expect(json.idempotency_key).to.eql(pm.collectionVariables.get('test_idem_created'));",
              "    pm.expect(json.message).to.include('duplicado');",
              "});"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          },
          {
            "key": "Idempotency-Key",
            "value": "{{test_idem_created}}",
            "type": "text"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"event\": \"ORDER_CREATED\",\n  \"agency\": {\n    \"code\": \"OMD\",\n    \"name\": \"OMD Centroamérica\"\n  },\n  \"budget\": {\n    \"code\": \"BUD-2026-OMD-009\",\n    \"rev\": 0,\n    \"date\": \"2026-10-20\",\n    \"campaign\": \"Campaña Navideña McCafé 2026\",\n    \"brand\": \"McCafé\",\n    \"period\": {\n      \"start\": \"2026-11-01\",\n      \"end\": \"2026-12-31\"\n    }\n  },\n  \"client\": {\n    \"code\": \"CLI-MCD-01\",\n    \"name\": \"Arcos Dorados Panamá S.A.\",\n    \"ruc\": \"155667788-2-2020\",\n    \"dv\": \"45\",\n    \"email\": \"facturas.panama@arcosdorados.com\",\n    \"payment_terms_days\": 30\n  },\n  \"order\": {\n    \"order_number\": \"{{test_order_num}}\",\n    \"status\": \"ACTIVA\",\n    \"concept\": \"Compra\",\n    \"media_type\": \"TELEVISION\",\n    \"submedia_type\": \"SPOT PRIME TIME\",\n    \"provider\": {\n      \"code\": \"PROV-MEDCOM\",\n      \"name\": \"Corporación Medcom Panamá S.A.\",\n      \"ruc\": \"45678-1-123456\",\n      \"dv\": \"08\"\n    },\n    \"item_detail\": {\n      \"service_description\": \"Transmisión 20 Spots 30s Prime Time - McCafé\",\n      \"purchase_format\": \"ROTATIVO\",\n      \"version\": \"Spot Navidad 30s V1\",\n      \"ad_units\": 20,\n      \"unit_cost\": 250.00\n    },\n    \"financials\": {\n      \"currency\": \"USD\",\n      \"gross_cost\": 5000.00,\n      \"agency_fee\": 0.00,\n      \"itbms_pct\": 7.00,\n      \"itbms_amount\": 350.00,\n      \"total\": 5350.00\n    },\n    \"personnel\": {\n      \"planner\": \"Carlos Medina\",\n      \"buyer\": \"Valeria Rios\"\n    }\n  }\n}"
        },
        "url": {
          "raw": "{{base_url}}",
          "host": [
            "{{base_url}}"
          ]
        },
        "description": "Reenvía exactamente el mismo mensaje con la misma Idempotency-Key. Demuestra de forma estricta que no se crea un duplicado y que el servidor responde HTTP 200 con status: duplicate."
      },
      "response": []
    },
    {
      "name": "3. Actualizar Orden Existente (POST 200 OK)",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('Código HTTP 200 OK en actualización', function () {",
              "    pm.response.to.have.status(200);",
              "});",
              "pm.test('Actualización aplicada: status updated, applied: true y rev: 1', function () {",
              "    var json = pm.response.json();",
              "    pm.expect(json.status).to.eql('updated');",
              "    pm.expect(json.order_number).to.eql(pm.collectionVariables.get('test_order_num'));",
              "    pm.expect(json.rev).to.eql(1);",
              "    pm.expect(json.applied).to.eql(true);",
              "    pm.expect(json.locked).to.eql(false);",
              "});"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          },
          {
            "key": "Idempotency-Key",
            "value": "{{test_idem_updated}}",
            "type": "text"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"event\": \"ORDER_UPDATED\",\n  \"agency\": {\n    \"code\": \"OMD\",\n    \"name\": \"OMD Centroamérica\"\n  },\n  \"budget\": {\n    \"code\": \"BUD-2026-OMD-009\",\n    \"rev\": 1,\n    \"date\": \"2026-10-21\",\n    \"campaign\": \"Campaña Navideña McCafé 2026 (Ajuste Tarifa)\",\n    \"brand\": \"McCafé\"\n  },\n  \"client\": {\n    \"code\": \"CLI-MCD-01\",\n    \"name\": \"Arcos Dorados Panamá S.A.\",\n    \"ruc\": \"155667788-2-2020\",\n    \"dv\": \"45\"\n  },\n  \"order\": {\n    \"order_number\": \"{{test_order_num}}\",\n    \"status\": \"MODIFICADA\",\n    \"concept\": \"Compra\",\n    \"item_detail\": {\n      \"service_description\": \"Transmisión 24 Spots 30s Prime Time - McCafé\",\n      \"ad_units\": 24,\n      \"unit_cost\": 250.00\n    },\n    \"financials\": {\n      \"currency\": \"USD\",\n      \"gross_cost\": 6000.00,\n      \"agency_fee\": 0.00,\n      \"itbms_pct\": 7.00,\n      \"itbms_amount\": 420.00,\n      \"total\": 6420.00\n    }\n  }\n}"
        },
        "url": {
          "raw": "{{base_url}}",
          "host": [
            "{{base_url}}"
          ]
        },
        "description": "Envía una modificación a la orden creada con rev: 1. Demuestra que se aplica la actualización con status: updated y applied: true."
      },
      "response": []
    },
    {
      "name": "4. Anular Orden Existente - Mensaje Mínimo (POST 200 OK)",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('Código HTTP 200 OK en anulación', function () {",
              "    pm.response.to.have.status(200);",
              "});",
              "pm.test('Anulación procesada con éxito: status updated, applied: true y rev: 2', function () {",
              "    var json = pm.response.json();",
              "    pm.expect(json.status).to.eql('updated');",
              "    pm.expect(json.order_number).to.eql(pm.collectionVariables.get('test_order_num'));",
              "    pm.expect(json.rev).to.eql(2);",
              "    pm.expect(json.applied).to.eql(true);",
              "});"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          },
          {
            "key": "Idempotency-Key",
            "value": "{{test_idem_cancelled}}",
            "type": "text"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"event\": \"ORDER_CANCELLED\",\n  \"agency\": {\n    \"code\": \"OMD\",\n    \"name\": \"OMD Centroamérica\"\n  },\n  \"budget\": {\n    \"code\": \"BUD-2026-OMD-009\",\n    \"rev\": 2\n  },\n  \"order\": {\n    \"order_number\": \"{{test_order_num}}\",\n    \"status\": \"ANULADA\"\n  }\n}"
        },
        "url": {
          "raw": "{{base_url}}",
          "host": [
            "{{base_url}}"
          ]
        },
        "description": "Notifica la anulación de la orden mediante un mensaje mínimo (sin cliente ni montos). Valida que se registre la anulación con applied: true."
      },
      "response": []
    },
    {
      "name": "5. Consultar y Verificar Preservación de Datos tras Anulación (GET 200 OK)",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('Código HTTP exitoso (200 OK)', function () {",
              "    pm.response.to.have.status(200);",
              "});",
              "pm.test('Verificación de preservación íntegra: cliente, RUC y montos permanecen intactos tras anulación', function () {",
              "    var json = pm.response.json();",
              "    pm.expect(json.order_number).to.eql(pm.collectionVariables.get('test_order_num'));",
              "    pm.expect(json.billing_status).to.eql('cancelled');",
              "    pm.expect(json.locked).to.eql(false);",
              "    pm.expect(json.stored_rev).to.eql(2);",
              "    pm.expect(json.client_name).to.eql('Arcos Dorados Panamá S.A.');",
              "    pm.expect(json.client_ruc).to.eql('155667788-2-2020');",
              "    pm.expect(json.gross_cost).to.eql(6000);",
              "    pm.expect(json.total).to.eql(6420);",
              "});"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [],
        "url": {
          "raw": "{{base_url}}?order_number={{test_order_num}}",
          "host": [
            "{{base_url}}"
          ],
          "query": [
            {
              "key": "order_number",
              "value": "{{test_order_num}}",
              "description": "Número de orden dinámico creado en la corrida"
            }
          ]
        },
        "description": "Consulta el estado actual de la orden en staging. Valida estrictamente que el nombre del cliente, RUC, gross_cost y total sobrevivieron a la anulación mínima sin borrarse."
      },
      "response": []
    },
    {
      "name": "6. Ingesta de Orden Multi-Servicio con Items (POST 201 Created)",
      "event": [
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "var ts = Date.now();",
              "pm.collectionVariables.set('test_multi_order_num', 'ORD-MULTI-' + ts);"
            ]
          }
        },
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('Código HTTP 201 Created', function () {",
              "    pm.response.to.have.status(201);",
              "});",
              "pm.test('Orden multi-servicio registrada: status created y applied: true', function () {",
              "    var json = pm.response.json();",
              "    pm.expect(json.status).to.eql('created');",
              "    pm.expect(json.order_number).to.eql(pm.collectionVariables.get('test_multi_order_num'));",
              "    pm.expect(json.applied).to.eql(true);",
              "});"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          },
          {
            "key": "Idempotency-Key",
            "value": "{{test_multi_order_num}}-0-CREATED",
            "type": "text"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"event\": \"ORDER_CREATED\",\n  \"agency\": {\n    \"code\": \"OMD\",\n    \"name\": \"OMD Centroamérica\"\n  },\n  \"budget\": {\n    \"code\": \"BUD-2026-OMD-010\",\n    \"rev\": 0,\n    \"date\": \"2026-10-20\",\n    \"campaign\": \"Campaña Digital y TV McCafé\",\n    \"brand\": \"McCafé\"\n  },\n  \"client\": {\n    \"code\": \"CLI-MCD-01\",\n    \"name\": \"Arcos Dorados Panamá S.A.\",\n    \"ruc\": \"155667788-2-2020\",\n    \"dv\": \"45\"\n  },\n  \"order\": {\n    \"order_number\": \"{{test_multi_order_num}}\",\n    \"status\": \"ACTIVA\",\n    \"concept\": \"Compra\",\n    \"items\": [\n      {\n        \"service_description\": \"15 Spots Telemetro Prime Time 30s\",\n        \"purchase_format\": \"ROTATIVO PRIME\",\n        \"version\": \"Navidad V1\",\n        \"ad_units\": 15,\n        \"unit_cost\": 200.00,\n        \"gross_cost\": 3000.00,\n        \"itbms_pct\": 7.00\n      },\n      {\n        \"service_description\": \"10 Spots RPC TV Rotativo 30s\",\n        \"purchase_format\": \"ROTATIVO\",\n        \"version\": \"Navidad V1\",\n        \"ad_units\": 10,\n        \"unit_cost\": 200.00,\n        \"gross_cost\": 2000.00,\n        \"itbms_pct\": 7.00\n      }\n    ],\n    \"financials\": {\n      \"currency\": \"USD\",\n      \"gross_cost\": 5000.00,\n      \"agency_fee\": 0.00,\n      \"itbms_pct\": 7.00,\n      \"itbms_amount\": 350.00,\n      \"total\": 5350.00\n    }\n  }\n}"
        },
        "url": {
          "raw": "{{base_url}}",
          "host": [
            "{{base_url}}"
          ]
        },
        "description": "Envía una orden con desglose multi-servicio en el arreglo items. La suma de gross_cost de cada ítem (3000 + 2000) concuerda con gross_cost de 5000."
      },
      "response": []
    },
    {
      "name": "7. Ingesta con Respaldo PDF Válido en Base64 (POST 201 Created)",
      "event": [
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "var ts = Date.now();",
              "pm.collectionVariables.set('test_pdf_order_num', 'ORD-PDF-' + ts);"
            ]
          }
        },
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('Código HTTP 201 Created', function () {",
              "    pm.response.to.have.status(201);",
              "});",
              "pm.test('Orden con PDF procesada: status created, applied: true y propiedad pdf_stored', function () {",
              "    var json = pm.response.json();",
              "    pm.expect(json.status).to.eql('created');",
              "    pm.expect(json.order_number).to.eql(pm.collectionVariables.get('test_pdf_order_num'));",
              "    pm.expect(json.applied).to.eql(true);",
              "    pm.expect(json).to.have.property('pdf_stored');",
              "    pm.expect(json.pdf_stored).to.eql(true);",
              "});"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          },
          {
            "key": "Idempotency-Key",
            "value": "{{test_pdf_order_num}}-0-CREATED",
            "type": "text"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"event\": \"ORDER_CREATED\",\n  \"sent_at\": \"2026-10-21T10:00:00Z\",\n  \"agency\": {\n    \"code\": \"OMD\",\n    \"name\": \"OMD Centroamérica\"\n  },\n  \"budget\": {\n    \"code\": \"BUD-2026-OMD-011\",\n    \"rev\": 0,\n    \"date\": \"2026-10-21\",\n    \"campaign\": \"Campaña Digital 2026\",\n    \"brand\": \"McCafé\"\n  },\n  \"client\": {\n    \"code\": \"CLI-MCD-01\",\n    \"name\": \"Arcos Dorados Panamá S.A.\",\n    \"ruc\": \"155667788-2-2020\",\n    \"dv\": \"45\"\n  },\n  \"order\": {\n    \"order_number\": \"{{test_pdf_order_num}}\",\n    \"status\": \"ACTIVA\",\n    \"concept\": \"Compra\",\n    \"item_detail\": {\n      \"service_description\": \"Pauta Digital Programática\",\n      \"ad_units\": 1,\n      \"unit_cost\": 1500.00\n    },\n    \"financials\": {\n      \"currency\": \"USD\",\n      \"gross_cost\": 1500.00,\n      \"agency_fee\": 0.00,\n      \"itbms_pct\": 7.00,\n      \"itbms_amount\": 105.00,\n      \"total\": 1605.00\n    },\n    \"custom_fields\": {\n      \"cost_center\": \"CC-PAN-MKT-01\",\n      \"contract_ref\": \"MEDCOM-2026-998\"\n    },\n    \"replaces_order_number\": null,\n    \"pdf\": {\n      \"filename\": \"OC-Digital-OMD.pdf\",\n      \"content_base64\": \"JVBERi0xLjQKMSAwIG9iajw8L1R5cGUvQ2F0YWxvZy9QYWdlcyAyIDAgUj4+ZW5kb2JqCjIgMCBvYmo8PC9UeXBlL1BhZ2VzL0NvdW50IDEvS2lkc1szIDAgUl0+PmVuZG9iagozIDAgb2JqPDwvVHlwZS9QYWdlL01lZGlhQm94WzAgMCA2MTIgNzkyXS9QYXJlbnQgMiAwIFIvUmVzb3VyY2VzPDw+Pj4+ZW5kb2JqCnhyZWYKMCA0CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDUyIDAwMDAwIG4gCjAwMDAwMDAxMDEgMDAwMDAgbiAKdHJhaWxlcjw8L1NpemUgNC9Sb290IDEgMCBSPj4Kc3RhcnR4cmVmCjE3OAolJUVPRg==\"\n    }\n  }\n}"
        },
        "url": {
          "raw": "{{base_url}}",
          "host": [
            "{{base_url}}"
          ]
        },
        "description": "Envía una orden con archivo PDF válido binario codificado en Base64. Verifica almacenamiento del adjunto con pdf_stored."
      },
      "response": []
    },
    {
      "name": "8. Ingesta Omitiendo Adjunto (pdf: null) (POST 201 Created)",
      "event": [
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "var ts = Date.now();",
              "pm.collectionVariables.set('test_nopdf_order_num', 'ORD-NOPDF-' + ts);"
            ]
          }
        },
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('Código HTTP 201 Created', function () {",
              "    pm.response.to.have.status(201);",
              "});",
              "pm.test('Orden sin PDF ingresa con applied: true, needs_review: true y pdf_stored: false', function () {",
              "    var json = pm.response.json();",
              "    pm.expect(json.status).to.eql('created');",
              "    pm.expect(json.order_number).to.eql(pm.collectionVariables.get('test_nopdf_order_num'));",
              "    pm.expect(json.applied).to.eql(true);",
              "    pm.expect(json.needs_review).to.eql(true);",
              "    pm.expect(json.pdf_stored).to.eql(false);",
              "});"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          },
          {
            "key": "Idempotency-Key",
            "value": "{{test_nopdf_order_num}}-0-CREATED",
            "type": "text"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"event\": \"ORDER_CREATED\",\n  \"agency\": {\n    \"code\": \"OMD\",\n    \"name\": \"OMD Centroamérica\"\n  },\n  \"budget\": {\n    \"code\": \"BUD-2026-OMD-012\",\n    \"rev\": 0\n  },\n  \"client\": {\n    \"code\": \"CLI-MCD-01\",\n    \"name\": \"Arcos Dorados Panamá S.A.\",\n    \"ruc\": \"155667788-2-2020\",\n    \"dv\": \"45\"\n  },\n  \"order\": {\n    \"order_number\": \"{{test_nopdf_order_num}}\",\n    \"status\": \"ACTIVA\",\n    \"concept\": \"Compra\",\n    \"financials\": {\n      \"currency\": \"USD\",\n      \"gross_cost\": 2000.00,\n      \"agency_fee\": 0.00,\n      \"itbms_pct\": 7.00,\n      \"itbms_amount\": 140.00,\n      \"total\": 2140.00\n    },\n    \"pdf\": null\n  }\n}"
        },
        "url": {
          "raw": "{{base_url}}",
          "host": [
            "{{base_url}}"
          ]
        },
        "description": "Demuestra la ingesta exitosa de una orden omitiendo el PDF (pdf: null). Comprueba que applied es true, needs_review es true y pdf_stored es false."
      },
      "response": []
    },
    {
      "name": "9. Validación de Error - Sin order_number (POST 400 Bad Request)",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('Código HTTP 400 Bad Request', function () {",
              "    pm.response.to.have.status(400);",
              "});",
              "pm.test('Esquema de error exacto con campo faltante', function () {",
              "    var json = pm.response.json();",
              "    pm.expect(json.error).to.eql('El campo order.order_number es obligatorio para identificar la orden');",
              "    pm.expect(json.field).to.eql('order.order_number');",
              "});"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"event\": \"ORDER_CREATED\",\n  \"agency\": {\n    \"code\": \"OMD\"\n  },\n  \"order\": {\n    \"concept\": \"Compra sin numero de orden\"\n  }\n}"
        },
        "url": {
          "raw": "{{base_url}}",
          "host": [
            "{{base_url}}"
          ]
        },
        "description": "Demuestra la respuesta formal 400 Bad Request cuando se omite el campo obligatorio order.order_number."
      },
      "response": []
    },
    {
      "name": "10. Simulación Error de Autenticación - Token Inválido (POST 401 Unauthorized)",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('Código HTTP 401 Unauthorized', function () {",
              "    pm.response.to.have.status(401);",
              "});",
              "pm.test('Mensaje de error: Token inválido o inactivo', function () {",
              "    var json = pm.response.json();",
              "    pm.expect(json.error).to.eql('Token inválido o inactivo');",
              "});"
            ]
          }
        }
      ],
      "request": {
        "auth": {
          "type": "bearer",
          "bearer": [
            {
              "key": "token",
              "value": "token_invalido_de_prueba",
              "type": "string"
            }
          ]
        },
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"event\": \"ORDER_CREATED\",\n  \"order\": {\n    \"order_number\": \"99999\"\n  }\n}"
        },
        "url": {
          "raw": "{{base_url}}",
          "host": [
            "{{base_url}}"
          ]
        },
        "description": "Demuestra la respuesta formal 401 Unauthorized cuando se utiliza un token inválido o revocado."
      },
      "response": []
    },
    {
      "name": "11. Validación de Error - Token No Autorizado para Agencia (POST 403 Forbidden)",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('Código HTTP 403 Forbidden', function () {",
              "    pm.response.to.have.status(403);",
              "});",
              "pm.test('Mensaje de error indica falta de permiso para la agencia', function () {",
              "    var json = pm.response.json();",
              "    pm.expect(json.error).to.eql('Token sin permiso para esa agencia');",
              "});"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"event\": \"ORDER_CREATED\",\n  \"agency\": {\n    \"code\": \"OTRA_AGENCIA_NO_ASIGNADA\"\n  },\n  \"order\": {\n    \"order_number\": \"TEST-FORBIDDEN-403\"\n  }\n}"
        },
        "url": {
          "raw": "{{base_url}}",
          "host": [
            "{{base_url}}"
          ]
        },
        "description": "Demuestra la respuesta formal 403 Forbidden cuando el Bearer Token no tiene permisos para la agencia indicada en agency.code."
      },
      "response": []
    },
    {
      "name": "12. Validación de Error - Consulta de Orden Inexistente (GET 404 Not Found)",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('Código HTTP 404 Not Found', function () {",
              "    pm.response.to.have.status(404);",
              "});",
              "pm.test('Mensaje de error exacto documentado: Orden no encontrada', function () {",
              "    var json = pm.response.json();",
              "    pm.expect(json.error).to.eql('Orden no encontrada');",
              "});"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [],
        "url": {
          "raw": "{{base_url}}?order_number=ORDEN_INEXISTENTE_999999",
          "host": [
            "{{base_url}}"
          ],
          "query": [
            {
              "key": "order_number",
              "value": "ORDEN_INEXISTENTE_999999",
              "description": "Número de orden inexistente para validar respuesta 404"
            }
          ]
        },
        "description": "Demuestra la respuesta formal 404 Not Found cuando se consulta el estado de una orden que no existe en el sistema."
      },
      "response": []
    },
    {
      "name": "13. Verificación de Cabeceras de Tasa (Rate Limit X-RateLimit-*) - GET",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('Cabeceras de límite de tasa presentes', function () {",
              "    pm.response.to.have.header('X-RateLimit-Limit');",
              "    pm.response.to.have.header('X-RateLimit-Remaining');",
              "    pm.response.to.have.header('X-RateLimit-Reset');",
              "});"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [],
        "url": {
          "raw": "{{base_url}}?order_number=test_rate_limit",
          "host": [
            "{{base_url}}"
          ],
          "query": [
            {
              "key": "order_number",
              "value": "test_rate_limit"
            }
          ]
        },
        "description": "Verifica la presencia de las cabeceras estándar de control de concurrencia X-RateLimit-* según la política de 120 req/min."
      },
      "response": []
    }
  ]
}