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