Neal Wilson 6 years ago
parent
commit
3b69352c1a
1 changed files with 303 additions and 4 deletions
  1. 303
    4
      config/Windows/navigation.xml

+ 303
- 4
config/Windows/navigation.xml View File

@@ -1,4 +1,6 @@
1 1
 <window id="navwindow">
2
+    <layout type="horizontal">
3
+    <layout type="vertical">
2 4
     <layout type="grid">
3 5
         <row>
4 6
             <column>
@@ -74,6 +76,10 @@
74 76
             </column>
75 77
         </row>
76 78
     </layout>
79
+    <stretch />
80
+    </layout>
81
+    <webview id="dashboard" stretch="1" />
82
+    </layout>
77 83
     <menu name="Reports" type="reports" src="Reports" />
78 84
     <menu name="Database">
79 85
         <item id="resetconnection">Forget Connection Details</item>
@@ -105,10 +111,10 @@
105 111
         schedule.clicked.connect(function() {
106 112
             createWindow("schedule");
107 113
         });
108
-		var manual = findChildObject(this, 'manual');
109
-		manual.clicked.connect(function() {
110
-			createWindow("manualLogEntry");
111
-		});
114
+        var manual = findChildObject(this, 'manual');
115
+        manual.clicked.connect(function() {
116
+            createWindow("manualLogEntry");
117
+        });
112 118
         var profilehistory = findChildObject(this, 'profilehistory');
113 119
         profilehistory.clicked.connect(function() {
114 120
                 createWindow("profilehistory");
@@ -346,6 +352,8 @@
346 352
             query.exec("CREATE TRIGGER notify_transactions_changed AFTER INSERT OR UPDATE OR DELETE ON purchase FOR EACH STATEMENT EXECUTE PROCEDURE notify_transactions_changed()");
347 353
             query.exec("CREATE TRIGGER notify_transactions_changed AFTER INSERT OR UPDATE OR DELETE ON sale FOR EACH STATEMENT EXECUTE PROCEDURE notify_transactions_changed()");
348 354
             query.exec("CREATE TRIGGER notify_transactions_changed AFTER INSERT OR UPDATE OR DELETE ON use FOR EACH STATEMENT EXECUTE PROCEDURE notify_transactions_changed()");
355
+            query.exec("CREATE OR REPLACE FUNCTION notify_reminders_changed() RETURNS trigger AS $$ BEGIN NOTIFY RemindersChange; RETURN NULL; END; $$ LANGUAGE plpgsql");
356
+            query.exec("CREATE TRIGGER notify_reminders_changed AFTER INSERT OR UPDATE OR DELETE ON reminders FOR EACH STATEMENT EXECUTE PROCEDURE notify_reminders_changed()");
349 357
             
350 358
             query.exec("UPDATE TypicaFeatures SET version = 8 WHERE feature = 'base-features'");
351 359
             query = query.invalidate();
@@ -443,6 +451,297 @@
443 451
 			var newUserDialog = new NewTypicaUser();
444 452
 			newUserDialog.exec();
445 453
 		});
