Browse Source

Merge branch 'development' into programpipe

Neal Wilson 10 years ago
parent
commit
2ec9699bab

+ 1
- 1
README View File

@@ -6,7 +6,7 @@ Project web site: http://www.randomfield.com/programs/typica/
6 6
 
7 7
 Typica is free software released under the MIT license as follows:
8 8
 
9
-Copyright 2007-2013 Neal Evan Wilson
9
+Copyright 2007-2014 Neal Evan Wilson
10 10
 
11 11
 Permission is hereby granteed, free of charge, to any person obtaining a copy
12 12
 of this software and associated documentation files (the "Software"), to deal

+ 54
- 2
config/Reports/auco.xml View File

@@ -37,7 +37,10 @@
37 37
 				QSettings.setValue("script/report_unit", unitBox.currentIndex);
38 38
 				refresh();
39 39
 			});
40
+			var rowData = new Array();
41
+			var rowIndex;
40 42
             function refresh() {
43
+				rowIndex = 0;
41 44
                 var buffer = new QBuffer;
42 45
                 buffer.open(3);
43 46
                 var output = new XmlWriter(buffer);
@@ -119,7 +122,15 @@
119 122
                 while(query.next())
120 123
                 {
121 124
                     output.writeStartElement("tr");
122
-                    output.writeTextElement("td", query.value(0));
125
+					output.writeAttribute("id", "r" + rowIndex);
126
+					output.writeStartElement("td");
127
+					output.writeStartElement("a");
128
+					output.writeAttribute("href", "typica://script/r" + rowIndex);
129
+					rowIndex++;
130
+					rowData.push(query.value(0));
131
+					output.writeCharacters(query.value(0));
132
+					output.writeEndElement();
133
+					output.writeEndElement();
123 134
                     output.writeTextElement("td", query.value(1));
124 135
                     output.writeTextElement("td", query.value(2));
125 136
 					output.writeTextElement("td", query.value(3));
@@ -146,7 +157,15 @@
146 157
                 while(query.next())
147 158
                 {
148 159
                     output.writeStartElement("tr");
149
-                    output.writeTextElement("td", query.value(0));
160
+					output.writeAttribute("id", "d" + rowIndex);
161
+					output.writeStartElement("td");
162
+					output.writeStartElement("a");
163
+					output.writeAttribute("href", "typica://script/d" + rowIndex);
164
+					rowIndex++;
165
+					rowData.push(query.value(0));
166
+					output.writeCharacters(query.value(0));
167
+					output.writeEndElement();
168
+					output.writeEndElement();
150 169
                     output.writeTextElement("td", query.value(1));
151 170
                     output.writeTextElement("td", query.value(2));
152 171
 					output.writeTextElement("td", query.value(3));
@@ -170,6 +189,39 @@
170 189
                 QSettings.setValue("auco_sort", sortBox.currentIndex);
171 190
                 refresh();
172 191
             });
192
+			report.scriptLinkClicked.connect(function(url) {
193
+				var element = new WebElement(report.findFirstElement("#" + url));
194
+				var regular = url[0] == 'r';
195
+				var index = url.slice(1, url.length);
196
+				var tableref;
197
+				if(regular) {
198
+					tableref = "regular_coffees";
199
+				} else {
200
+					tableref = "decaf_coffees";
201
+				}
202
+				var origin = rowData[Number(url.slice(1, url.length))];
203
+				var details = '<tr><td /><td colspan="6"><table><tr><th>Id</th><th>Name</th><th>Rate</th><th>Inventory</th><th>First Use</th><th>Last Use</th></tr>';
204
+				var query = new QSqlQuery();
205
+				query.prepare("SELECT id, name, (rate/:conversion1)::numeric(12,3), (stock/:conversion2)::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 + ") ORDER BY first_use DESC");
206
+				var conversion = 1;
207
+				if(unitBox.currentIndex == 0) {
208
+					conversion = 2.2;
209
+				}
210
+				query.bind(":conversion1", conversion);
211
+				query.bind(":conversion2", conversion);
212
+				query.bind(":origin", origin);
213
+				query.exec();
214
+				while(query.next()) {
215
+					details += "<tr>";
216
+					for(var i = 0; i < 6; i++) {
217
+						details += "<td>" + query.value(i) + "</td>";
218
+					}
219
+					details += "</tr>";
220
+				}
221
+				query = query.invalidate();
222
+				details += "</table></td></tr>";
223
+				element.appendOutside(details);
224
+			});
173 225
         ]]>
