Browse Source

Add weight loss and roasting specification notes feature

Neal Wilson 8 years ago
parent
commit
e6d49072ef
4 changed files with 328 additions and 168 deletions
  1. 41
    22
      config/Windows/navigation.xml
  2. 208
    146
      config/Windows/newbatch.xml
  3. 78
    0
      config/Windows/roastspec.xml
  4. 1
    0
      config/config.xml

+ 41
- 22
config/Windows/navigation.xml View File

@@ -23,6 +23,11 @@
23 23
 				<button name="Manage Roasted Coffee Items" id="newroasted" type="push" />
24 24
 			</column>
25 25
 		</row>
26
+                <row>
27
+                    <column>
28
+                        <button name="Edit Roasting Specification" id="roastspec" type="push" />
29
+                    </column>
30
+                </row>
26 31
 		<row>
27 32
 			<column>
28 33
 				<button name="Update Inventory" id="inventory" type="push" />
@@ -132,6 +137,10 @@ type="push" />
132 137
             var histwindow = createWindow("history");
133 138
             histwindow.windowTitle = "Typica - Batch Log";
134 139
         });
140
+        var roastspecbutton = findChildObject(this, 'roastspec');
141
+        roastspecbutton.clicked.connect(function() {
142
+            var specwindow = createWindow("roastspec");
143
+        });
135 144
         var gbutton = findChildObject(this, 'green');
