#qr #bank #gost #no-std

no-std gost-56042

Library for working with Russian Standard GOST-56042

1 unstable release

0.1.0 Sep 26, 2024

#5 in #bank

MIT license

69KB
1K SLoC

ГОСТ-56042

Библиотека для работы с "ГОСТ Р 56042-2014 Стандарты финансовых операций. Двумерные символы штрихового кода для осуществления платежей физических лиц".

Обзор

Официальный документ на русском языке можно скачать с сайта or или напрямую.

Кодирование

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

  • to_bytes(&self) -> super::Result<Vec<u8>> - преобразование структуры в массив байтов.
  • write_to(&self, buffer: &mut Vec<u8>) -> super::Result<()> - заполнение буфера информацией о платеже.
  • to_utf8_lossy(&self) -> super::Result<String> - преобразование структуры в строку. Из-за кодировок могут быть проблемы.
let raw = "ST00012|Name=ООО «Три кита»|PersonalAcc=40702810138250123017|BankName=ОАО \"БАНК\"|BIC=044525225|CorrespAcc=30101810400000000225|PayeeINN=6200098765|LastName=Иванов|FirstName=Иван|MiddleName=Иванович|Purpose=Оплата членского взноса|PayerAddress=г.Рязань ул.Ленина д.10 кв.15|Sum=100000";

let payment = Payment::builder(RequiredRequisite {
    name: "ООО «Три кита»".to_max_size().unwrap(),
    personal_acc: "40702810138250123017".to_exact_size().unwrap(),
    bank_name: "ОАО \"БАНК\"".to_max_size().unwrap(),
    bic: "044525225".to_exact_size().unwrap(),
    correstp_acc: "30101810400000000225".to_max_size().unwrap(),
})
.with_additional_requisites([
    Requisite::PayeeINN("6200098765".to_max_size().unwrap()),
    Requisite::LastName("Иванов".into()),
    Requisite::FirstName("Иван".into()),
    Requisite::MiddleName("Иванович".into()),
    Requisite::Purpose("Оплата членского взноса".to_max_size().unwrap()),
    Requisite::PayerAddress("г.Рязань ул.Ленина д.10 кв.15".into()),
    Requisite::Sum("100000".to_max_size().unwrap()),
])
.build();

let payment = payment.to_utf8_lossy();
let payment = payment.as_ref().map(|s| s.as_str());

assert_eq!(payment, Ok(raw));

Парсинг

Для парсинга необходимо создать структуру PaymentParser с помощью Payment::parser().

PaymentParser имеет следующие методы:

  • parse_from_str(&self, val: &str) -> super::Result<Payment<T>> - создание структуры из строки. Предполагается, что данные находятся в формате Utf-8.
  • parse_from_bytes(&self, bytes: &[u8]) -> super::Result<Payment<T>> - создание структуры из массива байтов.

Пример from_str:

let raw = "ST00012|Name=ООО «Три кита»|PersonalAcc=40702810138250123017|BankName=ОАО \"БАНК\"|BIC=044525225|CorrespAcc=30101810400000000225";

let parsed_payment = Payment::parser().parse_from_str(raw);

let payment = Payment::custom_builder(RequiredRequisite {
    name: "ООО «Три кита»".to_max_size().unwrap(),
    personal_acc: "40702810138250123017".to_exact_size().unwrap(),
    bank_name: "ОАО \"БАНК\"".to_max_size().unwrap(),
    bic: "044525225".to_exact_size().unwrap(),
    correstp_acc: "30101810400000000225".to_max_size().unwrap(),
})
.build();

assert_eq!(parsed_payment, Ok(payment));

Пример from_bytes:

let raw = "ST00012|Name=ООО «Три кита»|PersonalAcc=40702810138250123017|BankName=ОАО \"БАНК\"|BIC=044525225|CorrespAcc=30101810400000000225".as_bytes();

let parsed_payment = Payment::parser().parse_from_bytes(raw);

let payment = Payment::custom_builder(RequiredRequisite {
    name: "ООО «Три кита»".to_max_size().unwrap(),
    personal_acc: "40702810138250123017".to_exact_size().unwrap(),
    bank_name: "ОАО \"БАНК\"".to_max_size().unwrap(),
    bic: "044525225".to_exact_size().unwrap(),
    correstp_acc: "30101810400000000225".to_max_size().unwrap(),
})
.build();

assert_eq!(parsed_payment, Ok(payment));

Получение реквизитов