174 226
     </program>
175 227
 </window>

+ 112
- 0
config/Reports/greensales.xml View File

@@ -0,0 +1,112 @@
1
+<window id="greensales">
2
+	<reporttitle>Sales:->Green Coffee Sales</reporttitle>
3
+	<layout type="vertical">
4
+		<layout type="horizontal">
5
+			<daterange id="dates" initial="9" /><!-- Current Month to Date-->
6
+			<label>Weight Unit:</label>
7
+			<sqldrop id="unit" />
8
+			<stretch />
9
+		</layout>
10
+		<webview id="report" />
11
+	</layout>
12
+	<menu name="File">
13
+		<item id="print" shortcut="Ctrl+P">Print</item>
14
+	</menu>
15
+	<program>
16
+		<![CDATA[
17
+			this.windowTitle = "Typica - Green Coffee Sales";
18
+			var dateSelect = findChildObject(this, 'dates');
19
+			var dateQuery = new QSqlQuery();
20
+			dateQuery.exec("SELECT time::date FROM sale WHERE time = (SELECT min(time) FROM sale) OR time = (SELECT max(time) FROM sale) ORDER BY time ASC");
21
+			dateQuery.next();
22
+			var lifetimeStartDate = dateQuery.value(0);
23
+			var lifetimeEndDate;
24
+			if(dateQuery.next()) {
25
+				lifetimeEndDate = dateQuery.value(0);
26
+			} else {
27
+				lifetimeEndDate = lifetimeStartDate;
28
+			}
29
+			dateSelect.setLifetimeRange(lifetimeStartDate, lifetimeEndDate);
30
+			dateQuery = dateQuery.invalidate();
31
+			var unitBox = findChildObject(this, 'unit');
32
+			unitBox.addItem("Kg");
33
+			unitBox.addItem("Lb");
34
+			unitBox.currentIndex = QSettings.value("script/report_unit", 1);
35
+			unitBox['currentIndexChanged(int)'].connect(function() {
36
+				QSettings.setValue("script/report_unit", unitBox.currentIndex);
37
+				refresh();
38
+			});
39
+			var view = findChildObject(this, 'report');
40
+			var printMenu = findChildObject(this, 'print');
41
+			printMenu.triggered.connect(function() {
42
+				view.print();
43
+			});
44
+			var reportitems = new Array();
45
+			function refresh() {
46
+				var buffer = new QBuffer;
47
+				buffer.open(3);
48
+				var output = new XmlWriter(buffer);
49
+				var output = new XmlWriter(buffer);
50
+				output.writeStartDocument("1.0");
51
+				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">');
52
+				output.writeStartElement("html");
53
+				output.writeAttribute("xmlns", "http://www.w3.org/1999/xhtml");
54
+				output.writeStartElement("head");
55
+				output.writeTextElement("title", "Green Coffee Sales");
56
+				output.writeEndElement();
57
+				output.writeStartElement("body");
58
+				var dateRange = dateSelect.currentRange();
59
+				var startDate = dateRange[0];
60
+				var endDate = dateRange[dateRange.length - 1];
61
+				output.writeTextElement("h1", "Green Coffee Sales: " + startDate + " - " + endDate);
62
+				var conversion = 1;
63
+				var unitText = 'Lb';
64
+				if(unitBox.currentIndex == 0) {
65
+					conversion = 2.2;
66
+					unitText = 'Kg';
67
+				}
68
+				var query = new QSqlQuery();
69
+				query.prepare("SELECT item, (SELECT name FROM coffees WHERE id = item) AS name, (SELECT origin FROM coffees WHERE id = item) AS origin, (SELECT reference FROM coffees WHERE id = item) AS reference, (SUM(quantity)/:conversion)::numeric(12,3) FROM sale WHERE time < :ed ::date + interval '1 day' AND time >= :sd GROUP BY item ORDER BY name ASC");
70
+				query.bind(":conversion", conversion);
71
+				query.bind(":ed", endDate);
72
+				query.bind(":sd", startDate);
73
+				query.exec();
74
+				output.writeStartElement("table");
75
+				output.writeAttribute("rules", "groups");
76
+				output.writeAttribute("cellpadding", "3px");
77
+				output.writeStartElement("thead");
78
+				output.writeStartElement("tr");
79
+				output.writeTextElement("th", "ID"); // 0
80
+				output.writeTextElement("th", "Coffee"); // 1
81
+				output.writeTextElement("th", "Origin"); // 2
82
+				output.writeTextElement("th", "Reference"); // 3
83
+				output.writeTextElement("th", "Quantity"); // 4
84
+				output.writeEndElement();
85
+				output.writeEndElement();
86
+				output.writeStartElement("tbody");
87
+				while(query.next()) {
88
+					output.writeStartElement("tr");
89
+					output.writeAttribute("id", "r"+query.value(0));
90
+					reportitems.push(query.value(0));
91
+					output.writeTextElement("td", query.value(0));
92
+					output.writeTextElement("td", query.value(1));
93
+					output.writeTextElement("td", query.value(2));
94
+					output.writeTextElement("td", query.value(3));
95
+					output.writeTextElement("td", query.value(4));
96
+					output.writeEndElement();
97
+				}
98
+				output.writeEndElement();
99
+				output.writeEndElement();
100
+				output.writeEndElement();
101
+				output.writeEndElement();
102
+				output.writeEndDocument();
103
+				view.setContent(buffer);
104
+				buffer.close();
105
+				query = query.invalidate();
106
+			}
107
+			refresh();
108
+			dateSelect.rangeUpdated.connect(refresh);
109
+		]]>
110
+	</program>
111
+</window>
112
+

