Завдання та передумови

Порівняти суму заявки з персональним лімітом підрозділу, а не з однією константою для всіх.

Приклад містить навчальні дані та налаштування. Виберіть власні тестові джерела й підключення замість ідентифікаторів demo_*, відтворіть очікуваний результат і лише потім використовуйте робочі об’єкти.

Навчальні вхідні дані

requests.csv

Request;Dept;Amount
R1;IT;900
R2;HR;600
R3;IT;1200

limits.csv

Dept;Limit
IT;1000
HR;500

Блоки, зв’язки й точні налаштування

Пояснювальна схемаЗбільшити ↗11. Маршрутизація за довідником лімітів. Топологія прикладу 11: 7 блоків, 6 зв’язків. Збережено ідентифікатори вузлів і порти налаштованого графа.
Схема потоку 11

Топологія прикладу 11: 7 блоків, 6 зв’язків. Збережено ідентифікатори вузлів і порти налаштованого графа.

Схема: заявки й ліміти → Join за Dept → контроль наявності ліміту → маршрутизація Amount > Limit → два результати. Join має лівий тип і many_to_one, щоб дублікати довідника не множили заявки. Після Join поля мають префікси r. та l.

{
  "version": 3,
  "nodes": [
    {
      "id": "requests",
      "type": "file",
      "label": "Requests",
      "config": {
        "role": "source",
        "source_id": "demo_requests",
        "options": {
          "sheet": "CSV",
          "range": "A1:C4",
          "header": true,
          "delimiter": ";"
        }
      }
    },
    {
      "id": "limits",
      "type": "file",
      "label": "Limits",
      "config": {
        "role": "source",
        "source_id": "demo_limits",
        "options": {
          "sheet": "CSV",
          "range": "A1:B3",
          "header": true,
          "delimiter": ";"
        }
      }
    },
    {
      "id": "join",
      "type": "join",
      "label": "Department limit",
      "config": {
        "inputs": [
          {
            "id": "requests",
            "alias": "r"
          },
          {
            "id": "limits",
            "alias": "l",
            "how": "left",
            "keys": [
              {
                "left": "r.Dept",
                "right": "Dept"
              }
            ],
            "cardinality": "many_to_one"
          }
        ]
      }
    },
    {
      "id": "quality",
      "type": "quality",
      "label": "Limit required",
      "config": {
        "rules": [
          {
            "fields": [
              "l.Limit"
            ],
            "condition": "empty",
            "action": "error"
          }
        ]
      }
    },
    {
      "id": "router",
      "type": "router",
      "label": "Limit check",
      "config": {
        "route_type": "conditions",
        "mode": "first",
        "default_route": true,
        "routes": [
          {
            "id": "over",
            "label": "Over limit",
            "predicates": [
              {
                "column": "r.Amount",
                "op": "gt",
                "numeric": true,
                "value_mode": "field",
                "value_field": "l.Limit"
              }
            ]
          }
        ]
      }
    },
    {
      "id": "over_out",
      "type": "export",
      "label": "Over limit",
      "config": {
        "format": "csv",
        "filename": "over_limit",
        "destination": "download",
        "delimiter": ";",
        "timezone": "Europe/Kyiv"
      }
    },
    {
      "id": "within_out",
      "type": "export",
      "label": "Within limit",
      "config": {
        "format": "csv",
        "filename": "within_limit",
        "destination": "download",
        "delimiter": ";",
        "timezone": "Europe/Kyiv"
      }
    }
  ],
  "edges": [
    {
      "source": "requests",
      "target": "join",
      "source_port": "out",
      "target_port": "requests"
    },
    {
      "source": "limits",
      "target": "join",
      "source_port": "out",
      "target_port": "limits"
    },
    {
      "source": "join",
      "target": "quality",
      "source_port": "out",
      "target_port": "in"
    },
    {
      "source": "quality",
      "target": "router",
      "source_port": "out",
      "target_port": "in"
    },
    {
      "source": "router",
      "target": "over_out",
      "source_port": "over",
      "target_port": "in"
    },
    {
      "source": "router",
      "target": "within_out",
      "source_port": "else",
      "target_port": "in"
    }
  ]
}

Очікуваний результат

over_limit.csv містить R2 (600 > 500) і R3 (1200 > 1000). within_limit.csv містить R1 (900 ≤ 1000). Результат також має приєднаний ліміт; поля заявок мають префікс r., поля довідника — l.

Запуск і перевірка

  1. Зареєструйте обидва CSV та перевірте один ліміт на Dept.
  2. Зберіть граф із JSON; у Join виберіть requests як основний вхід, limits — ліве приєднання за Dept.
  3. Перевірте l.Limit у результаті Join та правило помилки для порожнього ліміту.
  4. Перевірте три заявки: R1 — у межах, R2 і R3 — перевищення.
  5. Додайте Dept=FIN без ліміту: контроль якості має зупинити процес до експорту.

Типові помилки

  • Використовуйте точні назви r.Amount і l.Limit після Join.
  • Повтор Dept у довіднику порушує many_to_one; виправте довідник.
  • Не замінюйте відсутній ліміт нулем без бізнес-правила.
  • Маршрутизатор порівнює поля поточного рядка, тому старий порт reference не потрібен.