Как знают держатели дебетовых банковских карт Райффайзенбанка, карта является лишь инструментом доступа к счету: она не имеет собственного баланса, по ней доступны только те средства, которые есть на текущем счете клиента. В этой статье мы расскажем об архитектуре технического решения, которое позволяет картам и счетам в нашем банке использовать единый баланс. И также вы узнаете о том, как был организован проект, который позволил нам эту архитектуру реализовать.
Для начала покажем на примере, чем отличаются схемы «карта к счету» и «карта само по себе». Допустим, через банковскую систему РФ вам поступил безналичный перевод — компенсация от государства за рождение ребенка. В схеме «карта к счету» эта сумма становится доступна для расходных операций по карте в момент зачисления перевода на ваш счет в банке. В схеме «карта само по себе» необходимо перевести некоторую сумму денег с обычного счета на карточный, после чего средства можно тратить картой.
Такая, казалось бы, элементарная и логичная функциональность обеспечивается довольно сложным техническим решением, которое удачно реализовано далеко не в каждом банке. Например, до 2014 года в нашем банке балансы дебетовых карт жили отдельно от балансов счетов: карты в процессинге, счета около АБС. Балансы синхронизировались по утрам рабочих дней. Излишне говорить, что такая схема приводила к проблемам у клиентов: если человек досрочно расторгал депозит, то потратить/снять деньги по карте мог только завтра. А если сегодня суббота, то «завтра» превращалось в понедельник. В те времена добрая треть жалоб на banki.ru была так или иначе связана с этой темой. Внутри банка эта реализация также приводила к сложностям: при любой расходной операции по счету нужно было проверить, а не потратил ли клиент те же самые деньги по карте. В итоге большинство систем использовало программный эмулятор POS-терминала, через который проверялся баланс по карте и ставилась специальная блокировка в процессинге. Эта проверка не во всех случаях работала корректно, часто требовалось ручное вмешательство операциониста. Например, карта временно заблокирована, на ней 100 рублей, клиент снимает со счета 100, эмулятор POS-терминала на такую блокировку выдаёт ошибку, сумму не блокирует. Если эту проблему проигнорировать, то после совершения расходной операции по счету клиент разблокирует карту и снимет еще 100 рублей.
Это далеко не полный перечень проблем, с которыми банк сталкивался при использовании прежней архитектуры. В какой-то момент пришло осознание, что эта архитектура сдерживает развитие сервисов банка, и мы решили переделать техническую реализацию «карта к счету».
Ключевой вопрос, на который необходимо было ответить: в какой системе будет жить текущее значение доступного баланса? Обычно в банках есть два кандидата на эту роль — процессинговая система и АБС. Традиционно, в процессинге живут балансы карт в парадигме «карта сама по себе», а в АБС — балансы текущих счетов. Также традиционно, обе эти системы — покупные коробочные решения от крупных поставщиков с ограниченными возможностями кастомизации. Мы решили пойти по третьему пути — сделать отдельную систему для работы с доступным балансом. На это решение нас подвигло несколько факторов.
Во-первых, большинство «счетовых» банковских продуктов (касса, межбанковские платежи, страховки и так далее) у нас не живут внутри АБС. Это вполне себе самостоятельные системы, которые сгружают в АБС готовые бухгалтерские проводки.
Во-вторых, мы хотели сделать минимум доработок в процессинге и АБС силами поставщиков этих систем.
В-третьих, для контроля баланса по расходным операциям со счетом этими внешними системами не использовался механизм самой АБС.
Исторически операционный день в банке был устроен так, что текущее значение баланса по счету вычислялось специальной системой на основании остатка на начало операционного дня в АБС, уже подтвержденных в АБС транзакций/проводок, и промежуточных операционных данных в некоторых транзакционных системах (всего было три таких системы). А как же устроен контроль баланса по операциям, которые инициируются внутри АБС? Ведь не может же она для проверки баланса обращаться в третью систему?! Для кредитных продуктов (плановые списания по графику платежей, работа с просрочкой) АБС использует свой баланс на конец дня, так как по процессу все промежуточные движения из третьих транзакционных систем записываются в АБС до завершения операционного дня. Для транзакционных продуктов (размещение депозитов, отправка валютных платежей и так далее) контроль баланса происходит либо в ручном режиме (если операция вручную вводится в АБС), либо во внешней системе, которая после всех проверок через API формирует операцию в АБС.
Опытный глаз увидит в этой схеме сразу несколько недостатков. Это и реализация расчета текущего баланса вне АБС, и учет в расчете баланса данных третьих систем (которые хранятся на отдельной от АБС СУБД). Мы постарались свои недостатки обратить в преимущества. Тот факт, что текущее значение доступного баланса счета вычисляется вне АБС, имеет ряд преимуществ. Банк может по своему усмотрению (без доработок АБС) менять алгоритмы расчета баланса, мы можем как-то научиться считать баланс в процессе закрытия дня в АБС. Об этом моменте поговорим чуть подробнее. Наша АБС построена по концепции из прошлого века: в ней предусмотрен процесс закрытия дня, который длится несколько часов, и во время которого с АБС нельзя вообще ничего делать — ни транзакции вводить, ни данные смотреть. Но если баланс считается вне АБС, то эту проблему можно обойти!
![image](https://habrastorage.org/r/w780q1/web/585/ba3/50f/585ba350f9494418bf8f700595edc3fd.jpeg)
Итак, мы определились с целевой системой, которая будет является источником истины по доступному балансу — это будет ни АБС, ни процессинг, а некая новая система. Назовем её кодовыми буквами NI. Исходя их обозначенных выше особенностей работы систем банка, для корректной реализации системы NI нужно выполнить следующие действия:
Как это работало? Допустим, на счете клиента на начало дня в АБС баланс составил 100 рублей. Клиент снял через кассу 50 рублей в 10 часов утра. В кассовой системе есть подтвержденная кассиром операция, но проводки по ней в АБС еще не созданы (вспоминаем, что АБС из прошлого века, проводки она любит принимать крупными пачками, а не по одной штучке). Кассовая система по своему плану эту и прочие подтвержденные операции планирует выгрузить проводками в АБС в 12 часов дня единой пачкой. Как учесть в балансе по счету, что 50 рублей уже нет? В начале 2000-х годов в банке этому нашли «элегантное» решение — система расчета баланса откроет соединение с базой кассовой системы и в ней отберет все операции, подтвержденные кассиром, но еще не выгруженные в АБС. И так по трем разным системам.
Очевидно, что учет в доступном балансе счета операции «в моменте», которая позднее будет выгружена в АБС пачкой проводок — достаточно типовая задача. Вся онлайнизация банковских продуктов последних полутора десятилетий была направлена в эту сторону. Получается, что по мере появления новых подобных систем, нашу систему расчета баланса пришлось бы подключать к каждой из них. Это тупик в плане развития. Мы это осознали, когда систем было всего три, и даже с ними было трудно справиться.
Более правильным нам показалось решение, когда создается единое хранилище всех подтвержденных, но еще не выгруженных в АБС движений по счету. А все системы, которым нужно учитывать свои операции в доступном балансе в реальном времени, должны подключаться к этому хранилищу через набор API, которые должны позволят как рассчитывать текущее значение доступного баланса, так и менять его посредством создания движений по счету. Поскольку новую систему решили обозвать NI, то её API будем называть “NI API”. При этом наша старая система расчета доступного баланса должна научиться смотреть в это новое хранилище NI, а само хранилище, в целях быстродействия и надежности, решили разместить на той же системе, где живет АБС. В нашем случае это платформа IBM i.
Все движения по счету мы решили условно разбить на два типа: холды и проводки. Холды — это блокировки конкретных сумм на счетах клиентов, которые не факт, что будут реально списаны. Холды могут как иметь срок действия, так и быть бессрочными. Этот тип движений планировалось использовать для карточных авторизаций, арестов сумм по решению различных надзорных органов и так далее. Проводки — это движения по счету, которые фактически уже произошли, но пока не доехали до АБС.
Также в API по созданию движений по счету разумно добавить опции, при которых движение создается только в случае успешной проверки доступного баланса. Внешняя система как бы говорит: «Создай расходную операцию по счету клиента на 100 рублей, если текущее значение его баланса позволяет это сделать».
Представим, как в нашем примере кассовая система должна работать с NI API. Клиент снимает через кассу 50 рублей в 10 часов утра. Кассовая система обращается в NI API с просьбой: «Создай расходную операцию по счету клиента на 50 рублей, если текущее значение его баланса позволяет это сделать». NI рассчитывает баланс, он позволяет совершить операцию, NI создает движение на 50 рублей в своем промежуточном хранилище и отвечает кассовой системе: «Всё хорошо, выдавай». Если бы баланс по счету клиента был меньше 50 рублей, NI ответил бы: «Дело плохо, текущее значение баланса 40 рублей».
Наступает 12 часов, кассовой системе пора выгружать свою пачку совершенных операций проводками в АБС. По идее, в момент выгрузки операций она должна сообщить NI API, что эти движения уже доехали до АБС, и пора бы их убрать из промежуточного хранилища движений. И тут начинаются сложности. По логике процесса выгрузки пачки проводок в АБС, на всю пачку делается один коммит. Значит, надо также пачкой и с одним коммитом убирать эти движения из хранилища NI. Пачки проводок могут быть достаточно большими, промежуток времени между коммитами может быть довольно большим (десятки секунд максимум, но для нас и это много), в течение которого у клиента на счете будет некорректный баланс. Также возможны технические сбои, когда коммит пачки в АБС прошел успешно, а в NI API по какой-то причине — нет. Из-за этого мы рискуем получить неверные значения текущих балансов по счетам клиентов, а в банке такое неуместно.
К счастью, мы идентифицировали эти риски на этапе проектирования системы NI. Для их нивелирования решили «протянуть» функционал NI до АБС. В API по созданию проводок добавили обязательное поле с идентификатором пачки проводок, в которую внешняя система хочет объединить эти проводки. Также была добавлена отдельная функция «Запиши пачку проводок в АБС», по вызову которой NI сам записывал проводки в АБС, с единым коммитом в своем хранилище и в АБС. В этом сильно помогло то, что базы NI и АБС были размещены, по сути, в одной СУБД. Таким образом, кассовая система в 12 часов просто говорила NI API: «Выгрузи пачку проводок NI в АБС и сообщи мне о возникших проблемах».
Проблемы очень редко, но возникали. Например, когда между добавлением расходного движения по счету в NI и выгрузкой этого движения в АБС в банк пришел судебный пристав и арестовал счет. В подобных случаях кассовая система выдавала пользователю информацию о проблемной операции, и надо было обработать ситуацию вручную.
Был разработан NI API, который предоставлял внешним системам несколько логически сгруппированных API:
Технически, API представлял собой набор программ, написанных на языке программирования Free format ILE RPG с использованием SQL. Для использования API вне платформы IBM I, программы были обернуты в хранимые процедуры на базе DB2 for i, с которыми внешние системы могли работать по стандартным протоколам ODBC, JDBC и так далее. Также доступ к NI API был реализован с корпоративной интеграционной шины ESB, которая, в свою очередь, также обращалась к API по ODBC/JDBC.
Так как мы решили доработать прежнюю систему расчета доступного баланса, чтобы она умела работать с новым промежуточным хранилищем движений по счетам NI, то у нас не было нужды дорабатывать все ИТ-системы банка. Но нам необходимо было переделать упомянутые три системы (касса, рублевые платежи, конверсии юр. лиц), чтобы они начали использовать NI API для промежуточных движений, а при расчете баланса мы бы уже не обращались в транзакционные данные этих систем. На деле это оказалось достаточно сложной доработкой, так как в каждой системе пришлось переделать основную логику по обработке жизненного цикла операции. Для системы рублевых платежей пришлось переделать внутреннюю архитектуру системы, перейдя с двухзвенной на трехзвенную. Это потребовалось для того, чтобы централизовать логику по работе с NI API на сервере приложений.
Но основные сложности на данном этапе были связаны не только с техническими и архитектурными, но и с бизнес-аспектами. Перечисленные системы весьма востребованы заказчиками в плане доработок, в беклоге всегда имеется масса идей по развитию, оптимизации продуктов и процессов. Необходимость выполнить столь масштабные доработки без ощутимой, с точки зрения бизнеса, выгоды была воспринята заказчиками без энтузиазма. Напомним, суть изменений сводилась к тому, чтобы система расчета доступного баланса перестала ходить в базы этих систем, а они сами через API уведомляли централизованную систему NI о движениях по счетам. Для бизнеса это практически не имеет ценности.
Найти выход из сложившейся ситуации и склонить бизнес на свою сторону нам помогло удачное стечение обстоятельств. Как раз в то время в кассовой системе внедрялся модуль по внебалансовому учету пластиковых карт. Карт много, процессы их движения достаточно сложные, что означает большое количество проводок по внебалансовым счетам. В старом механизме формирования проводок из внешних систем в АБС есть существенный изъян: созданные в АБС пакеты проводок необходимо акцептовать вручную, используя пользовательский интерфейс самой АБС. Причем это может сделать пользователь с особенными правами, которые выдают только ограниченному кругу лиц. И в упомянутом проекте по внебалансу шли яростные дебаты между различными подразделениями о том, кто будет эти пакеты акцептовывать, кому какие права можно или нельзя давать. Мы предложили решение: в NI API сделать опцию, которая позволит формировать пакеты проводок в АБС уже в акцептованном виде. Разумеется, для этого весь модуль необходимо перевести на новый API. Эта идея всем очень понравилась, нам дали добро на переделку.
Внедрение механизма создания уже акцептованных пакетов проводок технически оказалось довольно сложной, но интересной задачей. Мы анализировали стек вызовов штатных программ АБС по акцепту проводок, отслеживали по журналам транзакций СУБД её манипуляции с данными. В итоге мы научились обманывать АБС и создавать проводки акцептованными. Кассовый модуль по внебалансу запустился на NI API, проводки потекли в АБС без акцепта оператором, а мы получили понимание, как стимулировать бизнес переходить на NI. Секрет оказался прост — надо предлагать бизнесу при миграции дополнительную функциональность, которая упростит их процессы или каким-то иным образом улучшит продукт. И тут-то нам карта и пошла…
В результате NI оброс функциональностью по созданию проводок по заблокированным счетам (актуально для списаний по решению суда и так далее, в старом процессе счета временно разблокировали вручную), замороченными вариантами расчетами баланса под приоритет, овердрафт и прочими хитростями. Это позволило бизнесу при миграции функциональности получить свои плюшки и существенно оптимизировать процессы. Итак, касса и рублевые платежи — done, остались валютообменные операции корпоративных клиентов.
А с этой системой у нас дело не ладилось. В ней проходило очень мало операций, потребностей в развитии функциональности не было, оптимизация не сулила существенных выгод. В итоге нам так и не удалось убедить партнеров в необходимости доработок, и мы махнули на нее рукой. До сих при расчете баланса по счетам корпоративных клиентов открывается соединение с ее СУБД. Но тогда нас это не расстроило, потому что мы добились своей главной цели — по счетам физических лиц все данные для расчета баланса были сконцентрированы в единой СУБД IBM i, расчет работал быстро (порядка 5 миллисекунд на счет) и надежно.
При ближайшем рассмотрении эта задача оказалось на удивление простой. Так как наша АБС в процессе закрытия дня не способна была принимать в себя никакие движения по счетам, то банк ночью просто замирал. Никакие операции по счетам не проводились. Поэтому наши изменения в NI не надо было синхронизировать ни с какими иными системами, кроме самой АБС. В итоге мы сделали небольшие доработки в АБС, вставив вызов особых управляющих программ NI в самом начале (день->ночь) и в самом конце (ночь->день) процесса закрытия операционного дня.
Программа «день->ночь» просто копировала нужные для расчета баланса таблицы АБС в отдельную библиотеку в той же СУБД. Использовалась примитивная конструкция INSERT SELECT. Всё копирование занимало порядка 20 минут. После завершения копирования NI понимал, что теперь необходимо ходить не в таблицу АБС, а в её копию.
Программа «ночь->день» отрабатывала мгновенно, просто переключая NI на работу с основной базой АБС.
Это решение позволило переходить между фазами дня без прерывания сервиса. Все движения по счетам, которые внешние системы хотели совершить во время закрытия дня АБС, накапливались в NI. Далее, после открытия дня АБС, внешним системам надо было дать команду на выгрузку проводок в АБС через NI API. Это не очень удобно для внешних систем, поэтому в дальнейшем был создан механизм STP (от straight through processing), при котором внешняя система только создает проводку в NI, а дальше он уже сам группирует их в пакеты и выгружает в АБС, когда та для этого доступна.
Реализация схемы день-ночь не лишена изящества. Мы задействовали штатный механизм IBM i по работе с контекстом — список библиотек. Были созданы две библиотеки — дневная и ночная. В них были созданы алиасы на дневные и ночные копии таблиц АБС соответственно. Для каждой таблицы и её ночной копии имя алиаса совпадало. Во всех SQL-выражениях для доступа к данным АБС использовались исключительно алиасы.
Перед обработкой каждого вызова NI API смотрит в специальный объект Data Area (очень быстрый на чтение-запись) системы IBM i чтобы понять, не изменился ли режим с прошлого вызова API в этом процессе. Как нетрудно догадаться, режим в Data Area меняет программы день->ночь и ночь->день. Если режим изменился, то программа просто заменяет библиотеку с алиасами в списке библиотек процесса, это крайне быстрая операция.
В результате, все системы-клиенты NI API смогли рассчитывать баланс и проводить операции 24 часа в сутки без перерывов, не особо заботясь об операционном дне в АБС. Для нас это была революция.
На этом мы не остановили развитие логики перехода ночь/день. Те 20 минут на копирование таблиц силами SQL не давали нам покоя. Была придумана и внедрена схема с репликацией с помощью решения высокой доступности MIMIX. Идея в том, что ночная копия создается не в момент начала закрытия дня АБС, а при открытии дня. В течение дня эта копия в режиме, близком к реальному времени, синхронизируется с данными АБС. А чтобы быть готовыми к любым ударам судьбы, мы делаем репликацию сразу на двух системах IBM i: основной и резервной.
![image](https://habrastorage.org/r/w1560/web/94c/e28/a8f/94ce28a8f8a14790b7a2cbb7c2711a38.png)
В данный момент мы переходим день->ночь и обратно практически мгновенно, сервис не прерывается ни на секунду.
Как известно, жизненный цикл операции по банковской карте состоит из двух основных этапов: авторизации и клиринга. При этом в некоторых случаях авторизации может и не быть.
С точки зрения доступного баланса, при авторизации необходимо проверить доступный остаток по счету клиента, заблокировать «холдом» сумму транзакции и ответить в платежную систему о своем решении: одобрено или нет. Желательно еще послать клиенту уведомление об операции, но это мы рассмотрим в главе об интернет-банкинге. При клиринге необходимо попытаться найти холд, который был поставлен ранее при авторизации, удалить его и создать проводку по счету клиента.
Наша процессинговая система на момент начала проекта умела при авторизации обращаться за проверкой доступного баланса во внешние системы. Эта функциональность была создана ранее, при объединении с Импэксбанком, так как Импэкс имел продукт «карта к счету». В процессе авторизации операции, после успешного завершения чисто карточных проверок (криптография, PIN-код и так далее) авторизационная система посылает ISO-8583-сообщение во внешнюю систему для финансовой авторизации и ждет ответа определенное количество секунд. От нас требовалось создать специальный модуль NI, который умел бы общаться с процессинговой системой по этому протоколу. Принять сообщение, разобрать на поля, вызвать NI API, сформировать ответ. Достаточно простая задача, но только на первый взгляд.
Первая сложность подстерегала нас с онлайновыми операциями пополнения счета клиента с помощью банковской карты. Это взносы в банкоматы и входящие переводы с карты на карту. По логике работы этих операций, авторизация и клиринг могут пройти в разные банковские дни. Допустим, клиенту с нулевым балансом на счете поступает перевод из стороннего банка 1 апреля в 10:00. В 10:05 клиент эти средства пускает на досрочное погашение кредита. Клиринг по этой операции придет 2 апреля. Если мы 1 апреля (при авторизаици) не сделаем бухгалтерскую проводку с пополнением счета, а просто поднимем баланс «положительным холдом», то после погашения кредита на счете в бухгалтерском учете возникнет отрицательный остаток, технический овердрафт, который закроется только после получения клиринга. В банковской бухгалтерии технических овердрафтов всячески избегают, и выход у нас один — по операциям пополнения делать проводки при авторизации.
Из первой сложности вытекает вторая — курсовые разницы. Когда перевод приходит из иностранного банка, суммы при авторизации и клиринге могут различаться из-за колебания курсов валют. Проиллюстрируем на реальном примере. Наш клиент 11 июня получил перевод на карту из белорусского банка, сумма перевода 15,00 белорусских рублей. Банк физически не может поддерживать курсы конвертации ко всем валютам мира по карточным операциям, мы ведем курсы по трем валютам — рубли, доллары, евро. Платежная система для авторизации пересчитывает сумму перевода по собственному курсу в валюту эмитента, в данном случае это были рубли РФ, сумма составила 455,50. Счет клиента открыт в рублях, поэтому мы ему провели приход на 455,50 рублей. С этого момента клиент может распоряжаться этими деньгами как угодно.
14 июня к нам пришел клиринг из платежной системы, и по этой операции нашему банку перечислили 7,16 Евро. С точки зрения учета выходит, что мы клиенту провели распределенную во времени конверсионную операцию: за 455,50 рублей купили 7,16 Евро. Неплохо бы понять, заработал банк на такой операции или потерял. По нашим курсам на 14 июня выходит, что 7,16 евро мы купили бы у клиента за 445,35 рублей. Значит, банку не повезло и он потерял 10,15 рублей. Бывает, что везет, и на колебаниях банк зарабатывает. Техническая реализация такой схемы расчетов очень сложна. Зачем морочиться, спросите вы, ведь такие операции с валютным риском можно просто не показывать клиенту в балансе до клиринга. К тому же таких операций сравнительно немного. Что греха таить, некоторые банки так и поступают. Но пойти на это нам не позволяет наш девиз — «разница в отношении». Мы считаем, что клиенту важно иметь возможность распоряжаться деньгами в момент совершения перевода, а бухгалтерские и технические заморочки не должны тому препятствовать.
Третью сложность мы придумали себе сами. Наша процессинговая система не умеет считать транзакционные комиссии в момент авторизации. Эти комиссии она считает в оффлайне, когда в банк приходит клиринг, спустя несколько дней. Соответственно, клиент не видит сумму комиссии в SMS при совершении операции, она внезапно возникает в выписке спустя несколько дней. Следуя тактике реализации дополнительной функциональности, мы взяли на борт расчет этих комиссий. Это повлекло за собой создание реплик тарифных таблиц из процессинговой системы, повторение логики расчета комиссии, специальные экраны для ответов на вопросы клиентов и так далее. Зато в результате наши клиенты сразу видят сумму комиссии и в авторизационной SMS, и в выписке.
С авторизацией разобрались, переходим к клирингу. В прежней схеме работы специальная система-посредник брала клиринговые операции по счетам клиентов из процессинговой системы, превращала их в бухгалтерские проводки и складывала в АБС. Причем на момент, когда наш проект дошел до процессинга, эта система-посредник уже работала с NI API (бонус NI в виде автоакцепта пакетов проводок стимулировал бизнес-владельцев систем на подобный переход). На момент клиринга наша основная задача — найти в NI авторизацию, убрать по ней холд и выполнить проводку. Но данных бухгалтерской проводки недостаточно для поиска авторизации. Мы видели два варианта реализации:
После долгих раздумий мы отбросили первый вариант, так как в нем предполагалось два вызова NI API — на поиск авторизации и добавление проводки. Возникает риск, что если первый вызов проходит успешно, то второй по какой-то причине ломается. Тогда у клиента снимется холд, а проводка не добавится, и будет завышен баланс со всеми вытекающими последствиями. Для карточного клиринга мы сделали программу-обертку над NI API по добавлению проводок. В этой обертке появились дополнительные поля, специфичные для карточных операций. На основании данных из этих полей NI производил поиск авторизации, понимал, какая была схема обработки в тот момент, исходя из чего либо создавал проводку, либо модифицировал её (например, для случая с входящими переводами). С точки зрения системы-посредника, доработки минимальны. В самом NI пришлось разработать мощную функциональность по поиску авторизаций и поддержке различных вариантов её проведения.
![image](https://habrastorage.org/r/w780q1/web/a64/7ec/a90/a647eca906754ab3a6cc6a80af3fc2d5.jpeg)
По теме интернет-банка интересны две вещи: посмотреть баланс карты/счета и выписку. До реализации проекта эти сущности для дебетовых карт и их счетов жили в инернет-банке раздельно. Невозможно было посмотреть текущее значение баланса счетов, отображался лишь баланс на начало дня из АБС. Выписка по счетам также бралась из АБС за прошедшие дни. Сегодня пришел платеж на ваш счет? Увидите в интернет-банке завтра!
По картам клиенты видели реальный баланс и реальные списки операций. Но какая техническая реализация за этим стояла! Интернет-банк постоянно, каждые две минуты обращался в базу процессинга, забирая из нее свежие авторизации по картам и изменения балансов карт. Всё это он складывал в своей базе. Так как балансы из АБС загружались в процессинг раз в день, это событие интернет-банк ловил в логах процессинга и начинал массовую перегрузку балансов всех карт и активных холдов. Эта процедура занимала продолжительное время; пока она шла, клиенты могли увидеть некорректную информацию.
![image](https://habrastorage.org/r/w780q1/web/66a/e24/44f/66ae2444f6b64d2b825f1ae76196bf90.jpeg)
С переходом на NI для интернет-банка всё упростилось. Он перестал ходить в базу процессинга, перестал загружать остатки и проводки по счетам из АБС. В момент отображения страницы пользователю интернет-банк через NI API запрашивает балансы и выписки по картам и счетам. Теперь клиенты всегда видят актуальную информацию. По сути, мы перешли от сильной связанности на уровне БД интернет-банка с АБС и системой процессинга к сервисно-ориентированной архитектуре.
Отдельно мы обещали рассказать про SMS-информирование по факту авторизации по карте. До реализации NI SMS генерировались в системах интернет-банкинга по факту получения свежих авторизаций из БД процессинга. В этом проекте мы попробовали реализовать событийно-управляемую архитектуру. Специально для NI был создан топик в системе управления очередями IBM WebSphere MQ. NI публикует в этот топик все события, связанные с изменением баланса: появился холд, появилась проводка, удалился холд и так далее. При этом атрибуты событий выведены в заголовки сообщений, что позволяет подписчикам гибко выбирать только те события, которые им нужны. Система SMS-информирования клиентов первой подключилась к этому топику, клиенты стали получать сообщения быстрее. Наши сотрудники, участвующие в пилоте, даже жаловались, что в новой схеме SMS приходит быстрее, чем банкомат успевает набрать пачку и выдать наличность.
Результаты эксперимента с событийно-управляемой архитектурой были признаны крайне удачными, внутри банка этот подход теперь применяется в широком спектре задач.
![image](https://habrastorage.org/r/w780q1/web/c4e/19f/d65/c4e19fd6535641c0b0f471ea6ecf6247.jpeg)
Реализовав столь масштабный проект, банк сумел устранить ряд архитектурных огрехов в процессах обработки транзакций и отображения информации для клиентов, что создало мощную базу для развития продуктов. Вслед за физическими лицами эта функциональность была востребована корпоративными клиентами. Были выпущены специальные карты «Business 24x7», в которых акцент делается на общем балансе счета/карта. Интернет-банк для юридических лиц также оброс онлайновыми сервисами.
Ну, а вы теперь знаете, что стоит за вашей картой Райффайзенбанка, и как мы относимся к надежности и клиентскому опыту. И что у нас переводы на карты зачисляются на счет мгновенно!
Немного сухой статистики:
Для начала покажем на примере, чем отличаются схемы «карта к счету» и «карта само по себе». Допустим, через банковскую систему РФ вам поступил безналичный перевод — компенсация от государства за рождение ребенка. В схеме «карта к счету» эта сумма становится доступна для расходных операций по карте в момент зачисления перевода на ваш счет в банке. В схеме «карта само по себе» необходимо перевести некоторую сумму денег с обычного счета на карточный, после чего средства можно тратить картой.
Такая, казалось бы, элементарная и логичная функциональность обеспечивается довольно сложным техническим решением, которое удачно реализовано далеко не в каждом банке. Например, до 2014 года в нашем банке балансы дебетовых карт жили отдельно от балансов счетов: карты в процессинге, счета около АБС. Балансы синхронизировались по утрам рабочих дней. Излишне говорить, что такая схема приводила к проблемам у клиентов: если человек досрочно расторгал депозит, то потратить/снять деньги по карте мог только завтра. А если сегодня суббота, то «завтра» превращалось в понедельник. В те времена добрая треть жалоб на banki.ru была так или иначе связана с этой темой. Внутри банка эта реализация также приводила к сложностям: при любой расходной операции по счету нужно было проверить, а не потратил ли клиент те же самые деньги по карте. В итоге большинство систем использовало программный эмулятор POS-терминала, через который проверялся баланс по карте и ставилась специальная блокировка в процессинге. Эта проверка не во всех случаях работала корректно, часто требовалось ручное вмешательство операциониста. Например, карта временно заблокирована, на ней 100 рублей, клиент снимает со счета 100, эмулятор POS-терминала на такую блокировку выдаёт ошибку, сумму не блокирует. Если эту проблему проигнорировать, то после совершения расходной операции по счету клиент разблокирует карту и снимет еще 100 рублей.
Это далеко не полный перечень проблем, с которыми банк сталкивался при использовании прежней архитектуры. В какой-то момент пришло осознание, что эта архитектура сдерживает развитие сервисов банка, и мы решили переделать техническую реализацию «карта к счету».
Ключевой вопрос, на который необходимо было ответить: в какой системе будет жить текущее значение доступного баланса? Обычно в банках есть два кандидата на эту роль — процессинговая система и АБС. Традиционно, в процессинге живут балансы карт в парадигме «карта сама по себе», а в АБС — балансы текущих счетов. Также традиционно, обе эти системы — покупные коробочные решения от крупных поставщиков с ограниченными возможностями кастомизации. Мы решили пойти по третьему пути — сделать отдельную систему для работы с доступным балансом. На это решение нас подвигло несколько факторов.
Во-первых, большинство «счетовых» банковских продуктов (касса, межбанковские платежи, страховки и так далее) у нас не живут внутри АБС. Это вполне себе самостоятельные системы, которые сгружают в АБС готовые бухгалтерские проводки.
Во-вторых, мы хотели сделать минимум доработок в процессинге и АБС силами поставщиков этих систем.
В-третьих, для контроля баланса по расходным операциям со счетом этими внешними системами не использовался механизм самой АБС.
Исторически операционный день в банке был устроен так, что текущее значение баланса по счету вычислялось специальной системой на основании остатка на начало операционного дня в АБС, уже подтвержденных в АБС транзакций/проводок, и промежуточных операционных данных в некоторых транзакционных системах (всего было три таких системы). А как же устроен контроль баланса по операциям, которые инициируются внутри АБС? Ведь не может же она для проверки баланса обращаться в третью систему?! Для кредитных продуктов (плановые списания по графику платежей, работа с просрочкой) АБС использует свой баланс на конец дня, так как по процессу все промежуточные движения из третьих транзакционных систем записываются в АБС до завершения операционного дня. Для транзакционных продуктов (размещение депозитов, отправка валютных платежей и так далее) контроль баланса происходит либо в ручном режиме (если операция вручную вводится в АБС), либо во внешней системе, которая после всех проверок через API формирует операцию в АБС.
Опытный глаз увидит в этой схеме сразу несколько недостатков. Это и реализация расчета текущего баланса вне АБС, и учет в расчете баланса данных третьих систем (которые хранятся на отдельной от АБС СУБД). Мы постарались свои недостатки обратить в преимущества. Тот факт, что текущее значение доступного баланса счета вычисляется вне АБС, имеет ряд преимуществ. Банк может по своему усмотрению (без доработок АБС) менять алгоритмы расчета баланса, мы можем как-то научиться считать баланс в процессе закрытия дня в АБС. Об этом моменте поговорим чуть подробнее. Наша АБС построена по концепции из прошлого века: в ней предусмотрен процесс закрытия дня, который длится несколько часов, и во время которого с АБС нельзя вообще ничего делать — ни транзакции вводить, ни данные смотреть. Но если баланс считается вне АБС, то эту проблему можно обойти!
![image](https://habrastorage.org/web/585/ba3/50f/585ba350f9494418bf8f700595edc3fd.jpeg)
Итак, мы определились с целевой системой, которая будет является источником истины по доступному балансу — это будет ни АБС, ни процессинг, а некая новая система. Назовем её кодовыми буквами NI. Исходя их обозначенных выше особенностей работы систем банка, для корректной реализации системы NI нужно выполнить следующие действия:
- Отказаться при расчете баланса от анализа данных транзакционных систем (мы упоминали о трех таких системах — это касса, рублевые платежи, конверсии юридических лиц). Это нужно для надежной и быстрой работы авторизаций по картам, чтобы не ходить на сторонние СУБД.
- Переключить на NI все системы, использующие текущую специализированную систему для расчета баланса. Или подключить старую систему к NI, что проще; это мы в итоге и выбрали.
- Научить NI как-то работать в процессе закрытия операционного дня АБС.
- Интегрировать NI с карточным процессингом.
- Посмотреть, как все эти изменения отразятся на интернет-банкинге.
Отказ от данных третьих систем при расчете баланса по счету
Как это работало? Допустим, на счете клиента на начало дня в АБС баланс составил 100 рублей. Клиент снял через кассу 50 рублей в 10 часов утра. В кассовой системе есть подтвержденная кассиром операция, но проводки по ней в АБС еще не созданы (вспоминаем, что АБС из прошлого века, проводки она любит принимать крупными пачками, а не по одной штучке). Кассовая система по своему плану эту и прочие подтвержденные операции планирует выгрузить проводками в АБС в 12 часов дня единой пачкой. Как учесть в балансе по счету, что 50 рублей уже нет? В начале 2000-х годов в банке этому нашли «элегантное» решение — система расчета баланса откроет соединение с базой кассовой системы и в ней отберет все операции, подтвержденные кассиром, но еще не выгруженные в АБС. И так по трем разным системам.
Очевидно, что учет в доступном балансе счета операции «в моменте», которая позднее будет выгружена в АБС пачкой проводок — достаточно типовая задача. Вся онлайнизация банковских продуктов последних полутора десятилетий была направлена в эту сторону. Получается, что по мере появления новых подобных систем, нашу систему расчета баланса пришлось бы подключать к каждой из них. Это тупик в плане развития. Мы это осознали, когда систем было всего три, и даже с ними было трудно справиться.
Более правильным нам показалось решение, когда создается единое хранилище всех подтвержденных, но еще не выгруженных в АБС движений по счету. А все системы, которым нужно учитывать свои операции в доступном балансе в реальном времени, должны подключаться к этому хранилищу через набор API, которые должны позволят как рассчитывать текущее значение доступного баланса, так и менять его посредством создания движений по счету. Поскольку новую систему решили обозвать NI, то её API будем называть “NI API”. При этом наша старая система расчета доступного баланса должна научиться смотреть в это новое хранилище NI, а само хранилище, в целях быстродействия и надежности, решили разместить на той же системе, где живет АБС. В нашем случае это платформа IBM i.
Все движения по счету мы решили условно разбить на два типа: холды и проводки. Холды — это блокировки конкретных сумм на счетах клиентов, которые не факт, что будут реально списаны. Холды могут как иметь срок действия, так и быть бессрочными. Этот тип движений планировалось использовать для карточных авторизаций, арестов сумм по решению различных надзорных органов и так далее. Проводки — это движения по счету, которые фактически уже произошли, но пока не доехали до АБС.
Также в API по созданию движений по счету разумно добавить опции, при которых движение создается только в случае успешной проверки доступного баланса. Внешняя система как бы говорит: «Создай расходную операцию по счету клиента на 100 рублей, если текущее значение его баланса позволяет это сделать».
Представим, как в нашем примере кассовая система должна работать с NI API. Клиент снимает через кассу 50 рублей в 10 часов утра. Кассовая система обращается в NI API с просьбой: «Создай расходную операцию по счету клиента на 50 рублей, если текущее значение его баланса позволяет это сделать». NI рассчитывает баланс, он позволяет совершить операцию, NI создает движение на 50 рублей в своем промежуточном хранилище и отвечает кассовой системе: «Всё хорошо, выдавай». Если бы баланс по счету клиента был меньше 50 рублей, NI ответил бы: «Дело плохо, текущее значение баланса 40 рублей».
Наступает 12 часов, кассовой системе пора выгружать свою пачку совершенных операций проводками в АБС. По идее, в момент выгрузки операций она должна сообщить NI API, что эти движения уже доехали до АБС, и пора бы их убрать из промежуточного хранилища движений. И тут начинаются сложности. По логике процесса выгрузки пачки проводок в АБС, на всю пачку делается один коммит. Значит, надо также пачкой и с одним коммитом убирать эти движения из хранилища NI. Пачки проводок могут быть достаточно большими, промежуток времени между коммитами может быть довольно большим (десятки секунд максимум, но для нас и это много), в течение которого у клиента на счете будет некорректный баланс. Также возможны технические сбои, когда коммит пачки в АБС прошел успешно, а в NI API по какой-то причине — нет. Из-за этого мы рискуем получить неверные значения текущих балансов по счетам клиентов, а в банке такое неуместно.
К счастью, мы идентифицировали эти риски на этапе проектирования системы NI. Для их нивелирования решили «протянуть» функционал NI до АБС. В API по созданию проводок добавили обязательное поле с идентификатором пачки проводок, в которую внешняя система хочет объединить эти проводки. Также была добавлена отдельная функция «Запиши пачку проводок в АБС», по вызову которой NI сам записывал проводки в АБС, с единым коммитом в своем хранилище и в АБС. В этом сильно помогло то, что базы NI и АБС были размещены, по сути, в одной СУБД. Таким образом, кассовая система в 12 часов просто говорила NI API: «Выгрузи пачку проводок NI в АБС и сообщи мне о возникших проблемах».
Проблемы очень редко, но возникали. Например, когда между добавлением расходного движения по счету в NI и выгрузкой этого движения в АБС в банк пришел судебный пристав и арестовал счет. В подобных случаях кассовая система выдавала пользователю информацию о проблемной операции, и надо было обработать ситуацию вручную.
Был разработан NI API, который предоставлял внешним системам несколько логически сгруппированных API:
- Получение информации по счету (баланс, статусы и так далее).
- Работа с пачками (создание, удаление, выгрузка в АБС).
- Работа с отдельными проводками в пачках.
- Работа с холдами.
Технически, API представлял собой набор программ, написанных на языке программирования Free format ILE RPG с использованием SQL. Для использования API вне платформы IBM I, программы были обернуты в хранимые процедуры на базе DB2 for i, с которыми внешние системы могли работать по стандартным протоколам ODBC, JDBC и так далее. Также доступ к NI API был реализован с корпоративной интеграционной шины ESB, которая, в свою очередь, также обращалась к API по ODBC/JDBC.
Переключить некоторые системы на NI
Так как мы решили доработать прежнюю систему расчета доступного баланса, чтобы она умела работать с новым промежуточным хранилищем движений по счетам NI, то у нас не было нужды дорабатывать все ИТ-системы банка. Но нам необходимо было переделать упомянутые три системы (касса, рублевые платежи, конверсии юр. лиц), чтобы они начали использовать NI API для промежуточных движений, а при расчете баланса мы бы уже не обращались в транзакционные данные этих систем. На деле это оказалось достаточно сложной доработкой, так как в каждой системе пришлось переделать основную логику по обработке жизненного цикла операции. Для системы рублевых платежей пришлось переделать внутреннюю архитектуру системы, перейдя с двухзвенной на трехзвенную. Это потребовалось для того, чтобы централизовать логику по работе с NI API на сервере приложений.
Но основные сложности на данном этапе были связаны не только с техническими и архитектурными, но и с бизнес-аспектами. Перечисленные системы весьма востребованы заказчиками в плане доработок, в беклоге всегда имеется масса идей по развитию, оптимизации продуктов и процессов. Необходимость выполнить столь масштабные доработки без ощутимой, с точки зрения бизнеса, выгоды была воспринята заказчиками без энтузиазма. Напомним, суть изменений сводилась к тому, чтобы система расчета доступного баланса перестала ходить в базы этих систем, а они сами через API уведомляли централизованную систему NI о движениях по счетам. Для бизнеса это практически не имеет ценности.
Найти выход из сложившейся ситуации и склонить бизнес на свою сторону нам помогло удачное стечение обстоятельств. Как раз в то время в кассовой системе внедрялся модуль по внебалансовому учету пластиковых карт. Карт много, процессы их движения достаточно сложные, что означает большое количество проводок по внебалансовым счетам. В старом механизме формирования проводок из внешних систем в АБС есть существенный изъян: созданные в АБС пакеты проводок необходимо акцептовать вручную, используя пользовательский интерфейс самой АБС. Причем это может сделать пользователь с особенными правами, которые выдают только ограниченному кругу лиц. И в упомянутом проекте по внебалансу шли яростные дебаты между различными подразделениями о том, кто будет эти пакеты акцептовывать, кому какие права можно или нельзя давать. Мы предложили решение: в NI API сделать опцию, которая позволит формировать пакеты проводок в АБС уже в акцептованном виде. Разумеется, для этого весь модуль необходимо перевести на новый API. Эта идея всем очень понравилась, нам дали добро на переделку.
Внедрение механизма создания уже акцептованных пакетов проводок технически оказалось довольно сложной, но интересной задачей. Мы анализировали стек вызовов штатных программ АБС по акцепту проводок, отслеживали по журналам транзакций СУБД её манипуляции с данными. В итоге мы научились обманывать АБС и создавать проводки акцептованными. Кассовый модуль по внебалансу запустился на NI API, проводки потекли в АБС без акцепта оператором, а мы получили понимание, как стимулировать бизнес переходить на NI. Секрет оказался прост — надо предлагать бизнесу при миграции дополнительную функциональность, которая упростит их процессы или каким-то иным образом улучшит продукт. И тут-то нам карта и пошла…
В результате NI оброс функциональностью по созданию проводок по заблокированным счетам (актуально для списаний по решению суда и так далее, в старом процессе счета временно разблокировали вручную), замороченными вариантами расчетами баланса под приоритет, овердрафт и прочими хитростями. Это позволило бизнесу при миграции функциональности получить свои плюшки и существенно оптимизировать процессы. Итак, касса и рублевые платежи — done, остались валютообменные операции корпоративных клиентов.
А с этой системой у нас дело не ладилось. В ней проходило очень мало операций, потребностей в развитии функциональности не было, оптимизация не сулила существенных выгод. В итоге нам так и не удалось убедить партнеров в необходимости доработок, и мы махнули на нее рукой. До сих при расчете баланса по счетам корпоративных клиентов открывается соединение с ее СУБД. Но тогда нас это не расстроило, потому что мы добились своей главной цели — по счетам физических лиц все данные для расчета баланса были сконцентрированы в единой СУБД IBM i, расчет работал быстро (порядка 5 миллисекунд на счет) и надежно.
Научить NI работать в процессе закрытия операционного дня
При ближайшем рассмотрении эта задача оказалось на удивление простой. Так как наша АБС в процессе закрытия дня не способна была принимать в себя никакие движения по счетам, то банк ночью просто замирал. Никакие операции по счетам не проводились. Поэтому наши изменения в NI не надо было синхронизировать ни с какими иными системами, кроме самой АБС. В итоге мы сделали небольшие доработки в АБС, вставив вызов особых управляющих программ NI в самом начале (день->ночь) и в самом конце (ночь->день) процесса закрытия операционного дня.
Программа «день->ночь» просто копировала нужные для расчета баланса таблицы АБС в отдельную библиотеку в той же СУБД. Использовалась примитивная конструкция INSERT SELECT. Всё копирование занимало порядка 20 минут. После завершения копирования NI понимал, что теперь необходимо ходить не в таблицу АБС, а в её копию.
Программа «ночь->день» отрабатывала мгновенно, просто переключая NI на работу с основной базой АБС.
Это решение позволило переходить между фазами дня без прерывания сервиса. Все движения по счетам, которые внешние системы хотели совершить во время закрытия дня АБС, накапливались в NI. Далее, после открытия дня АБС, внешним системам надо было дать команду на выгрузку проводок в АБС через NI API. Это не очень удобно для внешних систем, поэтому в дальнейшем был создан механизм STP (от straight through processing), при котором внешняя система только создает проводку в NI, а дальше он уже сам группирует их в пакеты и выгружает в АБС, когда та для этого доступна.
Реализация схемы день-ночь не лишена изящества. Мы задействовали штатный механизм IBM i по работе с контекстом — список библиотек. Были созданы две библиотеки — дневная и ночная. В них были созданы алиасы на дневные и ночные копии таблиц АБС соответственно. Для каждой таблицы и её ночной копии имя алиаса совпадало. Во всех SQL-выражениях для доступа к данным АБС использовались исключительно алиасы.
Перед обработкой каждого вызова NI API смотрит в специальный объект Data Area (очень быстрый на чтение-запись) системы IBM i чтобы понять, не изменился ли режим с прошлого вызова API в этом процессе. Как нетрудно догадаться, режим в Data Area меняет программы день->ночь и ночь->день. Если режим изменился, то программа просто заменяет библиотеку с алиасами в списке библиотек процесса, это крайне быстрая операция.
В результате, все системы-клиенты NI API смогли рассчитывать баланс и проводить операции 24 часа в сутки без перерывов, не особо заботясь об операционном дне в АБС. Для нас это была революция.
На этом мы не остановили развитие логики перехода ночь/день. Те 20 минут на копирование таблиц силами SQL не давали нам покоя. Была придумана и внедрена схема с репликацией с помощью решения высокой доступности MIMIX. Идея в том, что ночная копия создается не в момент начала закрытия дня АБС, а при открытии дня. В течение дня эта копия в режиме, близком к реальному времени, синхронизируется с данными АБС. А чтобы быть готовыми к любым ударам судьбы, мы делаем репликацию сразу на двух системах IBM i: основной и резервной.
![image](https://habrastorage.org/web/94c/e28/a8f/94ce28a8f8a14790b7a2cbb7c2711a38.png)
В данный момент мы переходим день->ночь и обратно практически мгновенно, сервис не прерывается ни на секунду.
Интеграция с процессингом банковских карт
Как известно, жизненный цикл операции по банковской карте состоит из двух основных этапов: авторизации и клиринга. При этом в некоторых случаях авторизации может и не быть.
С точки зрения доступного баланса, при авторизации необходимо проверить доступный остаток по счету клиента, заблокировать «холдом» сумму транзакции и ответить в платежную систему о своем решении: одобрено или нет. Желательно еще послать клиенту уведомление об операции, но это мы рассмотрим в главе об интернет-банкинге. При клиринге необходимо попытаться найти холд, который был поставлен ранее при авторизации, удалить его и создать проводку по счету клиента.
Наша процессинговая система на момент начала проекта умела при авторизации обращаться за проверкой доступного баланса во внешние системы. Эта функциональность была создана ранее, при объединении с Импэксбанком, так как Импэкс имел продукт «карта к счету». В процессе авторизации операции, после успешного завершения чисто карточных проверок (криптография, PIN-код и так далее) авторизационная система посылает ISO-8583-сообщение во внешнюю систему для финансовой авторизации и ждет ответа определенное количество секунд. От нас требовалось создать специальный модуль NI, который умел бы общаться с процессинговой системой по этому протоколу. Принять сообщение, разобрать на поля, вызвать NI API, сформировать ответ. Достаточно простая задача, но только на первый взгляд.
Первая сложность подстерегала нас с онлайновыми операциями пополнения счета клиента с помощью банковской карты. Это взносы в банкоматы и входящие переводы с карты на карту. По логике работы этих операций, авторизация и клиринг могут пройти в разные банковские дни. Допустим, клиенту с нулевым балансом на счете поступает перевод из стороннего банка 1 апреля в 10:00. В 10:05 клиент эти средства пускает на досрочное погашение кредита. Клиринг по этой операции придет 2 апреля. Если мы 1 апреля (при авторизаици) не сделаем бухгалтерскую проводку с пополнением счета, а просто поднимем баланс «положительным холдом», то после погашения кредита на счете в бухгалтерском учете возникнет отрицательный остаток, технический овердрафт, который закроется только после получения клиринга. В банковской бухгалтерии технических овердрафтов всячески избегают, и выход у нас один — по операциям пополнения делать проводки при авторизации.
Из первой сложности вытекает вторая — курсовые разницы. Когда перевод приходит из иностранного банка, суммы при авторизации и клиринге могут различаться из-за колебания курсов валют. Проиллюстрируем на реальном примере. Наш клиент 11 июня получил перевод на карту из белорусского банка, сумма перевода 15,00 белорусских рублей. Банк физически не может поддерживать курсы конвертации ко всем валютам мира по карточным операциям, мы ведем курсы по трем валютам — рубли, доллары, евро. Платежная система для авторизации пересчитывает сумму перевода по собственному курсу в валюту эмитента, в данном случае это были рубли РФ, сумма составила 455,50. Счет клиента открыт в рублях, поэтому мы ему провели приход на 455,50 рублей. С этого момента клиент может распоряжаться этими деньгами как угодно.
14 июня к нам пришел клиринг из платежной системы, и по этой операции нашему банку перечислили 7,16 Евро. С точки зрения учета выходит, что мы клиенту провели распределенную во времени конверсионную операцию: за 455,50 рублей купили 7,16 Евро. Неплохо бы понять, заработал банк на такой операции или потерял. По нашим курсам на 14 июня выходит, что 7,16 евро мы купили бы у клиента за 445,35 рублей. Значит, банку не повезло и он потерял 10,15 рублей. Бывает, что везет, и на колебаниях банк зарабатывает. Техническая реализация такой схемы расчетов очень сложна. Зачем морочиться, спросите вы, ведь такие операции с валютным риском можно просто не показывать клиенту в балансе до клиринга. К тому же таких операций сравнительно немного. Что греха таить, некоторые банки так и поступают. Но пойти на это нам не позволяет наш девиз — «разница в отношении». Мы считаем, что клиенту важно иметь возможность распоряжаться деньгами в момент совершения перевода, а бухгалтерские и технические заморочки не должны тому препятствовать.
Третью сложность мы придумали себе сами. Наша процессинговая система не умеет считать транзакционные комиссии в момент авторизации. Эти комиссии она считает в оффлайне, когда в банк приходит клиринг, спустя несколько дней. Соответственно, клиент не видит сумму комиссии в SMS при совершении операции, она внезапно возникает в выписке спустя несколько дней. Следуя тактике реализации дополнительной функциональности, мы взяли на борт расчет этих комиссий. Это повлекло за собой создание реплик тарифных таблиц из процессинговой системы, повторение логики расчета комиссии, специальные экраны для ответов на вопросы клиентов и так далее. Зато в результате наши клиенты сразу видят сумму комиссии и в авторизационной SMS, и в выписке.
С авторизацией разобрались, переходим к клирингу. В прежней схеме работы специальная система-посредник брала клиринговые операции по счетам клиентов из процессинговой системы, превращала их в бухгалтерские проводки и складывала в АБС. Причем на момент, когда наш проект дошел до процессинга, эта система-посредник уже работала с NI API (бонус NI в виде автоакцепта пакетов проводок стимулировал бизнес-владельцев систем на подобный переход). На момент клиринга наша основная задача — найти в NI авторизацию, убрать по ней холд и выполнить проводку. Но данных бухгалтерской проводки недостаточно для поиска авторизации. Мы видели два варианта реализации:
- Создать отдельный API для поиска авторизации и снятия холда.
- Встроить в «проводочный» API данные карточной транзакции, чтобы за один вызов и проводку добавить, и холд снять.
После долгих раздумий мы отбросили первый вариант, так как в нем предполагалось два вызова NI API — на поиск авторизации и добавление проводки. Возникает риск, что если первый вызов проходит успешно, то второй по какой-то причине ломается. Тогда у клиента снимется холд, а проводка не добавится, и будет завышен баланс со всеми вытекающими последствиями. Для карточного клиринга мы сделали программу-обертку над NI API по добавлению проводок. В этой обертке появились дополнительные поля, специфичные для карточных операций. На основании данных из этих полей NI производил поиск авторизации, понимал, какая была схема обработки в тот момент, исходя из чего либо создавал проводку, либо модифицировал её (например, для случая с входящими переводами). С точки зрения системы-посредника, доработки минимальны. В самом NI пришлось разработать мощную функциональность по поиску авторизаций и поддержке различных вариантов её проведения.
![image](https://habrastorage.org/web/a64/7ec/a90/a647eca906754ab3a6cc6a80af3fc2d5.jpeg)
Изменения в интернет-банкинге
По теме интернет-банка интересны две вещи: посмотреть баланс карты/счета и выписку. До реализации проекта эти сущности для дебетовых карт и их счетов жили в инернет-банке раздельно. Невозможно было посмотреть текущее значение баланса счетов, отображался лишь баланс на начало дня из АБС. Выписка по счетам также бралась из АБС за прошедшие дни. Сегодня пришел платеж на ваш счет? Увидите в интернет-банке завтра!
По картам клиенты видели реальный баланс и реальные списки операций. Но какая техническая реализация за этим стояла! Интернет-банк постоянно, каждые две минуты обращался в базу процессинга, забирая из нее свежие авторизации по картам и изменения балансов карт. Всё это он складывал в своей базе. Так как балансы из АБС загружались в процессинг раз в день, это событие интернет-банк ловил в логах процессинга и начинал массовую перегрузку балансов всех карт и активных холдов. Эта процедура занимала продолжительное время; пока она шла, клиенты могли увидеть некорректную информацию.
![image](https://habrastorage.org/web/66a/e24/44f/66ae2444f6b64d2b825f1ae76196bf90.jpeg)
С переходом на NI для интернет-банка всё упростилось. Он перестал ходить в базу процессинга, перестал загружать остатки и проводки по счетам из АБС. В момент отображения страницы пользователю интернет-банк через NI API запрашивает балансы и выписки по картам и счетам. Теперь клиенты всегда видят актуальную информацию. По сути, мы перешли от сильной связанности на уровне БД интернет-банка с АБС и системой процессинга к сервисно-ориентированной архитектуре.
Отдельно мы обещали рассказать про SMS-информирование по факту авторизации по карте. До реализации NI SMS генерировались в системах интернет-банкинга по факту получения свежих авторизаций из БД процессинга. В этом проекте мы попробовали реализовать событийно-управляемую архитектуру. Специально для NI был создан топик в системе управления очередями IBM WebSphere MQ. NI публикует в этот топик все события, связанные с изменением баланса: появился холд, появилась проводка, удалился холд и так далее. При этом атрибуты событий выведены в заголовки сообщений, что позволяет подписчикам гибко выбирать только те события, которые им нужны. Система SMS-информирования клиентов первой подключилась к этому топику, клиенты стали получать сообщения быстрее. Наши сотрудники, участвующие в пилоте, даже жаловались, что в новой схеме SMS приходит быстрее, чем банкомат успевает набрать пачку и выдать наличность.
Результаты эксперимента с событийно-управляемой архитектурой были признаны крайне удачными, внутри банка этот подход теперь применяется в широком спектре задач.
![image](https://habrastorage.org/web/c4e/19f/d65/c4e19fd6535641c0b0f471ea6ecf6247.jpeg)
Заключение
Реализовав столь масштабный проект, банк сумел устранить ряд архитектурных огрехов в процессах обработки транзакций и отображения информации для клиентов, что создало мощную базу для развития продуктов. Вслед за физическими лицами эта функциональность была востребована корпоративными клиентами. Были выпущены специальные карты «Business 24x7», в которых акцент делается на общем балансе счета/карта. Интернет-банк для юридических лиц также оброс онлайновыми сервисами.
Ну, а вы теперь знаете, что стоит за вашей картой Райффайзенбанка, и как мы относимся к надежности и клиентскому опыту. И что у нас переводы на карты зачисляются на счет мгновенно!
Немного сухой статистики:
- Порядка 70% проводок в банке формируется через NI.
- API по запросу баланса вызывается в среднем 5 млн раз в сутки, в пиковые дни доходит до 8. Примерно половина всех запросов приходится на ДБО (отображение информации клиентам).