소스 검색

Add log summarisation functionality so that we can avoid so many queries on the entire Logs table.
Speed up PopulateGrid() dramatically by making use of summarised log information.
Add SIMULATE_HDD_SERIAL conditional compilation blocks.
Fix 'Retry' log field not being uploaded to server.
Better HTTP error handling.

Brett Credo 8 년 전
부모
커밋
41ff233365

+ 22 - 9
BulkPrinting/BulkPrinting/BatchDownloader.cs

@@ -12,12 +12,14 @@ namespace BulkPrinting
12 12
 
13 13
         private DBHelper _db;
14 14
         private Action _refreshAction;
15
+        private Action _downloadLogSummarisationAction;
15 16
         private bool _checkForNewBatches;
16 17
 
17
-        public BatchDownloader(DBHelper db, Action refreshAction)
18
+        public BatchDownloader(DBHelper db, Action refreshAction, Action downloadedLogSummarisationAction)
18 19
         {
19 20
             _db = db;
20 21
             _refreshAction = refreshAction;
22
+            _downloadLogSummarisationAction = downloadedLogSummarisationAction;
21 23
         }
22 24
 
23 25
         public void CheckForNewBatches()
@@ -39,6 +41,8 @@ namespace BulkPrinting
39 41
             {
40 42
                 if (Globals.SessionMode == SessionModes.Online)
41 43
                 {
44
+                    var gotErrors = false;
45
+
42 46
                     Log.Debug("Checking for downloads");
43 47
 
44 48
                     // Check for new batches if required.
@@ -76,6 +80,7 @@ namespace BulkPrinting
76 80
                             else
77 81
                             {
78 82
                                 // Error, so leave skipNewBatchCheck unchanged.
83
+                                gotErrors = true;
79 84
                                 break;
80 85
                             }
81 86
 
@@ -87,10 +92,11 @@ namespace BulkPrinting
87 92
                     }
88 93
                     catch (Exception e)
89 94
                     {
95
+                        gotErrors = true;
90 96
                         Log.Error(e, "Error while downloading batch list");
91 97
                     }
92 98
 
93
-                    // TODO: throttle or detect changes better
99
+                    // TODO: throttle
94 100
                     if (!isCancelled && doRefresh)
95 101
                     {
96 102
                         doRefresh = false;
@@ -218,20 +224,23 @@ namespace BulkPrinting
218 224
 
219 225
                                             doRefresh = true;
220 226
                                         }
221
-                                        // else retry later
227
+                                        else
228
+                                        {
229
+                                            gotErrors = true;
230
+                                        }
222 231
                                     }
223 232
                                     catch (Exception e)
224 233
                                     {
234
+                                        gotErrors = true;
225 235
                                         Log.Error(e, "Error while downloading vouchers for batch {0}", batchId);
226 236
                                     }
227 237
 
228
-                                    /* TODO: throttle or detect changes better
238
+                                    // TODO: throttle
229 239
                                     if (!isCancelled && doRefresh)
230 240
                                     {
231 241
                                         doRefresh = false;
232 242
                                         _refreshAction();
233 243
                                     }
234
-                                    */
235 244
 
236 245
                                     lock(_lock)
237 246
                                     {
@@ -243,14 +252,18 @@ namespace BulkPrinting
243 252
                     }
244 253
                     catch (Exception e)
245 254
                     {
255
+                        gotErrors = true;
246 256
                         Log.Error(e, "Error while downloading vouchers");
247 257
                     }
248 258
 
249
-                    // TODO: throttle or detect changes better
250
-                    if (!isCancelled && doRefresh)
259
+                    if (! isCancelled && ! gotErrors)
251 260
                     {
252
-                        doRefresh = false;
253
-                        _refreshAction();
261
+                        Log.Debug("Up to date");
262
+
263
+                        // If we weren't cancelled and didn't get any errors then we should be synchronised with the server,
264
+                        // so it is now safe to summarise any downloaded logs as the corresponding batches and vouchers should
265
+                        // all be present.
266
+                        _downloadLogSummarisationAction();
254 267
                     }
255 268
                 }
256 269
                 else

+ 69 - 53
BulkPrinting/BulkPrinting/BatchForm.cs

@@ -12,6 +12,7 @@ namespace BulkPrinting
12 12
     public partial class BatchForm : ObservedForm
