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.

auco.xml 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. <window id="useandcostreport">
  2. <reporttitle>Production:->Average Use and Cost by Origin</reporttitle>
  3. <layout type="vertical">
  4. <layout type="horizontal">
  5. <daterange id="dates" initial="23" /><!-- Lifetime -->
  6. <label>Sort Order:</label>
  7. <sqldrop id="sort" />
  8. <label>Weight Unit:</label>
  9. <sqldrop id="unit" />
  10. <stretch />
  11. </layout>
  12. <webview id="report" />
  13. </layout>
  14. <menu name="File">
  15. <item id="print" shortcut="Ctrl+P">Print...</item>
  16. </menu>
  17. <menu name="Reports" type="reports" src="Reports" />
  18. <program>
  19. <![CDATA[
  20. this.windowTitle = TTR("useandcostreport", "Typica - Average Use and Cost by Origin");
  21. var report = findChildObject(this, 'report');
  22. var printMenu = findChildObject(this, 'print');
  23. printMenu.triggered.connect(function() {
  24. report.print();
  25. });
  26. var sortBox = findChildObject(this, 'sort');
  27. sortBox.addItem(TTR("useandcostreport","Origin A-Z"));
  28. sortBox.addItem(TTR("useandcostreport", "Origin Z-A"));
  29. sortBox.addItem(TTR("useandcostreport", "Avg. Rate Ascending"));
  30. sortBox.addItem(TTR("useandcostreport", "Avg. Rate Descending"));
  31. sortBox.addItem(TTR("useandcostreport", "Avg. Cost Ascending"));
  32. sortBox.addItem(TTR("useandcostreport", "Avg. Cost Descending"));
  33. sortBox.currentIndex = QSettings.value("auco_sort", 0);
  34. var unitBox = findChildObject(this, 'unit');
  35. unitBox.addItem(TTR("useandcostreport", "Kg"));
  36. unitBox.addItem(TTR("useandcostreport", "Lb"));
  37. unitBox.currentIndex = QSettings.value("script/report_unit", 1);
  38. unitBox['currentIndexChanged(int)'].connect(function() {
  39. QSettings.setValue("script/report_unit", unitBox.currentIndex);
  40. refresh();
  41. });
  42. var dateSelect = findChildObject(this, 'dates');
  43. var dateQuery = new QSqlQuery;
  44. dateQuery.exec("SELECT time::date FROM transactions WHERE time = (SELECT min(time) FROM transactions) OR time = (SELECT max(time) FROM transactions) ORDER BY time ASC");
  45. dateQuery.next();
  46. var lifetimeStartDate = dateQuery.value(0);
  47. var lifetimeEndDate;
  48. if(dateQuery.next()) {
  49. lifetimeEndDate = dateQuery.value(0);
  50. } else {
  51. lifetimeEndDate = lifetimeStartDate;
  52. }
  53. dateSelect.setLifetimeRange(lifetimeStartDate, lifetimeEndDate);
  54. dateQuery = dateQuery.invalidate();
  55. dateSelect.rangeUpdated.connect(refresh);
  56. var rowData = new Array();
  57. var rowIndex;
  58. function refresh() {
  59. rowData.length = 0;
  60. var dateRange = dateSelect.currentRange();
  61. var startDate = dateRange[0];
  62. var endDate = dateRange[dateRange.length - 1];
  63. rowIndex = 0;
  64. var buffer = new QBuffer;
  65. buffer.open(3);
  66. var output = new XmlWriter(buffer);
  67. output.writeStartDocument("1.0");
  68. 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">');
  69. output.writeStartElement("html");
  70. output.writeAttribute("xmlns", "http://www.w3.org/1999/xhtml");
  71. output.writeStartElement("head");
  72. output.writeTextElement("title", TTR("useandcostreport", "Recent Use and Cost by Origin"));
  73. output.writeEndElement();
  74. output.writeStartElement("body");
  75. var cdt = new Date(Date.now());
  76. output.writeTextElement("p", cdt.toLocaleDateString(TTR("reports", "en-US")) + " " + cdt.toLocaleTimeString(TTR("reports", "en-US")));
  77. output.writeTextElement("h1", TTR("useandcostreport", "Average Use and Cost by Origin ") + startDate + " - " + endDate);
  78. switch(unitBox.currentIndex)
  79. {
  80. case 0:
  81. output.writeTextElement("p", TTR("useandcostreport", "This is a report of average rate of use in kilograms per day and cost of unroasted coffee."));
  82. break;
  83. case 1:
  84. output.writeTextElement("p", TTR("useandcostreport", "This is a report of average rate of use in pounds per day and cost of unroasted coffee."));
  85. break;
  86. }
  87. output.writeStartElement("table");
  88. output.writeAttribute("rules", "groups");
  89. output.writeAttribute("cellpadding", "3px");
  90. output.writeStartElement("thead");
  91. output.writeStartElement("tr");
  92. output.writeStartElement("th");
  93. output.writeAttribute("colspan", "9");
  94. output.writeCharacters(TTR("useandcostreport", "Regular Coffees"));
  95. output.writeEndElement();
  96. output.writeEndElement();
  97. output.writeStartElement("tr");
  98. output.writeTextElement("th", TTR("useandcostreport", "Origin"));
  99. output.writeTextElement("th", TTR("useandcostreport", "Avg. Rate"));
  100. output.writeTextElement("th", TTR("useandcostreport", "Avg. Cost"));
  101. output.writeTextElement("th", TTR("useandcostreport", "Last Cost"));
  102. output.writeTextElement("th", TTR("useandcostreport", "Last Purchase Date"));
  103. output.writeTextElement("th", TTR("useandcostreport", "Bag Size (min)"));
  104. output.writeTextElement("th", TTR("useandcostreport", "Bag Size (max)"));
  105. output.writeTextElement("th", TTR("useandcostreport", "Bag Size (mean)"));
  106. output.writeTextElement("th", TTR("useandcostreport", "Purchases"));
  107. output.writeEndElement();
  108. output.writeEndElement();
  109. output.writeStartElement("tbody");
  110. var query = new QSqlQuery();
  111. var conversion = 1;
  112. if(unitBox.currentIndex == 0) {
  113. conversion = 2.2;
  114. }
  115. var orderClause;
  116. switch(sortBox.currentIndex)
  117. {
  118. case 0:
  119. orderClause = "origin ASC";
  120. break;
  121. case 1:
  122. orderClause = "origin DESC";
  123. break;
  124. case 2:
  125. orderClause = "rate ASC";
  126. break;
  127. case 3:
  128. orderClause = "rate DESC";
  129. break;
  130. case 4:
  131. orderClause = "cost ASC";
  132. break;
  133. case 5:
  134. orderClause = "cost DESC";
  135. break;
  136. }
  137. query.prepare("WITH q AS (SELECT id, origin, rate/:c1 AS rate, (SELECT cost*:c2 FROM purchase WHERE item = id) AS cost, (SELECT min(time) FROM purchase WHERE item = id) AS purchase_time, (SELECT conversion/:c3 FROM lb_bag_conversion WHERE item = id) AS bag_weight FROM coffee_history WHERE id IN (SELECT id FROM regular_coffees) AND id IN (SELECT item FROM transactions WHERE time >= :startDate AND time < :endDate::date + interval '1 day')) SELECT DISTINCT origin, avg(rate)::numeric(10,2) AS rate, avg(cost)::numeric(10,2) AS cost, (SELECT (cost*:c4)::numeric(10,2) FROM purchase WHERE item = max(q.id)) AS last_cost, max(purchase_time)::date AS last_purchase, min(bag_weight)::numeric(10,2) AS min_weight, max(bag_weight)::numeric(10,2) AS max_weight, avg(bag_weight)::numeric(10,2) AS mean_weight, count(1) AS n FROM q GROUP BY origin ORDER BY " + orderClause);
  138. query.bind(":c1", conversion);
  139. query.bind(":c2", conversion);
  140. query.bind(":c3", conversion);
  141. query.bind(":c4", conversion);
  142. query.bind(":startDate", startDate);
  143. query.bind(":endDate", endDate);
  144. query.exec();
  145. while(query.next())
  146. {
  147. output.writeStartElement("tr");
  148. output.writeAttribute("id", "r" + rowIndex);
  149. output.writeStartElement("td");
  150. output.writeStartElement("a");
  151. output.writeAttribute("href", "typica://script/r" + rowIndex);
  152. rowIndex++;
  153. rowData.push(query.value(0));
  154. output.writeCharacters(query.value(0));
  155. output.writeEndElement();
  156. output.writeEndElement();
  157. output.writeTextElement("td", query.value(1));
  158. output.writeTextElement("td", query.value(2));
  159. output.writeTextElement("td", query.value(3));
  160. output.writeTextElement("td", query.value(4));
  161. output.writeTextElement("td", query.value(5));
  162. output.writeTextElement("td", query.value(6));
  163. output.writeTextElement("td", query.value(7));
  164. output.writeTextElement("td", query.value(8));
  165. output.writeEndElement();
  166. }
  167. output.writeStartElement("tr");
  168. output.writeStartElement("th");
  169. output.writeAttribute("colspan", "9");
  170. output.writeCharacters(TTR("useandcostreport", "Decaffeinated Coffees"));
  171. output.writeEndElement();
  172. output.writeEndElement();
  173. query.prepare("WITH q AS (SELECT id, origin, rate/:c1 AS rate, (SELECT cost*:c2 FROM purchase WHERE item = id) AS cost, (SELECT min(time) FROM purchase WHERE item = id) AS purchase_time, (SELECT conversion/:c3 FROM lb_bag_conversion WHERE item = id) AS bag_weight FROM coffee_history WHERE id IN (SELECT id FROM decaf_coffees) AND id IN (SELECT item FROM transactions WHERE time >= :startDate AND time < :endDate::date + interval '1 day')) SELECT DISTINCT origin, avg(rate)::numeric(10,2) AS rate, avg(cost)::numeric(10,2) AS cost, (SELECT (cost*:c4)::numeric(10,2) FROM purchase WHERE item = max(q.id)) AS last_cost, max(purchase_time)::date AS last_purchase, min(bag_weight)::numeric(10,2) AS min_weight, max(bag_weight)::numeric(10,2) AS max_weight, avg(bag_weight)::numeric(10,2) AS mean_weight, count(1) AS n FROM q GROUP BY origin ORDER BY " + orderClause);
  174. query.bind(":c1", conversion);
  175. query.bind(":c2", conversion);
  176. query.bind(":c3", conversion);
  177. query.bind(":c4", conversion);
  178. query.bind(":startDate", startDate);
  179. query.bind(":endDate", endDate);
  180. query.exec();
  181. while(query.next())
  182. {
  183. output.writeStartElement("tr");
  184. output.writeAttribute("id", "d" + rowIndex);
  185. output.writeStartElement("td");
  186. output.writeStartElement("a");
  187. output.writeAttribute("href", "typica://script/d" + rowIndex);
  188. rowIndex++;
  189. rowData.push(query.value(0));
  190. output.writeCharacters(query.value(0));
  191. output.writeEndElement();
  192. output.writeEndElement();
  193. output.writeTextElement("td", query.value(1));
  194. output.writeTextElement("td", query.value(2));
  195. output.writeTextElement("td", query.value(3));
  196. output.writeTextElement("td", query.value(4));
  197. output.writeTextElement("td", query.value(5));
  198. output.writeTextElement("td", query.value(6));
  199. output.writeTextElement("td", query.value(7));
  200. output.writeTextElement("td", query.value(8));
  201. output.writeEndElement();
  202. }
  203. query = query.invalidate();
  204. output.writeEndElement();
  205. output.writeEndElement();
  206. output.writeEndElement();
  207. output.writeEndElement();
  208. output.writeEndDocument();
  209. report.setContent(buffer);
  210. buffer.close();
  211. }
  212. refresh();
  213. sortBox['currentIndexChanged(int)'].connect(function() {
  214. QSettings.setValue("auco_sort", sortBox.currentIndex);
  215. refresh();
  216. });
  217. var notifier = Application.subscribe("transactionschange");
  218. notifier.notify.connect(function() {
  219. refresh();
  220. });
  221. report.scriptLinkClicked.connect(function(url) {
  222. if(url[0] == 'i') {
  223. url = url.slice(1, url.length);
  224. var itemReport = createReport("itemtransactions.xml");
  225. var sIB = findChildObject(itemReport, 'item');
  226. sIB.currentIndex = sIB.findData(url);
  227. return;
  228. }
  229. var element = new WebElement(report.findFirstElement("#" + url));
  230. var regular = url[0] == 'r';
  231. var index = url.slice(1, url.length);
  232. var tableref;
  233. if(regular) {
  234. tableref = "regular_coffees";
  235. } else {
  236. tableref = "decaf_coffees";
  237. }
  238. var origin = rowData[Number(url.slice(1, url.length))];
  239. var details = '<tr><td /><td colspan="6"><table><tr><th>' +
  240. TTR("useandcostreport", "Id") + '</th><th>' +
  241. TTR("useandcostreport", "Name") + '</th><th>' +
  242. TTR("useandcostreport", "Rate") + '</th><th>' +
  243. TTR("useandcostreport", "Cost") + '</th><th>' +
  244. TTR("useandcostreport", "Inventory") + '</th><th>' +
  245. TTR("useandcostreport", "First Use") + '</th><th>' +
  246. TTR("useandcostreport", "Last Use") + '</th></tr>';
  247. var query = new QSqlQuery();
  248. query.prepare("SELECT id, name, (rate/:conversion1)::numeric(12,3), (SELECT (cost*:conversion2)::numeric(12,2) FROM purchase WHERE item = id), (stock/:conversion3)::numeric(12,3), (SELECT min(time)::date FROM use WHERE item = id) AS first_use, (SELECT max(time)::date FROM use WHERE item = id) AS last_use FROM coffee_history WHERE origin = :origin AND id IN (SELECT id FROM " + tableref + ") AND id IN (SELECT item FROM transactions WHERE time >= :startDate AND time < :endDate::date + interval '1 day') ORDER BY first_use DESC");
  249. var conversion = 1;
  250. if(unitBox.currentIndex == 0) {
  251. conversion = 2.2;
  252. }
  253. var dateRange = dateSelect.currentRange();
  254. var startDate = dateRange[0];
  255. var endDate = dateRange[dateRange.length - 1];
  256. query.bind(":conversion1", conversion);
  257. query.bind(":conversion2", conversion);
  258. query.bind(":conversion3", conversion);
  259. query.bind(":origin", origin);
  260. query.bind(":startDate", startDate);
  261. query.bind(":endDate", endDate);
  262. query.exec();
  263. while(query.next()) {
  264. details += "<tr>";
  265. details += '<td><a href="typica://script/i' + query.value(0) + '">' + query.value(0) + "</a></td>";
  266. for(var i = 1; i < 7; i++) {
  267. details += "<td>" + query.value(i) + "</td>";
  268. }
  269. details += "</tr>";
  270. }
  271. query = query.invalidate();
  272. details += "</table></td></tr>";
  273. element.appendOutside(details);
  274. });
  275. ]]>
  276. </program>
  277. </window>