Production:->Previous Year Production Comparison
7
');
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();
});
]]>