Интеграции
Опасният запис в ERP е този, който успява
Released интерфейси, idempotency ключове и read-back проверка — и записът, който успява срещу deprecated endpoint, докато всички табла остават зелени.
- Публикувано
- Четене
- 8 мин
- Стъпва на
- Clean core доктрината на SAP, публикувани лимити на платформите (Temporal, Camunda 8, Power Automate, n8n) и интеграционна практика; метод, а не доставена ERP интеграция — границата е в края
Платежен цикъл осчетоводява 412 фактури от доставчици. Връзката пада на номер 287. Някой рестартира задачата и 126 фактури влизат втори път.
ERP-ът е работил коректно през цялото време. Поискали са от него да създаде документи и той ги е създал. Счупила се е интеграцията — и то по начина, по който интеграциите обикновено се чупят: не с грешка, а изпълнявайки точно това, което ѝ е казано, два пъти.
„Released“ или не — първият въпрос, и той не е въпрос на вкус
Clean core доктрината на SAP формулира правилото най-ясно: разширявате през released API-та и extension points или side-by-side върху BTP, но не пипате core ABAP. Санкционираните пътища за запис са BAPI, OData през SAP Gateway, IDoc и Business Events. Несанкционираните са директен UPDATE в таблица, unreleased функционални модули и запис на екрана през SAP GUI. Всеки производител тегли същата линия под друго име — Business Events в Dynamics 365 F&O, SuiteTalk REST в NetSuite, FBDI зареждания в Oracle Fusion, XML-RPC в Odoo, Service Layer в SAP Business One, който е и най-честият SAP отпечатък в българския среден бизнес.
Кажете честно какво струва released пътят, защото преструвката, че е безплатен, е причината екипите тихо да го заобикалят. По-бавен е, понякога му липсва точно полето, което ви трябва, и ще ви накара да моделирате зареждане от 5 000 реда като 5 000 извиквания. Директният INSERT се пише по-бързо и се изпълнява по-бързо. Той е и това, което ъпгрейдът чупи, без да ви каже, защото никой не е гарантирал формата на таблица, която не е трябвало да пипате. Това не е пряк път с прикачен риск; това е пасив с падеж, а падежът е следващата мажорна версия.
Там, където released път за запис наистина няма — а в Microinvest Delta Pro, Ажур L или Плюс Минус често няма — оставете UI автоматизацията, но я пренапишете като версиониран Playwright код с contract тестове, които вървят всяка нощ срещу целевата система, под service account вместо под нечий личен профил, и я запишете като дълг с дата за преглед. Селекторите са най-големият единичен източник на счупвания във всеки bot estate.
At-least-once без idempotency ключ е машина за дублирани плащания
Всяка опашка, всеки HTTP клиент и всеки orchestrator, който вероятно ще ползвате, по подразбиране е at-least-once. Това е правилното подразбиране и означава, че една и съща инструкция понякога ще се изпълни два пъти.
Убиецът е двусмисленият timeout. Синхронен POST, който изтича — Power Automate реже изходящия синхронен HTTP на 120 секунди — не казва нищо за това дали ERP-ът е commit-нал. Възможно е да е commit-нал и отговорът да се е загубил по обратния път. Повторите ли, рискувате дубликат; не повторите ли, може да не сте осчетоводили нищо.
Ключът се извежда от бизнес идентичността, никога от опита: доставчик, номер на фактура и сума при осчетоводяване по доставчици; номер на клиентската поръчка при продажба. UUID, генериран в момента на повторението, не е idempotency ключ. Timestamp — също.
Повечето ERP системи не ви дават нищо тук; няма Idempotency-Key header, който да ви чака. Регистърът е ваша работа: таблица, която владеете вие, ключувана по бизнес ключа и пазеща номера на документа в ERP, който този ключ е произвел — записана преди извикването и допълнена след него. Тогава повторението е lookup. И проверката стои на границата с ERP-а, не на опашката: дедупликация на съобщения не е дедупликация на осчетоводявания, защото вторият опит идва като различно съобщение, от друг worker, след рестарт.
В български контекст има и втори слой. Ако системата, в която пишете, попада под Наредба Н-18 и режима СУПТО, всяка продажба носи уникален номер и одитна следа. Дубликат от retry вече не е просто мръсни данни, а разминаване в регистър, който НАП може да поиска. Idempotency ключът там е контрол по съответствие, не оптимизация.
HTTP 201 казва нещо за заявката ви, не за документа
Отговор 2xx означава, че заявката е приета и обикновено че се е върнал номер на документ. Не означава, че обектът съществува в състоянието, което сте искали: прилагат се default-и, substitution правила пренаписват разходния център, а изпратено от вас поле се изхвърля мълчаливо, защото не е част от released структурата.
Затова проверката стои върху read-back-а. След записа прочетете документа през интерфейса, през който бизнесът реално го чете — репортната справка, CDS view-то, OData entity-то, към което е закачен отчетът на финансите — и сравнете кратък списък от поименни полета, а не целия payload, който винаги се различава, докато всички спрат да гледат diff-а. Ако интеграционният ви тест не прави пълен кръг, той тества собствения ви сериализатор.
Записът срещу deprecated интерфейс е повредата, която никой не вижда
Механизмът е конкретен. Производителят пуска версия, структура се заменя, а стар endpoint остава за обратна съвместимост — където вече пише в наследена структура, която никой надолу по веригата не чете. Извикването връща 200, orchestrator-ът записва успех и таблото остава зелено, защото таблото чете статус на изпълнение, а не бизнес резултат.
Никой технически монитор не хваща това, защото технически нищо не се е счупило. Излиза наяве, когато на месечно приключване някой забележи, че една сума не е вярна — а дотогава има седмици записи за изчистване.
Три контрола, от най-евтиния нагоре:
- Дневна равносметка по брой: документите, които orchestrator-ът смята, че е създал за периода, срещу собствената репортна справка на ERP-а за същия период, с аларма при разлика от един.
- Canary запис в sandbox след всеки пач на ERP-а и всеки ъпгрейд на конектора, проверен с read-back по поименни полета.
- Изрично фиксирана версия на интерфейса в самото извикване, за да стане промяната на server default съзнателна миграция.
Status колона и cron спират да стигат при първия случай, който чака
Схемата е коректна по-дълго, отколкото хората признават: status колона и задача, която взима редовете в едно състояние, свършва работата и ги мести нататък. Не я сменяйте, преди да се наложи.
Спира да стига на четири места: когато случаят чака дни за нещо извън вашия контрол — складова разписка или одобрение; когато вече commit-ната стъпка трябва да бъде върната, защото по-късна е паднала; когато различните стъпки искат различни retry политики вместо едно общо презареждане; и когато някой трябва да отговори „къде е случай 4471 и защо“, без да чете кода ви.
Признакът е в схемата на базата. В момента, в който таблицата е събрала retry_count, last_error, locked_by и locked_at, status enum-ът е минал осем стойности, а някой е написал втори cron, който отпушва редовете, останали в running след срив — вие вече сте построили workflow engine. Без история, без таймери и без видимост.
Durable orchestrator ви дава failure handling срещу determinism
Наблюдението на Flaviu Cristian, което Temporal обича да цитира: кодът за обработка на грешки е над две трети от една продукционна система. Това е честната причина happy path от 200 реда да отнема три месеца, докато стане надежден, и точно това продава durable execution — event-sourced история, която преживява смъртта на процеса и върши работа и на одитна следа, retry политики на ниво activity с backoff, таймери в дни и компенсиращи транзакции за вече минали стъпки.
Плащате с determinism. Workflow кодът не може да вика системния часовник, random, мрежата или база; целият I/O отива в Activities, извън replay пътя. А добавянето, премахването или разместването на извиквания, които генерират команди, чупи вече течащи изпълнения, освен ако не ползвате patching или Worker Versioning — което променя процеса ви по деплой, а не само кода.
Таваните идват през втората година. Temporal ограничава event history до 51 200 събития и 50 MB на изпълнение, с предупреждение на 10 240 събития, така че дълго живеещите entity workflow-и трябва да минат през Continue-As-New преди това; Camunda 8 иска оразмеряване за около 20 пъти средното натоварване. Power Automate позволява 500 действия на flow и пази историята на изпълненията 30 дни — прочетете това два пъти: ако одитната следа на едно осчетоводяване живее само в run history, тя престава да съществува след месец. n8n по подразбиране реже на 336 часа и 10 000 изпълнения. Пишете одитния запис някъде трайно, което е ваше.
Докъде важи това
Ако пишете по няколко нискостойностни записа на ден, без движение на пари и без документ със законово значение, status колоната и cron-ът са правилната архитектура, а orchestrator-ът е дежурство без насрещна полза. Решаващото не е обемът, а дали дубликат или изгубен запис струва пари или чупи контрол.
Сметката тук е различна и по друга линия. По Eurostat часовата цена на труда в България за 2025 г. е 12,0 EUR срещу 34,9 EUR средно за ЕС, така че интеграция, обоснована само с премахване на преписване, има близо тройно по-дълъг период на възвръщаемост от този, който западният шаблон допуска. Обосновавайте я с експозицията към дублирани плащания и с времето за цикъл, не със спестени часове.
И накрая — за нас. Palamed има четири доставени ангажимента: европейски маркетплейс за автомобили с над 300 000 обяви, платформа за агенция за AI автоматизация, дигиталният речник на Министерството на образованието и науката на beron.mon.bg и email marketing автоматизация за бранд в козметиката, където около 60% съкращение на времето за комуникация е измерване на самия клиент. Нито един от тях не е продукционна интеграция със запис в ERP. Всичко по-горе е публикуваният модел, документираните лимити на производителите и доктрината, върху която стои пътят за запис.
Което оставя два въпроса към всеки интегратор, включително към нас. От какво е изведен idempotency ключът и какво проверява read-back-ът? Ако и двата отговора са мъгливи, останалото в офертата е декорация.
