# Sberbank::Acquiring

[![Build Status](https://travis-ci.org/panasyuk/sberbank-acquiring.svg?branch=master)](https://travis-ci.org/panasyuk/sberbank-acquiring)

## Описание

GEM sberbank-acquiring предоставляет функциональность для взаимодействия с API эквайринга банка Сбербанк. Он использует RESTful API эквайринга Сбербанка.

Перед тем, как приступить к использованию этого гема, автор настоятельно рекомендует (хотя бы бегло) ознакомиться с официальной [документацией к JSON API эквайринга Сбербанка](https://securepayments.sberbank.ru/wiki/doku.php/integration:api:start), а так же [Wiki](https://github.com/panasyuk/sberbank-acquiring/wiki), кому интересно

## Установка

```ruby
# Gemfile
gem 'sberbank-acquiring', github: 'panasyuk/sberbank-acquiring'
```

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

### SBRF::Acquiring::Client

```ruby
# client отправляет запросы на боевой сервер эквайринга
client = SBRF::Acquiring::Client.new(username: 'username', password: 'password')

# test_client отправляет запросы на тестовый сервер эквайринга
test_client = SBRF::Acquiring::Client.new(token: 'token', test: true)
```

Клиент может выполнять следующие вызовы к API:

| Название метода                  | Путь API                                |
| -------------------------------- | --------------------------------------- |
| deposit                          | /payment/rest/deposit.do                |
| get_order_status_extended        | /payment/rest/getOrderStatusExtended.do |
| payment                          | /payment/rest/payment.do                |
| payment_sber_pay                 | /payment/rest/paymentSberPay.do         |
| refund                           | /payment/rest/refund.do                 |
| register                         | /payment/rest/register.do               |
| register_pre_auth                | /payment/rest/registerPreAuth.do        |
| reverse                          | /payment/rest/reverse.do                |
| verify_enrollment                | /payment/rest/verifyEnrollment.do       |

Все методы ожидают в качестве агрумента `Hash`, с ключами в **underscore**.
При подготовке параметров к отправке, эта структура претерпит следующие изменения:

1. Все ключи рекурсивно будут сконвертированы в **camelCase**
2. Все значения класса `Hash` будут переданы в виде JSON

Например этот код:

```ruby
client.register(
  amount: 1000,
  order_number: 'order#1',
  return_url: 'https://example.com/sberbank/success',
  json_params: { user_email: 'test@example.com' }
)
```

сначала приведет параметры к следующему виду:

```ruby
{
  'amount' => 1000,
  'orderNumber' => 'order#1',
  'returnUrl' => 'https://example.com/sberbank/success',
  'jsonParams' => '{"userEmail":"test@example.com"}'
}
```

a затем превратит их в параметры запроса:
`amount=1000&orderNumber=order%231&returnUrl=https%3A%2F%2Fexample.com%2Fsberbank%2Fsuccess&jsonParams=%7B%22userEmail%22%3A%22test%40example.com%22%7D`

#### Создание заказа на 10 рублей

```ruby
response = client.register(
  amount: 1000, # в самых мелких долях валюты
  order_number: 'order#1',
  return_url: 'https://example.com/sberbank/success'
)
```

```ruby
response.success? # => true
response.error?   # => false

response.data # => { "orderId" => "f3ced54d-45df-7c1a-f3ce-d54d04b11830", "formUrl" => "https://3dsec.sberbank.ru/payment/merchants/sbersafe/payment_ru.html?mdOrder=f3ced54d-45df-7c1a-f3ce-d54d04b11830" }

response.order_id # => "f3ced54d-45df-7c1a-f3ce-d54d04b11830"
response.form_url # => "https://3dsec.sberbank.ru/payment/merchants/sbersafe/payment_ru.html?mdOrder=f3ced54d-45df-7c1a-f3ce-d54d04b11830"

```

#### Проверка состояния заказа
```ruby
response = client.get_order_status_extended(order_id: 'f3ced54d-45df-7c1a-f3ce-d54d04b11830')
```
или

```ruby
response = client.get_order_status_extended(order_number: 'order#1')
```

```ruby
response.data # =>
# {
#   "errorCode" => "0",
#   "errorMessage" => "Успешно",
#   "orderNumber" => "order#2",
#   "orderStatus" => 0,
#   "actionCode" => -100,
#   "actionCodeDescription" => "",
#   "amount" => 1000,
#   "currency" => "643",
#   "date" => 1531643056391,
#   "merchantOrderParams" => [],
#   "attributes" => [{ "name" => "mdOrder", "value" => "aefeb658-48fb-7f37-aefe-b65804b11830" }],
#   "terminalId" => "123456",
#   "paymentAmountInfo" => { "paymentState" => "CREATED", "approvedAmount" => 0, "depositedAmount" => 0,  "refundedAmount" => 0},
#   "bankInfo" => { "bankCountryCode" => "UNKNOWN", "bankCountryName" => "<Неизвестно>" }
# }

response.attributes # => [{ "name" => "mdOrder", "value" => "aefeb658-48fb-7f37-aefe-b65804b11830" }]
response.bank_info # => { "bankCountryCode" => "UNKNOWN", "bankCountryName" => "<Неизвестно>" }
```

Запрос состояния заказа с результатом на английском языке:
```ruby
response = client.get_order_status_extended(language: 'en', order_number: 'order#1')
```

```ruby
response.data # =>
# {
#   "errorCode" => "0",
#   "errorMessage" => "Success",
#   "orderNumber" => "order#2",
#   "orderStatus" => 0,
#   "actionCode" => -100,
#   "actionCodeDescription" => "",
#   "amount" => 1000,
#   "currency" => "643",
#   "date" => 1531643056391,
#   "merchantOrderParams" => [],
#   "attributes" => [{ "name" => "mdOrder", "value" => "aefeb658-48fb-7f37-aefe-b65804b11830" }],
#   "terminalId" => "123456",
#   "paymentAmountInfo" => { "paymentState" => "CREATED", "approvedAmount" => 0, "depositedAmount" => 0, "refundedAmount" => 0},
#   "bankInfo" => { "bankCountryCode" => "UNKNOWN", "bankCountryName" => "<Unknown>" }
# }

response.terminal_id # => "123456"
```

### Проверка контрольной суммы callback-уведомлений

API эквайринга Сбербанка поддерживает два вида callback-уведомлений: без контрольной суммы и с контрольной суммой.
В случае обработки уведомления с контрольной суммой, алгоритм проверки включает в себя выполнение запроса 'getOrderStatusExtended' к API эквайринга для проверки действительного статуса платежа. В остальных случаях требуется проверка параметра `checksum` с использованием симметричного или асимметричного ключа.

#### Симметричный ключ

```ruby
# params = {}
symmetric_key = '20546026a3675994185a132875efe41a'

callback_params = params.dup
checksum = callback_params.delete('checksum')

validator = Sberbank::Acquiring::SymmetricKeyChecksumValidator.new(symmetric_key)
if validator.validate(checksum, callback_params)
  # запрос успешно прошел валидацию, контрольная сумма верна
else
  # запрос не может быть обработан, так как контрольная сумма неверна
end
```

## Разработка

После клонирования репозитория, выполните `bin/setup` чтобы установить зависимости. Затем выполните `rake test`, чтобы запустить тесты. Так же можно запустить интерактивную консоль для экспериментов, выполнив `bin/console`.

## TODO

1. Добавить проверку Callback-уведомлений для асимметричного ключа
2. v0.1.0
3. Добавить API для того чтобы сделать удобнее отправку заказов по ФФД 1.05. Примерный API:
```ruby
sberbank_order = SBRF::Acquiring::Order.new(
  number: 'order#1',
  amount: 1,
  amount_cents: 100,
  return_url: 'https://',
  fail_url: 'https://',
  params: { email: 'email@example.com' },
  tax_system: SBRF::USN_INCOME
)

item =
  SBRF::Acquiring::Item.new(
  name: 'item#1',
  quantity: 2,
  measure: 'pcs',
  price: 1,
  code: 'item#1',
  tax: SBRF::VAT0)

item.tax = SBRF::VAT18

item.to_h #=> { name: '', quantity: 2. ... amount: 200, tax: { tax_type: 3, tax_sum: 36 } }

sberbank_order.items << item
```

## Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/panasyuk/sberbank-acquiring.

## License

The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).