136 145
         gbutton.clicked.connect(function() {
137 146
             var purchasewindow = createWindow("purchase");
@@ -290,7 +299,13 @@ type="push" />
290 299
                     query.exec("UPDATE TypicaFeatures SET version = 5 WHERE feature = 'base-features'");
291 300
                     query = query.invalidate();
292 301
                 };
293
-		
302
+		var DBUpdateSpecification = function() {
303
+                    var query = new QSqlQuery;
304
+                    query.exec("CREATE TABLE IF NOT EXISTS roasting_specification (\"time\" timestamp without time zone NOT NULL, item bigint NOT NULL, loss numeric, tolerance numeric, notes text)");
305
+                    query.exec("UPDATE TypicaFeatures SET version = 6 WHERE feature = 'base-features'");
306
+                    query = query.invalidate();
307
+                };
308
+                
294 309
 		query = new QSqlQuery();
295 310
 		/* A table keeps track of database versioning information. This table is created
296 311
 		   if required. */
@@ -301,27 +316,31 @@ type="push" />
301 316
 		query.exec("SELECT feature, enabled, version FROM TypicaFeatures WHERE feature = 'base-features'");
302 317
 		if(query.next())
303 318
 		{
304
-			if(query.value(2) < 1)
305
-			{
306
-				DBCreateBase();
307
-			}
308
-			if(query.value(2) < 2)
309
-			{
310
-				DBUpdateMultiUser();
311
-				DBUpdateHistory();
312
-			}
313
-			if(query.value(2) < 3)
314
-			{
315
-				DBUpdateNotifications();
316
-			}
317
-			if(query.value(2) < 4)
318
-			{
319
-				DBUpdateTriggers();
320
-			}
321
-                        if(query.value(2) < 5)
322
-                        {
323
-                            DBUpdateReminders();
324
-                        }
319
+                    if(query.value(2) < 1)
320
+                    {
321
+                            DBCreateBase();
322
+                    }
323
+                    if(query.value(2) < 2)
324
+                    {
325
+                            DBUpdateMultiUser();
326
+                            DBUpdateHistory();
327
+                    }
328
+                    if(query.value(2) < 3)
329
+                    {
330
+                            DBUpdateNotifications();
331
+                    }
332
+                    if(query.value(2) < 4)
333
+                    {
334
+                            DBUpdateTriggers();
335
+                    }
336
+                    if(query.value(2) < 5)
337
+                    {
338
+                        DBUpdateReminders();
339
+                    }
340
+                    if(query.value(2) < 6)
341
+                    {
342
+                        DBUpdateSpecification();
343
+                    }
325 344
 		}
326 345
 		else
327 346
 		{

+ 208
- 146
config/Windows/newbatch.xml View File

@@ -2,65 +2,82 @@
2 2
     <menu name="Batch">
3 3
         <item id="new" shortcut="Ctrl+N">New Batch…</item>
4 4
     </menu>
5
-	<layout type="horizontal">
6
-    <layout type="vertical">
7
-        <layout type="horizontal">
8
-			<label>Machine:</label>
9
-			<line id="machine" writable="false" />
10
-			<label>Unit:</label>
11
-			<sqldrop id="unit" />
12
-            <stretch />
5
+    <layout type="horizontal">
6
+        <layout type="vertical">
7
+            <layout type="horizontal">
8
+                <label>Machine:</label>
9
+                <line id="machine" writable="false" />
10
+                <label>Unit:</label>
11
+                <sqldrop id="unit" />
12
+                <stretch />
13
+            </layout>
14
+            <layout type="horizontal">
15
+                <label>Roasted Coffee:</label>
16
+                <sqldrop data="0" display="1" showdata="true" id="roasted">
17
+                    <null />
18
+                    <query>SELECT id, name FROM items WHERE category = 'Coffee: Roasted' AND id IN (SELECT item FROM current_items) ORDER BY name</query>
19
+                </sqldrop>
20
+                <stretch />
21
+            </layout>
22
+            <label>Green Coffee:</label>
23
+            <sqltablearray columns="3" id="greens">
24
+                <column name="Coffee" delegate="sql" showdata="true" null="true" nulltext="Delete" nulldata="delete" data="0" display="1">SELECT id, name FROM coffees WHERE quantity &lt;&gt; 0 ORDER BY name</column>
25
+                <column name="Weight" delegate="numeric" />
26
+                <column name="Remaining" />
27
+            </sqltablearray>
28
+            <layout type="horizontal">
29
+                <label>Green Weight:</label>
30
+                <line id="green" writable="false">0.0</line>
31
+            </layout>
32
+            <layout type="horizontal">
33
+                <button name="Load Profile" type="push" id="load" />
34
+                <button name="No Profile" type="push" id="noprofile" />
35
+            </layout>
36
+            <layout type="horizontal">
37
+                <label>Time:</label>
38
+                <line id="time" writable="false" />
39
+                <label>Duration:</label>
40
+                <line id="duration" writable="false" />
41
+            </layout>
42
+            <layout type="horizontal">
43
+                <label>Roasted Weight:</label>
44
+                <line id="roast" validator="numeric" />
45
+                <label>Weight Loss:</label>
46
+                <line id="wloss" writable="false" />
47
+                <button type="check" id="approval" name="Approved" />
48
+            </layout>
49
+            <layout type="horizontal">
50
+                <label>Annotation:</label>
51
+                <textarea id="annotation" />
52
+            </layout>
53
+            <layout type="horizontal">
54
+                <button name="Submit" id="submit" type="push" />
55
+                <button name="Save log as target profile" type="check" id="target" />
56
+            </layout>
13 57
         </layout>
14
-        <layout type="horizontal">
15
-            <label>Roasted Coffee:</label>
16
-            <sqldrop data="0" display="1" showdata="true" id="roasted">
17
-                <null />
18
-                <query>SELECT id, name FROM items WHERE category = 'Coffee: Roasted' AND id IN (SELECT item FROM current_items) ORDER BY name</query>
19
-            </sqldrop>
58
+        <layout type="vertical">
59
+            <label>Connected Scales</label>
60
+            <layout type="vertical" id="scales" />
61
+            <label>Expected Weight Loss</label>
62
+            <line id="lossspec" writable="false" />
63
+            <label>Expected Roasted Weight</label>
64
+            <layout type="horizontal">
65
+                <label>Min:</label>
66
+                <line id="minroastweight" writable="false" />
67
+            </layout>
68
+            <layout type="horizontal">
69
+                <label>Expected:</label>
70
+                <line id="expectedroastweight" writable="false" />
71
+            </layout>
72
+            <layout type="horizontal">
73
+                <label>Max:</label>
74
+                <line id="maxroastweight" writable="false" />
75
+            </layout>
76
+            <label>Specification Details</label>
77
+            <textarea id="specnotes" />
20 78
             <stretch />
21 79
         </layout>
22
-        <label>Green Coffee:</label>
23
-        <sqltablearray columns="3" id="greens">
24
-            <column name="Coffee" delegate="sql" showdata="true" null="true" nulltext="Delete" nulldata="delete" data="0" display="1">SELECT id, name FROM coffees WHERE quantity &lt;&gt; 0 ORDER BY name</column>
25
-            <column name="Weight" delegate="numeric" />
26
-            <column name="Remaining" />
27
-        </sqltablearray>
28
-        <layout type="horizontal">
29
-            <label>Green Weight:</label>
30
-            <line id="green" writable="false">0.0</line>
31
-        </layout>
32
-        <layout type="horizontal">
33
-            <button name="Load Profile" type="push" id="load" />
34
-            <button name="No Profile" type="push" id="noprofile" />
35
-        </layout>
36
-        <layout type="horizontal">
37
-            <label>Time:</label>
38
-            <line id="time" writable="false" />
39
-            <label>Duration:</label>
40
-            <line id="duration" writable="false" />
41
-        </layout>
42
-        <layout type="horizontal">
43
-            <label>Roasted Weight:</label>
44
-            <line id="roast" validator="numeric" />
45
-            <label>Weight Loss:</label>
46
-            <line id="wloss" writable="false" />
47
-            <button type="check" id="approval" name="Approved" />
48
-        </layout>
49
-        <layout type="horizontal">
50
-            <label>Annotation:</label>
51
-            <textarea id="annotation" />
52
-        </layout>
53
-        <layout type="horizontal">
54
-            <button name="Submit" id="submit" type="push" />
55
-            <button name="Save log as target profile" type="check" id="target" />
56
-        </layout>
57 80
     </layout>
58
-	<layout type="vertical">
59
-		<label>Connected Scales</label>
60
-		<layout type="vertical" id="scales" />
61
-		<stretch />
62
-	</layout>
63
-	</layout>
64 81
     <program>
65 82
         <![CDATA[
66 83
             var unitBox = findChildObject(this, 'unit');
@@ -76,8 +93,8 @@
76 93
             machine.setText(selectedRoasterName + " (" + selectedRoasterID + ")");
77 94
             var newMenu = findChildObject(this, 'new');
78 95
             newMenu.triggered.connect(function() {
79
-                    var bwindow = createWindow("batchWindow");
80
-                    bwindow.windowTitle = "Typica - [*]New Batch";
96
+                var bwindow = createWindow("batchWindow");
97
+                bwindow.windowTitle = "Typica - [*]New Batch";
81 98
             });
82 99
             var batch = this;
83 100
             var table = findChildObject(this, 'greens');
@@ -91,36 +108,36 @@
91 108
             var scalesLayout = findChildObject(this, 'scales');
92 109
             scalesLayout.spacing = 10;
93 110
             if(navigationwindow.loggingWindow.scales.length > 0) {
94
-                    for(var i = 0; i < navigationwindow.loggingWindow.scales.length; i++) {
95
-                            var scale = navigationwindow.loggingWindow.scales[i];
96
-                            var label = new DragLabel();
97
-                            var weighButton = new QPushButton();
98
-                            weighButton.text = "Weigh";
99
-                            weighButton.clicked.connect(scale.weigh);
100
-                            label.updateMeasurement = function(m, u) {
101
-                                    switch(unitBox.currentIndex) {
102
-                                            case 0:
103
-                                                    this.text = Units.convertWeight(m, u, Units.Gram).toFixed(1);
104
-                                                    break;
105
-                                            case 1:
106
-                                                    this.text = Units.convertWeight(m, u, Units.Kilogram).toFixed(4);
107
-                                                    break;
108
-                                            case 2:
109
-                                                    this.text = Units.convertWeight(m, u, Units.Ounce).toFixed(3);
110
-                                                    break;
111
-                                            case 3:
112
-                                                    this.text = Units.convertWeight(m, u, Units.Pound).toFixed(4);
113
-                                                    break;
114
-                                    }
115
-                            };
116
-                            scalesLayout.addWidget(label);
117
-                            scalesLayout.addWidget(weighButton);
118
-                            scale.newMeasurement.connect(function(m, u) {
119
-                                    label.updateMeasurement(m, u);
120
-                            });
121
-                            scale.weigh();
122
-                            unitBox['currentIndexChanged(int)'].connect(scale.weigh);
123
-                    }
111
+                for(var i = 0; i < navigationwindow.loggingWindow.scales.length; i++) {
112
+                    var scale = navigationwindow.loggingWindow.scales[i];
113
+                    var label = new DragLabel();
114
+                    var weighButton = new QPushButton();
115
+                    weighButton.text = "Weigh";
116
+                    weighButton.clicked.connect(scale.weigh);
117
+                    label.updateMeasurement = function(m, u) {
118
+                        switch(unitBox.currentIndex) {
119
+                            case 0:
120
+                                this.text = Units.convertWeight(m, u, Units.Gram).toFixed(1);
121
+                                break;
122
+                            case 1:
123
+                                this.text = Units.convertWeight(m, u, Units.Kilogram).toFixed(4);
124
+                                break;
125
+                            case 2:
126
+                                this.text = Units.convertWeight(m, u, Units.Ounce).toFixed(3);
127
+                                break;
128
+                            case 3:
129
+                                this.text = Units.convertWeight(m, u, Units.Pound).toFixed(4);
130
+                                break;
131
+                        }
132
+                    };
133
+                    scalesLayout.addWidget(label);
134
+                    scalesLayout.addWidget(weighButton);
135
+                    scale.newMeasurement.connect(function(m, u) {
136
+                        label.updateMeasurement(m, u);
137
+                    });
138
+                    scale.weigh();
139
+                    unitBox['currentIndexChanged(int)'].connect(scale.weigh);
140
+                }
124 141
             }
125 142
             var remainingStock = new Array();
126 143
             var query = new QSqlQuery();
@@ -153,6 +170,15 @@
153 170
                 }
154 171
                 return w;
155 172
             };
173
+            var specnotes = findChildObject(this, 'specnotes');
174
+            specnotes.readOnly = true;
175
+            var lossspec = findChildObject(this, 'lossspec');
176
+            var minfield = findChildObject(this, 'minroastweight');
177
+            var midfield = findChildObject(this, 'expectedroastweight');
178
+            var maxfield = findChildObject(this, 'maxroastweight');
179
+            var minloss = 0;
180
+            var maxloss = 0;
181
+            var expectloss = 0;
156 182
             var updateGreenTable = function() {
157 183
                 var deleteRow = -1;
158 184
                 /* The combo box delegate updates user data before display data
@@ -162,11 +188,11 @@
162 188
                 row removal until both updates are complete.
163 189
                 */
164 190
                 while((deleteRow = table.findData("delete", 0)) > -1) {
165
-                        if(table.data(deleteRow, 0, 0) == "Delete") {
166
-                                table.removeRow(table.findData("delete", 0));
167
-                        } else {
168
-                                break;
169
-                        }
191
+                    if(table.data(deleteRow, 0, 0) == "Delete") {
192
+                        table.removeRow(table.findData("delete", 0));
193
+                    } else {
194
+                        break;
195
+                    }
170 196
                 }
171 197
                 green.text = table.columnSum(1, 0);
172 198
                 table.resizeColumnToContents(0);
@@ -230,6 +256,14 @@
230 256
                 }
231 257
                 if(parseFloat(green.text) > 0)
232 258
                 {
259
+                    var expectedLossDesc = "";
260
+                    if(lossspec.text.length > 0) {
261
+                        if(minloss != expectloss) {
262
+                            minfield.text = (-(parseFloat(green.text)) * (maxloss - 1)).toFixed(2);
263
+                            maxfield.text = (-(parseFloat(green.text)) * (minloss - 1)).toFixed(2);
264
+                        }
265
+                        midfield.text = (-(parseFloat(green.text)) * (expectloss - 1)).toFixed(2);
266
+                    }
233 267
                     if(parseFloat(roastwt.text) > 0)
234 268
                     {
235 269
                         lossField.text = (((parseFloat(green.text) - parseFloat(roastwt.text)) / parseFloat(green.text)) * 100).toFixed(2) + "%";
@@ -318,6 +352,34 @@
318 352
                         }
319 353
                     }
320 354
                 }
355
+                query.prepare("SELECT loss, tolerance, notes FROM roasting_specification WHERE item = :id1 AND time = (SELECT max(time) FROM roasting_specification WHERE item = :id2)");
356
+                query.bind(":id1", roasted.currentData());
357
+                query.bind(":id2", roasted.currentData());
358
+                query.exec();
359
+                var lossSpecDescription = "";
360
+                if(query.next()) {
361
+                    if(query.value(0).length > 0) {
362
+                        lossSpecDescription += (Number(query.value(0)) * 100).toFixed(2);
363
+                        minloss = Number(query.value(0));
364
+                        maxloss = Number(query.value(0));
365
+                        expectloss = Number(query.value(0));
366
+                    }
367
+                    if(query.value(1).length > 0) {
368
+                        lossSpecDescription += " +/- " + (Number(query.value(1)) * 100).toFixed(2);
369
+                        minloss -= Number(query.value(1));
370
+                        maxloss += Number(query.value(1));
371
+                    }
372
+                    if(lossSpecDescription.length > 0) {
373
+                        lossSpecDescription += "%";
374
+                    }
375
+                    lossspec.text = lossSpecDescription;
376
+                    specnotes.plainText = query.value(2);
377
+                } else {
378
+                    lossspec.text = "";
379
+                    specnotes.plainText = "";
380
+                }
381
+                roastestimate.text = "";
382
+                query = query.invalidate();
321 383
             });
