Browse Source

Merge branch 'development' into programpipe

Neal Wilson 10 years ago
parent
commit
2ec9699bab

+ 1
- 1
README View File

6
 
6
 
7
 Typica is free software released under the MIT license as follows:
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
 Permission is hereby granteed, free of charge, to any person obtaining a copy
11
 Permission is hereby granteed, free of charge, to any person obtaining a copy
12
 of this software and associated documentation files (the "Software"), to deal
12
 of this software and associated documentation files (the "Software"), to deal

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

37
 				QSettings.setValue("script/report_unit", unitBox.currentIndex);
37
 				QSettings.setValue("script/report_unit", unitBox.currentIndex);
38
 				refresh();
38
 				refresh();
39
 			});
39
 			});
40
+			var rowData = new Array();
41
+			var rowIndex;
40
             function refresh() {
42
             function refresh() {
43
+				rowIndex = 0;
41
                 var buffer = new QBuffer;
44
                 var buffer = new QBuffer;
42
                 buffer.open(3);
45
                 buffer.open(3);
43
                 var output = new XmlWriter(buffer);
46
                 var output = new XmlWriter(buffer);
119
                 while(query.next())
122
                 while(query.next())
120
                 {
123
                 {
121
                     output.writeStartElement("tr");
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
                     output.writeTextElement("td", query.value(1));
134
                     output.writeTextElement("td", query.value(1));
124
                     output.writeTextElement("td", query.value(2));
135
                     output.writeTextElement("td", query.value(2));
125
 					output.writeTextElement("td", query.value(3));
136
 					output.writeTextElement("td", query.value(3));
146
                 while(query.next())
157
                 while(query.next())
147
                 {
158
                 {
148
                     output.writeStartElement("tr");
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
                     output.writeTextElement("td", query.value(1));
169
                     output.writeTextElement("td", query.value(1));
151
                     output.writeTextElement("td", query.value(2));
170
                     output.writeTextElement("td", query.value(2));
152
 					output.writeTextElement("td", query.value(3));
171
 					output.writeTextElement("td", query.value(3));
170
                 QSettings.setValue("auco_sort", sortBox.currentIndex);
189
                 QSettings.setValue("auco_sort", sortBox.currentIndex);
171
                 refresh();
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
     </program>
226
     </program>
175
 </window>
227
 </window>

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

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
 				output.writeAttribute("xmlns", "http://www.w3.org/1999/xhtml");
46
 				output.writeAttribute("xmlns", "http://www.w3.org/1999/xhtml");
47
 				output.writeStartElement("head");
47
 				output.writeStartElement("head");
48
 				output.writeTextElement("title", "Item Transactions");
48
 				output.writeTextElement("title", "Item Transactions");
49
+				output.writeStartElement("script");
50
+				output.writeAttribute("src", "Scripts/d3.min.js");
51
+				output.writeEndElement();
49
 				output.writeStartElement("style");
52
 				output.writeStartElement("style");
50
 				output.writeAttribute("type", "text/css");
53
 				output.writeAttribute("type", "text/css");
51
 				output.writeCDATA("tr.PURCHASE {background-color: #77FF77}");
54
 				output.writeCDATA("tr.PURCHASE {background-color: #77FF77}");
126
 					}
129
 					}
127
 					output.writeEndElement() // table
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
 					switch(unitBox.currentIndex)
174
 					switch(unitBox.currentIndex)
131
 					{
175
 					{
132
 						case 0:
176
 						case 0:
146
 					output.writeTextElement("th", "Type");
190
 					output.writeTextElement("th", "Type");
147
 					output.writeTextElement("th", "Quantity");
191
 					output.writeTextElement("th", "Quantity");
148
 					output.writeTextElement("th", "Balance");
192
 					output.writeTextElement("th", "Balance");
193
+					output.writeTextElement("th", "Record");
149
 					output.writeEndElement(); // tr
194
 					output.writeEndElement(); // tr
150
 					var prev_balance = "0";
195
 					var prev_balance = "0";
151
 					var prev_prec = 0;
196
 					var prev_prec = 0;
175
 						}
220
 						}
176
 						output.writeTextElement("td", query.value(3));
221
 						output.writeTextElement("td", query.value(3));
177
 						prev_balance = query.value(3);
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
 						output.writeEndElement(); // tr
240
 						output.writeEndElement(); // tr
179
 					}
241
 					}
180
 					output.writeEndElement(); // table
242
 					output.writeEndElement(); // table
193
 				buffer.close();
255
 				buffer.close();
194
 				query = query.invalidate();
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
 	</program>
312
 	</program>
199
 </window>
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

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

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

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

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

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

+ 1
- 0
config/config.xml View File

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

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

142
 				<a href="http://tango.freedesktop.org">Tango Desktop Project</a>.</p>
142
 				<a href="http://tango.freedesktop.org">Tango Desktop Project</a>.</p>
143
 				<p>Entypo pictograms by Daniel Bruce &mdash;
143
 				<p>Entypo pictograms by Daniel Bruce &mdash;
144
 				<a href="http://www.entypo.com">www.entypo.com</a></p>
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
 			</div>
157
 			</div>
146
 		</div>
158
 		</div>
147
 	</body>
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
 engine->globalObject().setProperty("setFont", engine->newFunction(setFont));
3530
 engine->globalObject().setProperty("setFont", engine->newFunction(setFont));
3531
 engine->globalObject().setProperty("annotationFromRecord",
3531
 engine->globalObject().setProperty("annotationFromRecord",
3532
                                    engine->newFunction(annotationFromRecord));
3532
                                    engine->newFunction(annotationFromRecord));
3533
-engine->globalObject().setProperty("setTabOrder", engine->newFunction(setTabOrder));
3533
+engine->globalObject().setProperty("setTabOrder",
3534
+                                   engine->newFunction(setTabOrder));
3534
 
3535
 
3535
 @ These functions are not part of an object. They expect a string specifying
3536
 @ These functions are not part of an object. They expect a string specifying
3536
 the path to a file and return a string with either the name of the file without
3537
 the path to a file and return a string with either the name of the file without
5288
 void addCalendarToLayout(QDomElement element, QStack<QWidget *> *,@|
5289
 void addCalendarToLayout(QDomElement element, QStack<QWidget *> *,@|
5289
                          QStack<QLayout *> *layoutStack)
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
 	if(element.hasAttribute("id"))
5320
 	if(element.hasAttribute("id"))
5294
 	{
5321
 	{
5295
 		widget->setObjectName(element.attribute("id"));
5322
 		widget->setObjectName(element.attribute("id"));
5296
 	}
5323
 	}
5297
-	widget->setDate(QDate::currentDate());
5298
 	QBoxLayout *layout = qobject_cast<QBoxLayout *>(layoutStack->top());
5324
 	QBoxLayout *layout = qobject_cast<QBoxLayout *>(layoutStack->top());
5299
 	layout->addWidget(widget);
5325
 	layout->addWidget(widget);
5300
 }
5326
 }
5428
 {
5454
 {
5429
 	setQDateEditProperties(value, engine);
5455
 	setQDateEditProperties(value, engine);
5430
 }
5456
 }
5457
+else if(className == "QDateTimeEdit")
5458
+{
5459
+	setQDateTimeEditProperties(value, engine);
5460
+}
5431
 else if(className == "QFrame")
5461
 else if(className == "QFrame")
5432
 {
5462
 {
5433
 	setQFrameProperties(value, engine);
5463
 	setQFrameProperties(value, engine);

+ 4
- 1
src/webview.w View File

20
 #include <QPrintDialog>
20
 #include <QPrintDialog>
21
 #include <QWebFrame>
21
 #include <QWebFrame>
22
 #include <QWebElement>
22
 #include <QWebElement>
23
+#include <QSettings>
23
 
24
 
24
 #ifndef TypicaWebViewHeader
25
 #ifndef TypicaWebViewHeader
25
 #define TypicaWebViewHeader
26
 #define TypicaWebViewHeader
131
 
132
 
132
 void TypicaWebView::setContent(QIODevice *device)
133
 void TypicaWebView::setContent(QIODevice *device)
133
 {
134
 {
135
+	QSettings settings;
134
 	device->reset();
136
 	device->reset();
135
 	QByteArray content = device->readAll();
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
 QString TypicaWebView::saveXml()
142
 QString TypicaWebView::saveXml()

Loading…
Cancel
Save