+ 116
- 2
config/Reports/itemtransactions.xml View File

@@ -46,6 +46,9 @@
46 46
 				output.writeAttribute("xmlns", "http://www.w3.org/1999/xhtml");
47 47
 				output.writeStartElement("head");
48 48
 				output.writeTextElement("title", "Item Transactions");
49
+				output.writeStartElement("script");
50
+				output.writeAttribute("src", "Scripts/d3.min.js");
51
+				output.writeEndElement();
49 52
 				output.writeStartElement("style");
50 53
 				output.writeAttribute("type", "text/css");
51 54
 				output.writeCDATA("tr.PURCHASE {background-color: #77FF77}");
@@ -126,7 +129,48 @@
126 129
 					}
127 130
 					output.writeEndElement() // table
128 131
 					
129
-					query.prepare("SELECT time::date, type, quantity / :c1, balance / :c2 FROM item_history(:item)");
132
+					output.writeStartElement("div");
133
+					output.writeAttribute("id", "chart");
134
+					output.writeEndElement();
135
+					
136
+					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");
137
+					query.bind(":item1", itemBox.currentData());
138
+					query.bind(":item2", itemBox.currentData());
139
+					query.bind(":item3", itemBox.currentData());
140
+					query.bind(":item4", itemBox.currentData());
141
+					query.bind(":item5", itemBox.currentData());
142
+					query.bind(":item6", itemBox.currentData());
143
+					query.bind(":item7", itemBox.currentData());
144
+					query.bind(":item8", itemBox.currentData());
145
+					query.exec();
146
+					var chartData = "var data = [";
147
+					var roastedCoffeeLines = "";
148
+					var adjustmentLines = "";
149
+					var currentInventoryLine = "";
150
+					var conversion = 1;
151
+					if(unitBox.currentIndex == 0) {
152
+						conversion = 2.2;
153
+					}
154
+					while(query.next()) {
155
+						if(Number(query.value(1)) > 0) {
156
+							roastedCoffeeLines += "['" + query.value(0).replace(/\'/g, "\\x27") + "'," + query.value(2) / conversion + "," + query.value(3) + "," + query.value(4) / conversion + "],";
157
+						} else if (query.value(0) == "Current Inventory") {
158
+							currentInventoryLine = "['Current Inventory'," + query.value(2) / conversion + "," + query.value(3) + "," + query.value(4) / conversion + "]";
159
+						} else {
160
+							if(Number(query.value(3)) > 0) {
161
+								adjustmentLines += "['" + query.value(0) + "'," + query.value(2) / conversion + "," + query.value(3) + "," + query.value(4) / conversion + "],";
162
+							}
163
+						}
164
+					}
165
+					chartData = chartData + roastedCoffeeLines + adjustmentLines + currentInventoryLine + "];";
166
+					
167
+					output.writeTextElement("script", chartData);
168
+					
169
+					output.writeStartElement("script");
170
+					output.writeAttribute("src", "Scripts/greenusechart.js");
171
+					output.writeEndElement();
172
+					
173
+					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)");
130 174
 					switch(unitBox.currentIndex)
