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.

itemtransactions.xml 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. <window id="item_transactions">
  2. <reporttitle>Inventory:->Item Transactions</reporttitle>
  3. <layout type="vertical">
  4. <layout type="horizontal">
  5. <label>Item:</label>
  6. <sqldrop id="item" data="0" display="1" showdata="true">
  7. <null />
  8. <query>SELECT id, name FROM items WHERE category = 'Coffee: Unroasted' ORDER BY name</query>
  9. </sqldrop>
  10. <label>Weight Unit:</label>
  11. <sqldrop id="unit" />
  12. <stretch />
  13. </layout>
  14. <webview id="report" />
  15. </layout>
  16. <menu name="File">
  17. <item id="print" shortcut="Ctrl+P">Print</item>
  18. </menu>
  19. <program>
  20. <![CDATA[
  21. this.windowTitle = "Typica - Item Transactions";
  22. var itemBox = findChildObject(this, 'item');
  23. var unitBox = findChildObject(this, 'unit');
  24. unitBox.addItem("Kg");
  25. unitBox.addItem("Lb");
  26. unitBox.currentIndex = QSettings.value("script/report_unit", 1);
  27. unitBox['currentIndexChanged(int)'].connect(function() {
  28. QSettings.setValue("script/report_unit", unitBox.currentIndex);
  29. refresh();
  30. });
  31. var view = findChildObject(this, 'report');
  32. var printMenu = findChildObject(this, 'print');
  33. printMenu.triggered.connect(function() {
  34. view.print();
  35. });
  36. itemBox['currentIndexChanged(int)'].connect(function() {
  37. refresh();
  38. });
  39. function refresh() {
  40. var buffer = new QBuffer;
  41. buffer.open(3);
  42. var output = new XmlWriter(buffer);
  43. output.writeStartDocument("1.0");
  44. output.writeDTD('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg.dtd">');
  45. output.writeStartElement("html");
  46. output.writeAttribute("xmlns", "http://www.w3.org/1999/xhtml");
  47. output.writeStartElement("head");
  48. output.writeTextElement("title", "Item Transactions");
  49. output.writeStartElement("script");
  50. output.writeAttribute("src", "Scripts/d3.min.js");
  51. output.writeEndElement();
  52. output.writeStartElement("style");
  53. output.writeAttribute("type", "text/css");
  54. output.writeCDATA("tr.PURCHASE {background-color: #77FF77}");
  55. output.writeCDATA("tr.USE {background-color: #FFFFFF}");
  56. output.writeCDATA("tr.INVENTORY {background-color: #7777FF}");
  57. output.writeCDATA("tr.SALE {background-color: #FF77FF}");
  58. output.writeCDATA("tr.LOSS {background-color: #FF7777}");
  59. output.writeCDATA("tr.MAKE {background-color: #FFFF77}");
  60. output.writeEndElement(); // style
  61. output.writeEndElement();
  62. output.writeStartElement("body");
  63. output.writeTextElement("h1", "Item Transactions:");
  64. output.writeStartElement("table");
  65. output.writeStartElement("tr");
  66. output.writeStartElement("td");
  67. output.writeTextElement("strong", "Item: ")
  68. output.writeTextElement("span", itemBox.currentText);
  69. output.writeEndElement(); // td
  70. var query = new QSqlQuery();
  71. query.prepare("SELECT reference, category FROM items WHERE id = :item");
  72. query.bind(":item", itemBox.currentData());
  73. query.exec();
  74. if(query.next()) {
  75. output.writeStartElement("td");
  76. output.writeTextElement("strong", "Reference: ");
  77. output.writeTextElement("span", query.value(0));
  78. output.writeEndElement(); // td
  79. output.writeStartElement("td");
  80. output.writeTextElement("strong", "Category: ");
  81. output.writeTextElement("span", query.value(1));
  82. output.writeEndElement(); //td
  83. output.writeEndElement(); //tr
  84. query.prepare("SELECT origin, region, producer, grade, milling, drying FROM coffees WHERE id = :item");
  85. query.bind(":item", itemBox.currentData());
  86. query.exec();
  87. if(query.next()) {
  88. output.writeStartElement("tr");
  89. output.writeStartElement("td");
  90. output.writeTextElement("strong", "Origin: ");
  91. output.writeTextElement("span", query.value(0));
  92. output.writeEndElement(); // td
  93. output.writeStartElement("td");
  94. output.writeTextElement("strong", "Region: ");
  95. output.writeTextElement("span", query.value(1));
  96. output.writeEndElement(); // td
  97. output.writeStartElement("td");
  98. output.writeTextElement("strong", "Producer: ");
  99. output.writeTextElement("span", query.value(2));
  100. output.writeEndElement(); // td
  101. output.writeEndElement(); // tr
  102. output.writeStartElement("tr");
  103. output.writeStartElement("td");
  104. output.writeTextElement("strong", "Grade: ");
  105. output.writeTextElement("span", query.value(3));
  106. output.writeEndElement(); // td
  107. output.writeStartElement("td");
  108. output.writeTextElement("strong", "Milling: ");
  109. output.writeTextElement("span", query.value(4));
  110. output.writeEndElement(); // td
  111. output.writeStartElement("td");
  112. output.writeTextElement("strong", "Drying: ");
  113. output.writeTextElement("span", query.value(5));
  114. output.writeEndElement(); // td
  115. output.writeEndElement(); // tr
  116. query.prepare("SELECT decaf_method FROM decaf_coffees WHERE id = :item");
  117. query.bind(":item", itemBox.currentData());
  118. query.exec();
  119. if(query.next()) {
  120. output.writeStartElement("tr");
  121. output.writeStartElement("td");
  122. output.writeAttribute("colspan", "3");
  123. output.writeTextElement("strong", "Decaffeination Method: ");
  124. output.writeTextElement("span", query.value(0));
  125. output.writeEndElement(); // td
  126. output.writeEndElement(); // tr
  127. }
  128. }
  129. output.writeEndElement() // table
  130. output.writeStartElement("div");
  131. output.writeAttribute("id", "chart");
  132. output.writeEndElement();
  133. query.prepare("WITH q AS (SELECT roasted_id, unroasted_id, unroasted_quantity, unroasted_total_quantity, roasted_quantity, generate_subscripts(unroasted_quantity, 1) AS s FROM roasting_log) SELECT (SELECT name FROM items WHERE id = roasted_id) AS name, roasted_id, SUM(unroasted_quantity[s]) AS total, COUNT(unroasted_quantity[s]), SUM((unroasted_quantity[s]/unroasted_total_quantity)*roasted_quantity)::numeric(12,3) AS roast_proportion FROM q WHERE unroasted_id[s] = :item1 GROUP BY roasted_id UNION SELECT 'Green Sales', NULL, SUM(quantity), COUNT(1), NULL FROM sale WHERE item = :item2 UNION SELECT 'Inventory Adjustment', NULL, ((SELECT SUM(quantity) FROM purchase WHERE item = :item3) - (SELECT quantity FROM items WHERE id = :item4) - (SELECT SUM(quantity) FROM all_transactions WHERE type != 'PURCHASE' AND type != 'INVENTORY' AND item = :item5)), (SELECT COUNT(1) FROM inventory WHERE item = :item6), NULL UNION SELECT 'Loss', NULL, SUM(quantity), COUNT(1), NULL FROM loss WHERE item = :item7 UNION SELECT 'Current Inventory', NULL, (SELECT quantity FROM items WHERE id = :item8), NULL, NULL ORDER BY total DESC");
  134. query.bind(":item1", itemBox.currentData());
  135. query.bind(":item2", itemBox.currentData());
  136. query.bind(":item3", itemBox.currentData());
  137. query.bind(":item4", itemBox.currentData());
  138. query.bind(":item5", itemBox.currentData());
  139. query.bind(":item6", itemBox.currentData());
  140. query.bind(":item7", itemBox.currentData());
  141. query.bind(":item8", itemBox.currentData());
  142. query.exec();
  143. var chartData = "var data = [";
  144. var roastedCoffeeLines = "";
  145. var adjustmentLines = "";
  146. var currentInventoryLine = "";
  147. var conversion = 1;
  148. if(unitBox.currentIndex == 0) {
  149. conversion = 2.2;
  150. }
  151. while(query.next()) {
  152. if(Number(query.value(1)) > 0) {
  153. roastedCoffeeLines += "['" + query.value(0).replace(/\'/g, "\\x27") + "'," + query.value(2) / conversion + "," + query.value(3) + "," + query.value(4) / conversion + "],";
  154. } else if (query.value(0) == "Current Inventory") {
  155. currentInventoryLine = "['Current Inventory'," + query.value(2) / conversion + "," + query.value(3) + "," + query.value(4) / conversion + "]";
  156. } else {
  157. if(Number(query.value(3)) > 0) {
  158. adjustmentLines += "['" + query.value(0) + "'," + query.value(2) / conversion + "," + query.value(3) + "," + query.value(4) / conversion + "],";
  159. }
  160. }
  161. }
  162. chartData = chartData + roastedCoffeeLines + adjustmentLines + currentInventoryLine + "];";
  163. output.writeTextElement("script", chartData);
  164. output.writeStartElement("script");
  165. output.writeAttribute("src", "Scripts/greenusechart.js");
  166. output.writeEndElement();
  167. query.prepare("SELECT time::date, type, quantity / :c1, balance / :c2, (SELECT files FROM roasting_log WHERE roasting_log.time = item_history.time AND item = ANY(unroasted_id)), (SELECT invoice_id FROM invoice_items WHERE item = item_id AND item_history.type = 'PURCHASE'), (SELECT vendor || ' ' || invoice FROM invoices WHERE id = (SELECT invoice_id FROM invoice_items WHERE item = item_id AND item_history.type = 'PURCHASE')), (SELECT name FROM items WHERE id = (SELECT roasted_id FROM roasting_log WHERE roasting_log.time = item_history.time AND item = ANY(unroasted_id))) FROM item_history(:item)");
  168. switch(unitBox.currentIndex)
  169. {
  170. case 0:
  171. query.bind(":c1", 2.2);
  172. query.bind(":c2", 2.2);
  173. break;
  174. case 1:
  175. query.bind(":c1", 1);
  176. query.bind(":c2", 1);
  177. break;
  178. }
  179. query.bind(":item", itemBox.currentData());
  180. query.exec();
  181. output.writeStartElement("table");
  182. output.writeStartElement("tr");
  183. output.writeTextElement("th", "Date");
  184. output.writeTextElement("th", "Type");
  185. output.writeTextElement("th", "Quantity");
  186. output.writeTextElement("th", "Balance");
  187. output.writeTextElement("th", "Record");
  188. output.writeEndElement(); // tr
  189. var prev_balance = "0";
  190. var prev_prec = 0;
  191. var cur_prec = 0;
  192. while(query.next()) {
  193. output.writeStartElement("tr");
  194. output.writeAttribute("class", query.value(1));
  195. output.writeTextElement("td", query.value(0));
  196. output.writeTextElement("td", query.value(1));
  197. if(query.value(1) == "INVENTORY") {
  198. var split = prev_balance.split('.');
  199. if(split.length > 1) {
  200. prev_prec = split[1].length;
  201. } else {
  202. prev_prec = 0;
  203. }
  204. split = query.value(2).split('.');
  205. if(split.length > 1) {
  206. cur_prec = split[1].length;
  207. } else {
  208. cur_prec = 0;
  209. }
  210. var prec = prev_prec > cur_prec ? prev_prec : cur_prec;
  211. output.writeTextElement("td", (Number(query.value(2)) - Number(prev_balance)).toFixed(prec));
  212. } else {
  213. output.writeTextElement("td", query.value(2));
  214. }
  215. output.writeTextElement("td", query.value(3));
  216. prev_balance = query.value(3);
  217. if(query.value(1) == "PURCHASE") {
  218. output.writeStartElement("td");
  219. output.writeStartElement("a");
  220. output.writeAttribute("href", "typica://script/i" + query.value(5));
  221. output.writeCDATA(query.value(6) + " (" + query.value(5) + ")");
  222. output.writeEndElement();
  223. output.writeEndElement();
  224. } else if(query.value(1) == "USE") {
  225. output.writeStartElement("td");
  226. output.writeStartElement("a");
  227. output.writeAttribute("href", "typica://script/p" + query.value(4).slice(1,-1));
  228. output.writeCDATA(query.value(7) + " " + query.value(4));
  229. output.writeEndElement();
  230. output.writeEndElement();
  231. } else {
  232. output.writeTextElement("td", "");
  233. }
  234. output.writeEndElement(); // tr
  235. }
  236. output.writeEndElement(); // table
  237. /* Put the rest of the report here. No sense running queries if
  238. the item doesn't exist. */
  239. } else {
  240. /* Close tags if item data not found. */
  241. output.writeEndElement(); // tr
  242. output.writeEndElement(); // table
  243. }
  244. output.writeEndElement(); // body
  245. output.writeEndElement(); // html
  246. output.writeEndDocument();
  247. view.setContent(buffer);
  248. buffer.close();
  249. query = query.invalidate();
  250. }
  251. if(itemBox.currentData() > 0) {
  252. refresh();
  253. }
  254. /* Open invoices */
  255. var openInvoice = function(url) {
  256. var arg = url.slice(1, url.length);
  257. var info = createWindow("invoiceinfo");
  258. info.setInvoiceID(arg);
  259. var query = new QSqlQuery();
  260. query.exec("SELECT time, invoice, vendor FROM invoices WHERE id = " + arg);
  261. query.next();
  262. var timefield = findChildObject(info, 'date');
  263. timefield.text = query.value(0);
  264. var vendorfield = findChildObject(info, 'vendor');
  265. vendorfield.text = query.value(2);
  266. var invoicefield = findChildObject(info, 'invoice');
  267. invoicefield.text = query.value(1);
  268. var itemtable = findChildObject(info, 'itemtable');
  269. itemtable.setQuery("SELECT record_type, item_id, description, (SELECT reference FROM items WHERE id = item_id) AS reference, (SELECT cost FROM purchase WHERE item = item_id) AS unit_cost, (SELECT quantity FROM purchase WHERE item = item_id) AS quantity, ((SELECT quantity FROM purchase WHERE item = item_id)/(SELECT conversion FROM lb_bag_conversion WHERE item = item_id))::numeric(12,2) AS sacks, cost FROM invoice_items WHERE invoice_id = " + arg + " AND record_type = 'PURCHASE' UNION SELECT record_type, NULL, description, NULL, NULL, NULL, NULL, cost FROM invoice_items WHERE invoice_id = " + arg + " AND record_type = 'FEE' ORDER BY item_id");
  270. query = query.invalidate();
  271. };
  272. /* Open batch data */
  273. var openProfile = function(url) {
  274. var arg = url.slice(1, url.length);
  275. var details = createWindow("batchDetails");
  276. var fakeTable = new Object;
  277. fakeTable.holding = new Array(7);
  278. fakeTable.data = function(r, c) {
  279. return this.holding[c];
  280. };
  281. var query = new QSqlQuery();
  282. query.exec("SELECT time, machine, (SELECT name FROM items WHERE id = roasted_id) AS name, unroasted_total_quantity AS green, roasted_quantity AS roasted, ((unroasted_total_quantity - roasted_quantity) / unroasted_total_quantity * 100::numeric)::numeric(12,2) AS weight_loss, duration, annotation FROM roasting_log WHERE files = '{" + arg + "}'");
  283. query.next();
  284. for(var i = 0; i < 8; i++) {
  285. fakeTable.holding[i] = query.value(i);
  286. }
  287. query = query.invalidate();
  288. details.loadData(fakeTable, 0);
  289. };
  290. view.scriptLinkClicked.connect(function(url) {
  291. var linkType = url[0];
  292. switch(linkType) {
  293. case 'i':
  294. openInvoice(url);
  295. break;
  296. case 'p':
  297. openProfile(url);
  298. break;
  299. }
  300. });
  301. ]]>
  302. </program>
  303. </window>