gost_56042/
payment.rs

1use core::fmt::{Debug, Display};
2
3use alloc::{
4    boxed::Box,
5    format,
6    string::{String, ToString},
7    vec::Vec,
8};
9use encoding::Encoding;
10
11use crate::{LooseParser, PaymentParser, RequisiteToleranceParser, StrictParser};
12
13use super::{
14    string_types::{ExactSizeString, MaxSizeString, StringExt},
15    CustomRequisites, NoCustomRequisites,
16};
17
18pub(super) const FORMAT_ID_BYTES: [u8; 2] = [b'S', b'T'];
19pub(super) const VERSION_0001_BYTES: [u8; 4] = [b'0', b'0', b'0', b'1'];
20
21/// Информация о платеже.
22#[derive(Clone, Debug, PartialEq, Eq)]
23pub struct Payment<T: CustomRequisites = NoCustomRequisites> {
24    pub(super) header: PaymentHeader,
25    pub(super) requisites: Vec<Requisite<T>>,
26}
27
28#[derive(Debug)]
29pub struct PaymentBuilder<T: CustomRequisites = NoCustomRequisites> {
30    payment: Payment<T>,
31}
32
33impl<T: CustomRequisites> PaymentBuilder<T> {
34    /// Установка версии.
35    pub fn with_version(mut self, version: [u8; 4]) -> Self {
36        self.payment.header.version = version;
37        self
38    }
39
40    /// Установка кодировки.
41    pub fn with_encdoing(mut self, encdoing: PaymentEncoding) -> Self {
42        self.payment.header.encoding = encdoing;
43        self
44    }
45
46    /// Установка разделителя.
47    pub fn with_separator(mut self, separator: char) -> Self {
48        assert!(separator.is_ascii());
49
50        self.payment.header.separator = separator as u8;
51        self
52    }
53
54    /// Добавление дополнительных реквизитов.
55    pub fn with_additional_requisites(
56        mut self,
57        requisites: impl IntoIterator<Item = Requisite<T>>,
58    ) -> Self {
59        let requisites = requisites.into_iter().inspect(|requisite| {
60            assert!(!matches!(requisite, Requisite::Name(_)));
61            assert!(!matches!(requisite, Requisite::PersonalAcc(_)));
62            assert!(!matches!(requisite, Requisite::BankName(_)));
63            assert!(!matches!(requisite, Requisite::BIC(_)));
64            assert!(!matches!(requisite, Requisite::CorrespAcc(_)));
65        });
66
67        self.payment.requisites.extend(requisites);
68        self
69    }
70
71    /// Получение структуры с информацией о платеже.
72    pub fn build(self) -> Payment<T> {
73        self.payment
74    }
75}
76
77impl<T: CustomRequisites> Default for PaymentBuilder<T> {
78    fn default() -> Self {
79        Self {
80            payment: Payment {
81                header: PaymentHeader {
82                    format_id: FORMAT_ID_BYTES,
83                    version: VERSION_0001_BYTES,
84                    encoding: PaymentEncoding::Utf8,
85                    separator: b'|',
86                },
87                requisites: Vec::with_capacity(16),
88            },
89        }
90    }
91}
92
93impl Payment {
94    /// Строитель модели платежей.
95    pub fn builder(requisites: RequiredRequisite) -> PaymentBuilder {
96        let mut builder = PaymentBuilder::default();
97
98        let required_requisites = alloc::vec![
99            Requisite::Name(requisites.name),
100            Requisite::PersonalAcc(requisites.personal_acc),
101            Requisite::BankName(requisites.bank_name),
102            Requisite::BIC(requisites.bic),
103            Requisite::CorrespAcc(requisites.correstp_acc),
104        ];
105
106        builder.payment.requisites = required_requisites;
107
108        builder
109    }
110
111    /// Строгий парсер.
112    pub fn parser() -> PaymentParser {
113        PaymentParser::default()
114    }
115
116    /// Парсер, который пропускает неправильные реквизиты.
117    pub fn requisite_tolerance_parser() -> PaymentParser<RequisiteToleranceParser> {
118        PaymentParser::default()
119    }
120
121    /// Нестрогий парсер, пропускает все ошибки.
122    pub fn loose_parser() -> PaymentParser<LooseParser> {
123        PaymentParser::default()
124    }
125}
126
127impl<T: CustomRequisites> Payment<T> {
128    /// Строитель модели платежей с пользовательскими реквизитами.
129    pub fn custom_builder(requisites: RequiredRequisite) -> PaymentBuilder<T> {
130        let mut builder = PaymentBuilder::<T>::default();
131
132        let required_requisites = alloc::vec![
133            Requisite::Name(requisites.name),
134            Requisite::PersonalAcc(requisites.personal_acc),
135            Requisite::BankName(requisites.bank_name),
136            Requisite::BIC(requisites.bic),
137            Requisite::CorrespAcc(requisites.correstp_acc),
138        ];
139
140        builder.payment.requisites = required_requisites;
141
142        builder
143    }
144
145    /// Строгий парсер с пользовательскими реквизитами.
146    pub fn custom_parser() -> PaymentParser<StrictParser, T> {
147        PaymentParser::default()
148    }
149
150    /// Парсер с пользовательскими реквизитами, который пропускает неправильные реквизиты.
151    pub fn requisite_tolerance_custom_parser() -> PaymentParser<RequisiteToleranceParser, T> {
152        PaymentParser::default()
153    }
154
155    /// Нестрогий парсер с пользовательскими реквизитами, пропускает все ошибки.
156    pub fn loose_custom_parser() -> PaymentParser<LooseParser, T> {
157        PaymentParser::default()
158    }
159
160    /// Преобразования структуры в массив байтов согласно ГОСТ-56042.
161    pub fn to_bytes(&self) -> super::Result<Vec<u8>> {
162        let mut buffer = Vec::with_capacity(308);
163        self.write_to(&mut buffer)?;
164        Ok(buffer)
165    }
166
167    /// Заполнение буфера информацией о платеже согласно ГОСТ-56042.
168    pub fn write_to(&self, buffer: &mut Vec<u8>) -> super::Result<()> {
169        // Кодирование заголовка
170        buffer.push(self.header.format_id[0]);
171        buffer.push(self.header.format_id[1]);
172
173        buffer.push(self.header.version[0]);
174        buffer.push(self.header.version[1]);
175        buffer.push(self.header.version[2]);
176        buffer.push(self.header.version[3]);
177
178        buffer.push(self.header.encoding as u8);
179
180        // Кодирование реквизитов
181        for requisite in &self.requisites {
182            buffer.push(self.header.separator);
183            buffer.extend(self.encode_requisite(requisite)?);
184        }
185
186        Ok(())
187    }
188
189    /// Преобразования структуры в строку согласно ГОСТ-56042.
190    pub fn to_utf8_lossy(&self) -> super::Result<String> {
191        let bytes = self.to_bytes()?;
192        Ok(String::from_utf8_lossy(&bytes).to_string())
193    }
194
195    /// Получить значение по ключу.
196    pub fn get(&self, key: &str) -> Option<&str> {
197        self.requisites
198            .iter()
199            .find(|req| req.key() == key)
200            .map(|req| req.value())
201    }
202
203    /// Получение заголовка
204    pub fn header(&self) -> &PaymentHeader {
205        &self.header
206    }
207
208    /// Получение реквизитов
209    pub fn requisites(&self) -> impl Iterator<Item = &Requisite<T>> {
210        self.requisites.iter()
211    }
212}
213
214impl<T: CustomRequisites> Payment<T> {
215    fn encode_requisite(&self, req: &Requisite<T>) -> super::Result<Vec<u8>> {
216        let pair = format!("{}={}", req.key(), req.value());
217        match self.header.encoding {
218            PaymentEncoding::Win1251 => encoding::all::WINDOWS_1251
219                .encode(&pair, encoding::EncoderTrap::Strict)
220                .map_err(|_| super::Error::EncodingError),
221            PaymentEncoding::Utf8 => Ok(pair.into_bytes()),
222            PaymentEncoding::Koi8R => encoding::all::KOI8_R
223                .encode(&pair, encoding::EncoderTrap::Strict)
224                .map_err(|_| super::Error::EncodingError),
225        }
226    }
227}
228
229impl<T: CustomRequisites> Display for Payment<T> {
230    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
231        Display::fmt(&self.header, f)?;
232
233        for req in self.requisites.iter() {
234            write!(f, "{}", self.header.separator())?;
235            Display::fmt(req, f)?;
236        }
237
238        Ok(())
239    }
240}
241
242/// Заголовок платежа.
243#[derive(Clone, Debug, PartialEq, Eq)]
244pub struct PaymentHeader {
245    /// Идентификатор формата
246    pub(super) format_id: [u8; 2],
247
248    /// Версия стандарта
249    pub(super) version: [u8; 4],
250
251    /// Признак набора кодированных знаков
252    pub(super) encoding: PaymentEncoding,
253
254    /// Разделитель
255    pub(super) separator: u8,
256}
257
258impl PaymentHeader {
259    /// Идентификатор формата
260    pub fn format_id(&self) -> [char; 2] {
261        [self.format_id[0] as char, self.format_id[1] as char]
262    }
263
264    /// Версия стандарта
265    pub fn version(&self) -> [char; 4] {
266        [
267            self.version[0] as char,
268            self.version[1] as char,
269            self.version[2] as char,
270            self.version[3] as char,
271        ]
272    }
273
274    /// Версия стандарта
275    pub fn encoding(&self) -> PaymentEncoding {
276        self.encoding
277    }
278
279    /// Версия стандарта
280    pub fn separator(&self) -> char {
281        self.separator as char
282    }
283}
284
285impl Display for PaymentHeader {
286    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
287        write!(
288            f,
289            "{}{}{}{}{}{}{}",
290            self.format_id[0] as char,
291            self.format_id[1] as char,
292            self.version[0] as char,
293            self.version[1] as char,
294            self.version[2] as char,
295            self.version[3] as char,
296            self.encoding as u8 as char,
297        )
298    }
299}
300
301/// Требуемые реквизиты.
302#[derive(Clone, Debug, PartialEq, Eq)]
303pub struct RequiredRequisite {
304    pub name: MaxSizeString<160>,
305    pub personal_acc: ExactSizeString<20>,
306    pub bank_name: MaxSizeString<45>,
307    pub bic: ExactSizeString<9>,
308    pub correstp_acc: MaxSizeString<20>,
309}
310
311/// Варианты реквизитов.
312#[derive(Clone, Debug, PartialEq, Eq)]
313pub enum Requisite<T: CustomRequisites> {
314    // Обязательные
315    /// Наименование получателя платежа
316    Name(MaxSizeString<160>),
317
318    /// Номер счета получателя платежа
319    PersonalAcc(ExactSizeString<20>),
320
321    /// Наименование банка получателя платежа
322    BankName(MaxSizeString<45>),
323
324    /// БИК
325    BIC(ExactSizeString<9>),
326
327    /// Номер кор./сч. банка получателя платежа
328    CorrespAcc(MaxSizeString<20>),
329
330    // Дополнительные
331    /// Сумма платежа, в копейках
332    Sum(MaxSizeString<18>),
333
334    /// Наименование платежа (назначение)
335    Purpose(MaxSizeString<210>),
336
337    /// ИНН получателя платежа
338    PayeeINN(MaxSizeString<12>),
339
340    /// ИНН плательщика
341    PayerINN(MaxSizeString<12>),
342
343    /// Статус составителя платежного документа
344    DrawerStatus(MaxSizeString<2>),
345
346    /// КПП получателя платежа
347    KPP(MaxSizeString<9>),
348
349    /// КБК
350    CBC(MaxSizeString<20>),
351
352    /// Общероссийский классификатор территорий муниципальных образований (ОКТМО)
353    OKTMO(MaxSizeString<11>),
354
355    /// Основание налогового платежа
356    PaytReason(MaxSizeString<2>),
357
358    /// Налоговый период
359    TaxPeriod(MaxSizeString<10>),
360
361    /// Номер документа
362    DocNo(MaxSizeString<15>),
363
364    ///  Дата документа
365    DocDate(MaxSizeString<10>),
366
367    ///  Тип платежа
368    TaxPayKind(MaxSizeString<2>),
369
370    // Другие
371    /// Фамилия плательщика
372    LastName(Box<str>),
373
374    /// Имя плательщика
375    FirstName(Box<str>),
376
377    /// Отчество плательщика
378    MiddleName(Box<str>),
379
380    /// Адрес плательщика
381    PayerAddress(Box<str>),
382
383    /// Лицевой счет бюджетного получателя
384    PersonalAccount(Box<str>),
385
386    /// Индекс платежного документа
387    DocIdx(Box<str>),
388
389    /// № лицевого счета в системе персонифицированного учета в ПФР - СНИЛС
390    PensAcc(Box<str>),
391
392    /// Номер договора
393    Contract(Box<str>),
394
395    /// Номер лицевого счета плательщика в организации (в системе учета ПУ)
396    PersAcc(Box<str>),
397
398    /// Номер квартиры
399    Flat(Box<str>),
400
401    /// Номер телефона
402    Phone(Box<str>),
403
404    /// Вид ДУЛ плательщика
405    PayerIdType(Box<str>),
406
407    /// Номер ДУЛ плательщика
408    PayerIdNum(Box<str>),
409
410    /// Ф.И.О. ребенка/учащегося
411    ChildFio(Box<str>),
412
413    /// Дата рождения
414    BirthDate(Box<str>),
415
416    /// Срок платежа/дата выставления счета
417    PaymTerm(Box<str>),
418
419    /// Период оплаты
420    PaymPeriod(Box<str>),
421
422    /// Вид платежа
423    Category(Box<str>),
424
425    /// Код услуги/название прибора учета
426    ServiceName(Box<str>),
427
428    /// Номер прибора учета
429    CounterId(Box<str>),
430
431    /// Показание прибора учета
432    CounterVal(Box<str>),
433
434    /// Номер извещения, начисления, счета
435    QuittId(Box<str>),
436
437    /// Дата извещения/начисления/счета/постановления (для ГИБДД)
438    QuittDate(Box<str>),
439
440    /// Номер учреждения (образовательного, медицинского)
441    InstNum(Box<str>),
442
443    /// Номер группы детсада/класса школы
444    ClassNum(Box<str>),
445
446    /// ФИО преподавателя, специалиста, оказывающего услугу
447    SpecFio(Box<str>),
448
449    /// Сумма страховки/дополнительной услуги/Сумма пени (в копейках)
450    AddAmount(Box<str>),
451
452    /// Номер постановления (для ГИБДД)
453    RuleId(Box<str>),
454
455    /// Номер исполнительного производства
456    ExecId(Box<str>),
457
458    /// Код вида платежа (например, для платежей в адрес Росреестра)
459    RegType(Box<str>),
460
461    /// Уникальный идентификатор начисления
462    UIN(Box<str>),
463
464    /// Технический код, рекомендуемый для заполнения поставщиком услуг. Может использоваться принимающей организацией для вызова соответствующей обрабатывающей ИТ-системы.
465    TechCode(TechCode),
466
467    /// Собственный вариант реквизита
468    Custom(T),
469}
470
471impl<T: CustomRequisites> Requisite<T> {
472    pub fn key(&self) -> &str {
473        match self {
474            Requisite::Name(_) => "Name",
475            Requisite::PersonalAcc(_) => "PersonalAcc",
476            Requisite::BankName(_) => "BankName",
477            Requisite::BIC(_) => "BIC",
478            Requisite::CorrespAcc(_) => "CorrespAcc",
479            Requisite::Sum(_) => "Sum",
480            Requisite::Purpose(_) => "Purpose",
481            Requisite::PayeeINN(_) => "PayeeINN",
482            Requisite::PayerINN(_) => "PayerINN",
483            Requisite::DrawerStatus(_) => "DrawerStatus",
484            Requisite::KPP(_) => "KPP",
485            Requisite::CBC(_) => "CBC",
486            Requisite::OKTMO(_) => "OKTMO",
487            Requisite::PaytReason(_) => "PaytReason",
488            Requisite::TaxPeriod(_) => "TaxPeriod",
489            Requisite::DocNo(_) => "DocNo",
490            Requisite::DocDate(_) => "DocDate",
491            Requisite::TaxPayKind(_) => "TaxPayKind",
492            Requisite::LastName(_) => "LastName",
493            Requisite::FirstName(_) => "FirstName",
494            Requisite::MiddleName(_) => "MiddleName",
495            Requisite::PayerAddress(_) => "PayerAddress",
496            Requisite::PersonalAccount(_) => "PersonalAccount",
497            Requisite::DocIdx(_) => "DocIdx",
498            Requisite::PensAcc(_) => "PensAcc",
499            Requisite::Contract(_) => "Contract",
500            Requisite::PersAcc(_) => "PersAcc",
501            Requisite::Flat(_) => "Flat",
502            Requisite::Phone(_) => "Phone",
503            Requisite::PayerIdType(_) => "PayerIdType",
504            Requisite::PayerIdNum(_) => "PayerIdNum",
505            Requisite::ChildFio(_) => "ChildFio",
506            Requisite::BirthDate(_) => "BirthDate",
507            Requisite::PaymTerm(_) => "PaymTerm",
508            Requisite::PaymPeriod(_) => "PaymPeriod",
509            Requisite::Category(_) => "Category",
510            Requisite::ServiceName(_) => "ServiceName",
511            Requisite::CounterId(_) => "CounterId",
512            Requisite::CounterVal(_) => "CounterVal",
513            Requisite::QuittId(_) => "QuittId",
514            Requisite::QuittDate(_) => "QuittDate",
515            Requisite::InstNum(_) => "InstNum",
516            Requisite::ClassNum(_) => "ClassNum",
517            Requisite::SpecFio(_) => "SpecFio",
518            Requisite::AddAmount(_) => "AddAmount",
519            Requisite::RuleId(_) => "RuleId",
520            Requisite::ExecId(_) => "ExecId",
521            Requisite::RegType(_) => "RegType",
522            Requisite::UIN(_) => "UIN",
523            Requisite::TechCode(_) => "TechCode",
524            Requisite::Custom(v) => v.key(),
525        }
526    }
527
528    pub fn value(&self) -> &str {
529        match self {
530            Requisite::Name(v) => v,
531            Requisite::PersonalAcc(v) => v,
532            Requisite::BankName(v) => v,
533            Requisite::BIC(v) => v,
534            Requisite::CorrespAcc(v) => v,
535            Requisite::Sum(v) => v,
536            Requisite::Purpose(v) => v,
537            Requisite::PayeeINN(v) => v,
538            Requisite::PayerINN(v) => v,
539            Requisite::DrawerStatus(v) => v,
540            Requisite::KPP(v) => v,
541            Requisite::CBC(v) => v,
542            Requisite::OKTMO(v) => v,
543            Requisite::PaytReason(v) => v,
544            Requisite::TaxPeriod(v) => v,
545            Requisite::DocNo(v) => v,
546            Requisite::DocDate(v) => v,
547            Requisite::TaxPayKind(v) => v,
548            Requisite::LastName(v) => v,
549            Requisite::FirstName(v) => v,
550            Requisite::MiddleName(v) => v,
551            Requisite::PayerAddress(v) => v,
552            Requisite::PersonalAccount(v) => v,
553            Requisite::DocIdx(v) => v,
554            Requisite::PensAcc(v) => v,
555            Requisite::Contract(v) => v,
556            Requisite::PersAcc(v) => v,
557            Requisite::Flat(v) => v,
558            Requisite::Phone(v) => v,
559            Requisite::PayerIdType(v) => v,
560            Requisite::PayerIdNum(v) => v,
561            Requisite::ChildFio(v) => v,
562            Requisite::BirthDate(v) => v,
563            Requisite::PaymTerm(v) => v,
564            Requisite::PaymPeriod(v) => v,
565            Requisite::Category(v) => v,
566            Requisite::ServiceName(v) => v,
567            Requisite::CounterId(v) => v,
568            Requisite::CounterVal(v) => v,
569            Requisite::QuittId(v) => v,
570            Requisite::QuittDate(v) => v,
571            Requisite::InstNum(v) => v,
572            Requisite::ClassNum(v) => v,
573            Requisite::SpecFio(v) => v,
574            Requisite::AddAmount(v) => v,
575            Requisite::RuleId(v) => v,
576            Requisite::ExecId(v) => v,
577            Requisite::RegType(v) => v,
578            Requisite::UIN(v) => v,
579            Requisite::TechCode(tech_code) => tech_code.as_str(),
580            Requisite::Custom(v) => v.value(),
581        }
582    }
583}
584
585impl<T: CustomRequisites> TryFrom<(&str, &str)> for Requisite<T> {
586    type Error = super::Error;
587
588    fn try_from((key, val): (&str, &str)) -> super::Result<Self> {
589        let requisite = match key {
590            "Name" => Requisite::Name(
591                val.to_max_size()
592                    .ok_or(super::Error::WrongPair(key.into(), val.into()))?,
593            ),
594            "PersonalAcc" => Requisite::PersonalAcc(
595                val.to_exact_size()
596                    .ok_or(super::Error::WrongPair(key.into(), val.into()))?,
597            ),
598            "BankName" => Requisite::BankName(
599                val.to_max_size()
600                    .ok_or(super::Error::WrongPair(key.into(), val.into()))?,
601            ),
602            "BIC" => Requisite::BIC(
603                val.to_exact_size()
604                    .ok_or(super::Error::WrongPair(key.into(), val.into()))?,
605            ),
606            "CorrespAcc" => Requisite::CorrespAcc(
607                val.to_max_size()
608                    .ok_or(super::Error::WrongPair(key.into(), val.into()))?,
609            ),
610            "Sum" => Requisite::Sum(
611                val.to_max_size()
612                    .ok_or(super::Error::WrongPair(key.into(), val.into()))?,
613            ),
614            "Purpose" => Requisite::Purpose(
615                val.to_max_size()
616                    .ok_or(super::Error::WrongPair(key.into(), val.into()))?,
617            ),
618            "PayeeINN" => Requisite::PayeeINN(
619                val.to_max_size()
620                    .ok_or(super::Error::WrongPair(key.into(), val.into()))?,
621            ),
622            "PayerINN" => Requisite::PayerINN(
623                val.to_max_size()
624                    .ok_or(super::Error::WrongPair(key.into(), val.into()))?,
625            ),
626            "DrawerStatus" => Requisite::DrawerStatus(
627                val.to_max_size()
628                    .ok_or(super::Error::WrongPair(key.into(), val.into()))?,
629            ),
630            "KPP" => Requisite::KPP(
631                val.to_max_size()
632                    .ok_or(super::Error::WrongPair(key.into(), val.into()))?,
633            ),
634            "CBC" => Requisite::CBC(
635                val.to_max_size()
636                    .ok_or(super::Error::WrongPair(key.into(), val.into()))?,
637            ),
638            "OKTMO" => Requisite::OKTMO(
639                val.to_max_size()
640                    .ok_or(super::Error::WrongPair(key.into(), val.into()))?,
641            ),
642            "PaytReason" => Requisite::PaytReason(
643                val.to_max_size()
644                    .ok_or(super::Error::WrongPair(key.into(), val.into()))?,
645            ),
646            "TaxPeriod" => Requisite::TaxPeriod(
647                val.to_max_size()
648                    .ok_or(super::Error::WrongPair(key.into(), val.into()))?,
649            ),
650            "DocNo" => Requisite::DocNo(
651                val.to_max_size()
652                    .ok_or(super::Error::WrongPair(key.into(), val.into()))?,
653            ),
654            "DocDate" => Requisite::DocDate(
655                val.to_max_size()
656                    .ok_or(super::Error::WrongPair(key.into(), val.into()))?,
657            ),
658            "TaxPayKind" => Requisite::TaxPayKind(
659                val.to_max_size()
660                    .ok_or(super::Error::WrongPair(key.into(), val.into()))?,
661            ),
662            "LastName" => Requisite::LastName(val.into()),
663            "FirstName" => Requisite::FirstName(val.into()),
664            "MiddleName" => Requisite::MiddleName(val.into()),
665            "PayerAddress" => Requisite::PayerAddress(val.into()),
666            "PersonalAccount" => Requisite::PersonalAccount(val.into()),
667            "DocIdx" => Requisite::DocIdx(val.into()),
668            "PensAcc" => Requisite::PensAcc(val.into()),
669            "Flat" => Requisite::Flat(val.into()),
670            "Phone" => Requisite::Phone(val.into()),
671            "PayerIdType" => Requisite::PayerIdType(val.into()),
672            "PayerIdNum" => Requisite::PayerIdNum(val.into()),
673            "ChildFio" => Requisite::ChildFio(val.into()),
674            "BirthDate" => Requisite::BirthDate(val.into()),
675            "PaymTerm" => Requisite::PaymTerm(val.into()),
676            "PaymPeriod" => Requisite::PaymPeriod(val.into()),
677            "Category" => Requisite::Category(val.into()),
678            "ServiceName" => Requisite::ServiceName(val.into()),
679            "CounterId" => Requisite::CounterId(val.into()),
680            "CounterVal" => Requisite::CounterVal(val.into()),
681            "QuittId" => Requisite::QuittId(val.into()),
682            "QuittDate" => Requisite::QuittDate(val.into()),
683            "InstNum" => Requisite::InstNum(val.into()),
684            "ClassNum" => Requisite::ClassNum(val.into()),
685            "SpecFio" => Requisite::SpecFio(val.into()),
686            "AddAmount" => Requisite::AddAmount(val.into()),
687            "RuleId" => Requisite::RuleId(val.into()),
688            "ExecId" => Requisite::ExecId(val.into()),
689            "RegType" => Requisite::RegType(val.into()),
690            "UIN" => Requisite::UIN(val.into()),
691            "TechCode" => Requisite::TechCode(TechCode::from_str(val)?),
692            _ => Requisite::Custom((key, val).try_into()?),
693        };
694
695        Ok(requisite)
696    }
697}
698
699impl<T: CustomRequisites> Display for Requisite<T> {
700    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
701        write!(f, "{}={}", self.key(), self.value())
702    }
703}
704
705/// Значения технического кода платежа
706#[derive(Clone, Copy, Debug, PartialEq, Eq)]
707pub enum TechCode {
708    /// Мобильная связь, стационарный телефон
709    Mobile,
710
711    /// Коммунальные услуги, ЖКХ
712    HousingAndUtilites,
713
714    /// ГИБДД, налоги, пошлины, бюджетные платежи
715    Taxes,
716
717    /// Охранные услуги
718    SecurityServices,
719
720    /// Услуги, оказываемые УФМС
721    FMS,
722
723    // ПФР
724    PFR,
725
726    /// Погашение кредитов
727    LoanRepayments,
728
729    /// Образовательные учреждения
730    EducationalInstitutions,
731
732    /// Интернет и ТВ
733    InternetTV,
734
735    /// Электронные деньги
736    Emoney,
737
738    /// Отдых и путешествия
739    Vacation,
740
741    /// Инвестиции и страхование
742    InvestmentInsurance,
743
744    /// Спорт и здоровье
745    SportHealth,
746
747    /// Благотворительные и общественные организации
748    Charity,
749
750    ///  Прочие услуги
751    Other,
752}
753
754impl TechCode {
755    fn as_str(&self) -> &str {
756        match self {
757            TechCode::Mobile => "01",
758            TechCode::HousingAndUtilites => "02",
759            TechCode::Taxes => "03",
760            TechCode::SecurityServices => "04",
761            TechCode::FMS => "05",
762            TechCode::PFR => "06",
763            TechCode::LoanRepayments => "07",
764            TechCode::EducationalInstitutions => "08",
765            TechCode::InternetTV => "09",
766            TechCode::Emoney => "10",
767            TechCode::Vacation => "11",
768            TechCode::InvestmentInsurance => "12",
769            TechCode::SportHealth => "13",
770            TechCode::Charity => "14",
771            TechCode::Other => "15",
772        }
773    }
774
775    fn from_str(val: &str) -> super::Result<TechCode> {
776        match val {
777            "01" => Ok(TechCode::Mobile),
778            "02" => Ok(TechCode::HousingAndUtilites),
779            "03" => Ok(TechCode::Taxes),
780            "04" => Ok(TechCode::SecurityServices),
781            "05" => Ok(TechCode::FMS),
782            "06" => Ok(TechCode::PFR),
783            "07" => Ok(TechCode::LoanRepayments),
784            "08" => Ok(TechCode::EducationalInstitutions),
785            "09" => Ok(TechCode::InternetTV),
786            "10" => Ok(TechCode::Emoney),
787            "11" => Ok(TechCode::Vacation),
788            "12" => Ok(TechCode::InvestmentInsurance),
789            "13" => Ok(TechCode::SportHealth),
790            "14" => Ok(TechCode::Charity),
791            "15" => Ok(TechCode::Other),
792            _ => Err(super::Error::UnknownTechCode(val.into())),
793        }
794    }
795}
796
797/// Признак набора кодированных знаков.
798#[derive(Clone, Copy, Debug, PartialEq, Eq)]
799#[repr(u8)]
800pub enum PaymentEncoding {
801    /// Windows-1251
802    Win1251 = b'1',
803
804    /// Utf-8
805    Utf8 = b'2',
806
807    /// КОИ8-R
808    Koi8R = b'3',
809}
810
811impl TryFrom<u8> for PaymentEncoding {
812    type Error = super::Error;
813
814    fn try_from(value: u8) -> super::Result<PaymentEncoding> {
815        match value {
816            b'1' => Ok(Self::Win1251),
817            b'2' => Ok(Self::Utf8),
818            b'3' => Ok(Self::Koi8R),
819            code => Err(super::Error::UnknownEncodingCode(code)),
820        }
821    }
822}
823
824impl Display for PaymentEncoding {
825    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
826        match self {
827            PaymentEncoding::Win1251 => write!(f, "Windows-1251"),
828            PaymentEncoding::Utf8 => write!(f, "Utf-8"),
829            PaymentEncoding::Koi8R => write!(f, "KOI8-R"),
830        }
831    }
832}