0009768: Use ModelConfig for Timetracker models
[tine20] / tine20 / Timetracker / js / TimeaccountEditDialog.js
1 /**
2  * Tine 2.0
3  * 
4  * @package     Timetracker
5  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
6  * @author      Cornelius Weiss <c.weiss@metaways.de>
7  * @copyright   Copyright (c) 2007-2016 Metaways Infosystems GmbH (http://www.metaways.de)
8  *
9  */
10  
11 Ext.namespace('Tine.Timetracker');
12
13 Tine.Timetracker.TimeaccountEditDialog = Ext.extend(Tine.widgets.dialog.EditDialog, {
14     
15     /**
16      * @private
17      */
18     windowNamePrefix: 'TimeaccountEditWindow_',
19     appName: 'Timetracker',
20     recordClass: Tine.Timetracker.Model.Timeaccount,
21     recordProxy: Tine.Timetracker.timeaccountBackend,
22     useInvoice: false,
23     displayNotes: true,
24
25     windowWidth: 800,
26     windowHeight: 500,
27     
28     /**
29      * overwrite update toolbars function (we don't have record grants yet)
30      */
31     updateToolbars: function() {
32     },
33     
34     initComponent: function() {
35         var salesApp = Tine.Tinebase.appMgr.get('Sales');
36         this.useInvoice = salesApp
37             && salesApp.featureEnabled('invoicesModule')
38             && Tine.Tinebase.common.hasRight('manage', 'Sales', 'invoices')
39             && Tine.Sales.Model.Invoice;
40         Tine.Timetracker.TimeaccountEditDialog.superclass.initComponent.call(this);
41     },
42
43     isMultipleValid: function() {
44         return true;
45     },
46
47     /**
48      * containerProperty (all contracts in one container) exists, so overwrite creating selector here
49      */
50     initContainerSelector: Ext.emptyFn,
51     
52     onRecordLoad: function() {
53         // make sure grants grid is initialized
54         this.getGrantsGrid();
55         
56         var grants = this.record.get('grants') || [];
57         this.grantsStore.loadData({results: grants});
58         Tine.Timetracker.TimeaccountEditDialog.superclass.onRecordLoad.call(this);
59         
60         if (! this.copyRecord && ! this.record.id) {
61             this.window.setTitle(this.app.i18n._('Add New Timeaccount'));
62         }
63     },
64     
65     onRecordUpdate: function() {
66         Tine.Timetracker.TimeaccountEditDialog.superclass.onRecordUpdate.call(this);
67         this.record.set('grants', '');
68         
69         var grants = [];
70         this.grantsStore.each(function(_record){
71             grants.push(_record.data);
72         });
73         
74         this.record.set('grants', grants);
75     },
76     
77     /**
78      * returns dialog
79      * 
80      * NOTE: when this method gets called, all initalisation is done.
81      */
82     getFormItems: function() {
83         
84         var secondRow = [{
85             fieldLabel: this.app.i18n._('Unit'),
86             name: 'price_unit'
87         }, {
88             xtype: 'numberfield',
89             fieldLabel: this.app.i18n._('Unit Price'),
90             name: 'price',
91             allowNegative: false
92         }, {
93             xtype: 'numberfield',
94             fieldLabel: this.app.i18n._('Budget'),
95             name: 'budget',
96             allowNegative: false,
97             value: 0
98         }, {
99             fieldLabel: this.app.i18n._('Status'),
100             name: 'is_open',
101             xtype: 'combo',
102             mode: 'local',
103             forceSelection: true,
104             triggerAction: 'all',
105             store: [[0, this.app.i18n._('closed')], [1, this.app.i18n._('open')]]
106         }, {
107             fieldLabel: this.app.i18n._('Billed'),
108             name: 'status',
109             xtype: 'combo',
110             mode: 'local',
111             forceSelection: true,
112             triggerAction: 'all',
113             value: 'not yet billed',
114             store: [
115                 ['not yet billed', this.app.i18n._('not yet billed')], 
116                 ['to bill', this.app.i18n._('to bill')],
117                 ['billed', this.app.i18n._('billed')]
118             ],
119             listeners: {
120                 scope: this,
121                 select: this.onBilledChange.createDelegate(this)
122             }
123         }];
124         
125         secondRow.push({
126             columnWidth: 1/3,
127             disabled: false,
128             fieldLabel: this.app.i18n._('Cleared In'),
129             name: 'billed_in'
130         });
131         
132         secondRow.push({
133             fieldLabel: this.app.i18n._('Booking deadline'),
134             name: 'deadline',
135             xtype: 'combo',
136             mode: 'local',
137             forceSelection: true,
138             triggerAction: 'all',
139             value: 'none',
140             store: [
141                 ['none', this.app.i18n._('none')], 
142                 ['lastweek', this.app.i18n._('last week')]
143             ]
144         });
145         
146         secondRow.push({
147             xtype: 'extuxclearabledatefield',
148             name: 'cleared_at',
149             fieldLabel: this.app.i18n._('Cleared at')
150         });
151         
152         if (Tine.Tinebase.appMgr.get('Sales')) {
153             secondRow.push({
154                 xtype: 'tinerelationpickercombo',
155                 fieldLabel: this.app.i18n._('Cost Center'),
156                 editDialog: this,
157                 allowBlank: true,
158                 app: 'Sales',
159                 recordClass: Tine.Sales.Model.CostCenter,
160                 relationType: 'COST_CENTER',
161                 relationDegree: 'sibling',
162                 modelUnique: true
163             });
164         }
165         
166         var lastRow = [{
167             columnWidth: 1/3,
168             editDialog: this,
169             xtype: 'tinerelationpickercombo',
170             fieldLabel: this.app.i18n._('Responsible Person'),
171             allowBlank: true,
172             app: 'Addressbook',
173             recordClass: Tine.Addressbook.Model.Contact,
174             relationType: 'RESPONSIBLE',
175             relationDegree: 'sibling',
176             modelUnique: true
177         }, {
178             hideLabel: true,
179             boxLabel: this.app.i18n._('Timesheets are billable'),
180             name: 'is_billable',
181             xtype: 'checkbox',
182             columnWidth: 1/3
183         }];
184         
185         if (this.useInvoice) {
186             lastRow.push(Tine.widgets.form.RecordPickerManager.get('Sales', 'Invoice', {
187                 columnWidth: 1/3,
188                 disabled: true,
189                 fieldLabel: this.app.i18n._('Invoice'),
190                 name: 'invoice_id'
191             }));
192         }
193         return {
194             xtype: 'tabpanel',
195             border: false,
196             plain:true,
197             activeTab: 0,
198             plugins: [{
199                 ptype : 'ux.tabpanelkeyplugin'
200             }],
201             defaults: {
202                 hideMode: 'offsets'
203             },
204             items:[{
205                 title: this.app.i18n.ngettext('Time Account', 'Time Accounts', 1),
206                 autoScroll: true,
207                 border: false,
208                 frame: true,
209                 layout: 'border',
210                 items: [{
211                     region: 'center',
212                     xtype: 'columnform',
213                     labelAlign: 'top',
214                     formDefaults: {
215                         xtype:'textfield',
216                         anchor: '100%',
217                         labelSeparator: '',
218                         columnWidth: .333
219                     },
220                     items: [[{
221                         fieldLabel: this.app.i18n._('Number'),
222                         name: 'number',
223                         allowBlank: false,
224                         maxLength: 127
225                         }, {
226                         columnWidth: .666,
227                         fieldLabel: this.app.i18n._('Title'),
228                         name: 'title',
229                         maxLength: 255,
230                         allowBlank: false
231                         }], [{
232                         columnWidth: 1,
233                         fieldLabel: this.app.i18n._('Description'),
234                         xtype: 'textarea',
235                         name: 'description',
236                         height: 150
237                         }], secondRow, lastRow] 
238                 }, {
239                     // activities and tags
240                     layout: 'accordion',
241                     animate: true,
242                     region: 'east',
243                     width: 210,
244                     split: true,
245                     collapsible: true,
246                     collapseMode: 'mini',
247                     header: false,
248                     margins: '0 5 0 5',
249                     border: true,
250                     items: [
251                     new Tine.widgets.tags.TagPanel({
252                         app: 'Timetracker',
253                         border: false,
254                         bodyStyle: 'border:1px solid #B5B8C8;'
255                     })]
256                 }]
257             },{
258                 title: this.app.i18n._('Access'),
259                 layout: 'fit',
260                 items: [this.getGrantsGrid()]
261             }, new Tine.widgets.activities.ActivitiesTabPanel({
262                 app: this.appName,
263                 record_id: (! this.copyRecord) ? this.record.id : null,
264                 record_model: this.appName + '_Model_' + this.recordClass.getMeta('modelName')
265             })]
266         };
267     },
268     
269     getGrantsGrid: function() {
270         if (! this.grantsGrid) {
271             this.grantsStore =  new Ext.data.JsonStore({
272                 root: 'results',
273                 totalProperty: 'totalcount',
274                 // use account_id here because that simplifies the adding of new records with the search comboboxes
275                 id: 'account_id',
276                 fields: Tine.Timetracker.Model.TimeaccountGrant
277             });
278             
279             var columns = [
280                 new Ext.ux.grid.CheckColumn({
281                     header: this.app.i18n._('Book Own'),
282                     dataIndex: 'bookOwnGrant',
283                     tooltip: i18n._('The grant to add Timesheets to this Timeaccount'),
284                     width: 55
285                 }),
286                 new Ext.ux.grid.CheckColumn({
287                     header: this.app.i18n._('View All'),
288                     tooltip: i18n._('The grant to view Timesheets of other users'),
289                     dataIndex: 'viewAllGrant',
290                     width: 55
291                 }),
292                 new Ext.ux.grid.CheckColumn({
293                     header: this.app.i18n._('Book All'),
294                     tooltip: i18n._('The grant to add Timesheets for other users'),
295                     dataIndex: 'bookAllGrant',
296                     width: 55
297                 }),
298                 new Ext.ux.grid.CheckColumn({
299                     header:this.app.i18n._('Manage Clearing'),
300                     tooltip: i18n._('The grant to manage clearing of Timesheets'),
301                     dataIndex: 'manageBillableGrant',
302                     width: 55
303                 }),
304                 new Ext.ux.grid.CheckColumn({
305                     header:this.app.i18n._('Export'),
306                     tooltip: i18n._('The grant to export Timesheets of Timeaccount'),
307                     dataIndex: 'exportGrant',
308                     width: 55
309                 }),
310                 new Ext.ux.grid.CheckColumn({
311                     header: this.app.i18n._('Manage All'),
312                     tooltip: i18n._('Includes all other grants'),
313                     dataIndex: 'adminGrant',
314                     width: 55
315                 })
316             ];
317             
318             this.grantsGrid = new Tine.widgets.account.PickerGridPanel({
319                 selectType: 'both',
320                 title:  this.app.i18n._('Permissions'),
321                 store: this.grantsStore,
322                 hasAccountPrefix: true,
323                 configColumns: columns,
324                 selectAnyone: false,
325                 selectTypeDefault: 'group',
326                 recordClass: Tine.Tinebase.Model.Grant
327             });
328         }
329         return this.grantsGrid;
330     },
331     
332     /**
333      * is called is billed field changes
334      */
335     onBilledChange: function(combo, record, index) {
336         if (combo.getValue() == 'billed') {
337             if (! this.getForm().findField('cleared_at').getValue()) {
338                 this.getForm().findField('cleared_at').setValue(new Date());
339             }
340         }
341     },
342     
343     doCopyRecord: function() {
344         Tine.Timetracker.TimeaccountEditDialog.superclass.doCopyRecord.call(this);
345         
346         this.record.set('status', 'not yet billed');
347     }
348 });