|
|
@@ -86,12 +86,7 @@ namespace MAX
|
|
86
|
86
|
.Append(_vendorId)
|
|
87
|
87
|
.Append("|123451234512345||||||")).ConfigureAwait(false);
|
|
88
|
88
|
|
|
89
|
|
- var response = await ReadMessageAsync().ConfigureAwait(false);
|
|
90
|
|
- if (!response.StartsWith("Hi "))
|
|
91
|
|
- {
|
|
92
|
|
- _logger.LogError("Device authentication failed: {0}", response);
|
|
93
|
|
- return null;
|
|
94
|
|
- }
|
|
|
89
|
+ var response = ExpectResponse(await ReadMessageAsync().ConfigureAwait(false), "Hi");
|
|
95
|
90
|
|
|
96
|
91
|
// Request server RSA key
|
|
97
|
92
|
await WriteMessageAsync(new MessageBuilder().Append("PK")).ConfigureAwait(false);
|
|
|
@@ -104,11 +99,7 @@ namespace MAX
|
|
104
|
99
|
.Append("3D ")
|
|
105
|
100
|
.Append(EncryptRSA(response, BitConverter.ToString(_des.Key).Replace("-", "")))).ConfigureAwait(false);
|
|
106
|
101
|
|
|
107
|
|
- response = await ReadMessageAsync().ConfigureAwait(false);
|
|
108
|
|
- if (!response.StartsWith("OK"))
|
|
109
|
|
- {
|
|
110
|
|
- throw new Exception(String.Format("Key exchange failed: {0}", response));
|
|
111
|
|
- }
|
|
|
102
|
+ response = ExpectResponse(await ReadMessageAsync().ConfigureAwait(false), "OK");
|
|
112
|
103
|
|
|
113
|
104
|
// User authentication
|
|
114
|
105
|
await WriteMessageAsync(new MessageBuilder()
|
|
|
@@ -120,51 +111,40 @@ namespace MAX
|
|
120
|
111
|
.Append("|")
|
|
121
|
112
|
.Append(_password).ToString()))).ConfigureAwait(false);
|
|
122
|
113
|
|
|
123
|
|
- response = Decrypt(await ReadMessageAsync().ConfigureAwait(false));
|
|
124
|
|
- if (response.StartsWith("OK"))
|
|
125
|
|
- {
|
|
126
|
|
- var parts = response.Split('|');
|
|
127
|
|
- var user = new User()
|
|
128
|
|
- {
|
|
129
|
|
- Id = _userId,
|
|
130
|
|
- Username = _username,
|
|
131
|
|
- FirstName = parts[4],
|
|
132
|
|
- Surname = parts[3],
|
|
133
|
|
- Enabled = bool.Parse(parts[6]),
|
|
134
|
|
- Level = (User.UserLevel)int.Parse(parts[1]),
|
|
135
|
|
- System = int.Parse(parts[2]),
|
|
136
|
|
- LastLogin = DateTime.Parse(parts[5])
|
|
137
|
|
- };
|
|
138
|
|
-
|
|
139
|
|
- if (user.Level == User.UserLevel.CustomUser)
|
|
140
|
|
- {
|
|
141
|
|
- user.CanPrintOffline = bool.Parse(parts[7]);
|
|
142
|
|
- user.OfflinePrintValue = decimal.Parse(parts[8]);
|
|
143
|
|
- user.CanPrintOnline = bool.Parse(parts[9]);
|
|
144
|
|
- user.OnlinePrintValue = decimal.Parse(parts[10]);
|
|
145
|
|
- user.CanReprintOffline = bool.Parse(parts[11]);
|
|
146
|
|
- user.OfflineReprintValue = decimal.Parse(parts[12]);
|
|
147
|
|
- user.CanReprintOnline = bool.Parse(parts[13]);
|
|
148
|
|
- user.OnlineReprintValue = decimal.Parse(parts[14]);
|
|
149
|
|
- user.BulkExport = bool.Parse(parts[15]);
|
|
150
|
|
- user.BulkExportMaxValue = decimal.Parse(parts[16]);
|
|
151
|
|
- user.BulkOrder = bool.Parse(parts[17]);
|
|
152
|
|
- user.BulkOrderMaxValue = decimal.Parse(parts[18]);
|
|
153
|
|
- user.BulkViewPins = bool.Parse(parts[19]);
|
|
154
|
|
- user.BulkReExport = bool.Parse(parts[20]);
|
|
155
|
|
- }
|
|
|
114
|
+ response = ExpectResponse(Decrypt(await ReadMessageAsync().ConfigureAwait(false)), "OK");
|
|
156
|
115
|
|
|
157
|
|
- return user;
|
|
158
|
|
- }
|
|
159
|
|
- else if (response.StartsWith("ER"))
|
|
|
116
|
+ var parts = response.Split('|');
|
|
|
117
|
+ var user = new User()
|
|
160
|
118
|
{
|
|
161
|
|
- _logger.LogInformation("User authentication failed: {0}", response);
|
|
162
|
|
- return null;
|
|
163
|
|
- }
|
|
164
|
|
- else
|
|
|
119
|
+ Id = _userId,
|
|
|
120
|
+ Username = _username,
|
|
|
121
|
+ FirstName = parts[4],
|
|
|
122
|
+ Surname = parts[3],
|
|
|
123
|
+ Enabled = bool.Parse(parts[6]),
|
|
|
124
|
+ Level = (User.UserLevel)int.Parse(parts[1]),
|
|
|
125
|
+ System = int.Parse(parts[2]),
|
|
|
126
|
+ LastLogin = DateTime.Parse(parts[5])
|
|
|
127
|
+ };
|
|
|
128
|
+
|
|
|
129
|
+ if (user.Level == User.UserLevel.CustomUser)
|
|
165
|
130
|
{
|
|
166
|
|
- throw new Exception(String.Format("Invalid user information response: {0}", response));
|
|
|
131
|
+ user.CanPrintOffline = bool.Parse(parts[7]);
|
|
|
132
|
+ user.OfflinePrintValue = decimal.Parse(parts[8]);
|
|
|
133
|
+ user.CanPrintOnline = bool.Parse(parts[9]);
|
|
|
134
|
+ user.OnlinePrintValue = decimal.Parse(parts[10]);
|
|
|
135
|
+ user.CanReprintOffline = bool.Parse(parts[11]);
|
|
|
136
|
+ user.OfflineReprintValue = decimal.Parse(parts[12]);
|
|
|
137
|
+ user.CanReprintOnline = bool.Parse(parts[13]);
|
|
|
138
|
+ user.OnlineReprintValue = decimal.Parse(parts[14]);
|
|
|
139
|
+ user.BulkExport = bool.Parse(parts[15]);
|
|
|
140
|
+ user.BulkExportMaxValue = decimal.Parse(parts[16]);
|
|
|
141
|
+ user.BulkOrder = bool.Parse(parts[17]);
|
|
|
142
|
+ user.BulkOrderMaxValue = decimal.Parse(parts[18]);
|
|
|
143
|
+ user.BulkViewPins = bool.Parse(parts[19]);
|
|
|
144
|
+ user.BulkReExport = bool.Parse(parts[20]);
|
|
167
|
145
|
}
|
|
|
146
|
+
|
|
|
147
|
+ return user;
|
|
168
|
148
|
}
|
|
169
|
149
|
|
|
170
|
150
|
public int ConnectTimeout { get; set; }
|
|
|
@@ -262,28 +242,21 @@ namespace MAX
|
|
262
|
242
|
public async Task<Account> GetAccountAsync()
|
|
263
|
243
|
{
|
|
264
|
244
|
await WriteMessageAsync(new MessageBuilder().Append("Acc")).ConfigureAwait(false);
|
|
265
|
|
- var response = Decrypt(await ReadMessageAsync().ConfigureAwait(false));
|
|
266
|
|
- if (response.StartsWith("OK"))
|
|
|
245
|
+ var response = ExpectResponse(Decrypt(await ReadMessageAsync().ConfigureAwait(false)), "OK");
|
|
|
246
|
+ var parts = response.Split('|');
|
|
|
247
|
+ return new Account()
|
|
267
|
248
|
{
|
|
268
|
|
- var parts = response.Split('|');
|
|
269
|
|
- return new Account()
|
|
|
249
|
+ Id = int.Parse(parts[1]),
|
|
|
250
|
+ Name = parts[2],
|
|
|
251
|
+ Balance = decimal.Parse(parts[3]),
|
|
|
252
|
+ Status = (Account.AccountStatus)int.Parse(parts[4]),
|
|
|
253
|
+ Reference = parts[5],
|
|
|
254
|
+ Warehouse = new Warehouse()
|
|
270
|
255
|
{
|
|
271
|
|
- Id = int.Parse(parts[1]),
|
|
272
|
|
- Name = parts[2],
|
|
273
|
|
- Balance = decimal.Parse(parts[3]),
|
|
274
|
|
- Status = (Account.AccountStatus)int.Parse(parts[4]),
|
|
275
|
|
- Reference = parts[5],
|
|
276
|
|
- Warehouse = new Warehouse()
|
|
277
|
|
- {
|
|
278
|
|
- Id = int.Parse(parts[6]),
|
|
279
|
|
- Name = parts[7]
|
|
280
|
|
- }
|
|
281
|
|
- };
|
|
282
|
|
- }
|
|
283
|
|
- else
|
|
284
|
|
- {
|
|
285
|
|
- throw new Exception(String.Format("Invalid account information response: {0}", response));
|
|
286
|
|
- }
|
|
|
256
|
+ Id = int.Parse(parts[6]),
|
|
|
257
|
+ Name = parts[7]
|
|
|
258
|
+ }
|
|
|
259
|
+ };
|
|
287
|
260
|
}
|
|
288
|
261
|
|
|
289
|
262
|
public async Task<ProductCatalogue> GetProductCatalogueAsync(Account account)
|
|
|
@@ -292,51 +265,39 @@ namespace MAX
|
|
292
|
265
|
await WriteMessageAsync(new MessageBuilder()
|
|
293
|
266
|
.Append("Pdt ")
|
|
294
|
267
|
.Append(encryptedWarehouseName)).ConfigureAwait(false);
|
|
295
|
|
- var response = Decrypt(await ReadMessageAsync().ConfigureAwait(false));
|
|
296
|
|
- if (response.StartsWith("OK"))
|
|
297
|
|
- {
|
|
298
|
|
- var parts = response.Split('|');
|
|
299
|
|
- var count = int.Parse(parts[1]);
|
|
|
268
|
+ var response = ExpectResponse(Decrypt(await ReadMessageAsync().ConfigureAwait(false)), "OK");
|
|
300
|
269
|
|
|
301
|
|
- var catalogue = new ProductCatalogue();
|
|
|
270
|
+ var parts = response.Split('|');
|
|
|
271
|
+ var count = int.Parse(parts[1]);
|
|
|
272
|
+
|
|
|
273
|
+ var catalogue = new ProductCatalogue();
|
|
302
|
274
|
|
|
303
|
|
- var listCommand = new MessageBuilder().Append("List ")
|
|
304
|
|
- .Append(encryptedWarehouseName).GetBytes();
|
|
305
|
|
- for (var i = 0; i < count; i++)
|
|
|
275
|
+ var listCommand = new MessageBuilder().Append("List ")
|
|
|
276
|
+ .Append(encryptedWarehouseName).GetBytes();
|
|
|
277
|
+ for (var i = 0; i < count; i++)
|
|
|
278
|
+ {
|
|
|
279
|
+ await _connectionStream.WriteAsync(listCommand, 0, listCommand.Length).ConfigureAwait(false);
|
|
|
280
|
+ response = ExpectResponse(Decrypt(await ReadMessageAsync().ConfigureAwait(false)), "OK");
|
|
|
281
|
+
|
|
|
282
|
+ parts = response.Split('|');
|
|
|
283
|
+ int networkId = int.Parse(parts[4]);
|
|
|
284
|
+ Network network;
|
|
|
285
|
+ if (! catalogue.NetworkMap.TryGetValue(networkId, out network))
|
|
306
|
286
|
{
|
|
307
|
|
- await _connectionStream.WriteAsync(listCommand, 0, listCommand.Length).ConfigureAwait(false);
|
|
308
|
|
- response = Decrypt(await ReadMessageAsync().ConfigureAwait(false));
|
|
309
|
|
- if (response.StartsWith("OK"))
|
|
310
|
|
- {
|
|
311
|
|
- parts = response.Split('|');
|
|
312
|
|
- int networkId = int.Parse(parts[4]);
|
|
313
|
|
- Network network;
|
|
314
|
|
- if (! catalogue.NetworkMap.TryGetValue(networkId, out network))
|
|
315
|
|
- {
|
|
316
|
|
- network = catalogue.AddNetwork(networkId, parts[5]);
|
|
317
|
|
- }
|
|
318
|
|
-
|
|
319
|
|
- catalogue.AddProduct(
|
|
320
|
|
- network: network,
|
|
321
|
|
- id: int.Parse(parts[1]),
|
|
322
|
|
- faceValue: decimal.Parse(parts[2]),
|
|
323
|
|
- description: parts[3],
|
|
324
|
|
- voucherType: (Batch.Vouchertype)int.Parse(parts[6]),
|
|
325
|
|
- discountPercentage: decimal.Parse(parts[7])
|
|
326
|
|
- );
|
|
327
|
|
- }
|
|
328
|
|
- else
|
|
329
|
|
- {
|
|
330
|
|
- throw new Exception(String.Format("Invalid product item response: {0}", response));
|
|
331
|
|
- }
|
|
|
287
|
+ network = catalogue.AddNetwork(networkId, parts[5]);
|
|
332
|
288
|
}
|
|
333
|
289
|
|
|
334
|
|
- return catalogue;
|
|
335
|
|
- }
|
|
336
|
|
- else
|
|
337
|
|
- {
|
|
338
|
|
- throw new Exception(String.Format("Invalid product catalogue response: {0}", response));
|
|
|
290
|
+ catalogue.AddProduct(
|
|
|
291
|
+ network: network,
|
|
|
292
|
+ id: int.Parse(parts[1]),
|
|
|
293
|
+ faceValue: decimal.Parse(parts[2]),
|
|
|
294
|
+ description: parts[3],
|
|
|
295
|
+ voucherType: (Batch.Vouchertype)int.Parse(parts[6]),
|
|
|
296
|
+ discountPercentage: decimal.Parse(parts[7])
|
|
|
297
|
+ );
|
|
339
|
298
|
}
|
|
|
299
|
+
|
|
|
300
|
+ return catalogue;
|
|
340
|
301
|
}
|
|
341
|
302
|
|
|
342
|
303
|
public async Task<OrderResponse> PlaceOrderAsync(int accountId, Product product, int quantity,
|
|
|
@@ -365,42 +326,35 @@ namespace MAX
|
|
365
|
326
|
.Append(internalReference)
|
|
366
|
327
|
.ToString()))).ConfigureAwait(false);
|
|
367
|
328
|
|
|
368
|
|
- var response = Decrypt(await ReadMessageAsync().ConfigureAwait(false));
|
|
|
329
|
+ var response = ExpectResponse(Decrypt(await ReadMessageAsync().ConfigureAwait(false)), "OK");
|
|
369
|
330
|
|
|
370
|
|
- if (response.StartsWith("OK"))
|
|
|
331
|
+ var parts = response.Split('|');
|
|
|
332
|
+ return new OrderResponse()
|
|
371
|
333
|
{
|
|
372
|
|
- var parts = response.Split('|');
|
|
373
|
|
- return new OrderResponse()
|
|
|
334
|
+ Batch = new Batch()
|
|
374
|
335
|
{
|
|
375
|
|
- Batch = new Batch()
|
|
376
|
|
- {
|
|
377
|
|
- Id = int.Parse(parts[1]),
|
|
378
|
|
- OrderReference = parts[2],
|
|
379
|
|
- RequestedQuantity = int.Parse(parts[3]),
|
|
380
|
|
- DeliveredQuantity = int.Parse(parts[4]),
|
|
381
|
|
- Cost = decimal.Parse(parts[5]),
|
|
382
|
|
- InternalReference = internalReference,
|
|
383
|
|
- OrderGuid = orderGuid,
|
|
384
|
|
- AccountId = accountId,
|
|
385
|
|
- VendorId = _vendorId,
|
|
386
|
|
- ProductId = product.Id,
|
|
387
|
|
- ProductDescription = product.Description,
|
|
388
|
|
- VoucherType = product.VoucherType,
|
|
389
|
|
- FaceValue = product.FaceValue,
|
|
390
|
|
- DiscountPercentage = product.DiscountPercentage,
|
|
391
|
|
- NetworkId = product.Network.Id,
|
|
392
|
|
- NetworkName = product.Network.Name,
|
|
393
|
|
- OrderDate = DateTimeOffset.UtcNow,
|
|
394
|
|
- OrderedById = _userId,
|
|
395
|
|
- ReadyForDownload = false
|
|
396
|
|
- },
|
|
397
|
|
- RemainingBalance = decimal.Parse(parts[6])
|
|
398
|
|
- };
|
|
399
|
|
- }
|
|
400
|
|
- else
|
|
401
|
|
- {
|
|
402
|
|
- throw new Exception(string.Format("Invalid order response: {0}", response));
|
|
403
|
|
- }
|
|
|
336
|
+ Id = int.Parse(parts[1]),
|
|
|
337
|
+ OrderReference = parts[2],
|
|
|
338
|
+ RequestedQuantity = int.Parse(parts[3]),
|
|
|
339
|
+ DeliveredQuantity = int.Parse(parts[4]),
|
|
|
340
|
+ Cost = decimal.Parse(parts[5]),
|
|
|
341
|
+ InternalReference = internalReference,
|
|
|
342
|
+ OrderGuid = orderGuid,
|
|
|
343
|
+ AccountId = accountId,
|
|
|
344
|
+ VendorId = _vendorId,
|
|
|
345
|
+ ProductId = product.Id,
|
|
|
346
|
+ ProductDescription = product.Description,
|
|
|
347
|
+ VoucherType = product.VoucherType,
|
|
|
348
|
+ FaceValue = product.FaceValue,
|
|
|
349
|
+ DiscountPercentage = product.DiscountPercentage,
|
|
|
350
|
+ NetworkId = product.Network.Id,
|
|
|
351
|
+ NetworkName = product.Network.Name,
|
|
|
352
|
+ OrderDate = DateTimeOffset.UtcNow,
|
|
|
353
|
+ OrderedById = _userId,
|
|
|
354
|
+ ReadyForDownload = false
|
|
|
355
|
+ },
|
|
|
356
|
+ RemainingBalance = decimal.Parse(parts[6])
|
|
|
357
|
+ };
|
|
404
|
358
|
}
|
|
405
|
359
|
|
|
406
|
360
|
private async Task<byte[]> ReadBytesAsync(int count)
|
|
|
@@ -432,6 +386,31 @@ namespace MAX
|
|
432
|
386
|
|
|
433
|
387
|
public int SendTimeout { get; set; }
|
|
434
|
388
|
|
|
|
389
|
+ private string ExpectResponse(string response, string prefix)
|
|
|
390
|
+ {
|
|
|
391
|
+ if (response.StartsWith("ER"))
|
|
|
392
|
+ {
|
|
|
393
|
+ var parts = response.Split('|');
|
|
|
394
|
+ int errorCode;
|
|
|
395
|
+ if ((parts.Length < 2) || ! int.TryParse(parts[1], out errorCode))
|
|
|
396
|
+ {
|
|
|
397
|
+ errorCode = -1;
|
|
|
398
|
+ }
|
|
|
399
|
+ var message = parts.Length >= 3 ? parts[2] : String.Format("Malformed server error: {0}", response);
|
|
|
400
|
+ _logger.LogError("MAX Error for {0}: {1} (code {2})",
|
|
|
401
|
+ LoginCredentials.Format(_userId, _username, _vendorId, _serialNumber), message, errorCode);
|
|
|
402
|
+ throw new MAXException(errorCode, message);
|
|
|
403
|
+ }
|
|
|
404
|
+ else if (! response.StartsWith(prefix))
|
|
|
405
|
+ {
|
|
|
406
|
+ _logger.LogError("Invalid MAX response for {0}: {1}",
|
|
|
407
|
+ LoginCredentials.Format(_userId, _username, _vendorId, _serialNumber),
|
|
|
408
|
+ response);
|
|
|
409
|
+ throw new Exception(String.Format("Invalid server response: {0}", response));
|
|
|
410
|
+ }
|
|
|
411
|
+ return response;
|
|
|
412
|
+ }
|
|
|
413
|
+
|
|
435
|
414
|
private async Task WriteMessageAsync(MessageBuilder message)
|
|
436
|
415
|
{
|
|
437
|
416
|
byte[] data = message.GetBytes();
|