Giter VIP home page Giter VIP logo

atol-rb's Introduction

ruby-logo atol-logo

Gem Version BuildStatus Maintainability Coverage Status

atol-rb

Пакет содержит набор классов для работы с KaaS-сервисом АТОЛ-онлайн по описанному протоколу.

Совместимость

Для корректной работы необходим интерпретатор Руби версии 2.5. Пакет работает с версией протокола v4.

Использование

Установка пакета

Необходимо добавить в Gemfile проекта строку:

gem 'atol'

И запустить команду:

$ bundle install

Конфигурация

Для обращения к сервису необходимы данные учетной записи.

При инициализации приложение попытается найти необходимые параметры в константе ENV.

Для корректной работы потребуются следующие переменные окружения.

Все переменные являются обязательными.

# .env
ATOL_INN=123456789010
ATOL_LOGIN=example-login
ATOL_PASSWORD=example-password
ATOL_PAYMENT_ADDRESS="г. Москва, ул. Ленина, д.1 к.2"
ATOL_GROUP_CODE=example-group-code
ATOL_DEFAULT_SNO=esn
ATOL_DEFAULT_TAX=vat18
ATOL_CALLBACK_URL=https://www.example.com/callback_path
[email protected]
ATOL_DEFAULT_PAYMENT_TYPE=1

Значения ATOL_INN, ATOL_LOGIN, ATOL_PASSWORD, ATOL_PAYMENT_ADDRESS и ATOL_GROUP_CODE вы получаете при регистрации в сервисе.

ATOL_DEFAULT_SNO - система налогообложения. Возможные значения:

  1. "osn" – общая СН;
  2. "usn_income" – упрощенная СН (доходы);
  3. "usn_income_outcome" – упрощенная СН (доходы минус расходы);
  4. "envd" – единый налог на вмененный доход;
  5. "esn" – единый сельскохозяйственный налог;
  6. "patent" – патентная СН.

ATOL_DEFAULT_TAX - номер налога в ККТ. Возможные значения:

  1. "none" – без НДС;
  2. "vat0" – НДС по ставке 0%;
  3. "vat10" – НДС чека по ставке 10%;
  4. "vat18" – НДС чека по ставке 18%;
  5. "vat110" – НДС чека по расчетной ставке 10/110;
  6. "vat118" – НДС чека по расчетной ставке 18/118.

ATOL_CALLBACK_URL - адрес, по которому сервис будет отправлять информацию после создания чека.

ATOL_DEFAULT_PAYMENT_TYPE - вид оплаты. Возможные значения:

  1. "1" – электронный;
  2. "2" – "9" – расширенные типы оплаты. Для каждого фискального типа оплаты можно указать расширенный тип оплаты.

ATOL_COMPANY_EMAIL - адрес электронной почты вашей компании.

Конфигурация в инициализаторе

Для Rails-приложений так же можно создать файл инициализации и задать параметры непосредственно в коде:

# config/initializers/atol.rb

Rails.application.config.after_initialize do
  Atol.config.tap do |config|
    config.inn                  = '123456789010'
    config.login                = 'example-login'
    config.password             = 'example-password'
    config.payment_address      = 'г. Москва, ул. Ленина, д.1 к.2'
    config.group_code           = 'example-group-code'
    config.default_sno          = 'esn'
    config.default_tax          = 'vat18'
    config.callback_url         = 'https://www.example.com/callback_path'
    config.company_email        = '[email protected]'
    config.default_payment_type = '1'
  end
end

Для объектов конфигурации используется класс унаследованный от класса из гема anyway-config. Другие способы задания конфигурации можно найти в его документации.

Использование тестового окружения АТОЛ

АТОЛ предоставляет тестовую среду для отработки интеграции. Данные для авторизации в тестовой среде можно найти в библиотеке документации АТОЛ Онлайн, пункт "Параметры тестовой среды"

URL тестовой среды необходимо указывать в конфигурации. При использовании переменных окружения вам необходимо задать переменную ATOL_API_URL.

# .env
ATOL_API_URL=https://testonline.atol.ru/possystem/v4

Внимание! При создании чеков в тестовой среде АТОЛ будет отправлять письма на электронную почту покупателя.

Прокси

