Случайны выбор дневника Раскрыть/свернуть полный список возможностей


Найдено 1707 сообщений
Cообщения с меткой

платежные системы - Самое интересное в блогах

Следующие 30  »
rss_rss_hh_new

Разбираемся с Replace-By-Fee транзакциями Bitcoin

Понедельник, 24 Апреля 2017 г. 10:55 (ссылка)

Всем привет! В этой статье мы разберемся что такое Replace-By-Fee транзакции и как их использовать. Бонус! Пара поучительных историй в конце.







Итак, представим ситуацию когда A посылает монеты B. Он создает и подписывает транзакцию, и выпускает ее в сеть для подтверждения. К сожалению, транзакция долго не подтверждается, у транзакции слишком маленькая комиссия (или комиссия нормальная в обычных обстоятельствах, но в данный момент очередь неподтвержденных транзакций слишком большая и майнеры предпочитают майнить транзакции с бОльшими комиссиями). Что делать пользователю A? Варианты: a) ждать подтверждения (ждать можно долго) б) ждать отмены транзакции (когда большинство нод решат наконец выкинуть из mempool транзакцию) и освобожденными монетами можно будет снова распоряжаться (то есть создавать транзакции и пулы не будут считать их даблспендами и отвергать) в) Заменить транзакцию с повышением комиссии (RBF)



Итак, RBF — замена существующей транзакции новой транзакцией с повышением комиссии. Замена означает что в новой транзакции будут использованы те же входы что и в старой транзакции, и это не будет считаться даблспендом (читай, мошенничеством). В итоге только одна транзакция будет добавлена в блокчейн (с большой вероятностью это будет транзакция с повышенной комиссией).



RBF описан в BIP-0125 github.com/bitcoin/bips/blob/master/bip-0125.mediawiki



Какая транзакция может быть заменена? Это хороший вопрос. Замена транзакций была предусмотрена еще создателем системы Сатоши Накамото, но выключена в определенный момент. Затем она была доработана до RBF и включена в код Bitcoin Core 0.12 и старше. Для замены в данных транзакции предусмотрено специальное int поле nSequence, которое сигнализирует о том, какая транзакция старше какой. Чтоб транзакция была потенциально заменяемой, значение nSequence должно быть меньше (0xffffffff — 1).

По умолчанию, большинство современных кошельков nSequence сразу ставят максимальным, и возможность заменять транзакции надо включать в настройках. Вот так это выглядит в кошельке Electrum:



image



Пример декодированой транзакции:



...
"inputs": [
{
"addresses": [
"...."
],
"output_index": 0,
"output_value": 1010000,
"prev_hash": "...",
"script": "...",
"script_type": "pay-to-pubkey-hash",
"sequence": 0
},
...




Sequence указывается для каждого входа транзакции.



В том же кошельке Electrum после включения опции RBF станет возможным увеличивать комиссию за транзакцию прямо в GUI, но сейчас мы с вами будем собирать RBF транзакцию руками. Зачем? Во-первых — разобраться, во-вторых — для большей гибкости, например, в этом случае в RBF транзакции мы сможем указать совершенно другие целевые адреса для перевода, чем периодически пытаются воспользоваться злоумышленники.

Выглядит это так: A хочет заплатить B. A создает, подписывает и транслирует транзакцию на перевод монет B, но умышленно ставит пониженную или нулевую комиссию. Если B недостаточно осторожен он засчитывает неподтвержденную транзакцию (и отдает товар А, например). После этого A заменяет транзакцию и перенаправляет выход транзакции на С, где С подконтролен А.



Как B может этого избежать? Если все же B предпочитает засчитывать неподтвержденные транзакции (для скорости), не стоит засчитывать пластичные транзакции (где nSequence позволяет транзакции заменять). И вообще, с подозрением относиться к таким транзакциям. Если вы когда-то засчитывали пластичные транзакции то неплохо бы их перепроверить на факт наличия фрода и применить санкции к плательщику, если тот мошенничает. Ну и естественно, идеально было бы дожидаться не менее 2х подтверждений.



Пример.



Будем пользоваться замечательной опенсорсной тулзой github.com/OutCast3k/coinbin с помощью которой можно вручную легко создавать транзакции с нужными нам входами и выходами. Работает полностью в браузере не общаясь с сервером. Живая версия доступна по адресу coinb.in



Создаем транзакцию через New->Transaction. Берем приватный ключ в формате WIF и загружаем доступные (непотраченные) выходы для этого ключа. Во вкладке Outputs указываем целевой адрес, указываем amount. В Advanced Options не забываем поставить галку на “Make this a RBF transaction” — в этом случае nSequence транзакции будет меньше максимального значения. Жмем Submit.



image



Транзакция создана. Обратите внимание на Transaction Fee — это разница между доступным количеством монет суммарно со всех входов МИНУС сумма всех выходов (в нашем случае 1 выход). Разница и будет комиссией которую майнер заберет себе. В этом примере она специально нулевая.



Жмем Sign, копипастим туда полученный hex транзакции, все тот же приватный ключ, и подписываем транзакцию:



image



Транслируем транзакцию в сеть (можно использовать любой ендпоинт):



image



Так транзакция выглядит:



image



Теперь давайте воспользуемся RBF. Создаем новую транзакцию, входы берем с того же WIF. Но выходы укажем совершенно иные! Один из выходов укажем 1CWHWkTWaq1K5hevimJia3cyinQsrgXUvg — донейт адрес создателя coinb.in

Amount укажем такие чтоб комиссия за транзакцию была достаточной для быстрого подтверждения.



image



Обратите внимание на вкладку Inputs — если исходный адрес многоразовый и на нем много транзакций, то нам придется во входах вручную прописать только те инпуты, которые входят в транзакцию которую мы хотим заменить (удалить лишние, оставить только нужные). Входов этих могут быть сотни, и в некоторых случаях это может быть достаточно кропотливая работа.



Подписываем:



image



Транслируем:



image



Вот так это теперь выглядит на bitcoin.info. У новой транзакции есть все шансы быть включенной в блок раньше своей предыдущей версии.



image



Ждем. Есть подтверждение:



image



Мы только что заменили транзакцию с помощью RBF, причем монеты отправили совсем не на тот адрес который хотели изначально.



Опять о безопасности.

Не всегда nSequence=MAX гарантирует что транзакция финальная и заменить ее нельзя. На самом деле галку “Make this a RBF transaction” можно было не ставить, но:


  • При замене транзакции не все ноды согласятся ретранслировать новую версию, ссылаясь на mempool-conflict

  • Некоторые ноды примут транзакцию, и таки ретранслируют ее в сеть

  • Информационные ресурсы типа blockchain.info будут прямым текстом писать DOUBLE SPEND

  • Не все пулы будут майнить эту транзакцию, справедливо считая её даблспендом. Некоторые пулы будут ее майнить, но это может занять больше времени (по сравнению со временем если вся сеть будет её майнить)

  • Если новая транзакция будет таки включена в блок — это абсолютно валидно и не противоречит правилам сети. Любые претензии потенциально обманутых нигде не принимаются





Т.о. мы приходим к мысли что любые транзакции без подтверждения хотя бы в 2х блоках являются ненадежными. Почему в 2х а не 1м? Короткий ответ — orphaned blocks.



Ссылки и материалы:





Бонус!



История 1.

Как-то один из проектов использующих мой биткоин платежный шлюз взломали, и поставили на вывод 2 BTC. В той версии шлюза была захардкоджена комиссия 0.0001 BTC, что было достаточно мало на тот момент. Времени оказалось достаточно чтобы во всем разобраться и заменить транзакцию на возврат средств, повысив комиссию до 0.1 BTC. Злоумышленники наверное расстроились. Мораль — используйте RBF во благо!



История 2.

Я на bitmedia.io пополнял счет биткоином. Счет там пополняется засчитывая входящие транзакции на специальный top-up адрес пользователя, и прибавляя сумму транзакции к общему балансу пользователя. Засчитываются только транзакции с 6 подтверждениями.

Баланс я хотел пополнить поскорее, поэтому когда первая транзакция зависла, я несколько раз заменял транзакцию с помощью RBF. Когда транзакция подтвердилась — баланс мне приплюсовался в столько раз больше, сколько RBF замен я сделал. Я сразу написал в поддержку, чтобы баг исправили. В благодарность лишние 0.3 BTC мне подарили как bug bounty. Мораль — проверьте свои системы как они поведут себя с RBF!
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/327218/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

…And Justice for All

Четверг, 20 Апреля 2017 г. 19:10 (ссылка)

Коллега IvanKlut в своей статье "В поисках идеальной модели лицензирования" поднял вопрос о несовершенстве существующих лицензий, используемых при разработке OpenSource-проектов, с точки зрения монетизации усилий разработчиков, и предложил "поразмыслить об устройстве более эффективной экосистемы разработки сложных программных продуктов сообществом независимых разработчиков" (с).



image

Под катом мои субъективные соображения на этот счет.



Централизованное распределение дохода



Как мне кажется, в предлагаемой коллегой схеме "Нужна некоммерческая организация, целью которой является обеспечение устойчивого развития проекта и максимальная доступность для потребителей при достаточном ресурсном обеспечении" не хватает толики анархии.



Независимые некоммерческие организации в условиях капитализма не выживают, а "кто платит — тот и заказывает музыку". Более чем уверен, что разработчик свеженького модуля для подобного проекта, только что выложившийся на github, даже не помышляет об участии в финансировании подобной "некоммерческой организации". И как следствие, его интересы в этом "концерне" остаются непредставленными.



У меня есть некоторый опыт разработки модулей в подобной структуре, правда это коммерческая структура (но это-то как раз и естественно, коль мы обсуждаем монетизацию разработки). Я имею в виду мою "любимую" Magento (нет, и вправду любимую — я все-таки на нее потратил лет 6 своей жизни). Так вот, платформа Magento CE вполне себе даже бесплатна (в отличие от Enterprise Edition), а вот стоимость некоторых модулей для нее может достигать 5-х значных чисел в американской валюте.



Некоторая аналогия с предложением коллеги IvanKlut прослеживается также и в размещении приложений (модулей) на таких сервисах как Google Play (проект — Android) и App Store (проект — Apple).



Во всех трех случаях интересы разработчиков "модулей" явно находятся в "тени" интересов разработчиков "платформ". И это нормально, странно было бы, если бы было наоборот. И я сомневаюсь, что "некоммерческая организация" сможет изменить ситуацию на 180 градусов.



Delegation pattern



А что будет, если применить к сложившейся ситуации шаблон делегирования? Допустим, разработчик не заморачивается сам сбором денег с потребителя его продукта, а делегирует ответственность за эту хлопотную работу некоему "связанному объекту"? Назовем этот объект Агентом — по аналогии с Риком Пеком, агентом актера Тагга Спидмена (фильм "Tropic Thunder")



image



Великолепный Мэттью Макконахи блистательно отыграл поведение агента в ситуации, когда ему грозит потеря дохода, приносимого актером. Впрочем, как и его же поведение, когда актер приносит агенту стабильный доход.



Так вот, пусть Разработчик пишет программы, а Агент собирает для него деньги с Потребителя, использующего эти программы в коммерческих целях. Справедливо ведь, что Разработчик может рассчитывать на часть коммерческой прибыли, получаемой Потребителем за счет его программ? Уверен, что разработчики сочтут этот вопрос риторическим.



Для чего вводить Агента посредником? Мне кажется, что каждый должен заниматься своим делом: разработчик — разрабатывать программы, актер — играть на сцене и в кино, предприниматель — зарабатывать деньги, а агент — представлять чьи-то интересы. Ну а что делать, если Тагг Спидмен лучше играет в кино, а с Лессом Гроссманом лучше говорит о деньгах Рик Пек?! Это очевидно — Таггу лучше продолжать играть, а Рику — продолжать говорить о деньгах. Не стоит им меняться местами, не выйдет из этого ничего путевого.



Хорошо, допустим, Разработчик делегировал Агенту право собирать плату за разработанный им продукт с Потребителя. Где гарантия, что деньги полученные Агентом дойдут хоть в каком-то виде до Разработчика? Ведь это далеко не риторический вопрос.



Я бы сказал так, до Разработчика дойдет ровно столько денег, сколько нужно, чтобы он сидел, развивал свой продукт дальше и не сильно интересовался окружающим миром в целом и стоимостью его продукта для конечного Потребителя в частности. Ну а разве не в этом и заключается цель большинства Разработчиков свободного ПО — иметь возможность развивать свой продукт?



Будет ли разделен полученный доход Агентом по справедливости? Уверен, что — да! Как минимум с точки зрения того, кто этот доход делит. А что делать, если сам Разработчик считает иначе? Ответ прост — уволить Агента и делегировать его обязанности другому Агенту. А лучше — другим Агентам.



У каждого Агента свой стиль работы, своя "потребительская ниша". Это актеру тяжело сниматься в 100500 фильмах одновременно, а Разработчику написать программу, которая будет работать в 100500 коммерческих проектах вполне по силам. Вот пусть Агенты и представляют его интересы в этих самых 100500 проектах. Если нужно — пусть хоть по одному Агенту на проект. На каких условиях Агент продает его продукт? Да на каких продается — продукт стоит столько, за сколько его можно продать. Больше Агентов, хороших и разных. Самое главное, чтобы у Разработчика была возможность "уволить" любого Агента, если он не доволен по каким-то причинам его работой.



И у меня есть подозрения, что хорошие Агенты смогут представлять интересы не одного Разработчика, а интересы сразу множества Разработчиков. Причем самых разных проектов — начиная с jQuery, и заканчивая ядром Линукса (хотя там с монетизацией все более-менее, разве нет?).



Таким образом, имеем как раз "сложную систему со множеством независимых субъектов" (ну, или слабо-зависимых). Агенты зависят от множества Разработчиков, а Разработчик — от множества Агентов. В целом, отдельная связка "Агент РП — Разработчик ТС" в данной композиции ничего не решает и с легкостью может быть разорвана любой стороной. Но вот если все Агенты разорвут свои отношения с конкретным Разработчиком или все Разработчики — с конкретным Агентом, то для этой конкретной стороны игра может закончиться.



С моей точки зрения, подобная ситуация должна стимулировать все элементы этой мозаики придерживаться стратегии "win-win", что должно пойти на пользу индустрии в целом.



"Что делать?" (с)



И как нам дойти до жизни такой? Пусть специалисты по лицензированию меня поправят, но мне кажется, что достаточно вставить следующие 3 пунта в некторые лицензии типа MIT и BSD, чтобы предпосылки для подобной жизни начали создаваться и накапливаться. Вот эти три пункта:




  • Любая институция, имеющая законные права на проведение финансовых операций и признающая условия данной лицензии, может выступать Агентом, представляя коммерческие интересы Владельца данного ПО, если только Владелец в явном виде не ограничил список приемлемых для него Агентов.

  • В случае прямого коммерческого использования данного ПО конечный выгодополучатель обязуется приобрести право коммерческого использования у любого Агента, приемлемого для Владельца данного ПО.

  • В случае коммерческого использования данного ПО в составе другого ПО, конечный выгодополучатель обязуется приобрести право коммерческого использования на весь комплект программного обеспечения у любого Агента, приемлемого для Владельца данного ПО.



Данные три пункта вступают в действие только в том случае, если лицензируемое ПО используется в коммерческих целях и не ограничивают остальных свобод (копировать, анализировать, изменять, использовать для собственных нужд и т.п.).



Владельцу (разработчику) даже не нужно самому следить за тем, чтобы пользователи выполняли этих три пункта. Достаточно добавить их в лицензионное соглашение. Как только сложится такая ситуация, что станет возможно вести коммерчески выгодную деятельность по взыманию денег с выгодополучателей, я уверен, что сразу же появятся Агенты. Не зря ведь бытует мнение, что "нет такого преступления, на которое не пошел бы капитал при 300% прибыли". А тут даже и на преступление идти нет нужды.



Ну а если даже такие парни, как Лесс Гросманн и Рик Пек не смогут извлечь из твоей программы доход, то куда уж тебе, простому разработчику, впрягаться? Программируй и далее своего питомца в свободное от основной работы время.



И самое главное



И самое главное, добавить эти три пункта в лицензию для твоего проекта прямо сейчас тебе не стоит ничего.


Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/327000/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Экстремальная миграция на PostgreSQL: без остановки, потерь и тестирования

Четверг, 20 Апреля 2017 г. 16:14 (ссылка)



Буквально месяц назад в Яндекс.Деньгах завершился переезд сервиса профилей пользователей с Oracle на PostgreSQL. Так что теперь у нас есть опробованное решение по миграции больших объемов данных без потерь и остановки использующего их сервиса.



Под катом я расскажу подробнее о том, как все происходило, зачем мы выбрали для миграции SymmetricDS и почему без «ручных» усилий все равно не обошлось. Поделюсь также некоторыми наработками по вспомогательному коду для миграции.



Для первой миграции и обкатки решения выбрали сервис, обслуживающий пользовательские профили. К профилю относится история платежей, избранное, напоминалки и прочие подобные вещи — все важное, но для работы системы не критичное. База данных у нас без встроенной логики, поэтому перевезти на новую платформу нужно было только сами данные и секвенции.


Итак, через 3 месяца профили пользователей должны работать без Oracle



В связи с надвигающимися релизами по другим проектам решили завершить перенос за три месяца. Команда миграции состояла из 4 человек, зато это были разработчики уровня Senior и специалисты DBA. Чтобы небольшая команда смогла справиться в сжатый срок, под проект искали максимально автоматизированное решение: без написания кода миграции данных, ручной сборки схемы БД и т.п. База содержит около 50 таблиц, поэтому вероятность человеческой ошибки особенно высока при ручных преобразованиях.



Обычно такие миграции выполняются с остановкой сервиса — в нерабочее время. Но в Яндекс.Деньгах платежи проходят круглосуточно, поэтому останавливать систему ради внутренних «оптимизаций» было нельзя. Фактически для этого компонента бизнес согласовал нам приостановку на одну-две минуты, без потери данных.



В поисках идеального инструмента



Квартальный срок проекта не оставлял простора для изобретения собственных квазивелосипедов. Поэтому путем мозгового штурма мы собрали и отсеяли список подходящих продуктов для миграции:




  1. Oracle GoldenGate — может показаться, что это та самая серебряная пуля. По крайней мере, до момента ознакомления с ценой.




  2. SymmetricDS — есть миграция схемы, она будет создана или обновлена при регистрации узла PostgreSQL в мастер-узле Oracle. Есть возможность трансформировать данные при выгрузке или загрузке, используя BASH, Java или SQL.




  3. Full Convert — умеет мигрировать схему и данные, но ограничены возможности кастомизации, нет изменяемых трансформеров (код для изменения данных при миграции).




  4. Oracle to PostgreSQL Migration — переносит схему, данные, внешние ключи, индексы. Полуавтоматическая репликация, трансформации нет, но можно задать соответствие типов в разных БД.




  5. ESF Database Migration Toolkit — переносит все то же, что и Oracle to PostgreSQL Migration. Данные передаются в пакетном режиме, возможность миграции в несколько потоков отсутствует.




  6. Ora2Pg — переносит схему, данные, внешние ключи, индексы, возможна миграция в несколько потоков. Из минусов: медленный перенос таблиц с типами blob/clob (около 200 записей/сек), нет трансформатора.




  7. SQLData Tool — мигрирует только схему, ограничены возможности кастомизации.



Остальные представленные на рынке продукты или уже заброшены разработчиками, или не имеют развитой поддержки в сообществе.



В результате выбрали Ora2Pg для переноса схемы БД и SymmetricDS для миграции данных. Вообще, последний предназначен больше для синхронизации разных СУБД, чем для переноса данных. Но в нашем случае он позволил обеспечить миграцию без остановки сервисов.



Тысяча и одна мелочь для миграции



Когда обкатывали миграцию на копии продакшн-базы, то нашли целый набор «особенностей» и странностей в миграционном решении. Например, PostgreSQL не корректно отрабатывал некоторые запросы, которые без проблем проходили в Oracle. Например, SELECT * вызывал ошибку и остановку работы всего зависящего от БД сервиса. Вообще, такие запросы — дурной тон, на самом деле они были другие, а эти я привел просто как дозволенный пример. Оказалось, что это скорее проблема Java-драйвера, поэтому на момент реализации проекта было проще не использовать проблемные запросы. Позже этот баг исправили.



Были сложности и с транзакциями при установленном флаге AutoCommit-OFF. В PostgreSQL код падал, если при его выполнении предварительно не была открыта транзакция. Oracle вел себя иначе: транзакция откатывалась или завершалась кодом, который пришёл в этот же поток выполнения. Решение для PostgreSQL — написать код, который бы проверял наличие явно открытой транзакции для всех запросов на изменение данных.



При выполнении запросов сервис пользовательских профилей не указывал порядок сортировки выводимых значений (ORDER BY), так как в Oracle отсутствие признака означает вывод в хронологическом порядке. И на этом мы поскользнулись в PostgreSQL, который выводил результаты запроса вразнобой — причесали код так, чтобы ORDER BY был везде.



image alt text



Интересный нюанс был и с композитными транзакциями, которые изменяли данные как в исходной БД Oracle, так и в перенесенном на PostgreSQL экземпляре. Чтобы в обеих базах были одинаковые значения, наша команда разработала специальный менеджер транзакций. Он синхронно открывал и закрывал транзакции в обеих СУБД. Если в таких транзакциях возникали ошибки, то их уже приходилось решать вручную.



И понеслось



Миграция данных была поэтапной — по заранее утвержденному списку из 50 таблиц. Переключение решили сделать на уровне каждой таблицы в базе, что позволило достичь высокой гибкости и декомпозиции процесса. То есть в определенный момент, после переноса данных, для таблицы выставлялся специальный флаг, по которому сервис Я.Денег переключался на экземпляр данных в PostgreSQL.



Для удачной миграции Oracle-PostgreSQL важно заранее составить план, чтобы никакая досадная мелочь не забылась. Такой план был и у нас, вот он под спойлером:



Чек-лист миграции Oracle-PostgreSQL

Что нужно сделать разработчику:




  1. получить DDL таблицы на PostgreSQL;




  2. выделить интерфейс для DAO-класса;




  3. создать DAO-класс для работы с PostgreSQL;




  4. создать флаг для переключения работы с Oracle DAO на PostgreSQL DAO;




  5. написать тесты на новое DAO с покрытием от 80% (очень помогает избежать ошибок в синтаксисе SQL запросов использование механизма jOOQ). Больше — лучше;




  6. обкатать миграцию на тестовом стенде;




  7. выполнить миграции на приемочном стенде, убедиться в прохождении приемочных тестов;




  8. Релиз изменений на боевую среду.



Методичка для DBA:




  1. получить от разработчика DDL мигрируемой таблицы в БД PostgreSQL, создать таблицу и все связанные с ней сущности;




  2. уточнить у разработчика способ миграции — нужна ли первичная прогрузка старых данных и синхронизация новых записей?

    Если данных много, то по каким критериям можно ограничить объем первичной загрузки;




  3. настроить SymmetricDS на синхронизацию таблицы;




  4. в одной транзакции запустить первичную загрузку (если требуется) и синхронизацию новых записей;




  5. периодически проверять статус загрузки и синхронизации;




  6. непосредственно перед переключением сервисов на PostgreSQL передвинуть секвенции в таблице назначения для запаса по первичным ключам.



Что нужно не забыть ответственному за процесс:




  1. убедиться, что на продакшене поддерживается работа с PostgreSQL для конкретной таблицы;




  2. проверить, что на продакшене успешно выполнена первичная загрузка данных и включена синхронизация новых записей;




  3. попросить DBA передвинуть секвенции в PostgreSQL;




  4. переключить один экземпляр сервиса на работу с PostgreSQL, убедиться, что нет ошибок в логах и логике работы сервиса;




  5. переключить оставшиеся экземпляры сервиса;




  6. после полного переключения попросить DBA переименовать мигрированные таблицы в Oracle. Внимательно следить за ошибками в системе — какая-то «забытая» логика сервиса может пытаться по-прежнему работать с Oracle.



В процессе миграции часть из 50 таблиц работала на Oracle, другая — на PostgreSQL. Здесь и пригодился SymmetricDS, который мигрировал данные из Oracle в PostgreSQL и тем самым обеспечивал консистентность как для логики с перенесенными таблицами, так и для тех, что еще работали по старой схеме.



После переноса данных в сервисе устанавливался флажок «работай с PostgreSQL» для каждой конкретной таблицы, и запросы переходили к новой СУБД. Сначала переключение проверялось на dev-стенде, потом на приемочном. Если ОК — переключение на продакшн и переименование таблицы в Oracle (чтобы понять, не используется ли еще где старая таблица).



image alt text



На схеме суть идеи: после создания дубликата базы на PostgreSQL в сервисе устанавливается флаг new db, после чего все обращения идут к новой базе.



Но самым сложным было правильно подобрать момент переключения. Фактически у нас было 3 варианта миграции, в зависимости от критичности и сложности таблицы:




  1. Перенос таблицы целиком с последующим переключением. Вариант подходил в тех случаях, когда часть запросов можно было потерять (пользователя можно попросить нажать кнопку еще раз, или сработает автоматическое продолжение операции).




  2. На уровне дата центра (ДЦ, всего их 2). Способ для переноса критичных таблиц, при котором сначала переводим на PostgreSQL первый ЦОД, а в процессе его включения отключаем второй (с Oracle). На время старта — остановки Oracle и PostgreSQL могли работать параллельно, поэтому тут и пригодились механизмы синхронизации и переключения данных. Простоя в работе сервисов при этом не было.




  3. По методике «остаточного дожатия». Оставляем 2 экземпляра: Oracle для обработки опоздавших к переключению запросов и новый PostgreSQL. Новые задачи обрабатывались в новой базе, а старые удалялись после выполнения в оставшемся Oracle. Так переезжали очереди базы — автоплатежи, напоминалки и т.п.



Не обошлось и без сложностей. При первичном формировании схемы БД под PostgreSQL конвертер выдал не на 100% готовый вариант, что и ожидалось, в общем-то. Пришлось вручную менять некоторые типы колонок, исправлять секвенции и разбивать схему по таблицам и индексам. Впрочем, последнее — это уже для порядка и общей эстетики.



Чуть позже оказалось, что SymmetricDS не синхронизирует таблицы объемом более 150 ГБ. Поэтому пришлось засесть за код и создать обходной вариант переноса на такие случаи.



Впрочем, серебряной пули и тут не получилось. SymmetricDS не переносил поля CLOB\BLOB, если из-за них был превышен суммарный объем таблицы, поэтому пришлось писать ручные очереди миграции. Столкнулись и с совсем экзотическими случаями, когда миграция с Oracle на PostgreSQL приводила к резкому проседанию производительности. Ничего не оставалось, кроме как вручную разбирать каждый отдельный случай. Например, для одной таблицы пришлось выделить поле CLOB в отдельную таблицу, перенести ее на SSD-диск и читать это поле только при необходимости.



Так как нужно было поддерживать одновременно активными старые и новые экземпляры БД, для новых мы сделали запас по секвенциям, чтобы не происходило наслоения и попыток переноса в PostgreSQL дублирующихся ключей.



На схеме — схематичное изображение новой таблицы в PostgreSQL с «отступом» между старыми и новыми данными в 1000 ключей.



То есть если в таблице последний ключ был 100, то при переносе к этому значению добавлялась еще 1000, чтобы SymmetricDS мог свободно синхронизировать ключи 101, 102 и все остальные без перезаписи новых данных.



Финишная ленточка



За плановый квартал наша маленькая команда перенесла 80% таблиц на PostgreSQL. Оставшиеся 20% — это большие таблицы (в среднем более 150 ГБ), включая сборную таблицу с объемными полями CLOB\BLOB. Все это пришлось доделывать вручную следующие 1,5 месяца. Тем не менее связка SymmetricDS и Ora2Pg сделала большую часть рутинной работы, что и требовалось по условиям задачи. Наша команда разработки изрядно пополнила за этот проект внутреннюю копилку «грабель», часть из которых на момент выхода статьи наверняка осталась за кадром.



Но от Яндекс.Денег уже готовится десант на грядущую конференцию PG Days’17, которая пройдет в Санкт-Петербурге. Приходите на расширенный доклад и готовьте каверзные вопросы.



Впрочем, самые животрепещущие темы предлагаю поднять прямо тут, в комментариях. Очень любопытно почитать о вашем опыте миграции и, может быть, о том, что мы упустили из виду.



В репозитории Яндекс.Денег вы найдете немного кода описанных в статье решений:




  • Исходники Transaction Manager




  • Код класса проверки наличия транзакции.


Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/326998/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Своя криптовалюта на ethereum

Воскресенье, 17 Апреля 2017 г. 00:27 (ссылка)





Общая рыночная капитализация глобального рынка криптовалют за последний год выросла с $6 млрд (в январе 2016 года) до $28 млрд (на текущий момент). С начала 2017 года рынок криптовалют вырос примерно в полтора раза. На биржах торгуются уже больше сотни разных криптовалют. Крупные организации объединяются в консорциумы, чтобы выпускать свою валюту. Даже государства делают свои национальные криптовалюты. Технологии блокчейна дошли до такого уровня, что уже почти любой может запустить свою криптовалюту, чем мы в этой статье и займемся. Легче всего создать свои монеты на смарт контрактах на базе ethereum.



Зайдя на крупнейшую в настоящий момент биржу криптовалют, вверху списка можно найти к примеру следующие валюты: GNT (Golem), REP (Augur).







Хотя они и находятся в одном списке с Bitcoin (первая и самая известная криптовалюта) и Ethereum (вторая по популярности и капитализации валюта) — они не являются самостоятельными криптовалютами в классическом их понимании. Они являются крипто-токенами (tokens или assets) на базе блокчейна ethereum.



Список подобных токенов можно найти например здесь, там же можно найти статистику по ним.



Нужны подобные токены обычно для следующего: какая-то компания хочет выпустить продукт, в котором нужна некая внутренняя валюта. Также эта компания хочет провести ICO (Initial Coin Offering), т.е. собрать денег на проект путём предварительной продажи токенов инвесторам. Так и появляются эти токены. Преимущества здесь прямо истекают из преимуществ блокчейна и смарт контрактов: прозрачность, защищенность и распределенность.



Например, посмотрим на одну из первых таких компаний Golem. Суть её заключается в следующем: когда нам понадобятся вычислительные мощности, мы можем идти не на Amazon (Azure, Google...), а арендовать компьютер у другого участника сети, расплатившись с ним GNT токенами. Соответственно, также можно сдать свой компьютер в аренду и получить некоторое количество GNT. Дальше эти токены можно либо тратить внутри сети, либо продать на бирже. Некоторые токены могут приносить дивиденды, либо давать права голоса на проводимых выборах о каких-либо вопросах связанных с продуктом компании (такое реализуется на смарт контрактах).



Golem, выпустив 1,000,000,000 токенов, смогли привлечь 820,000 ETH, что по текущему курсы составляет примерно $32,800,000, но во времена их ICO курс был раза в 3 хуже.



Сейчас я вам расскажу, как сделать свою подобную криптовалюту (tokens) на базе Ethereum.



В настоящий момент стандартом считается ERC20, описанный здесь.



Интерфейс обычно выглядит примерно так:



/*
* ERC20 interface
* see https://github.com/ethereum/EIPs/issues/20
*/
contract ERC20 {
uint public totalSupply;
function balanceOf(address who) constant returns (uint);
function transfer(address to, uint value);
function allowance(address owner, address spender) constant returns (uint);

function transferFrom(address from, address to, uint value);
function approve(address spender, uint value);

event Transfer(address indexed from, address indexed to, uint value);
event Approval(address indexed owner, address indexed spender, uint value);
}


А реализация примерно так:



contract StandardToken is ERC20 {

string public constant name = "Token Name";
string public constant symbol = "TKN";
uint8 public constant decimals = 18;

mapping (address => mapping (address => uint)) allowed;
mapping (address => uint) balances;

function transferFrom(address _from, address _to, uint _value) {
var _allowance = allowed[_from][msg.sender];

// Check is not needed because safeSub(_allowance, _value) will already throw if this condition is not met
// if (_value > _allowance) throw;

balances[_to] +=_value;
balances[_from] -= _value;
allowed[_from][msg.sender] -= _value;
Transfer(_from, _to, _value);
}

function approve(address _spender, uint _value) {
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
}

function allowance(address _owner, address _spender) constant returns (uint remaining) {
return allowed[_owner][_spender];
}

function transfer(address _to, uint _value) {
balances[msg.sender] -= _value;
balances[_to] += _value;
Transfer(msg.sender, _to, _value);
}

function balanceOf(address _owner) constant returns (uint balance) {
return balances[_owner];
}
}


Разберем подробнее.



Это текущее количество выпущенных монет:



uint public totalSupply;


Узнаём баланс по адресу:



function balanceOf(address who) constant returns (uint);


Переводим свои токены кому-то другому:



function transfer(address to, uint value);


Узнаём сколько монет нам разрешено потратить с чужого аккаунта. Управление этими разрешениями осуществляется функцией approve, описанной ниже:



function allowance(address owner, address spender) constant returns (uint);


Переводим чужие, но доступные нам токены кому-то другому:



function transferFrom(address from, address to, uint value);


Разрешаем кому-то пользоваться нашими токенами. Но остаются эти токены у нас. Нет ограничений на количество аккаунтов, которому будет разрешено использовать наши токены:



function approve(address spender, uint value);


События о том, что кто-то перевел токены и о том, что кто-то разрешил пользоваться своими токенами:



event Transfer(address indexed from, address indexed to, uint value);
event Approval(address indexed owner, address indexed spender, uint value);


Полное имя токена:



string public constant name = "Token Name";


Краткое имя токена:



string public constant symbol = "TKN";


Количество десятичных разрядов. В ETH их 18, но можно поставить другое число



uint8 public constant decimals = 18; 


Словарь адрес -> количество токенов:



mapping (address => uint) balances;


Словарь доступных для распоряжения кому-то другому токенов:



mapping (address => mapping (address => uint)) allowed;


Вот, в принципе и все. Но в данном виде смарт контракт бесполезен, т.к. сейчас не предусматривает создание токенов и их количество всегда будет равно нулю.



Добавим конструктор, который будет создавать 1,000,000 токенов и переводить их владельцу смарт контракта. Также не помешало бы все математичекие операции сопровождать проверками на переполнение, но здесь я это упущу.



function StandardToken(){
balances[msg.sender] = 1000000;
}


Не помешало бы и добавить функцию, которая позволит покупать токены. Для простоты будем чеканить токены по курсу 1 к 1, т.е. за 1 ETH будем начислять 1 наш токен.

Выглядеть она может например так:



function mint() payable external {
if (msg.value == 0) throw;

var numTokens = msg.value;
totalSupply += numTokens;

balances[msg.sender] += numTokens;

Transfer(0, msg.sender, numTokens);
}


Осталось это опубликовать в блокчейн. После этого можно будет пересылать эти токены на другие аккаунты.



Полезные ссылки по теме:



-> Статистика по токенам

-> [Список активных и грядущих ICO](https://www.icoalert.com )


Original source: habrahabr.ru.

https://habrahabr.ru/post/326626/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Как IaaS-провайдер может сделать оплату услуг удобнее: 2 простых правила

Воскресенье, 09 Апреля 2017 г. 16:09 (ссылка)

Ранее мы уже неоднократно рассказывали о своем опыте оптимизации внутренних служб и общего развития сервиса в сторону повышения удобства работы с IaaS даже для тех, кто не сталкивался с администрированием серверов и далек от ИТ-сферы в целом.



Пара примеров:





Сегодня мы решили обсудить тему удобства проведения платежей за IaaS-услуги и поделиться своим опытом работы с различными платежными шлюзами.





/ Фото Alexander Baxevanis / CC



Переход на новые технологии — это всегда стресс. Зачастую люди не готовы отказаться от привычных инструментов в пользу более эффективных новинок. Вместо того, чтобы винить их в этом, стоит разобраться реальной выгоде от нововведений.



В качестве примера можно привести IaaS. Эта услуга появилась не вчера, но существенная часть компаний все еще опасается отдавать управление своей ИТ-инфраструктурой во вне. При этом содержание собственного парка серверов становится все более затратным мероприятием: необходимо выплачивать заработную плату администраторам и обслуживать свое железо.



Наш опыт внедрения новинок привел нас к следующим выводам.



Правило 1: Открытость информации



Для того, чтобы люди смогли быстрее разобраться в вашем продукте стоит задуматься о том, на сколько вы — открытая компания. Простота использования какой-либо функциональной возможности — понятие субъективное, поэтому здесь потребуется дополнительно поработать.



От скорости реакции на сообщения в профилях социальных сетей и ведения корпоративного блога, например на «Хабрахабре», до тематических руководств, в которых простыми словами даны ответы на наиболее частые вопросы, приведены пошаговые инструкции и советы для начинающих.



Все это необходимо для того, чтобы люди могли действовать самостоятельно — без звонков в службу поддержки с просьбой разобраться.



Одним из таких решений, которое мы решили использовать, стал специальный калькулятор, который позволяет быстро оценить уровень необходимых затрат на те или иные облачные ресурсы. Он доступен для использования даже теми, кто не является ИТ-специалистами.



Мы начали с того, что поместили на главную старницу сайта, но в дальнейшем немного пересмотрели этот подход и выделили три блока основных услуг, по которым можно получить расчет:





Такое решение позволяет моментально установить необходимые ожидания относительно потенциальных затрат на облачные ресурсы и принять решение о сотрудничестве.





/ Калькулятор для VPS/VDS, который включает в себя в том числе и ссылку на дополнительную информацию — статьи по категории «Тарификация и биллинг»



Помимо предоставления общей информации открытость подразумевает еще и оперативное информирование клиентов о сбоях и проблемах с предоставлением должного уровня обслуживания. С подобными ситуациями сталкиваются даже крупные провайдеры, бывают и технические сложности с платежным шлюзом — именно такую проблему нам и пришлось решать в конце 2014 года во время «падения» систем «Деньги Online».



О произошедшем мы были вынуждены сообщить всем клиентам, которых эта неисправность могла бы затронуть, и предложить другие варианты разрешения ситуации. Помимо этого мы быстро изучили альтернативные платежные шлюзы и занялись их подключением.



И тут мы подходим ко второму правилу.



Правило 2: «Это проблема разработчика»



Сложный интерфейс, технические неполадки, высокая степень загрузки службы поддержки — все это не волнует ваших клиентов. Мало кому интересно вникать в подробности устройства ваших бизнес-процессов и всевозможные сложности, связанные с работой ваших ИТ-специалистов.



Сложности с платежным шлюзом «Деньги Online» подтолкнули нас к анализу альтернативных вариантов. Мы начали с PayPal. Он был выбран еще и в силу наличия существенного потока зарубежных клиентов, которые хотели бы оплачивать наши услуги с помощью этого сервиса.



Самостоятельное изучение документации показало, что работа с API PayPal требует многочисленных «танцев» сами знаете с чем. Как-либо помогать и подсказать выход из ситуации служба поддержки PayPal отказалась, поэтому завершение настройки интеграции потребовало от нас различных хитростей с точки зрения разработки. Так или иначе, мы заключили прямое соглашение и благополучно добавили PayPal в качестве нового метода оплаты.



Далее мы занялись подключением «Робокассы» — более знакомого шлюза для русскоязычного сегмента Сети. Здесь не обошлось без аналогичных сложностей, но общение с коллегами из «Робокассы» позволило устранить ряд устаревших описаний в документации API и продвинуться дальше. В итоге и этот платежный шлюз был благополучно настроен.



По мере использования данных шлюзов мы удостоверились в том, что они неплохо дополняют «Деньги Online» и страхуют ситуацию на случай очередных технологических сложностей. Тем не менее, мы рассматривали и другие варианты, которые нам предлагали потенциальные партнеры.



Именно так мы и начали сотрудничество с платежной системой PayMaster, которая предложила нам выгодные условия по комиссии и очень удобный API. На данный момент мы настроили все доступные интеграции PayMaster и планируем использовать этот платежный шлюз в качестве основного (в том числе и с возможностью подключения повторяющихся платежей).







Технологическая безупречность обслуживания и доступность всех систем — критически важный фактор. Отсутствие сбоев и наличие альтернативных инструментов позволяет нам не заниматься ситуационным микроменеджментом отдельных проблем с оплатой (хотя ранее мы были вынуждены неоднократно «входить в ситуацию» и продлевать обслуживание ряда клиентов во время сбоев на стороне платежного шлюза).



Подобные нюансы могут и не повлиять на вашу выручку в первое время их ввода, но они обязательно изменят отношение ваших клиентов к тому, что вы делаете для их удобства работы. Именно этот подход и позволяет говорить о доверии, которое служит отправной точкой для стабильного и долговременного роста компании.



Дополнительные материалы по теме:




Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/325976/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Интеграция Android-приложения с фискальным принтером и кардридером

Пятница, 07 Апреля 2017 г. 17:48 (ссылка)

Всем привет! Сегодня мы хотим поделиться нашим опытом работы с периферийными устройствами на платформе Android.



Представим себе...



Вы пришли в горнолыжный прокат за лыжами и вам нужно рассчитаться картой и получить договор-оферту об оказании услуги и чек. Казалось бы, что может быть проще?

image






  1. Делаем раз. Выбрали инвентарь (лыжи, палки, ботинки, шлем и маску).

  2. Сотрудник ловко достает смартфон и сканирует им баркоды на инвентаре.

  3. Тут же достает считыватель пластиковых карт, снимает денежные средства и замораживает залог.

  4. А вот чек и договор-оферта, которые напечатал принтер, прикрепленный на пояс.

    image



Эх, мечты-мечты…



В реальности все куда дольше, и вы сами прекрасно знаете почему.



В одном месте вы выбираете инвентарь, потом идете в кассу, куда стекаются все со всех стоек проката, там оплачиваете, возвращаетесь к прокатчику, получаете у него инвентарь и, наконец-то готовы ко встрече с горой!

image

А в часы пиковых нагрузок эта история неминуемо превращается в сущий ад.




  1. Отстояли длиннющую очередь к прокатчику, выбрали инвентарь.

  2. Теперь постоим в общей очереди на кассу.

  3. Потом вернемся к прокатчику за законно оплаченным. И снова отстоим очередь. Вам ведь только спросить (забрать)? Да кого это волнует.



Вот так скорость обслуживания из полутора минут растянулась на все 20, а в это время утренний вельвет снежного склона уже кто-то режет лыжами!



Кто виноват, и что делать?



Почему бы прокату не обустроить каждую стойку кассой? Да потому, что такая проблема не постоянна. Пиковые нагрузки случаются регулярно, но по большому счету не так часто – утро выходных и праздников, и это только если погода катальная. Поэтому инвестировать в кассовое оборудование с точки зрения владельцев явно затраты не супер оправданные. Эту задачу решает появление дополнительного мобильного сотрудника который раз, два, и помог очереди рассосаться.



В кейсе с горнолыжкой достаточно было бы купить коробочное решение для интеграции смартфона с кассовым принтером и картридером, коих на рынке хватает. Ими пользуются и курьеры, которые доставляют заказы, и девушки, которые продают билеты на аэроэкспресс.



Мы бы тоже могли ввести сумму и получить оплату, но у нас не прокат инвентаря!



В системе заказчика с которой работали мы, буква закона требовала выдачи клиенту не просто чека на энную сумму, но еще и квитанции с подробным описанием услуги и уникальным присвоенным ей номером. То есть мы должны провести оплату, зарегистрировать это на сервере, получить уникальный номер транзакции, и затем распечатать чек, в котором отображается этот номер, полное описание услуги и баркод с закодированной информацией.



Задача поставлена, переходим к реализации.



Реализация



1. Выбираем принтер и картридер



Для начала определились, что надо использовать комплекс со смартфоном, который позволяет пользователю настраивать параметры услуги и взаимодействовать с сервером. Вопрос о выборе смартфонов для системы решился сам собой. Заказчик выбрал «рабочих лошадок» — смартфоны на базе Android. Ими оказались Huawei Honor 5C. Удобные недорогие устройства от китайского производителя. Главное, что Bluetooth есть и работает. А вот дальше надо было решить задачи посложнее. Чтобы все операции с продажей услуг проводились законно, нам был нужен фискальный регистратор. Это принтер с памятью, в которую записывается история операций по проведенным продажам.



Мобильные фискальные принтеры (а мы помним, что наше решение должно быть мобильным!) выпускаются рядом российских компаний «Атол», «Инкотекс», «Счетмаш», «Штрих-М». Мы изучили их предложения, но в нашем решении принтер должен был печатать на широкой ленте (3” вместо 2”), поскольку нам нужно было разместить на чеке подробные данные об оказанной услуге. Широкая лента нашлась только у одного включенного в государственный реестр мобильного фискального принтера ШТРИХ-MOBILE-ПТК.



С клиентов нам необходимо брать не только наличные платежи, но и списывать деньги с карты. А значит нужны картридер и провайдер такого решения, чтобы проводить оплаты и учитывать все проводимые таким способом средства. И таких решений на нашем рынке достаточно. Различаются они, пожалуй, типами моделей устройств для считывания, процентом комиссии за проведение эквайринга и… интеграциями с фискальными принтерами! Тут-то нам и попалось решение от iBox Pro, использующее картридер модели chip-n-pin с клавиатурой, а также, по счастью, интегрированное с мобильным фискальным регистратором ШТРИХ-MOBILE-ПТК.



Компания предоставила нам тестовые устройства, и мы принялись за работу...



2. Снимаем деньги



С платежной системой iBox Pro мобильное приложение можно интегрировать простым (через intent-вызов) и сложным способом (через SDK). Мы выбрали сложный путь, но вовсе не потому, что нам нравится преодолевать трудности. А по другой важной причине. Тут понадобится лирическое отступление.



В случае intent-вызова алгоритм такой:

image

Наш алгоритм выглядит иначе. Мы не можем просто взять, вбить сумму за услугу и распечатать чек. Нам нужно отправить данные на сервер, получить стоимость услуги, затем получить оплату от клиента, и после этого обратиться к серверу и получить уникальный код и затем обязательно отразить этот код в чеке.



Поэтому мы разработали такой алгоритм:

image

В итоге с помощью SDK iBox (свежую версию их эволюционирующего SDK можно скачать с GitHUB) мы встроили вызовы к iBox в наше мобильное приложение. Бонусом получили более удобный для пользователя единый интерфейс – на этапе оплаты человеку не приходится переключаться на сторонний интерфейс iBox, все процессы происходят только в рамках нашего мобильного приложения.



Пример работы с iBox SDK
// С помощью вызовов методов PaymentController-а происходит передача команд устройству:

// Устанавливаем однофакторную авторизацию.
PaymentController.getInstance().setSingleStepEMV(true);

// Задаем логин и пароль кассира через которого будет проводиться оплата
PaymentController.getInstance().setCredentials(loginInfo.userName, loginInfo.userPassword);

// Среди сопряженных с телефоном устройств находим то,
// которое было указано в качестве картридера.
// Индекс этого устройства передаем PaymentCotroller-у.
ReaderBluetoothInfo readerBluetoothInfo = settingsService.getReaderBluetoothInfo();

List devices =
PaymentController.getInstance().getBluetoothDevices(getView().getContext());

for (int i = 0; i < devices.size(); ++i) {
if (devices.get(i).getAddress().equals(readerBluetoothInfo.readerAddres) &&
devices.get(i).getName().equals(readerBluetoothInfo.readerName)) {
PaymentController.getInstance().setReaderType(
getView().getContext(),
PaymentController.ReaderType.WISEPAD, i, null);
}
}
}

...
PaymentDialog paymentDialog = new PaymentDialog();

// Перед непосредственным проведением платежа:
// Передаем в контроллер листенер, на который будут приходить статусы и результат платежей от ibox. В нашем случае это диалог, который отображает статус оплаты.
PaymentController.getInstance().setPaymentControllerListener(paymentDialog);
PaymentController.getInstance().enable();

// Запускаем платеж по карте
PaymentController.getInstance().startPayment(getContext(), mPaymentContext);

...
// Метод который вызывает PaymentController во время проведения оплаты.
public void onReaderEvent(PaymentController.ReaderEvent event) {
switch (event) {
case CONNECTED :
case START_INIT :
lblState.setText(R.string.reader_state_init);
break;
case DISCONNECTED :
stopProgress();
lblState.setText(R.string.reader_state_disconnected);
break;
case SWIPE_CARD :
case TRANSACTION_STARTED :
startProgress();
break;

...
case EJECT_CARD :
stopProgress();
lblState.setText(R.string.reader_state_eject);
break;
case BAD_SWIPE :
Toast.makeText(mActivity, R.string.reader_bad_swipe, Toast.LENGTH_LONG).show();
break;
case LOW_BATTERY :
Toast.makeText(mActivity, R.string.reader_low_battery, Toast.LENGTH_LONG).show();
break;
default :
break;
}
}


3. Печатаем документы



После фиксации факта продажи необходимо выдать клиенту чек, а иногда и дополнительные документы – договор-оферту, бланк заказа или гарантийное письмо. Вопрос “на чем будем печатать?” — если у пользователя на поясе висит мобильный принтер — пусть печатается на нём. Поэтому, мы заставили принтер печатать помимо фискальных чеков и другие документы.



С принтером мы работаем через небольшую библиотеку от Штрих-М, которую они создали для удобства работы с JPOS.



Осторожно, грабельный лес!



При печати документов на мобильном принтере мы столкнулись с двумя случаями, когда матрица давала сбой:




  • В сочетании с некоторыми смартфонами, которые мы использовали для тестирования, скорость работы принтера падала катастрофически. Нас это очень тревожило, так как по стандарту обслуживания заказчик требовал от нас уложиться в 1,5 минуты со всем процессом от оформления услуги до выдачи чека. По счастью, целевой девайс печатал по Bluetooth без проблем, и эту загадку мы решили оставить неразгаданной.




  • На боевом тестировании абсолютно одинаковые фискальные принтеры вели себя по-разному: из-за внутренних настроек некоторые из них при печати баркода сдвигали баркод на документе вправо, отрезая часть информации. Решить удалось только применив волшебный workaround :) – уменьшили некоторые элементы чека и баркода без потери качества считывания сканером.