131 175
 					{
132 176
 						case 0:
@@ -146,6 +190,7 @@
146 190
 					output.writeTextElement("th", "Type");
147 191
 					output.writeTextElement("th", "Quantity");
148 192
 					output.writeTextElement("th", "Balance");
193
+					output.writeTextElement("th", "Record");
149 194
 					output.writeEndElement(); // tr
150 195
 					var prev_balance = "0";
151 196
 					var prev_prec = 0;
@@ -175,6 +220,23 @@
175 220
 						}
176 221
 						output.writeTextElement("td", query.value(3));
177 222
 						prev_balance = query.value(3);
223
+						if(query.value(1) == "PURCHASE") {
224
+							output.writeStartElement("td");
225
+							output.writeStartElement("a");
226
+							output.writeAttribute("href", "typica://script/i" + query.value(5));
227
+							output.writeCDATA(query.value(6) + " (" + query.value(5) + ")");
228
+							output.writeEndElement();
229
+							output.writeEndElement();
230
+						} else if(query.value(1) == "USE") {
231
+							output.writeStartElement("td");
232
+							output.writeStartElement("a");
233
+							output.writeAttribute("href", "typica://script/p" + query.value(4).slice(1,-1));
234
+							output.writeCDATA(query.value(7) + " " + query.value(4));
235
+							output.writeEndElement();
236
+							output.writeEndElement();
237
+						} else {
238
+							output.writeTextElement("td", "");
239
+						}
178 240
 						output.writeEndElement(); // tr
179 241
 					}
180 242
 					output.writeEndElement(); // table
@@ -193,7 +255,59 @@
193 255
 				buffer.close();
194 256
 				query = query.invalidate();
195 257
 			}
196
-			refresh();
258
+			if(itemBox.currentData() > 0) {
259
+				refresh();
260
+			}
261
+			
262
+			/* Open invoices */
263
+			var openInvoice = function(url) {
264
+				var arg = url.slice(1, url.length);
265
+				var info = createWindow("invoiceinfo");
266
+				info.setInvoiceID(arg);
267
+				var query = new QSqlQuery();
268
+				query.exec("SELECT time, invoice, vendor FROM invoices WHERE id = " + arg);
269
+				query.next();
270
+				var timefield = findChildObject(info, 'date');
271
+				timefield.text = query.value(0);
272
+				var vendorfield = findChildObject(info, 'vendor');
273
+				vendorfield.text = query.value(2);
274
+				var invoicefield = findChildObject(info, 'invoice');
275
+				invoicefield.text = query.value(1);
276
+				var itemtable = findChildObject(info, 'itemtable');
277
+				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");
278
+				query = query.invalidate();
279
+			};
280
+			
281
+			/* Open batch data */
282
+			var openProfile = function(url) {
283
+				var arg = url.slice(1, url.length);
284
+				var details = createWindow("batchDetails");
285
+				var fakeTable = new Object;
286
+				fakeTable.holding = new Array(7);
287
+				fakeTable.data = function(r, c) {
288
+					return this.holding[c];
289
+				};
290
+				var query = new QSqlQuery();
291
+				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 + "}'");
292
+				query.next();
293
+				for(var i = 0; i < 8; i++) {
294
+					fakeTable.holding[i] = query.value(i);
295
+				}
296
+				query = query.invalidate();
297
+				details.loadData(fakeTable, 0);
298
+			};
299
+			
300
+			view.scriptLinkClicked.connect(function(url) {
301
+				var linkType = url[0];
302
+				switch(linkType) {
303
+					case 'i':
304
+						openInvoice(url);
305
+						break;
306
+					case 'p':
307
+						openProfile(url);
308
+						break;
309
+				}
310
+			});
197 311
 		]]>
