Add history tab to contract edit dialog
[tine20] / tine20 / Sales / js / ContractEditDialog.js
1 /*
2  * Tine 2.0
3  * 
4  * @package     Sales
5  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
6  * @author      Philipp Schuele <p.schuele@metaways.de>
7  * @copyright   Copyright (c) 2007-2010 Metaways Infosystems GmbH (http://www.metaways.de)
8  *
9  */
10  
11 Ext.namespace('Tine.Sales');
12
13 /**
14  * Contract edit dialog
15  * 
16  * @namespace   Tine.Sales
17  * @class       Tine.Sales.ContractEditDialog
18  * @extends     Tine.widgets.dialog.EditDialog
19  * 
20  * <p>Contract Edit Dialog</p>
21  * <p><pre>
22  * </pre></p>
23  * 
24  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
25  * @author      Philipp Schuele <p.schuele@metaways.de>
26  * @copyright   Copyright (c) 2007-2014 Metaways Infosystems GmbH (http://www.metaways.de)
27  * 
28  * @param       {Object} config
29  * @constructor
30  * Create a new Tine.Sales.ContractGridPanel
31  */
32 Tine.Sales.ContractEditDialog = Ext.extend(Tine.widgets.dialog.EditDialog, {
33     windowWidth: 800,
34     windowHeight: 600,
35     displayNotes: true,
36
37     /**
38      * autoset
39      * 
40      * @type combo
41      */
42     customerPicker: null,
43     
44     /**
45      * autoset
46      * 
47      * @type combo
48      */
49     addressPicker: null,
50     
51     /**
52      * if true, number will be readOnly and will be generated automatically
53      * @type {Boolean} autoGenerateNumber
54      */
55     autoGenerateNumber: null,
56     
57     /**
58      * how should the number be validated text/integer possible
59      * @type {String} validateNumber
60      */
61     validateNumber: null,
62
63     displayNotes: true,
64     
65     initComponent: function() {
66         this.autoGenerateNumber = (Tine.Sales.registry.get('config').contractNumberGeneration.value == 'auto') ? true : false;
67         this.validateNumber = Tine.Sales.registry.get('config').contractNumberValidation.value;
68
69         Tine.Sales.ContractEditDialog.superclass.initComponent.call(this);
70     },
71     
72     /**
73      * called on multiple edit
74      *
75      * @return {Boolean}
76      */
77     isMultipleValid: function() {
78         return true;
79     },
80     
81     /**
82      * containerProperty (all contracts in one container) exists, so overwrite creating selector here
83      */
84     initContainerSelector: Ext.emptyFn,
85     
86     /**
87      * extra validation for the number field, calls parent
88      * @return {Boolean}
89      */
90     isValid: function() {
91         var valid = Tine.Sales.ContractEditDialog.superclass.isValid.call(this);
92         var isValid = this.autoGenerateNumber ? true : (this.validateNumber == 'integer') ? Ext.isNumber(Ext.num(this.getForm().findField('number').getValue())) : true;
93         if (!isValid) {
94             this.getForm().findField('number').markInvalid(this.app.i18n._('Please use a decimal number here!'));
95         }
96         return isValid && valid;
97     },
98     
99     /**
100      * executed after record got updated from proxy
101      * 
102      * @private
103      */
104     onRecordLoad: function() {
105         // interrupt process flow until dialog is rendered
106         if (! this.rendered) {
107             this.onRecordLoad.defer(250, this);
108             return;
109         }
110         
111         Tine.Sales.ContractEditDialog.superclass.onRecordLoad.call(this);
112         
113         if (this.record.id) {
114             var relations = this.record.get('relations'), foundCustomer = false;
115             
116             if (Ext.isArray(relations)) {
117                 for (var index = 0; index < relations.length; index++) {
118                     if (relations[index].related_model == 'Sales_Model_Customer') {
119                         if (relations[index].type == 'CUSTOMER') {
120                             foundCustomer = relations[index].related_record;
121                         }
122                     }
123                 }
124             }
125             
126             if (foundCustomer) {
127                 this.addressPicker.enable();
128                 var ba = this.record.get('billing_address_id');
129                 
130                 if (ba && ba.hasOwnProperty('locality')) {
131                     var record = new Tine.Sales.Model.Address(ba);
132                 }
133              
134                 this.setAddressPickerFilter();
135             }
136         }
137     },
138     
139     /**
140      * sets the filter used for the addresspicker by the selected customer
141      */
142     setAddressPickerFilter: function() {
143         this.addressPicker.additionalFilters = [
144             {field: 'type', operator: 'not', value: 'delivery'},
145             {field: 'customer_id', operator: 'AND', value: [
146                 {field: ':id', operator: 'in', value: [this.customerPicker.getValue()] }
147             ]}
148         ];
149     },
150     
151     /**
152      * loads the full-featured record, if a contract gets selected
153      * 
154      * @param {Tine.widgets.relation.PickerCombo} combo
155      * @param {Tine.Sales.Model.Contract} record
156      * @param {Number} index
157      */
158     onCustomerLoad: function(combo, record, index) {
159         if (this.addressPicker.disabled) {
160             this.addressPicker.enable();
161         } else {
162             this.addressPicker.reset();
163         }
164         
165         this.addressPicker.lastQuery = null;
166         this.setAddressPickerFilter();
167         this.loadAddress(record);
168     },
169     
170     /**
171      * loads the first billing address or the postal 
172      * address into the addresspicker on loading a customer
173      * 
174      * @param {Tine.Sales.Model.Customer} record
175      */
176     loadAddress: function(record) {
177         var billingAddresses = record.get('billing');
178         if (Ext.isArray(billingAddresses) && billingAddresses.length > 0) {
179             var address = new Tine.Sales.Model.Address(billingAddresses[0]);
180         } else {
181             var address = new Tine.Sales.Model.Address(record.get('postal_id'));
182         }
183         
184         this.addressPicker.setValue(address.data);
185     },
186     
187     /**
188      * returns dialog
189      * 
190      * NOTE: when this method gets called, all initalisation is done.
191      */
192     getFormItems: function() {
193         
194         this.productGridPanel = new Tine.Sales.ProductAggregateGridPanel({
195             app: this.app,
196             editDialog: this,
197             title: this.app.i18n._('Products'),
198             editDialogRecordProperty: 'products'
199         });
200         
201         var items = [[{
202             columnWidth: .25,
203             fieldLabel: this.app.i18n._('Number'),
204             name: 'number',
205             multiEditable: false,
206             readOnly: this.autoGenerateNumber,
207             allowBlank: this.autoGenerateNumber
208         },{
209             columnWidth: .75,
210             fieldLabel: this.app.i18n._('Title'),
211             name: 'title',
212             allowBlank: false
213         }], [{
214             columnWidth: 1,
215             editDialog: this,
216             xtype: 'tinerelationpickercombo',
217             allowBlank: true,
218             app: 'Sales',
219             recordClass: Tine.Sales.Model.Customer,
220             relationType: 'CUSTOMER',
221             relationDegree: 'sibling',
222             modelUnique: true,
223             listeners: {
224                 scope: this,
225                 select: this.onCustomerLoad
226             },
227             ref: '../../../../../customerPicker',
228             fieldLabel: this.app.i18n._('Customer')
229         }], [ Tine.widgets.form.RecordPickerManager.get('Sales', 'Address', {
230                 fieldLabel: this.app.i18n._('Billing Address'),
231                 name: 'billing_address_id',
232                 ref: '../../../../../addressPicker',
233                 columnWidth: 1,
234                 disabled: true,
235                 allowBlank: true
236             })], [{
237                     xtype: 'extuxclearabledatefield',
238                     name: 'start_date',
239                     columnWidth: 1/2,
240                     fieldLabel: this.app.i18n._('Start Date'),
241                     allowBlank: false
242                 }, {
243                     xtype: 'extuxclearabledatefield',
244                     name: 'end_date',
245                     fieldLabel: this.app.i18n._('End Date'),
246                     columnWidth: 1/2
247                 }], [{
248                 columnWidth: 1/3,
249                 xtype: 'tinerelationpickercombo',
250                 fieldLabel: this.app.i18n._('Contact Person (external)'),
251                 editDialog: this,
252                 allowBlank: true,
253                 app: 'Addressbook',
254                 recordClass: Tine.Addressbook.Model.Contact,
255                 relationType: 'CUSTOMER',
256                 relationDegree: 'sibling',
257                 modelUnique: true
258             }, {
259                 columnWidth: 1/3,
260                 editDialog: this,
261                 xtype: 'tinerelationpickercombo',
262                 fieldLabel: this.app.i18n._('Contact Person (internal)'),
263                 allowBlank: true,
264                 app: 'Addressbook',
265                 recordClass: Tine.Addressbook.Model.Contact,
266                 relationType: 'RESPONSIBLE',
267                 relationDegree: 'sibling',
268                 modelUnique: true
269             }, {
270                 columnWidth: 1/3,
271                 editDialog: this,
272                 xtype: 'tinerelationpickercombo',
273                 fieldLabel: this.app.i18n._('Lead Cost Center'),
274                 allowBlank: true,
275                 app: 'Sales',
276                 recordClass: Tine.Sales.Model.CostCenter,
277                 relationType: 'LEAD_COST_CENTER',
278                 relationDegree: 'sibling',
279                 modelUnique: true
280             }]];
281             
282         items.push([{
283             columnWidth: 1,
284             fieldLabel: this.app.i18n._('Description'),
285             emptyText: this.app.i18n._('Enter description...'),
286             name: 'description',
287             xtype: 'textarea',
288             height: 200
289         }]);
290         
291         return {
292             xtype: 'tabpanel',
293             border: false,
294             plain:true,
295             activeTab: 0,
296             border: false,
297             defaults: {
298                 hideMode: 'offsets'
299             },
300             plugins: [{
301                 ptype : 'ux.tabpanelkeyplugin'
302             }],
303             items:[
304                 {
305                 title: this.app.i18n.n_('Contract', 'Contracts', 1),
306                 autoScroll: true,
307                 border: false,
308                 frame: true,
309                 layout: 'border',
310                 items: [{
311                     region: 'center',
312                     xtype: 'columnform',
313                     labelAlign: 'top',
314                     formDefaults: {
315                         xtype:'textfield',
316                         anchor: '100%',
317                         labelSeparator: '',
318                         columnWidth: .333
319                     },
320                     items: items
321                 }, {
322                     // activities and tags
323                     layout: 'accordion',
324                     animate: true,
325                     region: 'east',
326                     width: 210,
327                     split: true,
328                     collapsible: true,
329                     collapseMode: 'mini',
330                     header: false,
331                     margins: '0 5 0 5',
332                     border: true,
333                     items: [
334                         new Tine.widgets.tags.TagPanel({
335                             app: 'Sales',
336                             border: false,
337                             bodyStyle: 'border:1px solid #B5B8C8;'
338                         })
339                     ]
340                 }]
341             }, this.productGridPanel,
342                 new Tine.widgets.activities.ActivitiesTabPanel({
343                     app: this.appName,
344                     record_id: this.record.id,
345                     record_model: 'Sales_Model_Contract'
346                 })
347             ]
348         };
349     }
350 });