13 13
     {
14 14
         private BatchDownloader BatchDownloader;
15
+        private DownloadedLogSummariser DownloadedLogSummariser;
15 16
 
16 17
         public BatchForm()
17 18
         {
@@ -27,39 +28,6 @@ namespace BulkPrinting
27 28
 
28 29
         public void PopulateGrid()
29 30
         {
30
-            Dictionary<int, BatchEvent> BatchEvents = new Dictionary<int, BatchEvent>();
31
-            string Sql = "Select COUNT(v.BatchId) AS Total, v.BatchId,l.EventType,l.Retry FROM Voucher v LEFT JOIN Logs l on v.Id = l.VoucherId WHERE l.EventType in (@printevent,@exportevent) GROUP BY v.BatchId,l.EventType,l.Retry ORDER BY BatchId";
32
-            using (var Command = Globals.DB.CreateCommand(Sql,
33
-                new SQLiteParameter("@printevent", VendorEvent.VendorEventType.PrintVoucher),
34
-                new SQLiteParameter("@exportevent", VendorEvent.VendorEventType.ExportVoucher)))
35
-            {
36
-                using (SQLiteDataReader read = Command.ExecuteReader())
37
-                {
38
-                    while (read.Read())
39
-                    {
40
-                        int BatchId = int.Parse(read["BatchId"].ToString());
41
-                        if (!BatchEvents.ContainsKey(BatchId))
42
-                        {
43
-                            BatchEvents.Add(BatchId, new BatchEvent());
44
-                        }
45
-                        if (read["EventType"].ToString() == "6")
46
-                        {
47
-                            if (read["Retry"].ToString() == "True")
48
-                            {
49
-                                BatchEvents[BatchId].ReprintCount += int.Parse(read["Total"].ToString());
50
-                            }
51
-                            else
52
-                            {
53
-                                BatchEvents[BatchId].PrintCount += int.Parse(read["Total"].ToString());
54
-                            }
55
-                        }
56
-                        else if (read["EventType"].ToString() == "8")
57
-                        {
58
-                            BatchEvents[BatchId].ExportCount += int.Parse(read["Total"].ToString());
59
-                        }
60
-                    }
61
-                }
62
-            }
63 31
             bool CanOrder = Utility.CheckUserAccess(Utility.UserPermissions.BulkOrder);
64 32
             bool CanExport = Utility.CheckUserAccess(Utility.UserPermissions.BulkExport);
65 33
             dgvBatches.Rows.Clear();
@@ -79,12 +47,11 @@ namespace BulkPrinting
79 47
             dgvBatches.Columns.Add("Downloaded", "Downloaded");
80 48
             dgvBatches.Columns.Add("PrintedQuantity", "Quantity Printed");
81 49
             if (CanExport) dgvBatches.Columns.Add("Exported", "Exported Batch");
82
-            Sql = "Select Id,OrderDate,OrderReference,InternalReference,NetworkName,ProductDescription,VoucherType,FaceValue,RequestedQuantity,DeliveredQuantity,ReadyForDownload,Downloaded From Batch WHERE OrderDate BETWEEN @startdate AND @enddate";
50
+            var Sql = "Select Id,OrderDate,OrderReference,InternalReference,NetworkName,ProductDescription,VoucherType,FaceValue,RequestedQuantity,DeliveredQuantity,ReadyForDownload,Downloaded,PrintCount,ReprintCount,ExportCount,ReExportCount From Batch WHERE OrderDate BETWEEN @startdate AND @enddate";
83 51
 
84 52
             //Sql = "Select Id,OrderDate,OrderReference,InternalReference,NetworkName,ProductDescription,VoucherType,FaceValue,RequestedQuantity,DeliveredQuantity,ReadyForDownload,Downloaded,(SELECT COUNT(*) FROM Voucher WHERE Voucher.BatchId=Batch.Id) AS VoucherCount From Batch WHERE OrderDate BETWEEN @startdate AND @enddate";
85 53
             //dgvBatches.Columns.Add("VoucherCount", "Voucher Count");
86 54
 
87
-
88 55
             CultureInfo IVC = CultureInfo.InvariantCulture;
89 56
             using (var Command = Globals.DB.CreateCommand(Sql,
90 57
                 new SQLiteParameter("@startdate", dtpFilterStartDate.Value.Date.ToString("yyyy-MM-dd 00:00:00", IVC)),
@@ -96,44 +63,45 @@ namespace BulkPrinting
96 63
                     while (read.Read())
97 64
                     {
98 65
                         int BatchId = int.Parse(read["Id"].ToString());
99
-                        if (!BatchEvents.ContainsKey(BatchId))
100
-                        { //For batches with no events
101
-                            BatchEvents.Add(BatchId, new BatchEvent());
102
-                        }
103 66
                         int DeliveredQuantity = int.Parse(read["DeliveredQuantity"].ToString());
67
+                        int PrintCount = (int)read["PrintCount"];
68
+                        int ReprintCount = (int)read["ReprintCount"];
69
+                        int ExportCount = (int)read["ExportCount"];
70
+                        int ReExportCount = (int)read["ReExportCount"];
71
+
104 72
 
105 73
                         //Filters to exclude rows that don't match
106 74
                         if (rdoFilterPrinted.Checked)
107 75
                         {
108
-                            if (BatchEvents[BatchId].PrintCount == 0)
76
+                            if (PrintCount == 0)
109 77
                             {
110 78
                                 continue;
111 79
                             }
112 80
                         }
113 81
                         if (rdoFilterUnprinted.Checked)
114 82
                         {
115
-                            if (BatchEvents[BatchId].PrintCount >= DeliveredQuantity)
83
+                            if (PrintCount >= DeliveredQuantity)
116 84
                             {
117 85
                                 continue;
118 86
                             }
119 87
                         }
120 88
                         if (rdoFilterReprinted.Checked)
121 89
                         {
122
-                            if (BatchEvents[BatchId].ReprintCount == 0)
90
+                            if (ReprintCount == 0)
123 91
                             {
124 92
                                 continue;
125 93
                             }
126 94
                         }
127 95
                         if (rdoFilterExported.Checked)
128 96
                         {
129
-                            if (BatchEvents[BatchId].ExportCount == 0)
97
+                            if (ExportCount == 0)
130 98
                             {
131 99
                                 continue;
132 100
                             }
133 101
                         }
134 102
                         else
135 103
                         {
136
-                            if (BatchEvents[BatchId].ExportCount > 0)
104
+                            if (ExportCount > 0)
137 105
                             {
138 106
                                 continue;
139 107
                             }
@@ -163,10 +131,10 @@ namespace BulkPrinting
163 131
                             BatchRow.Add(((bool)read["ReadyForDownload"] == true ? "Yes" : "No"));
164 132
 
165 133
                         BatchRow.Add((bool)read["Downloaded"] ? "Yes" : "No");
166
-                        BatchRow.Add((object)BatchEvents[BatchId].PrintCount);
134
+                        BatchRow.Add(PrintCount);
167 135
 
168 136
                         if (CanExport)
169
-                            BatchRow.Add((BatchEvents[BatchId].ExportCount > 0 ? "Exported" : ""));
137
+                            BatchRow.Add(ExportCount > 0 ? "Exported" : "");
170 138
 
171 139
                         //BatchRow.Add(read["VoucherCount"]);
172 140
 
@@ -254,13 +222,22 @@ namespace BulkPrinting
254 222
             Globals.OpenBatches = new List<int>();
255 223
 
256 224
             var hwnd = new System.Runtime.InteropServices.HandleRef(this, Handle);
257
-            BatchDownloader = new BatchDownloader(Globals.DB, () =>
258
-            {
259
-                // DO NOT use Invoke as this can cause a deadlock if we are attempting to join the BatchDownloader after a cancel.
260
-                // Also, use PostMessage rather than SendMessage as PostMessage doesn't wait for the message to be processed and
261
-                // therefore won't block.
262
-                Utility.PostMessage(hwnd, Utility.WM_USER, IntPtr.Zero, IntPtr.Zero);
263
-            });
225
+            BatchDownloader = new BatchDownloader(
226
+                Globals.DB,
227
+                () =>
228
+                {
229
+                    // Refresh grid
230
+
231
+                    // DO NOT use Invoke as this can cause a deadlock if we are attempting to join the BatchDownloader after a cancel.
232
+                    // Also, use PostMessage rather than SendMessage as PostMessage doesn't wait for the message to be processed and
233
+                    // therefore won't block.
234
+                    Utility.PostMessage(hwnd, Utility.WM_USER, IntPtr.Zero, IntPtr.Zero);
235
+                },
236
+                () =>
237
+                {
238
+                    // Trigger download log summarisation
239
+                    Utility.PostMessage(hwnd, Utility.WM_USER + 1, IntPtr.Zero, IntPtr.Zero);
240
+                });
264 241
             BatchDownloader.Start();
265 242
 
266 243
             Utility.InitialiseUserLimits(Globals.DB);
@@ -277,9 +254,36 @@ namespace BulkPrinting
277 254
                 PopulateGrid();
278 255
                 return;
279 256
             }
257
+            else if (m.Msg == Utility.WM_USER + 1)
258
+            {
259
+                TriggerDownloadedLogSummarisation();
260
+                return;
261
+            }
280 262
             base.WndProc(ref m);
281 263
         }
282 264
 
265
+        private void TriggerDownloadedLogSummarisation()
266
+        {
267
+            if (DownloadedLogSummariser == null)
268
+            {
269
+                var hwnd = new System.Runtime.InteropServices.HandleRef(this, Handle);
270
+
271
+                DownloadedLogSummariser = new DownloadedLogSummariser(
272
+                    Globals.DB,
273
+                    () =>
274
+                    {
275
+                        // Refresh grid
276
+
277
+                        // DO NOT use Invoke as this can cause a deadlock if we are attempting to join the BatchDownloader after a cancel.
278
+                        // Also, use PostMessage rather than SendMessage as PostMessage doesn't wait for the message to be processed and
279
+                        // therefore won't block.
280
+                        Utility.PostMessage(hwnd, Utility.WM_USER, IntPtr.Zero, IntPtr.Zero);
281
+                    });
282
+
283
+                DownloadedLogSummariser.Start();
284
+            }
285
+        }
286
+
283 287
         public void NewBatchAvailable()
284 288
         {
285 289
             BatchDownloader.CheckForNewBatches();
@@ -368,8 +372,20 @@ namespace BulkPrinting
368 372
             if (BatchDownloader != null)
369 373
             {
370 374
                 BatchDownloader.Cancel();
375
+            }
376
+            if (DownloadedLogSummariser != null)
377
+            {
378
+                DownloadedLogSummariser.Cancel();
379
+            }
380
+
381
+            if (BatchDownloader != null)
382
+            {
371 383
                 BatchDownloader.Join();
372 384
             }
385
+            if (DownloadedLogSummariser != null)
386
+            {
387
+                DownloadedLogSummariser.Join();
388
+            }
373 389
 
374 390
             Utility.Logout();
375 391
         }

+ 2 - 1
BulkPrinting/BulkPrinting/BulkPrinting.csproj

@@ -79,7 +79,7 @@
79 79
   <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
80 80
     <DebugSymbols>true</DebugSymbols>
81 81
     <OutputPath>bin\x86\Debug\</OutputPath>
82
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
82
+    <DefineConstants>TRACE;DEBUG</DefineConstants>
83 83
     <DebugType>full</DebugType>
84 84
     <PlatformTarget>x86</PlatformTarget>
85 85
     <ErrorReport>prompt</ErrorReport>
@@ -157,6 +157,7 @@
157 157
     <Compile Include="BatchDownloader.cs" />
158 158
     <Compile Include="Configuration.cs" />
159 159
     <Compile Include="DBHelper.cs" />
160
+    <Compile Include="DownloadedLogSummariser.cs" />
160 161
     <Compile Include="ExportForm.cs">
161 162
       <SubType>Form</SubType>
162 163
     </Compile>

+ 114 - 0
BulkPrinting/BulkPrinting/DownloadedLogSummariser.cs

@@ -0,0 +1,114 @@
1
+using System;
2
+using System.Threading;
3
+
4
+namespace BulkPrinting
5
+{
6
+    public class DownloadedLogSummariser : ThreadHelper
7
+    {
8
+        private const int _retryInterval = 30000;
9
+
10
+        private DBHelper _db;
11
+        private Action _refreshAction;
12
+
13
+        public DownloadedLogSummariser(DBHelper db, Action refreshAction)
14
+        {
15
+            _db = db;
16
+            _refreshAction = refreshAction;
17
+        }
18
+
19
+        protected override void Run()
20
+        {
21
+            bool isCancelled = false;
22
+            while (!isCancelled)
23
+            {
24
+                bool doRefresh = false;
25
+
26
+                while (!isCancelled)
27
+                {
28
+                    lock (_db.WriteLock)
29
+                    {
30
+                        using (var trans = _db.BeginTransaction())
31
+                        {
32
+                            using (var selectCommand = _db.CreateCommand(
33
+                                "SELECT l.*, v.BatchId FROM Logs l " +
34
+                                    "LEFT JOIN Voucher v ON l.VoucherId=v.Id " +
35
+                                "WHERE Summarised=0 " +
36
+                                "LIMIT 1000",
37
+                                trans))
38
+                            using (var updateLogsCommand = _db.CreateCommand(
39
+                                "UPDATE Logs SET Summarised=1 WHERE Id=@Id"))
40
+                            using (var updateVoucherCommand = Utility.CreateVoucherEventCountUpdateCommand(_db, trans))
41
+                            using (var updateBatchCommand = Utility.CreateBatchEventCountUpdateCommand(_db, trans))
42
+                            {
43
+                                updateLogsCommand.Parameters.AddWithValue("@Id", null);
44
+
45
+                                using (var reader = selectCommand.ExecuteReader())
46
+                                {
47
+                                    var rowCount = 0;
48
+                                    while (reader.Read())
49
+                                    {
50
+                                        rowCount++;
51
+                                        doRefresh = true;
52
+
53
+                                        int printCountDelta, reprintCountDelta, exportCountDelta, reExportCountDelta;
54
+                                        if ((reader["VoucherId"] != null) &&
55
+                                            Utility.CalculateEventCountDeltas(
56
+                                            (VendorEvent.VendorEventType)int.Parse((string)reader["EventType"]),
57
+                                            (bool)reader["Retry"],
58
+                                            out printCountDelta,
59
+                                            out reprintCountDelta,
60
+                                            out exportCountDelta,
61
+                                            out reExportCountDelta))
62
+                                        {
63
+                                            Utility.ExecuteEventCountUpdateQuery(updateVoucherCommand, (int)reader["VoucherId"],
64
+                                                printCountDelta, reprintCountDelta, exportCountDelta, reExportCountDelta);
65
+
66
+                                            if (reader["BatchId"] != null)
67
+                                            {
68
+                                                Utility.ExecuteEventCountUpdateQuery(updateBatchCommand, (int)reader["BatchId"],
69
+                                                    printCountDelta, reprintCountDelta, exportCountDelta, reExportCountDelta);
70
+                                            }
71
+                                        }
72
+
73
+                                        var logId = (long)reader["Id"];
74
+
75
+                                        updateLogsCommand.Parameters["@Id"].Value = (int)logId;
76
+                                        updateLogsCommand.ExecuteNonQuery();
77
+                                    }
78
+
79
+                                    if (rowCount == 0)
80
+                                    {
81
+                                        break;
82
+                                    }
83
+                                }
84
+                            }
85
+
86
+                            trans.Commit();
87
+                        }
88
+                    }
89
+
90
+                    lock (_lock)
91
+                    {
92
+                        isCancelled = _cancelled;
93
+                    }
94
+                }
95
+
96
+                if (! isCancelled && doRefresh)
97
+                {
98
+                    doRefresh = false;
99
+                    _refreshAction();
100
+                }
101
+
102
+                // We sleep and try again on the offchance that we got triggered too early.
103
+                lock (_lock)
104
+                {
105
+                    if (!_cancelled)
106
+                    {
107
+                        Monitor.Wait(_lock, _retryInterval);
108
+                    }
109
+                    isCancelled = _cancelled;
110
+                }
111
+            }
112
+        }
113
+    }
114
+}

+ 1 - 0
BulkPrinting/BulkPrinting/ExportForm.cs

@@ -198,6 +198,7 @@ namespace BulkPrinting
198 198
                                         var ExportEvent = new EventLog();
199 199
                                         ExportEvent.EventType = VendorEvent.VendorEventType.ExportVoucher;
200 200
                                         ExportEvent.VoucherId = int.Parse(read["Id"].ToString());
201
+                                        ExportEvent.BatchId = ExportBatch.Id;
201 202
                                         ExportEvent.Retry = (read["Exports"].ToString() != "0");
202 203
                                         LogEvents.Add(ExportEvent);
203 204
                                     }

+ 2 - 2
BulkPrinting/BulkPrinting/LogDownloader.cs

@@ -30,8 +30,8 @@ namespace BulkPrinting
30 30
                         using (var trans = _db.BeginTransaction())
31 31
                         {
32 32
                             using (var insertCommand = _db.CreateCommand(
33
-                                "INSERT INTO Logs (Id,  UserId,  VoucherId,  EventDate,  EventType,  Retry) " +
34
-                                          "VALUES (@id, @userid, @voucherid, @eventdate, @eventtype, @retry)",
33
+                                "INSERT INTO Logs (Id,  UserId,  VoucherId,  EventDate,  EventType,  Retry,  Summarised) " +
34
+                                          "VALUES (@id, @userid, @voucherid, @eventdate, @eventtype, @retry, 0)",
35 35
                                 trans))
36 36
                             using (var updateCommand = _db.CreateCommand(
37 37
                                 "UPDATE Parameters SET Value=@Value WHERE Key='SyncBackwardsFromLogId'", trans))

+ 2 - 1
BulkPrinting/BulkPrinting/LogUploader.cs

@@ -38,7 +38,7 @@ namespace BulkPrinting
38 38
                     List<RemoteVendorEvent> eventList = new List<RemoteVendorEvent>();
39 39
                     int counter = 0;
40 40
                     using (var Command = _db.CreateCommand(
41
-                        "Select Id,UserId,VoucherId,EventDate,EventType From Logs WHERE Id > @id",
41
+                        "Select Id,UserId,VoucherId,EventDate,EventType,Retry From Logs WHERE Id > @id",
42 42
                         new SQLiteParameter("@id", lastSyncedLogId)))
43 43
                     {
44 44
                         using (SQLiteDataReader read = Command.ExecuteReader())
@@ -60,6 +60,7 @@ namespace BulkPrinting
60 60
                                 nextEvent.EventDate = read.GetDateTime(3);
61 61
                                 nextEvent.EventType = (VendorEvent.VendorEventType)Enum.Parse(typeof(VendorEvent.VendorEventType), read.GetValue(4).ToString());
62 62
                                 nextEvent.VendorId = Globals.SessionData.Credentials.Payload.Vendor.id;
63
+                                nextEvent.Retry = read.GetBoolean(5);
63 64
                                 eventList.Add(nextEvent);
64 65
 
65 66
                                 if (counter == _uploadPageSize)

+ 71 - 8
BulkPrinting/BulkPrinting/Migrations.cs

@@ -1,9 +1,12 @@
1 1
 using System;
2
+using System.Data.SQLite;
2 3
 
3 4
 namespace BulkPrinting
4 5
 {
5 6
     class Migrations
6 7
     {
8
+        private delegate void PostMigrateDelegate(DBHelper db, SQLiteTransaction trans);
9
+
7 10
         public static void CheckMigrations(DBHelper db)
8 11
         {
9 12
             var result = db.ExecuteScalar("SELECT Value FROM Parameters WHERE Key = 'Migration'");
@@ -17,7 +20,7 @@ namespace BulkPrinting
17 20
                 throw new Exception(String.Format("Invalid migration value: {0}", result));
18 21
             }
19 22
 
20
-            if (startingMigration > 3)
23
+            if (startingMigration > 4)
21 24
             {
22 25
                 throw new Exception("Database is for a newer version of this application. Please upgrade and try again.");
23 26
             }
@@ -33,12 +36,16 @@ namespace BulkPrinting
33 36
             {
34 37
                 Migration3(db);
35 38
             }
39
+            if (startingMigration < 4)
40
+            {
41
+                Migration4(db);
42
+            }
36 43
             //Add further migration executions here - Migration = '1', '2', '3' etc
37 44
 
38 45
             return;
39 46
         }
40 47
 
41
-        private static bool ApplyMigrationQueries(DBHelper db, params string[] queries)
48
+        private static bool ApplyMigrationQueries(DBHelper db, PostMigrateDelegate postMigrate, params string[] queries)
42 49
         {
43 50
             lock (db.WriteLock)
44 51
             {
@@ -51,6 +58,7 @@ namespace BulkPrinting
51 58
                             command.ExecuteNonQuery();
52 59
                         }
53 60
                     }
61
+                    postMigrate?.Invoke(db, trans);
54 62
                     trans.Commit();
55 63
                 }
56 64
             }
@@ -60,7 +68,7 @@ namespace BulkPrinting
60 68
         public static bool InitialVersion(DBHelper db)
61 69
         {
62 70
             return ApplyMigrationQueries(
63
-                db,
71
+                db, null,
64 72
                 "CREATE TABLE Batch (" +
65 73
                     "Id INT," +
66 74
                     "OrderDate DATETIME," +
@@ -129,7 +137,7 @@ namespace BulkPrinting
129 137
         public static bool Migration1(DBHelper db)
130 138
         {
131 139
             return ApplyMigrationQueries(
132
-                db,
140
+                db, null,
133 141
                 "ALTER TABLE Orders ADD COLUMN InternalReference VARCHAR(32)",
134 142
                 "ALTER TABLE Batch ADD COLUMN InternalReference VARCHAR(32)",
135 143
 
@@ -141,7 +149,7 @@ namespace BulkPrinting
141 149
         public static bool Migration2(DBHelper db)
142 150
         {
143 151
             return ApplyMigrationQueries(
144
-                db,
152
+                db, null,
145 153
                 "ALTER TABLE Batch ADD COLUMN Downloaded BOOLEAN",
146 154
                 "CREATE UNIQUE INDEX Batch_Id ON Batch(Id)",
147 155
                 "CREATE INDEX Batch_OrderDate ON Batch(OrderDate)",
@@ -176,14 +184,69 @@ namespace BulkPrinting
176 184
         public static bool Migration3(DBHelper db)
177 185
         {
178 186
             return ApplyMigrationQueries(
179
-                db,
187
+                db, null,
180 188
 
181
-                // Forgot to update the migration value initially, hence the 'NOT EXISTS'
182
-                "CREATE INDEX IF NOT EXISTS Logs_VoucherId_EventType_Id ON Logs(VoucherId, EventType, Id)",
189
+                "CREATE INDEX Logs_VoucherId_EventType_Id ON Logs(VoucherId, EventType, Id)",
183 190
 
184 191
                 // IMPORTANT
185 192
                 "UPDATE Parameters SET Value='3' WHERE Key='Migration'"
186 193
            );
187 194
         }
195
+
196
+        public static bool Migration4(DBHelper db)
197
+        {
198
+            return ApplyMigrationQueries(
199
+                db,
200
+                (db2, trans) =>
201
+                {
202
+                    using (var selectCommand = db2.CreateCommand(
203
+                        "SELECT l.*, v.BatchId FROM Logs l " +
204
+                            "INNER JOIN Voucher v ON l.VoucherId=v.Id",
205
+                        trans))
206
+                    using (var updateVoucherCommand = Utility.CreateVoucherEventCountUpdateCommand(db2, trans))
207
+                    using (var updateBatchCommand = Utility.CreateBatchEventCountUpdateCommand(db2, trans))
208
+                    {
209
+                        using (var reader = selectCommand.ExecuteReader())
210
+                        {
211
+                            while (reader.Read())
212
+                            {
213
+                                int printCountDelta, reprintCountDelta, exportCountDelta, reExportCountDelta;
214
+                                if (Utility.CalculateEventCountDeltas(
215
+                                    (VendorEvent.VendorEventType)int.Parse((string)reader["EventType"]),
216
+                                    (bool)reader["Retry"],
217
+                                    out printCountDelta,
218
+                                    out reprintCountDelta,
219
+                                    out exportCountDelta,
220
+                                    out reExportCountDelta))
221
+                                {
222
+                                    Utility.ExecuteEventCountUpdateQuery(updateVoucherCommand, (int)reader["VoucherId"],
223
+                                        printCountDelta, reprintCountDelta, exportCountDelta, reExportCountDelta);
224
+
225
+                                    Utility.ExecuteEventCountUpdateQuery(updateBatchCommand, (int)reader["BatchId"],
226
+                                        printCountDelta, reprintCountDelta, exportCountDelta, reExportCountDelta);
227
+                                }
228
+                            }
229
+                        }
230
+                    }
231
+                },
232
+
233
+                "ALTER TABLE Logs ADD COLUMN Summarised BOOLEAN DEFAULT 0",
234
+                "CREATE INDEX Logs_Summarised_Id ON Logs(Summarised, Id)",
235
+                "UPDATE Logs SET Summarised=1",
236
+
237
+                "ALTER TABLE Batch ADD COLUMN PrintCount INT DEFAULT 0",
238
+                "ALTER TABLE Batch ADD COLUMN ReprintCount INT DEFAULT 0",
239
+                "ALTER TABLE Batch ADD COLUMN ExportCount INT DEFAULT 0",
240
+                "ALTER TABLE Batch ADD COLUMN ReExportCount INT DEFAULT 0",
241
+
242
+                "ALTER TABLE Voucher ADD COLUMN PrintCount INT DEFAULT 0",
243
+                "ALTER TABLE Voucher ADD COLUMN ReprintCount INT DEFAULT 0",
244
+                "ALTER TABLE Voucher ADD COLUMN ExportCount INT DEFAULT 0",
245
+                "ALTER TABLE Voucher ADD COLUMN ReExportCount INT DEFAULT 0",
246
+
247
+                // IMPORTANT
248
+                "UPDATE Parameters SET Value='4' WHERE Key='Migration'"
249
+           );
250
+        }
188 251
     }
189 252
 }

+ 1 - 0
BulkPrinting/BulkPrinting/Models.cs

@@ -501,6 +501,7 @@ namespace BulkPrinting
501 501
     public class EventLog {
502 502
         public VendorEvent.VendorEventType EventType { get; set; }
503 503
         public int? VoucherId { get; set; }
504
+        public int? BatchId { get; set; }
504 505
         public bool Retry { get; set; }
505 506
     }
506 507
 

+ 4 - 0
BulkPrinting/BulkPrinting/Program.cs

@@ -30,7 +30,11 @@ namespace BulkPrinting
30 30
 
31 31
             AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
32 32
 
33
+#if SIMULATE_HDD_SERIAL
34
+            Globals.HDDSerialNumber = "9VMTDFGX";
35
+#else
33 36
             Globals.HDDSerialNumber = Utility.GetHDDSerial();
37
+#endif
34 38
 
35 39
             Application.EnableVisualStyles();
36 40
             Application.SetCompatibleTextRenderingDefault(false);

+ 154 - 21
BulkPrinting/BulkPrinting/Utility.cs

@@ -103,13 +103,21 @@ namespace BulkPrinting
103 103
                 if (ex.Response != null)
104 104
                 {
105 105
                     var response = ex.Response;
106
-                    var stream = response.GetResponseStream();
107
-                    var reader = new StreamReader(stream);
108
-                    var message = reader.ReadToEnd();
109
-                    MaxException MaxError = JsonConvert.DeserializeObject<MaxException>(message);
110
-                    if (MaxError.Code != null)
106
+                    HttpStatusCode? status = (response as HttpWebResponse)?.StatusCode;
107
+                    if (status.HasValue && (status.Value == HttpStatusCode.InternalServerError))
111 108
                     {
112
-                        MessageBox.Show("Error " + MaxError.Code.ToString() + ": " + MaxError.Error, "Login Failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
109
+                        var stream = response.GetResponseStream();
110
+                        var reader = new StreamReader(stream);
111
+                        var message = reader.ReadToEnd();
112
+                        MaxException MaxError = JsonConvert.DeserializeObject<MaxException>(message);
113
+                        if (MaxError.Code != null)
114
+                        {
115
+                            MessageBox.Show("Error " + MaxError.Code.ToString() + ": " + MaxError.Error, "Login Failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
116
+                        }
117
+                        else
118
+                        {
119
+                            MessageBox.Show("Login Failed. Please try again.", "Login Failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
120
+                        }
113 121
                     }
114 122
                     else
115 123
                     {
@@ -172,7 +180,7 @@ namespace BulkPrinting
172 180
                     {
173 181
                         Result = default(R);
174 182
                     }
175
-                    else
183
+                    else if (status.HasValue && (status == HttpStatusCode.InternalServerError))
176 184
                     {
177 185
                         var stream = response.GetResponseStream();
178 186
                         var reader = new StreamReader(stream);
@@ -182,6 +190,14 @@ namespace BulkPrinting
182 190
                         {
183 191
                             MessageBox.Show("Error " + MaxError.Code.ToString() + ": " + MaxError.Error, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
184 192
                         }
193
+                        else
194
+                        {
195
+                            MessageBox.Show(MaxError.Error, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
196
+                        }
197
+                    }
198
+                    else
199
+                    {
200
+                        MessageBox.Show("The server encountered an unexpected error.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
185 201
                     }
186 202
                 }
187 203
                 return false;
@@ -472,6 +488,7 @@ namespace BulkPrinting
472 488
                                 var ExportEvent = new EventLog();
473 489
                                 ExportEvent.EventType = VendorEvent.VendorEventType.PrintVoucher;
474 490
                                 ExportEvent.VoucherId = PrintedVoucher.VoucherId;
491
+                                ExportEvent.BatchId = BatchId;
475 492
                                 ExportEvent.Retry = IsReprint;
476 493
                                 LogEvents.Add(ExportEvent);
477 494
                             }
@@ -623,15 +640,18 @@ namespace BulkPrinting
623 640
 
624 641
         public static void TriggerLogDownload()
625 642
         {
643
+#if ! SIMULATE_HDD_SERIAL
626 644
             if (Globals.LogDownloader == null)
627 645
             {
628 646
                 Globals.LogDownloader = new LogDownloader(Globals.DB);
629 647
                 Globals.LogDownloader.Start();
630 648
             }
649
+#endif
631 650
         }
632 651
 
633 652
         public static void TriggerLogUpload()
634 653
         {
654
+#if ! SIMULATE_HDD_SERIAL
635 655
             if (Globals.LogUploader == null)
636 656
             {
637 657
                 Globals.LogUploader = new LogUploader(Globals.DB);
@@ -641,27 +661,138 @@ namespace BulkPrinting
641 661
             {
642 662
                 Globals.LogUploader.TriggerUpload();
643 663
             }
664
+#endif
665
+        }
666
+
667
+        public static void CreateEventCountUpdateQueryParameters(SQLiteCommand command)
668
+        {
669
+            command.Parameters.AddWithValue("@Id", null);
670
+            command.Parameters.AddWithValue("@PrintCountDelta", null);
671
+            command.Parameters.AddWithValue("@ReprintCountDelta", null);
672
+            command.Parameters.AddWithValue("@ExportCountDelta", null);
673
+            command.Parameters.AddWithValue("@ReExportCountDelta", null);
674
+        }
675
+
676
+        public static void ExecuteEventCountUpdateQuery(SQLiteCommand command, int id,
677
+            int printCountDelta, int reprintCountDelta, int exportCountDelta, int reExportCountDelta)
678
+        {
679
+            command.Parameters["@Id"].Value = id;
680
+            command.Parameters["@PrintCountDelta"].Value = printCountDelta;
681
+            command.Parameters["@ReprintCountDelta"].Value = reprintCountDelta;
682
+            command.Parameters["@ExportCountDelta"].Value = exportCountDelta;
683
+            command.Parameters["@ReExportCountDelta"].Value = reExportCountDelta;
684
+            command.ExecuteNonQuery();
685
+        }
686
+
687
+        public static SQLiteCommand CreateVoucherEventCountUpdateCommand(DBHelper db, SQLiteTransaction trans)
688
+        {
689
+            var command = db.CreateCommand(
690
+                "UPDATE Voucher SET " +
691
+                    "PrintCount=PrintCount+@PrintCountDelta," +
692
+                    "ReprintCount=ReprintCount+@ReprintCountDelta," +
693
+                    "ExportCount=ExportCount+@ExportCountDelta," +
694
+                    "ReExportCount=ReExportCount+@ReExportCountDelta " +
695
+                "WHERE Id=@Id",
696
+                trans);
697
+            CreateEventCountUpdateQueryParameters(command);
698
+            return command;
699
+        }
700
+
701
+        public static bool CalculateEventCountDeltas(VendorEvent.VendorEventType eventType, bool retry,
702
+            out int printCountDelta, out int reprintCountDelta, out int exportCountDelta, out int reExportCountDelta)
703
+        {
704
+            printCountDelta = 0;
705
+            reprintCountDelta = 0;
706
+            exportCountDelta = 0;
707
+            reExportCountDelta = 0;
708
+
709
+            if (eventType == VendorEvent.VendorEventType.PrintVoucher)
710
+            {
711
+                if (retry)
712
+                {
713
+                    reprintCountDelta++;
714
+                }
715
+                else
716
+                {
717
+                    printCountDelta++;
718
+                }
719
+                return true;
720
+            }
721
+            else if (eventType == VendorEvent.VendorEventType.ExportVoucher)
722
+            {
723
+                if (retry)
724
+                {
725
+                    reExportCountDelta++;
726
+                }
727
+                else
728
+                {
729
+                    exportCountDelta++;
730
+                }
731
+                return true;
732
+            }
733
+            return false;
734
+        }
735
+
736
+        public static SQLiteCommand CreateBatchEventCountUpdateCommand(DBHelper db, SQLiteTransaction trans)
737
+        {
738
+            var command = db.CreateCommand(
739
+                "UPDATE Batch SET " +
740
+                    "PrintCount=PrintCount+@PrintCountDelta," +
741
+                    "ReprintCount=ReprintCount+@ReprintCountDelta," +
742
+                    "ExportCount=ExportCount+@ExportCountDelta," +
743
+                    "ReExportCount=ReExportCount+@ReExportCountDelta " +
744
+                "WHERE Id=@Id",
745
+                trans);
746
+            CreateEventCountUpdateQueryParameters(command);
747
+            return command;
644 748
         }
645 749
 
646 750
         public static void LogBulkEvents(DBHelper db, List<EventLog> EventLogs)
647 751
         {
648
-            string Sql = "INSERT INTO Logs (UserId, VoucherId, EventDate, EventType, Retry) VALUES (@userid, @voucherid, @eventdate, @eventtype, @retry)";
752
+            string Sql = "INSERT INTO Logs (UserId,  VoucherId,  EventDate,  EventType,  Retry,  Summarised) " +
753
+                                   "VALUES (@userid, @voucherid, @eventdate, @eventtype, @retry, 1)";
649 754
 
650 755
             lock (db.WriteLock)
651 756
             {
652 757
                 using (var trans = db.BeginTransaction())
653 758
                 {
654
-                    using (var Command = db.CreateCommand(Sql, trans))
759
+                    using (var insertLogsCommand = db.CreateCommand(Sql, trans))
760
+                    using (var updateVoucherCommand = CreateVoucherEventCountUpdateCommand(db, trans))
761
+                    using (var updateBatchCommand = CreateBatchEventCountUpdateCommand(db, trans))
655 762
                     {
656 763
                         foreach (var EventLog in EventLogs)
657 764
                         {
658
-                            Command.Parameters.Clear();
659
-                            Command.Parameters.AddWithValue("@userid", Globals.SessionData.Credentials.Payload.User.Id);
660
-                            Command.Parameters.AddWithValue("@voucherid", EventLog.VoucherId);
661
-                            Command.Parameters.AddWithValue("@eventdate", DateTime.UtcNow);
662
-                            Command.Parameters.AddWithValue("@eventtype", EventLog.EventType);
663
-                            Command.Parameters.AddWithValue("@retry", EventLog.Retry);
664
-                            Command.ExecuteNonQuery();
765
+                            insertLogsCommand.Parameters.Clear();
766
+                            insertLogsCommand.Parameters.AddWithValue("@userid", Globals.SessionData.Credentials.Payload.User.Id);
767
+                            insertLogsCommand.Parameters.AddWithValue("@voucherid", EventLog.VoucherId);
768
+                            insertLogsCommand.Parameters.AddWithValue("@eventdate", DateTime.UtcNow);
769
+                            insertLogsCommand.Parameters.AddWithValue("@eventtype", EventLog.EventType);
770
+                            insertLogsCommand.Parameters.AddWithValue("@retry", EventLog.Retry);
771
+                            insertLogsCommand.ExecuteNonQuery();
772
+
773
+                            if (EventLog.VoucherId.HasValue)
774
+                            {
775
+                                if (! EventLog.BatchId.HasValue)
776
+                                {
777
+                                    throw new Exception("Event log entry is missing a batch ID");
778
+                                }
779
+
780
+                                int printCountDelta, reprintCountDelta, exportCountDelta, reExportCountDelta;
781
+                                if (CalculateEventCountDeltas(
782
+                                    EventLog.EventType,
783
+                                    EventLog.Retry,
784
+                                    out printCountDelta,
785
+                                    out reprintCountDelta,
786
+                                    out exportCountDelta,
787
+                                    out reExportCountDelta))
788
+                                {
789
+                                    ExecuteEventCountUpdateQuery(updateVoucherCommand, EventLog.VoucherId.Value,
790
+                                        printCountDelta, reprintCountDelta, exportCountDelta, reExportCountDelta);
791
+
792
+                                    ExecuteEventCountUpdateQuery(updateBatchCommand, EventLog.BatchId.Value,
793
+                                        printCountDelta, reprintCountDelta, exportCountDelta, reExportCountDelta);
794
+                                }
795
+                            }
665 796
                         }
666 797
                     }
667 798
                     trans.Commit();
@@ -674,16 +805,18 @@ namespace BulkPrinting
674 805
             }
675 806
         }
676 807
 
677
-        public static void LogEvent(DBHelper db, VendorEvent.VendorEventType EventType, int? VoucherId = null, bool Retry = false)
808
+        public static void LogEvent(DBHelper db, VendorEvent.VendorEventType EventType)
678 809
         {
810
+            // Not for voucher-related events. If you add support for individual voucher events, please update print counts,
811
+            // etc., as in LogBulkEvents.
679 812
             db.ExecuteNonQuery(
680
-                "INSERT INTO Logs (UserId,  VoucherId,  EventDate,  EventType,  Retry) " +
681
-                          "VALUES (@userid, @voucherid, @eventdate, @eventtype, @retry)",
813
+                "INSERT INTO Logs (UserId,  VoucherId,  EventDate,  EventType,  Retry,  Summarised) " +
814
+                          "VALUES (@userid, @voucherid, @eventdate, @eventtype, @retry, 1)",
682 815
                 new SQLiteParameter("@userid", Globals.SessionData.Credentials.Payload.User.Id),
683
-                new SQLiteParameter("@voucherid", VoucherId),
816
+                new SQLiteParameter("@voucherid", null),
684 817
                 new SQLiteParameter("@eventdate", DateTime.UtcNow),
685 818
                 new SQLiteParameter("@eventtype", EventType),
686
-                new SQLiteParameter("@retry", Retry));
819
+                new SQLiteParameter("@retry", false));
687 820
             if (Globals.SessionMode == SessionModes.Online)
688 821
             {
689 822
                 TriggerLogUpload();