В итоге получился вот такой код печати баркода, если кому интересно.
ShtrihFiscalPrinter printer = new ShtrihFiscalPrinter(new FiscalPrinter());

PrinterBarcode printerBarcode = new PrinterBarcode();
printerBarcode.setText(boardingPass.barcodeText); //Информация, зашифрованная в баркоде.
printerBarcode.setLabel("");
// Устанавливаем ширину, что пропорционально меняет размер баркода.
// Возможные значения параметра - см. документацию к принтеру.
printerBarcode.setBarWidth(2); // 2 - small width
printerBarcode.setType(PrinterBarcode.SM_BARCODE_PDF417);

Map parameters = new HashMap<>();

// В качестве альтернативы вместо изменения размера элементов баркода можно уменьшить его по ширине и увеличить по высоте.
// Поменять измерения баркода можно в строчке ниже.
parameters.put(EncodeHintType.PDF417_DIMENSIONS, new Dimensions(5, 5, 2, 60));

printerBarcode.addParameter(parameters);

printer.printBarcode(printerBarcode);



  • Ещё одна странная проблема всплыла при работе с iBox. При работе с нашими смартфонами устройство могло войти в спящий режим и не выходило из него. Проявлялось только с Huawei и вылечилось с помощью установки последней версии прошивки картридера.



