4
4
using System . Globalization ;
5
5
using System . Text ;
6
6
using System . Text . RegularExpressions ;
7
- #if NETSTANDARD1_1
7
+ #if NETSTANDARD1_3
8
8
using System . Reflection ;
9
9
#endif
10
10
@@ -2455,65 +2455,168 @@ public class RussiaPaymentOrder : Payload
2455
2455
private CharacterSets characterSet ;
2456
2456
private MandatoryFields mFields ;
2457
2457
private OptionalFields oFields ;
2458
+ private string separator = "|" ;
2458
2459
2459
2460
private RussiaPaymentOrder ( )
2460
2461
{
2461
2462
mFields = new MandatoryFields ( ) ;
2462
2463
oFields = new OptionalFields ( ) ;
2463
2464
}
2464
-
2465
- public RussiaPaymentOrder ( CharacterSets characterSet , string name , string personalAcc , string bankName , string BIC , string correspAcc , OptionalFields optionalFields = null ) : this ( )
2465
+
2466
+ /// <summary>
2467
+ /// Generates a RussiaPaymentOrder payload
2468
+ /// </summary>
2469
+ /// <param name="name">Name of the payee (Наименование получателя платежа)</param>
2470
+ /// <param name="personalAcc">Beneficiary account number (Номер счета получателя платежа)</param>
2471
+ /// <param name="bankName">Name of the beneficiary's bank (Наименование банка получателя платежа)</param>
2472
+ /// <param name="BIC">BIC (БИК)</param>
2473
+ /// <param name="correspAcc">Box number / account payee's bank (Номер кор./сч. банка получателя платежа)</param>
2474
+ /// <param name="optionalFields">An (optional) object of additional fields</param>
2475
+ /// <param name="characterSet">Type of encoding (default UTF-8)</param>
2476
+ public RussiaPaymentOrder ( string name , string personalAcc , string bankName , string BIC , string correspAcc , OptionalFields optionalFields = null , CharacterSets characterSet = CharacterSets . utf_8 ) : this ( )
2466
2477
{
2467
2478
this . characterSet = characterSet ;
2468
- mFields . Name = validateInput ( name , "Name" , @"^.{1,160}$" ) ;
2469
- mFields . PersonalAcc = validateInput ( personalAcc , "PersonalAcc" , @"^[1-9]\d{4}[0-9ABCEHKMPTX]\d{14}$" ) ;
2470
- mFields . BankName = validateInput ( bankName , "BankName" , @"^.{1,45}$" ) ;
2471
- mFields . BIC = validateInput ( BIC , "BIC" , @"^\d{9}$" ) ;
2472
- mFields . CorrespAcc = validateInput ( correspAcc , "CorrespAcc" , @"^[1-9]\d{4}[0-9ABCEHKMPTX]\d{14}$" ) ;
2479
+ mFields . Name = ValidateInput ( name , "Name" , @"^.{1,160}$" ) ;
2480
+ mFields . PersonalAcc = ValidateInput ( personalAcc , "PersonalAcc" , @"^[1-9]\d{4}[0-9ABCEHKMPTX]\d{14}$" ) ;
2481
+ mFields . BankName = ValidateInput ( bankName , "BankName" , @"^.{1,45}$" ) ;
2482
+ mFields . BIC = ValidateInput ( BIC , "BIC" , @"^\d{9}$" ) ;
2483
+ mFields . CorrespAcc = ValidateInput ( correspAcc , "CorrespAcc" , @"^[1-9]\d{4}[0-9ABCEHKMPTX]\d{14}$" ) ;
2473
2484
2474
2485
if ( optionalFields != null )
2475
2486
oFields = optionalFields ;
2476
2487
}
2477
2488
2489
+ /// <summary>
2490
+ /// Returns payload as string.
2491
+ /// </summary>
2492
+ /// <remarks>⚠ Attention: If CharacterSets was set to windows-1251 or koi8-r you should use ToBytes() instead of ToString() and pass the bytes to CreateQrCode()!</remarks>
2493
+ /// <returns></returns>
2478
2494
public override string ToString ( )
2479
2495
{
2480
- string ret = $ "ST0001" + ( ( int ) characterSet ) . ToString ( ) + $ "|Name={ mFields . Name } " +
2481
- $ "|PersonalAcc={ mFields . PersonalAcc } " +
2482
- $ "|BankName={ mFields . BankName } " +
2483
- $ "|BIC={ mFields . BIC } " +
2484
- $ "|CorrespAcc={ mFields . CorrespAcc } ";
2496
+ var cp = characterSet . ToString ( ) . Replace ( "_" , "-" ) ;
2497
+ var bytes = ToBytes ( ) ;
2498
+
2499
+ #if ! NET35 && ! NET40 && ! NETSTANDARD1_3_OR_GREATER
2500
+ System . Text . Encoding . RegisterProvider ( System . Text . CodePagesEncodingProvider . Instance ) ;
2501
+ #endif
2502
+ #if NETSTANDARD1_3
2503
+ // TODO: Fix for NETSTANDARD1.1
2504
+ return Encoding . GetEncoding ( cp ) . GetString ( bytes , 0 , bytes . Length ) ;
2505
+ #else
2506
+ return Encoding . GetEncoding ( cp ) . GetString ( bytes ) ;
2507
+ #endif
2508
+ }
2509
+
2510
+ /// <summary>
2511
+ /// Returns payload as byte[].
2512
+ /// </summary>
2513
+ /// <remarks>Should be used if CharacterSets equals windows-1251 or koi8-r</remarks>
2514
+ /// <returns></returns>
2515
+
2516
+ public byte [ ] ToBytes ( )
2517
+ {
2518
+ //Calculate the seperator
2519
+ separator = DetermineSeparator ( ) ;
2520
+
2521
+ //Create the payload string
2522
+ string ret = $ "ST0001" + ( ( int ) characterSet ) . ToString ( ) + //(separator != "|" ? separator : "") +
2523
+ $ "{ separator } Name={ mFields . Name } " +
2524
+ $ "{ separator } PersonalAcc={ mFields . PersonalAcc } " +
2525
+ $ "{ separator } BankName={ mFields . BankName } " +
2526
+ $ "{ separator } BIC={ mFields . BIC } " +
2527
+ $ "{ separator } CorrespAcc={ mFields . CorrespAcc } ";
2485
2528
2486
2529
//Add optional fields, if filled
2487
- var optionalFieldsList = new List < string > ( ) ;
2488
- #if NETSTANDARD1_1
2489
- optionalFieldsList = oFields . GetType ( ) . GetRuntimeProperties ( )
2530
+ var optionalFieldsList = GetOptionalFieldsAsList ( ) ;
2531
+ if ( optionalFieldsList . Count > 0 )
2532
+ ret += $ "|{ string . Join ( "|" , optionalFieldsList . ToArray ( ) ) } ";
2533
+ ret += separator ;
2534
+
2535
+ //Encode return string as byte[] with correct CharacterSet
2536
+ #if ! NET35_OR_GREATER
2537
+ Encoding . RegisterProvider ( CodePagesEncodingProvider . Instance ) ;
2538
+ #endif
2539
+ var cp = this . characterSet . ToString ( ) . Replace ( "_" , "-" ) ;
2540
+ byte [ ] bytesOut = Encoding . Convert ( Encoding . UTF8 , Encoding . GetEncoding ( cp ) , Encoding . UTF8 . GetBytes ( ret ) ) ;
2541
+ if ( bytesOut . Length > 300 )
2542
+ throw new RussiaPaymentOrderException ( $ "Data too long. Payload must not exceed 300 bytes, but actually is { bytesOut . Length } bytes long. Remove additional data fields or shorten strings/values.") ;
2543
+ return bytesOut ;
2544
+ }
2545
+
2546
+
2547
+ /// <summary>
2548
+ /// Determines a valid separator
2549
+ /// </summary>
2550
+ /// <returns></returns>
2551
+ private string DetermineSeparator ( )
2552
+ {
2553
+ // See chapter 5.2.1 of Standard (https://sbqr.ru/standard/files/standart.pdf)
2554
+
2555
+ var mandatoryValues = GetMandatoryFieldsAsList ( ) ;
2556
+ var optionalValues = GetOptionalFieldsAsList ( ) ;
2557
+
2558
+ // Possible candidates for field separation
2559
+ var separatorCandidates = new string [ ] { "|" , "#" , ";" , ":" , "^" , "_" , "~" , "{" , "}" , "!" , "#" , "$" , "%" , "&" , "(" , ")" , "*" , "+" , "," , "/" , "@" } ;
2560
+ foreach ( var sepCandidate in separatorCandidates )
2561
+ {
2562
+ if ( ! mandatoryValues . Any ( x => x . Contains ( sepCandidate ) ) && ! optionalValues . Any ( x => x . Contains ( sepCandidate ) ) )
2563
+ return sepCandidate ;
2564
+ }
2565
+ throw new RussiaPaymentOrderException ( "No valid separator found." ) ;
2566
+ }
2567
+
2568
+ /// <summary>
2569
+ /// Takes all optional fields that are not null and returns their string represantion
2570
+ /// </summary>
2571
+ /// <returns>A List of strings</returns>
2572
+ private List < string > GetOptionalFieldsAsList ( )
2573
+ {
2574
+ #if NETSTANDARD1_3
2575
+ return oFields . GetType ( ) . GetRuntimeProperties ( )
2490
2576
. Where ( field => field . GetValue ( oFields ) != null )
2491
2577
. Select ( field => {
2492
2578
var objValue = field . GetValue ( oFields , null ) ;
2493
- var value = field . GetType ( ) . Equals ( typeof ( DateTime ) ) ? ( ( DateTime ) objValue ) . ToString ( "dd.MM.YYYY " ) : objValue . ToString ( ) ;
2579
+ var value = field . PropertyType . Equals ( typeof ( DateTime ? ) ) ? ( ( DateTime ) objValue ) . ToString ( "dd.MM.yyyy " ) : objValue . ToString ( ) ;
2494
2580
return $ "{ field . Name } ={ value } ";
2495
2581
} )
2496
2582
. ToList ( ) ;
2497
2583
#else
2498
- optionalFieldsList = oFields . GetType ( ) . GetProperties ( )
2584
+ return oFields . GetType ( ) . GetProperties ( )
2499
2585
. Where ( field => field . GetValue ( oFields , null ) != null )
2500
2586
. Select ( field => {
2501
2587
var objValue = field . GetValue ( oFields , null ) ;
2502
- var value = field . GetType ( ) . Equals ( typeof ( DateTime ) ) ? ( ( DateTime ) objValue ) . ToString ( "dd.MM.YYYY " ) : objValue . ToString ( ) ;
2588
+ var value = field . PropertyType . Equals ( typeof ( DateTime ? ) ) ? ( ( DateTime ) objValue ) . ToString ( "dd.MM.yyyy " ) : objValue . ToString ( ) ;
2503
2589
return $ "{ field . Name } ={ value } ";
2504
2590
} )
2505
2591
. ToList ( ) ;
2506
2592
#endif
2507
- if ( optionalFieldsList . Count > 0 )
2508
- ret += $ "|{ string . Join ( "|" , optionalFieldsList . ToArray ( ) ) } ";
2593
+ }
2509
2594
2510
2595
2511
- string page = this . characterSet . ToString ( ) . Replace ( "_" , "-" ) ;
2512
- #if NETSTANDARD1_1
2513
- var bytes = Encoding . Convert ( Encoding . UTF8 , Encoding . GetEncoding ( page ) , Encoding . GetEncoding ( page ) . GetBytes ( ret ) ) ;
2514
- return Encoding . GetEncoding ( page ) . GetString ( bytes , 0 , bytes . Length ) ;
2596
+ /// <summary>
2597
+ /// Takes all mandatory fields that are not null and returns their string represantion
2598
+ /// </summary>
2599
+ /// <returns>A List of strings</returns>
2600
+ private List < string > GetMandatoryFieldsAsList ( )
2601
+ {
2602
+ #if NETSTANDARD1_3
2603
+ return mFields . GetType ( ) . GetRuntimeFields ( )
2604
+ . Where ( field => field . GetValue ( mFields ) != null )
2605
+ . Select ( field => {
2606
+ var objValue = field . GetValue ( mFields ) ;
2607
+ var value = field . FieldType . Equals ( typeof ( DateTime ? ) ) ? ( ( DateTime ) objValue ) . ToString ( "dd.MM.yyyy" ) : objValue . ToString ( ) ;
2608
+ return $ "{ field . Name } ={ value } ";
2609
+ } )
2610
+ . ToList ( ) ;
2515
2611
#else
2516
- return Encoding . GetEncoding ( page ) . GetString ( Encoding . Convert ( Encoding . Default , Encoding . GetEncoding ( page ) , Encoding . GetEncoding ( page ) . GetBytes ( ret ) ) ) ;
2612
+ return mFields . GetType ( ) . GetFields ( )
2613
+ . Where ( field => field . GetValue ( mFields ) != null )
2614
+ . Select ( field => {
2615
+ var objValue = field . GetValue ( mFields ) ;
2616
+ var value = field . FieldType . Equals ( typeof ( DateTime ? ) ) ? ( ( DateTime ) objValue ) . ToString ( "dd.MM.yyyy" ) : objValue . ToString ( ) ;
2617
+ return $ "{ field . Name } ={ value } ";
2618
+ } )
2619
+ . ToList ( ) ;
2517
2620
#endif
2518
2621
}
2519
2622
@@ -2525,9 +2628,9 @@ public override string ToString()
2525
2628
/// <param name="pattern">A regex pattern to be used for validation</param>
2526
2629
/// <param name="errorText">An optional error text. If null, a standard error text is generated</param>
2527
2630
/// <returns>Input value (in case it is valid)</returns>
2528
- private static string validateInput ( string input , string fieldname , string pattern , string errorText = null )
2631
+ private static string ValidateInput ( string input , string fieldname , string pattern , string errorText = null )
2529
2632
{
2530
- return validateInput ( input , fieldname , new string [ ] { pattern } , errorText ) ;
2633
+ return ValidateInput ( input , fieldname , new string [ ] { pattern } , errorText ) ;
2531
2634
}
2532
2635
2533
2636
/// <summary>
@@ -2538,7 +2641,7 @@ private static string validateInput(string input, string fieldname, string patte
2538
2641
/// <param name="patterns">An array of regex patterns to be used for validation</param>
2539
2642
/// <param name="errorText">An optional error text. If null, a standard error text is generated</param>
2540
2643
/// <returns>Input value (in case it is valid)</returns>
2541
- private static string validateInput ( string input , string fieldname , string [ ] patterns , string errorText = null )
2644
+ private static string ValidateInput ( string input , string fieldname , string [ ] patterns , string errorText = null )
2542
2645
{
2543
2646
if ( input == null )
2544
2647
throw new RussiaPaymentOrderException ( $ "The input for '{ fieldname } ' must not be null.") ;
@@ -2569,7 +2672,7 @@ public class OptionalFields
2569
2672
public string Sum
2570
2673
{
2571
2674
get { return _sum ; }
2572
- set { _sum = validateInput ( value , "Sum" , @"^\d{1,18}$" ) ; }
2675
+ set { _sum = ValidateInput ( value , "Sum" , @"^\d{1,18}$" ) ; }
2573
2676
}
2574
2677
2575
2678
private string _purpose ;
@@ -2580,7 +2683,7 @@ public string Sum
2580
2683
public string Purpose
2581
2684
{
2582
2685
get { return _purpose ; }
2583
- set { _purpose = validateInput ( value , "Purpose" , @"^.{1,160}$" ) ; }
2686
+ set { _purpose = ValidateInput ( value , "Purpose" , @"^.{1,160}$" ) ; }
2584
2687
}
2585
2688
2586
2689
private string _payeeInn ;
@@ -2591,7 +2694,7 @@ public string Purpose
2591
2694
public string PayeeINN
2592
2695
{
2593
2696
get { return _payeeInn ; }
2594
- set { _payeeInn = validateInput ( value , "PayeeINN" , @"^.{1,12}$" ) ; }
2697
+ set { _payeeInn = ValidateInput ( value , "PayeeINN" , @"^.{1,12}$" ) ; }
2595
2698
}
2596
2699
2597
2700
private string _payerInn ;
@@ -2602,7 +2705,7 @@ public string PayeeINN
2602
2705
public string PayerINN
2603
2706
{
2604
2707
get { return _payerInn ; }
2605
- set { _payerInn = validateInput ( value , "PayerINN" , @"^.{1,12}$" ) ; }
2708
+ set { _payerInn = ValidateInput ( value , "PayerINN" , @"^.{1,12}$" ) ; }
2606
2709
}
2607
2710
2608
2711
private string _drawerStatus ;
@@ -2613,7 +2716,7 @@ public string PayerINN
2613
2716
public string DrawerStatus
2614
2717
{
2615
2718
get { return _drawerStatus ; }
2616
- set { _drawerStatus = validateInput ( value , "DrawerStatus" , @"^.{1,2}$" ) ; }
2719
+ set { _drawerStatus = ValidateInput ( value , "DrawerStatus" , @"^.{1,2}$" ) ; }
2617
2720
}
2618
2721
2619
2722
private string _kpp ;
@@ -2624,7 +2727,7 @@ public string DrawerStatus
2624
2727
public string KPP
2625
2728
{
2626
2729
get { return _kpp ; }
2627
- set { _kpp = validateInput ( value , "KPP" , @"^.{1,9}$" ) ; }
2730
+ set { _kpp = ValidateInput ( value , "KPP" , @"^.{1,9}$" ) ; }
2628
2731
}
2629
2732
2630
2733
private string _cbc ;
@@ -2635,7 +2738,7 @@ public string KPP
2635
2738
public string CBC
2636
2739
{
2637
2740
get { return _cbc ; }
2638
- set { _cbc = validateInput ( value , "CBC" , @"^.{1,20}$" ) ; }
2741
+ set { _cbc = ValidateInput ( value , "CBC" , @"^.{1,20}$" ) ; }
2639
2742
}
2640
2743
2641
2744
private string _oktmo ;
@@ -2646,7 +2749,7 @@ public string CBC
2646
2749
public string OKTMO
2647
2750
{
2648
2751
get { return _oktmo ; }
2649
- set { _oktmo = validateInput ( value , "OKTMO" , @"^.{1,11}$" ) ; }
2752
+ set { _oktmo = ValidateInput ( value , "OKTMO" , @"^.{1,11}$" ) ; }
2650
2753
}
2651
2754
2652
2755
private string _paytReason ;
@@ -2657,7 +2760,7 @@ public string OKTMO
2657
2760
public string PaytReason
2658
2761
{
2659
2762
get { return _paytReason ; }
2660
- set { _paytReason = validateInput ( value , "PaytReason" , @"^.{1,2}$" ) ; }
2763
+ set { _paytReason = ValidateInput ( value , "PaytReason" , @"^.{1,2}$" ) ; }
2661
2764
}
2662
2765
2663
2766
private string _taxPeriod ;
@@ -2668,7 +2771,7 @@ public string PaytReason
2668
2771
public string TaxPeriod
2669
2772
{
2670
2773
get { return _taxPeriod ; }
2671
- set { _taxPeriod = validateInput ( value , "ТaxPeriod" , @"^.{1,10}$" ) ; }
2774
+ set { _taxPeriod = ValidateInput ( value , "ТaxPeriod" , @"^.{1,10}$" ) ; }
2672
2775
}
2673
2776
2674
2777
private string _docNo ;
@@ -2679,7 +2782,7 @@ public string TaxPeriod
2679
2782
public string DocNo
2680
2783
{
2681
2784
get { return _docNo ; }
2682
- set { _docNo = validateInput ( value , "DocNo" , @"^.{1,15}$" ) ; }
2785
+ set { _docNo = ValidateInput ( value , "DocNo" , @"^.{1,15}$" ) ; }
2683
2786
}
2684
2787
2685
2788
/// <summary>
@@ -2696,7 +2799,7 @@ public string DocNo
2696
2799
public string TaxPaytKind
2697
2800
{
2698
2801
get { return _taxPaytKind ; }
2699
- set { _taxPaytKind = validateInput ( value , "TaxPaytKind" , @"^.{1,2}$" ) ; }
2802
+ set { _taxPaytKind = ValidateInput ( value , "TaxPaytKind" , @"^.{1,2}$" ) ; }
2700
2803
}
2701
2804
2702
2805
/**************************************************************************
@@ -2931,17 +3034,10 @@ public enum CharacterSets
2931
3034
2932
3035
public class RussiaPaymentOrderException : Exception
2933
3036
{
2934
- public RussiaPaymentOrderException ( )
2935
- {
2936
- }
2937
3037
public RussiaPaymentOrderException ( string message )
2938
3038
: base ( message )
2939
3039
{
2940
3040
}
2941
- public RussiaPaymentOrderException ( string message , Exception inner )
2942
- : base ( message , inner )
2943
- {
2944
- }
2945
3041
}
2946
3042
2947
3043
}
0 commit comments