Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/vasfed/orangedata

Ruby client for orangedata.ru API, includes certificate generation
https://github.com/vasfed/orangedata

api client orangedata ruby

Last synced: 7 days ago
JSON representation

Ruby client for orangedata.ru API, includes certificate generation

Awesome Lists containing this project

README

        

# Orangedata Client

[![Gem Version](https://badge.fury.io/rb/orangedata.svg)](https://badge.fury.io/rb/orangedata)
![Gem downloads](https://img.shields.io/gem/dt/orangedata.svg)
![Build Status](https://github.com/Vasfed/orangedata/actions/workflows/test.yml/badge.svg?branch=master)

A ruby client for orangedata.ru service.
Target service is pretty local to RU, so parts of readme will be in russian.

Ruby-клиент для сервиса онлайн-касс OrangeData

Умеет:
- собственно транспорт с подписью запросов
- сгенерировать ключ сразу в нужном виде
- маппинг для данных генерируется на базе приведенного в человеческий вид официального json-schema-описания

В планах получше подружить с рельсами.

На всякий случай disclaimer: API еще не полностью устоялось и возможно будет обновляться по мере обкатки.

## Установка

Все стандартно - `bundle add orangedata`, либо по-старике пишем в Gemfile:

```ruby
gem 'orangedata'
```

и давим `bundle`. Совсем руками можно `gem install orangedata`

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

Для тестового окружения ключики в комплекте - [credentials_test.yml](lib/orange_data/credentials_test.yml), собрано из родного `File_for_test.zip`, доступны как `OrangeData::Credentials.default_test`.
Получение ключей для продакшна описано ниже.

### Пробитие чека

Описание полей смотреть в [официальной документации](https://github.com/orangedata-official/API), названия маппинга и некоторые комментарии есть [в схеме данных](lib/orange_data/schema_definitions.yml) (метасхема расширений [тут](spec/lib/extensions_metaschema.yml)).

Для `enum`-полей есть маппинг, например `content.positions[0].tax` принимает значения: `:vat_20`, `:vat_10`, `:vat_20_120`, `:vat_10_110`, `:vat_0`, `:vat_not_charged`.

Простейший чек в тестовом окружении:

```ruby
transport = OrangeData::Transport.new("https://apip.orangedata.ru:2443/api/v2/", OrangeData::Credentials.default_test)
receipt = OrangeData::Receipt.income(inn:"1234567890"){|r|
r.customer = "Иван Иваныч"
r.add_position("Спички", price: 12.34){|pos| pos.tax = :vat_not_charged }
r.add_payment(50, :cash)
}
transport.post_document(receipt)
# wait some time
res = transport.get_document(receipt.inn, receipt.id)

# => (внутри такое, а вернет объект)
# {
# "id"=>"50152258-a9aa-4d19-9216-5a3eecec7241",
# "deviceSN"=>"1400000000001033",
# "deviceRN"=>"0000000400054952",
# "fsNumber"=>"9999078900001341",
# "ofdName"=>"ООО \"Ярус\" (\"ОФД-Я\")",
# "ofdWebsite"=>"www.ofd-ya.ru",
# "ofdinn"=>"7728699517",
# "fnsWebsite"=>"www.nalog.ru",
# "companyINN"=>"1234567890",
# "companyName"=>"Тест",
# "documentNumber"=>3243,
# "shiftNumber"=>234,
# "documentIndex"=>7062, "processedAt"=>"2018-10-26T20:21:00",
# "content"=>{
# "type"=>1,
# "positions"=>[{"price"=>12.34, "tax"=>6, "text"=>"Спички"}],
# "checkClose"=>{"payments"=>[{"type"=>1, "amount"=>50.0}], "taxationSystem"=>0},
# "customer"=>"Иван Иваныч"
# },
# "change"=>37.66,
# "fp"=>"301645583"
# }

res.device_sn
# => "1400000000001033"

# и даже так:
res.qr_code_content
# => "t=20181026T2021&s=50.0&fn=9999078900001341&i=3243&fp=301645583&n=1"
```

### Чек коррекции
Осторожно: в API не все значения поля `tax` соответствуют цифрам в `taxNSum`, поддержка OD ответила, что все ок, так и должно быть. Скорее всего непонятки с номерами налогов приехали еще из налоговой, т.к. номера тегов тут идут подряд.

Поэтому в маппинге есть алиасы:

```ruby
transport = OrangeData::Transport.new("https://apip.orangedata.ru:2443/api/v2/", OrangeData::Credentials.default_test)
correction = OrangeData::Correction.income(inn:"123456789012", id:"12345678990"){|c|
c.correction_type = :prescribed
c.assign_attributes(
description: "НЕ ХОЧЕТСЯ НО НАДО",
cause_document_date: "2017-08-10T00:00:00", cause_document_number: "ФЗ-54",
total_sum: 17.25,
sum_cash: 1.23, sum_card: 2.34,
sum_prepaid: 5.67, sum_credit: 4.56, sum_counterclaim: 3.45,

vat_20: 1.34, vat_10: 2.34, vat_0: 3.34,
vat_not_charged: 4.34, vat_20_120: 5.34, vat_10_110: 6.34,
taxation_system: :simplified,

automat_number: "123456789",
settlement_address: "г.Москва, Красная площадь, д.1",
settlement_place: "Палата No6",
)
}
transport.post_correction(correction)
# wait some time
res = transport.get_correction(correction.inn, correction.id)
```

### Получаем сертификаты

Предполагается, что всякие договоры и прочая фискализация уже успешно пройдена и у вас есть доступ
к ЛК orangedata.

В [ЛК в разделе интеграций](https://lk.orangedata.ru/lk/integrations/direct) запрашиваем сертификат (шаг 3, первый шаг не нужен, а данные для второго получатся ниже), распаковываем полученный zip-архив и натравливаем туда генератор:

```ruby
c = OrangeData::Credentials.read_certs_from_pack('~/Downloads/1234567890', title:'My production', cert_key_pass:'1234') # cert_key_pass берем из readme_v2.txt, но есть подозрение что он у всех 1234
File.open("my_production.yml", "wt"){|f| f.write c.to_yaml }
c.signature_public_xml
# "..."

# опционально на маке копируем публичный ключ в буфер обмена:
system("echo '#{c.signature_public_xml}' | pbcopy")
```

Если все прошло гладко - теперь у вас есть файлик `my_production.yml` со всеми реквизитами доступа к продакшн-кассе. Обращаться с ним стоит как и с любой другой очень чувствительной информацией, например не стоит коммитить его (ну или как минимум, убрать из него поля `signature_key_pass` и `certificate_key_pass` и хранить отдельно)

Дальше публичный ключ с предыдущего шага отправляется в ЛК, там его сохраняем, "подключаем интеграцию", и пользуемся:

```ruby
transport = OrangeData::Transport.new(OrangeData::Transport::DEFAULT_PRODUCTION_API_URL, OrangeData::Credentials.from_hash(YAML.load_file('my_production.yml')))
transport.post_document # и далее по тексту, осторожно - не пробейте лишние чеки во время проверок
```

Еще есть `OrangeData::Credentials.read_certs_from_zip_pack`, куда можно скормить нераспакованный файлик, если у вас есть `gem 'rubyzip'`:

```ruby
c = Zip::File.open("cert_123.zip") do |zip_file|
OrangeData::Credentials.read_certs_from_zip_pack(zip_file, cert_key_pass:'1234')
end
```

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

After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).

## Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/Vasfed/orangedata.

## License

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