4. Печатаем фискальный чек



По умолчанию фискальный принтер выдает чек от платежной системы с минимумом информации. Нас это не устроило. Во-первых, нам нужен был красиво оформленный чек, который выглядел бы аналогично чекам, утвержденным в других системах заказчика. Во-вторых, нам нужно было совместить чек с квитанцией об оказании услуги и подробной информацией о ней. Итого – с помощью SDK принтера мы сделали красивый документ чек-квитанцию. А потом долго и мучительно на тестировании один за другим печатали чеки, меняя параметры, пока, наконец, реальная бумажка не стала выглядеть на всех принтерах одинаково и так, как нужно.



Вот код для печати фискального чека:
private void printTicket(PrinterInfo printerInfo, boolean isRefund, String agentId) throws Exception {
ShtrihFiscalPrinter printer = new ShtrihFiscalPrinter(new FiscalPrinter());

//Здесь заполняется таблица налогов внутри принтера
final String NO_TAX = "0";
final String TEN_PERCENT_TAX = "1000";
printer.setVatValue(1, NO_TAX);
printer.setVatValue(2, TEN_PERCENT_TAX); //НДС 10%
printer.setVatValue(3, NO_TAX);
printer.setVatValue(4, NO_TAX);
printer.setVatTable();

printer.setHeaderLine(1, StringTools.appendStrings("", "*", LINE_LENGTH), false);
printer.setHeaderLine(2, getHeader("ООО \"Хорошая компания\""), false);
printer.setHeaderLine(3, getHeader("Тридевятое государство"), false);
printer.setHeaderLine(4, getHeader("улица Пушкина, \nДом колотушкина"), false);
printer.setHeaderLine(5, getHeader("+7(XXX)XXX-XX-XX"), false);
printer.setHeaderLine(6, StringTools.appendStrings("", "*", LINE_LENGTH), false);

if (isRefund) {
printer.setFiscalReceiptType(jpos.FiscalPrinterConst.FPTR_RT_REFUND);
} else {
printer.setFiscalReceiptType(jpos.FiscalPrinterConst.FPTR_RT_SALES);
}

printer.beginFiscalReceipt(true);

printLine();

double priceSum = 0;
//PrinterEmdData содержит информацию о купленной пассажиром услуге.
for (PrinterEmdData printerEmdData : printerInfo.getPrinterEmdDatas()) {
String description = getDescription(printerEmdData, printerInfo.isCashierFormat());
int tax = 0;
final int TEN_PERCENT_NDS = 10;
final int SECOND_TAX_SLOT = 2;
if (printerEmdData.taxValue == TEN_PERCENT_TAX) {
tax = SECOND_TAX_SLOT; // Здесь указываем, что нас интересует налог 10% (он у нас стоит во 2-ом слоте таблицы налогов)
}
priceSum += printerEmdData.price;

if (isRefund) {
printer.printRecItemRefund(description, 0, 0, tax, (long) printerEmdData.price, "");
} else {
printer.printRecItem(description, 0, 0, tax, (long) printerEmdData.price, "");
}

}

printLine();
if (printerInfo.isCard()) {
printer.printRecTotal((long) priceSum, (long) priceSum, "1");
} else {
long cashIn = (long) priceSum;
if (printerInfo.getCashIn() > 0) {
cashIn = (long) printerInfo.getCashIn();
}
printer.printRecTotal((long) priceSum, cashIn, "");
}

printer.endFiscalReceipt(true);
}