322 384
             profilebutton.clicked.connect(function() {
323 385
                 batch.windowModified = true;
@@ -332,51 +394,51 @@
332 394
                 var log;
333 395
                 if(query.next())
334 396
                 {
335
-                        var files = query.value(0);
336
-                        files = files.replace("{", "(");
337
-                        files = files.replace("}", ")");
338
-                        q = "SELECT file, name FROM files WHERE id IN ";
339
-                        q = q + files;
340
-                        q = q + " AND type = 'profile'";
341
-                        query.exec(q);
342
-                        if(query.next())
343
-                        {
344
-                                var targetseries = -1;
345
-                                var buffer = new QBuffer(query.value(0));
346
-                                var pname = query.value(1);
347
-                                var input = new XMLInput(buffer, 1);
348
-                                graph = findChildObject(navigationwindow.loggingWindow, 'graph');
349
-                                log = findChildObject(navigationwindow.loggingWindow, 'log');
350
-                                log.clear();
351
-                                graph.clear();
352
-                                input.newTemperatureColumn.connect(log.setHeaderData);
353
-                                input.newTemperatureColumn.connect(function(col, text) {
354
-                                        if(text == navigationwindow.loggingWindow.targetcolumnname)
355
-                                        {
356
-                                                targetseries = col;
357
-                                        }
358
-                                });
359
-                                input.newAnnotationColumn.connect(log.setHeaderData);
360
-                                input.measure.connect(graph.newMeasurement);
361
-                                input.measure.connect(log.newMeasurement);
362
-                                input.measure.connect(function(data, series) {
363
-                                        if(series == targetseries)
364
-                                        {
365
-                                                targetDetector.newMeasurement(data);
366
-                                        }
367
-                                });
368
-                                var lc;
369
-                                input.lastColumn.connect(function(c) {
370
-                                        lc = c;
371
-                                        QSettings.setValue("liveColumn", c + 1);
372
-                                        navigationwindow.loggingWindow.postLoadColumnSetup(c)
373
-                                });
374
-                                input.annotation.connect(function(note, tcol, ncol) {
375
-                                        for(var i = tcol; i < ncol; i++) {
376
-                                                log.newAnnotation(note, i, ncol);
377
-                                        }
378
-                                });
379
-                        }
397
+                    var files = query.value(0);
398
+                    files = files.replace("{", "(");
399
+                    files = files.replace("}", ")");
400
+                    q = "SELECT file, name FROM files WHERE id IN ";
401
+                    q = q + files;
402
+                    q = q + " AND type = 'profile'";
403
+                    query.exec(q);
404
+                    if(query.next())
405
+                    {
406
+                        var targetseries = -1;
407
+                        var buffer = new QBuffer(query.value(0));
408
+                        var pname = query.value(1);
409
+                        var input = new XMLInput(buffer, 1);
410
+                        graph = findChildObject(navigationwindow.loggingWindow, 'graph');
411
+                        log = findChildObject(navigationwindow.loggingWindow, 'log');
412
+                        log.clear();
413
+                        graph.clear();
414
+                        input.newTemperatureColumn.connect(log.setHeaderData);
415
+                        input.newTemperatureColumn.connect(function(col, text) {
416
+                            if(text == navigationwindow.loggingWindow.targetcolumnname)
417
+                            {
418
+                                targetseries = col;
419
+                            }
420
+                        });
421
+                        input.newAnnotationColumn.connect(log.setHeaderData);
422
+                        input.measure.connect(graph.newMeasurement);
423
+                        input.measure.connect(log.newMeasurement);
424
+                        input.measure.connect(function(data, series) {
425
+                            if(series == targetseries)
426
+                            {
427
+                                targetDetector.newMeasurement(data);
428
+                            }
429
+                        });
430
+                        var lc;
431
+                        input.lastColumn.connect(function(c) {
432
+                            lc = c;
433
+                            QSettings.setValue("liveColumn", c + 1);
434
+                            navigationwindow.loggingWindow.postLoadColumnSetup(c)
435
+                        });
436
+                        input.annotation.connect(function(note, tcol, ncol) {
437
+                            for(var i = tcol; i < ncol; i++) {
438
+                                log.newAnnotation(note, i, ncol);
439
+                            }
440
+                        });
441
+                    }
380 442
                 }
381 443
                 query = query.invalidate();
382 444
                 navigationwindow.loggingWindow.windowTitle = "Typica - [*]" + pname;
@@ -391,10 +453,10 @@
391 453
             });