454
+        var dashboard = findChildObject(this, 'dashboard');
455
+        var refresh = function() {            
456
+            var buffer = new QBuffer;
457
+            buffer.open(3);
458
+            var output = new XmlWriter(buffer);
459
+            output.writeStartDocument("1.0");
460
+            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">');
461
+            output.writeStartElement("html");
462
+            output.writeAttribute("xmlns", "http://www.w3.org/1999/xhtml");
463
+            output.writeStartElement("head");
464
+            
465
+            output.writeStartElement("link");
466
+            output.writeAttribute("rel", "stylesheet");
467
+            output.writeAttribute("href", QSettings.value("config") + "/Scripts/dashboard.css");
468
+            output.writeEndElement();
469
+            
470
+            output.writeEndElement(); // head
471
+            output.writeStartElement("body");
472
+            
473
+            output.writeStartElement("div");
474
+            output.writeAttribute("class", "container");
475
+            
476
+            var query = new QSqlQuery;
477
+            drawReminders(output, query);
478
+            drawSchedule(output, query);
479
+            drawLatest(output, query);
480
+            drawMostRoasted(output, query);
481
+            drawLeastRoasted(output, query);
482
+            query = query.invalidate();
483
+            
484
+            output.writeEndElement(); // End of container
485
+            
486
+            output.writeEndElement(); // body
487
+            output.writeEndElement(); // html
488
+            output.writeEndDocument();
489
+            
490
+            dashboard.setContent(buffer);
491
+            buffer.close();
492
+        }
493
+        var startCell = function(output, title) {
494
+            output.writeStartElement("div");
495
+            output.writeAttribute("class", "cell");
496
+            output.writeStartElement("div");
497
+            output.writeAttribute("class", "cell-wrapper");
498
+            output.writeStartElement("div");
499
+            output.writeAttribute("class", "cell-title");
500
+            output.writeCharacters(title);
501
+            output.writeEndElement();
502
+        }
503
+        var startStage = function(output) {
504
+            output.writeStartElement("div");
505
+            output.writeAttribute("class", "cell-stage");
506
+        }
507
+        var endStage = function(output) {
508
+            output.writeEndElement();
509
+        }
510
+        var endCell = function(output, summary) {
511
+            if(arguments.length > 1) {
512
+                output.writeStartElement("div");
513
+                output.writeAttribute("class", "cell-notes");
514
+                output.writeCharacters(summary);
515
+                output.writeEndElement();
516
+            }
517
+            output.writeEndElement();
518
+            output.writeEndElement();
519
+        }
520
+        var drawReminders = function(output, query) {
521
+            query.exec("SELECT id, reminder FROM reminders");
522
+            e = new Array();
523
+            while(query.next()) {
524
+                var reminder = JSON.parse(query.value(1));
525
+                reminder.dbid = query.value(0);
526
+                var start_time = "" + reminder.start_year + "-" + reminder.start_month + "-" + reminder.start_day + " " + reminder.start_time;
527
+                if(reminder.condition == "PRODUCTIONWEIGHT") {
528
+                    var convert = 1;
529
+                    var unittext = TTR("navwindow", " Lb");
530
+                    if(reminder.unit == "KG") {
531
+                        convert = 2.2;
532
+                        unittext = TTR("navwindow", " Kg");
533
+                    }
534
+                    var dq = new QSqlQuery;
535
+                    dq.prepare("SELECT sum(roasted_quantity)/:conversion FROM roasting_log WHERE time > :since");
536
+                    dq.bind(":conversion", convert);
537
+                    dq.bind(":since", start_time);
538
+                    dq.exec();
539
+                    dq.next();
540
+                    var proportion;
541
+                    var remain;
542
+                    if(reminder.value == 0 || (reminder.value < Number(dq.value(0)))) {
543
+                        proportion = 1;
544
+                    } else {
545
+                        proportion = Number(dq.value(0)) / reminder.value;
546
+                    }
547
+                    remain = (reminder.value - Number(dq.value(0))).toFixed(0);
548
+                    reminder.completion = proportion;
549
+                    reminder.detail = remain + unittext;
550
+                    dq = dq.invalidate();
551
+                } else if (reminder.condition == "DAYS") {
552
+                    var dq = new QSqlQuery;
553
+                    dq.prepare("SELECT 'now'::date - :since::date");
554
+                    dq.bind(":since", start_time);
555
+                    dq.exec();
556
+                    dq.next();
557
+                    var proportion;
558
+                    var remain;
559
+                    if(reminder.value == 0 || (reminder.value < Number(dq.value(0)))) {
560
+                        proportion = 1;
561
+                    } else {
562
+                        proportion = Number(dq.value(0)) / reminder.value;
563
+                    }
564
+                    remain = reminder.value - Number(dq.value(0));
565
+                    reminder.completion = proportion;
566
+                    reminder.detail = remain + TTR("navwindow", " Days");
567
+                    dq = dq.invalidate();
568
+                } else if (reminder.condition == "PRODUCTIONBATCHES") {
569
+                    var dq = new QSqlQuery;
570
+                    dq.prepare("SELECT count(1) FROM roasting_log WHERE time > :since");
571
+                    dq.bind(":since", start_time);
572
+                    dq.exec();
573
+                    dq.next();
574
+                    var proportion;
575
+                    var remain;
576
+                    if(reminder.value == 0 || (reminder.value < Number(dq.value(0)))) {
577
+                        proportion = 1;
578
+                    } else {
579
+                        proportion = Number(dq.value(0)) / reminder.value;
580
+                    }
581
+                    remain = reminder.value - Number(dq.value(0));
582
+                    reminder.completion = proportion;
583
+                    reminder.detail = remain + TTR("navwindow", " Batches");
584
+                    dq = dq.invalidate();
585
+                } else if (reminder.condition == "PRODUCTIONHOURS") {
586
+                    var dq = new QSqlQuery;
587
+                    dq.prepare("SELECT extract(epoch FROM (SELECT sum(duration) FROM roasting_log WHERE time > :since) / 3600)");
588
+                    dq.bind(":since", start_time);
589
+                    dq.exec();
590
+                    dq.next();
591
+                    var proportion;
592
+                    var remain;
593
+                    if(reminder.value == 0 || (reminder.value < Number(dq.value(0)))) {
594
+                        proportion = 1;
595
+                    } else {
596
+                        proportion = Number(dq.value(0)) / reminder.value;
597
+                    }
598
+                    remain = reminder.value - Number(dq.value(0));
599
+                    reminder.completion = proportion;
600
+                    reminder.detail = remain.toFixed(1) + TTR("navwindow", " Hours");
601
+                    dq = dq.invalidate();
602
+                }
603
+                e[reminder.dbid] = reminder;
604
+            }
605
+            var s = e.filter(function(n) {
606
+            return n.hasOwnProperty("completion")}).sort(function(a, b) {
607
+                return b.completion - a.completion});
608
+            var c = 0;
609
+            var so = 0;
610
+            s.forEach(function(item) {
611
+                if(item.completion >= 1) {
612
+                    c += 1;
613
+                } else if (item.completion >= 0.8) {
614
+                    so += 1;
615
+                }
616
+            });
617
+            if(c > 0 || s > 0) {
618
+                output.writeStartElement("a");
619
+                output.writeAttribute("href", "typica://script/reminders");
620
+                startCell(output, TTR("navwindow", "Reminders"));
621
+                startStage(output);
622
+                var summaryText;
623
+                if(c > 0) {
624
+                    summaryText = "" + c + TTR("navwindow", " reminders due");
625
+                } else {
626
+                    summaryText = "" + s + TTR("navwindow", " reminders due soon");
627
+                }
628
+                output.writeTextElement("p", s[0].title);
629
+                output.writeTextElement("p", Math.floor(s[0].completion * 100) + "%");
630
+                output.writeTextElement("p", s[0].detail);
631
+                endStage(output);
632
+                endCell(output, summaryText);
633
+                output.writeEndElement();
634
+            }
635
+        }
636
+        var kilounit = TTR("navwindow", "Kg");
637
+        var poundunit = TTR("navwindow", "Lb");
638
+        var unitData = function() {
639
+            var retval = new Object;
640
+            if(Number(QSettings.value("script/report_unit")) == 0) {
641
+                retval.conversion = 2.2;
642
+                retval.unittext = "Kg";
643
+            } else {
644
+                retval.conversion = 1;
645
+                retval.unittext = "Lb";
646
+            }
647
+            return retval;
648
+        }
649
+        var drawSchedule = function(output, query) {
650
+            var c = 0;
651
+            var u = unitData();
652
+            query.prepare("SELECT (SELECT name FROM items WHERE id = (data#>>'{roasted}')::numeric), (data#>>'{green_weight}')::numeric/:conversion FROM scheduled_roasts WHERE machine IS NULL");
653
+            query.bind(":conversion", u.conversion);
654
+            query.exec();
655
+            if(query.next()) {
656
+                output.writeStartElement("a");
657
+                output.writeAttribute("href", "typica://script/schedule");
658
+                startCell(output, TTR("navwindow", "Scheduled Roasts"));
659
+                startStage(output);
660
+                do {
661
+                    c += 1;
662
+                    output.writeTextElement("p", query.value(1) + u.unittext + " " + query.value(0));
663
+                } while(query.next());
664
+                endStage(output);
665
+                endCell(output, "" + c + TTR("navwindow", " batches scheduled"));
666
+                output.writeEndElement();
667
+            }
668
+        }
669
+        var drawLatest = function(output, query) {
670
+            var u = unitData();
671
+            query.prepare("SELECT time, roasted_quantity/:conversion, (SELECT name FROM items WHERE id = roasted_id), approval FROM roasting_log ORDER BY time DESC LIMIT 5");
672
+            query.bind(":conversion", u.conversion);
673
+            query.exec();
674
+            if(query.next()) {
675
+                output.writeStartElement("a");
676
+                output.writeAttribute("href", "typica://script/log");
677
+                startCell(output, TTR("navwindow", "Latest Batches"));
678
+                startStage(output);
679
+                do {
680
+                    output.writeStartElement("p");
681
+                    if(query.value(3) == "false") {
682
+                        output.writeAttribute("style", "color: #FF0000;");
683
+                    }
684
+                    output.writeCharacters(query.value(0).replace("T", " ") + " " + query.value(1) + u.unittext + " " + query.value(2));
685
+                    output.writeEndElement();
686
+                } while(query.next());
687
+                endStage(output);
688
+                endCell(output);
689
+                output.writeEndElement();
690
+            }
691
+        }
692
+        var drawMostRoasted = function(output, query) {
693
+            var u = unitData();
694
+            query.prepare("SELECT (sum(roasted_quantity)/:conversion) AS sum, (SELECT name FROM items WHERE id = roasted_id) FROM roasting_log WHERE time > 'now'::date - '28 days'::interval AND approval = true GROUP BY roasted_id ORDER BY sum DESC LIMIT 5");
695
+            query.bind(":conversion", u.conversion);
696
+            query.exec();
697
+            if(query.next()) {
698
+                startCell(output, TTR("navwindow", "Most Roasted Items (Last 28 Days)"));
699
+                startStage(output);
700
+                do {
701
+                    output.writeTextElement("p", query.value(0) + u.unittext + " " + query.value(1));
702
+                } while(query.next());
703
+                endStage(output);
704
+                endCell(output);
705
+            }
706
+        }
707
+        var drawLeastRoasted = function(output, query) {
708
+            var u = unitData();
709
+            query.prepare("SELECT (sum(roasted_quantity)/:conversion) AS sum, (SELECT name FROM items WHERE id = roasted_id) FROM roasting_log WHERE time > 'now'::date - '28 days'::interval AND approval = true GROUP BY roasted_id ORDER BY sum ASC LIMIT 5");
710
+            query.bind(":conversion", u.conversion);
711
+            query.exec();
712
+            if(query.next()) {
713
+                startCell(output, TTR("navwindow", "Least Roasted Items (Last 28 Days)"));
714
+                startStage(output);
715
+                do {
716
+                    output.writeTextElement("p", query.value(0) + u.unittext + " " + query.value(1));
717
+                } while(query.next());
718
+                endStage(output);
719
+                endCell(output);
720
+            }
721
+        }
722
+        refresh();
723
+        dashboard.scriptLinkClicked.connect(function(url) {
724
+            if(url == "reminders") {
725
+                createReport("reminders.xml");
726
+            } else if(url == "log") {
727
+                createReport("historyreport.xml");
728
+            } else if(url == "schedule") {
729
+                createWindow("schedule");
730
+            }
731
+        });
732
+        
733
+        var remindernotification = Application.subscribe("reminderschange");
734
+        remindernotification.notify.connect(function() {
735
+            refresh();
736
+        });
737
+        var schedulenotification = Application.subscribe("scheduledroastschange");
738
+        schedulenotification.notify.connect(function() {
739
+            refresh();
740
+        });
741
+        var lognotification = Application.subscribe("roastinglogchange");
742
+        lognotification.notify.connect(function() {
743
+            refresh();
744
+        });
446 745
         ]]>
447 746
     </program>
448 747
 </window>

Loading…
Cancel
Save