5. Обеспечиваем отказоустойчивость системы



Конечно, мало просто сделать интеграцию в системе, важно сделать эту систему надежной. Для нас важно было обеспечить механизмы отката назад с любого этапа. Например, платежный сервис подтвердил приложению снятие денег, приложение запросило у сервиса бронирования услуг уникальный номер услуги, и тут пропала связь с сервером. И вот на этом этапе нужно сделать Fallback-механизм, который позволит повторить запрос на сервер или вернуть деньги на карту.



Вариантов подобных ошибок оказалось множество: при снятии денег рано вытащили карту, неправильно ввели пин-код, при попытке распечатать чек закончилась кассовая лента, принтер разрядился и так далее. Границы необходимой отказоустойчивости на каждом этапе мы определяли в ходе тест-сессий с участием опытных кассиров. В результате для каждой ошибки были разработаны необходимые Fallback-механизмы.



Возможные ошибки в процессе приема денег и распечатки чека



image



Итого:




  • Сделали отказоустойчивую интеграцию смартфон + картридер + фискальный принтер.

  • Протестировали в боевых условиях и наладили еще раз все Fallback-механизмы.

  • Решение внедрено, работает и радует пользователей приложения и их клиентов.



Мы на собственном примере убедились, что решить задачу приёма платежей с помощью мобильных устройств можно, даже если на стороне сервера необходимо вести строгий учёт каждой операции. Может быть, прочитав статью, кто-то увидит возможность избавить людей от потери времени в очередях и в какой то другой сфере.



Даешь больше комфорта клиентам, которыми можем оказаться и мы с вами!