198 312
 	</program>
199 313
 </window>

+ 5
- 0
config/Scripts/d3.min.js
File diff suppressed because it is too large
View File


+ 116
- 0
config/Scripts/greenusechart.js View File

@@ -0,0 +1,116 @@
1
+// Data access functions
2
+var label = function(d) {return d[0];};
3
+var greenValue = function(d) {return d[1];};
4
+var transactionCount = function(d) {return d[2];};
5
+var roastValue = function(d) {return d[3];};
6
+
7
+// Chart parameters
8
+var valueLabelWidth = 0; // Temporary, will be updated when labels are generated
9
+var barHeight = 30;
10
+var barHeight2 = barHeight / 2;
11
+var barLabelWidth = 0;
12
+var barLabelPadding = 5;
13
+var gridLabelHeight = 18;
14
+var gridChartOffset = 3;
15
+var maxBarWidth = 500;
16
+
17
+// Scales
18
+var x1s = d3.scale.linear().domain([0, d3.max(data, function(d) { return greenValue(d); })*1.15]).range([0, maxBarWidth]);
19
+var x2s = d3.scale.linear().domain([0, d3.max(data, function(d) { return transactionCount(d); })*1.15]).range([0, maxBarWidth]);
20
+var ys = d3.scale.ordinal().domain(d3.range(0, data.length)).rangeBands([0, data.length * barHeight]);
21
+var ytext = function(d, i) {return ys(i) + ys.rangeBand() / 2;};
22
+var ybar = function(d, i) {return ys(i);};
23
+var ybar2 = function(d, i) {return ys(i) + (barHeight2 / 2)};
24
+var ybar3 = function(d, i) {return ys(i);};
25
+var ybar4 = function(d, i) {return ys(i) + barHeight;};
26
+
27
+// Chart
28
+var svg = d3.select("#chart").append("svg")
29
+	.attr("width", 1000)
30
+	.attr("height", gridLabelHeight + gridLabelHeight + gridChartOffset + data.length * barHeight);
31
+
32
+// Bar labels
33
+var yxe = svg.append("g")
34
+	.attr("class", "y axis left");
35
+yxe.selectAll("text").data(data).enter().append("text")
36
+	.attr("y", ytext)
37
+	.attr("stroke", "none")
38
+	.attr("fill", "black")
39
+	.attr("dy", ".35em")
40
+	.attr("text-anchor", "end")
41
+	.text(label);
42
+// Determine maximum label width
43
+yxe.selectAll("text").each(function() {
44
+	if(barLabelWidth < this.getComputedTextLength()) {
45
+		barLabelWidth = this.getComputedTextLength();
46
+	}
47
+});
48
+barLabelWidth += 10;
49
+yxe.attr("transform", "translate(" + (barLabelWidth - barLabelPadding) + "," + (gridLabelHeight + gridChartOffset) + ")");
50
+
51
+// Weight axis
52
+var x1xe = svg.append("g")
53
+	.attr("class", "x axis top")
54
+	.attr("transform", "translate(" + barLabelWidth + "," + gridLabelHeight + ")");
55
+	
56
+x1xe.selectAll("text").data(x1s.ticks(10)).enter().append("text")
57
+	.attr("x", x1s)
58
+	.attr("dy", -3)
59
+	.attr("text-anchor", "middle")
60
+	.text(String);
61
+// Top ticks extend approximately half way down the chart
62
+x1xe.selectAll("line").data(x1s.ticks(10)).enter().append("line")
63
+	.attr("x1", x1s)
64
+	.attr("x2", x1s)
65
+	.attr("y1", 0)
66
+	.attr("y2", ys.rangeExtent()[1] /2)
67
+	.style("stroke", "#ccc");
68
+
69
+// Transaction count axis
70
+var x2xe = svg.append("g")
71
+	.attr("class", "x axis bottom")
72
+	.attr("transform", "translate(" + barLabelWidth + "," + (ys.rangeExtent()[1] + gridChartOffset + gridLabelHeight + gridLabelHeight) + ")");
73
+
74
+x2xe.selectAll("text").data(x2s.ticks(10)).enter().append("text")
75
+	.attr("x", x2s)
76
+	.attr("dy", -3)
77
+	.attr("text-anchor", "middle")
78
+	.text(String);
79
+// Bottom ticks extend approximately half way up the chart	
80
+x2xe.selectAll("line").data(x2s.ticks(10)).enter().append("line")
81
+	.attr("x1", x2s)
82
+	.attr("x2", x2s)
83
+	.attr("y1", -gridLabelHeight - (ys.rangeExtent()[1] /2))
84
+	.attr("y2", -gridLabelHeight)
85
+	.style("stroke", "#ccc");
86
+
87
+// Green coffee bars
88
+var gbars = svg.append("g")
89
+	.attr("transform", "translate(" + barLabelWidth + "," + (gridLabelHeight + gridChartOffset) + ")");
90
+gbars.selectAll("rect").data(data).enter().append("rect")
91
+	.attr("y", ybar)
92
+	.attr("height", barHeight)
93
+	.attr("width", function(d) {return x1s(greenValue(d));})
94
+	.attr("stroke", "white")
95
+	.attr("fill", "royalblue");
96
+
97
+// Roasted coffee bars
98
+var rbars = svg.append("g")
99
+	.attr("transform", "translate(" + barLabelWidth + "," + (gridLabelHeight + gridChartOffset) + ")");
100
+rbars.selectAll("rect").data(data).enter().append("rect")
101
+	.attr("y", ybar2)
102
+	.attr("height", barHeight2)
103
+	.attr("width", function(d) {return x1s(roastValue(d));})
104
+	.attr("stroke", "white")
105
+	.attr("fill", "orangered");
106
+
107
+// Transaction ticks
108
+var tticks = svg.append("g")
109
+	.attr("transform", "translate(" + barLabelWidth + "," + (gridLabelHeight + gridChartOffset) + ")");
110
+tticks.selectAll("line").data(data).enter().append("line")
111
+	.attr("x1", function(d) {return x2s(transactionCount(d));})
112
+	.attr("x2", function(d) {return x2s(transactionCount(d));})
113
+	.attr("y1", ybar3)
114
+	.attr("y2", ybar4)
115
+	.attr("stroke-width", "3")
116
+	.style("stroke", "black");

