Browse Source

New window for sample roasting. Fixes #51

Neal Wilson 11 years ago
parent
commit
0d7b235186
3 changed files with 318 additions and 0 deletions
  1. 312
    0
      config/Windows/newsamplebatch.xml
  2. 5
    0
      config/Windows/productionroaster.xml
  3. 1
    0
      config/config.xml

+ 312
- 0
config/Windows/newsamplebatch.xml View File

@@ -0,0 +1,312 @@
1
+<window id="sampleRoastingBatch">
2
+	<menu name="Batch">
3
+		<item id="new" shortcut="Ctrl+N">New Batch...</item>
4
+	</menu>
5
+	<layout type="horizontal">
6
+		<layout type="vertical">
7
+			<label>Sample Details:</label>
8
+			<layout type="grid">
9
+				<row>
10
+					<column><label>Name:</label></column>
11
+					<column><line id="name" /></column>
12
+				</row>
13
+				<row>
14
+					<column><label>Vendor:</label></column>
15
+					<column><line id="vendor" /></column>
16
+				</row>
17
+				<row>
18
+					<column><label>Date:</label></column>
19
+					<column><calendar id="date" /></column>
20
+				</row>
21
+			</layout>
22
+			<label>Optional Details:</label>
23
+			<sqltablearray columns="2" id="attributes">
24
+				<column name="Attribute" />
25
+				<column name="Value" />
26
+			</sqltablearray>
27
+			<stretch />
28
+		</layout>
29
+		<layout type="vertical">
30
+			<label>Roasting Details:</label>
31
+			<layout type="grid">
32
+				<row>
33
+					<column><label>Machine:</label></column>
34
+					<column><line id="machine" writable="false" /></column>
35
+				</row>
36
+				<row>
37
+					<column><label>Target Profile:</label></column>
38
+					<column>
39
+						<sqldrop data="0" display="0" showdata="false" editable="true" id="profile">
40
+							<query>SELECT DISTINCT profile_name FROM sample_roast_profiles UNION SELECT '' ORDER BY profile_name ASC</query>
41
+						</sqldrop>
42
+					</column>
43
+				</row>
44
+				<row>
45
+					<column><label>Green Weight:</label></column>
46
+					<column><line id="greenWt" /></column>
47
+					<column>
48
+						<sqldrop data="0" display="0" showdata="false" editable="false" id="Gunits" />
49
+					</column>
50
+				</row>
51
+				<row>
52
+					<column><label>Roasted Weight:</label></column>
53
+					<column><line id="roastedWt" /></column>
54
+				</row>
55
+				<row>
56
+					<column><label>Weight Loss:</label></column>
57
+					<column><line writable="false" id="loss" /></column>
58
+				</row>
59
+				<row>
60
+					<column><label>Time:</label></column>
61
+					<column><line id="time" writable="false" /></column>
62
+				</row>
63
+			</layout>
64
+			<label>Notes:</label>
65
+			<textarea id="annotation" />
66
+			<layout type="horizontal">
67
+				<button name="Roast" type="push" id="load" />
68
+				<button name="Submit" type="push" id="submit" />
69
+			</layout>
70
+			<button name="Save log as target profile" type="check" id="target" />
71
+			<stretch />
72
+		</layout>
73
+		<layout type="vertical">
74
+			<label>Connected Scales</label>
75
+			<layout type="vertical" id="scales" />
76
+			<stretch />
77
+		</layout>
78
+	</layout>
79
+	<program>
80
+		<![CDATA[
81
+			var machine = findChildObject(this, 'machine');
82
+			machine.setText(selectedRoasterName + " (" + selectedRoasterID + ")");
83
+			var GunitBox = findChildObject(this, 'Gunits');
84
+			GunitBox.addItem("g");
85
+			GunitBox.addItem("Kg");
86
+			GunitBox.addItem("oz");
87
+			GunitBox.addItem("lb");
88
+			var scalesLayout = findChildObject(this, 'scales');
89
+			scalesLayout.spacing = 10;
90
+			if(navigationwindow.loggingWindow.scales.length > 0)
91
+			{
92
+				for(var i = 0; i < navigationwindow.loggingWindow.scales.length; i++)
93
+				{
94
+					var scale = navigationwindow.loggingWindow.scales[i];
95
+					var label = new DragLabel();
96
+					var weighButton = new QPushButton();
97
+					weighButton.text = "Weigh";
98
+					weighButton.clicked.connect(scale.weigh);
99
+					label.updateMeasurement = function(m, u) {
100
+						switch(GunitBox.currentIndex) {
101
+							case 0:
102
+								this.text = Units.convertWeight(m, u, Units.Gram).toFixed(1);
103
+								break;
104
+							case 1:
105
+								this.text = Units.convertWeight(m, u, Units.Kilogram).toFixed(4);
106
+								break;
107
+							case 2:
108
+								this.text = Units.convertWeight(m, u, Units.Ounce).toFixed(3);
109
+								break;
110
+							case 3:
111
+								this.text = Units.convertWeight(m, u, Units.Pound).toFixed(4);
112
+								break;
113
+						}
114
+					};
115
+					scalesLayout.addWidget(label);
116
+					scalesLayout.addWidget(weighButton);
117
+					scale.newMeasurement.connect(function(m, u) {
118
+						label.updateMeasurement(m, u);
119
+					});
120
+					scale.weigh();
121
+					GunitBox['currentIndexChanged(int)'].connect(scale.weigh);
122
+				}
123
+			}
124
+			var submit = findChildObject(this, 'submit');
125
+			submit.setEnabled(false);
126
+			this.windowTitle = "Typica - New Sample Roasting Batch";
127
+			var newMenu = findChildObject(this, 'new');
128
+			newMenu.triggered.connect(function() {
129
+				createWindow("sampleRoastingBatch");
130
+			});
131
+			var batch = this;
132
+			batch.submitButton = submit;
133
+			var name = findChildObject(this, 'name');
134
+			var green = findChildObject(this, 'greenWt');
135
+			var roasted = findChildObject(this, 'roastedWt');
136
+			var loss = findChildObject(this, 'loss');
137
+			var timefield = findChildObject(this, 'time');
138
+			var convertToPounds = function(w, u) {
139
+				switch(u)
140
+				{
141
+					case "g":
142
+						return w * 0.0022;
143
+					case "oz":
144
+						return w * 0.0625;
145
+					case "Kg":
146
+						return w * 2.2;
147
+				}
148
+				return w;
149
+			};
150
+			var updateWeightLoss = function() {
151
+				var cgreen = parseFloat(green.text);
152
+				var croast = parseFloat(roasted.text);
153
+				if(cgreen > 0)
154
+				{
155
+					if(croast > 0)
156
+					{
157
+						loss.text = (((cgreen - croast) / cgreen) * 100).toFixed(2) + "%";
158
+					}
159
+					else
160
+					{
161
+						loss.text = "100%";
162
+					}
163
+				}
164
+			};
165
+			green.textChanged.connect(function() {
166
+				updateWeightLoss();
167
+			});
168
+			roasted.textChanged.connect(function() {
169
+				updateWeightLoss();
170
+			});
171
+			var roastButton = findChildObject(this, 'load');
172
+			var profileName = findChildObject(this, 'profile');
173
+			var greenName = findChildObject(this, 'name');
174
+			roastButton.clicked.connect(function() {
175
+				var stop = findChildObject(navigationwindow.loggingWindow, 'stopbutton');
176
+				stop.clicked.connect(function() {
177
+					submit.setEnabled(true);
178
+				});
179
+				var lc = 1;
180
+				currentBatchInfo = batch;
181
+				query = new QSqlQuery();
182
+				var q = "SELECT file FROM sample_roast_profiles WHERE profile_name = :name AND time = (SELECT max(time) FROM sample_roast_profiles WHERE profile_name = :again)";
183
+				query.prepare(q);
184
+				query.bind(":name", profileName.currentText);
185
+				query.bind(":again", profileName.currentText);
186
+				query.exec();
187
+				if(query.next())
188
+				{
189
+					var file = query.value(0);
190
+					query.prepare("SELECT file FROM files WHERE id = :id");
191
+					query.bind(":id", file);
192
+					query.exec();
193
+					if(query.next())
194
+					{
195
+						var targetseries = -1;
196
+						var buffer = new QBuffer(query.value(0));
197
+						var input = new XMLInput(buffer, 1);
198
+						var graph = findChildObject(navigationwindow.loggingWindow, 'graph');
199
+						var log = findChildObject(navigationwindow.loggingWindow, 'log');
200
+						log.clear();
201
+						graph.clear();
202
+						input.newTemperatureColumn.connect(function(col, text) {
203
+							log.setHeaderData(col, text);
204
+							if(text == navigationwindow.loggingWindow.targetcolumnname)
205
+							{
206
+								targetseries = col;
207
+							}
208
+						});
209
+						input.newAnnotationColumn.connect(log.setHeaderData);
210
+						input.measure.connect(graph.newMeasurement);
211
+						input.measure.connect(log.newMeasurement);
212
+						input.measure.connect(function(data, series) {
213
+							if(series == targetseries)
214
+							{
215
+								targetDetector.newMeasurement(data);
216
+							}
217
+						});
218
+						input.annotation.connect(log.newAnnotation);
219
+						input.lastColumn.connect(function(c) {
220
+							lc = c;
221
+							QSettings.setValue("liveColumn", c+1);
222
+							navigationwindow.loggingWindow.postLoadColumnSetup(c);
223
+						});
224
+						navigationwindow.loggingWindow.raise();
225
+						navigationwindow.loggingWindow.activateWindow();
226
+						input.input();
227
+						log.newAnnotation("End", 1, lc);
228
+					}
229
+				}
230
+				query = query.invalidate();
231
+				var t = "Typica - Sample Roasting: [*]" + name.text;
232
+				if(profileName.currentText != '')
233
+				{
234
+					t = t + ", " + profileName.currentText;
235
+				}
236
+				navigationwindow.loggingWindow.windowTitle = t;
237
+			});
238
+			var notes = findChildObject(this, 'annotation');
239
+			var machine = findChildObject(this, 'machine');
240
+			var duration = findChildObject(this, 'duration');
241
+			var arrival = findChildObject(this, 'date');
242
+			var vendor = findChildObject(this, 'vendor');
243
+			var attributes = findChildObject(this, 'attributes');
244
+			var target = findChildObject(this, 'target');
245
+			submit.clicked.connect(function() {
246
+				query = new QSqlQuery();
247
+				query.prepare("INSERT INTO files VALUES(default, :name, 'profile', NULL, :data) RETURNING id");
248
+				query.bind(":name", timefield.text + " " + name.text + " " + profileName.currentText);
249
+				query.bindFileData(":data", batch.tempData);
250
+				query.exec();
251
+				query.next();
252
+				var fileno = query.value(0);
253
+				var file = new QFile(batch.tempData);
254
+				file.remove();
255
+				if(target.checked)
256
+				{
257
+					query.prepare("INSERT INTO sample_roast_profiles VALUES(:time, :name, :file)");
258
+					query.bind(":time", timefield.text);
259
+					query.bind(":name", profileName.currentText);
260
+					query.bind(":file", Number(fileno));
261
+					query.exec();
262
+				}
263
+				var attnames = sqlToArray(attributes.columnArray(0, 0));
264
+				for(var i = 0; i < attnames.length; i++)
265
+				{
266
+					query.prepare("SELECT id FROM item_attributes WHERE name = :name");
267
+					query.bind(":name", attnames[i]);
268
+					query.exec();
269
+					if(query.next())
270
+					{
271
+						attributes.setData(i, 0, query.value(0), 32);
272
+					}
273
+					else
274
+					{
275
+						query.prepare("INSERT INTO item_attributes VALUES(DEFAULT, :name) RETURNING id");
276
+						query.bind(":name", attnames[i]);
277
+						query.exec();
278
+						query.next();
279
+						attributes.setData(i, 0, query.value(0), 32);
280
+					}
281
+				}
282
+				query.prepare("INSERT INTO coffee_sample_items(DEFAULT, :name, NULL, 'lb', 0, 'Coffee: Green Sample', :arrival, :vendor, :attrids, :attrvals, NULL) RETURNING id");
283
+				query.bind(":name", name.text);
284
+				query.bind(":arrival", arrival.date);
285
+				query.bind(":vendor", vendor.text);
286
+				query.bind(":attrids", attributes.bindableColumnArray(0, 32));
287
+				query.bind(":attrvals", attributes.bindableQuotedColumnArray(1, 0));
288
+				query.exec();
289
+				query.next();
290
+				var greenId = query.value(0);
291
+				query.prepare("INSERT INTO items(DEFAULT, :name, NULL, 'lb', 0, 'Coffee: Roasted Sample') RETURNING id");
292
+				query.bind(":name", name.text + " " + profileName.currentText);
293
+				query.exec();
294
+				query.next();
295
+				var roastedId = query.value(0);
296
+				query.prepare("INSERT INTO roasting_log VALUES(:time, :unroastedids, NULL, :green, :roastedid, :roasted, 'SAMPLEROAST', :note, :machine, :duration, TRUE, NULL, NULL, NULL, NULL, :files)");
297
+				query.bind(":time", timefield.text);
298
+				query.bind(":unroastedids", "{" + greenId + "}");
299
+				query.bind(":green", convertToPounds(parseFloat(green.text), GunitBox.currentText));
300
+				query.bind(":roastedid", Number(roastedId));
301
+				query.bind(":roasted", convertToPounds(parseFloat(roasted.text), GunitBox.currentText));
302
+				query.bind(":note", notes.plainText);
303
+				query.bind(":machine", Number(selectedRoastedID));
304
+				query.bind(":duration", duration.text);
305
+				query.bind(":files", "{" + fileno + "}");
306
+				query.exec();
307
+				query = query.invalidate();
308
+				batch.close();
309
+			});
310
+		]]>
311
+	</program>
312
+</window>