Original source: habrahabr.ru.

https://habrahabr.ru/post/325950/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Интеграция Android-приложения с фискальным принтером и кардридером

Пятница, 07 Апреля 2017 г. 17:48 (ссылка)

Всем привет! Сегодня мы хотим поделиться нашим опытом работы с периферийными устройствами на платформе Android.



Представим себе...



Вы пришли в горнолыжный прокат за лыжами и вам нужно рассчитаться картой и получить договор-оферту об оказании услуги и чек. Казалось бы, что может быть проще?

image






  1. Делаем раз. Выбрали инвентарь (лыжи, палки, ботинки, шлем и маску).

  2. Сотрудник ловко достает смартфон и сканирует им баркоды на инвентаре.

  3. Тут же достает считыватель пластиковых карт, снимает денежные средства и замораживает залог.

  4. А вот чек и договор-оферта, которые напечатал принтер, прикрепленный на пояс.

    image



Эх, мечты-мечты…



В реальности все куда дольше, и вы сами прекрасно знаете почему.



В одном месте вы выбираете инвентарь, потом идете в кассу, куда стекаются все со всех стоек проката, там оплачиваете, возвращаетесь к прокатчику, получаете у него инвентарь и, наконец-то готовы ко встрече с горой!

image

А в часы пиковых нагрузок эта история неминуемо превращается в сущий ад.




  1. Отстояли длиннющую очередь к прокатчику, выбрали инвентарь.

  2. Теперь постоим в общей очереди на кассу.

  3. Потом вернемся к прокатчику за законно оплаченным. И снова отстоим очередь. Вам ведь только спросить (забрать)? Да кого это волнует.



Вот так скорость обслуживания из полутора минут растянулась на все 20, а в это время утренний вельвет снежного склона уже кто-то режет лыжами!



Кто виноват, и что делать?



Почему бы прокату не обустроить каждую стойку кассой?

Да потому, что такая проблема не постоянна. Пиковые нагрузки случаются регулярно, но по большому счету не так часто – утро выходных и праздников, и это только если погода катальная. Поэтому инвестировать в кассовое оборудование с точки зрения владельцев явно затраты не супер оправданные.

Эту задачу решает появление дополнительного мобильного сотрудника который раз, два, и помог очереди рассосаться.



В кейсе с горнолыжкой достаточно было бы купить коробочное решение для интеграции смартфона с кассовым принтером и картридером, коих на рынке хватает. Ими пользуются и курьеры, которые доставляют заказы, и девушки, которые продают билеты на аэроэкспресс.



Мы бы тоже могли ввести сумму и получить оплату,

но у нас не прокат инвентаря!



В системе заказчика с которой работали мы, буква закона требовала выдачи клиенту не просто чека на энную сумму, но еще и квитанции с подробным описанием услуги и уникальным присвоенным ей номером. То есть мы должны провести оплату, зарегистрировать это на сервере, получить уникальный номер транзакции, и затем распечатать чек, в котором отображается этот номер, полное описание услуги и баркод с закодированной информацией.



Задача поставлена, переходим к реализации.



Реализация



1. Выбираем принтер и картридер



Для начала определились, что надо использовать комплекс со смартфоном, который позволяет пользователю настраивать параметры услуги и взаимодействовать с сервером. Вопрос о выборе смартфонов для системы решился сам собой. Заказчик выбрал «рабочих лошадок» — смартфоны на базе Android. Ими оказались Huawei Honor 5C. Удобные недорогие устройства от китайского производителя. Главное, что Bluetooth есть и работает. А вот дальше надо было решить задачи посложнее. Чтобы все операции с продажей услуг проводились законно, нам был нужен фискальный регистратор. Это принтер с памятью, в которую записывается история операций по проведенным продажам.



Мобильные фискальные принтеры (а мы помним, что наше решение должно быть мобильным!) выпускаются рядом российских компаний «Атол», «Инкотекс», «Счетмаш», «Штрих-М». Мы изучили их предложения, но в нашем решении принтер должен был печатать на широкой ленте (3” вместо 2”), поскольку нам нужно было разместить на чеке подробные данные об оказанной услуге. Широкая лента нашлась только у одного включенного в государственный реестр мобильного фискального принтера ШТРИХ-MOBILE-ПТК.



С клиентов нам необходимо брать не только наличные платежи, но и списывать деньги с карты. А значит нужны картридер и провайдер такого решения, чтобы проводить оплаты и учитывать все проводимые таким способом средства. И таких решений на нашем рынке достаточно. Различаются они, пожалуй, типами моделей устройств для считывания, процентом комиссии за проведение эквайринга и… интеграциями с фискальными принтерами! Тут-то нам и попалось решение от iBox Pro, использующее картридер модели chip-n-pin с клавиатурой, а также, по счастью, интегрированное с мобильным фискальным регистратором ШТРИХ-MOBILE-ПТК.

Компания предоставила нам тестовые устройства, и мы принялись за работу...



2. Снимаем деньги



С платежной системой iBox Pro мобильное приложение можно интегрировать простым (через intent-вызов) и сложным способом (через SDK). Мы выбрали сложный путь, но вовсе не потому, что нам нравится преодолевать трудности. А по другой важной причине. Тут понадобится лирическое отступление.



В случае intent-вызова алгоритм такой:

image

Наш алгоритм выглядит иначе. Мы не можем просто взять, вбить сумму за услугу и распечатать чек. Нам нужно отправить данные на сервер, получить стоимость услуги, затем получить оплату от клиента, и после этого обратиться к серверу и получить уникальный код и затем обязательно отразить этот код в чеке.



Поэтому мы разработали такой алгоритм:

image

В итоге с помощью SDK iBox (свежую версию их эволюционирующего SDK можно скачать с GitHUB) мы встроили вызовы к iBox в наше мобильное приложение. Бонусом получили более удобный для пользователя единый интерфейс – на этапе оплаты человеку не приходится переключаться на сторонний интерфейс iBox, все процессы происходят только в рамках нашего мобильного приложения.



Пример работы с iBox SDK
// С помощью вызовов методов PaymentController-а происходит передача команд устройству:

// Устанавливаем однофакторную авторизацию.
PaymentController.getInstance().setSingleStepEMV(true);

// Задаем логин и пароль кассира через которого будет проводиться оплата
PaymentController.getInstance().setCredentials(loginInfo.userName, loginInfo.userPassword);

// Среди сопряженных с телефоном устройств находим то,
// которое было указано в качестве картридера.
// Индекс этого устройства передаем PaymentCotroller-у.
ReaderBluetoothInfo readerBluetoothInfo = settingsService.getReaderBluetoothInfo();

List devices =
PaymentController.getInstance().getBluetoothDevices(getView().getContext());

for (int i = 0; i < devices.size(); ++i) {
if (devices.get(i).getAddress().equals(readerBluetoothInfo.readerAddres) &&
devices.get(i).getName().equals(readerBluetoothInfo.readerName)) {
PaymentController.getInstance().setReaderType(
getView().getContext(),
PaymentController.ReaderType.WISEPAD, i, null);
}
}
}

...
PaymentDialog paymentDialog = new PaymentDialog();

// Перед непосредственным проведением платежа:
// Передаем в контроллер листенер, на который будут приходить статусы и результат платежей от ibox. В нашем случае это диалог, который отображает статус оплаты.
PaymentController.getInstance().setPaymentControllerListener(paymentDialog);
PaymentController.getInstance().enable();

// Запускаем платеж по карте
PaymentController.getInstance().startPayment(getContext(), mPaymentContext);

...
// Метод который вызывает PaymentController во время проведения оплаты.
public void onReaderEvent(PaymentController.ReaderEvent event) {
switch (event) {
case CONNECTED :
case START_INIT :
lblState.setText(R.string.reader_state_init);
break;
case DISCONNECTED :
stopProgress();
lblState.setText(R.string.reader_state_disconnected);
break;
case SWIPE_CARD :
case TRANSACTION_STARTED :
startProgress();
break;

...
case EJECT_CARD :
stopProgress();
lblState.setText(R.string.reader_state_eject);
break;
case BAD_SWIPE :
Toast.makeText(mActivity, R.string.reader_bad_swipe, Toast.LENGTH_LONG).show();
break;
case LOW_BATTERY :
Toast.makeText(mActivity, R.string.reader_low_battery, Toast.LENGTH_LONG).show();
break;
default :
break;
}
}


3. Печатаем документы



После фиксации факта продажи необходимо выдать клиенту чек, а иногда и дополнительные документы – договор-оферту, бланк заказа или гарантийное письмо. Вопрос “на чем будем печатать?” — если у пользователя на поясе висит мобильный принтер — пусть печатается на нём. Поэтому, мы заставили принтер печатать помимо фискальных чеков и другие документы.

С принтером мы работаем через небольшую библиотеку от Штрих-М, которую они создали для удобства работы с JPOS.



Осторожно, грабельный лес!



При печати документов на мобильном принтере мы столкнулись с двумя случаями, когда матрица давала сбой:




  • В сочетании с некоторыми смартфонами, которые мы использовали для тестирования, скорость работы принтера падала катастрофически. Нас это очень тревожило, так как по стандарту обслуживания заказчик требовал от нас уложиться в 1,5 минуты со всем процессом от оформления услуги до выдачи чека. По счастью, целевой девайс печатал по Bluetooth без проблем, и эту загадку мы решили оставить неразгаданной.




  • На боевом тестировании абсолютно одинаковые фискальные принтеры вели себя по-разному: из-за внутренних настроек некоторые из них при печати баркода сдвигали баркод на документе вправо, отрезая часть информации. Решить удалось только применив волшебный workaround :) – уменьшили некоторые элементы чека и баркода без потери качества считывания сканером.



В итоге получился вот такой код печати баркода, если кому интересно.
ShtrihFiscalPrinter printer = new ShtrihFiscalPrinter(new FiscalPrinter());

PrinterBarcode printerBarcode = new PrinterBarcode();
printerBarcode.setText(boardingPass.barcodeText); //Информация, зашифрованная в баркоде.
printerBarcode.setLabel("");
// Устанавливаем ширину, что пропорционально меняет размер баркода.
// Возможные значения параметра - см. документацию к принтеру.
printerBarcode.setBarWidth(2); // 2 - small width
printerBarcode.setType(PrinterBarcode.SM_BARCODE_PDF417);

Map parameters = new HashMap<>();

// В качестве альтернативы вместо изменения размера элементов баркода можно уменьшить его по ширине и увеличить по высоте.
// Поменять измерения баркода можно в строчке ниже.
parameters.put(EncodeHintType.PDF417_DIMENSIONS, new Dimensions(5, 5, 2, 60));

printerBarcode.addParameter(parameters);

printer.printBarcode(printerBarcode);



  • Ещё одна странная проблема всплыла при работе с iBox. При работе с нашими смартфонами устройство могло войти в спящий режим и не выходило из него. Проявлялось только с Huawei и вылечилось с помощью установки последней версии прошивки картридера.



4. Печатаем фискальный чек



По умолчанию фискальный принтер выдает чек от платежной системы с минимумом информации. Нас это не устроило. Во-первых, нам нужен был красиво оформленный чек, который выглядел бы аналогично чекам, утвержденным в других системах заказчика. Во-вторых, нам нужно было совместить чек с квитанцией об оказании услуги и подробной информацией о ней. Итого – с помощью SDK принтера мы сделали красивый документ чек-квитанцию. А потом долго и мучительно на тестировании один за другим печатали чеки, меняя параметры, пока, наконец, реальная бумажка не стала выглядеть на всех принтерах одинаково и так, как нужно.