Объект конфигурации позволяет задать прокси для http-запросов:

  uri = URI('http://example-proxy.com')
  proxy = Net::HTTP.Proxy(uri.host, uri.port)
  Atol.config.http_client = proxy

Получение токена

Для создания документа в системе АТОЛ необходимо получить токен авторизации. Вот как это можно сделать:

token = Atol::Transaction::GetToken.new.call
# => 'example-token-string'

Токен можно будет использовать в течение 24 часов после первого запроса.

Сервис АТОЛ не предоставляет информации о сроке жизни токена, поэтому механизм его кеширования полностью зависит от приложения.

Регистрация документа

Создание тела запроса

Тело запроса должно соответствовать схеме. Для упрощения кода создан класс Atol::Request::PostDocument::Sell::Body.

Конструктор в качестве обязательных аргументов принимает external_id, один из аргументов phone или email и items.

body = Atol::Request::PostDocument::Sell::Body.new(
  external_id: 123,
  email: '[email protected]',
  items: [
    ...
  ],
  agent_info_type: 'bank_paying_agent'
).to_json

agent_info_type опциональный аргумент - признак агента (тег ФФД - 1057)

Массив items должен включать в себя объекты, которые так же соответствуют схеме.

Для создания items можно использовать класс Atol::Request::PostDocument::Item::Body.

Его конструктор принимает обязательные аргументы name, price, payment_method, payment_object и опциональные quantity (по умолчанию 1), supplier_info_inn, supplier_info_name, agent_info_type (тег ФФД - 1222).

supplier_info_inn обязателен, если передан agent_info_type.

Допустимые значения payment_method:

[
  'full_prepayment', 'prepayment', 'advance', 'full_payment',
  'partial_payment', 'credit', 'credit_payment'
]

Допустимые значения payment_object:

[
  'commodity', 'excise', 'job', 'service', 'gambling_bet', 'gambling_prize',
  'lottery', 'lottery_prize', 'intellectual_activity', 'payment','agent_commission',
  'composite', 'another'
]

Например:

item = Atol::Request::PostDocument::Item::Body.new(
  name: 'product name',
  price: 100,
  payment_method: 'full_payment',
  payment_object: 'service',
  quantity: 2
).to_h

Тогда создание всего тела запроса будет выглядеть так:

body = Atol::Request::PostDocument::Sell::Body.new(
  external_id: 123,
  email: '[email protected]',
  items: [
    Atol::Request::PostDocument::Item::Body.new(
      name: 'number 9',
      price: 50,
      payment_method: 'full_payment',
      payment_object: 'service',
      quantity: 2
    ).to_h,
    Atol::Request::PostDocument::Item::Body.new(
      name: 'number 9 large',
      price: 100,
      payment_method: 'full_payment',
      payment_object: 'service'
    ).to_h,
    Atol::Request::PostDocument::Item::Body.new(
      name: 'number 6',
      price: 60,
      payment_method: 'full_payment',
      payment_object: 'service'
    ).to_h
  ]
).to_json

Результат:

{
  "receipt":{
    "attributes":{
      "sno":"usn_income_outcome",
      "email":"[email protected]"
    },
    "items":[
      {
        "name":"number 9",
        "price":50.0,
        "quantity":2.0,
        "sum":100.0,
        "tax":"none"
      },
      {
        "name":"number 9 large",
        "price":100.0,
        "quantity":1.0,
        "sum":100.0,
        "tax":"none"
      },
      {
        "name":"number 6",
        "price":60.0,
        "quantity":1.0,
        "sum":60.0,
        "tax":"none"
      }
    ],
    "payments":[
      {
        "sum":260.0,
        "type":1
      }
    ],
    "total":260.0
  },
  "service":{
    "inn":"123456789010",
    "payment_address":"г. Москва, ул. Ленина, д.1 к.2"
  },
  "timestamp":"06.02.2018 12:35:00",
  "external_id":123
}

Отправка документа

Когда токен и тело запроса составлены, остается только сделать post-запрос.

Для этого используем класс Atol::Transaction::PostDocument, принимающий название операции, токен и тело запроса:

Atol::Transaction::PostDocument.new(
  operation: :sell,
  token: token,
  body: body
).call

Объект возьмет на себя составление URL, добавит необходимые параметры из конфигурации, отправит запрос и вернет объект http-ответа.

В случае возникновения ошибок он вернет исключение специальных классов.

