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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  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. batch.windowModified = true;
  184. currentBatchInfo = batch;
  185. query = new QSqlQuery();
  186. var q = "SELECT files FROM item_files WHERE item = :item AND time = (SELECT max(time) FROM item_files WHERE item = :again)";
  187. query.prepare(q);
  188. query.bind(":item", Number(roasted.currentData()));
  189. query.bind(":again", Number(roasted.currentData()));
  190. query.exec();
  191. if(query.next())
  192. {
  193. var files = query.value(0);
  194. files = files.replace("{", "(");
  195. files = files.replace("}", ")");
  196. q = "SELECT file, name FROM files WHERE id IN ";
  197. q = q + files;
  198. q = q + " AND type = 'profile'";
  199. query.exec(q);
  200. if(query.next())
  201. {
  202. var targetseries = -1;
  203. var buffer = new QBuffer(query.value(0));
  204. var pname = query.value(1);
  205. var input = new XMLInput(buffer, 1);
  206. var graph = findChildObject(navigationwindow.loggingWindow, 'graph');
  207. var log = findChildObject(navigationwindow.loggingWindow, 'log');
  208. log.clear();
  209. graph.clear();
  210. input.newTemperatureColumn.connect(log.setHeaderData);
  211. input.newTemperatureColumn.connect(function(col, text) {
  212. if(text == navigationwindow.loggingWindow.targetcolumnname)
  213. {
  214. targetseries = col;
  215. }
  216. });
  217. input.newAnnotationColumn.connect(log.setHeaderData);
  218. input.measure.connect(graph.newMeasurement);
  219. input.measure.connect(log.newMeasurement);
  220. input.measure.connect(function(data, series) {
  221. if(series == targetseries)
  222. {
  223. targetDetector.newMeasurement(data);
  224. }
  225. });
  226. input.annotation.connect(log.newAnnotation);
  227. var lc;
  228. input.lastColumn.connect(function(c) {
  229. lc = c;
  230. QSettings.setValue("liveColumn", c + 1);
  231. navigationwindow.loggingWindow.postLoadColumnSetup(c)
  232. });
  233. }
  234. }
  235. query = query.invalidate();
  236. navigationwindow.loggingWindow.windowTitle = "Typica - " + pname;
  237. navigationwindow.loggingWindow.raise();
  238. navigationwindow.loggingWindow.activateWindow();
  239. input.input();
  240. log.newAnnotation("End", 1, lc);
  241. });
  242. var noprofilebutton = findChildObject(this, 'noprofile');
  243. noprofilebutton.clicked.connect(function() {
  244. batch.windowModified = true;
  245. currentBatchInfo = batch;
  246. navigationwindow.loggingWindow.raise();
  247. navigationwindow.loggingWindow.activateWindow();
  248. });
  249. var submitbutton = findChildObject(this, 'submit');
  250. var timefield = findChildObject(this, 'time');
  251. var notes = findChildObject(this, 'annotation');
  252. var duration = findChildObject(this, 'duration');
  253. var approval = findChildObject(this, 'approval');
  254. var target = findChildObject(this, 'target');
  255. submitbutton.clicked.connect(function() {
  256. checkQuery = new QSqlQuery();
  257. checkQuery.exec("SELECT 1 FROM machine WHERE id = " + selectedRoasterID);
  258. if(!checkQuery.next())
  259. {
  260. checkQuery.prepare("INSERT INTO machine VALUES(:id, :name)");
  261. checkQuery.bind(":id", selectedRoasterID);
  262. checkQuery.bind(":name", selectedRoasterName);
  263. checkQuery.exec();
  264. }
  265. checkQuery = checkQuery.invalidate();
  266. var q = "INSERT INTO files VALUES(default, :name, 'profile', NULL, :data) RETURNING id";
  267. query = new QSqlQuery();
  268. query.prepare(q);
  269. query.bind(":name", timefield.text + " " + roasted.currentText);
  270. query.bindFileData(":data", batch.tempData);
  271. query.exec();
  272. query.next();
  273. var fileno = query.value(0);
  274. var file = new QFile(batch.tempData);
  275. file.remove();
  276. var q2 = "INSERT INTO roasting_log VALUES(:time, ";
  277. q2 = q2 + table.columnArray(0, 32);
  278. q2 = q2 + ", ";
  279. for(var i = 0; table.data(i, 1, 0).value != ""; i++)
  280. {
  281. table.setData(i, 1, convertToPounds(parseFloat(table.data(i, 1, 0)), unitBox.currentText) ,32)
  282. }
  283. q2 = q2 + table.columnArray(1, 32);
  284. q2 = q2 + ", ";
  285. q2 = q2 + convertToPounds(parseFloat(green.text), unitBox.currentText);
  286. q2 = q2 + ", ";
  287. q2 = q2 + roasted.currentData();
  288. q2 = q2 + ", ";
  289. q2 = q2 + convertToPounds(parseFloat(roastwt.text), unitBox.currentText);
  290. q2 = q2 + ", 'ROAST', :annotation, ";
  291. q2 = q2 + selectedRoasterID;
  292. q2 = q2 + ", :duration, :approval, NULL, NULL, NULL, NULL, '{";
  293. q2 = q2 + fileno;
  294. q2 = q2 + "}')";
  295. query2 = new QSqlQuery();
  296. query2.prepare(q2);
  297. query2.bind(":time", timefield.text);
  298. query2.bind(":annotation", notes.plainText);
  299. query2.bind(":duration", duration.text);
  300. query2.bind(":approval", approval.checked);
  301. query2.exec();
  302. query2 = query2.invalidate();
  303. if(target.checked) {
  304. var q3 = "INSERT INTO item_files VALUES(:time, :item, '{";
  305. q3 = q3 + fileno;
  306. q3 = q3 + "}')";
  307. query.prepare(q3);
  308. query.bind(":time", timefield.text);
  309. query.bind(":item", roasted.currentData());
  310. query.exec();
  311. }
  312. query = query.invalidate();
  313. batch.windowModified = false;
  314. batch.close();
  315. });
  316. ]]>
  317. </program>
  318. </window>