private void ValidateAlternativeSchemes()
        {
            List <AlternativeScheme> schemesOut = null;

            if (_billIn.AlternativeSchemes != null)
            {
                schemesOut = new List <AlternativeScheme>();

                foreach (AlternativeScheme schemeIn in _billIn.AlternativeSchemes)
                {
                    AlternativeScheme schemeOut = new AlternativeScheme
                    {
                        Name        = schemeIn.Name.Trimmed(),
                        Instruction = schemeIn.Instruction.Trimmed()
                    };
                    if ((schemeOut.Name != null || schemeOut.Instruction != null) &&
                        ValidateLength(schemeOut.Instruction, 100, ValidationConstants.FieldAlternativeSchemes))
                    {
                        schemesOut.Add(schemeOut);
                    }
                }

                if (schemesOut.Count > 0)
                {
                    if (schemesOut.Count > 2)
                    {
                        _validationResult.AddMessage(MessageType.Error, ValidationConstants.FieldAlternativeSchemes, ValidationConstants.KeyAltSchemeExceeded);
                        schemesOut = schemesOut.GetRange(0, 2);
                    }
                }
                else
                {
                    schemesOut = null;
                }
            }
            _billOut.AlternativeSchemes = schemesOut;
        }
        /// <summary>
        /// Decodes the specified text and returns the bill data.
        /// <para>
        /// The text is assumed to be in the data structured for the QR code defined by SIX.
        /// </para>
        /// <para>
        /// The returned data is only minimally validated. The format and the header are
        /// checked. Amount and date must be parsable.
        /// </para>
        /// </summary>
        /// <param name="text">The text to decode.</param>
        /// <returns>The decoded bill data.</returns>
        /// <exception cref="QRBillValidationException">The text is in an invalid format.</exception>
        public static Bill Decode(string text)
        {
            string[] lines = SplitLines(text);
            if (lines.Length < 32 || lines.Length > 34)
            {
                ThrowSingleValidationError(ValidationConstants.FieldQrType, ValidationConstants.KeyValidDataStructure);
            }

            if ("SPC" != lines[0])
            {
                ThrowSingleValidationError(ValidationConstants.FieldQrType, ValidationConstants.KeyValidDataStructure);
            }

            if ("0200" != lines[1])
            {
                ThrowSingleValidationError(ValidationConstants.FieldVersion, ValidationConstants.KeySupportedVersion);
            }

            if ("1" != lines[2])
            {
                ThrowSingleValidationError(ValidationConstants.FieldCodingType, ValidationConstants.KeySupportedCodingType);
            }

            Bill billData = new Bill
            {
                Version = Bill.QrBillStandardVersion.V2_0,

                Account = lines[3],

                Creditor = DecodeAddress(lines, 4, false)
            };

            if (lines[18].Length > 0)
            {
                if (decimal.TryParse(lines[18], NumberStyles.Number, AmountNumberInfo, out decimal amount))
                {
                    billData.Amount = amount;
                }
                else
                {
                    ThrowSingleValidationError(ValidationConstants.FieldAmount, ValidationConstants.KeyValidNumber);
                }
            }
            else
            {
                billData.Amount = null;
            }

            billData.Currency = lines[19];

            billData.Debtor = DecodeAddress(lines, 20, true);

            // reference type is ignored (line 27)
            billData.Reference           = lines[28];
            billData.UnstructuredMessage = lines[29];
            if ("EPD" != lines[30])
            {
                ThrowSingleValidationError(ValidationConstants.FieldTrailer, ValidationConstants.KeyValidDataStructure);
            }

            billData.BillInformation = lines[31];

            List <AlternativeScheme> alternativeSchemes = null;
            int numSchemes = lines.Length - 32;

            if (numSchemes > 0)
            {
                alternativeSchemes = new List <AlternativeScheme>();
                for (int i = 0; i < numSchemes; i++)
                {
                    AlternativeScheme scheme = new AlternativeScheme
                    {
                        Instruction = lines[32 + i]
                    };
                    alternativeSchemes.Add(scheme);
                }
            }
            billData.AlternativeSchemes = alternativeSchemes;

            return(billData);
        }
Exemple #3
0
        /// <summary>
        /// Decodes the specified text and returns the bill data.
        /// <para>
        /// The text is assumed to be in the data structured for the QR code defined by SIX.
        /// </para>
        /// <para>
        /// The returned data is only minimally validated. The format and the header are
        /// checked. Amount and date must be parsable.
        /// </para>
        /// </summary>
        /// <param name="text">The text to decode.</param>
        /// <returns>The decoded bill data.</returns>
        /// <exception cref="QRBillValidationException">The text is in an invalid format.</exception>
        public static Bill Decode(string text)
        {
            var lines = SplitLines(text);

            if (lines.Count < 31 || lines.Count > 34)
            {
                // A line feed at the end is illegal (cf 4.2.3) but found in practice. Don't be too strict.
                if (!(lines.Count == 35 && lines[34].Length == 0))
                {
                    ThrowSingleValidationError(ValidationConstants.FieldQrType, ValidationConstants.KeyDataStructureInvalid);
                }
            }

            if ("SPC" != lines[0])
            {
                ThrowSingleValidationError(ValidationConstants.FieldQrType, ValidationConstants.KeyDataStructureInvalid);
            }

            if (!ValidVersion.IsMatch(lines[1]))
            {
                ThrowSingleValidationError(ValidationConstants.FieldVersion, ValidationConstants.KeyVersionUnsupported);
            }

            if ("1" != lines[2])
            {
                ThrowSingleValidationError(ValidationConstants.FieldCodingType, ValidationConstants.KeyCodingTypeUnsupported);
            }

            var billData = new Bill
            {
                Version = Bill.QrBillStandardVersion.V2_0,

                Account = lines[3],

                Creditor = DecodeAddress(lines, 4, false)
            };

            if (lines[18].Length > 0)
            {
                if (decimal.TryParse(lines[18], NumberStyles.Number, AmountNumberInfo, out var amount))
                {
                    billData.Amount = amount;
                }
                else
                {
                    ThrowSingleValidationError(ValidationConstants.FieldAmount, ValidationConstants.KeyNumberInvalid);
                }
            }
            else
            {
                billData.Amount = null;
            }

            billData.Currency = lines[19];

            billData.Debtor = DecodeAddress(lines, 20, true);

            // Set reference type and reference in reverse order
            // to retain reference type (as it is updated by setting 'Reference')
            billData.Reference           = lines[28];
            billData.ReferenceType       = lines[27];
            billData.UnstructuredMessage = lines[29];
            if ("EPD" != lines[30])
            {
                ThrowSingleValidationError(ValidationConstants.FieldTrailer, ValidationConstants.KeyDataStructureInvalid);
            }

            billData.BillInformation = lines.Count > 31 ? lines[31] : "";

            List <AlternativeScheme> alternativeSchemes = null;
            var numSchemes = lines.Count - 32;

            // skip empty schemes at end (due to invalid trailing line feed)
            if (numSchemes > 0 && lines[32 + numSchemes - 1].Length == 0)
            {
                numSchemes--;
            }
            if (numSchemes > 0)
            {
                alternativeSchemes = new List <AlternativeScheme>();
                for (var i = 0; i < numSchemes; i++)
                {
                    var scheme = new AlternativeScheme
                    {
                        Instruction = lines[32 + i]
                    };
                    alternativeSchemes.Add(scheme);
                }
            }
            billData.AlternativeSchemes = alternativeSchemes;

            return(billData);
        }