Вот код для печати фискального чека:
private void printTicket(PrinterInfo printerInfo, boolean isRefund, String agentId) throws Exception {
ShtrihFiscalPrinter printer = new ShtrihFiscalPrinter(new FiscalPrinter());

//Здесь заполняется таблица налогов внутри принтера
final String NO_TAX = "0";
final String TEN_PERCENT_TAX = "1000";
printer.setVatValue(1, NO_TAX);
printer.setVatValue(2, TEN_PERCENT_TAX); //НДС 10%
printer.setVatValue(3, NO_TAX);
printer.setVatValue(4, NO_TAX);
printer.setVatTable();

printer.setHeaderLine(1, StringTools.appendStrings("", "*", LINE_LENGTH), false);
printer.setHeaderLine(2, getHeader("ООО \"Хорошая компания\""), false);
printer.setHeaderLine(3, getHeader("Тридевятое государство"), false);
printer.setHeaderLine(4, getHeader("улица Пушкина, \nДом колотушкина"), false);
printer.setHeaderLine(5, getHeader("+7(XXX)XXX-XX-XX"), false);
printer.setHeaderLine(6, StringTools.appendStrings("", "*", LINE_LENGTH), false);

if (isRefund) {
printer.setFiscalReceiptType(jpos.FiscalPrinterConst.FPTR_RT_REFUND);
} else {
printer.setFiscalReceiptType(jpos.FiscalPrinterConst.FPTR_RT_SALES);
}

printer.beginFiscalReceipt(true);

printLine();

double priceSum = 0;
//PrinterEmdData содержит информацию о купленной пассажиром услуге.
for (PrinterEmdData printerEmdData : printerInfo.getPrinterEmdDatas()) {
String description = getDescription(printerEmdData, printerInfo.isCashierFormat());
int tax = 0;
final int TEN_PERCENT_NDS = 10;
final int SECOND_TAX_SLOT = 2;
if (printerEmdData.taxValue == TEN_PERCENT_TAX) {
tax = SECOND_TAX_SLOT; // Здесь указываем, что нас интересует налог 10% (он у нас стоит во 2-ом слоте таблицы налогов)
}
priceSum += printerEmdData.price;

if (isRefund) {
printer.printRecItemRefund(description, 0, 0, tax, (long) printerEmdData.price, "");
} else {
printer.printRecItem(description, 0, 0, tax, (long) printerEmdData.price, "");
}

}

printLine();
if (printerInfo.isCard()) {
printer.printRecTotal((long) priceSum, (long) priceSum, "1");
} else {
long cashIn = (long) priceSum;
if (printerInfo.getCashIn() > 0) {
cashIn = (long) printerInfo.getCashIn();
}
printer.printRecTotal((long) priceSum, cashIn, "");
}

printer.endFiscalReceipt(true);
}


5. Обеспечиваем отказоустойчивость системы



Конечно, мало просто сделать интеграцию в системе, важно сделать эту систему надежной. Для нас важно было обеспечить механизмы отката назад с любого этапа. Например, платежный сервис подтвердил приложению снятие денег, приложение запросило у сервиса бронирования услуг уникальный номер услуги, и тут пропала связь с сервером. И вот на этом этапе нужно сделать Fallback-механизм, который позволит повторить запрос на сервер или вернуть деньги на карту.



Вариантов подобных ошибок оказалось множество: при снятии денег рано вытащили карту, неправильно ввели пин-код, при попытке распечатать чек закончилась кассовая лента, принтер разрядился и так далее. Границы необходимой отказоустойчивости на каждом этапе мы определяли в ходе тест-сессий с участием опытных кассиров. В результате для каждой ошибки были разработаны необходимые Fallback-механизмы.



Возможные ошибки в процессе приема денег и распечатки чека



image



Итого:




  • Сделали отказоустойчивую интеграцию смартфон + картридер + фискальный принтер.

  • Протестировали в боевых условиях и наладили еще раз все Fallback-механизмы.

  • Решение внедрено, работает и радует пользователей приложения и их клиентов.



Мы на собственном примере убедились, что решить задачу приёма платежей с помощью мобильных устройств можно, даже если на стороне сервера необходимо вести строгий учёт каждой операции. Может быть, прочитав статью, кто-то увидит возможность избавить людей от потери времени в очередях и в какой то другой сфере.



Даешь больше комфорта клиентам, которыми можем оказаться и мы с вами!


Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/325950/

Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Мир платежного посредничества: практикум в волшебстве

Пятница, 07 Апреля 2017 г. 07:51 (ссылка)

Как я и обещал в предыдущей статье «Введение в волшебный мир платежного посредничества» (ссылка будет под статьей), во второй части статьи я рассмотрю способы разрешения кризиса рынка посреднических услуг и некоторые особенности продаж сложного информационного продукта. Возможно, он будет интересен не только дистрибьюторам/агрегаторам и банкам, но и просто специалистам в сфере продаж.



Итак, мы остановились на небольших изменениях блока ЛПР в нашем сценарии (Я рассмотрю одно из направлений). Изначально менеджеру предлагалось выходить на SPIN, используя такие вопросы:



«Верно ли я понимаю, что вы занимаетесь, в основном, консультацией и содействием в оформлении документов



«И Вы, при этом, стараетесь предоставлять клиентам комплекс услуг в одном окне?»



«А как обычно происходит оплата клиентом пошлин и налогов



Их мы заменили такими:



«Верно ли я понимаю, что Вы оформляете мигрантов под ключ?»



«А как у Вас организована оплата патентов



Далее по сценарию следует сжатый SPIN-материал, который от изначально запланированного составил от силы треть, именно потому что дальнейшие разбирательства/обработчики возражений уже не требовались. Ожидали волшебных слов? А их нет. Мы тоже были озадачены масштабом изменений при таких незначительных корректировках.



Обратная связь была не такой, какой мы ее ожидали по опыту первых попыток переговоров. Не было вопросов, на которые настроены обработчики возражений:



1. «Зачем нам этим заниматься?»

2. «Как организован прием платежей?»

3. «Сколько все это стоит?»



Если вопрос был, он был такой: «А будут платить?». Будут. Это уже дело техники. На данном этапе в дело шли уже все наши расчеты и презентации, которых мы за время работы подготовили не мало.



Так в чем же разница в нашем предложении до и после вышеуказанных изменений? На первый взгляд, разницы вообще никакой нет. Если проводить контент-анализ формулировок, можно заметить, что сделан значительный шаг к конкретизации предложения, а так же изменена терминология. Но по какой причине эти корректировки так влияют на результат? Далее идёт построение гипотез и всевозможная трансцендентная соционика, так что будьте готовы и критически воспринимайте данную информацию.



Дело в том, что мы как эксперты в области процессинга и приема платежей обладаем отличным от агентов понятийным аппаратом, так как работаем в другой сфере. Для нас госпошлины, налоги, штрафы — это, по сути, одни и те же операции с некоторыми частными оговорками, которые для краткости можно именовать «платежи в УФК». Данные операции обладают всеми свойствами «платежей в УФК» как макрообъекта, и этот макрообъект для нас легко угадывается, когда мы фиксируем свойства его отдельных представлений вроде «госпошлина» или «штраф». Соответственно, изначально мы перечисляли «налоги», «пошлины», «штрафы», тем самым желая сформировать в голове ЛПР ассоциацию с подобным «платежам в УФК» макрообъектом. А вот его то у них и не было, потому что для них указанные платежи не являются представителями «платежей в УФК». Могу догадываться, что для ЛПРа существуют иные ключевые сущности, например «Обязательные документы», представлением которого является «документ об оплате налога». Почему так? Очевидно, что человеческая психика склонна к абстрагированию, но делает она это для того, чтобы формировать образ реальности и протекающих в ней процессов. Так вот им важны процессы, связанные не с обработкой платежей и их характеристиками, а, допустим, процессы проверки важных документов на полноту, поэтому и абстракции другие.



Замена термина «налог» на термин «патент» выполняет аналогичную роль. Да, патент на работу иностранных граждан является налогом, вносимым по авансовой системе налогообложения. И в нашей формулировке никаких неточностей нет. Но для ЛПР все не так. Давайте углубимся в популярную психологию еще сильней, чтобы предположить, как изменение данного термина влияет на проходящие в мозгу ЛПР процессы.



Какова цель продажника, когда он обрабатывает ЛПР? Вызвать интерес. То есть, зарезервировать в психике ЛПРа необходимые ресурсы, которые готовы будут анализировать пользу от предлагаемых товара/услуги/переговоров. Какими бы ни были методики продаж, легко заметить, что их глобальная цель универсальна — вызвать ориентировочный рефлекс. Нередко это предлагается делать через узнавание. На это и направлены всевозможные «хвостатые» вопросы, вроде: «Вы же сталкивались с такими ситуациями, не так ли?». Даже если и не сталкивались, есть неплохой шанс вызвать ассоциативный ряд с теми вопросами, с которыми реально сталкивался ЛПР, пока он будет обрабатывать указанный. Зачем это нужно? Во-первых, вызвать возбуждение коры. Во-вторых, если ЛПР о чем-то в фоне размышляет, снизить влияние этих размышлений как доминанты на остальные мыслительные процессы или возбудить другие доминанты. В-третьих, пройти критическую проверку «свой-чужой», за счет демонстрации того, что продажник живет в той же проблемной реальности, что и ЛПР. Этих же целей достигает, кстати, и отсылка к знакомым лицам или рекомендации от них.



Что происходит в случае успеха? У ЛПР пробуждается ориентировочный рефлекс, формируется готовность к получению новой информации и, возможно, закрытию старых вопросов, которые были отложены «до поры». Он мобилизуется, говоря кратко. Как достигается эта реакция в теории? Массовым возбуждением «нужных» участков коры. Как это сделать? Обратиться к тем клеткам, которые имеют максимальное количество синаптических связей. Разумеется, связанных с профессиональной информацией. Вспомним, как формируются синаптические связи? При частом электрическом обмене аксонов/дендритов. Если грубо. И, возможно, меня смогут поправить более компетентные в данном вопросе теоретики, но в целом — механизм такой, теоретики мнемотехники не дадут соврать.



Итак, менеджеру нужно попадать в такие понятийные конструкции, которые вызовут максимально полный ассоциативный ряд и максимально долгое незадухание нервного возбуждения. Наша цель — понятия из сферы деятельности ЛПР с максимальными:



1. Точностью;

2. Частотой употребления;

3. Эмоциональной интенсивностью.



Если рассматривать изменение буквально нескольких слов в сценарии с позиции вышеуказанных механизмов, думаю, становится очевидным, почему эффект оказался таким заметным. Часто употребляемый термин, который ЛПР слышит ежедневно — не пошлина, не налог, а именно патент. Вот и весь «It's magic!»



Так же работает и изменение вопроса о сфере деятельности организации. Нужно попасть именно в тот термин, который ЛПР сам тиражирует. Да, он готовит документы, да он осуществляет консультации, но сам он называет это по-другому. Он «оформляет мигрантов». И возможно нам его макрообъект «Оформить мигрантов» ни о чем не скажет, как и ему наш макрообъект «Платежи в УФК», но мы то стремимся его кору возбудить, а не свою. Значит и общаться нужно на его языке.



