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); }
/// <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); }