+ 9
- 9
config/Windows/batchdetailsnew.xml View File

@@ -17,7 +17,7 @@
17 17
 			var compare = findChildObject(this, 'compare');
18 18
 			var edit = findChildObject(this, 'edit');
19 19
 			edit.enabled = false;
20
-			if(typeof(navigationwindow.loggingWindow) == "undefined") {
20
+			if(typeof(Windows.loggingWindow) == "undefined") {
21 21
 				compare.enabled = false;
22 22
 				target.enabled = false;
23 23
 			}
@@ -44,7 +44,7 @@
44 44
                 var nextSeries = startSeries + 2;
45 45
                 QSettings.setValue('cseries', nextSeries);
46 46
                 var input = new XMLInput(buffer, startSeries);
47
-                var graph = findChildObject(navigationwindow.loggingWindow, 'graph');
47
+                var graph = findChildObject(Windows.loggingWindow, 'graph');
48 48
                 input.measure.connect(graph.newMeasurement);
49 49
                 input.input();
50 50
 				query = query.invalidate();
@@ -59,13 +59,13 @@
59 59
 				var pname = query.value(1);
60 60
                 query = query.invalidate();
61 61
 				var input = new XMLInput(buffer, 1);
62
-				var graph = findChildObject(navigationwindow.loggingWindow, 'graph');
63
-				var log = findChildObject(navigationwindow.loggingWindow, 'log');
62
+				var graph = findChildObject(Windows.loggingWindow, 'graph');
63
+				var log = findChildObject(Windows.loggingWindow, 'log');
64 64
 				log.clear();
65 65
 				graph.clear();
66 66
 				input.newTemperatureColumn.connect(log.setHeaderData);
67 67
 				input.newTemperatureColumn.connect(function(col, text) {
68
-					if(text == navigationwindow.loggingWindow.targetcolumnname)
68
+					if(text == Windows.loggingWindow.targetcolumnname)
69 69
 					{
70 70
 						targetseries = col;
71 71
 					}
@@ -83,7 +83,7 @@
83 83
 				input.lastColumn.connect(function(c) {
84 84
 					lc = c;
85 85
 					QSettings.setValue("liveColumn", c + 1);
86
-					navigationwindow.loggingWindow.postLoadColumnSetup(c);
86
+					Windows.loggingWindow.postLoadColumnSetup(c);
87 87
 				});
88 88
 				input.annotation.connect(log.newAnnotation);
89 89
 				input.annotation.connect(function(note, tcol, ncol) {
@@ -91,9 +91,9 @@
91 91
 						log.newAnnotation(note, i, ncol);
92 92
 					}
93 93
 				});
94
-				navigationwindow.loggingWindow.windowTitle = "Typica - " + pname;
95
-				navigationwindow.loggingWindow.raise();
96
-				navigationwindow.loggingWindow.activateWindow();
94
+				Windows.loggingWindow.windowTitle = "Typica - " + pname;
95
+				Windows.loggingWindow.raise();
96
+				Windows.loggingWindow.activateWindow();
97 97
 				input.input();
98 98
 				log.newAnnotation("End", 1, lc);
99 99
 				query = query.invalidate();

+ 1
- 1
config/Windows/greensales.xml View File

@@ -2,7 +2,7 @@
2 2
 	<layout type="vertical">
3 3
 		<layout type="horizontal">
4 4
 			<label>Date:</label>
5
-			<calendar id="date" />
5
+			<calendar time="true" id="date" />
6 6
 			<label>Customer:</label>
7 7
 			<line id="customer" />
8 8
 			<label>Weight Unit:</label>

+ 2
- 0
config/Windows/productionroaster.xml View File

@@ -644,6 +644,7 @@
644 644
             lsplit.saveState("script/logSplitter");
645 645
             log.saveState("script/log", 7);
646 646
 			window.navigationWindow.loggingWindow = undefined;
647
+			Windows.loggingWindow = undefined;
647 648
         });
