shows a warning if application of billable is not found
[tine20] / tine20 / Sales / js / InvoicePositionPanel.js
1 /*
2  * Tine 2.0
3  * 
4  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
5  * @author      Alexander Stintzing <a.stintzing@metaways.de>
6  * @copyright   Copyright (c) 2014 Metaways Infosystems GmbH (http://www.metaways.de)
7  */
8 Ext.ns('Tine.Sales');
9
10 /**
11  * InvoicePosition panel
12  * 
13  * @namespace   Tine.Sales
14  * @class       Tine.Sales.InvoicePositionPanel
15  * @extends     Ext.Panel
16  * 
17  * <p>InvoicePosition Grid Panel</p>
18  * <p><pre>
19  * </pre></p>
20  * 
21  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
22  * @author      Alexander Stintzing <a.stintzing@metaways.de>
23  * 
24  * @param       {Object} config
25  * @constructor
26  * Create a new Tine.Sales.InvoiceGridPanel
27  */
28 Tine.Sales.InvoicePositionPanel = Ext.extend(Ext.Panel, {
29     /**
30      * holds positions from the edit dialog records positions property
31      * 
32      * @type array
33      */
34     positions: null,
35     
36     /**
37      * holds the id of the invoice
38      * 
39      * @type string
40      */
41     invoiceId: null,
42     
43     positionsPerAccountable: null,
44     
45     app: null,
46     
47     autoScroll: true,
48     
49     /**
50      * holds all accountables needed
51      * 
52      * @type {Array}
53      */
54     accountables: null,
55     /**
56      * 
57      * @type {Array}
58      */
59     modelsOfAccountable: null,
60     sumsPerAccountable: null,
61     
62     initComponent: function(deferred) {
63         
64         // defer this, otherwise renderers won't have been registered, yet.
65         if (! deferred) {
66             this.initComponent.defer(150, this, [true]);
67             return false;
68         }
69
70         this.accountables = [];
71         this.positionsPerAccountable = {};
72         this.sumsPerAccountable = {};
73         this.modelsOfAccountable = [];
74         
75         Tine.Sales.InvoicePositionPanel.superclass.initComponent.call(this);
76         
77         this.initStoreAndPanels();
78     },
79     
80     /**
81      * creates a store containing all positions
82      */
83     initStoreAndPanels: function() {
84         // interrupt process flow until we got the positions from the editdialog set
85         if (! this.positions) {
86             this.initStoreAndPanels.defer(50, this);
87             return;
88         }
89         
90         if (! Ext.isArray(this.positions)) {
91             Tine.log.error('No Invoice Positions given:');
92             Tine.log.error(this.positions);
93             return;
94         }
95         
96         for (var index = 0; index < this.positions.length; index++) {
97             var key = this.positions[index].model + this.positions[index].unit;
98             var key = key.replace(/\s/g, "");
99             if (this.accountables.indexOf(key) == -1) {
100                 this.accountables.push(key);
101                 this.modelsOfAccountable[key] = this.positions[index].model;
102                 this.positionsPerAccountable[key] = [];
103                 this.sumsPerAccountable[key] = 0.0;
104             }
105             
106             this.positionsPerAccountable[key].push(this.positions[index]);
107             this.sumsPerAccountable[key] += parseFloat(this.positions[index].quantity);
108         }
109         
110         // prepeare rendered sums registry
111         Tine.Sales.renderedSumsPerMonth[this.invoiceId] = {};
112         
113         // not needed anymore
114         this.positions = null;
115         
116         for (var index = 0; index < this.accountables.length; index++) {
117             
118             var mypositions = this.positionsPerAccountable[this.accountables[index]];
119             
120             var pseudoRecord     = new Tine.Sales.Model.Invoice({
121                 positions: mypositions,
122                 id: this.invoiceId
123             });
124             
125             // find out months of the accountable type to decide if grouping is required
126             var mymonths = [];
127             var mysumspermonth = {};
128             for (var index2 = 0; index2 < mypositions.length; index2++) {
129                 if (! mysumspermonth['month-' + mypositions[index2].month]) {
130                     mysumspermonth['month-' + mypositions[index2].month] = 0.0;
131                 }
132                 
133                 mysumspermonth['month-' + mypositions[index2].month] += parseFloat(mypositions[index2].quantity);
134                 
135                 if (mymonths.indexOf(mypositions[index2].month) == -1) {
136                     mymonths.push(mypositions[index2].month);
137                 }
138             }
139             var pseudoRecord2 = {data: {unit: mypositions[0]['unit'], model: this.modelsOfAccountable[this.accountables[index]]}};
140             var renderedSumsPerMonth = {};
141             
142             Ext.iterate(mysumspermonth, function(month, sum) {
143                 renderedSumsPerMonth[month] = Tine.Sales.renderInvoicePositionQuantity(mysumspermonth[month], null, pseudoRecord2);
144             });
145             
146             Tine.Sales.renderedSumsPerMonth[this.invoiceId][this.accountables[index]] = renderedSumsPerMonth;
147             
148             var pseudoEditDialog = {record: pseudoRecord, app: this.app};
149             
150             var split = this.modelsOfAccountable[this.accountables[index]].split('_Model_');
151             if (Tine[split[0]]) {
152                 var model = Tine[split[0]].Model[split[1]];
153                 var accountableApplication = Tine.Tinebase.appMgr.get(split[0]);
154                 var renderedSum = Tine.Sales.renderInvoicePositionQuantity(this.sumsPerAccountable[this.accountables[index]], null, pseudoRecord2);
155                 var grid = new Tine.Sales.InvoicePositionGridPanel({
156                     collapsible: true,
157                     collapsed: true,
158                     editDialog: pseudoEditDialog,
159                     height: (mymonths.length > 1) ? 350 : 250, // if grid will be grouped, make it bigger
160                     title: accountableApplication.i18n._(model.getRecordsName()) +
161                     ' (' + mypositions.length + ')' + ' - ' +
162                     accountableApplication.i18n._(mypositions[0]['unit']) + ': ' + renderedSum,
163                     app: this.app,
164                     i18nModelsName: accountableApplication.i18n._(model.getRecordsName()),
165                     i18nUnitName: accountableApplication.i18n._(mypositions[0]['unit']),
166                     accountable: this.modelsOfAccountable[this.accountables[index]],
167                     accountableApplication: accountableApplication,
168                     invoiceId: this.invoiceId,
169                     renderedSum: renderedSum,
170                     renderedSumsPerMonth: renderedSumsPerMonth,
171                     unitName: mypositions[0]['unit'],
172                     groupField: (mymonths.length > 1) ? 'month' : null
173                 });
174
175                 this.add(grid);
176             } else {
177                 Tine.log.warn('Application for accountable ' + this.accountables[index] + ' not found!');
178             }
179         }
180     }
181 });