# πŸ’³ Sberbank::Acquiring

[![Gem Version](https://badge.fury.io/rb/sberbank-acquiring.svg)](https://badge.fury.io/rb/sberbank-acquiring)
[![Build Status](https://travis-ci.org/panasyuk/sberbank-acquiring.svg?branch=master)](https://travis-ci.org/panasyuk/sberbank-acquiring)

πŸ”»Ruby Version 2.1 - 2.6 (+ JRuby)
πŸŽˆΠΠΈΠΊΠ°ΠΊΠΈΡ… сторонних зависимостСй

## Основная Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ
- Π’Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ всСх запросов ΠΊ API эквайринга Π‘Π±Π΅Ρ€Π±Π°Π½ΠΊΠ° согласно Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ (созданиС Π·Π°ΠΊΠ°Π·ΠΎΠ², ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° ΠΈΡ… статуса ΠΈ Ρ‚.Π΄)
- Π’Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Π»ΡŽΠ±Ρ‹Ρ… запросов ΠΊ API эквайринга Π‘Π±Π΅Ρ€Π±Π°Π½ΠΊΠ°
- ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»ΡŒΠ½ΠΎΠΉ суммы callback-ΡƒΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΠΉ с симмСтричной ΠΈ асиммСтричной ΠΊΡ€ΠΈΠΏΡ‚ΠΎΠ³Ρ€Π°Ρ„ΠΈΠ΅ΠΉ

**Π’ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ΅:**
- ΠŸΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠ° Π€Π€Π” 1.05

## ОписаниС

GEM sberbank-acquiring прСдоставляСт Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ для взаимодСйствия с API эквайринга Π±Π°Π½ΠΊΠ° Π‘Π±Π΅Ρ€Π±Π°Π½ΠΊ. Он ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ RESTful API эквайринга Π‘Π±Π΅Ρ€Π±Π°Π½ΠΊΠ°.

ΠŸΠ΅Ρ€Π΅Π΄ Ρ‚Π΅ΠΌ, ΠΊΠ°ΠΊ ΠΏΡ€ΠΈΡΡ‚ΡƒΠΏΠΈΡ‚ΡŒ ΠΊ использованию этого Π³Π΅ΠΌΠ°, Π°Π²Ρ‚ΠΎΡ€ Π½Π°ΡΡ‚ΠΎΡΡ‚Π΅Π»ΡŒΠ½ΠΎ Ρ€Π΅ΠΊΠΎΠΌΠ΅Π½Π΄ΡƒΠ΅Ρ‚ (хотя Π±Ρ‹ Π±Π΅Π³Π»ΠΎ) ΠΎΠ·Π½Π°ΠΊΠΎΠΌΠΈΡ‚ΡŒΡΡ с ΠΎΡ„ΠΈΡ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠΉ [Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠ΅ΠΉ ΠΊ JSON API эквайринга Π‘Π±Π΅Ρ€Π±Π°Π½ΠΊΠ°](https://securepayments.sberbank.ru/wiki/doku.php/integration:api:start#%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D1%84%D0%B5%D0%B9%D1%81_rest), Π° Ρ‚Π°ΠΊ ΠΆΠ΅ [Wiki](https://github.com/panasyuk/sberbank-acquiring/wiki), ΠΊΠΎΠΌΡƒ интСрСсно

## Установка

```ruby
# Gemfile
gem 'sberbank-acquiring', github: 'panasyuk/sberbank-acquiring'
# ΠΈΠ»ΠΈ
gem 'sberbank-acquiring', '~> 0.2.1'
```

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

### 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` с использованиСм [симмСтричной ΠΈΠ»ΠΈ асиммСтричной ΠΊΡ€ΠΈΠΏΡ‚ΠΎΠ³Ρ€Π°Ρ„ΠΈΠΈ](https://securepayments.sberbank.ru/wiki/doku.php/integration:api:callback:start).

#### БиммСтричная криптография

```ruby
# params = { 'checksum' => '...', ... }
key = '20546026a3675994185a132875efe41a'

validator = Sberbank::Acquiring::SymmetricKeyChecksumValidator.new(key)
if validator.valid?(params)
  # запрос ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΠΏΡ€ΠΎΡˆΠ΅Π» Π²Π°Π»ΠΈΠ΄Π°Ρ†ΠΈΡŽ, ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»ΡŒΠ½Π°Ρ сумма Π²Π΅Ρ€Π½Π°
else
  # запрос Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Π½, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»ΡŒΠ½Π°Ρ сумма Π½Π΅Π²Π΅Ρ€Π½Π°
end
```

#### АсиммСтричная криптография

```ruby
# params = { 'checksum' => '...', ... }
pem = File.read('< ΠΏΡƒΡ‚ΡŒ Π΄ΠΎ Ρ„Π°ΠΉΠ»Π° сСртификата >')

validator = Sberbank::Acquiring::AsymmetricKeyChecksumValidator.new(pem)
if validator.valid?(params)
  # запрос ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΠΏΡ€ΠΎΡˆΠ΅Π» Π²Π°Π»ΠΈΠ΄Π°Ρ†ΠΈΡŽ, ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»ΡŒΠ½Π°Ρ сумма Π²Π΅Ρ€Π½Π°
else
  # запрос Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Π½, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»ΡŒΠ½Π°Ρ сумма Π½Π΅Π²Π΅Ρ€Π½Π°
end
```

## Π Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ°

- ПослС клонирования рСпозитория, Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚Π΅ `bin/setup` Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ зависимости.
- Π—Π°Ρ‚Π΅ΠΌ Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚Π΅ `rake test`, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ тСсты.
- Π’Π°ΠΊ ΠΆΠ΅ ΠΌΠΎΠΆΠ½ΠΎ Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½ΡƒΡŽ консоль для экспСримСнтов, Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΠ² `bin/console`.

## TODO

1. Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ 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).