Для логгирования конструктор принимает необязательные аргументы req_logger и res_logger.

Этими аргументами должны быть объекты, отвечающие на #call и принимающие один аргумент, объект запроса или ответа:

Atol::Transaction::PostDocument.new(
  operation: :sell,
  token: token,
  body: body,
  req_logger: lambda { |req| puts req.body },
  res_logger: lambda { |res| puts res.body }
).call

Коллбэк регистрации документа

После отправки документа в обработку сервер АТОЛ отправит запрос с состоянием обработки документа на URL, указанный в запросе.

Atol::Request::PostDocument::Sell::Body добавить в тело URL, если он будет указан в конфигурации.

На примере Rails-приложения динамический параметр может быть добавлен при инициализации сервера:

# config/initializers/atol.rb

Rails.application.config.after_initialize do
  Atol.config.callback_url = Rails.application.routes.url_helpers.atol_callback_url
end

Запрос статуса документа

Если в течение 300 секунд не поступил запрос с состоянием документа, то необходимо запросить его через get-запрос.

Для этого можно воспользоваться классом Atol::Transaction::GetDocumentState, достаточно передать ему токен и uuid документа:

response = Atol::Transaction::GetDocumentState.new(token: token, uuid: uuid).call

atol-rb's People

Contributors

dependabot[bot] avatar eiririna avatar georgegorbanev avatar inner-whisper avatar manelyset avatar pserg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

atol-rb's Issues

Обновить названия эксепшнов в соответствии с документацией API v4

При тестировании интеграции с АТОЛ с помощью данного gem-а заметил следующую особенность:

  • При попытке запросить документ с просроченным токеном мне возвращается эксепшн Atol::StateBadRequestError ({"error":{"code":11,"error_id":"adec8ba2-6ec3-4163-bf1f-f0a663a9da56","text":"Переданный токен не активен","type":"system"},"timestamp":"24.04.2020 13:23:55"})
  • При попытке запросить документ с неправильным токеном мне возвращается эксепшн Atol::IncomingExistExternalIdError ({"error":{"code":10,"error_id":"4bd55993-f094-4ea9-ae06-60dcf3bacfc7","text":"Не распознан токен запроса","type":"system"},"timestamp":"24.04.2020 13:24:48"})

Если посмотреть в документацию https://online.atol.ru/files/API_atol_online_v4.pdf в таблицу 6 на странице 60, то можно увидеть, что передаваемым кодам ошибок (поле code в json с ошибкой) есть соответствующие человекопонятные названия:

Ошибка Код ошибки
MissingToken 10
ExpiredToken 11

Мне данные названия кажутся более понятными и соответствующими сути происходящих ошибок.

Предлагаю названия всех эксепшнов в

ERRORS = Hash[
1 => BadJSONError,
2 => IncomingBadRequestError,
3 => IncomingOperationNotSupportError,
4 => IncomingMissingTokenError,
5 => IncomingNotExistTokenError,
6 => IncomingExpiredTokenError,
7 => IncomingQueueTimeoutError,
8 => IncomingValidationError,
9 => IncomingQueueError,
10 => IncomingExistExternalIdError,
11 => StateBadRequestError,
12 => StateMissingTokenError,
13 => StateNotExistTokenError,
14 => StateExpiredTokenError,
15 => StateMissingUuidError,
16 => StateNotFoundError,
22 => GroupCodeToTokenError,
23 => IsNullExternalIdError,
-3804 => ZeroItemQuantityError
].freeze
заменить на сформированные от названий в документации (название ошибки в документации + добавление Error в конце названия эксепшна).

Т.е. для моего примера это было бы в следующем виде:

  • При попытке запросить документ с просроченным токеном мне бы вернулся эксепшн Atol::ExpiredTokenError ({"error":{"code":11,"error_id":"adec8ba2-6ec3-4163-bf1f-f0a663a9da56","text":"Переданный токен не активен","type":"system"},"timestamp":"24.04.2020 13:23:55"})
  • При попытке запросить документ с неправильным токеном мне бы вернулся эксепшн Atol::MissingTokenError ({"error":{"code":10,"error_id":"4bd55993-f094-4ea9-ae06-60dcf3bacfc7","text":"Не распознан токен запроса","type":"system"},"timestamp":"24.04.2020 13:24:48"})

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.