+ 5
- 0
config/Windows/productionroaster.xml View File

@@ -24,6 +24,7 @@
24 24
     </menu>
25 25
     <menu name="Batch">
26 26
         <item id="new" shortcut="Ctrl+N">New Batch…</item>
27
+		<item id="newsample">New Sample Batch…</item>
27 28
         <item id="compare">Load Additional Profiles...</item>
28 29
     </menu>
29 30
     <menu name="Log">
@@ -932,6 +933,10 @@
932 933
             var bwindow = createWindow("batchWindow");
933 934
             bwindow.windowTitle = "Typica - [*]New Batch";
934 935
         });
936
+		var newSampleMenu = findChildObject(this, 'newsample');
937
+		newSampleMenu.triggered.connect(function() {
938
+			var bwindow = createWindow("sampleRoastingBatch");
939
+		});
935 940
 		window.postLoadColumnSetup(0);
936 941
 		]]>
937 942
     </program>

+ 1
- 0
config/config.xml View File

@@ -32,6 +32,7 @@
32 32
 	<include src="Windows/greensales.xml" />
33 33
 	<include src="Windows/profilehistory.xml" />
34 34
 	<include src="Windows/editbatchdetails.xml" />
35
+	<include src="Windows/newsamplebatch.xml" />
35 36
 	<program>
36 37
 		var loggingWindow;
37 38
 		var currentBatchInfo;

Loading…
Cancel
Save