Commit 91e86db4 authored by Yusei Tahara's avatar Yusei Tahara

erp5_travel_expense: Add a report page as an example.

parent 7214302d
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Travel Expense App Report</title>
<script src="rsvp.js"></script>
<script src="travel_expense_renderjs.js"></script>
<script src="gadget_global.js" ></script>
<script src="handlebars.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/chartist.js/0.9.8/chartist.min.css">
<script src="https://cdn.jsdelivr.net/chartist.js/0.9.8/chartist.min.js"></script>
<script class="view-report-template" type="text/x-handlebars-template">
<div class="ui-grid-b ui-responsive">
<div class="ui-block-a"></div>
<div class="ui-block-b">
<form class="view-report-form">
<div class="ct-chart ct-perfect-fourth"></div>
<input data-inline="true" type="submit" name="save" value="Save" data-theme="b" data-i18n="[value]Save">
</form>
</div>
<div class="ui-block-c"></div>
</div>
</script>
<script src="gadget_travel_expense_page_report.js"></script>
</head>
<body>
</body>
</html>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Web Page" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Access_contents_information_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Add_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Change_local_roles_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Modify_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_View_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>content_md5</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>contributors</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>gadget_travel_expense_page_report.html</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>gadget_travel_expense_page_report.html</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value> <string>en</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Web Page</string> </value>
</item>
<item>
<key> <string>short_title</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Travel Expense Record Report Page</string> </value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>001</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>document_publication_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>edit_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
<item>
<key> <string>processing_status_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAU=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
</pickle>
<pickle>
<tuple>
<none/>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>publish_alive</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <string>zope</string> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="DateTime" module="DateTime.DateTime"/>
</klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1472793721.09</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>published_alive</string> </value>
</item>
</dictionary>
</list>
</tuple>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
</pickle>
<pickle>
<tuple>
<none/>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>edit</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <string>zope</string> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>953.46487.56947.2389</string> </value>
</item>
<item>
<key> <string>state</string> </key>
<value> <string>current</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="DateTime" module="DateTime.DateTime"/>
</klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1473065777.57</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</tuple>
</pickle>
</record>
<record id="5" aka="AAAAAAAAAAU=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
</pickle>
<pickle>
<tuple>
<none/>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>detect_converted_file</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <string>zope</string> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_processing_state</string> </key>
<value> <string>converted</string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>0.0.0.0</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="DateTime" module="DateTime.DateTime"/>
</klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1472791825.39</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</tuple>
</pickle>
</record>
</ZopeData>
/*globals window, rJS, Handlebars, RSVP*/
/*jslint indent: 2, nomen: true, maxlen: 80*/
(function (window, document, RSVP, rJS, Handlebars, promiseEventListener, loopEventListener, $) {
"use strict";
var gadget_klass = rJS(window),
source = gadget_klass.__template_element
.querySelector(".view-report-template")
.innerHTML,
template = Handlebars.compile(source);
gadget_klass
.ready(function (g) {
g.props = {};
g.options = null;
return g.getElement()
.push(function (element) {
g.props.element = element;
g.props.deferred = RSVP.defer();
});
})
.declareAcquiredMethod("updateHeader", "updateHeader")
.declareAcquiredMethod("get", "jio_get")
.declareAcquiredMethod("translateHtml", "translateHtml")
.declareAcquiredMethod('allDocs', 'jio_allDocs')
.declareMethod("render", function (options) {
var gadget = this;
gadget.options = options;
var bar_data = [];
var currency_list = [];
return new RSVP.Queue()
.push(function (result_list) {
return gadget.translateHtml(template({}));
})
.push(function (html) {
gadget.props.element.innerHTML = html;
var currency_dict = {};
return gadget.allDocs({
query: 'portal_type: "Currency" AND validation_state: "validated"',
select_list: ["title", "relative_url"],
limit: [0, 1234567890]
})
.push(function(result){
for (var i = 0; i < result.data.total_rows; i += 1) {
currency_dict[result.data.rows[i].value.relative_url] = result.data.rows[i].value.title;
}
return new RSVP.Queue();
})
.push(function(){
return gadget.allDocs({
query: 'visible_in_html5_app_flag:1 AND portal_type:("Expense Record" OR "Expense Record Temp")',
select_list: ["date", "resource", "quantity"],
limit: [0, 1234567890]
})
})
.push(function(result){
function zeroFill( number, width ){
width -= number.toString().length;
if ( width > 0 ){
return new Array( width + (/\./.test( number ) ? 2 : 1) ).join( '0' ) + number;
}
return number + "";
}
var currency_path, date, quantity;
var temp_dict = {};
for (var i=0; i<result.data.total_rows; i++) {
currency_path = result.data.rows[i].value.resource;
date = result.data.rows[i].value.date;
quantity = parseFloat(result.data.rows[i].value.quantity);
var re_result = date.match(/(\d*)\-(\d*)-(\d*)/);
var year = parseInt(re_result[1], 10);
var month = parseInt(re_result[2], 10);
var year_month = zeroFill(year, 4) + zeroFill(month, 2);
var currency = currency_dict[currency_path];
var key = year_month;
if (currency_list.indexOf(currency) == -1){
currency_list.push(currency);
}
if (temp_dict[key]==undefined){
temp_dict[key] = {};
}
if (temp_dict[key][currency]==undefined){
temp_dict[key][currency] = quantity;
}else{
temp_dict[key][currency] += quantity;
}
}
var label_list = [];
for (var key in temp_dict) {
label_list.push(key);
}
label_list.sort();
for (var currency of currency_list){
var value_list = [];
for(var label of label_list){
value_list.push(temp_dict[label][currency] || 0);
}
bar_data.push(value_list);
}
var data = {
labels: label_list,
series: bar_data,
};
new Chartist.Bar(gadget.props.element.querySelector('.ct-chart'),
data,
{seriesBarDistance: 10,
axisX: {offset: 60},
});
return new RSVP.Queue();
})
})
.push(function(){
return gadget.updateHeader({
title: "Report"
});
})
.push(function () {
gadget.props.deferred.resolve();
})
})
/////////////////////////////////////////
// Form submit
/////////////////////////////////////////
.declareService(function () {
var gadget = this;
return new RSVP.Queue()
.push(function () {
return gadget.props.deferred.promise;
})
.push(function () {
return promiseEventListener(
gadget.props.element.querySelector('form.view-report-form'),
'submit',
false
);
})
.push(function (submit_event) {
gadget.props.element.querySelector("input[type=submit]").disabled = true;
})
.push(function () {
});
})
}(window, document, RSVP, rJS, Handlebars, promiseEventListener, loopEventListener, jQuery));
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Web Script" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Access_contents_information_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Add_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Change_local_roles_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Modify_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_View_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>content_md5</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>contributors</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>gadget_travel_expense_page_report.js</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>gadget_travel_expense_page_report.js</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value> <string>en</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Web Script</string> </value>
</item>
<item>
<key> <string>short_title</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Travel Expense Record Report Page JS</string> </value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>001</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>document_publication_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>edit_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
<item>
<key> <string>processing_status_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAU=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
</pickle>
<pickle>
<tuple>
<none/>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>publish_alive</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <string>zope</string> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="DateTime" module="DateTime.DateTime"/>
</klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1472793726.14</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>published_alive</string> </value>
</item>
</dictionary>
</list>
</tuple>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
</pickle>
<pickle>
<tuple>
<none/>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>edit</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <string>zope</string> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>953.46462.30849.58624</string> </value>
</item>
<item>
<key> <string>state</string> </key>
<value> <string>current</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="DateTime" module="DateTime.DateTime"/>
</klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1473064520.76</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</tuple>
</pickle>
</record>
<record id="5" aka="AAAAAAAAAAU=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
</pickle>
<pickle>
<tuple>
<none/>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>detect_converted_file</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <string>zope</string> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_processing_state</string> </key>
<value> <string>converted</string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>0.0.0.0</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="DateTime" module="DateTime.DateTime"/>
</klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1472791823.85</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</tuple>
</pickle>
</record>
</ZopeData>
......@@ -113,6 +113,8 @@ CACHE:\n
https://netdna.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css\n
https://netdna.bootstrapcdn.com/font-awesome/4.2.0/fonts/fontawesome-webfont.woff?v=4.2.0\n
https://netdna.bootstrapcdn.com/font-awesome/4.2.0/fonts/fontawesome-webfont.ttf?v=4.2.0\n
https://cdn.jsdelivr.net/chartist.js/0.9.8/chartist.min.css\n
https://cdn.jsdelivr.net/chartist.js/0.9.8/chartist.min.js\n
gadget_erp5.css\n
gadget_global.js\n
gadget_jio.html\n
......@@ -144,6 +146,8 @@ gadget_travel_expense_page_setting.html\n
gadget_travel_expense_page_setting.js\n
gadget_travel_expense_page_sync.html\n
gadget_travel_expense_page_sync.js\n
gadget_travel_expense_page_report.html\n
gadget_travel_expense_page_report.js\n
gadget_travel_expense_record_application.html\n
gadget_travel_expense_record_application.js\n
gadget_travel_expense_standalone_jio.html\n
......@@ -289,7 +293,7 @@ NETWORK:\n
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>953.37691.19909.55057</string> </value>
<value> <string>953.41954.28591.13226</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -307,7 +311,7 @@ NETWORK:\n
</tuple>
<state>
<tuple>
<float>1472540424.17</float>
<float>1473065774.89</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -48,6 +48,7 @@
<div class="ui-content">
<ul data-role="listview" class="ui-listview">
<li><a href="#jio_key=expense_record_module&page=view" data-i18n="Expense Record">Expense Record</a></li>
<li><a href="#page=report" data-i18n="Report">Report</a></li>
<li><a href="#page=sync" data-i18n="Synchronisation">Synchronisation</a></li>
<li class="ui-last-child"><a href="#page=setting" data-i18n="Setting">Setting</a></li>
</ul>
......
......@@ -248,7 +248,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>953.39239.61932.30958</string> </value>
<value> <string>953.39337.46159.3891</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -266,7 +266,7 @@
</tuple>
<state>
<tuple>
<float>1472636742.13</float>
<float>1472793381.11</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -30,7 +30,7 @@ else:
response.setHeader("X-Content-Type-Options", "nosniff")
# Only fetch code (html, js, css, image) and data from this ERP5, to prevent any data leak as the web site do not control the gadget's code
response.setHeader("Content-Security-Policy", "default-src 'none'; img-src 'self' blob: data:; media-src 'self'; connect-src * 'self' mail.tiolive.com; script-src 'self' 'unsafe-eval'; font-src netdna.bootstrapcdn.com; style-src 'self' netdna.bootstrapcdn.com 'unsafe-inline' data:; frame-src 'self' data:")
response.setHeader("Content-Security-Policy", "default-src 'none'; img-src 'self' blob: data:; media-src 'self'; connect-src * 'self' mail.tiolive.com; script-src 'self' 'unsafe-eval' cdn.jsdelivr.net cdnjs.cloudflare.com; font-src netdna.bootstrapcdn.com; style-src 'self' cdn.jsdelivr.net netdna.bootstrapcdn.com cdnjs.cloudflare.com 'unsafe-inline' data:; frame-src 'self' data:")
response.setHeader('Content-Type', 'text/html')
......
......@@ -12,6 +12,8 @@ web_page_module/gadget_travel_expense_page_setting.html
web_page_module/gadget_travel_expense_page_setting.js
web_page_module/gadget_travel_expense_page_sync.html
web_page_module/gadget_travel_expense_page_sync.js
web_page_module/gadget_travel_expense_page_report.html
web_page_module/gadget_travel_expense_page_report.js
web_page_module/gadget_travel_expense_record_application.appcache
web_page_module/gadget_travel_expense_record_application.html
web_page_module/gadget_travel_expense_record_application.js
......
......@@ -9,6 +9,8 @@ web_page_module/gadget_travel_expense_jio_expense_record_view.html
web_page_module/gadget_travel_expense_jio_expense_record_view.js
web_page_module/gadget_travel_expense_page_login.html
web_page_module/gadget_travel_expense_page_login.js
web_page_module/gadget_travel_expense_page_report.html
web_page_module/gadget_travel_expense_page_report.js
web_page_module/gadget_travel_expense_page_setting.html
web_page_module/gadget_travel_expense_page_setting.js
web_page_module/gadget_travel_expense_page_sync.html
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment