Skip to content

Ruby client for orangedata.ru API, includes certificate generation

License

Notifications You must be signed in to change notification settings

Vasfed/orangedata

Repository files navigation

Orangedata Client

Gem Version Gem downloads Build Status

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:

gem 'orangedata'

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

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

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

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

Описание полей смотреть в официальной документации, названия маппинга и некоторые комментарии есть в схеме данных (метасхема расширений тут).

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

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

  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 ответила, что все ок, так и должно быть. Скорее всего непонятки с номерами налогов приехали еще из налоговой, т.к. номера тегов тут идут подряд.

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

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.

В ЛК в разделе интеграций запрашиваем сертификат (шаг 3, первый шаг не нужен, а данные для второго получатся ниже), распаковываем полученный zip-архив и натравливаем туда генератор:

  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
  # "<RSAKeyValue>...</Exponent></RSAKeyValue>"

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

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

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

  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':

  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.

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. Copyright (c) 2018 Vasily Fedoseyev

About

Ruby client for orangedata.ru API, includes certificate generation

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published