Подведем итог: лицо, принимающее решение о том, стоит ли присоединяться к нашему проекту, мысленно находится в другой проблемной реальности, для него не существует национальной платежной системы и её представителей, его не интересует, как банки и операторы с поставщиками коммунальных услуг рассчитываются друг с другом. В бизнес-реальности такого партнера есть некоторые типовые вопросы, упоминания о которых вызывают у него когнитивные процессы, а упоминание о наших типовых вопросов вызывает у него скуку и «До свидания». По идее, ЛПР начинает выпытывать у вас полезную для него самого информацию и без наших SPINов или FABов. На данном этапе важно свободно этой информацией владеть.



Рассмотрим комментарий к моей предыдущей статье, который ссылается на текст на нашем сайте о невозможности Банка быть платежным агентом:



«Мы как банк подключись к одному из платежных агрегаторов, завели его на кассы, клиент-банк, на подходе банкоматы и где это мы не правы в юридическом плане?»



Типичный пример разницы в терминологии. Рассмотрим её в контексте данной статьи.



Оговорка: на данный момент платежные сервисы в РФ состоят из многих организаций. Не смотря на то, что 103ФЗ дает однозначную терминологию и методологию организации отношений в платежных сервисах, а так же задает функции Оператора по приему платежей (Платежного агента), в реальности такие сервисы работают так себе (читай — «их нет»). Обуславливается это массой законодательный ограничений и костылей, которые обходятся только при участии других компаний в расчетном взаимодействии. Причем, Банки выполняют логически те же функции, но на основании отдельного закона и с отдельной терминологией. При этом, банк обрабатывает «переводы без открытия счета», а платежный агент «платежи». Операции одни и те же, но кара постигает того, кто их путает в деловых переговорах. Дело в том, что банкам принимать наличные платежи закон запрещает прямо. А вот переводы — нет. А вот расчетные центры не могут быть Поставщиками, услуги которых оплачиваются «платежами», а вот Получателями, которым переводятся «переводы» — могут. Эти особенности мешают восприятию коммерческих предложений и бизнес-моделей, если терминология не подогнана под реалии ЛПР.



В данном случае комментирующий является представителем банковской сферы. Обратив внимание на указанный на сайте текст, он посчитал его не точным и, скорее всего, не профессиональным. Представьте, если бы такую же неточность допустил менеджер по продажам в предложении банку? Отказ.



Из таких мелочей и формируется представление о собеседнике как об эксперте. При соблюдении понятийного аппарата, при максимально точном предложении, ЛПР получает сигнал о том, что собеседник:



1. Относится к его бизнес-сообществу и имеет представление о реалиях и проблемах;

2. Является носителем полезной информации, которую можно получить немедленно и бесплатно;

3. Может обладать средствами влияния на неразрешимые им самим вопросы или необходимыми связями.



С того момента, когда у ЛПР появляется потребность в беседе, разговор можно планировать таким образом, чтобы полноценно презентовать свое предложение, так как «встреча», как называют этот процесс менеджеры по продажам, совершилась.



Но давайте вернемся к посредничеству. Отметив первые успехи нашего отдела продаж, мы озвучили результаты данного наблюдения партнерам-дистрибьюторам. Соответствующим образом скорректировав свое предложение, дистрибьютор так же смог преодолеть «мертвую точку» в процессе активного привлечения партнеров. Причем эффективность от такого привлечения превысила нашу собственную многократно, так как свой отдел продаж к тому времени мы не развивали, не видя заметного прогресса.



К чему это привело: стабильное поступление заявок на подключение переориентировало наш отдел продаж практически полностью на поддержание данного потока, а функции менеджеров трансформировал таким образом, что они стали выполнять, в основном, функции техподдержки. В то же время организация-дистрибьютор устойчиво закрепилась как наш стратегический партнер, поставляющий нам агентов и получателей платежей.



После такой специализации мы смогли уделить внимание тем аспектам нашего сервиса, которые откладывали «до лучших времен». Успех данных отношений позволил переориентировать стратегию развития на стимулирование именно посредников на работу с нашей организацией и практически отказаться от поиска агентов своими силами.



При этом, смысл жалеть процент, удерживаемый посредником, имеется в том случае, если рынок полностью занят, и рост сети сбыта замедлился. До этого момента посредник гарантирует рост прибыли и преимущество в экспансии рынка перед конкурентами. Тем более, процесс экспансии поддерживает сам себя.



Как я упоминал выше, на данный момент организаций — посредников на рынке банкинга и процессинга найти не просто даже при желании. Обычно они носят характер агрегаторов — сателлитов крупных процессинговых компаний, например банков. Предприятий, занимающихся привлечением агентов вообще найти практически не реально. По моей информации их не больше трех штук на всей территории России.



В чем же причины такой свободы на посредническом рынке? По моему мнению, подтверждаемому опытом компании, все дело в фундаментальной ошибке подхода при организации отдел продаж как такового. Неумение менеджеров отражать свою экспертность в коммерческом предложении приводит к неэффективности работы таких предприятий, которые специализируются на посреднических услугах, так как прибыль они получают только за результат работы. Тем временем, потребность рынка в таких услугах есть. Наш опыт показывает, что рост прибыли организации, которая использует услуги дистрибьютора гораздо выше, так как предложение, являющееся по большей части программным продуктом, не ограничено в количестве.



Кроме того, посредники могут себе позволить использовать разные понятийные системы. Отдел привлечения банков говорит как банк. Отдел подключения агентов — общается на языке агентов.



Если с организациями все понятно, то как быть с теми предприимчивыми лицами, которые ищут себя в сфере посреднических услуг в качестве индивидуальных предпринимателей? Как ни парадоксально это звучит, но их ниша мне видна еще более отчетливо, чем ниша специализированных компаний. Экономический кризис 2013 года привел к росту незанятых офисных работников, которые пытаются найти себя во многих спорных направлениях вроде удаленных работников одного всем известного интернет-банка или даже в качестве представителей MLM-сетей. Не секрет, что данная деятельность значительной прибыли не приносит, тем временем у представителей данного профессионального слоя есть все навыки для организации деятельности в качестве посредников на финансовом рынке, потому что их отличают:



1. Хорошие коммуникативные навыки;

2. Высокая стрессоустойчивость;

3. Вовлеченность в крупные сообщества, по которым быстро распространяется информация;

4. Ненормированный рабочий день.



Мы можем многое говорить о навязчивости представителей сетевого маркетинга и холодных «звонарей», предлагающих купить акции очередной «компании с положительным квартальным отчетом», но в чем нужно отдать им должное — обычно они умеют поддержать разговор. Что будет, если продукция, которую они предлагают, перестанет быть сахарно-крахмальными конфетами или разноцветными фантиками, и данные лица начнут предлагать инструменты, действительно востребованные в определенных сферах бизнеса? Лично я вижу в этом решение многих экономических и социальных проблем: одни получат реальную занятость по их интересам, другие — партнеров, третьи — средства дополнительного дохода. И все же фрилансеров или предпринимателей, выполняющих роль посредников на рынке платежей и процессинга так же практически не наблюдается.



Кроме маргинальности данного направления для сферы экономических отношений нашей страны, данный факт я могу соотнести только с неудачами в подобном направлении работы, которые останавливают потенциальных посредников. Возможно, для анализа данных неудач не хватает обратной связи от потребителя услуги.



В таком случае, я готов предоставить эту обратную связь от лица оператора по приему платежей, банковского платежного агента и платежного агрегатора. Начнем с самых основ. Что я как ЛПР компании, пользующейся услугами дистрибьютора, хотел бы видеть в качестве услуги:



1. Компенсация рисков. Посредник — на то и посредник, чтобы компенсировать риски встречных отношений партнеров на своем уровне. Документооборот должен быть защищен от потерь, встречные гарантии должны быть обеспечены высокой репутацией посредника, а все вопросы между партнерами должны контролироваться посредником вплоть до их успешного разрешения.

2. Регулярный рост партнерской сети. Посредник должен иметь убедительные механизмы привлечения партнеров. Чтобы банально не обанкротиться и не убить развивающуюся сеть непомерными тарифами за свои услуги.

3. Высокий экспертный уровень. Посредник должен разбираться в тематике сферы, в которой работают его клиенты, а не он. Он должен быстро понимать, о чем болит голова у партнера и предпринимать решительные меры по разрешению таких вопросов.

4. Наглядные, понятные и убедительные материалы. Да, посредник должен уметь излагать информацию в качестве текстовых и графических материалов и, если требуется, систематизировать опыт партнеров, формализуя терминологию и сводя все многообразие проблем его сферы к стандартным.

5. Обширная база контактов. Не лишним, а очень даже полезным будет наличие максимально полной базы контактов, полезных в выбранной сфере работы. А еще лучше — личное знакомство с ключевыми фигурами.



Я понимаю, что этот перечень достаточно массивен и способен многих отпугнуть, но посреднику на любом рынке, не только на рынке финансов, приходится продавать только два товара: информацию и репутацию. Скажу банальность, чтобы сгладить разочарование: сначала посредник работает на данные показатели, но потом — наоборот. Эти показатели можно и нужно наращивать постепенно.



Что является непосредственным предметом услуг посредника? Это всегда компенсация разрыва, в основном — терминологического. Если речь идет о переводчике, выполняющем, по сути функции языкового посредника, то и компенсация тут подразумевается языкового разрыва. Говоря терминологией, близкой к IT, посредник выполняет роль адаптера между двумя информационными системами. Таким образом, в нашем случае речь идет о посреднике как лице, понимающим потребности и проблемы потребителя товара и возможности и стандарты поставщика товара, где товаром являются юридические и программные средства организации обработки и приема платежей.



В помощь тем юридическим и физическим лицам, которые решат попробовать свои силы на ниве нелегкого труда дистрибьютора как посредника в подключении агентов или поставщиков услуг к платежному сервису, я позволю себе дать несколько советов:



1. Изучите язык ваших партнеров. Грамотное использование отраслевой терминологии позволяет наладит коммуникации за секунды, а так же избежать возражений о «Невозможности» какой-то работы. Помним пример с банками и агентами.

2. Изучите, как работает рынок платежей в том регионе, на который Вы нацелены. Какие организации являются монополистами, чьи процессинговые решения используют, какие банки доминируют, какие особенности на законодательном уровне препятствуют или способствуют развитию платежных сервисов и т. д.

3. Изучите актуальные для региона тарифы. Вы удивитесь, как свободно можно играть на их разнице, оставаясь в выгоде и гарантируя выгоду партнерам;

4. Подключайте связи. Нет ничего предосудительного в том, чтобы привлечь к работе компанию, если у Вас есть в ней знакомые.

5. Будьте экспертом в своей области. Это, пожалуй, самое главное.



Дистрибьютор, который понимает реальные нужды бизнеса, всегда найдет свою нишу. А понимать нужды бизнеса может только выходец из определенного бизнес-сообщества, либо специально подготовленный человек.



Очевидно, что подготовленные кадры с профильным образованием предметом данной статьи интересоваться не будут, поэтому акцент сделан именно на ту аудиторию, которая не является участником бизнес-сообщества, но желает таковым стать.



Ссылка на первую статью: habrahabr.ru/post/325696

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/325858/

Комментарии (0)КомментироватьВ цитатник или сообщество

Следующие 30  »

<платежные системы - Самое интересное в блогах

Страницы: [1] 2 3 ..
.. 10

LiveInternet.Ru Ссылки: на главную|почта|знакомства|одноклассники|фото|открытки|тесты|чат
О проекте: помощь|контакты|разместить рекламу|версия для pda