392 454
             var noprofilebutton = findChildObject(this, 'noprofile');
393 455
             noprofilebutton.clicked.connect(function() {
394
-                    batch.windowModified = true;
395
-                    currentBatchInfo = batch;
396
-                    navigationwindow.loggingWindow.raise();
397
-                    navigationwindow.loggingWindow.activateWindow();
456
+                batch.windowModified = true;
457
+                currentBatchInfo = batch;
458
+                navigationwindow.loggingWindow.raise();
459
+                navigationwindow.loggingWindow.activateWindow();
398 460
             });
399 461
             var submitbutton = findChildObject(this, 'submit');
400 462
             var timefield = findChildObject(this, 'time');
@@ -408,10 +470,10 @@
408 470
                 checkQuery.exec("SELECT 1 FROM machine WHERE id = " + selectedRoasterID);
409 471
                 if(!checkQuery.next())
410 472
                 {
411
-                        checkQuery.prepare("INSERT INTO machine (id, name) VALUES(:id, :name)");
412
-                        checkQuery.bind(":id", selectedRoasterID);
413
-                        checkQuery.bind(":name", selectedRoasterName);
414
-                        checkQuery.exec();
473
+                    checkQuery.prepare("INSERT INTO machine (id, name) VALUES(:id, :name)");
474
+                    checkQuery.bind(":id", selectedRoasterID);
475
+                    checkQuery.bind(":name", selectedRoasterName);
476
+                    checkQuery.exec();
415 477
                 }
