Typica is a free program for professional coffee roasters. https://typica.us
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

newbatch.xml 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. <window id="batchWindow">
  2. <menu name="Batch">
  3. <item id="new" shortcut="Ctrl+N">New Batch…</item>
  4. </menu>
  5. <layout type="vertical">
  6. <layout type="horizontal">
  7. <label>Machine:</label>
  8. <line id="machine" writable="false" />
  9. <label>Unit:</label>
  10. <sqldrop id="unit" />
  11. <stretch />
  12. </layout>
  13. <layout type="horizontal">
  14. <label>Roasted Coffee:</label>
  15. <sqldrop data="0" display="1" showdata="true" id="roasted">
  16. <null />
  17. <query>SELECT id, name FROM items WHERE category = 'Coffee: Roasted' AND id IN (SELECT item FROM current_items) ORDER BY name</query>
  18. </sqldrop>
  19. <stretch />
  20. </layout>
  21. <label>Green Coffee:</label>
  22. <sqltablearray columns="2" id="greens">
  23. <column name="Coffee" delegate="sql" showdata="true" null="false" data="0" display="1">SELECT id, name FROM coffees WHERE quantity &lt;&gt; 0 ORDER BY name</column>
  24. <column name="Weight" />
  25. </sqltablearray>
  26. <layout type="horizontal">
  27. <label>Green Weight:</label>
  28. <line id="green" writable="false">0.0</line>
  29. </layout>
  30. <layout type="horizontal">
  31. <button name="Load Profile" type="push" id="load" />
  32. <button name="No Profile" type="push" id="noprofile" />
  33. </layout>
  34. <layout type="horizontal">
  35. <label>Time:</label>
  36. <line id="time" writable="false" />
  37. <label>Duration:</label>
  38. <line id="duration" writable="false" />
  39. </layout>
  40. <layout type="horizontal">
  41. <label>Roasted Weight:</label>
  42. <line id="roast" validator="numeric" />
  43. <label>Weight Loss:</label>
  44. <line id="wloss" writable="false" />
  45. <button type="check" id="approval" name="Approved" />
  46. </layout>
  47. <layout type="horizontal">
  48. <label>Annotation:</label>
  49. <textarea id="annotation" />
  50. </layout>
  51. <layout type="horizontal">
  52. <button name="Submit" id="submit" type="push" />
  53. <button name="Save log as target profile" type="check" id="target" />
  54. </layout>
  55. </layout>
  56. <program>
  57. <![CDATA[
  58. var unitBox = findChildObject(this, 'unit');
  59. unitBox.addItem("g");
  60. unitBox.addItem("Kg");
  61. unitBox.addItem("oz");
  62. unitBox.addItem("lb");
  63. unitBox.currentIndex = (QSettings.value("script/batch_unit", unitBox.findText("lb")));
  64. var machine = findChildObject(this, "machine");
  65. machine.setText(selectedRoasterName + " (" + selectedRoasterID + ")");
  66. var newMenu = findChildObject(this, 'new');
  67. newMenu.triggered.connect(function() {
  68. var bwindow = createWindow("batchWindow");
  69. bwindow.windowTitle = "Typica - New Batch";
  70. });
  71. var batch = this;
  72. var table = findChildObject(this, 'greens');
  73. var green = findChildObject(this, 'green');
  74. var model = table.model();
  75. var lossField = findChildObject(this, 'wloss');
  76. lossField.maximumWidth = 80;
  77. var roasted = findChildObject(this, 'roasted');
  78. var roastwt = findChildObject(this, 'roast');
  79. roastwt.maximumWidth = 80;
  80. model.dataChanged.connect(function() {
  81. green.text = table.columnSum(1, 0);
  82. table.resizeColumnToContents(0);
  83. if(parseFloat(green.text) > 0)
  84. {
  85. if(parseFloat(roastwt.text) > 0)
  86. {
  87. lossField.text = (((parseFloat(green.text) - parseFloat(roastwt.text)) / parseFloat(green.text)) * 100).toFixed(2) + "%";
  88. }
  89. else
  90. {
  91. lossField.text = "100%";
  92. }
  93. }
  94. });
  95. roastwt.textChanged.connect(function() {
  96. if(parseFloat(green.text) > 0)
  97. {
  98. if(parseFloat(roastwt.text) > 0)
  99. {
  100. lossField.text = (((parseFloat(green.text) - parseFloat(roastwt.text)) / parseFloat(green.text)) * 100).toFixed(2) + "%";
  101. }
  102. else
  103. {
  104. lossField.text = "100%";
  105. }
  106. }
  107. });
  108. var convertToPounds = function(w, u) {
  109. switch(u) {
  110. case "g":
  111. return w * 0.0022;
  112. case "oz":
  113. return w * 0.0625;
  114. case "Kg":
  115. return w * 2.2;
  116. }
  117. return w;
  118. };
  119. var profilebutton = findChildObject(this, 'load');
  120. profilebutton.setEnabled(false);
  121. roasted['currentIndexChanged(int)'].connect(function() {
  122. var query = new QSqlQuery();
  123. var q = "SELECT EXISTS(SELECT 1 FROM item_files WHERE item = ";
  124. q = q + roasted.currentData();
  125. q = q + ")";
  126. query.exec(q);
  127. if(query.next())
  128. {
  129. if(query.value(0) == 'false')
  130. {
  131. profilebutton.setEnabled(false);
  132. }
  133. else
  134. {
  135. profilebutton.setEnabled(true);
  136. }
  137. }
  138. else
  139. {
  140. profilebutton.setEnabled(false);
  141. }
  142. var title = "Typica - New Batch (";
  143. title = title + roasted.currentText;
  144. title = title + ")";
  145. batch.windowTitle = title;
  146. q = "SELECT unroasted_id FROM roasting_log WHERE roasted_id = ";
  147. q = q + roasted.currentData();
  148. q = q + " AND time = (SELECT max(time) FROM roasting_log WHERE roasted_id = ";
  149. q = q + roasted.currentData();
  150. q = q + ")";
  151. query.exec(q);
  152. if(query.next())
  153. {
  154. var unroasted_items = sqlToArray(query.value(0));
  155. var names = [];
  156. q = "SELECT name FROM items WHERE id = :id AND quantity <> 0";
  157. query.prepare(q);
  158. var allInStock = true;
  159. for(var i = 0; i < unroasted_items.length; i++)
  160. {
  161. query.bind("id", unroasted_items[i]);
  162. query.exec();
  163. if(query.next())
  164. {
  165. names[i] = query.value(0);
  166. }
  167. else
  168. {
  169. allInStock = false;
  170. }
  171. }
  172. if(allInStock)
  173. {
  174. for(var i = 0; i < unroasted_items.length; i++)
  175. {
  176. table.setData(i, 0, names[i], 0);
  177. table.setData(i, 0, unroasted_items[i], 32);
  178. }
  179. }
  180. }
  181. });
  182. profilebutton.clicked.connect(function() {
  183. currentBatchInfo = batch;
  184. query = new QSqlQuery();
  185. var q = "SELECT files FROM item_files WHERE item = :item AND time = (SELECT max(time) FROM item_files WHERE item = :again)";
  186. query.prepare(q);
  187. query.bind(":item", Number(roasted.currentData()));
  188. query.bind(":again", Number(roasted.currentData()));
  189. query.exec();
  190. if(query.next())
  191. {
  192. var files = query.value(0);
  193. files = files.replace("{", "(");
  194. files = files.replace("}", ")");
  195. q = "SELECT file, name FROM files WHERE id IN ";
  196. q = q + files;
  197. q = q + " AND type = 'profile'";
  198. query.exec(q);
  199. if(query.next())
  200. {
  201. var targetseries = -1;
  202. var buffer = new QBuffer(query.value(0));
  203. var pname = query.value(1);
  204. var input = new XMLInput(buffer, 1);
  205. var graph = findChildObject(navigationwindow.loggingWindow, 'graph');
  206. var log = findChildObject(navigationwindow.loggingWindow, 'log');
  207. log.clear();
  208. graph.clear();
  209. input.newTemperatureColumn.connect(log.setHeaderData);
  210. input.newTemperatureColumn.connect(function(col, text) {
  211. if(text == navigationwindow.loggingWindow.targetcolumnname)
  212. {
  213. targetseries = col;
  214. }
  215. });
  216. input.newAnnotationColumn.connect(log.setHeaderData);
  217. input.measure.connect(graph.newMeasurement);
  218. input.measure.connect(log.newMeasurement);
  219. input.measure.connect(function(data, series) {
  220. if(series == targetseries)
  221. {
  222. targetDetector.newMeasurement(data);
  223. }
  224. });
  225. input.annotation.connect(log.newAnnotation);
  226. var lc;
  227. input.lastColumn.connect(function(c) {
  228. lc = c;
  229. QSettings.setValue("liveColumn", c + 1);
  230. navigationwindow.loggingWindow.postLoadColumnSetup(c)
  231. });
  232. }
  233. }
  234. query = query.invalidate();
  235. navigationwindow.loggingWindow.windowTitle = "Typica - " + pname;
  236. navigationwindow.loggingWindow.raise();
  237. navigationwindow.loggingWindow.activateWindow();
  238. input.input();
  239. log.newAnnotation("End", 1, lc);
  240. });
  241. var noprofilebutton = findChildObject(this, 'noprofile');
  242. noprofilebutton.clicked.connect(function() {
  243. currentBatchInfo = batch;
  244. navigationwindow.loggingWindow.raise();
  245. navigationwindow.loggingWindow.activateWindow();
  246. });
  247. var submitbutton = findChildObject(this, 'submit');
  248. var timefield = findChildObject(this, 'time');
  249. var notes = findChildObject(this, 'annotation');
  250. /*
  251. var machine = findChildObject(this, 'machine');
  252. machine.currentIndex = QSettings.value("batchmachine_last", 0);
  253. machine['currentIndexChanged(int)'].connect(function() {
  254. QSettings.setValue("batchmachine_last", machine.currentIndex);
  255. });
  256. */
  257. var duration = findChildObject(this, 'duration');
  258. var approval = findChildObject(this, 'approval');
  259. var target = findChildObject(this, 'target');
  260. submitbutton.clicked.connect(function() {
  261. checkQuery = new QSqlQuery();
  262. checkQuery.exec("SELECT 1 FROM machine WHERE id = " + selectedRoasterID);
  263. if(!checkQuery.next())
  264. {
  265. checkQuery.prepare("INSERT INTO machine VALUES(:id, :name)");
  266. checkQuery.bind(":id", selectedRoasterID);
  267. checkQuery.bind(":name", selectedRoasterName);
  268. checkQuery.exec();
  269. }
  270. checkQuery = checkQuery.invalidate();
  271. var q = "INSERT INTO files VALUES(default, :name, 'profile', NULL, :data) RETURNING id";
  272. query = new QSqlQuery();
  273. query.prepare(q);
  274. query.bind(":name", timefield.text + " " + roasted.currentText);
  275. query.bindFileData(":data", batch.tempData);
  276. query.exec();
  277. query.next();
  278. var fileno = query.value(0);
  279. var file = new QFile(batch.tempData);
  280. file.remove();
  281. var q2 = "INSERT INTO roasting_log VALUES(:time, ";
  282. q2 = q2 + table.columnArray(0, 32);
  283. q2 = q2 + ", ";
  284. for(var i = 0; table.data(i, 1, 0).value != ""; i++)
  285. {
  286. table.setData(i, 1, convertToPounds(parseFloat(table.data(i, 1, 0)), unitBox.currentText) ,32)
  287. }
  288. q2 = q2 + table.columnArray(1, 32);
  289. q2 = q2 + ", ";
  290. q2 = q2 + convertToPounds(parseFloat(green.text), unitBox.currentText);
  291. q2 = q2 + ", ";
  292. q2 = q2 + roasted.currentData();
  293. q2 = q2 + ", ";
  294. q2 = q2 + convertToPounds(parseFloat(roastwt.text), unitBox.currentText);
  295. q2 = q2 + ", 'ROAST', :annotation, ";
  296. q2 = q2 + selectedRoasterID;
  297. q2 = q2 + ", :duration, :approval, NULL, NULL, NULL, NULL, '{";
  298. q2 = q2 + fileno;
  299. q2 = q2 + "}')";
  300. query2 = new QSqlQuery();
  301. query2.prepare(q2);
  302. query2.bind(":time", timefield.text);
  303. query2.bind(":annotation", notes.plainText);
  304. query2.bind(":duration", duration.text);
  305. query2.bind(":approval", approval.checked);
  306. query2.exec();
  307. query2 = query2.invalidate();
  308. if(target.checked) {
  309. var q3 = "INSERT INTO item_files VALUES(:time, :item, '{";
  310. q3 = q3 + fileno;
  311. q3 = q3 + "}')";
  312. query.prepare(q3);
  313. query.bind(":time", timefield.text);
  314. query.bind(":item", roasted.currentData());
  315. query.exec();
  316. }
  317. query = query.invalidate();
  318. batch.close();
  319. });
  320. ]]>
  321. </program>
  322. </window>