Merge lp:~openerp-dev/openobject-addons/trunk-website_sign into lp:openobject-addons
- trunk-website_sign
- Merge into trunk
Status: | Work in progress |
---|---|
Proposed branch: | lp:~openerp-dev/openobject-addons/trunk-website_sign |
Merge into: | lp:openobject-addons |
Diff against target: |
1449 lines (+1186/-108) 17 files modified
mail/static/src/xml/mail.xml (+26/-24) website/static/lib/jSignature/jSignature.min.js (+77/-0) website/views/website_templates.xml (+1/-1) website_quote/static/lib/jSignature/jSignature.min.js (+0/-77) website_quote/views/website_quotation.xml (+6/-6) website_sign/__init__.py (+25/-0) website_sign/__openerp__.py (+46/-0) website_sign/controllers/__init__.py (+3/-0) website_sign/controllers/main.py (+183/-0) website_sign/data/website_sign_data.xml (+66/-0) website_sign/models/__init__.py (+1/-0) website_sign/models/website_sign.py (+257/-0) website_sign/security/ir.model.access.csv (+3/-0) website_sign/static/src/css/website_sign.css (+83/-0) website_sign/static/src/js/sign.js (+200/-0) website_sign/static/src/xml/sign.xml (+58/-0) website_sign/views/website_sign.xml (+151/-0) |
To merge this branch: | bzr merge lp:~openerp-dev/openobject-addons/trunk-website_sign |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
OpenERP Core Team | Pending | ||
Review via email: mp+213410@code.launchpad.net |
Commit message
Description of the change
Hello,
I have developed website sign module which will add functionality on attachment for digital signature of requested partner. We can request to those partner who are followers of that record only.
Also this module contains track of signers like how many person requested to sign, on which date he has signed and how much sign requests are pending.
Thanks,
Kunal Chavda
- 9244. By Kunal Chavda
-
[MERGE]with latest.
- 9245. By Kunal Chavda
-
[IMP]Improved varible names.
- 9246. By Kunal Chavda
-
[FIX]forgot to change in getting partner ids.
- 9247. By Kunal Chavda
-
[FIX]when there is log an note than request signature icon should not be shown on attachment.
- 9248. By Kunal Chavda
-
[IMP]Improved code for see request signature link on attachment while full mail composer wizard opened.
- 9249. By Kunal Chavda
-
[MERGE]with latest trunk.
- 9250. By Kunal Chavda
-
[FIX]passing integer instead of string ids.
- 9251. By Kunal Chavda
-
[MERGE]with latest trunk.
- 9252. By Kunal Chavda
-
[IMP]Improved code for web assets moved from manifests to ir.ui.view bundles as per trunk changes.
- 9253. By Kunal Chavda
-
[MERGE]with latest trunk.
- 9254. By Kunal Chavda
-
[MERGE]with latest trunk.
- 9255. By Ronak Baxi (OpenERP)
-
[MERGE]with trunk revno. 9457
- 9256. By Ronak Baxi (OpenERP)
-
[MERGE]with revno 9459
- 9257. By Ronak Baxi (OpenERP)
-
[MERGE]with latest revno 9460
- 9258. By Ronak Baxi (OpenERP)
-
[FIX]foreach enumurator error
Unmerged revisions
- 9258. By Ronak Baxi (OpenERP)
-
[FIX]foreach enumurator error
- 9257. By Ronak Baxi (OpenERP)
-
[MERGE]with latest revno 9460
- 9256. By Ronak Baxi (OpenERP)
-
[MERGE]with revno 9459
- 9255. By Ronak Baxi (OpenERP)
-
[MERGE]with trunk revno. 9457
- 9254. By Kunal Chavda
-
[MERGE]with latest trunk.
- 9253. By Kunal Chavda
-
[MERGE]with latest trunk.
- 9252. By Kunal Chavda
-
[IMP]Improved code for web assets moved from manifests to ir.ui.view bundles as per trunk changes.
- 9251. By Kunal Chavda
-
[MERGE]with latest trunk.
- 9250. By Kunal Chavda
-
[FIX]passing integer instead of string ids.
- 9249. By Kunal Chavda
-
[MERGE]with latest trunk.
Preview Diff
1 | === modified file 'mail/static/src/xml/mail.xml' |
2 | --- mail/static/src/xml/mail.xml 2014-05-07 16:51:26 +0000 |
3 | +++ mail/static/src/xml/mail.xml 2014-05-15 14:05:22 +0000 |
4 | @@ -88,30 +88,32 @@ |
5 | --> |
6 | <t t-name="mail.thread.message.attachments"> |
7 | <t t-foreach='widget.attachment_ids' t-as='attachment'> |
8 | - <t t-if="attachment.file_type_icon !== 'webimage'"> |
9 | - <div t-attf-class="oe_attachment #{attachment.upload ? 'oe_uploading' : ''}"> |
10 | - <a t-att-href='attachment.url' target="_blank"> |
11 | - <img t-att-src="'/mail/static/src/img/mimetypes/' + attachment.file_type_icon + '.png'"></img> |
12 | - <div class='oe_name'><t t-raw='attachment.name' /></div> |
13 | - </a> |
14 | - <div class='oe_delete oe_e' title="Delete this attachment" t-att-data-id="attachment.id">[</div> |
15 | - <div class='oe_progress_bar'> |
16 | - uploading |
17 | - </div> |
18 | - </div> |
19 | - </t> |
20 | - <t t-if="attachment.file_type_icon === 'webimage'"> |
21 | - <div t-attf-class="oe_attachment oe_preview #{attachment.upload ? 'oe_uploading' : ''}"> |
22 | - <a t-att-href='attachment.url' target="_blank"> |
23 | - <img t-att-src="widget.attachments_resize_image(attachment.id, [100,80])"></img> |
24 | - <div class='oe_name'><t t-raw='attachment.name' /></div> |
25 | - </a> |
26 | - <div class='oe_delete oe_e' title="Delete this attachment" t-att-data-id="attachment.id">[</div> |
27 | - <div class='oe_progress_bar'> |
28 | - uploading |
29 | - </div> |
30 | - </div> |
31 | - </t> |
32 | + <div id="attachments" style="display:inline-block;"> |
33 | + <t t-if="attachment.file_type_icon !== 'webimage'"> |
34 | + <div t-attf-class="oe_attachment #{attachment.upload ? 'oe_uploading' : ''}"> |
35 | + <a t-att-href='attachment.url' target="_blank"> |
36 | + <img t-att-src="'/mail/static/src/img/mimetypes/' + attachment.file_type_icon + '.png'"></img> |
37 | + <div class='oe_name'><t t-raw='attachment.name' /></div> |
38 | + </a> |
39 | + <div class='oe_delete oe_e' title="Delete this attachment" t-att-data-id="attachment.id">[</div> |
40 | + <div class='oe_progress_bar'> |
41 | + uploading |
42 | + </div> |
43 | + </div> |
44 | + </t> |
45 | + <t t-if="attachment.file_type_icon === 'webimage'"> |
46 | + <div t-attf-class="oe_attachment oe_preview #{attachment.upload ? 'oe_uploading' : ''}"> |
47 | + <a t-att-href='attachment.url' target="_blank"> |
48 | + <img t-att-src="widget.attachments_resize_image(attachment.id, [100,80])"></img> |
49 | + <div class='oe_name'><t t-raw='attachment.name' /></div> |
50 | + </a> |
51 | + <div class='oe_delete oe_e' title="Delete this attachment" t-att-data-id="attachment.id">[</div> |
52 | + <div class='oe_progress_bar'> |
53 | + uploading |
54 | + </div> |
55 | + </div> |
56 | + </t> |
57 | + </div> |
58 | </t> |
59 | </t> |
60 | |
61 | |
62 | === added directory 'website/static/lib/jSignature' |
63 | === added file 'website/static/lib/jSignature/jSignature.min.js' |
64 | --- website/static/lib/jSignature/jSignature.min.js 1970-01-01 00:00:00 +0000 |
65 | +++ website/static/lib/jSignature/jSignature.min.js 2014-05-15 14:05:22 +0000 |
66 | @@ -0,0 +1,77 @@ |
67 | +/* |
68 | + |
69 | +jSignature v2 "2012-11-01T22:48" "commit ID 1c15dfafecc75925c3b7d529356a558b59220edb" |
70 | +Copyright (c) 2012 Willow Systems Corp http://willow-systems.com |
71 | +Copyright (c) 2010 Brinley Ang http://www.unbolt.net |
72 | +MIT License <http://www.opensource.org/licenses/mit-license.php> |
73 | + |
74 | + |
75 | +Simplify.js BSD |
76 | +(c) 2012, Vladimir Agafonkin |
77 | +mourner.github.com/simplify-js |
78 | + |
79 | + |
80 | +base64 encoder |
81 | +MIT, GPL |
82 | +http://phpjs.org/functions/base64_encode |
83 | ++ original by: Tyler Akins (http://rumkin.com) |
84 | ++ improved by: Bayron Guevara |
85 | ++ improved by: Thunder.m |
86 | ++ improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) |
87 | ++ bugfixed by: Pellentesque Malesuada |
88 | ++ improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) |
89 | ++ improved by: Rafal Kukawski (http://kukawski.pl) |
90 | + |
91 | + |
92 | +jSignature v2 jSignature's Undo Button and undo functionality plugin |
93 | + |
94 | + |
95 | +jSignature v2 jSignature's custom "base30" format export and import plugins. |
96 | + |
97 | + |
98 | +jSignature v2 SVG export plugin. |
99 | + |
100 | +*/ |
101 | +(function(){function q(b){for(var j,s=b.css("color"),g,b=b[0],c=!1;b&&!g&&!c;){try{j=$(b).css("background-color")}catch(d){j="transparent"}"transparent"!==j&&"rgba(0, 0, 0, 0)"!==j&&(g=j);c=b.body;b=b.parentNode}var b=/rgb[a]*\((\d+),\s*(\d+),\s*(\d+)/,c=/#([AaBbCcDdEeFf\d]{2})([AaBbCcDdEeFf\d]{2})([AaBbCcDdEeFf\d]{2})/,a;j=void 0;(j=s.match(b))?a={r:parseInt(j[1],10),g:parseInt(j[2],10),b:parseInt(j[3],10)}:(j=s.match(c))&&(a={r:parseInt(j[1],16),g:parseInt(j[2],16),b:parseInt(j[3],16)});var f;g? |
102 | +(j=void 0,(j=g.match(b))?f={r:parseInt(j[1],10),g:parseInt(j[2],10),b:parseInt(j[3],10)}:(j=g.match(c))&&(f={r:parseInt(j[1],16),g:parseInt(j[2],16),b:parseInt(j[3],16)})):f=a?127<Math.max.apply(null,[a.r,a.g,a.b])?{r:0,g:0,b:0}:{r:255,g:255,b:255}:{r:255,g:255,b:255};j=function(b){return"rgb("+[b.r,b.g,b.b].join(", ")+")"};a&&f?(b=Math.max.apply(null,[a.r,a.g,a.b]),a=Math.max.apply(null,[f.r,f.g,f.b]),a=Math.round(a+-0.75*(a-b)),a={r:a,g:a,b:a}):a?(a=Math.max.apply(null,[a.r,a.g,a.b]),b=1,127<a&& |
103 | +(b=-1),a=Math.round(a+96*b),a={r:a,g:a,b:a}):a={r:191,g:191,b:191};return{color:s,"background-color":f?j(f):g,"decor-color":j(a)}}function m(b,j){this.x=b;this.y=j;this.reverse=function(){return new this.constructor(-1*this.x,-1*this.y)};this._length=null;this.getLength=function(){this._length||(this._length=Math.sqrt(Math.pow(this.x,2)+Math.pow(this.y,2)));return this._length};var s=function(b){return Math.round(b/Math.abs(b))};this.resizeTo=function(b){if(0===this.x&&0===this.y)this._length=0;else if(0=== |
104 | +this.x)this._length=b,this.y=b*s(this.y);else if(0===this.y)this._length=b,this.x=b*s(this.x);else{var j=Math.abs(this.y/this.x),a=Math.sqrt(Math.pow(b,2)/(1+Math.pow(j,2))),j=j*a;this._length=b;this.x=a*s(this.x);this.y=j*s(this.y)}return this};this.angleTo=function(b){var j=this.getLength()*b.getLength();return 0===j?0:Math.acos(Math.min(Math.max((this.x*b.x+this.y*b.y)/j,-1),1))/Math.PI}}function k(b,j){this.x=b;this.y=j;this.getVectorToCoordinates=function(b,j){return new m(b-this.x,j-this.y)}; |
105 | +this.getVectorFromCoordinates=function(b,j){return this.getVectorToCoordinates(b,j).reverse()};this.getVectorToPoint=function(b){return new m(b.x-this.x,b.y-this.y)};this.getVectorFromPoint=function(b){return this.getVectorToPoint(b).reverse()}}function t(b,j,a,g,c){this.data=b;this.context=j;if(b.length)for(var d=b.length,f,l,i=0;i<d;i++){f=b[i];l=f.x.length;a.call(j,f);for(var e=1;e<l;e++)g.call(j,f,e);c.call(j,f)}this.changed=function(){};this.startStrokeFn=a;this.addToStrokeFn=g;this.endStrokeFn= |
106 | +c;this.inStroke=!1;this._stroke=this._lastPoint=null;this.startStroke=function(b){if(b&&"number"==typeof b.x&&"number"==typeof b.y){this._stroke={x:[b.x],y:[b.y]};this.data.push(this._stroke);this._lastPoint=b;this.inStroke=!0;var j=this._stroke,a=this.startStrokeFn,g=this.context;setTimeout(function(){a.call(g,j)},3);return b}return null};this.addToStroke=function(b){if(this.inStroke&&"number"===typeof b.x&&"number"===typeof b.y&&4<Math.abs(b.x-this._lastPoint.x)+Math.abs(b.y-this._lastPoint.y)){var j= |
107 | +this._stroke.x.length;this._stroke.x.push(b.x);this._stroke.y.push(b.y);this._lastPoint=b;var a=this._stroke,g=this.addToStrokeFn,s=this.context;setTimeout(function(){g.call(s,a,j)},3);return b}return null};this.endStroke=function(){var b=this.inStroke;this.inStroke=!1;this._lastPoint=null;if(b){var j=this._stroke,a=this.endStrokeFn,g=this.context,s=this.changed;setTimeout(function(){a.call(g,j);s.call(g)},3);return!0}return null}}function r(b,j,a){var g=this.$parent=$(b),b=this.eventTokens={};this.events= |
108 | +new v(this);var c=$.fn[e]("globalEvents"),d={width:"ratio",height:"ratio",sizeRatio:4,color:"#000","background-color":"#fff","decor-color":"#eee",lineWidth:0,minFatFingerCompensation:-10,showUndoButton:!1,data:[]};$.extend(d,q(g));j&&$.extend(d,j);this.settings=d;for(var f in a)a.hasOwnProperty(f)&&a[f].call(this,f);this.events.publish(e+".initializing");this.$controlbarUpper=$('<div style="padding:0 !important;margin:0 !important;width: 100% !important; height: 0 !important;margin-top:-1em !important;margin-bottom:1em !important;"></div>').appendTo(g); |
109 | +this.isCanvasEmulator=!1;a=this.canvas=this.initializeCanvas(d);j=$(a);this.$controlbarLower=$('<div style="padding:0 !important;margin:0 !important;width: 100% !important; height: 0 !important;margin-top:-1.5em !important;margin-bottom:1.5em !important;"></div>').appendTo(g);this.canvasContext=a.getContext("2d");j.data(e+".this",this);g=(g=d.lineWidth)?g:Math.max(Math.round(a.width/400),2);d.lineWidth=g;this.lineCurveThreshold=3*d.lineWidth;d.cssclass&&""!=$.trim(d.cssclass)&&j.addClass(d.cssclass); |
110 | +this.fatFingerCompensation=0;var g=function(b){var j,a,g=function(g){g=g.changedTouches&&0<g.changedTouches.length?g.changedTouches[0]:g;return new k(Math.round(g.pageX+j),Math.round(g.pageY+a)+b.fatFingerCompensation)},d=new y(750,function(){b.dataEngine.endStroke()});this.drawEndHandler=function(j){try{j.preventDefault()}catch(a){}d.clear();b.dataEngine.endStroke()};this.drawStartHandler=function(c){c.preventDefault();var s=$(b.canvas).offset();j=-1*s.left;a=-1*s.top;b.dataEngine.startStroke(g(c)); |
111 | +d.kick()};this.drawMoveHandler=function(j){j.preventDefault();b.dataEngine.inStroke&&(b.dataEngine.addToStroke(g(j)),d.kick())};return this}.call({},this),l=g.drawEndHandler,i=g.drawStartHandler,p=g.drawMoveHandler,h=this.canvas,j=$(h);this.isCanvasEmulator?(j.bind("mousemove."+e,p),j.bind("mouseup."+e,l),j.bind("mousedown."+e,i)):(h.ontouchstart=function(b){h.onmousedown=void 0;h.onmouseup=void 0;h.onmousemove=void 0;this.fatFingerCompensation=d.minFatFingerCompensation&&-3*d.lineWidth>d.minFatFingerCompensation? |
112 | +-3*d.lineWidth:d.minFatFingerCompensation;i(b);h.ontouchend=l;h.ontouchstart=i;h.ontouchmove=p},h.onmousedown=function(b){h.ontouchstart=void 0;h.ontouchend=void 0;h.ontouchmove=void 0;i(b);h.onmousedown=i;h.onmouseup=l;h.onmousemove=p});b[e+".windowmouseup"]=c.subscribe(e+".windowmouseup",g.drawEndHandler);this.events.publish(e+".attachingEventHandlers");var n=this,b=d.width.toString(10),w=e;if("ratio"===b||"%"===b.split("")[b.length-1])this.eventTokens[w+".parentresized"]=c.subscribe(w+".parentresized", |
113 | +function(b,j,a){return function(){var g=j.width();if(g!==a){for(var d in b)b.hasOwnProperty(d)&&(c.unsubscribe(b[d]),delete b[d]);var s=n.settings;n.$parent.children().remove();for(d in n)n.hasOwnProperty(d)&&delete n[d];d=s.data;var g=1*g/a,f=[],l,i,e,h,k,p;i=0;for(e=d.length;i<e;i++){p=d[i];l={x:[],y:[]};h=0;for(k=p.x.length;h<k;h++)l.x.push(p.x[h]*g),l.y.push(p.y[h]*g);f.push(l)}s.data=f;j[w](s)}}}(this.eventTokens,this.$parent,this.$parent.width(),1*this.canvas.width/this.canvas.height));this.resetCanvas(d.data); |
114 | +this.events.publish(e+".initialized");return this}var e="jSignature",y=function(b,j){var a;this.kick=function(){clearTimeout(a);a=setTimeout(j,b)};this.clear=function(){clearTimeout(a)};return this},v=function(b){this.topics={};this.context=b?b:this;this.publish=function(b,a,g,d){if(this.topics[b]){var c=this.topics[b],f=Array.prototype.slice.call(arguments,1),l=[],i,e,h,p;e=0;for(h=c.length;e<h;e++)p=c[e],i=p[0],p[1]&&(p[0]=function(){},l.push(e)),i.apply(this.context,f);e=0;for(h=l.length;e<h;e++)c.splice(l[e], |
115 | +1)}};this.subscribe=function(b,a,g){this.topics[b]?this.topics[b].push([a,g]):this.topics[b]=[[a,g]];return{topic:b,callback:a}};this.unsubscribe=function(b){if(this.topics[b.topic])for(var a=this.topics[b.topic],g=0,d=a.length;g<d;g++)a[g][0]===b.callback&&a.splice(g,1)}},z=function(b){var a=this.canvasContext,d=b.x[0],b=b.y[0],g=this.settings.lineWidth,c=a.fillStyle;a.fillStyle=a.strokeStyle;a.fillRect(d+g/-2,b+g/-2,g,g);a.fillStyle=c},u=function(b,a){var d=new k(b.x[a-1],b.y[a-1]),g=new k(b.x[a], |
116 | +b.y[a]),c=d.getVectorToPoint(g);if(1<a){var f=new k(b.x[a-2],b.y[a-2]),l=f.getVectorToPoint(d),i;if(l.getLength()>this.lineCurveThreshold){i=2<a?(new k(b.x[a-3],b.y[a-3])).getVectorToPoint(f):new m(0,0);var e=0.35*l.getLength(),h=l.angleTo(i.reverse()),p=c.angleTo(l.reverse());i=(new m(i.x+l.x,i.y+l.y)).resizeTo(Math.max(0.05,h)*e);var n=(new m(l.x+c.x,l.y+c.y)).reverse().resizeTo(Math.max(0.05,p)*e),l=this.canvasContext,e=f.x,p=f.y,h=d.x,w=d.y,A=f.x+i.x,f=f.y+i.y;i=d.x+n.x;n=d.y+n.y;l.beginPath(); |
117 | +l.moveTo(e,p);l.bezierCurveTo(A,f,i,n,h,w);l.stroke()}}c.getLength()<=this.lineCurveThreshold&&(c=this.canvasContext,f=d.x,d=d.y,i=g.x,g=g.y,c.beginPath(),c.moveTo(f,d),c.lineTo(i,g),c.stroke())},x=function(b){var a=b.x.length-1;if(0<a){var d=new k(b.x[a],b.y[a]),g=new k(b.x[a-1],b.y[a-1]),c=g.getVectorToPoint(d);if(c.getLength()>this.lineCurveThreshold){if(1<a){var b=(new k(b.x[a-2],b.y[a-2])).getVectorToPoint(g),f=(new m(b.x+c.x,b.y+c.y)).resizeTo(c.getLength()/2),c=this.canvasContext,b=g.x,a=g.y, |
118 | +l=d.x,i=d.y,e=g.x+f.x,g=g.y+f.y,f=d.x,d=d.y;c.beginPath();c.moveTo(b,a);c.bezierCurveTo(e,g,f,d,l,i)}else c=this.canvasContext,b=g.x,g=g.y,a=d.x,d=d.y,c.beginPath(),c.moveTo(b,g),c.lineTo(a,d);c.stroke()}}};r.prototype.resetCanvas=function(b){var a=this.canvas,d=this.settings,c=this.canvasContext,f=this.isCanvasEmulator,l=a.width,i=a.height;c.clearRect(0,0,l+30,i+30);c.shadowColor=c.fillStyle=d["background-color"];f&&c.fillRect(0,0,l+30,i+30);c.lineWidth=Math.ceil(parseInt(d.lineWidth,10));c.lineCap= |
119 | +c.lineJoin="round";c.strokeStyle=d["decor-color"];c.shadowOffsetX=0;c.shadowOffsetY=0;var h=Math.round(i/5),p=1.5*h,k=i-h,l=l-1.5*h,i=i-h;c.beginPath();c.moveTo(p,k);c.lineTo(l,i);c.stroke();c.strokeStyle=d.color;f||(c.shadowColor=c.strokeStyle,c.shadowOffsetX=0.5*c.lineWidth,c.shadowOffsetY=-0.6*c.lineWidth,c.shadowBlur=0);b||(b=[]);c=this.dataEngine=new t(b,this,z,u,x);d.data=b;$(a).data(e+".data",b).data(e+".settings",d);var n=this.$parent,w=this.events,A=e;c.changed=function(){w.publish(A+".change"); |
120 | +n.trigger("change")};c.changed();return!0};r.prototype.initializeCanvas=function(b){var a=document.createElement("canvas"),c=$(a);b.width===b.height&&"ratio"===b.height&&(b.width="100%");c.css("margin",0).css("padding",0).css("border","none").css("height","ratio"===b.height||!b.height?1:b.height.toString(10)).css("width","ratio"===b.width||!b.width?1:b.width.toString(10));c.appendTo(this.$parent);"ratio"===b.height?c.css("height",Math.round(c.width()/b.sizeRatio)):"ratio"===b.width&&c.css("width", |
121 | +Math.round(c.height()*b.sizeRatio));c.addClass(e);a.width=c.width();a.height=c.height();b=a;if(b.getContext)b=!1;else{var c=b.ownerDocument.parentWindow,d=c.FlashCanvas?b.ownerDocument.parentWindow.FlashCanvas:"undefined"===typeof FlashCanvas?void 0:FlashCanvas;if(d){b=d.initElement(b);d=1;c&&(c.screen&&c.screen.deviceXDPI&&c.screen.logicalXDPI)&&(d=1*c.screen.deviceXDPI/c.screen.logicalXDPI);if(1!==d)try{$(b).children("object").get(0).resize(Math.ceil(b.width*d),Math.ceil(b.height*d)),b.getContext("2d").scale(d, |
122 | +d)}catch(f){}b=!0}else throw Error("Canvas element does not support 2d context. jSignature cannot proceed.");}this.isCanvasEmulator=b;a.onselectstart=function(b){b&&b.preventDefault&&b.preventDefault();b&&b.stopPropagation&&b.stopPropagation();return!1};return a};var p=window,h=function(b,a){var c=new Image,d=this;c.onload=function(){d.getContext("2d").drawImage(c,0,0,c.width<d.width?c.width:d.width,c.height<d.height?c.height:d.height)};c.src="data:"+a+","+b},a=function(b){this.find("canvas."+e).add(this.filter("canvas."+ |
123 | +e)).data(e+".this").resetCanvas(b);return this},f=function(b,a){if(void 0===a&&("string"===typeof b&&"data:"===b.substr(0,5))&&(a=b.slice(5).split(",")[0],b=b.slice(6+a.length),a===b))return;var c=this.find("canvas."+e).add(this.filter("canvas."+e));if(n.hasOwnProperty(a))0!==c.length&&n[a].call(c[0],b,a,function(b){return function(){return b.resetCanvas.apply(b,arguments)}}(c.data(e+".this")));else throw Error(e+" is unable to find import plugin with for format '"+String(a)+"'");return this},d=new v, |
124 | +c=e,l,i=function(){d.publish(c+".parentresized")};$(p).bind("resize."+c,function(){l&&clearTimeout(l);l=setTimeout(i,500)}).bind("mouseup."+c,function(){d.publish(c+".windowmouseup")});var w={},A={"default":function(){return this.toDataURL()},"native":function(b){return b},image:function(){var b=this.toDataURL();if("string"===typeof b&&4<b.length&&"data:"===b.slice(0,5)&&-1!==b.indexOf(",")){var a=b.indexOf(",");return[b.slice(5,a),b.substr(a+1)]}return[]}},n={"native":function(b,a,c){c(b)},image:h, |
125 | +"image/png;base64":h,"image/jpeg;base64":h,"image/jpg;base64":h},B={"export":A,"import":n,instance:w},C={init:function(b){return this.each(function(){var a,c=!1;for(a=this.parentNode;a&&!c;)c=a.body,a=a.parentNode;!c||new r(this,b,w)})},getSettings:function(){return this.find("canvas."+e).add(this.filter("canvas."+e)).data(e+".this").settings},clear:a,reset:a,addPlugin:function(b,a,c){B.hasOwnProperty(b)&&(B[b][a]=c);return this},listPlugins:function(b){var a=[];if(B.hasOwnProperty(b)){var b=B[b], |
126 | +c;for(c in b)b.hasOwnProperty(c)&&a.push(c)}return a},getData:function(b){var a=this.find("canvas."+e).add(this.filter("canvas."+e));void 0===b&&(b="default");if(0!==a.length&&A.hasOwnProperty(b))return A[b].call(a.get(0),a.data(e+".data"))},importData:f,setData:f,globalEvents:function(){return d},events:function(){return this.find("canvas."+e).add(this.filter("canvas."+e)).data(e+".this").events}};$.fn[e]=function(b){if(!b||"object"===typeof b)return C.init.apply(this,arguments);if("string"===typeof b&& |
127 | +C[b])return C[b].apply(this,Array.prototype.slice.call(arguments,1));$.error("Method "+String(b)+" does not exist on jQuery."+e)}})(); |
128 | +(function(){$.fn.jSignature("addPlugin","instance","UndoButton",function(q){this.events.subscribe("jSignature.attachingEventHandlers",function(){if(this.settings[q]){var m=this.settings[q];"function"!==typeof m&&(m=function(){var e=$('<input type="button" value="Undo last stroke" style="position:absolute;display:none;margin:0 !important;top:auto" />').appendTo(this.$controlbarLower),k=e.width();e.css("left",Math.round((this.canvas.width-k)/2));k!==e.width()&&e.width(k);return e});var k=m.call(this), |
129 | +t=this;t.events.subscribe("jSignature.change",function(){t.dataEngine.data.length?k.show():k.hide()});var r=this,e=(this.events.topics.hasOwnProperty("jSignature.undo")?q:"jSignature")+".undo";k.bind("click",function(){r.events.publish(e)});r.events.subscribe(e,function(){var e=r.dataEngine.data;e.length&&(e.pop(),r.resetCanvas(e))})}})})})(); |
130 | +(function(){for(var q={},m={},k="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX".split(""),t=k.length/2,r=t-1;-1<r;r--)q[k[r]]=k[r+t],m[k[r+t]]=k[r];var e=function(e){for(var e=e.split(""),h=e.length,a=1;a<h;a++)e[a]=q[e[a]];return e.join("")},y=function(k){for(var h=[],a=0,f=1,d=k.length,c,l,i=0;i<d;i++)c=Math.round(k[i]),l=c-a,a=c,0>l&&0<f?(f=-1,h.push("Z")):0<l&&0>f&&(f=1,h.push("Y")),c=Math.abs(l),c>=t?h.push(e(c.toString(t))):h.push(c.toString(t));return h.join("")},v=function(e){for(var h= |
131 | +[],e=e.split(""),a=e.length,f,d=1,c=[],l=0,i=0;i<a;i++)f=e[i],f in q||"Z"===f||"Y"===f?(0!==c.length&&(c=parseInt(c.join(""),t)*d+l,h.push(c),l=c),"Z"===f?(d=-1,c=[]):"Y"===f?(d=1,c=[]):c=[f]):c.push(m[f]);h.push(parseInt(c.join(""),t)*d+l);return h},z=function(e){for(var h=[],a=e.length,f,d=0;d<a;d++)f=e[d],h.push(y(f.x)),h.push(y(f.y));return h.join("_")},u=function(e){for(var h=[],e=e.split("_"),a=e.length/2,f=0;f<a;f++)h.push({x:v(e[2*f]),y:v(e[2*f+1])});return h},k=function(e){return["image/jsignature;base30", |
132 | +z(e)]},r=function(e,h,a){"string"===typeof e&&("image/jsignature;base30"===e.substring(0,23).toLowerCase()&&(e=e.substring(24)),a(u(e)))};if(null==this.jQuery)throw Error("We need jQuery for some of the functionality. jQuery is not detected. Failing to initialize...");var x=this.jQuery.fn.jSignature;x("addPlugin","export","base30",k);x("addPlugin","export","image/jsignature;base30",k);x("addPlugin","import","base30",r);x("addPlugin","import","image/jsignature;base30",r);this.jSignatureDebug&&(this.jSignatureDebug.base30= |
133 | +{remapTailChars:e,compressstrokeleg:y,uncompressstrokeleg:v,compressstrokes:z,uncompressstrokes:u,charmap:q})}).call("undefined"!==typeof window?window:this); |
134 | +(function(){function q(a,f){this.x=a;this.y=f;this.reverse=function(){return new this.constructor(-1*this.x,-1*this.y)};this._length=null;this.getLength=function(){this._length||(this._length=Math.sqrt(Math.pow(this.x,2)+Math.pow(this.y,2)));return this._length};var d=function(a){return Math.round(a/Math.abs(a))};this.resizeTo=function(a){if(0===this.x&&0===this.y)this._length=0;else if(0===this.x)this._length=a,this.y=a*d(this.y);else if(0===this.y)this._length=a,this.x=a*d(this.x);else{var f=Math.abs(this.y/ |
135 | +this.x),e=Math.sqrt(Math.pow(a,2)/(1+Math.pow(f,2))),f=f*e;this._length=a;this.x=e*d(this.x);this.y=f*d(this.y)}return this};this.angleTo=function(a){var d=this.getLength()*a.getLength();return 0===d?0:Math.acos(Math.min(Math.max((this.x*a.x+this.y*a.y)/d,-1),1))/Math.PI}}function m(a,f){this.x=a;this.y=f;this.getVectorToCoordinates=function(a,c){return new q(a-this.x,c-this.y)};this.getVectorFromCoordinates=function(a,c){return this.getVectorToCoordinates(a,c).reverse()};this.getVectorToPoint=function(a){return new q(a.x- |
136 | +this.x,a.y-this.y)};this.getVectorFromPoint=function(a){return this.getVectorToPoint(a).reverse()}}function k(a,f){var d=Math.pow(10,f);return Math.round(a*d)/d}function t(a,f,d){var f=f+1,c=new m(a.x[f-1],a.y[f-1]),e=new m(a.x[f],a.y[f]),e=c.getVectorToPoint(e),i=new m(a.x[f-2],a.y[f-2]),c=i.getVectorToPoint(c);return c.getLength()>d?(d=2<f?(new m(a.x[f-3],a.y[f-3])).getVectorToPoint(i):new q(0,0),a=0.35*c.getLength(),i=c.angleTo(d.reverse()),f=e.angleTo(c.reverse()),d=(new q(d.x+c.x,d.y+c.y)).resizeTo(Math.max(0.05, |
137 | +i)*a),e=(new q(c.x+e.x,c.y+e.y)).reverse().resizeTo(Math.max(0.05,f)*a),e=new q(c.x+e.x,c.y+e.y),["c",k(d.x,2),k(d.y,2),k(e.x,2),k(e.y,2),k(c.x,2),k(c.y,2)]):["l",k(c.x,2),k(c.y,2)]}function r(a,f){var d=a.x.length-1,c=new m(a.x[d],a.y[d]),e=new m(a.x[d-1],a.y[d-1]),c=e.getVectorToPoint(c);if(1<d&&c.getLength()>f){var d=(new m(a.x[d-2],a.y[d-2])).getVectorToPoint(e),e=c.angleTo(d.reverse()),i=0.35*c.getLength(),d=(new q(d.x+c.x,d.y+c.y)).resizeTo(Math.max(0.05,e)*i);return["c",k(d.x,2),k(d.y,2),k(c.x, |
138 | +2),k(c.y,2),k(c.x,2),k(c.y,2)]}return["l",k(c.x,2),k(c.y,2)]}function e(a,e,d){for(var e=["M",k(a.x[0]-e,2),k(a.y[0]-d,2)],d=1,c=a.x.length-1;d<c;d++)e.push.apply(e,t(a,d,1));0<c?e.push.apply(e,r(a,d,1)):0===c&&e.push.apply(e,["l",1,1]);return e.join(" ")}function y(a){var f=['<?xml version="1.0" encoding="UTF-8" standalone="no"?>','<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'],d,c=a.length,l,i=[],h=[],k=l=d=0,n=0,p=[];if(0!==c){for(d=0;d<c;d++){k= |
139 | +a[d];n=[];l={x:[],y:[]};for(var m=void 0,b=void 0,m=0,b=k.x.length;m<b;m++)n.push({x:k.x[m],y:k.y[m]});n=simplify(n,0.7,!0);m=0;for(b=n.length;m<b;m++)l.x.push(n[m].x),l.y.push(n[m].y);p.push(l);i=i.concat(l.x);h=h.concat(l.y)}a=Math.min.apply(null,i)-1;c=Math.max.apply(null,i)+1;i=Math.min.apply(null,h)-1;h=Math.max.apply(null,h)+1;k=0>a?0:a;n=0>i?0:i;d=c-a;l=h-i}f.push('<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="'+d.toString()+'" height="'+l.toString()+'">');d=0;for(c=p.length;d< |
140 | +c;d++)l=p[d],f.push('<path fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="'+e(l,k,n)+'"/>');f.push("</svg>");return f.join("")}function v(a){return[p,y(a)]}function z(a){return[h,x(y(a))]}var u=window;"use strict";("undefined"!=typeof exports?exports:u).simplify=function(a,e,d){e=void 0!==e?e*e:1;if(!d){for(var c=a.length,l,i=a[0],h=[i],d=1;d<c;d++){l=a[d];var k=l.x-i.x,n=l.y-i.y;k*k+n*n>e&&(h.push(l),i=l)}a=(i!==l&&h.push(l),h)}l=a;var d=l.length, |
141 | +c=new ("undefined"!=typeof Uint8Array?Uint8Array:Array)(d),i=0,h=d-1,m,p,b=[],j=[],s=[];for(c[i]=c[h]=1;h;){n=0;for(k=i+1;k<h;k++){m=l[k];var g=l[i],r=l[h],q=g.x,t=g.y,g=r.x-q,u=r.y-t,v=void 0;if(0!==g||0!==u)v=((m.x-q)*g+(m.y-t)*u)/(g*g+u*u),1<v?(q=r.x,t=r.y):0<v&&(q+=g*v,t+=u*v);m=(g=m.x-q,u=m.y-t,g*g+u*u);m>n&&(p=k,n=m)}n>e&&(c[p]=1,b.push(i),j.push(p),b.push(p),j.push(h));i=b.pop();h=j.pop()}for(k=0;k<d;k++)c[k]&&s.push(l[k]);return a=s,a};if("function"!==typeof x)var x=function(a){var e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".split(""), |
142 | +d,c,h,i,k=0,m=0,n="",n=[];do d=a.charCodeAt(k++),c=a.charCodeAt(k++),h=a.charCodeAt(k++),i=d<<16|c<<8|h,d=i>>18&63,c=i>>12&63,h=i>>6&63,i&=63,n[m++]=e[d]+e[c]+e[h]+e[i];while(k<a.length);n=n.join("");a=a.length%3;return(a?n.slice(0,a-3):n)+"===".slice(a||3)};var p="image/svg+xml",h="image/svg+xml;base64";if("undefined"===typeof $)throw Error("We need jQuery for some of the functionality. jQuery is not detected. Failing to initialize...");u=$.fn.jSignature;u("addPlugin","export","svg",v);u("addPlugin", |
143 | +"export",p,v);u("addPlugin","export","svgbase64",z);u("addPlugin","export",h,z)})(); |
144 | \ No newline at end of file |
145 | |
146 | === modified file 'website/views/website_templates.xml' |
147 | --- website/views/website_templates.xml 2014-05-13 08:18:31 +0000 |
148 | +++ website/views/website_templates.xml 2014-05-15 14:05:22 +0000 |
149 | @@ -178,7 +178,7 @@ |
150 | </p> |
151 | </div> |
152 | <ul class="list-inline js_language_selector mt16" t-if="(request.website_multilang and len(languages) > 1) or editable"> |
153 | - <li t-foreach="languages" t-as="lg"> |
154 | + <li t-foreach="website.get_languages()" t-as="lg"> |
155 | <a t-att-href="url_for(request.httprequest.path + '?' + keep_query(), lang=lg[0])" |
156 | t-att-data-default-lang="editable and 'true' if lg[0] == website.default_lang_code else None"> |
157 | <t t-esc="lg[1].split('/').pop()"/> |
158 | |
159 | === removed directory 'website_quote/static/lib' |
160 | === removed directory 'website_quote/static/lib/jSignature' |
161 | === removed file 'website_quote/static/lib/jSignature/jSignature.min.js' |
162 | --- website_quote/static/lib/jSignature/jSignature.min.js 2014-01-18 10:46:34 +0000 |
163 | +++ website_quote/static/lib/jSignature/jSignature.min.js 1970-01-01 00:00:00 +0000 |
164 | @@ -1,77 +0,0 @@ |
165 | -/* |
166 | - |
167 | -jSignature v2 "2012-11-01T22:48" "commit ID 1c15dfafecc75925c3b7d529356a558b59220edb" |
168 | -Copyright (c) 2012 Willow Systems Corp http://willow-systems.com |
169 | -Copyright (c) 2010 Brinley Ang http://www.unbolt.net |
170 | -MIT License <http://www.opensource.org/licenses/mit-license.php> |
171 | - |
172 | - |
173 | -Simplify.js BSD |
174 | -(c) 2012, Vladimir Agafonkin |
175 | -mourner.github.com/simplify-js |
176 | - |
177 | - |
178 | -base64 encoder |
179 | -MIT, GPL |
180 | -http://phpjs.org/functions/base64_encode |
181 | -+ original by: Tyler Akins (http://rumkin.com) |
182 | -+ improved by: Bayron Guevara |
183 | -+ improved by: Thunder.m |
184 | -+ improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) |
185 | -+ bugfixed by: Pellentesque Malesuada |
186 | -+ improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) |
187 | -+ improved by: Rafal Kukawski (http://kukawski.pl) |
188 | - |
189 | - |
190 | -jSignature v2 jSignature's Undo Button and undo functionality plugin |
191 | - |
192 | - |
193 | -jSignature v2 jSignature's custom "base30" format export and import plugins. |
194 | - |
195 | - |
196 | -jSignature v2 SVG export plugin. |
197 | - |
198 | -*/ |
199 | -(function(){function q(b){for(var j,s=b.css("color"),g,b=b[0],c=!1;b&&!g&&!c;){try{j=$(b).css("background-color")}catch(d){j="transparent"}"transparent"!==j&&"rgba(0, 0, 0, 0)"!==j&&(g=j);c=b.body;b=b.parentNode}var b=/rgb[a]*\((\d+),\s*(\d+),\s*(\d+)/,c=/#([AaBbCcDdEeFf\d]{2})([AaBbCcDdEeFf\d]{2})([AaBbCcDdEeFf\d]{2})/,a;j=void 0;(j=s.match(b))?a={r:parseInt(j[1],10),g:parseInt(j[2],10),b:parseInt(j[3],10)}:(j=s.match(c))&&(a={r:parseInt(j[1],16),g:parseInt(j[2],16),b:parseInt(j[3],16)});var f;g? |
200 | -(j=void 0,(j=g.match(b))?f={r:parseInt(j[1],10),g:parseInt(j[2],10),b:parseInt(j[3],10)}:(j=g.match(c))&&(f={r:parseInt(j[1],16),g:parseInt(j[2],16),b:parseInt(j[3],16)})):f=a?127<Math.max.apply(null,[a.r,a.g,a.b])?{r:0,g:0,b:0}:{r:255,g:255,b:255}:{r:255,g:255,b:255};j=function(b){return"rgb("+[b.r,b.g,b.b].join(", ")+")"};a&&f?(b=Math.max.apply(null,[a.r,a.g,a.b]),a=Math.max.apply(null,[f.r,f.g,f.b]),a=Math.round(a+-0.75*(a-b)),a={r:a,g:a,b:a}):a?(a=Math.max.apply(null,[a.r,a.g,a.b]),b=1,127<a&& |
201 | -(b=-1),a=Math.round(a+96*b),a={r:a,g:a,b:a}):a={r:191,g:191,b:191};return{color:s,"background-color":f?j(f):g,"decor-color":j(a)}}function m(b,j){this.x=b;this.y=j;this.reverse=function(){return new this.constructor(-1*this.x,-1*this.y)};this._length=null;this.getLength=function(){this._length||(this._length=Math.sqrt(Math.pow(this.x,2)+Math.pow(this.y,2)));return this._length};var s=function(b){return Math.round(b/Math.abs(b))};this.resizeTo=function(b){if(0===this.x&&0===this.y)this._length=0;else if(0=== |
202 | -this.x)this._length=b,this.y=b*s(this.y);else if(0===this.y)this._length=b,this.x=b*s(this.x);else{var j=Math.abs(this.y/this.x),a=Math.sqrt(Math.pow(b,2)/(1+Math.pow(j,2))),j=j*a;this._length=b;this.x=a*s(this.x);this.y=j*s(this.y)}return this};this.angleTo=function(b){var j=this.getLength()*b.getLength();return 0===j?0:Math.acos(Math.min(Math.max((this.x*b.x+this.y*b.y)/j,-1),1))/Math.PI}}function k(b,j){this.x=b;this.y=j;this.getVectorToCoordinates=function(b,j){return new m(b-this.x,j-this.y)}; |
203 | -this.getVectorFromCoordinates=function(b,j){return this.getVectorToCoordinates(b,j).reverse()};this.getVectorToPoint=function(b){return new m(b.x-this.x,b.y-this.y)};this.getVectorFromPoint=function(b){return this.getVectorToPoint(b).reverse()}}function t(b,j,a,g,c){this.data=b;this.context=j;if(b.length)for(var d=b.length,f,l,i=0;i<d;i++){f=b[i];l=f.x.length;a.call(j,f);for(var e=1;e<l;e++)g.call(j,f,e);c.call(j,f)}this.changed=function(){};this.startStrokeFn=a;this.addToStrokeFn=g;this.endStrokeFn= |
204 | -c;this.inStroke=!1;this._stroke=this._lastPoint=null;this.startStroke=function(b){if(b&&"number"==typeof b.x&&"number"==typeof b.y){this._stroke={x:[b.x],y:[b.y]};this.data.push(this._stroke);this._lastPoint=b;this.inStroke=!0;var j=this._stroke,a=this.startStrokeFn,g=this.context;setTimeout(function(){a.call(g,j)},3);return b}return null};this.addToStroke=function(b){if(this.inStroke&&"number"===typeof b.x&&"number"===typeof b.y&&4<Math.abs(b.x-this._lastPoint.x)+Math.abs(b.y-this._lastPoint.y)){var j= |
205 | -this._stroke.x.length;this._stroke.x.push(b.x);this._stroke.y.push(b.y);this._lastPoint=b;var a=this._stroke,g=this.addToStrokeFn,s=this.context;setTimeout(function(){g.call(s,a,j)},3);return b}return null};this.endStroke=function(){var b=this.inStroke;this.inStroke=!1;this._lastPoint=null;if(b){var j=this._stroke,a=this.endStrokeFn,g=this.context,s=this.changed;setTimeout(function(){a.call(g,j);s.call(g)},3);return!0}return null}}function r(b,j,a){var g=this.$parent=$(b),b=this.eventTokens={};this.events= |
206 | -new v(this);var c=$.fn[e]("globalEvents"),d={width:"ratio",height:"ratio",sizeRatio:4,color:"#000","background-color":"#fff","decor-color":"#eee",lineWidth:0,minFatFingerCompensation:-10,showUndoButton:!1,data:[]};$.extend(d,q(g));j&&$.extend(d,j);this.settings=d;for(var f in a)a.hasOwnProperty(f)&&a[f].call(this,f);this.events.publish(e+".initializing");this.$controlbarUpper=$('<div style="padding:0 !important;margin:0 !important;width: 100% !important; height: 0 !important;margin-top:-1em !important;margin-bottom:1em !important;"></div>').appendTo(g); |
207 | -this.isCanvasEmulator=!1;a=this.canvas=this.initializeCanvas(d);j=$(a);this.$controlbarLower=$('<div style="padding:0 !important;margin:0 !important;width: 100% !important; height: 0 !important;margin-top:-1.5em !important;margin-bottom:1.5em !important;"></div>').appendTo(g);this.canvasContext=a.getContext("2d");j.data(e+".this",this);g=(g=d.lineWidth)?g:Math.max(Math.round(a.width/400),2);d.lineWidth=g;this.lineCurveThreshold=3*d.lineWidth;d.cssclass&&""!=$.trim(d.cssclass)&&j.addClass(d.cssclass); |
208 | -this.fatFingerCompensation=0;var g=function(b){var j,a,g=function(g){g=g.changedTouches&&0<g.changedTouches.length?g.changedTouches[0]:g;return new k(Math.round(g.pageX+j),Math.round(g.pageY+a)+b.fatFingerCompensation)},d=new y(750,function(){b.dataEngine.endStroke()});this.drawEndHandler=function(j){try{j.preventDefault()}catch(a){}d.clear();b.dataEngine.endStroke()};this.drawStartHandler=function(c){c.preventDefault();var s=$(b.canvas).offset();j=-1*s.left;a=-1*s.top;b.dataEngine.startStroke(g(c)); |
209 | -d.kick()};this.drawMoveHandler=function(j){j.preventDefault();b.dataEngine.inStroke&&(b.dataEngine.addToStroke(g(j)),d.kick())};return this}.call({},this),l=g.drawEndHandler,i=g.drawStartHandler,p=g.drawMoveHandler,h=this.canvas,j=$(h);this.isCanvasEmulator?(j.bind("mousemove."+e,p),j.bind("mouseup."+e,l),j.bind("mousedown."+e,i)):(h.ontouchstart=function(b){h.onmousedown=void 0;h.onmouseup=void 0;h.onmousemove=void 0;this.fatFingerCompensation=d.minFatFingerCompensation&&-3*d.lineWidth>d.minFatFingerCompensation? |
210 | --3*d.lineWidth:d.minFatFingerCompensation;i(b);h.ontouchend=l;h.ontouchstart=i;h.ontouchmove=p},h.onmousedown=function(b){h.ontouchstart=void 0;h.ontouchend=void 0;h.ontouchmove=void 0;i(b);h.onmousedown=i;h.onmouseup=l;h.onmousemove=p});b[e+".windowmouseup"]=c.subscribe(e+".windowmouseup",g.drawEndHandler);this.events.publish(e+".attachingEventHandlers");var n=this,b=d.width.toString(10),w=e;if("ratio"===b||"%"===b.split("")[b.length-1])this.eventTokens[w+".parentresized"]=c.subscribe(w+".parentresized", |
211 | -function(b,j,a){return function(){var g=j.width();if(g!==a){for(var d in b)b.hasOwnProperty(d)&&(c.unsubscribe(b[d]),delete b[d]);var s=n.settings;n.$parent.children().remove();for(d in n)n.hasOwnProperty(d)&&delete n[d];d=s.data;var g=1*g/a,f=[],l,i,e,h,k,p;i=0;for(e=d.length;i<e;i++){p=d[i];l={x:[],y:[]};h=0;for(k=p.x.length;h<k;h++)l.x.push(p.x[h]*g),l.y.push(p.y[h]*g);f.push(l)}s.data=f;j[w](s)}}}(this.eventTokens,this.$parent,this.$parent.width(),1*this.canvas.width/this.canvas.height));this.resetCanvas(d.data); |
212 | -this.events.publish(e+".initialized");return this}var e="jSignature",y=function(b,j){var a;this.kick=function(){clearTimeout(a);a=setTimeout(j,b)};this.clear=function(){clearTimeout(a)};return this},v=function(b){this.topics={};this.context=b?b:this;this.publish=function(b,a,g,d){if(this.topics[b]){var c=this.topics[b],f=Array.prototype.slice.call(arguments,1),l=[],i,e,h,p;e=0;for(h=c.length;e<h;e++)p=c[e],i=p[0],p[1]&&(p[0]=function(){},l.push(e)),i.apply(this.context,f);e=0;for(h=l.length;e<h;e++)c.splice(l[e], |
213 | -1)}};this.subscribe=function(b,a,g){this.topics[b]?this.topics[b].push([a,g]):this.topics[b]=[[a,g]];return{topic:b,callback:a}};this.unsubscribe=function(b){if(this.topics[b.topic])for(var a=this.topics[b.topic],g=0,d=a.length;g<d;g++)a[g][0]===b.callback&&a.splice(g,1)}},z=function(b){var a=this.canvasContext,d=b.x[0],b=b.y[0],g=this.settings.lineWidth,c=a.fillStyle;a.fillStyle=a.strokeStyle;a.fillRect(d+g/-2,b+g/-2,g,g);a.fillStyle=c},u=function(b,a){var d=new k(b.x[a-1],b.y[a-1]),g=new k(b.x[a], |
214 | -b.y[a]),c=d.getVectorToPoint(g);if(1<a){var f=new k(b.x[a-2],b.y[a-2]),l=f.getVectorToPoint(d),i;if(l.getLength()>this.lineCurveThreshold){i=2<a?(new k(b.x[a-3],b.y[a-3])).getVectorToPoint(f):new m(0,0);var e=0.35*l.getLength(),h=l.angleTo(i.reverse()),p=c.angleTo(l.reverse());i=(new m(i.x+l.x,i.y+l.y)).resizeTo(Math.max(0.05,h)*e);var n=(new m(l.x+c.x,l.y+c.y)).reverse().resizeTo(Math.max(0.05,p)*e),l=this.canvasContext,e=f.x,p=f.y,h=d.x,w=d.y,A=f.x+i.x,f=f.y+i.y;i=d.x+n.x;n=d.y+n.y;l.beginPath(); |
215 | -l.moveTo(e,p);l.bezierCurveTo(A,f,i,n,h,w);l.stroke()}}c.getLength()<=this.lineCurveThreshold&&(c=this.canvasContext,f=d.x,d=d.y,i=g.x,g=g.y,c.beginPath(),c.moveTo(f,d),c.lineTo(i,g),c.stroke())},x=function(b){var a=b.x.length-1;if(0<a){var d=new k(b.x[a],b.y[a]),g=new k(b.x[a-1],b.y[a-1]),c=g.getVectorToPoint(d);if(c.getLength()>this.lineCurveThreshold){if(1<a){var b=(new k(b.x[a-2],b.y[a-2])).getVectorToPoint(g),f=(new m(b.x+c.x,b.y+c.y)).resizeTo(c.getLength()/2),c=this.canvasContext,b=g.x,a=g.y, |
216 | -l=d.x,i=d.y,e=g.x+f.x,g=g.y+f.y,f=d.x,d=d.y;c.beginPath();c.moveTo(b,a);c.bezierCurveTo(e,g,f,d,l,i)}else c=this.canvasContext,b=g.x,g=g.y,a=d.x,d=d.y,c.beginPath(),c.moveTo(b,g),c.lineTo(a,d);c.stroke()}}};r.prototype.resetCanvas=function(b){var a=this.canvas,d=this.settings,c=this.canvasContext,f=this.isCanvasEmulator,l=a.width,i=a.height;c.clearRect(0,0,l+30,i+30);c.shadowColor=c.fillStyle=d["background-color"];f&&c.fillRect(0,0,l+30,i+30);c.lineWidth=Math.ceil(parseInt(d.lineWidth,10));c.lineCap= |
217 | -c.lineJoin="round";c.strokeStyle=d["decor-color"];c.shadowOffsetX=0;c.shadowOffsetY=0;var h=Math.round(i/5),p=1.5*h,k=i-h,l=l-1.5*h,i=i-h;c.beginPath();c.moveTo(p,k);c.lineTo(l,i);c.stroke();c.strokeStyle=d.color;f||(c.shadowColor=c.strokeStyle,c.shadowOffsetX=0.5*c.lineWidth,c.shadowOffsetY=-0.6*c.lineWidth,c.shadowBlur=0);b||(b=[]);c=this.dataEngine=new t(b,this,z,u,x);d.data=b;$(a).data(e+".data",b).data(e+".settings",d);var n=this.$parent,w=this.events,A=e;c.changed=function(){w.publish(A+".change"); |
218 | -n.trigger("change")};c.changed();return!0};r.prototype.initializeCanvas=function(b){var a=document.createElement("canvas"),c=$(a);b.width===b.height&&"ratio"===b.height&&(b.width="100%");c.css("margin",0).css("padding",0).css("border","none").css("height","ratio"===b.height||!b.height?1:b.height.toString(10)).css("width","ratio"===b.width||!b.width?1:b.width.toString(10));c.appendTo(this.$parent);"ratio"===b.height?c.css("height",Math.round(c.width()/b.sizeRatio)):"ratio"===b.width&&c.css("width", |
219 | -Math.round(c.height()*b.sizeRatio));c.addClass(e);a.width=c.width();a.height=c.height();b=a;if(b.getContext)b=!1;else{var c=b.ownerDocument.parentWindow,d=c.FlashCanvas?b.ownerDocument.parentWindow.FlashCanvas:"undefined"===typeof FlashCanvas?void 0:FlashCanvas;if(d){b=d.initElement(b);d=1;c&&(c.screen&&c.screen.deviceXDPI&&c.screen.logicalXDPI)&&(d=1*c.screen.deviceXDPI/c.screen.logicalXDPI);if(1!==d)try{$(b).children("object").get(0).resize(Math.ceil(b.width*d),Math.ceil(b.height*d)),b.getContext("2d").scale(d, |
220 | -d)}catch(f){}b=!0}else throw Error("Canvas element does not support 2d context. jSignature cannot proceed.");}this.isCanvasEmulator=b;a.onselectstart=function(b){b&&b.preventDefault&&b.preventDefault();b&&b.stopPropagation&&b.stopPropagation();return!1};return a};var p=window,h=function(b,a){var c=new Image,d=this;c.onload=function(){d.getContext("2d").drawImage(c,0,0,c.width<d.width?c.width:d.width,c.height<d.height?c.height:d.height)};c.src="data:"+a+","+b},a=function(b){this.find("canvas."+e).add(this.filter("canvas."+ |
221 | -e)).data(e+".this").resetCanvas(b);return this},f=function(b,a){if(void 0===a&&("string"===typeof b&&"data:"===b.substr(0,5))&&(a=b.slice(5).split(",")[0],b=b.slice(6+a.length),a===b))return;var c=this.find("canvas."+e).add(this.filter("canvas."+e));if(n.hasOwnProperty(a))0!==c.length&&n[a].call(c[0],b,a,function(b){return function(){return b.resetCanvas.apply(b,arguments)}}(c.data(e+".this")));else throw Error(e+" is unable to find import plugin with for format '"+String(a)+"'");return this},d=new v, |
222 | -c=e,l,i=function(){d.publish(c+".parentresized")};$(p).bind("resize."+c,function(){l&&clearTimeout(l);l=setTimeout(i,500)}).bind("mouseup."+c,function(){d.publish(c+".windowmouseup")});var w={},A={"default":function(){return this.toDataURL()},"native":function(b){return b},image:function(){var b=this.toDataURL();if("string"===typeof b&&4<b.length&&"data:"===b.slice(0,5)&&-1!==b.indexOf(",")){var a=b.indexOf(",");return[b.slice(5,a),b.substr(a+1)]}return[]}},n={"native":function(b,a,c){c(b)},image:h, |
223 | -"image/png;base64":h,"image/jpeg;base64":h,"image/jpg;base64":h},B={"export":A,"import":n,instance:w},C={init:function(b){return this.each(function(){var a,c=!1;for(a=this.parentNode;a&&!c;)c=a.body,a=a.parentNode;!c||new r(this,b,w)})},getSettings:function(){return this.find("canvas."+e).add(this.filter("canvas."+e)).data(e+".this").settings},clear:a,reset:a,addPlugin:function(b,a,c){B.hasOwnProperty(b)&&(B[b][a]=c);return this},listPlugins:function(b){var a=[];if(B.hasOwnProperty(b)){var b=B[b], |
224 | -c;for(c in b)b.hasOwnProperty(c)&&a.push(c)}return a},getData:function(b){var a=this.find("canvas."+e).add(this.filter("canvas."+e));void 0===b&&(b="default");if(0!==a.length&&A.hasOwnProperty(b))return A[b].call(a.get(0),a.data(e+".data"))},importData:f,setData:f,globalEvents:function(){return d},events:function(){return this.find("canvas."+e).add(this.filter("canvas."+e)).data(e+".this").events}};$.fn[e]=function(b){if(!b||"object"===typeof b)return C.init.apply(this,arguments);if("string"===typeof b&& |
225 | -C[b])return C[b].apply(this,Array.prototype.slice.call(arguments,1));$.error("Method "+String(b)+" does not exist on jQuery."+e)}})(); |
226 | -(function(){$.fn.jSignature("addPlugin","instance","UndoButton",function(q){this.events.subscribe("jSignature.attachingEventHandlers",function(){if(this.settings[q]){var m=this.settings[q];"function"!==typeof m&&(m=function(){var e=$('<input type="button" value="Undo last stroke" style="position:absolute;display:none;margin:0 !important;top:auto" />').appendTo(this.$controlbarLower),k=e.width();e.css("left",Math.round((this.canvas.width-k)/2));k!==e.width()&&e.width(k);return e});var k=m.call(this), |
227 | -t=this;t.events.subscribe("jSignature.change",function(){t.dataEngine.data.length?k.show():k.hide()});var r=this,e=(this.events.topics.hasOwnProperty("jSignature.undo")?q:"jSignature")+".undo";k.bind("click",function(){r.events.publish(e)});r.events.subscribe(e,function(){var e=r.dataEngine.data;e.length&&(e.pop(),r.resetCanvas(e))})}})})})(); |
228 | -(function(){for(var q={},m={},k="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX".split(""),t=k.length/2,r=t-1;-1<r;r--)q[k[r]]=k[r+t],m[k[r+t]]=k[r];var e=function(e){for(var e=e.split(""),h=e.length,a=1;a<h;a++)e[a]=q[e[a]];return e.join("")},y=function(k){for(var h=[],a=0,f=1,d=k.length,c,l,i=0;i<d;i++)c=Math.round(k[i]),l=c-a,a=c,0>l&&0<f?(f=-1,h.push("Z")):0<l&&0>f&&(f=1,h.push("Y")),c=Math.abs(l),c>=t?h.push(e(c.toString(t))):h.push(c.toString(t));return h.join("")},v=function(e){for(var h= |
229 | -[],e=e.split(""),a=e.length,f,d=1,c=[],l=0,i=0;i<a;i++)f=e[i],f in q||"Z"===f||"Y"===f?(0!==c.length&&(c=parseInt(c.join(""),t)*d+l,h.push(c),l=c),"Z"===f?(d=-1,c=[]):"Y"===f?(d=1,c=[]):c=[f]):c.push(m[f]);h.push(parseInt(c.join(""),t)*d+l);return h},z=function(e){for(var h=[],a=e.length,f,d=0;d<a;d++)f=e[d],h.push(y(f.x)),h.push(y(f.y));return h.join("_")},u=function(e){for(var h=[],e=e.split("_"),a=e.length/2,f=0;f<a;f++)h.push({x:v(e[2*f]),y:v(e[2*f+1])});return h},k=function(e){return["image/jsignature;base30", |
230 | -z(e)]},r=function(e,h,a){"string"===typeof e&&("image/jsignature;base30"===e.substring(0,23).toLowerCase()&&(e=e.substring(24)),a(u(e)))};if(null==this.jQuery)throw Error("We need jQuery for some of the functionality. jQuery is not detected. Failing to initialize...");var x=this.jQuery.fn.jSignature;x("addPlugin","export","base30",k);x("addPlugin","export","image/jsignature;base30",k);x("addPlugin","import","base30",r);x("addPlugin","import","image/jsignature;base30",r);this.jSignatureDebug&&(this.jSignatureDebug.base30= |
231 | -{remapTailChars:e,compressstrokeleg:y,uncompressstrokeleg:v,compressstrokes:z,uncompressstrokes:u,charmap:q})}).call("undefined"!==typeof window?window:this); |
232 | -(function(){function q(a,f){this.x=a;this.y=f;this.reverse=function(){return new this.constructor(-1*this.x,-1*this.y)};this._length=null;this.getLength=function(){this._length||(this._length=Math.sqrt(Math.pow(this.x,2)+Math.pow(this.y,2)));return this._length};var d=function(a){return Math.round(a/Math.abs(a))};this.resizeTo=function(a){if(0===this.x&&0===this.y)this._length=0;else if(0===this.x)this._length=a,this.y=a*d(this.y);else if(0===this.y)this._length=a,this.x=a*d(this.x);else{var f=Math.abs(this.y/ |
233 | -this.x),e=Math.sqrt(Math.pow(a,2)/(1+Math.pow(f,2))),f=f*e;this._length=a;this.x=e*d(this.x);this.y=f*d(this.y)}return this};this.angleTo=function(a){var d=this.getLength()*a.getLength();return 0===d?0:Math.acos(Math.min(Math.max((this.x*a.x+this.y*a.y)/d,-1),1))/Math.PI}}function m(a,f){this.x=a;this.y=f;this.getVectorToCoordinates=function(a,c){return new q(a-this.x,c-this.y)};this.getVectorFromCoordinates=function(a,c){return this.getVectorToCoordinates(a,c).reverse()};this.getVectorToPoint=function(a){return new q(a.x- |
234 | -this.x,a.y-this.y)};this.getVectorFromPoint=function(a){return this.getVectorToPoint(a).reverse()}}function k(a,f){var d=Math.pow(10,f);return Math.round(a*d)/d}function t(a,f,d){var f=f+1,c=new m(a.x[f-1],a.y[f-1]),e=new m(a.x[f],a.y[f]),e=c.getVectorToPoint(e),i=new m(a.x[f-2],a.y[f-2]),c=i.getVectorToPoint(c);return c.getLength()>d?(d=2<f?(new m(a.x[f-3],a.y[f-3])).getVectorToPoint(i):new q(0,0),a=0.35*c.getLength(),i=c.angleTo(d.reverse()),f=e.angleTo(c.reverse()),d=(new q(d.x+c.x,d.y+c.y)).resizeTo(Math.max(0.05, |
235 | -i)*a),e=(new q(c.x+e.x,c.y+e.y)).reverse().resizeTo(Math.max(0.05,f)*a),e=new q(c.x+e.x,c.y+e.y),["c",k(d.x,2),k(d.y,2),k(e.x,2),k(e.y,2),k(c.x,2),k(c.y,2)]):["l",k(c.x,2),k(c.y,2)]}function r(a,f){var d=a.x.length-1,c=new m(a.x[d],a.y[d]),e=new m(a.x[d-1],a.y[d-1]),c=e.getVectorToPoint(c);if(1<d&&c.getLength()>f){var d=(new m(a.x[d-2],a.y[d-2])).getVectorToPoint(e),e=c.angleTo(d.reverse()),i=0.35*c.getLength(),d=(new q(d.x+c.x,d.y+c.y)).resizeTo(Math.max(0.05,e)*i);return["c",k(d.x,2),k(d.y,2),k(c.x, |
236 | -2),k(c.y,2),k(c.x,2),k(c.y,2)]}return["l",k(c.x,2),k(c.y,2)]}function e(a,e,d){for(var e=["M",k(a.x[0]-e,2),k(a.y[0]-d,2)],d=1,c=a.x.length-1;d<c;d++)e.push.apply(e,t(a,d,1));0<c?e.push.apply(e,r(a,d,1)):0===c&&e.push.apply(e,["l",1,1]);return e.join(" ")}function y(a){var f=['<?xml version="1.0" encoding="UTF-8" standalone="no"?>','<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'],d,c=a.length,l,i=[],h=[],k=l=d=0,n=0,p=[];if(0!==c){for(d=0;d<c;d++){k= |
237 | -a[d];n=[];l={x:[],y:[]};for(var m=void 0,b=void 0,m=0,b=k.x.length;m<b;m++)n.push({x:k.x[m],y:k.y[m]});n=simplify(n,0.7,!0);m=0;for(b=n.length;m<b;m++)l.x.push(n[m].x),l.y.push(n[m].y);p.push(l);i=i.concat(l.x);h=h.concat(l.y)}a=Math.min.apply(null,i)-1;c=Math.max.apply(null,i)+1;i=Math.min.apply(null,h)-1;h=Math.max.apply(null,h)+1;k=0>a?0:a;n=0>i?0:i;d=c-a;l=h-i}f.push('<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="'+d.toString()+'" height="'+l.toString()+'">');d=0;for(c=p.length;d< |
238 | -c;d++)l=p[d],f.push('<path fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="'+e(l,k,n)+'"/>');f.push("</svg>");return f.join("")}function v(a){return[p,y(a)]}function z(a){return[h,x(y(a))]}var u=window;"use strict";("undefined"!=typeof exports?exports:u).simplify=function(a,e,d){e=void 0!==e?e*e:1;if(!d){for(var c=a.length,l,i=a[0],h=[i],d=1;d<c;d++){l=a[d];var k=l.x-i.x,n=l.y-i.y;k*k+n*n>e&&(h.push(l),i=l)}a=(i!==l&&h.push(l),h)}l=a;var d=l.length, |
239 | -c=new ("undefined"!=typeof Uint8Array?Uint8Array:Array)(d),i=0,h=d-1,m,p,b=[],j=[],s=[];for(c[i]=c[h]=1;h;){n=0;for(k=i+1;k<h;k++){m=l[k];var g=l[i],r=l[h],q=g.x,t=g.y,g=r.x-q,u=r.y-t,v=void 0;if(0!==g||0!==u)v=((m.x-q)*g+(m.y-t)*u)/(g*g+u*u),1<v?(q=r.x,t=r.y):0<v&&(q+=g*v,t+=u*v);m=(g=m.x-q,u=m.y-t,g*g+u*u);m>n&&(p=k,n=m)}n>e&&(c[p]=1,b.push(i),j.push(p),b.push(p),j.push(h));i=b.pop();h=j.pop()}for(k=0;k<d;k++)c[k]&&s.push(l[k]);return a=s,a};if("function"!==typeof x)var x=function(a){var e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".split(""), |
240 | -d,c,h,i,k=0,m=0,n="",n=[];do d=a.charCodeAt(k++),c=a.charCodeAt(k++),h=a.charCodeAt(k++),i=d<<16|c<<8|h,d=i>>18&63,c=i>>12&63,h=i>>6&63,i&=63,n[m++]=e[d]+e[c]+e[h]+e[i];while(k<a.length);n=n.join("");a=a.length%3;return(a?n.slice(0,a-3):n)+"===".slice(a||3)};var p="image/svg+xml",h="image/svg+xml;base64";if("undefined"===typeof $)throw Error("We need jQuery for some of the functionality. jQuery is not detected. Failing to initialize...");u=$.fn.jSignature;u("addPlugin","export","svg",v);u("addPlugin", |
241 | -"export",p,v);u("addPlugin","export","svgbase64",z);u("addPlugin","export",h,z)})(); |
242 | \ No newline at end of file |
243 | |
244 | === modified file 'website_quote/views/website_quotation.xml' |
245 | --- website_quote/views/website_quotation.xml 2014-01-28 20:50:17 +0000 |
246 | +++ website_quote/views/website_quotation.xml 2014-05-15 14:05:22 +0000 |
247 | @@ -163,7 +163,7 @@ |
248 | <t t-call="website.layout"> |
249 | <t t-set="head"> |
250 | <script type="text/javascript" src="/website_quote/static/src/js/website_quotation.js"></script> |
251 | - <script type="text/javascript" src="/website_quote/static/lib/jSignature/jSignature.min.js"></script> |
252 | + <script type="text/javascript" src="/website/static/lib/jSignature/jSignature.min.js"></script> |
253 | <link rel='stylesheet' href='/website_quote/static/src/css/website_quotation.css'/> |
254 | <t t-raw="head or ''"/> |
255 | </t> |
256 | @@ -183,7 +183,7 @@ |
257 | <div class="mt8" t-if="order_valid"> |
258 | <a type="submit" href="#discussion"> |
259 | Ask Changes |
260 | - </a> or |
261 | + </a> or |
262 | <a data-toggle="modal" data-target="#modeldecline"> |
263 | Reject |
264 | </a> |
265 | @@ -210,7 +210,7 @@ |
266 | |
267 | <div class="text-center mb16" t-if="quotation.amount_undiscounted > quotation.amount_total"> |
268 | <p class="text-muted mb8">Your advantage:</p> |
269 | - <strong t-field="quotation.amount_total" |
270 | + <strong t-field="quotation.amount_total" |
271 | t-field-options='{"widget": "monetary", "display_currency": "quotation.pricelist_id.currency_id"}'/> |
272 | <strong t-field="quotation.amount_undiscounted" |
273 | t-field-options='{"widget": "monetary", "display_currency": "quotation.pricelist_id.currency_id"}' |
274 | @@ -257,7 +257,7 @@ |
275 | <p> |
276 | I agree that by signing this proposal, I |
277 | accept it on the behalf of <b t-field="quotation.company_id"/>, |
278 | - for an amount of |
279 | + for an amount of |
280 | <b data-id="total_amount" t-field="quotation.amount_total" |
281 | t-field-options='{"widget": "monetary", "display_currency": "quotation.pricelist_id.currency_id"}'/> |
282 | with payment terms: <b t-field="quotation.payment_term"/>. |
283 | @@ -361,12 +361,12 @@ |
284 | <a t-att-id="line.id"/> |
285 | <div t-field="line.website_description"/> |
286 | </t> |
287 | - |
288 | + |
289 | <div class="oe_structure"/> |
290 | |
291 | <a id="pricing"/> |
292 | <t t-call="website_quote.pricing"/> |
293 | - |
294 | + |
295 | <a id="options"/> |
296 | <t t-call="website_quote.optional_products"/> |
297 | |
298 | |
299 | === added directory 'website_sign' |
300 | === added file 'website_sign/__init__.py' |
301 | --- website_sign/__init__.py 1970-01-01 00:00:00 +0000 |
302 | +++ website_sign/__init__.py 2014-05-15 14:05:22 +0000 |
303 | @@ -0,0 +1,25 @@ |
304 | +# -*- coding: utf-8 -*- |
305 | +############################################################################## |
306 | +# |
307 | +# OpenERP, Open Source Management Solution |
308 | +# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>). |
309 | +# |
310 | +# This program is free software: you can redistribute it and/or modify |
311 | +# it under the terms of the GNU Affero General Public License as |
312 | +# published by the Free Software Foundation, either version 3 of the |
313 | +# License, or (at your option) any later version. |
314 | +# |
315 | +# This program is distributed in the hope that it will be useful, |
316 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
317 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
318 | +# GNU Affero General Public License for more details. |
319 | +# |
320 | +# You should have received a copy of the GNU Affero General Public License |
321 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
322 | +# |
323 | +############################################################################## |
324 | +import controllers |
325 | +import models |
326 | + |
327 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
328 | + |
329 | |
330 | === added file 'website_sign/__openerp__.py' |
331 | --- website_sign/__openerp__.py 1970-01-01 00:00:00 +0000 |
332 | +++ website_sign/__openerp__.py 2014-05-15 14:05:22 +0000 |
333 | @@ -0,0 +1,46 @@ |
334 | +# -*- coding: utf-8 -*- |
335 | +############################################################################## |
336 | +# |
337 | +# OpenERP, Open Source Management Solution |
338 | +# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>). |
339 | +# |
340 | +# This program is free software: you can redistribute it and/or modify |
341 | +# it under the terms of the GNU Affero General Public License as |
342 | +# published by the Free Software Foundation, either version 3 of the |
343 | +# License, or (at your option) any later version. |
344 | +# |
345 | +# This program is distributed in the hope that it will be useful, |
346 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
347 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
348 | +# GNU Affero General Public License for more details. |
349 | +# |
350 | +# You should have received a copy of the GNU Affero General Public License |
351 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
352 | +# |
353 | +############################################################################## |
354 | + |
355 | + |
356 | +{ |
357 | + 'name': 'Digital Sign on Document', |
358 | + 'version': '1.0', |
359 | + 'category': 'Website', |
360 | + 'description': """ |
361 | +Digital sign on attached Document. |
362 | +=================================== |
363 | + |
364 | + """, |
365 | + 'author': 'OpenERP SA', |
366 | + 'website': 'http://www.openerp.com', |
367 | + 'depends': ['website'], |
368 | + 'data': [ |
369 | + 'security/ir.model.access.csv', |
370 | + 'views/website_sign.xml', |
371 | + 'data/website_sign_data.xml', |
372 | + ], |
373 | + 'demo': [], |
374 | + 'qweb': [ |
375 | + 'static/src/xml/*.xml' |
376 | + ], |
377 | + 'installable': True, |
378 | +} |
379 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
380 | |
381 | === added directory 'website_sign/controllers' |
382 | === added file 'website_sign/controllers/__init__.py' |
383 | --- website_sign/controllers/__init__.py 1970-01-01 00:00:00 +0000 |
384 | +++ website_sign/controllers/__init__.py 2014-05-15 14:05:22 +0000 |
385 | @@ -0,0 +1,3 @@ |
386 | +import main |
387 | + |
388 | +# vim:expandtab:tabstop=4:softtabstop=4:shiftwidth=4: |
389 | |
390 | === added file 'website_sign/controllers/main.py' |
391 | --- website_sign/controllers/main.py 1970-01-01 00:00:00 +0000 |
392 | +++ website_sign/controllers/main.py 2014-05-15 14:05:22 +0000 |
393 | @@ -0,0 +1,183 @@ |
394 | +# -*- coding: utf-8 -*- |
395 | +############################################################################## |
396 | +# |
397 | +# OpenERP, Open Source Management Solution |
398 | +# Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>). |
399 | +# |
400 | +# This program is free software: you can redistribute it and/or modify |
401 | +# it under the terms of the GNU Affero General Public License as |
402 | +# published by the Free Software Foundation, either version 3 of the |
403 | +# License, or (at your option) any later version. |
404 | +# |
405 | +# This program is distributed in the hope that it will be useful, |
406 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
407 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
408 | +# GNU Affero General Public License for more details. |
409 | +# |
410 | +# You should have received a copy of the GNU Affero General Public License |
411 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
412 | +# |
413 | +############################################################################## |
414 | + |
415 | +from openerp import SUPERUSER_ID |
416 | +from openerp.addons.web import http |
417 | +from openerp.addons.web.http import request |
418 | +from openerp.addons.website.models import website |
419 | +from openerp.tools import DEFAULT_SERVER_DATE_FORMAT |
420 | +import time |
421 | +from openerp.addons.web.controllers.main import login_redirect |
422 | +from openerp.tools.translate import _ |
423 | + |
424 | +class website_sign(http.Controller): |
425 | + @http.route([ |
426 | + "/sign/document/<int:id>", |
427 | + "/sign/document/<int:id>/<token>" |
428 | + ], type='http', auth="public", website=True) |
429 | + def request_sign(self, id, token=None, message=False, **post): |
430 | + if not request.session.uid: |
431 | + return login_redirect() |
432 | + current_sign = None |
433 | + ir_attachment_signature = request.registry.get('ir.attachment.signature') |
434 | + ir_attachment = request.registry.get('ir.attachment') |
435 | + |
436 | + if token: |
437 | + signature_id = ir_attachment_signature.search(request.cr, request.uid,[('document_id', '=', id),('access_token', '=', token)], context=request.context) |
438 | + if not signature_id: |
439 | + return request.website.render('website.404') |
440 | + current_sign = ir_attachment_signature.browse(request.cr, request.uid, signature_id[0]) |
441 | + |
442 | + # list out partners and their signatures who are requested to sign. |
443 | + request_sign = ir_attachment_signature.search(request.cr, request.uid,[('document_id', '=', id)], context=request.context) |
444 | + signatures = ir_attachment_signature.browse(request.cr, SUPERUSER_ID, request_sign) |
445 | + req_count = [signs.id for signs in signatures if signs.state == 'draft'] |
446 | + attachment = ir_attachment.browse(request.cr, SUPERUSER_ID, id) |
447 | + record = request.registry.get(attachment.res_model).browse(request.cr, token and SUPERUSER_ID or request.uid, attachment.res_id) |
448 | + |
449 | + values = { |
450 | + 'attachment_id': id, |
451 | + 'signatures': signatures, |
452 | + 'current_sign': current_sign, |
453 | + 'token': token, |
454 | + 'attachment': attachment, |
455 | + 'record': record, |
456 | + 'sign_req': req_count, |
457 | + 'message': message and int(message) or False |
458 | + } |
459 | + |
460 | + return request.website.render('website_sign.doc_sign', values) |
461 | + |
462 | + @http.route(['/website_sign/signed'], type='json', auth="public", website=True) |
463 | + def signed(self, res_id=None, token=None, sign=None, signer=None, **post): |
464 | + ir_attachment_signature = request.registry.get('ir.attachment.signature') |
465 | + signature_id = ir_attachment_signature.search(request.cr, request.uid,[('document_id', '=', int(res_id)),('access_token', '=', token)], context=request.context) |
466 | + ir_attachment_signature.write(request.cr, request.uid, signature_id[0], {'state': 'closed', 'signing_date': time.strftime(DEFAULT_SERVER_DATE_FORMAT), 'sign': sign, 'signer_name': signer}, context=request.context) |
467 | + |
468 | + #send mail and notification in chatter about signed by user. |
469 | + model = request.registry.get('ir.attachment').search_read(request.cr, request.uid, [('id', '=', int(res_id))], ['res_model', 'res_id', 'name'], context=request.context)[0] |
470 | + thread_model = model['res_model'] |
471 | + thread_id = model['res_id'] |
472 | + message = _('Document <b>%s</b> signed by %s') % (model['name'], signer) |
473 | + self.__message_post(message, thread_model, thread_id, type='comment', subtype='mt_comment') |
474 | + |
475 | + return True |
476 | + |
477 | + def __message_post(self, message, thread_model, thread_id, type='comment', subtype=False, attachments=[]): |
478 | + request.session.body = message |
479 | + cr, uid, context = request.cr, request.uid, request.context |
480 | + user = request.registry['res.users'].browse(cr, SUPERUSER_ID, uid, context=context) |
481 | + if 'body' in request.session and request.session.body: |
482 | + context.update({'notify_author': True}) |
483 | + request.registry.get(thread_model).message_post(cr, SUPERUSER_ID, thread_id, |
484 | + body=request.session.body, |
485 | + type=type, |
486 | + subtype=subtype, |
487 | + author_id=user.partner_id.id, |
488 | + partner_ids=[user.partner_id.id], |
489 | + context=context, |
490 | + ) |
491 | + request.session.body = False |
492 | + return True |
493 | + |
494 | + @http.route(['/website_sign/get_followers'], type='json', auth="public", website=True) |
495 | + def get_followers(self, thread_id=None, attachment_id=None, model=None, **post): |
496 | + partner_id = (request.registry.get('res.users').browse(request.cr, request.uid, request.uid)).partner_id.id |
497 | + |
498 | + fol_obj = request.registry.get('mail.followers') |
499 | + fol_ids = fol_obj.search(request.cr, SUPERUSER_ID, [('res_model', '=', model), ('res_id', 'in', [thread_id])]) |
500 | + |
501 | + # get already selected signers |
502 | + sel_fol_obj = request.registry.get('ir.attachment.signature') |
503 | + sel_follower = sel_fol_obj.search_read(request.cr, SUPERUSER_ID,[('document_id','=', attachment_id)],['partner_id'], context=request.context) |
504 | + sel_fol_ids = map(lambda d: d['partner_id'][0], sel_follower) |
505 | + |
506 | + res = [] |
507 | + followers_data = {} |
508 | + for follower in fol_obj.browse(request.cr, SUPERUSER_ID, fol_ids): |
509 | + if not partner_id == follower.partner_id.id: |
510 | + if follower.partner_id.id in sel_fol_ids: |
511 | + res.append({'followers_id': follower.partner_id.id, 'name': follower.partner_id.name, 'email': follower.partner_id.email, 'selected':'checked'}) |
512 | + else: |
513 | + res.append({'followers_id': follower.partner_id.id, 'name': follower.partner_id.name, 'email': follower.partner_id.email, 'selected': None}) |
514 | + followers_data['signer_data'] = res |
515 | + |
516 | + #get title and comments of attachment |
517 | + doc_data = request.registry.get('ir.attachment').search_read(request.cr, SUPERUSER_ID,[('id','=', attachment_id)],['name','description'], context=request.context) |
518 | + followers_data['doc_data'] = doc_data |
519 | + |
520 | + return followers_data |
521 | + |
522 | + @http.route(['/website_sign/set_signer'], type='json', auth="public", website=True) |
523 | + def set_signer(self, attachment_id=None, signer_id=None, title=None, comments=None, **post): |
524 | + ir_attachment_signature = request.registry.get('ir.attachment.signature') |
525 | + vals, att_vals = {}, {} |
526 | + |
527 | + set_fol = ir_attachment_signature.search_read(request.cr, SUPERUSER_ID,[('document_id','=', attachment_id)],['partner_id'], context=request.context) |
528 | + set_fol_ids = map(lambda d: d['partner_id'][0], set_fol) |
529 | + |
530 | + attach_data = request.registry.get('ir.attachment').search_read(request.cr, SUPERUSER_ID,[('id','=', attachment_id)],['name','description'], context=request.context)[0] |
531 | + if attach_data['name'] != title: |
532 | + att_vals['name'] = title |
533 | + if attach_data['description'] != comments: |
534 | + att_vals['description'] = comments |
535 | + |
536 | + if att_vals: |
537 | + request.registry.get('ir.attachment').write(request.cr, request.uid, attachment_id, att_vals, context=request.context) |
538 | + |
539 | + if not set(signer_id) == set(set_fol_ids): |
540 | + for partner in set_fol_ids: |
541 | + for doc_id in set_fol: |
542 | + if doc_id['partner_id'][0] == partner: |
543 | + ir_attachment_signature.unlink(request.cr, SUPERUSER_ID, [doc_id['id']], context=request.context) |
544 | + |
545 | + for signer in signer_id: |
546 | + vals['partner_id'] = signer |
547 | + vals['document_id'] = attachment_id |
548 | + vals['state'] = 'draft' |
549 | + vals['date'] = time.strftime(DEFAULT_SERVER_DATE_FORMAT) |
550 | + ir_attachment_signature.create(request.cr, request.uid, vals, context=request.context) |
551 | + |
552 | + return True |
553 | + |
554 | + @http.route(['/website_sign/get_signer'], type='json', auth="public", website=True) |
555 | + def get_signer(self, attachment_ids=None, **post): |
556 | + ir_attachment_signature = request.registry.get('ir.attachment.signature') |
557 | + signer_obj = ir_attachment_signature.search(request.cr, request.uid, [('document_id', 'in', attachment_ids)], context=request.context) |
558 | + signers = ir_attachment_signature.browse(request.cr, SUPERUSER_ID, signer_obj) |
559 | + signer_ids = map(lambda d: d.partner_id.id, signers) |
560 | + |
561 | + signers_data = {} |
562 | + for sign_id in signer_ids: |
563 | + signers_data[sign_id] = [] |
564 | + for doc in signers: |
565 | + if sign_id == doc.partner_id.id: |
566 | + signers_data[sign_id].append({'id': doc.document_id.id,'name': doc.document_id.name, 'token': doc.access_token, 'fname': doc.document_id.datas_fname}) |
567 | + return signers_data |
568 | + |
569 | + @http.route(['/sign/document/<int:id>/<token>/note'], type='http', auth="public", website=True) |
570 | + def post_note(self, id, token, **post): |
571 | + record = request.registry.get('ir.attachment').search_read(request.cr, request.uid,[('id', '=', id)], ['res_id', 'res_model'], context=request.context)[0] |
572 | + message = post.get('comment') |
573 | + |
574 | + if message: |
575 | + self.__message_post(message, record['res_model'], record['res_id'], type='comment', subtype='mt_comment') |
576 | + return request.redirect("/sign/document/%s/%s?message=1" % (id, token)) |
577 | |
578 | === added directory 'website_sign/data' |
579 | === added file 'website_sign/data/website_sign_data.xml' |
580 | --- website_sign/data/website_sign_data.xml 1970-01-01 00:00:00 +0000 |
581 | +++ website_sign/data/website_sign_data.xml 2014-05-15 14:05:22 +0000 |
582 | @@ -0,0 +1,66 @@ |
583 | +<?xml version="1.0"?> |
584 | +<openerp> |
585 | + <data> |
586 | + <record id="request_sign_template" model="email.template"> |
587 | + <field name="name">Document Sign Request</field> |
588 | + <field name="model_id" ref="website_sign.model_ir_attachment_signature"/> |
589 | + <field name="auto_delete" eval="True"/> |
590 | + <field name="email_from">${ctx['email_from']}</field> |
591 | + <field name="email_to" >${ctx['email_to']}</field> |
592 | + <field name="body_html"><![CDATA[ |
593 | + <center> |
594 | + <table width = "60%"> |
595 | + <tbody> |
596 | + <tr> |
597 | + <td style="background-color:#ffffff;border:1px solid #ccc;padding:10px 10px 5px 10px" bgcolor="FFFFFF" align="center"> |
598 | + <h1 style="font-size:14px"> |
599 | + ${ctx['email_from_usr']} has requested your signature |
600 | + </h1> |
601 | + </td> |
602 | + </tr> |
603 | + </tbody> |
604 | + </table> |
605 | + <table width="60%"> |
606 | + <tbody> |
607 | + <tr> |
608 | + <td style="background-color:#ffffff;border:1px solid #ccc;padding:40px 40px 30px 40px" bgcolor="FFFFFF"> |
609 | + <h1 style="font-size:18px;margin:0 0 10px 0;font-weight:bold">${ctx['docnames']}</h1> |
610 | + <p style="line-height:1.4em;font-size:14px;margin:10px 0px"> |
611 | + <span style="color:#8c8c8c">From: ${ctx['email_from_usr']} - |
612 | + <a href="mailto:${ctx['email_from']}?subject=RE:" style="color:#368bc6;text-decoration:none" target="_blank">Reply</a> |
613 | + </span> |
614 | + </p> |
615 | + % if ctx['msgbody']: |
616 | + <hr style="color:#cccccc;background-color:#cccccc;min-height:1px;border:none"/> |
617 | + <p style="margin:20px 0px 20px 0px"> |
618 | + ${ctx['msgbody'] | safe} |
619 | + </p> |
620 | + % endif |
621 | + <hr style="color:#cccccc;background-color:#cccccc;min-height:1px;border:none"/> |
622 | + <div style="margin:20px 0px 20px 0px"> |
623 | + <table> |
624 | + <tbody> |
625 | + <tr> |
626 | + % for link in ctx['links']: |
627 | + <td style='padding:9px 16px 9px 16px;font-size:16px;color:#f7fbfd;background:#0088cc'> |
628 | + <a style='text-decoration:none;font-size:16px;color:#f7fbfd' href=${link[0]}> |
629 | + <span style='color:#f7fbfd'>Sign on ${link[1]}</span> |
630 | + </a> |
631 | + </td> |
632 | + % endfor |
633 | + </tr> |
634 | + </tbody> |
635 | + </table> |
636 | + </div> |
637 | + <hr style="color:#cccccc;background-color:#cccccc;min-height:1px;border:none"> |
638 | + <p style="margin:10px 0px;font-size:14px;line-height:1.4em;color:#ff0000">Warning: do not forward this email to others or else they will be able to access your document.</p> |
639 | + </td> |
640 | + </tr> |
641 | + </tbody> |
642 | + </table> |
643 | + </center> |
644 | + ]]> |
645 | + </field> |
646 | + </record> |
647 | + </data> |
648 | +</openerp> |
649 | \ No newline at end of file |
650 | |
651 | === added directory 'website_sign/models' |
652 | === added file 'website_sign/models/__init__.py' |
653 | --- website_sign/models/__init__.py 1970-01-01 00:00:00 +0000 |
654 | +++ website_sign/models/__init__.py 2014-05-15 14:05:22 +0000 |
655 | @@ -0,0 +1,1 @@ |
656 | +import website_sign |
657 | |
658 | === added file 'website_sign/models/website_sign.py' |
659 | --- website_sign/models/website_sign.py 1970-01-01 00:00:00 +0000 |
660 | +++ website_sign/models/website_sign.py 2014-05-15 14:05:22 +0000 |
661 | @@ -0,0 +1,257 @@ |
662 | +# -*- coding: utf-8 -*- |
663 | +############################################################################## |
664 | +# |
665 | +# OpenERP, Open Source Management Solution |
666 | +# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>). |
667 | +# |
668 | +# This program is free software: you can redistribute it and/or modify |
669 | +# it under the terms of the GNU Affero General Public License as |
670 | +# published by the Free Software Foundation, either version 3 of the |
671 | +# License, or (at your option) any later version. |
672 | +# |
673 | +# This program is distributed in the hope that it will be useful, |
674 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
675 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
676 | +# GNU Affero General Public License for more details. |
677 | +# |
678 | +# You should have received a copy of the GNU Affero General Public License |
679 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
680 | +# |
681 | +############################################################################## |
682 | +import uuid,re |
683 | + |
684 | +from openerp import tools |
685 | +from openerp import SUPERUSER_ID |
686 | +from openerp.osv import osv, orm, fields |
687 | +from openerp.tools.translate import _ |
688 | + |
689 | +class prepare_signers(osv.Model): |
690 | + _inherit = "mail.compose.message" |
691 | + |
692 | + def get_mail_values(self, cr, uid, wizard, res_ids, context=None): |
693 | + attachment_ids = [attach.id for attach in wizard.attachment_ids] |
694 | + ir_attachment_signature = self.pool.get('ir.attachment.signature') |
695 | + signer_obj = ir_attachment_signature.search(cr, uid, [('document_id', 'in', attachment_ids)], context=context) |
696 | + signers = ir_attachment_signature.browse(cr, SUPERUSER_ID, signer_obj) |
697 | + signer_ids = map(lambda d: d.partner_id.id, signers) |
698 | + |
699 | + signers_data = {} |
700 | + for sign_id in signer_ids: |
701 | + signers_data[sign_id] = [] |
702 | + for doc in signers: |
703 | + if sign_id == doc.partner_id.id: |
704 | + signers_data[sign_id].append({'id': doc.document_id.id,'name': doc.document_id.name, 'token': doc.access_token, 'fname': doc.document_id.datas_fname}) |
705 | + if signers_data: |
706 | + context.update({'signers_data': signers_data}) |
707 | + return super(prepare_signers, self).get_mail_values(cr, uid, wizard, res_ids, context=context) |
708 | + |
709 | +class preprocess_attachment(osv.Model): |
710 | + _inherit = "mail.message" |
711 | + |
712 | + def _message_read_dict_postprocess(self, cr, uid, messages, message_tree, context=None): |
713 | + """ Post-processing on values given by message_read. This method will |
714 | + handle partners in batch to avoid doing numerous queries. |
715 | + |
716 | + :param list messages: list of message, as get_dict result |
717 | + :param dict message_tree: {[msg.id]: msg browse record} |
718 | + """ |
719 | + res_partner_obj = self.pool.get('res.partner') |
720 | + ir_attachment_obj = self.pool.get('ir.attachment') |
721 | + pid = self.pool['res.users'].browse(cr, SUPERUSER_ID, uid, context=context).partner_id.id |
722 | + |
723 | + # 1. Aggregate partners (author_id and partner_ids) and attachments |
724 | + partner_ids = set() |
725 | + attachment_ids = set() |
726 | + for key, message in message_tree.iteritems(): |
727 | + if message.author_id: |
728 | + partner_ids |= set([message.author_id.id]) |
729 | + if message.subtype_id and message.notified_partner_ids: # take notified people of message with a subtype |
730 | + partner_ids |= set([partner.id for partner in message.notified_partner_ids]) |
731 | + elif not message.subtype_id and message.partner_ids: # take specified people of message without a subtype (log) |
732 | + partner_ids |= set([partner.id for partner in message.partner_ids]) |
733 | + if message.attachment_ids: |
734 | + attachment_ids |= set([attachment.id for attachment in message.attachment_ids]) |
735 | + # Read partners as SUPERUSER -> display the names like classic m2o even if no access |
736 | + partners = res_partner_obj.name_get(cr, SUPERUSER_ID, list(partner_ids), context=context) |
737 | + partner_tree = dict((partner[0], partner) for partner in partners) |
738 | + |
739 | + # calculate total requested and signed on specific attachment. |
740 | + sign_obj = self.pool.get('ir.attachment.signature').search(cr, uid, [('document_id', 'in', list(attachment_ids))], context=context) |
741 | + req_ids = self.pool.get('ir.attachment.signature').browse(cr, SUPERUSER_ID, sign_obj) |
742 | + req_doc_ids = map(lambda d: d.document_id.id, req_ids) |
743 | + doc_data = {} |
744 | + for doc_id in req_doc_ids: |
745 | + doc_count = [] |
746 | + doc_state = [] |
747 | + for ids in req_ids: |
748 | + if doc_id == ids.document_id.id: |
749 | + doc_count.append(doc_id) |
750 | + if ids.state == 'closed': |
751 | + doc_state.append(ids.state) |
752 | + doc_data[doc_id] = {'signed': len(doc_state), 'count': len(doc_count)} |
753 | + |
754 | + # 2. Attachments as SUPERUSER, because could receive msg and attachments for doc uid cannot see |
755 | + attachments = ir_attachment_obj.read(cr, SUPERUSER_ID, list(attachment_ids), ['id', 'datas_fname', 'name', 'file_type_icon'], context=context) |
756 | + attachments_tree = dict((attachment['id'], { |
757 | + 'id': attachment['id'], |
758 | + 'filename': attachment['datas_fname'], |
759 | + 'name': attachment['name'], |
760 | + 'file_type_icon': attachment['file_type_icon'], |
761 | + }) for attachment in attachments) |
762 | + |
763 | + #add attachment data(count and draft state) into main attachment tree |
764 | + for item in doc_data: |
765 | + if item in attachments_tree: |
766 | + for leaf in doc_data[item]: |
767 | + attachments_tree[item][leaf] = doc_data[item][leaf] |
768 | + else: |
769 | + attachments_tree[item] = doc_data[item] |
770 | + |
771 | + # 3. Update message dictionaries |
772 | + for message_dict in messages: |
773 | + message_id = message_dict.get('id') |
774 | + message = message_tree[message_id] |
775 | + if message.author_id: |
776 | + author = partner_tree[message.author_id.id] |
777 | + else: |
778 | + author = (0, message.email_from) |
779 | + partner_ids = [] |
780 | + if message.subtype_id: |
781 | + partner_ids = [partner_tree[partner.id] for partner in message.notified_partner_ids |
782 | + if partner.id in partner_tree] |
783 | + else: |
784 | + partner_ids = [partner_tree[partner.id] for partner in message.partner_ids |
785 | + if partner.id in partner_tree] |
786 | + attachment_ids = [] |
787 | + for attachment in message.attachment_ids: |
788 | + if attachment.id in attachments_tree: |
789 | + attachment_ids.append(attachments_tree[attachment.id]) |
790 | + message_dict.update({ |
791 | + 'is_author': pid == author[0], |
792 | + 'author_id': author, |
793 | + 'partner_ids': partner_ids, |
794 | + 'attachment_ids': attachment_ids, |
795 | + 'user_pid': pid |
796 | + }) |
797 | + return True |
798 | + |
799 | +class website_sign(osv.Model): |
800 | + _inherit = 'mail.notification' |
801 | + |
802 | + def get_partners_to_email(self, cr, uid, ids, message, context=None): |
803 | + """ Return the list of partners to notify, based on their preferences. |
804 | + |
805 | + :param browse_record message: mail.message to notify |
806 | + :param list partners_to_notify: optional list of partner ids restricting |
807 | + the notifications to process |
808 | + """ |
809 | + notify_pids = [] |
810 | + for notification in self.browse(cr, uid, ids, context=context): |
811 | + if notification.read: |
812 | + continue |
813 | + partner = notification.partner_id |
814 | + # Do not send to partners without email address defined |
815 | + if not partner.email: |
816 | + continue |
817 | + # Do not send to partners having same email address than the author (can cause loops or bounce effect due to messy database) |
818 | + if message.author_id and message.author_id.email == partner.email: |
819 | + if not context.get('notify_author'): |
820 | + continue |
821 | + # Partner does not want to receive any emails or is opt-out |
822 | + if partner.notify_email == 'none': |
823 | + continue |
824 | + notify_pids.append(partner.id) |
825 | + return notify_pids |
826 | + |
827 | + def _notify(self, cr, uid, message_id, partners_to_notify=None, context=None, force_send=False, user_signature=True): |
828 | + if context.get('signers_data'): |
829 | + for ids in context.get('signers_data'): |
830 | + super(website_sign, self)._notify(cr, uid, message_id, partners_to_notify=[int(ids)], context=context, force_send=force_send, user_signature=user_signature) |
831 | + else: |
832 | + super(website_sign, self)._notify(cr, uid, message_id, partners_to_notify=partners_to_notify, context=context, force_send=force_send, user_signature=user_signature) |
833 | + |
834 | + def _notify_email(self, cr, uid, ids, message_id, force_send=False, user_signature=True, context=None): |
835 | + message = self.pool['mail.message'].browse(cr, uid, message_id, context=context) |
836 | + sign_pool = self.pool['ir.attachment.signature'] |
837 | + attachment_pool = self.pool['ir.attachment'] |
838 | + partner_pool = self.pool['res.partner'] |
839 | + |
840 | + # compute partners |
841 | + email_pids = self.get_partners_to_email(cr, uid, ids, message, context=context) |
842 | + if not email_pids: |
843 | + return True |
844 | + |
845 | + # compute epartners_to_notify mail body (signature, company data) |
846 | + if context.get('signers_data'): |
847 | + local_context = context.copy() |
848 | + local_context['email_from_usr'] = re.sub('<.*>','',message.email_from) |
849 | + local_context['email_from'] = message.email_from |
850 | + docs, links = [], [] |
851 | + signers_data = context.get('signers_data') |
852 | + template_id = self.pool['ir.model.data'].get_object_reference(cr, uid, 'website_sign', 'request_sign_template')[1] |
853 | + email_to = partner_pool.search_read(cr, uid, [('id', '=', email_pids[0])], ['email'],context=context)[0] |
854 | + local_context['email_to'] = email_to['email'] |
855 | + for signer_ids in signers_data: |
856 | + if email_pids[0] == int(signer_ids): |
857 | + for signers in signers_data[signer_ids]: |
858 | + docs.append(signers['name']) |
859 | + res_id = attachment_pool.search_read(cr, uid, [('id', '=', signers['id'])], ['res_id'], context=context)[0] |
860 | + link = _("sign/document/%s/%s") % (signers['id'], signers['token']) |
861 | + links.append([link, signers['fname'].split('.')[:-1][0]]) |
862 | + local_context['docnames'] = ", ".join(docs) |
863 | + local_context['msgbody'] = message.body |
864 | + local_context['links'] = links |
865 | + sign_template = self.pool['email.template'].generate_email_batch(cr, uid, template_id, [res_id['res_id']], context=local_context) |
866 | + body_html = sign_template[res_id['res_id']]['body_html'] |
867 | + else: |
868 | + body_html = message.body |
869 | + |
870 | + user_id = message.author_id and message.author_id.user_ids and message.author_id.user_ids[0] and message.author_id.user_ids[0].id or None |
871 | + if user_signature: |
872 | + signature_company = self.get_signature_footer(cr, uid, user_id, res_model=message.model, res_id=message.res_id, context=context) |
873 | + body_html = tools.append_content_to_html(body_html, signature_company, plaintext=False, container_tag='div') |
874 | + |
875 | + # compute email references |
876 | + references = message.parent_id.message_id if message.parent_id else False |
877 | + |
878 | + # create email values |
879 | + mail_values = { |
880 | + 'mail_message_id': message.id, |
881 | + 'auto_delete': True, |
882 | + 'body_html': body_html, |
883 | + 'recipient_ids': [(4, id) for id in email_pids], |
884 | + 'references': references, |
885 | + } |
886 | + email_notif_id = self.pool.get('mail.mail').create(cr, uid, mail_values, context=context) |
887 | + if force_send: |
888 | + self.pool.get('mail.mail').send(cr, uid, [email_notif_id], context=context) |
889 | + return True |
890 | + |
891 | +class ir_attachment(osv.Model): |
892 | + _inherit = 'ir.attachment' |
893 | + _columns = { |
894 | + 'signature_ids': fields.one2many('ir.attachment.signature', 'document_id', 'Signatures') |
895 | + } |
896 | + |
897 | +class ir_attachment_signature(osv.Model): |
898 | + _name = "ir.attachment.signature" |
899 | + _description = "Signature For Attachments" |
900 | + _columns = { |
901 | + 'partner_id' : fields.many2one('res.partner', 'Partner'), |
902 | + 'document_id' : fields.many2one('ir.attachment', 'Attachment', ondelete='cascade'), |
903 | + 'sign': fields.binary('Signature'), |
904 | + 'date': fields.date('Creation Date', help="Date of requesting Signature."), |
905 | + 'signing_date': fields.date('Creation Date', help="Date of signing Attachment ."), |
906 | + 'deadline_date': fields.date('Creation Date', readonly=True, select=True, help="Deadline to sign Attachment."), |
907 | + 'state': fields.selection([ |
908 | + ('draft', 'To be signed'), |
909 | + ('closed', 'Signed'), |
910 | + ('cancelled', 'Cancelled'), |
911 | + ]), |
912 | + 'access_token': fields.char('Security Token', size=256, required=True), |
913 | + 'signer_name': fields.char('Signer Name', size=256), |
914 | + } |
915 | + _defaults = { |
916 | + 'access_token': lambda self, cr, uid, ctx={}: str(uuid.uuid4()) |
917 | + } |
918 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
919 | |
920 | === added directory 'website_sign/security' |
921 | === added file 'website_sign/security/ir.model.access.csv' |
922 | --- website_sign/security/ir.model.access.csv 1970-01-01 00:00:00 +0000 |
923 | +++ website_sign/security/ir.model.access.csv 2014-05-15 14:05:22 +0000 |
924 | @@ -0,0 +1,3 @@ |
925 | +"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" |
926 | +"access_ir_attachment_signature_all","ir_attachment_signature all","model_ir_attachment_signature",,1,0,0,0 |
927 | +"access_ir_attachment_signature_group_user","ir_attachment_signature group_user","model_ir_attachment_signature","base.group_user",1,1,1,1 |
928 | |
929 | === added directory 'website_sign/static' |
930 | === added directory 'website_sign/static/src' |
931 | === added directory 'website_sign/static/src/css' |
932 | === added file 'website_sign/static/src/css/website_sign.css' |
933 | --- website_sign/static/src/css/website_sign.css 1970-01-01 00:00:00 +0000 |
934 | +++ website_sign/static/src/css/website_sign.css 2014-05-15 14:05:22 +0000 |
935 | @@ -0,0 +1,83 @@ |
936 | +.openerp .oe_mail .oe_attachment .oe_sign{ |
937 | + display: none; |
938 | +} |
939 | +.openerp .oe_mail .oe_msg_composer .oe_attachment .oe_sign{ |
940 | + display: block; |
941 | + position: absolute; |
942 | + top: -15px; |
943 | + right: 0px; |
944 | + text-shadow: 1px 0px white, -1px 0px white, 0px 1px white, 0px -1px white; |
945 | + cursor: pointer; |
946 | + opacity: 0; |
947 | + -webkit-transition: opacity 0.2s linear; |
948 | + -moz-transition: opacity 0.2s linear; |
949 | + -o-transition: opacity 0.2s linear; |
950 | + transition: opacity 0.2s linear; |
951 | +} |
952 | +.openerp .oe_mail .oe_msg_composer .oe_attachment:hover .oe_sign{ |
953 | + opacity: 1; |
954 | + -webkit-transition: opacity 0.2s linear; |
955 | + -moz-transition: opacity 0.2s linear; |
956 | + -o-transition: opacity 0.2s linear; |
957 | + transition: opacity 0.2s linear; |
958 | +} |
959 | +.openerp .oe_mail .oe_msg_composer .oe_attachment .oe_delete{ |
960 | + top: -20px !important; |
961 | +} |
962 | + |
963 | +.bs-sidebar { |
964 | + position: fixed; |
965 | + z-index : 1; |
966 | + background-color: #f7f5fa; |
967 | + border-radius: 5px; |
968 | +} |
969 | + |
970 | +.media, .media-body { |
971 | + overflow: hidden; |
972 | + zoom: 1; |
973 | + background-color: #f7f5fa; |
974 | + width: 75%; |
975 | + padding: 5px 5px; |
976 | +} |
977 | + |
978 | +@media (min-width: 992px) { |
979 | + .bs-sidebar { |
980 | + width: 213px; |
981 | + } |
982 | +} |
983 | +@media (min-width: 1200px) { |
984 | + .bs-sidebar { |
985 | + width: 263px; |
986 | + } |
987 | +} |
988 | +@media print { |
989 | + body { |
990 | + padding : 0 !important; |
991 | + } |
992 | +} |
993 | +.oe_lside_panel{ |
994 | + padding: 10px; |
995 | + word-wrap:break-word; |
996 | +} |
997 | + |
998 | +.openerp .oe_email{ |
999 | + color: #777777; |
1000 | +} |
1001 | +.openerp .oe_img{ |
1002 | + width:23px; |
1003 | +} |
1004 | +.openerp .table.oe_sel_followers td{ |
1005 | + border-top: 0; |
1006 | + padding: 3px 3px; |
1007 | +} |
1008 | +.openerp .oe_sign_title{ |
1009 | + padding:10px 15px; |
1010 | +} |
1011 | +.openerp .oe_sign_title span{ |
1012 | + font-weight: bold; |
1013 | + font-size: 20px; |
1014 | + color: #7c7bad; |
1015 | +} |
1016 | +.openerp .oe_sign_comment{ |
1017 | + padding:10px 30px; |
1018 | +} |
1019 | |
1020 | === added directory 'website_sign/static/src/img' |
1021 | === added file 'website_sign/static/src/img/sign.png' |
1022 | Binary files website_sign/static/src/img/sign.png 1970-01-01 00:00:00 +0000 and website_sign/static/src/img/sign.png 2014-05-15 14:05:22 +0000 differ |
1023 | === added directory 'website_sign/static/src/js' |
1024 | === added file 'website_sign/static/src/js/sign.js' |
1025 | --- website_sign/static/src/js/sign.js 1970-01-01 00:00:00 +0000 |
1026 | +++ website_sign/static/src/js/sign.js 2014-05-15 14:05:22 +0000 |
1027 | @@ -0,0 +1,200 @@ |
1028 | +$(document).ready(function () { |
1029 | + var empty_sign = false; |
1030 | + $('#modesign').on('shown.bs.modal', function (e) { |
1031 | + $("#sign").empty().jSignature({'decor-color' : '#D1D0CE'}); |
1032 | + empty_sign = $("#sign").jSignature("getData",'image'); |
1033 | + }); |
1034 | + |
1035 | + $('#sign_clean').on('click', function (e) { |
1036 | + $("#sign").jSignature('reset'); |
1037 | + }); |
1038 | + |
1039 | + |
1040 | + $('form.js_sign_json').submit(function(ev){ |
1041 | + ev.preventDefault(); |
1042 | + var $link = $(ev.currentTarget); |
1043 | + var href = $link.attr("action"); |
1044 | + var attach_id = href.match(/signed\/([0-9]+)/); |
1045 | + var token = href.match(/token=(.*)/); |
1046 | + if (token) |
1047 | + token = token[1]; |
1048 | + var signer_name = $("#signer_name").val(); |
1049 | + var sign = $("#sign").jSignature("getData",'image'); |
1050 | + var is_empty = sign?empty_sign[1]==sign[1]:false; |
1051 | + $('#signer').toggleClass('has-error', ! signer_name); |
1052 | + $('#drawsign').toggleClass('panel-danger', is_empty).toggleClass('panel-default', ! is_empty); |
1053 | + |
1054 | + if (is_empty || ! signer_name) |
1055 | + return false; |
1056 | + $('#signed_req').prop('disabled',true); |
1057 | + |
1058 | + openerp.jsonRpc("/website_sign/signed", 'call', { |
1059 | + 'res_id': parseInt(attach_id[1]), |
1060 | + 'token': token, |
1061 | + 'sign': sign?JSON.stringify(sign[1]):false, |
1062 | + 'signer': signer_name |
1063 | + }).then(function (data) { |
1064 | + $('#modesign').modal('hide'); |
1065 | + window.location.href = '/sign/document/'+attach_id[1]+'/'+token+'?message=2'; |
1066 | + }); |
1067 | + return false |
1068 | + }); |
1069 | +}); |
1070 | +openerp.website_sign = function (session) { |
1071 | +var QWeb = session.web.qweb, |
1072 | + _t = session.web._t; |
1073 | + |
1074 | +session.web.SignRequest = session.web.Widget.extend({ |
1075 | + init: function (parent, attachment_id, res_id, model) { |
1076 | + this._super(parent); |
1077 | + this.attach_id = attachment_id; |
1078 | + this.res_id = res_id; |
1079 | + this.model = model; |
1080 | + }, |
1081 | + get_followers: function () { |
1082 | + var self = this; |
1083 | + $('div.oe_edit_partner_list').remove(); |
1084 | + openerp.jsonRpc("/website_sign/get_followers", 'call', { |
1085 | + 'thread_id': parseInt(self.res_id), |
1086 | + 'attachment_id': parseInt(self.attach_id), |
1087 | + 'model': self.model, |
1088 | + }).then(function (data) { |
1089 | + if (data.signer_data.length === 0) { |
1090 | + var dialog = new session.web.Dialog(this, { |
1091 | + size: 'small', |
1092 | + title: _t("Warning"), |
1093 | + buttons:[{ |
1094 | + text: _t("Ok"), |
1095 | + click: function() { |
1096 | + this.parents('.modal').modal('hide'); |
1097 | + } |
1098 | + }], |
1099 | + }, $("<div />").text(_t("This document doesn't have any followers, please add them."))).open(); |
1100 | + return false; |
1101 | + } |
1102 | + self.$dialog = new session.web.Dialog(this, { |
1103 | + size: 'medium', |
1104 | + title: _t('Request Signature From'), |
1105 | + }, $('<div class="oe_edit_partner_list">' + QWeb.render('select.people', {"result": data, "attach_id": self.attach_id}))).open(); |
1106 | + self.$dialog.$buttons.find('.oe_dialog_custom_buttons').empty(); |
1107 | + self.$dialog.$buttons.find('.oe_dialog_custom_buttons').append('<button class="oe_button oe_form_button oe_highlight" type="button" id="request">Request Signature</button><span> or </span> <button class="oe_button oe_form_button oe_link" type="button" id="cancel_request"><span>Cancel</span></button>'); |
1108 | + $('#request').click(function(event) { |
1109 | + self.request_followers(); |
1110 | + }); |
1111 | + $('#cancel_request').click(function(event) { |
1112 | + self.$dialog.$el.parents('.modal').modal('hide'); |
1113 | + }); |
1114 | + return false |
1115 | + }); |
1116 | + }, |
1117 | + request_followers: function () { |
1118 | + var self = this; |
1119 | + var attachment_id = this.$dialog.$el.find("#attach_id").val(); |
1120 | + var title = this.$dialog.$el.find("#title").val(); |
1121 | + var comments = this.$dialog.$el.find("#comments").val() || false; |
1122 | + var sign_ids = []; |
1123 | + var oe_action = $('div.oe_edit_partner_list input[type="checkbox"]'); |
1124 | + _(oe_action).each(function (record) { |
1125 | + if ($(record).is(':checked')) { |
1126 | + sign_ids.push(parseInt($(record).data('id'))); |
1127 | + } |
1128 | + }); |
1129 | + $('#doc_title').toggleClass('has-error', !title); |
1130 | + if (!title) { |
1131 | + return false; |
1132 | + }; |
1133 | + openerp.jsonRpc("/website_sign/set_signer", 'call', { |
1134 | + 'attachment_id': parseInt(attachment_id), |
1135 | + 'signer_id': sign_ids, |
1136 | + 'title': title, |
1137 | + 'comments': comments, |
1138 | + }).then(function () { |
1139 | + self.$dialog.$el.parents('.modal').modal('hide'); |
1140 | + }); |
1141 | + return false |
1142 | + }, |
1143 | +}); |
1144 | + |
1145 | +session.mail.ThreadComposeMessage.include({ |
1146 | + on_attachment_loaded: function (event, result) { |
1147 | + var self = this; |
1148 | + if (result.erorr || !result.id ) { |
1149 | + this.do_warn( session.web.qweb.render('mail.error_upload'), result.error); |
1150 | + this.attachment_ids = _.filter(this.attachment_ids, function (val) { return !val.upload; }); |
1151 | + } else { |
1152 | + for (var i in this.attachment_ids) { |
1153 | + if (this.attachment_ids[i].filename == result.filename && this.attachment_ids[i].upload) { |
1154 | + this.attachment_ids[i]={ |
1155 | + 'id': result.id, |
1156 | + 'name': result.name, |
1157 | + 'filename': result.filename, |
1158 | + 'url':session.mail.ChatterUtils.get_attachment_url(this.session, this.id, result.id) |
1159 | + }; |
1160 | + } |
1161 | + } |
1162 | + } |
1163 | + this.display_attachments(); |
1164 | + if (!self.is_log){ |
1165 | + attach_ids = _.map(this.attachment_ids, function (file) {return file.id;}); |
1166 | + for (var id in attach_ids) { |
1167 | + self.$el.find("[data-id='" + attach_ids[id] + "']").after(_.str.sprintf("<div id='request_sign' title='Request Signature'><img id='%s' src='/website_sign/static/src/img/sign.png' style='margin-top:32px; margin-left:-17px; height:20px; width:20px'/></div>", attach_ids[id])); |
1168 | + } |
1169 | + this.$('div #request_sign').addClass('oe_sign'); |
1170 | + $('div#request_sign img').on('click', function (ev) { |
1171 | + var attach_id = ev.currentTarget.id; |
1172 | + var res_id = self.res_id; |
1173 | + var model = self.model; |
1174 | + var followers = new session.web.SignRequest(self, attach_id, res_id, model); |
1175 | + followers.get_followers(); |
1176 | + }); |
1177 | + } |
1178 | + var $input = this.$('input.oe_form_binary_file'); |
1179 | + $input.after($input.clone(true)).remove(); |
1180 | + this.$(".oe_attachment_file").show(); |
1181 | + }, |
1182 | + do_send_message_post: function (partner_ids, log) { |
1183 | + var self = this; |
1184 | + var attach_ids = _.map(this.attachment_ids, function (file) {return file.id;}) |
1185 | + var parent = this._super; |
1186 | + var args = arguments; |
1187 | + openerp.jsonRpc("/website_sign/get_signer", 'call', { |
1188 | + 'attachment_ids': attach_ids, |
1189 | + }).then(function (res) { |
1190 | + var values = { |
1191 | + 'context': _.extend(self.parent_thread.context, { |
1192 | + 'signers_data': res, |
1193 | + }), |
1194 | + }; |
1195 | + return parent.apply(self, args); |
1196 | + }); |
1197 | + }, |
1198 | +}); |
1199 | +session.web.form.FieldMany2ManyBinaryMultiFiles.include({ |
1200 | + render_value: function () { |
1201 | + var self = this; |
1202 | + this.read_name_values().then(function (ids) { |
1203 | + var render = $(session.web.qweb.render('FieldBinaryFileUploader.files', {'widget': self, 'values': ids})); |
1204 | + render.on('click', '.oe_delete', _.bind(self.on_file_delete, self)); |
1205 | + self.$('.oe_placeholder_files, .oe_attachments').replaceWith( render ); |
1206 | + if (!self.field_manager.datarecord.is_log) { |
1207 | + for (var id in ids) { |
1208 | + self.$el.find("[data-id='" + ids[id] + "']").after(_.str.sprintf("<div id='request_sign' title='Request Signature'><img id='%s' src='/website_sign/static/src/img/sign.png' style='margin-top:35px; margin-left:32px; height:20px; width:20px'/></div>", ids[id])); |
1209 | + } |
1210 | + $('div#request_sign img').on('click', function (ev) { |
1211 | + var attach_id = ev.currentTarget.id |
1212 | + var res_id = self.field_manager.datarecord.res_id; |
1213 | + var model = self.field_manager.datarecord.model; |
1214 | + var followers = new session.web.SignRequest(self, attach_id, res_id, model); |
1215 | + followers.get_followers(); |
1216 | + }); |
1217 | + } |
1218 | + |
1219 | + // reinit input type file |
1220 | + var $input = self.$('input.oe_form_binary_file'); |
1221 | + $input.after($input.clone(true)).remove(); |
1222 | + self.$(".oe_fileupload").show(); |
1223 | + |
1224 | + }); |
1225 | + }, |
1226 | +}); |
1227 | +}; |
1228 | \ No newline at end of file |
1229 | |
1230 | === added directory 'website_sign/static/src/xml' |
1231 | === added file 'website_sign/static/src/xml/sign.xml' |
1232 | --- website_sign/static/src/xml/sign.xml 1970-01-01 00:00:00 +0000 |
1233 | +++ website_sign/static/src/xml/sign.xml 2014-05-15 14:05:22 +0000 |
1234 | @@ -0,0 +1,58 @@ |
1235 | +<?xml version="1.0" encoding="UTF-8"?> |
1236 | +<template> |
1237 | + <t t-name="select.people"> |
1238 | + <input type="hidden" t-att-value="attach_id" id="attach_id"/> |
1239 | + <div class="row"> |
1240 | + <div class="col-md-12 oe_sign_title"> |
1241 | + <span>1. Who needs to sign ?</span> |
1242 | + </div> |
1243 | + </div> |
1244 | + <div class="table-responsive col-md-12"> |
1245 | + <table class="table table-hover oe_sel_followers"> |
1246 | + <t t-foreach='result.signer_data' t-as='res'> |
1247 | + <tr> |
1248 | + <td> |
1249 | + <t t-if="res.selected"> |
1250 | + <input type="checkbox" t-att-checked="res.selected" t-att-id="'input_mail_followers_'+res.followers_id" t-att-data-id="res.followers_id" t-att-name="res.name"/> |
1251 | + </t> |
1252 | + <t t-if="!res.selected"> |
1253 | + <input type="checkbox" t-att-id="'input_mail_followers_'+res.followers_id" t-att-data-id="res.followers_id" t-att-name="res.name"/> |
1254 | + </t> |
1255 | + </td> |
1256 | + <td> |
1257 | + <label t-att-for="'input_mail_followers_'+res.followers_id"><t t-raw="res.name"/></label> |
1258 | + </td> |
1259 | + <td class="oe_email"> |
1260 | + <label t-att-for="'input_mail_followers_'+res.followers_id"><t t-raw="res.email"/></label> |
1261 | + </td> |
1262 | + <td> |
1263 | + <img class="oe_img" t-att-src="'/website/image?model=res.partner&field=image_small&id='+res.followers_id"></img> |
1264 | + </td> |
1265 | + </tr> |
1266 | + </t> |
1267 | + </table> |
1268 | + </div> |
1269 | + <div class="row"> |
1270 | + <div class="col-md-12 oe_sign_title"> |
1271 | + <span>2. Add document title and comments.</span> |
1272 | + </div> |
1273 | + </div> |
1274 | + <div class="row"> |
1275 | + <div id="doc_title" class="col-md-12 oe_sign_comment"> |
1276 | + <input id="title" type="text" class="form-control" placeholder="Title" t-att-value="result.doc_data[0].name"/> |
1277 | + </div> |
1278 | + </div> |
1279 | + <div class="row"> |
1280 | + <div class="col-md-12 oe_sign_comment"> |
1281 | + <textarea id="comments" rows="3" class="form-control" placeholder="Comments"><t t-raw="result.doc_data[0].description ? result.doc_data[0].description:'' "/></textarea> |
1282 | + </div> |
1283 | + </div> |
1284 | + </t> |
1285 | + <t t-extend="mail.thread.message.attachments"> |
1286 | + <t t-jquery="div#attachments" t-operation="append"> |
1287 | + <div style="text-align:center;" t-if="attachment.count"> |
1288 | + <a t-att-href="'/sign/document/'+attachment.id" target="_blank"> <b>Signed(<t t-raw="attachment.signed+'/'+attachment.count"/>)</b> </a> |
1289 | + </div> |
1290 | + </t> |
1291 | + </t> |
1292 | +</template> |
1293 | |
1294 | === added directory 'website_sign/views' |
1295 | === added file 'website_sign/views/website_sign.xml' |
1296 | --- website_sign/views/website_sign.xml 1970-01-01 00:00:00 +0000 |
1297 | +++ website_sign/views/website_sign.xml 2014-05-15 14:05:22 +0000 |
1298 | @@ -0,0 +1,151 @@ |
1299 | +<?xml version="1.0" encoding="utf-8"?> |
1300 | +<openerp> |
1301 | +<data> |
1302 | + <template id="assets_backend" name="website_sign assets" inherit_id="web.assets_backend"> |
1303 | + <xpath expr="." position="inside"> |
1304 | + <link rel="stylesheet" href="/website_sign/static/src/css/website_sign.css"/> |
1305 | + <script type="text/javascript" src="/website_sign/static/src/js/sign.js"></script> |
1306 | + </xpath> |
1307 | + </template> |
1308 | + <template id="website_sign.doc_sign" name="Document Sign"> |
1309 | + <t t-call="website.layout"> |
1310 | + <t t-set="head"> |
1311 | + <script type="text/javascript" src="/website_sign/static/src/js/sign.js"></script> |
1312 | + <script type="text/javascript" src="/website/static/lib/jSignature/jSignature.min.js"></script> |
1313 | + <link rel='stylesheet' href='/website_sign/static/src/css/website_sign.css'/> |
1314 | + <t t-raw="head or ''"/> |
1315 | + </t> |
1316 | + <body data-spy="scroll" data-target=".navspy"> |
1317 | + <div class="container"> |
1318 | + <div class="row mt16"> |
1319 | + <div class="col-md-3"> |
1320 | + <div class="bs-sidebar"> |
1321 | + <div class="text-left hidden-print oe_lside_panel"> |
1322 | + <t t-if="current_sign and current_sign.state == 'draft' "> |
1323 | + <a class="btn btn-primary btn-block fa fa-check" data-toggle="modal" data-target="#modesign"> |
1324 | + Sign Document |
1325 | + </a> |
1326 | + </t> |
1327 | + <t t-if="current_sign and current_sign.state != 'draft'"> |
1328 | + <h4 class="modal-title">You have Signed the document.</h4> |
1329 | + </t> |
1330 | + </div> |
1331 | + <div class="oe_lside_panel"><h4><t t-raw="attachment.name"/></h4></div> |
1332 | + <div class="oe_lside_panel" t-if="attachment.description"> <t t-raw="attachment.description"/> </div> |
1333 | + </div> |
1334 | + </div> |
1335 | + <div class="col-md-9"> |
1336 | + <div t-if="message==1" class="alert alert-success alert-dismissable"> |
1337 | + <button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button> |
1338 | + Your message has been successfully sent! |
1339 | + </div> |
1340 | + <div t-if="message==2" class="alert alert-success alert-dismissable"> |
1341 | + <button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button> |
1342 | + You have successfully signed the document. |
1343 | + </div> |
1344 | + <div id="main_panel" class="row mb32" style="margin-left:0"> |
1345 | + <div class="col-md-8"> |
1346 | + <t t-foreach="record.message_ids" t-as="message"> |
1347 | + <t t-foreach='message.attachment_ids' t-as='attachment'> |
1348 | + <div class="row" t-if="attachment.id == attachment_id"> |
1349 | + <a t-att-href="'/mail/download_attachment?model=mail.message&id='+str(message.id)+'&method=download_attachment&attachment_id='+str(attachment_id)" target="_blank"> |
1350 | + <t t-if="attachment.file_type_icon == 'webimage'"> |
1351 | + <img class="media-object pull-left" t-att-src="'/web/binary/image?model=ir.attachment&field=datas&id=' + str(attachment_id) + '&resize=300,180'" style="width: 400px;"/> |
1352 | + </t> |
1353 | + <t t-if="attachment.file_type_icon != 'webimage'"> |
1354 | + <img class="media-object pull-left" t-att-src="'/mail/static/src/img/mimetypes/' + attachment.file_type_icon + '.png'" style="width: 400px;"></img> |
1355 | + </t> |
1356 | + </a> |
1357 | + </div> |
1358 | + </t> |
1359 | + </t> |
1360 | + <t t-if="signatures"> |
1361 | + <t t-foreach="signatures" t-as="sign"> |
1362 | + <div class="row" t-if="sign.state == 'closed'"> |
1363 | + <img class="media-object pull-left" t-att-src="'/web/binary/image?model=ir.attachment.signature&field=sign&id=' + str(sign.id) + '&resize=500,180'" style="width: 150px;"/> |
1364 | + <div style="line-height:65px; font-weight:bold;"> |
1365 | + by <t t-raw="sign.signer_name"/> on <t t-raw="sign.signing_date"/>. |
1366 | + </div> |
1367 | + </div> |
1368 | + </t> |
1369 | + </t> |
1370 | + </div> |
1371 | + <div class="col-md-4" id="right_panel"> </div> |
1372 | + </div> |
1373 | + <div class="modal fade" id="modesign" role="dialog" aria-hidden="true"> |
1374 | + <div class="modal-dialog"> |
1375 | + <form id="sign_doc" method="post" t-attf-action="/website_sign/signed/#{attachment_id}/?token=#{token}" class="js_sign_json modal-content"> |
1376 | + <div class="modal-header"> |
1377 | + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button> |
1378 | + <h4 class="modal-title">Sign Document</h4> |
1379 | + </div> |
1380 | + <div class="modal-body" id="sign-modal-dialog"> |
1381 | + <p> |
1382 | + I agree, by signing this document. |
1383 | + </p> |
1384 | + <div id="signer" class="form-group" t-if="current_sign"> |
1385 | + <label class="control-label" for="name">Your Name:</label> |
1386 | + <input class="form-control" name="signer" id="signer_name" t-att-value="current_sign.partner_id.name" type="text"/> |
1387 | + <div class="panel panel-default mt16 mb0" id="drawsign"> |
1388 | + <div class="panel-heading"> |
1389 | + <div class="pull-right"> |
1390 | + <a id="sign_clean" class="btn btn-xs">Clear</a> |
1391 | + </div> |
1392 | + <strong>Draw your signature</strong> |
1393 | + </div> |
1394 | + <div id="sign" class="panel-body" style="padding: 0"/> |
1395 | + </div> |
1396 | + </div> |
1397 | + </div> |
1398 | + <div class="modal-footer"> |
1399 | + <button type="submit" id="signed_req" t-attf-class="btn btn-primary">Sign Document</button> or |
1400 | + <button type="button" class="btn btn-link" data-dismiss="modal" style="padding: 0">Cancel</button> |
1401 | + </div> |
1402 | + </form> |
1403 | + </div> |
1404 | + </div> |
1405 | + </div> |
1406 | + </div> |
1407 | + </div> |
1408 | + </body> |
1409 | + </t> |
1410 | + </template> |
1411 | + |
1412 | + <template id="opt_website_sign_right_panel" name="Requested Sign" inherit_option_id="website_sign.doc_sign" inherit_id="website_sign.doc_sign"> |
1413 | + <xpath expr="//div[@id='right_panel']" position="inside"> |
1414 | + <div class="panel panel-default"> |
1415 | + <div class="panel-heading"> |
1416 | + <h4> |
1417 | + <t t-if="not sign_req"> |
1418 | + Signed(<t t-raw="str(len(signatures)) +'/'+ str(len(signatures))"/>) |
1419 | + </t> |
1420 | + <t t-if="len(sign_req) and (len(sign_req) == len(signatures) or len(sign_req) != len(signatures))"> |
1421 | + Waiting Signatures(<t t-raw="str(len(sign_req)) +'/'+ str(len(signatures))"/>) |
1422 | + </t> |
1423 | + </h4> |
1424 | + </div> |
1425 | + <div class="panel-body"> |
1426 | + <t t-foreach="signatures" t-as="sign"> |
1427 | + <div t-if="sign.state == 'draft'"><b><t t-raw="sign.partner_id.name"/></b> is requested to sign.</div> |
1428 | + <div t-if="sign.state == 'closed'"><b><t t-raw="sign.partner_id.name"/></b> has signed the Document.</div> |
1429 | + </t> |
1430 | + </div> |
1431 | + </div> |
1432 | + </xpath> |
1433 | + </template> |
1434 | + |
1435 | + <template id="opt_website_sign_chatter_comment" name="Allow Comments" inherit_option_id="website_sign.doc_sign" inherit_id="website_sign.doc_sign"> |
1436 | + <xpath expr="//div[@id='main_panel']" position="after"> |
1437 | + <section class="mt32 mb32 css_editable_mode_hidden hidden-print"> |
1438 | + <form id="comment" t-attf-action="/sign/document/#{attachment_id}/#{token}/note" method="POST"> |
1439 | + <div class="pull-left mb32 mt32" style="width: 75%"> |
1440 | + <textarea rows="4" name="comment" class="form-control" placeholder="Send us a note..."></textarea> |
1441 | + <button type="submit" class="btn btn-primary mt8">Send</button> |
1442 | + </div> |
1443 | + </form> |
1444 | + </section> |
1445 | + <div class="clearfix"/> |
1446 | + </xpath> |
1447 | + </template> |
1448 | +</data> |
1449 | +</openerp> |