let payment = Payment::builder(RequiredRequisite {
    name: "ООО «Три кита»".to_max_size().unwrap(),
    personal_acc: "40702810138250123017".to_exact_size().unwrap(),
    bank_name: "ОАО \"БАНК\"".to_max_size().unwrap(),
    bic: "044525225".to_exact_size().unwrap(),
    correstp_acc: "30101810400000000225".to_max_size().unwrap(),
})
.build();

assert_eq!(payment.get("Name"), Some("ООО «Три кита»"));

Определение новых реквизитов

Для добавления новых реквизитов необходимо создать собственный тип и реализовать для него трейт CustomRequisites.

enum MyReq {
    Foo,
    Bar,
}

impl TryFrom<(&str, &str)> for MyReq {
    type Error = Error;

    fn try_from(_: (&str, &str)) -> Result<Self, Self::Error> {
        Ok(Self::Foo)
    }
}

impl CustomRequisites for MyReq {
    fn key(&self) -> &str {
        match self {
            MyReq::Foo => "Foo",
            MyReq::Bar => "Bar",
        }
    }

    fn value(&self) -> &str {
        match self {
            MyReq::Foo => "Foo",
            MyReq::Bar => "Bar",
        }
    }
}

let raw = "ST00012|Name=ООО «Три кита»|PersonalAcc=40702810138250123017|BankName=ОАО \"БАНК\"|BIC=044525225|CorrespAcc=30101810400000000225|Foo=Foo|Bar=Bar";

let payment = Payment::custom_builder(RequiredRequisite {
    name: "ООО «Три кита»".to_max_size().unwrap(),
    personal_acc: "40702810138250123017".to_exact_size().unwrap(),
    bank_name: "ОАО \"БАНК\"".to_max_size().unwrap(),
    bic: "044525225".to_exact_size().unwrap(),
    correstp_acc: "30101810400000000225".to_max_size().unwrap(),
})
.with_additional_requisites([Requisite::Custom(MyReq::Foo), Requisite::Custom(MyReq::Bar)])
.build();

assert_eq!(payment.get("Foo"), Some("Foo"));
assert_eq!(payment.get("Bar"), Some("Bar"));

let payment = payment.to_utf8_lossy();
let payment = payment.as_ref().map(|s| s.as_str());

assert_eq!(payment, Ok(raw));

Тип парсеров

Реализованы следующие типы парсеров:

  • StrictParser - строгий парсер, делает все проверки.
  • RequisiteToleranceParser - менее строгий парсер, если произошла ошибка в парсинге реквизитов, то она игнорируется.
  • LooseParser - нестрогий парсер, проверяет только заголовок.

Для создания парсеров используются методы структуры Payment:

  • parser() -> PaymentParser
  • pub fn requisite_tolerance_parser() -> PaymentParser<RequisiteToleranceParser>
  • pub fn loose_parser() -> PaymentParser<LooseParser>

Для каждого метода существует метод custom_*, чтобы указать пользовательские реквизиты.

StrictParser:

let raw =
    "ST00012|BankName=ОАО \"БАНК\"|BIC=044525225|CorrespAcc=30101810400000000225|Тест=42";

let parsed_payment = Payment::parser().parse_from_str(raw);

assert!(parsed_payment.is_err());

RequisiteToleranceParser:

let raw = "ST00012|Name=ООО «Три кита»|PersonalAcc=40702810138250123017|BankName=ОАО \"БАНК\"|BIC=044525225|CorrespAcc=30101810400000000225|Тест=42|fasfdsfsdfs|  |";

let parsed_payment = Payment::requisite_tolerance_parser().parse_from_str(raw);

let payment = Payment::builder(RequiredRequisite {
    name: "ООО «Три кита»".to_max_size().unwrap(),
    personal_acc: "40702810138250123017".to_exact_size().unwrap(),
    bank_name: "ОАО \"БАНК\"".to_max_size().unwrap(),
    bic: "044525225".to_exact_size().unwrap(),
    correstp_acc: "30101810400000000225".to_max_size().unwrap(),
})
.build();

assert_eq!(parsed_payment, Ok(payment));

LooseParser:

let raw = "ST00012|Name=ООО «Три кита»||Тест=42|fasfdsfsdfs|  |";

let parsed_payment = Payment::loose_parser().parse_from_str(raw);

assert_eq!(parsed_payment.unwrap().get("Name"), Some("ООО «Три кита»"));

Dependencies

~2MB
~30K SLoC