648 649
 		this.restoreSizeAndPosition('window');
649 650
         vsplit.restoreState("script/mainSplitter");
@@ -985,6 +986,7 @@
985 986
 			var bwindow = createWindow("sampleRoastingBatch");
986 987
 		});
987 988
 		window.postLoadColumnSetup(0);
989
+		Windows.loggingWindow = window;
988 990
 		]]>
989 991
     </program>
990 992
 </window>

+ 1
- 0
config/config.xml View File

@@ -34,6 +34,7 @@
34 34
 	<include src="Windows/editbatchdetails.xml" />
35 35
 	<include src="Windows/newsamplebatch.xml" />
36 36
 	<program>
37
+		Windows = new Object();
37 38
 		var loggingWindow;
38 39
 		var currentBatchInfo;
39 40
 		var navwindow = createWindow("navwindow");

+ 12
- 0
src/resources/html/about.html View File

@@ -142,6 +142,18 @@
142 142
 				<a href="http://tango.freedesktop.org">Tango Desktop Project</a>.</p>
143 143
 				<p>Entypo pictograms by Daniel Bruce &mdash;
144 144
 				<a href="http://www.entypo.com">www.entypo.com</a></p>
145
+				<p>Some charts are produced with the help of d3.js which is provided
146
+				with the following license:</p>
147
+				<p>Copyright &copy; 2010-2014, Michael Bostock</p>
148
+				<p>All rights reserved.</p>
149
+				<p>Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:</p>
150
+				<ul>
151
+					<li>Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
152
+					<li>Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
153
+					<li>The name Michael Bostock may not be used to endorse or promote products derived from this software without specific prior written permission.
154
+				</ul>
155
+				<p>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</p>
156
+
145 157
 			</div>
146 158
 		</div>
147 159
 	</body>

+ 3161
- 2165
src/typica.cpp
File diff suppressed because it is too large
View File


+ 34
- 4
src/typica.w View File

