public ActionType(XE actionType) { if (actionType == null) { throw new ArgumentNullException(nameof(actionType)); } var tidAttribute = actionType.Attribute(C.tid); var tidAttributeValue = int.Parse(tidAttribute.Value); if (!Enum.IsDefined(typeof(TransactionId), tidAttributeValue)) { throw new ArgumentException($"Unknown {nameof(C.tid)} '{tidAttributeValue}'"); } Id = (TransactionId)int.Parse(tidAttribute.Value); var success = TidToString.TryGetValue(Id, out var value); if (!success) { throw new ArgumentException($"{nameof(TidToString)} mapping doesn't contain {nameof(TransactionId)} with value {tidAttribute.Value}"); } if (value != actionType.Value) { throw new ArgumentException($"Expected Action Type element to have value '{value}'. Was '{actionType.Value}'"); } // UNDOCUMENTED: type or length of Action/Type content. We can only // assume an Ax of sufficient length to represent every // TransactionId in textual form. FieldTypes.AssertA25(actionType.Value); }
// If an error occurs and response code isn't "Approved", form of // response is // // <ResponseCode hostCode="20">D</ResponseCode> // <DisplayMessage>Missing SVAN Element</DisplayMessage> // // A successful response code has the form <ResponseCode>A</ResponseCode> // and sometimes, but not always, contains DisplayMessage element. public ResponseCode(XE responseCode) { // POS API spec, Page 19: according to DisplayMessage documentation, // additional response codes include E, V, and P. Those should be // shown to POS terminal user. We haven't encountered these codes // and thus doesn't parse those. var value = responseCode.Value; FieldTypes.AssertA1(value); if (value == "A") { Value = Kind.Approved; } else if (value == "D") { var hostCodeAttribute = ExpectAttribute(responseCode, C.hostCode); HostCode = hostCodeAttribute.Value; Value = Kind.DataCenterInitiatedError; } else { throw new ArgumentException($"Unsupported {nameof(Kind)} value: '{value}'"); } }
public CheckNumber(string value) { // UNDOCUMENTED: CheckNumber element is missing from POS API spec, // Page 19, Element Definitions. We assume CheckNumber is identical // to the CheckNumber part of TraceID which is N4. Value = FieldTypes.AssertN4(value); }
public ExchangeRate(string value) { Value = FieldTypes.AssertDecimal(value); if (Value <= 0) { throw new ArgumentException($"{nameof(ExchangeRate)} rate must be positive. Was {value}"); } }
public Points(string value) { Value = FieldTypes.AssertDecimal(value); if (Value < 0) { throw new ArgumentException($"{nameof(Points)} must be positive. Was {value}"); } }
public RequestCode(string value) { FieldTypes.AssertA100(value); if (!Enum.IsDefined(typeof(TransactionKind), value)) { throw new ArgumentException($"Unknown value '{value}'"); } Value = (TransactionKind)Enum.Parse(typeof(TransactionKind), value); }
public Transmission(string value) { FieldTypes.AssertA1(value); Value = value switch { "n" => Kind.Normal, "y" => Kind.Retransmission, _ => throw new ArgumentException($"Unsupported {nameof(Kind)} value: '{value}'") }; }
public Language(string value) { FieldTypes.AssertA5(value); if (value != Kind.EnUs) { throw new ArgumentException($"Expected '{Kind.EnUs}'. Was {value}"); } Value = value; }
public Currency(string value) { FieldTypes.AssertA3(value); // Not only must value not be null or whitespace and satisfy A3, // only Kind is allowed. if (!Enum.IsDefined(typeof(Kind), value)) { throw new ArgumentException($"Error parsing {nameof(Kind)}: {value}"); } Value = (Kind)Enum.Parse(typeof(Kind), value); }
public ItemType(string value) { // UNDOCUMENTED: according to POS API spec, Page 21, ItemType is of // type XML with no field type definition. We've yet to encounter // any XML beneath the ItemType element. In the responses we've // encountered, the format is <ItemType>T</ItemType>. FieldTypes.AssertA1(value); Value = value switch { "M" => Kind.MenuOrSalesItem, "D" => Kind.Discount, "S" => Kind.ServiceCharge, "T" => Kind.Tender, _ => throw new ArgumentException($"Unsupported {nameof(Kind)} value: '{value}'"), }; }
public HostVersion(string value) { // UNDOCUMENTED: POS API spec, Page 18, designates hostVersion // attribute as A8. "1.00.8" example in documentation supports this // field type, but time seems to have surpassed documentation. // Current hostVersion is "9.1.0000.2301" which doesn't fit in A8. // We assume field is A16. Value = FieldTypes.AssertA16(value); // UNDOCUMENTED: Oracle's versioning strategy is unclear. Which // component of the version number, if any, would change to signal a // breaking change? For now, we hardcode version to force an // expclit failure on Oracle update. const string hostVersion = "9.1.0000.2301"; if (value != hostVersion) { throw new ArgumentException($"Oracle updated POS host version from '{hostVersion}' to '{value}'"); } }
public TraceId(string value) { // UNDOCUMENTED: while POS API spec, Page 23 designates TraceID as // A25, examples show it as A19. Possibly for Oracle to change // TraceID in the future without updating the schema. FieldTypes.AssertA25(value); // Date part of TraceID doesn't follow the pattern used with // LocalDate and BusinessDate. For TraceID, year is two characters // only. Since TraceID is an element on its own and not a field type // (Ax, Nx, ...), its regular expression is defined inline and not // with FieldTypes. const string pattern = @"^(?<year>\d{2})(?<month>\d{2})(?<day>\d{2})(?<hour>\d{2})(?<minute>\d{2})(?<second>\d{2})(?<retransmit>.{1})(?<sequence>\d{2})(?<checkNumber>\d{4})$"; var re = new Regex(pattern); var m = re.Match(value); if (!m.Success) { throw new ArgumentException($"{nameof(value)} must match pattern: {pattern}. Was '{value}'"); } var date = FieldTypes.AssertDate($"20{m.Groups["year"].Value}{m.Groups["month"].Value}{m.Groups["day"].Value}"); var time = FieldTypes.AssertTime($"{m.Groups["hour"].Value}{m.Groups["minute"].Value}{m.Groups["second"].Value}"); Timestamp = date.Add(time); var retransmit = m.Groups["retransmit"].Value; if (!(retransmit == "N" || retransmit == "R")) { throw new ArgumentException($"Retransmit must be either 'N' or 'R'. Was '{retransmit}'"); } Kind = retransmit == "N" ? TransmissionKind.Normal : TransmissionKind.Retransmit; var sequence = int.Parse(m.Groups["sequence"].Value); Sequence = new SequenceNumber(sequence); var checkNumber = int.Parse(m.Groups["checkNumber"].Value); CheckNumber = new CheckNumber(checkNumber); }
public TerminalId(string value) { FieldTypes.AssertN9(value); Value = int.Parse(value); }
public TransactionEmployee(string value) { Value = FieldTypes.AssertN9(value); }
public RevenueCenter(string value) { Value = FieldTypes.AssertN9(value); }