33fcdd271f08f9b1c41bb98a72798b68615e80a6
[tine20] / tine20 / Timetracker / js / TimesheetEditDialog.js
1 /**
2  * Tine 2.0
3  * 
4  * @package     Timetracker
5  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
6  * @author      Philipp Schüle <p.schuele@metaways.de>
7  * @copyright   Copyright (c) 2007-2011 Metaways Infosystems GmbH (http://www.metaways.de)
8  *
9  */
10  
11 Ext.namespace('Tine.Timetracker');
12
13 /**
14  * Timetracker Edit Dialog
15  */
16 Tine.Timetracker.TimesheetEditDialog = Ext.extend(Tine.widgets.dialog.EditDialog, {
17
18     /**
19      * @private
20      */
21     windowNamePrefix: 'TimesheetEditWindow_',
22     appName: 'Timetracker',
23     recordClass: Tine.Timetracker.Model.Timesheet,
24     recordProxy: Tine.Timetracker.timesheetBackend,
25     tbarItems: null,
26     evalGrants: false,
27     useInvoice: false,
28     displayNotes: true,
29     
30     /**
31      * overwrite update toolbars function (we don't have record grants yet)
32      */
33     updateToolbars: function(record) {
34         this.onTimeaccountUpdate();
35         Tine.Timetracker.TimesheetEditDialog.superclass.updateToolbars.call(this, record, 'timeaccount_id');
36     },
37     
38     /**
39      * this gets called when initializing and if a new timeaccount is chosen
40      * 
41      * @param {} field
42      * @param {} timeaccount
43      */
44     onTimeaccountUpdate: function(field, timeaccount) {
45         // check for manage_timeaccounts right
46         var manageRight = Tine.Tinebase.common.hasRight('manage', 'Timetracker', 'timeaccounts');
47         
48         var notBillable = false;
49         var notClearable = false;
50
51         var grants = timeaccount ? timeaccount.get('account_grants') : (this.record.get('timeaccount_id') ? this.record.get('timeaccount_id').account_grants : {});
52         
53         if (grants) {
54             var setDisabled = ! (grants.bookAllGrant || grants.adminGrant || manageRight);
55             var accountField = this.getForm().findField('account_id');
56             accountField.setDisabled(setDisabled);
57             // set account id to the current user, if he doesn't have the right to edit other users timesheets
58             if (setDisabled) {
59                 if (this.copyRecord && (this.record.get('account_id') != Tine.Tinebase.registry.get('currentAccount').accountId)) {
60                     accountField.setValue(Tine.Tinebase.registry.get('currentAccount'));
61                 }
62             }
63             notBillable = ! (grants.manageBillableGrant || grants.adminGrant || manageRight);
64             notClearable = ! (grants.adminGrant || manageRight);
65             this.getForm().findField('billed_in').setDisabled(! (grants.adminGrant || manageRight));
66         }
67
68         if (timeaccount) {
69             notBillable = notBillable || timeaccount.data.is_billable == "0" || this.record.get('timeaccount_id').is_billable == "0";
70             
71             // clearable depends on timeaccount is_billable as well (changed by ps / 2009-09-01, behaviour was inconsistent)
72             notClearable = notClearable || timeaccount.data.is_billable == "0" || this.record.get('timeaccount_id').is_billable == "0";
73         }
74         
75         this.getForm().findField('is_billable').setDisabled(notBillable);
76         this.getForm().findField('is_cleared').setDisabled(notClearable);
77         
78         if (this.record.id == 0 && timeaccount) {
79             // set is_billable for new records according to the timeaccount setting
80             this.getForm().findField('is_billable').setValue(timeaccount.data.is_billable);
81         }
82     },
83
84     /**
85      * this gets called when initializing and if cleared checkbox is changed
86      *
87      * @param {} field
88      * @param {} newValue
89      *
90      * @todo    add prompt later?
91      */
92     onClearedUpdate: function(field, checked) {
93         if (!this.useMultiple) {
94             this.getForm().findField('billed_in').setDisabled(! checked);
95         }
96     },
97
98     initComponent: function() {
99         var salesApp = Tine.Tinebase.appMgr.get('Sales');
100         this.useInvoice = Tine.Tinebase.appMgr.get('Sales')
101             && salesApp.featureEnabled('invoicesModule')
102             && Tine.Tinebase.common.hasRight('manage', 'Sales', 'invoices')
103             && Tine.Sales.Model.Invoice;
104         
105         Tine.Timetracker.TimesheetEditDialog.superclass.initComponent.apply(this, arguments);
106     },
107
108     /**
109      * overwrites the isValid method on multipleEdit
110      */
111     isMultipleValid: function() {
112         var valid = true;
113         var keys = ['timeaccount_id', 'description', 'account_id'];
114         Ext.each(keys, function(key) {
115             var field = this.getForm().findField(key);
116             if(field.edited && ! field.validate()) {
117                 field.markInvalid();
118                 valid = false;
119             }
120         }, this);
121         return valid;
122     },
123
124     /**
125      * returns dialog
126      * 
127      * NOTE: when this method gets called, all initialization is done.
128      */
129     getFormItems: function() {
130         var lastRow = [new Tine.Addressbook.SearchCombo({
131             allowBlank: false,
132             forceSelection: true,
133             columnWidth: 1,
134             disabled: true,
135             useAccountRecord: true,
136             userOnly: true,
137             nameField: 'n_fileas',
138             fieldLabel: this.app.i18n._('Account'),
139             name: 'account_id'
140         }), {
141             columnWidth: .25,
142             disabled: (this.useMultiple) ? false : true,
143             boxLabel: this.app.i18n._('Billable'),
144             name: 'is_billable',
145             xtype: 'checkbox'
146         }, {
147             columnWidth: .25,
148             disabled: (this.useMultiple) ? false : true,
149             boxLabel: this.app.i18n._('Cleared'),
150             name: 'is_cleared',
151             xtype: 'checkbox',
152             listeners: {
153                 scope: this,
154                 check: this.onClearedUpdate
155             }
156         }, {
157                 columnWidth: .5,
158                 disabled: true,
159                 fieldLabel: this.app.i18n._('Cleared In'),
160                 name: 'billed_in'
161             }];
162         
163         if (this.useInvoice) {
164             lastRow.push(Tine.widgets.form.RecordPickerManager.get('Sales', 'Invoice', {
165                 columnWidth: .5,
166                 disabled: true,
167                 fieldLabel: this.app.i18n._('Invoice'),
168                 name: 'invoice_id'
169             }));
170         }
171         
172         
173         return {
174             xtype: 'tabpanel',
175             border: false,
176             plain:true,
177             activeTab: 0,
178             plugins: [{
179                 ptype : 'ux.tabpanelkeyplugin'
180             }],
181             defaults: {
182                 hideMode: 'offsets'
183             },
184             items:[
185                 {
186                 title: this.app.i18n.ngettext('Timesheet', 'Timesheets', 1),
187                 autoScroll: true,
188                 border: false,
189                 frame: true,
190                 layout: 'border',
191                 items: [{
192                     region: 'center',
193                     xtype: 'columnform',
194                     labelAlign: 'top',
195                     formDefaults: {
196                         xtype:'textfield',
197                         anchor: '100%',
198                         labelSeparator: '',
199                         columnWidth: .333
200                     },
201                     items: [[Tine.widgets.form.RecordPickerManager.get('Timetracker', 'Timeaccount', {
202                         columnWidth: 1,
203                         fieldLabel: this.app.i18n.ngettext('Time Account', 'Time Accounts', 1),
204                         emptyText: this.app.i18n._('Select Time Account...'),
205                         allowBlank: false,
206                         forceSelection: true,
207                         name: 'timeaccount_id',
208                         lazyInit: false,
209                         listeners: {
210                             scope: this,
211                             render: function(field){
212                                 if(!this.useMultiple) {
213                                     field.focus(false, 250);
214                                 }
215                             },
216                             select: this.onTimeaccountUpdate
217                         }
218                     })], [{
219                         fieldLabel: this.app.i18n._('Duration'),
220                         name: 'duration',
221                         allowBlank: false,
222                         xtype: 'tinedurationspinner'
223                         }, {
224                         fieldLabel: this.app.i18n._('Date'),
225                         name: 'start_date',
226                         allowBlank: false,
227                         xtype: 'datefield'
228                         }, {
229                         fieldLabel: this.app.i18n._('Start'),
230                         emptyText: this.app.i18n._('not set'),
231                         name: 'start_time',
232                         xtype: 'timefield'
233                     }], [{
234                         columnWidth: 1,
235                         fieldLabel: this.app.i18n._('Description'),
236                         emptyText: this.app.i18n._('Enter description...'),
237                         name: 'description',
238                         allowBlank: false,
239                         xtype: 'textarea',
240                         height: 150
241                     }], lastRow] 
242                 }, {
243                     // activities and tags
244                     layout: 'accordion',
245                     animate: true,
246                     region: 'east',
247                     width: 210,
248                     split: true,
249                     collapsible: true,
250                     collapseMode: 'mini',
251                     header: false,
252                     margins: '0 5 0 5',
253                     border: true,
254                     items: [
255                         new Tine.widgets.tags.TagPanel({
256                             app: 'Timetracker',
257                             border: false,
258                             bodyStyle: 'border:1px solid #B5B8C8;'
259                         })
260                     ]
261                 }]
262             }, new Tine.widgets.activities.ActivitiesTabPanel({
263                 app: this.appName,
264                 record_id: (! this.copyRecord) ? this.record.id : null,
265                 record_model: this.appName + '_Model_' + this.recordClass.getMeta('modelName')
266             })]
267         };
268     },
269     
270     /**
271      * show error if request fails
272      * 
273      * @param {} response
274      * @param {} request
275      * @private
276      */
277     onRequestFailed: function(response, request) {
278         this.saving = false;
279         
280         if (response.code && response.code == 902) {
281             // deadline exception
282             Ext.MessageBox.alert(
283                 this.app.i18n._('Failed'), 
284                 String.format(this.app.i18n._('Could not save {0}.'), this.i18nRecordName) 
285                     + ' ( ' + this.app.i18n._('Booking deadline for this Timeaccount has been exceeded.') /* + ' ' + response.message  */ + ')'
286             );
287         } else {
288             // call default exception handler
289             Tine.Tinebase.ExceptionHandler.handleRequestException(response);
290         }
291         this.loadMask.hide();
292     }
293 });
294
295 /**
296  * Timetracker Edit Popup
297  */
298 Tine.Timetracker.TimesheetEditDialog.openWindow = function (config) {
299     var id = (config.record && config.record.id) ? config.record.id : 0;
300     var window = Tine.WindowFactory.getWindow({
301         width: 800,
302         height: 500,
303         name: Tine.Timetracker.TimesheetEditDialog.prototype.windowNamePrefix + id,
304         contentPanelConstructor: 'Tine.Timetracker.TimesheetEditDialog',
305         contentPanelConstructorConfig: config
306     });
307     return window;
308 };