@@ -3530,7 +3530,8 @@ engine->globalObject().setProperty("sqlToArray",
3530 3530
 engine->globalObject().setProperty("setFont", engine->newFunction(setFont));
3531 3531
 engine->globalObject().setProperty("annotationFromRecord",
3532 3532
                                    engine->newFunction(annotationFromRecord));
3533
-engine->globalObject().setProperty("setTabOrder", engine->newFunction(setTabOrder));
3533
+engine->globalObject().setProperty("setTabOrder",
3534
+                                   engine->newFunction(setTabOrder));
3534 3535
 
3535 3536
 @ These functions are not part of an object. They expect a string specifying
3536 3537
 the path to a file and return a string with either the name of the file without
@@ -5288,13 +5289,38 @@ editor. This one provides a calendar.
5288 5289
 void addCalendarToLayout(QDomElement element, QStack<QWidget *> *,@|
5289 5290
                          QStack<QLayout *> *layoutStack)
5290 5291
 {
5291
-	QDateEdit *widget = new QDateEdit;
5292
-	widget->setCalendarPopup(true);
5292
+	QWidget *widget;
5293
+	if(element.hasAttribute("time"))
5294
+	{
5295
+		if(element.attribute("time") == "true")
5296
+		{
5297
+			QDateTimeEdit *edit = new QDateTimeEdit;
5298
+			edit->setDateTime(QDateTime::currentDateTime());
5299
+			edit->setCalendarPopup(true);
5300
+			edit->setDisplayFormat("yyyy-MM-dd hh:mm:ss");
5301
+			widget = qobject_cast<QWidget *>(edit);
5302
+		}
5303
+		else
5304
+		{
5305
+			QDateEdit *edit = new QDateEdit;
5306
+			edit->setDate(QDate::currentDate());
5307
+			edit->setCalendarPopup(true);
5308
+			edit->setDisplayFormat("yyyy-MM-dd");
5309
+			widget = qobject_cast<QWidget *>(edit);
5310
+		}
5311
+	}
5312
+	else
5313
+	{
5314
+		QDateEdit *edit = new QDateEdit;
5315
+		edit->setDate(QDate::currentDate());
5316
+		edit->setCalendarPopup(true);
5317
+		edit->setDisplayFormat("yyyy-MM-dd");
5318
+		widget = qobject_cast<QWidget *>(edit);
5319
+	}
5293 5320
 	if(element.hasAttribute("id"))
5294 5321
 	{
5295 5322
 		widget->setObjectName(element.attribute("id"));
5296 5323
 	}
5297
-	widget->setDate(QDate::currentDate());
5298 5324
 	QBoxLayout *layout = qobject_cast<QBoxLayout *>(layoutStack->top());
5299 5325
 	layout->addWidget(widget);
5300 5326
 }
@@ -5428,6 +5454,10 @@ else if(className == "QDateEdit")
5428 5454
 {
5429 5455
 	setQDateEditProperties(value, engine);
5430 5456
 }
5457
+else if(className == "QDateTimeEdit")
5458
+{
5459
+	setQDateTimeEditProperties(value, engine);
5460
+}
5431 5461
 else if(className == "QFrame")
5432 5462
 {
5433 5463
 	setQFrameProperties(value, engine);

+ 4
- 1
src/webview.w View File

@@ -20,6 +20,7 @@ In order to simplify the implementation of certain features, we subclass
20 20
 #include <QPrintDialog>
21 21
 #include <QWebFrame>
22 22
 #include <QWebElement>
23
+#include <QSettings>
23 24
 
24 25
 #ifndef TypicaWebViewHeader
25 26
 #define TypicaWebViewHeader
@@ -131,9 +132,11 @@ void TypicaWebView::setHtml(const QString &html, const QUrl &baseUrl)
131 132
 
132 133
 void TypicaWebView::setContent(QIODevice *device)
133 134
 {
135
+	QSettings settings;
134 136
 	device->reset();
135 137
 	QByteArray content = device->readAll();
136
-	QWebView::setContent(content, "application/xhtml+xml");
138
+	QUrl baseDir = QUrl("file://" + settings.value("config").toString() + "/");
139
+	QWebView::setContent(content, "application/xhtml+xml", baseDir);
137 140
 }
138 141
 
139 142
 QString TypicaWebView::saveXml()

Loading…
Cancel
Save