416 478
                 checkQuery = checkQuery.invalidate();
417 479
                 var q = "INSERT INTO files (id, name, type, note, file) VALUES(default, :name, 'profile', NULL, :data) RETURNING id";
@@ -429,7 +491,7 @@
429 491
                 q2 = q2 + ", ";
430 492
                 for(var i = 0; table.data(i, 1, 0).value != ""; i++)
431 493
                 {
432
-                        table.setData(i, 1, convertToPounds(parseFloat(table.data(i, 1, 0)), unitBox.currentText) ,32)
494
+                    table.setData(i, 1, convertToPounds(parseFloat(table.data(i, 1, 0)), unitBox.currentText) ,32)
433 495
                 }
434 496
                 q2 = q2 + table.columnArray(1, 32);
435 497
                 q2 = q2 + ", ";

+ 78
- 0
config/Windows/roastspec.xml View File

@@ -0,0 +1,78 @@
1
+<window id="roastspec">
2
+    <layout type="vertical">
3
+        <layout type="horizontal">
4
+            <label>Coffee:</label>
5
+            <sqldrop data="0" display="1" showdata="false" id="currentitems">
6
+                <query>SELECT id, name FROM items WHERE id IN (SELECT item FROM current_items) ORDER BY name</query>
7
+            </sqldrop>
8
+        </layout>
9
+        <layout type="horizontal">
10
+            <label>Expected % weight loss:</label>
11
+            <line validator="numeric" id="expectedloss" />
12
+        </layout>
13
+        <layout type="horizontal">
14
+            <label>Tolerance</label>
15
+            <line validator="numeric" id="tolerance" />
16
+        </layout>
17
+        <label>Specification Notes:</label>
18
+        <textarea id="notes" />
19
+        <layout type="horizontal">
20
+            <stretch />
21
+            <button id="save" type="push" name="Save" />
22
+        </layout>
23
+    </layout>
24
+    <program>
25
+        <![CDATA[
26
+            var window = this;
27
+            this.windowTitle = "Typica - Edit Roasting Specification";
28
+            var selector = findChildObject(this, 'currentitems');
29
+            var expected = findChildObject(this, 'expectedloss');
30
+            var tolerance = findChildObject(this, 'tolerance');
31
+            var notes = findChildObject(this, 'notes');
32
+            var savebutton = findChildObject(this, 'save');
33
+            selector['currentIndexChanged(int)'].connect(function() {
34
+                var query = new QSqlQuery();
35
+                query.prepare("SELECT loss, tolerance, notes FROM roasting_specification WHERE item = :id1 AND time = (SELECT max(time) FROM roasting_specification WHERE item = :id2)");
36
+                query.bind(":id1", selector.currentData());
37
+                query.bind(":id2", selector.currentData());
38
+                query.exec();
39
+                if(query.next()) {
40
+                    if(query.value(0).length > 0) {
41
+                        expected.text = Number(query.value(0)) * 100;
42
+                    }
43
+                    if(query.value(1).length > 0) {
44
+                        tolerance.text = Number(query.value(1)) * 100;
45
+                    }
46
+                    notes.plainText = query.value(2);
47
+                }
48
+                query = query.invalidate();
49
+            });
50
+            savebutton.clicked.connect(function() {
51
+                var query = new QSqlQuery();
52
+                var columnspec = "time, item, ";
53
+                var valuespec = "'now', :id, ";
54
+                if(expected.text.length > 0) {
55
+                    columnspec += "loss, ";
56
+                    valuespec += ":loss, ";
57
+                }
58
+                if(tolerance.text.length > 0) {
59
+                    columnspec += "tolerance, ";
60
+                    valuespec += ":tolerance, ";
61
+                }
62
+                columnspec += "notes";
63
+                valuespec += ":notes";
64
+                query.prepare("INSERT INTO roasting_specification (" + columnspec + ") VALUES (" + valuespec + ")");
65
+                query.bind(":id", selector.currentData());
66
+                if(expected.text.length > 0) {
67
+                    query.bind(":loss", Number(expected.text) / 100);
68
+                }
69
+                if(tolerance.text.length > 0) {
70
+                    query.bind(":tolerance", Number(tolerance.text) / 100);
71
+                }
72
+                query.bind(":notes", notes.plainText);
73
+                query.exec();
74
+                window.close();
75
+            });
76
+        ]]>
77
+    </program>
78
+</window>

+ 1
- 0
config/config.xml View File

@@ -34,6 +34,7 @@
34 34
     <include src="Windows/editbatchdetails.xml" />
35 35
     <include src="Windows/newsamplebatch.xml" />
36 36
     <include src="Windows/editreminder.xml" />
37
+    <include src="Windows/roastspec.xml" />
37 38
     <program>
38 39
         <![CDATA[
39 40
             Windows = new Object();

Loading…
Cancel
Save