123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567 |
- <window id="pytdprodcomp">
- <reporttitle>Production:->Previous Year Production Comparison</reporttitle>
- <layout type="vertical">
- <layout type="horizontal">
- <label>Batch Type:</label>
- <sqldrop id="batchtype" />
- <label>Approval:</label>
- <sqldrop id="approval" />
- <daterange id="dates" initial="19" /><!-- Current Year to Date -->
- <label>Days to Average:</label>
- <line validator="integer" id="days">7</line>
- <label>Weight Unit:</label>
- <sqldrop id="unit" />
- <stretch />
- </layout>
- <webview id="report" />
- </layout>
- <menu name="File">
- <item id="print" shortcut="Ctrl+P">Print...</item>
- </menu>
- <program>
- <![CDATA[
- this.windowTitle = TTR("pytdprodcomp", "Typica - Previous Year Production Comparison");
- var dateSelect = findChildObject(this, 'dates');
- dateSelect.removeIndex(23); // Remove Lifetime range
- var view = findChildObject(this, 'report');
- var printMenu = findChildObject(this, 'print');
- printMenu.triggered.connect(function() {
- view.print();
- });
- var avgField = findChildObject(this, 'days');
- var unitBox = findChildObject(this, 'unit');
- unitBox.addItem(TTR("pytdprodcomp", "Kg"));
- unitBox.addItem(TTR("pytdprodcomp", "Lb"));
- unitBox.currentIndex = QSettings.value("script/report_unit", 1);
- unitBox['currentIndexChanged(int)'].connect(function() {
- QSettings.setValue("script/report_unit", unitBox.currentIndex);
- refresh();
- });
- var batchType = findChildObject(this, 'batchtype');
- batchType.addItem(TTR("pytdprodcomp", "Any"));
- batchType.addItem(TTR("pytdprodcomp", "Production Roasts"));
- batchType.addItem(TTR("pytdprodcomp", "Sample Roasts"));
- batchType.currentIndex = QSettings.value("script/batchtypefilter", 1);
- batchType['currentIndexChanged(int)'].connect(function() {
- QSettings.setValue("script/batchtypefilter", batchType.currentIndex);
- refresh();
- });
- var approval = findChildObject(this, 'approval');
- approval.addItem(TTR("pytdprodcomp", "Any"));
- approval.addItem(TTR("pytdprodcomp", "Approved"));
- approval.addItem(TTR("pytdprodcomp", "Not Approved"));
- approval.currentIndex = QSettings.value("script/approvalfilter", 1);
- approval['currentIndexChanged(int)'].connect(function() {
- QSettings.setValue("script/approvalfilter", approval.currentIndex);
- refresh();
- });
- function refresh() {
- var conversion = 1;
- if(unitBox.currentIndex == 0) {
- conversion = 2.2;
- }
- var buffer = new QBuffer;
- buffer.open(3);
- var output = new XmlWriter(buffer);
- output.writeStartDocument("1.0");
- 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">');
- output.writeStartElement("html");
- output.writeAttribute("xmlns", "http://www.w3.org/1999/xhtml");
- output.writeStartElement("head");
- output.writeTextElement("title", TTR("pytdprodcomp", "Previous Year Production Comparison"));
- output.writeEndElement();
- output.writeStartElement("body");
- var cdt = new Date(Date.now());
- output.writeTextElement("p", cdt.toLocaleDateString(TTR("reports", "en-US")) + " " + cdt.toLocaleTimeString(TTR("reports", "en-US")));
- output.writeTextElement("h1", TTR("pytdprodcomp", "Previous Year Production Comparison"));
- output.writeTextElement("p", TTR("pytdprodcomp", "This report provides an itemized and overall comparison of roasted coffee production for the dates specified with those dates in the previous year. A chart of this data along with percent change and rolling average of the percent change is also produced."));
- output.writeStartElement("table");
- output.writeAttribute("style", "page-break-after:auto;");
- output.writeAttribute("rules", "groups");
- output.writeAttribute("cellpadding", "3px");
- output.writeStartElement("thead");
- output.writeStartElement("tr");
- output.writeTextElement("th", "Coffee");
- switch(unitBox.currentIndex) {
- case 0:
- output.writeTextElement("th", TTR("pytdprodcomp", "Previous (Kg)"));
- output.writeTextElement("th", TTR("pytdprodcomp", "Current (Kg)"));
- output.writeTextElement("th", TTR("pytdprodcomp", "Change (Kg)"));
- break;
- case 1:
- output.writeTextElement("th", TTR("pytdprodcomp", "Previous (Lb)"));
- output.writeTextElement("th", TTR("pytdprodcomp", "Current (Lb)"));
- output.writeTextElement("th", TTR("pytdprodcomp", "Change (Lb)"));
- break;
- }
- output.writeEndElement();
- output.writeEndElement();
- output.writeStartElement("tbody");
- var query = new QSqlQuery();
- query.exec("START TRANSACTION");
- var dateRange = dateSelect.currentRange();
- var curStartDate = "'"+dateRange[0]+"'";
- var curEndDate = "'"+dateRange[dateRange.length - 1]+"'";
- query.exec("SELECT "+curStartDate+"::date - interval '1 year', "+curEndDate+"::date - interval '1 year' + interval '1 day', "+curEndDate+"::date + interval '1 day'");
- query.next();
- curEndDate = "'"+query.value(2)+"'";
- var prevStartDate = "'"+query.value(0)+"'";
- var prevEndDate = "'"+query.value(1)+"'";
- var transaction_filter;
- var approval_filter;
- switch(batchType.currentIndex) {
- case 0:
- transaction_filter = "";
- break;
- case 1:
- transaction_filter = " AND transaction_type = 'ROAST'";
- break;
- case 2:
- transaction_filter = " AND transaction_type = 'SAMPLEROAST'";
- break;
- }
- switch(approval.currentIndex) {
- case 0:
- approval_filter = "";
- break;
- case 1:
- approval_filter = " AND approval = true";
- break;
- case 2:
- approval_filter = " AND approval = false";
- break;
- }
- var q = "CREATE TEMPORARY TABLE previous ON COMMIT DROP AS SELECT roasted_id, sum(roasted_quantity) AS p FROM roasting_log WHERE time > "+prevStartDate+" AND time < "+prevEndDate+" AND roasted_id IS NOT NULL" + transaction_filter + approval_filter + " GROUP BY roasted_id";
- query.exec(q);
- q = "CREATE TEMPORARY TABLE current ON COMMIT DROP AS SELECT roasted_id, sum(roasted_quantity) AS c FROM roasting_log WHERE time > "+curStartDate+" AND time < "+curEndDate+" AND roasted_id IS NOT NULL" + transaction_filter + approval_filter + " GROUP BY roasted_id";
- query.exec(q);
- query.exec("INSERT INTO previous SELECT roasted_id, 0 FROM current WHERE roasted_id NOT IN (SELECT roasted_id FROM previous)");
- query.exec("INSERT INTO current SELECT roasted_id, 0 FROM previous WHERE roasted_id NOT IN (SELECT roasted_id FROM current)");
- query.exec("CREATE TEMPORARY TABLE comp ON COMMIT DROP AS SELECT previous.roasted_id, p, c FROM previous LEFT OUTER JOIN current ON previous.roasted_id = current.roasted_id");
- query.exec("SELECT (SELECT name FROM items WHERE id = roasted_id) AS name, p, c, (c-p) FROM comp WHERE p > 0 OR c > 0 ORDER BY name");
- while(query.next())
- {
- output.writeStartElement("tr");
- output.writeTextElement("td", query.value(0));
- output.writeTextElement("td", (query.value(1) / conversion).toFixed(2));
- output.writeTextElement("td", (query.value(2) / conversion).toFixed(2));
- output.writeTextElement("td", (query.value(3) / conversion).toFixed(2));
- output.writeEndElement();
- }
- output.writeEndElement();
- output.writeStartElement("tfoot");
- output.writeTextElement("th", TTR("pytdprodcomp", "Totals"));
- query.exec("SELECT sum(p), sum(c), sum(c-p) FROM comp");
- query.next();
- output.writeTextElement("td", (query.value(0) / conversion).toFixed(2));
- output.writeTextElement("td", (query.value(1) / conversion).toFixed(2));
- output.writeTextElement("td", (query.value(2) / conversion).toFixed(2));
- output.writeEndElement();
- query.exec("ABORT");
- output.writeEndElement();
- output.writeStartElement("p");
- output.writeAttribute("style", "page-break-inside: avoid");
- output.writeStartElement("svg");
- output.writeAttribute("xmlns", "http://www.w3.org/2000/svg");
- output.writeAttribute("width", "7.5in");
- output.writeAttribute("height", "6.3in");
- output.writeStartElement("g");
- output.writeAttribute("transform", "translate(0,470)");
- output.writeStartElement("g");
- output.writeAttribute("transform", "scale(1,-1)");
- output.writeStartElement("line");
- output.writeAttribute("x1", "40");
- output.writeAttribute("x2", "40");
- output.writeAttribute("y1", "0");
- output.writeAttribute("y2", "450");
- output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1;");
- output.writeEndElement();
- output.writeStartElement("line");
- output.writeAttribute("x1", "50");
- output.writeAttribute("x2", "650");
- output.writeAttribute("y1", "-10");
- output.writeAttribute("y2", "-10");
- output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1;");
- output.writeEndElement();
- output.writeStartElement("line");
- output.writeAttribute("x1", "660");
- output.writeAttribute("x2", "660");
- output.writeAttribute("y1", "0");
- output.writeAttribute("y2", "450");
- output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1;");
- output.writeEndElement();
- var q = "SELECT "+curEndDate+"::date - "+curStartDate+"::date";
- query.exec(q);
- query.next();
- var days = query.value(0);
- var dates = new Array();
- var curpounds = new Array();
- var prevpounds = new Array();
- var change = new Array();
- var avgchange = new Array();
- var i;
- for(i = 0; i < days; i++)
- {
- q = "SELECT "+curStartDate+"::date + "+(i+1);
- query.exec(q);
- query.next();
- dates[i] = query.value(0);
- q = "SELECT sum(roasted_quantity) FROM roasting_log WHERE time > "+curStartDate+" AND time < '"+dates[i]+"'" + transaction_filter + approval_filter;
- query.exec(q);
- if(query.next())
- {
- curpounds[i] = Number(query.value(0));
- }
- else
- {
- curpounds[i] = 0;
- }
- q = "SELECT sum(roasted_quantity) FROM roasting_log WHERE time > "+curStartDate+"::date - '1 year'::interval AND time < '"+dates[i]+"'::date - '1 year'::interval" + transaction_filter + approval_filter;
- query.exec(q);
- if(query.next())
- {
- prevpounds[i] = Number(query.value(0));
- }
- else
- {
- prevpounds[i] = 0;
- }
- if(curpounds[i] > 0)
- {
- change[i] = (curpounds[i] - prevpounds[i])/curpounds[i];
- }
- else
- {
- if(prevpounds[i] > 0)
- {
- change[i] = -1;
- }
- else
- {
- change[i] = 0;
- }
- }
- if(i > (parseInt(avgField.text)-2))
- {
- var sum = 0;
- var j;
- for(j = 0; j < parseInt(avgField.text); j++)
- {
- sum += change[i-j];
- }
- avgchange[i] = sum / parseInt(avgField.text);
- }
- }
- // Calculate the domain of the primary y axis.
- var maxy1 = 0;
- var increment = 100; // Starting increment is 100 Lb.
- if(unitBox.currentIndex == 0) {
- increment = 110; // Starting increment is 50 Kg if Kg is requested.
- }
- while(maxy1 < Math.max(curpounds[days - 1], prevpounds[days - 1]))
- {
- maxy1 += increment;
- }
- // Calculate the number of grid lines and loosen spacing if there are too many.
- var divisions = maxy1 / increment;
- while(divisions > 10) {
- increment *= 2;
- divisions = maxy1 / increment;
- }
- // Draw y axis grid lines.
- var pos = 0;
- while(pos <= maxy1)
- {
- output.writeStartElement("line");
- output.writeAttribute("x1", "35");
- output.writeAttribute("x2", "45");
- output.writeAttribute("y1", (450/maxy1)*pos);
- output.writeAttribute("y2", (450/maxy1)*pos);
- output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1;");
- output.writeEndElement();
- pos += increment;
- }
- var n = Math.min.apply(Math, change);
- var m = Math.max.apply(Math, change);
- var miny2 = 0;
- var maxy2;
- if(n < 0)
- {
- while(miny2 > n)
- {
- miny2 -= 0.1;
- }
- maxy2 = miny2;
- }
- else
- {
- while(miny2 < n)
- {
- miny2 += 0.1;
- }
- miny2 -= 0.1;
- maxy2 = miny2;
- }
- while(maxy2 < m)
- {
- maxy2 += 0.1;
- }
- var range = maxy2 - miny2;
- pos = miny2;
- while(pos <= maxy2)
- {
- output.writeStartElement("line");
- output.writeAttribute("x1", "655");
- output.writeAttribute("x2", "665");
- output.writeAttribute("y1", (pos-miny2)*(4.5/(range*100))*10000);
- output.writeAttribute("y2", (pos-miny2)*(4.5/(range*100))*10000);
- output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1;");
- output.writeEndElement();
- pos += 0.1;
- }
- pos = 0;
- while(pos < days)
- {
- output.writeStartElement("line");
- output.writeAttribute("x1", 50+((600/(days-1))*pos));
- output.writeAttribute("x2", 50+((600/(days-1))*pos));
- output.writeAttribute("y1", "-5");
- output.writeAttribute("y2", "-15");
- output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1;");
- output.writeEndElement();
- pos += 7;
- }
- output.writeStartElement("line");
- output.writeAttribute("x1", 50+((600/(days-1))*(days-1)));
- output.writeAttribute("x2", 50+((600/(days-1))*(days-1)));
- output.writeAttribute("y1", "-5");
- output.writeAttribute("y2", "-15");
- output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1;");
- output.writeEndElement();
- pos = 1;
- while(pos < days)
- {
- output.writeStartElement("line");
- output.writeAttribute("x1", 50+((600/(days-1))*(pos - 1)));
- output.writeAttribute("x2", 50+((600/(days-1))*pos));
- output.writeAttribute("y1", (prevpounds[pos-1]/maxy1)*450);
- output.writeAttribute("y2", (prevpounds[pos]/maxy1)*450);
- output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1;");
- output.writeEndElement();
- output.writeStartElement("line");
- output.writeAttribute("x1", 50+((600/(days-1))*(pos - 1)));
- output.writeAttribute("x2", 50+((600/(days-1))*pos));
- output.writeAttribute("y1", (curpounds[pos-1]/maxy1)*450);
- output.writeAttribute("y2", (curpounds[pos]/maxy1)*450);
- output.writeAttribute("style", "stroke:rgb(255,0,0);stroke-width:1;");
- output.writeEndElement();
- output.writeStartElement("line");
- output.writeAttribute("x1", 50+((600/(days-1))*(pos-1)));
- output.writeAttribute("x2", 50+((600/(days-1))*pos));
- output.writeAttribute("y1", (change[pos-1]-miny2)*(4.5/(range*100))*10000);
- output.writeAttribute("y2", (change[pos]-miny2)*(4.5/(range*100))*10000);
- output.writeAttribute("style", "stroke:rgb(0,255,0);stroke-width:1;");
- output.writeEndElement();
- if(pos > (parseInt(avgField.text)-1))
- {
- output.writeStartElement("line");
- output.writeAttribute("x1", 50+((600/(days-1))*(pos-1)));
- output.writeAttribute("x2", 50+((600/(days-1))*pos));
- output.writeAttribute("y1", (avgchange[pos-1]-miny2)*(4.5/(range*100))*10000);
- output.writeAttribute("y2", (avgchange[pos]-miny2)*(4.5/(range*100))*10000);
- output.writeAttribute("style", "stroke:rgb(0,0,255);stroke-width:1;");
- output.writeEndElement();
- }
- pos++;
- }
- output.writeEndElement();
- i = 0;
- while(i <= maxy1)
- {
- output.writeStartElement("text");
- output.writeAttribute("x", "0");
- output.writeAttribute("y", -((450/maxy1)*i)+5);
- output.writeAttribute("font-size", "12");
- switch(unitBox.currentIndex) {
- case 0:
- output.writeCharacters((i / 2.2).toFixed(0));
- break;
- case 1:
- default:
- output.writeCharacters(i);
- break;
- }
- output.writeEndElement();
- i += increment;
- }
- i = miny2;
- var stepSize = 0.1;
- while((maxy2 - miny2) / stepSize > 20)
- {
- stepSize += 0.05;
- }
- while(i <= maxy2)
- {
- output.writeStartElement("text");
- output.writeAttribute("x", "670");
- output.writeAttribute("y", -((i-miny2)*(4.5/(range*100))*10000)+5);
- output.writeAttribute("font-size", "12");
- output.writeCharacters(Number(i*100).toFixed(0)+"%");
- output.writeEndElement();
- i += stepSize;
- }
- i = 0;
- while(i <= days-1)
- {
- output.writeStartElement("text");
- output.writeAttribute("x", 45+((600/(days-1))*i));
- output.writeAttribute("y", "20");
- output.writeAttribute("font-size", "12");
- output.writeAttribute("transform", "rotate(90 "+(45+((600/(days-1))*i))+",20)");
- q = "SELECT ('"+dates[i]+"'::date - '1 day'::interval)::date";
- query.exec(q);
- query.next();
- var ds = query.value(0);
- var parts = ds.split("-");
- switch(parts[1])
- {
- case '01':
- ds = TTR("pytdprodcomp", "January ");
- break;
- case '02':
- ds = TTR("pytdprodcomp", "February ");
- break;
- case '03':
- ds = TTR("pytdprodcomp", "March ");
- break;
- case '04':
- ds = TTR("pytdprodcomp", "April ");
- break;
- case '05':
- ds = TTR("pytdprodcomp", "May ");
- break;
- case '06':
- ds = TTR("pytdprodcomp", "June ");
- break;
- case '07':
- ds = TTR("pytdprodcomp", "July ");
- break;
- case '08':
- ds = TTR("pytdprodcomp", "August ");
- break;
- case '09':
- ds = TTR("pytdprodcomp", "September ");
- break;
- case '10':
- ds = TTR("pytdprodcomp", "October ");
- break;
- case '11':
- ds = TTR("pytdprodcomp", "November ");
- break;
- case '12':
- ds = TTR("pytdprodcomp", "December ");
- break;
- }
- ds = ds + Number(parts[2]);
- output.writeCharacters(ds);
- output.writeEndElement();
- if(i == days-1)
- {
- break;
- }
- i += 7;
- if(i > days-1)
- {
- i = days - 1;
- }
- }
- query = query.invalidate();
- output.writeStartElement("rect");
- output.writeAttribute("fill", "rgb(0,0,0)");
- output.writeAttribute("x", "45");
- output.writeAttribute("y", "110");
- output.writeAttribute("width", "24");
- output.writeAttribute("height", "12");
- output.writeEndElement();
- output.writeStartElement("text");
- output.writeAttribute("x", "75");
- output.writeAttribute("y", "120");
- output.writeAttribute("font-size", "12");
- switch(unitBox.currentIndex) {
- case 0:
- output.writeCharacters(TTR("pytdprodcomp", "Previous Year Kg"));
- break;
- case 1:
- output.writeCharacters(TTR("pytdprodcomp", "Previous Year Lb"));
- break;
- }
- output.writeEndElement();
- output.writeStartElement("rect");
- output.writeAttribute("fill", "rgb(255,0,0)");
- output.writeAttribute("x", "195");
- output.writeAttribute("y", "110");
- output.writeAttribute("width", "24");
- output.writeAttribute("height", "12");
- output.writeEndElement();
- output.writeStartElement("text");
- output.writeAttribute("x", "225");
- output.writeAttribute("y", "120");
- output.writeAttribute("font-size", "12");
- switch(unitBox.currentIndex) {
- case 0:
- output.writeCharacters(TTR("pytdprodcomp", "Current Year Kg"));
- break;
- case 1:
- output.writeCharacters(TTR("pytdprodcomp", "Current Year Lb"));
- break;
- }
- output.writeEndElement();
- output.writeStartElement("rect");
- output.writeAttribute("fill", "rgb(0,255,0)");
- output.writeAttribute("x", "345");
- output.writeAttribute("y", "110");
- output.writeAttribute("width", "24");
- output.writeAttribute("height", "12");
- output.writeEndElement();
- output.writeStartElement("text");
- output.writeAttribute("x", "375");
- output.writeAttribute("y", "120");
- output.writeAttribute("font-size", "12");
- output.writeCharacters(TTR("pytdprodcomp", "% Change"));
- output.writeEndElement();
- output.writeStartElement("rect");
- output.writeAttribute("fill", "rgb(0,0,255)");
- output.writeAttribute("x", "495");
- output.writeAttribute("y", "110");
- output.writeAttribute("width", "24");
- output.writeAttribute("height", "12");
- output.writeEndElement();
- output.writeStartElement("text");
- output.writeAttribute("x", "525");
- output.writeAttribute("y", "120");
- output.writeAttribute("font-size", "12");
- output.writeCharacters(TTR("pytdprodcomp", "Average % Change"));
- output.writeEndElement();
- output.writeEndElement();
- output.writeEndElement();
- output.writeEndElement();
- output.writeEndElement();
- output.writeEndElement();
- output.writeEndDocument();
- view.setContent(buffer);
- buffer.close();
- }
- refresh();
- dateSelect.rangeUpdated.connect(function() {
- refresh();
- });
- avgField.editingFinished.connect(function() {
- refresh();
- });
- var notifier = Application.subscribe("roastinglogchange");
- notifier.notify.connect(function() {
- refresh();
- });
- ]]>
- </program>
- </window>
|