~txerpa-openerp/openobject-client-web/txerpa

817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
1
###############################################################################
2
#
4354 by Fabien Meghazi
[IMP] Replaced Tiny by OpenERP SA in license headers
3
#  Copyright (C) 2007-TODAY OpenERP SA. All Rights Reserved.
4
#
5
#  $Id$
6
#
7
#  Developed by OpenERP (http://openerp.com) and Axelor (http://axelor.com).
8
#
9
#  The OpenERP web client is distributed under the "OpenERP Public License".
10
#  It's based on Mozilla Public License Version (MPL) 1.1 with following 
11
#  restrictions:
12
#
13
#  -   All names, links and logos of OpenERP must be kept as in original
14
#      distribution without any changes in all software screens, especially
15
#      in start-up page and the software header, even if the application
16
#      source code has been changed or updated or code has been added.
17
#
18
#  You can see the MPL licence at: http://www.mozilla.org/MPL/MPL-1.1.html
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
19
#
20
###############################################################################
4422 by Antony Lesuisse
[FIX] correct implementation of binary widget image
21
import base64,os,re
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
22
2812 by ame (Tiny)
[IMP] initial work on addons
23
import cherrypy
2938.1.1 by Xavier Morel
[imp] Reorganize imports across the board
24
from openerp import utils, widgets as tw, validators
2870 by ame (Tiny)
[REF] namespace fix
25
from openerp.controllers import SecuredController
4177 by noz (Open ERP)
[FIX] Domain evaluated properly.
26
from openerp.utils import rpc, common, TinyDict, TinyForm, expr_eval
2939.25.24 by sma(Tiny)
[IMP] Improved maintenance stuff.
27
from error_page import _ep
2938.1.1 by Xavier Morel
[imp] Reorganize imports across the board
28
from openobject.tools import expose, redirect, validate, error_handler, exception_handler
3330 by Xavier Morel
[IMP] tentative pretty major reorganization of the validators import in order to try and avoid systemic import failures due to a bunch of undebuggable errors related to Python getting lost in the crap.
29
import openobject
4441 by Antony Lesuisse
[FIX] binary image fix placeholder loading on windows
30
import openobject.paths
3922.1.2 by Xavier Morel
[FIX] don't display shortcuts star *everywhere*
31
import simplejson
2572 by Christophe Simonis
[IMP] on_change now works for picture widgets
32
2616 by ame (Tiny/Axelor)
[FIX] search view (incorrect search result on selection fields).
33
def make_domain(name, value, kind='char'):
2056 by Amit Mendapara
* Refactoring Search controller (now derived from Form)
34
    """A helper function to generate domain for the given name, value pair.
35
    Will be used for search window...
36
    """
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
37
2056 by Amit Mendapara
* Refactoring Search controller (now derived from Form)
38
    if isinstance(value, int) and not isinstance(value, bool):
39
        return [(name, '=', value)]
40
41
    if isinstance(value, dict):
42
43
        start = value.get('from')
44
        end = value.get('to')
45
46
        if start and end:
47
            return [(name, '>=', start), (name, '<=', end)]
48
49
        elif start:
50
            return [(name, '>=', start)]
51
52
        elif end:
53
            return [(name, '<=', end)]
54
55
        return None
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
56
2616 by ame (Tiny/Axelor)
[FIX] search view (incorrect search result on selection fields).
57
    if kind == "selection" and value:
58
        return [(name, '=', value)]
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
59
2056 by Amit Mendapara
* Refactoring Search controller (now derived from Form)
60
    if isinstance(value, basestring) and value:
61
        return [(name, 'ilike', value)]
62
63
    if isinstance(value, bool) and value:
64
        return [(name, '=', 1)]
65
66
    return []
67
3901 by sma(Tiny)
[FIX] Set default limit=50.
68
def search(model, offset=0, limit=50, domain=[], context={}, data={}):
2056 by Amit Mendapara
* Refactoring Search controller (now derived from Form)
69
    """A helper function to search for data by given criteria.
70
71
    @param model: the resource on which to make search
72
    @param offset: offset from when to start search
73
    @param limit: limit of the search result
74
    @param domain: the domain (search criteria)
75
    @param context: the context
76
    @param data: the form data
77
78
    @returns dict with list of ids count of records etc.
79
    """
80
81
    domain = domain or []
82
    context = context or {}
83
    data = data or {}
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
84
2616 by ame (Tiny/Axelor)
[FIX] search view (incorrect search result on selection fields).
85
    proxy = rpc.RPCProxy(model)
4021.1.1 by sma(Tiny)
[FIX] Add context for fields_get, name_get calls.
86
    fields = proxy.fields_get([], rpc.session.context)
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
87
2056 by Amit Mendapara
* Refactoring Search controller (now derived from Form)
88
    search_domain = domain[:]
89
    search_data = {}
90
91
    for k, v in data.items():
2616 by ame (Tiny/Axelor)
[FIX] search view (incorrect search result on selection fields).
92
        t = fields.get(k, {}).get('type', 'char')
93
        t = make_domain(k, v, t)
2056 by Amit Mendapara
* Refactoring Search controller (now derived from Form)
94
95
        if t:
96
            search_domain += t
97
            search_data[k] = v
98
99
    l = limit
100
    o = offset
101
3901 by sma(Tiny)
[FIX] Set default limit=50.
102
    if l < 1: l = 50
2056 by Amit Mendapara
* Refactoring Search controller (now derived from Form)
103
    if o < 0: o = 0
104
105
    ctx = rpc.session.context.copy()
106
    ctx.update(context)
107
108
    ids = proxy.search(search_domain, o, l, 0, ctx)
2939.1.103 by sma(Tiny)
[FIX] reviewed search_count calls.
109
    if len(ids) < l:
2939.1.96 by sma(Tiny)
[IMP] Improved search view.
110
        count = len(ids)
111
    else:
112
        count = proxy.search_count(search_domain, ctx)
2939.25.69 by Xavier Morel
[IMP] use os.path.splitext for file extensions management
113
2939.1.47 by noz at tinyerp
[IMP] Removed use of search_count.
114
    if isinstance(ids, list):
115
        count = len(ids)
2056 by Amit Mendapara
* Refactoring Search controller (now derived from Form)
116
117
    return dict(model=model, ids=ids, count=count, offset=o, limit=l,
118
                search_domain=search_domain, search_data=search_data)
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
119
2055 by Amit Mendapara
* Generic validation schema generator for all Form controllers
120
def get_validation_schema(self):
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
121
    """Generate validation schema for the given Form instance. Should be used
2055 by Amit Mendapara
* Generic validation schema generator for all Form controllers
122
    to validate form inputs with @validate decorator.
123
124
    @param self: and instance of Form
125
126
    @returns a new instance of Form with validation schema
127
    """
128
129
    kw = cherrypy.request.params
130
    params, data = TinyDict.split(kw)
131
132
    # bypass validations, if saving from button in non-editable view
133
    if params.button and not params.editable and params.id:
134
        return None
135
136
    cherrypy.request.terp_validators = {}
2518 by ame (Tiny/Axelor)
[FIX] fixed M2M problem (preserver value during validation)
137
    cherrypy.request.terp_data = data
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
138
2055 by Amit Mendapara
* Generic validation schema generator for all Form controllers
139
    params.nodefault = True
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
140
2055 by Amit Mendapara
* Generic validation schema generator for all Form controllers
141
    form = self.create_form(params)
142
    cherrypy.request.terp_form = form
143
144
    vals = cherrypy.request.terp_validators
145
    keys = vals.keys()
146
    for k in keys:
147
        if k not in kw:
148
            vals.pop(k)
149
3330 by Xavier Morel
[IMP] tentative pretty major reorganization of the validators import in order to try and avoid systemic import failures due to a bunch of undebuggable errors related to Python getting lost in the crap.
150
    form.validator = openobject.validators.Schema(**vals)
2055 by Amit Mendapara
* Generic validation schema generator for all Form controllers
151
    return form
152
2158 by ame (Tiny/Axelor)
* Added default error handler
153
def default_error_handler(self, tg_errors=None, **kw):
154
    """ Error handler for the given Form instance.
155
156
    @param self: an instance for Form
157
    @param tg_errors: errors
158
    """
159
    params, data = TinyDict.split(kw)
160
    return self.create(params, tg_errors=tg_errors)
161
162
def default_exception_handler(self, tg_exceptions=None, **kw):
163
    """ Exception handler for the given Form instance.
164
165
    @param self: an instance for Form
166
    @param tg_exceptions: exception
167
    """
168
    # let _cp_on_error handle the exception
169
    raise tg_exceptions
170
2524.2.24 by ame (Tiny/Axelor)
[REF] major refactoring
171
class Form(SecuredController):
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
172
2939.19.1 by vda(Open ERP)
[IMP] _cp_path per addons.
173
    _cp_path = "/openerp/form"
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
174
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
175
    def create_form(self, params, tg_errors=None):
176
        if tg_errors:
177
            return cherrypy.request.terp_form
2939.25.69 by Xavier Morel
[IMP] use os.path.splitext for file extensions management
178
2939.20.75 by vda(Open ERP)
[IMP] Improved attachment.
179
        cherrypy.session['params'] = params
2939.25.69 by Xavier Morel
[IMP] use os.path.splitext for file extensions management
180
1005 by Amit Mendapara
* Reimplemented `TinyDict` to prevent name conflicts
181
        params.offset = params.offset or 0
3901 by sma(Tiny)
[FIX] Set default limit=50.
182
        params.limit = params.limit or 50
1005 by Amit Mendapara
* Reimplemented `TinyDict` to prevent name conflicts
183
        params.count = params.count or 0
841 by Amit Mendapara
* Better `view_id` selection from current view instead of original view...
184
        params.view_type = params.view_type or params.view_mode[0]
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
185
2939.19.1 by vda(Open ERP)
[IMP] _cp_path per addons.
186
        return tw.form_view.ViewForm(params, name="view_form", action="/openerp/form/save")
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
187
3330.1.9 by Xavier Morel
[IMP] remove all smarts from the template loading layer
188
    @expose(template="/openerp/controllers/templates/form.mako")
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
189
    def create(self, params, tg_errors=None):
190
2067 by Amit Mendapara
* Fixed search popup.
191
        params.view_type = params.view_type or params.view_mode[0]
2939.25.69 by Xavier Morel
[IMP] use os.path.splitext for file extensions management
192
2067 by Amit Mendapara
* Fixed search popup.
193
        if params.view_type == 'tree':
194
            params.editable = True
4670.77.3 by Xavier ALT
[FIX] web: form create: handle specific '_terp_view_target' before calling create_form()
195
196
        target = getattr(cherrypy.request, '_terp_view_target', None)
197
        if target == 'new':
198
            # for target='new' keep orignal value as '_terp_view_target' hidden field,
199
            # that's necessary to keep wizard without toolbar button (new, save, pager, etc...)
200
            hidden_fields = params.hidden_fields or []
201
            hidden_fields.append(tw.form.Hidden(name='_terp_view_target', default=ustr(target)))
202
            params.hidden_fields = hidden_fields
203
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
204
        form = self.create_form(params, tg_errors)
205
2169 by ame (Tiny/Axelor)
[IMP] Remember active page of notebooks.
206
        if not tg_errors:
207
            try:
208
                cherrypy.session.pop('remember_notebooks')
209
            except:
2939.1.12 by noz at tinyerp
[IMP] Moved reset_notebook function back.
210
                self.reset_notebooks()
2159 by ame (Tiny/Axelor)
* Remember active notebook page.
211
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
212
        editable = form.screen.editable
841 by Amit Mendapara
* Better `view_id` selection from current view instead of original view...
213
        mode = form.screen.view_type
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
214
        id = form.screen.id
1555 by Amit Mendapara
* Only show CUSTOMISE WORKFLOW link if a workflow is associated to the resource.
215
        buttons = TinyDict()    # toolbar
3424.2.1 by ksh (Axelor)
[REM] remove fadeout effect
216
        buttons.new = (not editable or mode == 'tree') and mode != 'diagram'
3863 by Shanta Kabra
[IMP] Allow for switching read-only diagram view to editable
217
        buttons.edit = not editable and (mode == 'form' or mode == 'diagram')
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
218
        buttons.save = editable and mode == 'form'
219
        buttons.cancel = editable and mode == 'form'
220
        buttons.delete = not editable and mode == 'form'
2901.1.1 by ksh (Axelor)
[IMP] Initial commit for diagram-view
221
        buttons.pager =  mode == 'form' or mode == 'diagram'# Pager will visible in edit and non-edit mode in form view.
1590 by Christophe Simonis
when there are attachments, a different icon is shown
222
        buttons.can_attach = id and mode == 'form'
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
223
        buttons.i18n = not editable and mode == 'form'
3212 by Shanta Kabra
[IMP] Remove tool bar from diagram view, replace by regular buttons
224
        buttons.show_grid = mode == 'diagram'
3424.2.1 by ksh (Axelor)
[REM] remove fadeout effect
225
        buttons.create_node = mode == 'diagram' and editable
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
226
2933 by ame (Tiny)
[IMP] create/overrite openerp view with addons
227
        from openerp.widgets import get_registered_views
228
        buttons.views = []
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
229
3389 by Xavier Morel
[FIX] get_registered_views has to instantiate the views it fetches from the pooler itself or sort is random
230
        for kind, view in get_registered_views():
3390 by Xavier Morel
[IMP] remove unused parameter in definition of displayed view buttons
231
            buttons.views.append(dict(kind=kind, name=view.name, desc=view.desc))
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
232
4452 by Antony Lesuisse
[FIX] dont look len of view to decide of toolbar or not
233
        buttons.toolbar = (target != 'new' and not form.is_dashboard) or mode == 'diagram'
4670.77.1 by Xavier ALT
[FIX] web: keep wizard without toolbar buttons (new, save, pager, etc...) when clicking on a wizard button
234
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
235
        pager = None
236
        if buttons.pager:
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
237
            pager = tw.pager.Pager(id=form.screen.id, ids=form.screen.ids, offset=form.screen.offset,
1602 by Amit Mendapara
* removed buggy (don't show header/footer/toolbar in wizards)
238
                                   limit=form.screen.limit, count=form.screen.count, view_type=params.view_type)
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
239
2939.1.97 by noz at tinyerp
[IMP] Improved Shortcut Creation.
240
        can_shortcut = self.can_shortcut_create()
2939.1.98 by noz at tinyerp
[FIX] Fixed shortcut creation (Not possible if already created).
241
        shortcut_ids = []
2939.25.69 by Xavier Morel
[IMP] use os.path.splitext for file extensions management
242
2939.1.98 by noz at tinyerp
[FIX] Fixed shortcut creation (Not possible if already created).
243
        if cherrypy.session.get('terp_shortcuts'):
244
            for sc in cherrypy.session['terp_shortcuts']:
245
                if isinstance(sc['res_id'], tuple):
246
                    shortcut_ids.append(sc['res_id'][0])
247
                else:
3099 by vda(Open ERP)
[FIX] Minor changes for logs.
248
                    shortcut_ids.append(sc['res_id'])        
249
        
2993 by vda(Open ERP)
[FIX] Fix title issue.
250
        title = form.screen.string or ''
2939.1.277 by vda(Open ERP)
[FIX] Fixed form display header.
251
        display_name = {}
2939.25.290 by vda(Open ERP)
[FIX] name_get when pager action.
252
        if params.view_type == 'form':
2939.1.277 by vda(Open ERP)
[FIX] Fixed form display header.
253
            if params.id:
2939.1.292 by noz
[Merge] Backporting - Stable to Trunk (Bug fixes).
254
                if form.screen.view.get('fields') and form.screen.view['fields'].get('name'):
3020 by sma(Tiny)
[FIX] Fixed unicode error.
255
                    display_name = {'field': form.screen.view['fields']['name']['string'], 'value': ustr(form.screen.view['fields']['name']['value'])}
256
                    title= ustr(display_name['field']) + ':' + ustr(display_name['value'])
3477 by Shanta Kabra
[IMP] display name of the current model in workflow view
257
        elif params.view_type == 'diagram':
4021.1.1 by sma(Tiny)
[FIX] Add context for fields_get, name_get calls.
258
            display_name = {'field': form.screen.view['fields']['name']['string'], 'value': rpc.RPCProxy(params.model).name_get(form.screen.id, rpc.session.context)[0][1]}
3477 by Shanta Kabra
[IMP] display name of the current model in workflow view
259
3856 by jra at tinyerp
[FIX] Fixed Corporate Intelligence Visibility.
260
        # For Corporate Intelligence visibility.
261
        obj_process = rpc.RPCProxy('ir.model').search([('model', '=', 'process.process')]) or None
262
        
3737 by sma(Tiny)
[IMP] Improve rpc calls for display menu tips.
263
        tips = params.display_menu_tip
264
        if params.view_type == params.view_mode[0] and tips:
265
            tips = tips
3923 by vda(Open ERP)
[FIX] Fixes for dashboard.
266
        
4374 by vda(Open ERP)
[FIX] Better Sidebar options(not consider for wizard,dashboard and configuration).
267
        is_dashboard = form.screen.is_dashboard or False
3923 by vda(Open ERP)
[FIX] Fixes for dashboard.
268
        return dict(form=form, pager=pager, buttons=buttons, path=self.path, can_shortcut=can_shortcut, shortcut_ids=shortcut_ids, display_name=display_name, title=title, tips=tips, obj_process=obj_process, is_dashboard=is_dashboard)
3422 by jra
[IMP] Improved Help Tips.
269
270
    @expose('json', methods=('POST',))
3409 by jra
[FIX] Implemented Help Tips.
271
    def close_or_disable_tips(self):
3423 by jra
[IMP] Minor change in last commit for Help Tips.
272
        rpc.RPCProxy('res.users').write(rpc.session.uid,{'menu_tips':False}, rpc.session.context)
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
273
2939.21.24 by Xavier Morel
[IMP] remove redundancies between Form.edit and Form.read
274
    def _read_form(self, context, count, domain, filter_domain, id, ids, kw,
275
                   limit, model, offset, search_data, search_domain, source,
4395 by Xavier Morel
[FIX] clicking on line edition in editable o2m with unsaved parent, save parent and redisplay
276
                   view_ids, view_mode, view_type, notebook_tab, o2m_edit=False,
277
                   editable=False):
2939.21.24 by Xavier Morel
[IMP] remove redundancies between Form.edit and Form.read
278
        """ Extract parameters for form reading/creation common to both
279
        self.edit and self.view
280
        """
905 by Navrang Oza
* Fixed bug in on_change.
281
        params, data = TinyDict.split({'_terp_model': model,
824 by Amit Mendapara
* Fixed navigation problem.
282
                                       '_terp_id' : id,
283
                                       '_terp_ids' : ids,
284
                                       '_terp_view_ids' : view_ids,
841 by Amit Mendapara
* Better `view_id` selection from current view instead of original view...
285
                                       '_terp_view_mode' : view_mode,
3863 by Shanta Kabra
[IMP] Allow for switching read-only diagram view to editable
286
                                       '_terp_view_type' : view_type,
824 by Amit Mendapara
* Fixed navigation problem.
287
                                       '_terp_source' : source,
832 by Amit Mendapara
* Fixed `VIEW, EDIT` controller (missing domain, context).
288
                                       '_terp_domain' : domain,
289
                                       '_terp_context' : context,
824 by Amit Mendapara
* Fixed navigation problem.
290
                                       '_terp_offset': offset,
291
                                       '_terp_limit': limit,
292
                                       '_terp_count': count,
2939.1.32 by sma(Tiny)
[IMP] Improved search filter.
293
                                       '_terp_search_domain': search_domain,
2939.1.40 by sma(Tiny)
[IMP] Improved custom filter widget.
294
                                       '_terp_search_data': search_data,
3156 by sma(Tiny)
Fixed remember notepad page for edit/save.
295
                                       '_terp_filter_domain': filter_domain,
296
                                       '_terp_notebook_tab': notebook_tab})
4395 by Xavier Morel
[FIX] clicking on line edition in editable o2m with unsaved parent, save parent and redisplay
297
        params.o2m_edit = o2m_edit
2939.21.24 by Xavier Morel
[IMP] remove redundancies between Form.edit and Form.read
298
        params.editable = editable
4593 by Olivier Dony
[FIX] form controller: action_id should be available in form views
299
        params.action_id = kw.get('action_id')
2939.25.69 by Xavier Morel
[IMP] use os.path.splitext for file extensions management
300
2939.24.36 by sma(Tiny)
[FIX] Fixed default_date context for calendar (#516978).
301
        if kw.get('default_date'):
2939.24.74 by sma(Tiny)
[IMP] Improved reviewed code.
302
            params.context.update({'default_date' : kw['default_date']})
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
303
2694 by ame (Tiny)
[FIX] don't show header/footer on button action if source form has not header/footer.
304
        cherrypy.request._terp_view_target = kw.get('target')
1016 by Navrang Oza
* Fixed navigation problem in view mode.
305
1014 by Amit Mendapara
* Fixed `edit & view` controller
306
        if params.view_mode and 'form' not in params.view_mode:
307
            params.view_type = params.view_mode[-1]
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
308
1063 by Amit Mendapara
* Fixed `edit/view` controllers, now ensures NON-TREE mode. (bug #458)
309
        if params.view_type == 'tree':
310
            params.view_type = 'form'
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
311
2094 by Navrang Oza
* Fixed navigation problem.
312
        if not params.ids:
2939.21.24 by Xavier Morel
[IMP] remove redundancies between Form.edit and Form.read
313
            params.offset = 0
314
315
        return params
316
317
    @expose()
318
    def edit(self, model, id=False, ids=None, view_ids=None,
3866 by sma(Tiny)
[FIX] Fixed default view_type.
319
             view_mode=['form', 'tree'], view_type='form', source=None, domain=[], context={},
3901 by sma(Tiny)
[FIX] Set default limit=50.
320
             offset=0, limit=50, count=0, search_domain=None,
4395 by Xavier Morel
[FIX] clicking on line edition in editable o2m with unsaved parent, save parent and redisplay
321
             search_data=None, filter_domain=None, o2m_edit=False, **kw):
2939.21.24 by Xavier Morel
[IMP] remove redundancies between Form.edit and Form.read
322
3156 by sma(Tiny)
Fixed remember notepad page for edit/save.
323
        notebook_tab = kw.get('notebook_tab') or 0
2939.21.24 by Xavier Morel
[IMP] remove redundancies between Form.edit and Form.read
324
        params = self._read_form(context, count, domain, filter_domain, id,
325
                                 ids, kw, limit, model, offset, search_data,
326
                                 search_domain, source, view_ids, view_mode,
4395 by Xavier Morel
[FIX] clicking on line edition in editable o2m with unsaved parent, save parent and redisplay
327
                                 view_type, notebook_tab, o2m_edit=o2m_edit, editable=True)
2939.21.24 by Xavier Morel
[IMP] remove redundancies between Form.edit and Form.read
328
329
        if not params.ids:
2222 by ame (Tiny/Axelor)
[FIX] pagination problem.
330
            params.count = 0
826 by Amit Mendapara
* Fixed `New` record problem for O2M fields (form mode).
331
1003 by Navrang Oza
* Fixed new in O2M problem in form mode.
332
        # On New O2M
826 by Amit Mendapara
* Fixed `New` record problem for O2M fields (form mode).
333
        if params.source:
1003 by Navrang Oza
* Fixed new in O2M problem in form mode.
334
            current = TinyDict()
335
            current.id = False
336
            params[params.source] = current
826 by Amit Mendapara
* Fixed `New` record problem for O2M fields (form mode).
337
819 by Amit Mendapara
* Reimplemented `edit` and `view` method of `Form` contrllers.
338
        return self.create(params)
905 by Navrang Oza
* Fixed bug in on_change.
339
819 by Amit Mendapara
* Reimplemented `edit` and `view` method of `Form` contrllers.
340
    @expose()
2939.21.24 by Xavier Morel
[IMP] remove redundancies between Form.edit and Form.read
341
    def view(self, model, id, ids=None, view_ids=None,
4009.1.1 by jra-OpenERP
[IMP] The system come back to the list view on 'save' current page.
342
             view_mode=['form', 'tree'], view_type='form', source=None, domain=[], context={},
3901 by sma(Tiny)
[FIX] Set default limit=50.
343
             offset=0, limit=50, count=0, search_domain=None,
2939.21.24 by Xavier Morel
[IMP] remove redundancies between Form.edit and Form.read
344
             search_data=None, filter_domain=None, **kw):
345
3156 by sma(Tiny)
Fixed remember notepad page for edit/save.
346
        notebook_tab = kw.get('notebook_tab') or 0
2939.21.24 by Xavier Morel
[IMP] remove redundancies between Form.edit and Form.read
347
        params = self._read_form(context, count, domain, filter_domain, id,
348
                                 ids, kw, limit, model, offset, search_data,
3156 by sma(Tiny)
Fixed remember notepad page for edit/save.
349
                                 search_domain, source, view_ids, view_mode,
3863 by Shanta Kabra
[IMP] Allow for switching read-only diagram view to editable
350
                                 view_type, notebook_tab)
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
351
2094 by Navrang Oza
* Fixed navigation problem.
352
        if not params.ids:
353
            params.count = 1
819 by Amit Mendapara
* Reimplemented `edit` and `view` method of `Form` contrllers.
354
355
        return self.create(params)
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
356
357
    @expose()
358
    def cancel(self, **kw):
359
        params, data = TinyDict.split(kw)
360
1750 by Amit Mendapara
* Fixed button=cancel (now continues to next action instead of redirecting to /)
361
        if params.button:
362
            res = self.button_action(params)
363
            if res:
364
                return res
365
            raise redirect('/')
366
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
367
        if not params.id and params.ids:
368
            params.id = params.ids[0]
369
981 by Navrang Oza
* Fixed editable view problem.
370
        if params.id and params.editable:
371
            raise redirect(self.path + "/view", model=params.model,
372
                                               id=params.id,
373
                                               ids=ustr(params.ids),
374
                                               view_ids=ustr(params.view_ids),
375
                                               view_mode=ustr(params.view_mode),
376
                                               domain=ustr(params.domain),
377
                                               context=ustr(params.context),
378
                                               offset=params.offset,
379
                                               limit=params.limit,
380
                                               count=params.count,
2939.1.32 by sma(Tiny)
[IMP] Improved search filter.
381
                                               search_domain=ustr(params.search_domain),
2939.1.40 by sma(Tiny)
[IMP] Improved custom filter widget.
382
                                               search_data = ustr(params.search_data),
383
                                               filter_domain= ustr(params.filter_domain))
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
384
981 by Navrang Oza
* Fixed editable view problem.
385
        params.view_type = 'tree'
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
386
        return self.create(params)
387
3327 by noz
[FIX] CSRF vulnerability (bug #632935).
388
    @expose(methods=('POST',))
2055 by Amit Mendapara
* Generic validation schema generator for all Form controllers
389
    @validate(form=get_validation_schema)
2158 by ame (Tiny/Axelor)
* Added default error handler
390
    @error_handler(default_error_handler)
391
    @exception_handler(default_exception_handler)
392
    def save(self, terp_save_only=False, **kw):
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
393
        """Controller method to save/button actions...
394
395
        @param tg_errors: TG special arg, used durring validation
396
        @param kw: keyword arguments
397
398
        @return: form view
399
        """
400
        params, data = TinyDict.split(kw)
2169 by ame (Tiny/Axelor)
[IMP] Remember active page of notebooks.
401
        # remember the current page (tab) of notebooks
402
        cherrypy.session['remember_notebooks'] = True
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
403
3884.1.3 by Xavier Morel
[IMP] simplify and deduplicate model-saving code in form.Form.save
404
        Model = rpc.RPCProxy(params.model)
4106 by sma(Tiny)
[FIX] Bypass save, for button action in non-editable view.
405
        # bypass save, for button action in non-editable view
4141 by sma(Tiny)
[FIX] Now always save in editable mode.
406
        if params.editable:
4106 by sma(Tiny)
[FIX] Bypass save, for button action in non-editable view.
407
            if not params.id:
408
409
                if params.default_o2m:
410
                    data.update(params.default_o2m)
411
                ctx = dict((params.context or {}), **rpc.session.context)
412
                params.id = int(Model.create(data, ctx))
413
                params.ids = (params.ids or []) + [params.id]
414
                params.count += 1
415
            else:
4670.67.1 by msh-openerp
[FIX]Fixed the issue of context in read which is forgotten when calling read method.
416
                ctx = dict((params.context or {}), **rpc.session.context)
417
                original_data = Model.read(params.id, data.keys(), ctx)
4615 by Xavier Morel
[FIX] only send values for modified fields when calling write() for an object edition
418
                modified = {}
4637 by Mohammed Shekha(OpenERP)
[FIX] Basic condition checked for empty dict (checked for modified data else form data).
419
                
4638 by Mohammed Shekha(OpenERP)
[FIX] Fixed mistake in condition.
420
                if original_data and isinstance(original_data, dict):
4637 by Mohammed Shekha(OpenERP)
[FIX] Basic condition checked for empty dict (checked for modified data else form data).
421
                    for field, original_value in original_data.iteritems():
422
                        if isinstance(original_value, tuple):
423
                            original_data[field] = original_value[0]
424
                        if field in data and data[field] != original_data[field]:
4670.24.2 by Mohammed Shekha(Open ERP)
[FIX]Changed the code for save many2many field.
425
                            #When field is many2many at that time following code will be applied
426
                            if isinstance(data[field], list) and isinstance(data[field][0][2], list):
4670.24.1 by Mohammed Shekha(Open ERP)
[FIX]Fixed the issue, data of many2manysended in write method even it is not modified
427
                                if sorted(data[field][0][2]) != sorted(original_data[field]):
428
                                    modified[field] = data[field]
429
                            else:
430
                                modified[field] = data[field]
4615 by Xavier Morel
[FIX] only send values for modified fields when calling write() for an object edition
431
4637 by Mohammed Shekha(OpenERP)
[FIX] Basic condition checked for empty dict (checked for modified data else form data).
432
                    ctx = utils.context_with_concurrency_info(params.context, params.concurrency_info)
4670.133.2 by Xavier ALT
[FIX] web: call write on object if there is *some* data to be written, otherwise this confuse concurrency info handling
433
                    if modified:
434
                        Model.write([params.id], modified, ctx)
4637 by Mohammed Shekha(OpenERP)
[FIX] Basic condition checked for empty dict (checked for modified data else form data).
435
                else:
436
                    ctx = utils.context_with_concurrency_info(params.context, params.concurrency_info)
4670.133.2 by Xavier ALT
[FIX] web: call write on object if there is *some* data to be written, otherwise this confuse concurrency info handling
437
                    if data:
438
                        Model.write([params.id], data, ctx)
4106 by sma(Tiny)
[FIX] Bypass save, for button action in non-editable view.
439
440
            tw.ConcurrencyInfo.update(
441
                params.model, Model.read([params.id], ['__last_update'], ctx)
442
            )
443
4066 by vda(Open ERP)
[FIX] Updated session params(When performing button action and if TinyWarning raise,update current record value).
444
        cherrypy.request.params = params
3884.1.3 by Xavier Morel
[IMP] simplify and deduplicate model-saving code in form.Form.save
445
961 by Amit Mendapara
* Now `Button click` preserves `edit mode`
446
        button = params.button
981 by Navrang Oza
* Fixed editable view problem.
447
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
448
        # perform button action
449
        if params.button:
450
            res = self.button_action(params)
451
            if res:
452
                return res
453
1005 by Amit Mendapara
* Reimplemented `TinyDict` to prevent name conflicts
454
        current = params.chain_get(params.source or '')
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
455
        if current:
456
            current.id = None
961 by Amit Mendapara
* Now `Button click` preserves `edit mode`
457
        elif not button:
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
458
            params.editable = False
459
460
        if terp_save_only:
461
            return dict(params=params, data=data)
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
462
2926 by sma(Tiny)
[FIX] Fixed nested o2m in o2m popup.
463
        def get_params(p, f):
464
465
            pp = p.chain_get(f)
466
            px = rpc.RPCProxy(p.model)
467
468
            _ids = pp.ids
469
            _all = px.read([p.id], [f])[0][f]
470
            _new = [i for i in _all if i not in _ids]
471
472
            pp.ids = _all
473
            if _new:
474
                pp.id = _new[0]
475
476
            return pp
477
478
        if params.source and len(params.source.split("/")) > 1:
479
480
            path = params.source.split("/")
481
            p = params
482
            for f in path:
483
                p = get_params(p, f)
484
485
            return self.create(params)
905 by Navrang Oza
* Fixed bug in on_change.
486
824 by Amit Mendapara
* Fixed navigation problem.
487
        args = {'model': params.model,
488
                'id': params.id,
489
                'ids': ustr(params.ids),
832 by Amit Mendapara
* Fixed `VIEW, EDIT` controller (missing domain, context).
490
                'view_ids': ustr(params.view_ids),
841 by Amit Mendapara
* Better `view_id` selection from current view instead of original view...
491
                'view_mode': ustr(params.view_mode),
832 by Amit Mendapara
* Fixed `VIEW, EDIT` controller (missing domain, context).
492
                'domain': ustr(params.domain),
493
                'context': ustr(params.context),
824 by Amit Mendapara
* Fixed navigation problem.
494
                'offset': params.offset,
495
                'limit': params.limit,
496
                'count': params.count,
2939.1.32 by sma(Tiny)
[IMP] Improved search filter.
497
                'search_domain': ustr(params.search_domain),
2939.1.40 by sma(Tiny)
[IMP] Improved custom filter widget.
498
                'search_data': ustr(params.search_data),
3156 by sma(Tiny)
Fixed remember notepad page for edit/save.
499
                'filter_domain': ustr(params.filter_domain),
500
                'notebook_tab': params.notebook_tab}
4670.77.1 by Xavier ALT
[FIX] web: keep wizard without toolbar buttons (new, save, pager, etc...) when clicking on a wizard button
501
        if params.view_target and params.view_target == 'new':
502
            # within a wizard popup dialog - keep the orignal target mode
503
            # (here target='new' will hide toolbar buttons (new, save, pager, etc..)
4670.77.2 by Xavier ALT
[FIX] assign attribute directly
504
            args['target'] = 'new'
4395 by Xavier Morel
[FIX] clicking on line edition in editable o2m with unsaved parent, save parent and redisplay
505
        if params.o2m_edit:
506
            # hack to avoid creating new record line when editing o2m inline:
507
            # by default one2many.mako is going to fetch a new line (.create)
508
            # on /edit
509
            args['o2m_edit'] = "1"
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
510
1172 by Amit Mendapara
* Save & Edit
511
        if params.editable or params.source or params.return_edit:
826 by Amit Mendapara
* Fixed `New` record problem for O2M fields (form mode).
512
            raise redirect(self.path + '/edit', source=params.source, **args)
824 by Amit Mendapara
* Fixed navigation problem.
513
        raise redirect(self.path + '/view', **args)
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
514
3815 by Xavier Morel
[REF] split button_action into a separate method for each button type
515
    def button_action_cancel(self, name, params):
516
        if name:
517
            params.button.btype = "object"
518
            params.id = False
519
            res = self.button_action(params)
520
            if res:
521
                return res
522
523
        import actions
4054.1.1 by Xavier Morel
[FIX] do not reload content view when closing a dialog with a special=cancel button
524
        return actions.close_popup(reload=False)
3815 by Xavier Morel
[REF] split button_action into a separate method for each button type
525
    def button_action_save(self, _, params):
526
        params.id = False
527
        params.button = None
528
529
    def button_action_workflow(self, name, params):
3817 by Xavier Morel
[IMP] rename unused return values to make clear we don't care about them
530
        model, id, _, _ = self._get_button_infos(params)
3815 by Xavier Morel
[REF] split button_action into a separate method for each button type
531
        res = rpc.session.execute('object', 'exec_workflow', model, name, id)
532
        if isinstance(res, dict):
533
            import actions
534
            return actions.execute(res, ids=[id])
535
        params.button = None
536
537
    def button_action_object(self, name, params):
538
        model, id, ids, ctx = self._get_button_infos(params)
539
540
        res = rpc.session.execute('object', 'execute', model, name, ids, ctx)
4427 by Xavier Morel
[IMP] reload context after executing some type of action
541
        # after installation of modules (esp. initial) we may
542
        # need values from the global context for some contexts & domains (e.g.
543
        # leads) => installer wizards are generally postfixed by '.installer'
544
        # so use this characteristic to setup context reloads
545
        if model.endswith('.installer'):
546
            rpc.session.context_reload()
3815 by Xavier Morel
[REF] split button_action into a separate method for each button type
547
        if isinstance(res, dict):
548
            import actions
4420 by Xavier Morel
[FIX] forward current local context when executing actions, otherwise we lose filtering data & stuff. Fixes journal item's Journal selection (journal_id, clamped by the 'journal_type' context value)
549
            return actions.execute(res, ids=[id], context=ctx)
3815 by Xavier Morel
[REF] split button_action into a separate method for each button type
550
        params.button = None
551
552
    def button_action_action(self, name, params):
553
        model, id, ids, ctx = self._get_button_infos(params)
554
        import actions
555
556
        action_id = int(name)
557
        action_type = actions.get_action_type(action_id)
558
559
        if action_type == 'ir.actions.wizard':
560
            cherrypy.session['wizard_parent_form'] = self.path
561
            cherrypy.session['wizard_parent_params'] = params.parent_params or params
562
563
        res = actions.execute_by_id(
564
                action_id, type=action_type,
565
                model=model, id=id, ids=ids,
566
                context=ctx or {})
567
        if res:
568
            return res
569
        params.button = None
570
571
    BUTTON_ACTIONS_BY_BTYPE = {
3816 by Xavier Morel
[IMP] sort keys of BUTTON_ACTIONS_BY_BTYPE for improved readability
572
        'action': button_action_action,
3815 by Xavier Morel
[REF] split button_action into a separate method for each button type
573
        'cancel': button_action_cancel,
3816 by Xavier Morel
[IMP] sort keys of BUTTON_ACTIONS_BY_BTYPE for improved readability
574
        'object': button_action_object,
3815 by Xavier Morel
[REF] split button_action into a separate method for each button type
575
        'save': button_action_save,
576
        'workflow': button_action_workflow,
577
    }
578
579
    def _get_button_infos(self, params):
580
        model = params.button.model
581
        id = params.button.id or params.id
3451 by sma(Tiny)
[FIX] Fixed button action when performed from calendar or gantt views.
582
        id = (id or False) and (id)
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
583
        ids = (id or []) and [id]
2939.24.74 by sma(Tiny)
[IMP] Improved reviewed code.
584
        ctx = dict((params.context or {}), **rpc.session.context)
3815 by Xavier Morel
[REF] split button_action into a separate method for each button type
585
        ctx.update(params.button.context or {})
586
        return model, id, ids, ctx
587
588
    def button_action(self, params):
589
        button_name = openobject.ustr(params.button.name)
590
        button_name = button_name.rsplit('/', 1)[-1]
591
592
        btype = params.button.btype
593
        try:
594
            return self.BUTTON_ACTIONS_BY_BTYPE[btype](self, button_name, params)
595
        except KeyError:
596
            raise common.warning(_('Invalid button type "%s"') % btype)
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
597
598
    @expose()
1103 by Amit Mendapara
* Duplicate is moved from Search View to Browsable View
599
    def duplicate(self, **kw):
600
        params, data = TinyDict.split(kw)
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
601
4670.137.2 by Xavier ALT
[FIX] web: uppon duplication make sure 'ids' is a list not False - courtesy of Quentin THEURET
602
        if not params.ids:
603
            params.ids = []
604
1103 by Amit Mendapara
* Duplicate is moved from Search View to Browsable View
605
        id = params.id
606
        ctx = params.context
607
        model = params.model
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
608
1103 by Amit Mendapara
* Duplicate is moved from Search View to Browsable View
609
        proxy = rpc.RPCProxy(model)
2186 by ame (Tiny/Axelor)
[FIX] duplicate warning.
610
        new_id = proxy.copy(id, {}, ctx)
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
611
1103 by Amit Mendapara
* Duplicate is moved from Search View to Browsable View
612
        if new_id:
613
            params.id = new_id
1112 by Amit Mendapara
* Fixed `duplicate` controller
614
            params.ids += [int(new_id)]
1111 by Amit Mendapara
* Fixed `duplicate` controller
615
            params.count += 1
1103 by Amit Mendapara
* Duplicate is moved from Search View to Browsable View
616
617
        args = {'model': params.model,
618
                'id': params.id,
619
                'ids': ustr(params.ids),
620
                'view_ids': ustr(params.view_ids),
621
                'view_mode': ustr(params.view_mode),
622
                'domain': ustr(params.domain),
623
                'context': ustr(params.context),
624
                'offset': params.offset,
625
                'limit': params.limit,
626
                'count': params.count,
2939.1.40 by sma(Tiny)
[IMP] Improved custom filter widget.
627
                'search_domain': ustr(params.search_domain),
628
                'filter_domain': ustr(params.filter_domain)}
1103 by Amit Mendapara
* Duplicate is moved from Search View to Browsable View
629
1166 by Amit Mendapara
* Duplicate now opens in `edit` mode
630
        if new_id:
631
            raise redirect(self.path + '/edit', **args)
632
1103 by Amit Mendapara
* Duplicate is moved from Search View to Browsable View
633
        raise redirect(self.path + '/view', **args)
634
635
    @expose()
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
636
    def delete(self, **kw):
637
        params, data = TinyDict.split(kw)
638
1005 by Amit Mendapara
* Reimplemented `TinyDict` to prevent name conflicts
639
        current = params.chain_get(params.source or '') or params
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
640
        proxy = rpc.RPCProxy(current.model)
641
642
        idx = -1
643
        if current.id:
2870 by ame (Tiny)
[REF] namespace fix
644
            ctx = utils.context_with_concurrency_info(current.context, params.concurrency_info)
2206 by ame (Tiny/Axelor)
[FIX] concurrency problem (form, tree view only).
645
            res = proxy.unlink([current.id], ctx)
4480 by Christophe Simonis
[FIX] be tolerant to invalid value from js
646
            if current.ids:
647
                idx = current.ids.index(current.id)
648
                if idx >= 0:
649
                    current.ids.remove(current.id)
4513 by vda(Open ERP)
[FIX] count incorrect in pager when deleting objects in form view
650
            params.count -= 1
4523 by vda(Open ERP)
[FIX] form view should not go into edition mode (and - / 1) when deleting the last object of a page
651
            if not len(current.ids) and params.count > 0:
652
                params.offset = params.offset - params.limit
653
                current.ids = proxy.search([], params.offset, params.limit,0, ctx)
654
                idx = -1
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
655
            if idx == len(current.ids):
656
                idx = -1
657
        current.id = (current.ids or None) and current.ids[idx]
2939.1.12 by noz at tinyerp
[IMP] Moved reset_notebook function back.
658
        self.reset_notebooks()
905 by Navrang Oza
* Fixed bug in on_change.
659
825 by Amit Mendapara
* Applying `Post/Redirect/Get` pattern for `DELETE` controller.
660
        args = {'model': params.model,
661
                'id': params.id,
662
                'ids': ustr(params.ids),
663
                'view_ids': ustr(params.view_ids),
841 by Amit Mendapara
* Better `view_id` selection from current view instead of original view...
664
                'view_mode': ustr(params.view_mode),
665
                'domain': ustr(params.domain),
666
                'context': ustr(params.context),
825 by Amit Mendapara
* Applying `Post/Redirect/Get` pattern for `DELETE` controller.
667
                'offset': params.offset,
668
                'limit': params.limit,
669
                'count': params.count,
2939.1.40 by sma(Tiny)
[IMP] Improved custom filter widget.
670
                'search_domain': ustr(params.search_domain),
671
                'filter_domain': ustr(params.filter_domain)}
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
672
887 by Amit Mendapara
* Fixed `DELETE and redirect to VIEW` bug...
673
        if not params.id:
674
            raise redirect(self.path + '/edit', **args)
905 by Navrang Oza
* Fixed bug in on_change.
675
825 by Amit Mendapara
* Applying `Post/Redirect/Get` pattern for `DELETE` controller.
676
        raise redirect(self.path + '/view', **args)
905 by Navrang Oza
* Fixed bug in on_change.
677
1414 by Amit Mendapara
* Now uses `Report Name` as filename while printing reports.
678
    @expose(content_type='application/octet-stream')
1521 by Amit Mendapara
* Fixed `save_binary_data` controller
679
    def save_binary_data(self, _fname='file.dat', **kw):
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
680
        params, data = TinyDict.split(kw)
4670.10.2 by Mohammed Shekha(Open ERP)
[FIX]Refixed the issue of Thunder plugin download
681
        
3023 by Xavier Morel
[FIX] issue with downloading binary files in forms
682
        cherrypy.response.headers['Content-Disposition'] = 'attachment; filename="%s"' % _fname
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
683
684
        if params.datas:
685
            form = params.datas['form']
686
            res = form.get(params.field)
687
            return base64.decodestring(res)
3369 by vda(Open ERP)
[IMP] Improved binary, image widget.
688
        
689
        elif params.id:
690
            proxy = rpc.RPCProxy(params.model)
691
            res = proxy.read([params.id],[params.field], rpc.session.context)
692
            return base64.decodestring(res[0][params.field])
693
        else:
694
            return base64.decodestring(data[params.field])
695
        
2939.25.69 by Xavier Morel
[IMP] use os.path.splitext for file extensions management
696
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
697
    @expose()
1017 by Amit Mendapara
* Improved `binary (file upload)` widget, now tries to save file with actual filename.
698
    def clear_binary_data(self, **kw):
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
699
        params, data = TinyDict.split(kw)
700
701
        proxy = rpc.RPCProxy(params.model)
2870 by ame (Tiny)
[REF] namespace fix
702
        ctx = utils.context_with_concurrency_info(params.context, params.concurrency_info)
2206 by ame (Tiny/Axelor)
[FIX] concurrency problem (form, tree view only).
703
1783 by Navrang Oza
* Some improvement in binary widget related to 'filename' attribute.
704
        if params.fname:
2206 by ame (Tiny/Axelor)
[FIX] concurrency problem (form, tree view only).
705
            proxy.write([params.id], {params.field: False, params.fname: False}, ctx)
1783 by Navrang Oza
* Some improvement in binary widget related to 'filename' attribute.
706
        else:
2206 by ame (Tiny/Axelor)
[FIX] concurrency problem (form, tree view only).
707
            proxy.write([params.id], {params.field: False}, ctx)
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
708
2524.2.4 by ame (Tiny/Axelor)
* Reverting back sma's patch
709
        args = {'model': params.model,
710
                'id': params.id,
711
                'ids': ustr(params.ids),
712
                'view_ids': ustr(params.view_ids),
713
                'view_mode': ustr(params.view_mode),
714
                'domain': ustr(params.domain),
715
                'context': ustr(params.context),
716
                'offset': params.offset,
717
                'limit': params.limit,
718
                'count': params.count,
2939.1.40 by sma(Tiny)
[IMP] Improved custom filter widget.
719
                'search_domain': ustr(params.search_domain),
720
                'filter_domain': ustr(params.filter_domain)}
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
721
2524.2.4 by ame (Tiny/Axelor)
* Reverting back sma's patch
722
        raise redirect(self.path + '/edit', **args)
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
723
4447 by Antony Lesuisse
[FIX] binary image on IE
724
    @expose(content_type='image/png')
4422 by Antony Lesuisse
[FIX] correct implementation of binary widget image
725
    def binary_image_get_image(self, **kw):
726
        model = kw.get('model')
727
        field = kw.get('field')
728
        id = kw.get('id')
4670.2.176 by Xavier ALT
[MERGE] OPW 574014: image widget: provided image default to avoid double call to default_get()
729
        default_value = kw.get('default_value')
4422 by Antony Lesuisse
[FIX] correct implementation of binary widget image
730
        proxy = rpc.RPCProxy(model)
731
        if id == 'None':
732
            # FIXME: doesnt honor the context
4670.2.176 by Xavier ALT
[MERGE] OPW 574014: image widget: provided image default to avoid double call to default_get()
733
            res = default_value or proxy.default_get([field]).get(field,'')
4422 by Antony Lesuisse
[FIX] correct implementation of binary widget image
734
        else:
735
            res = proxy.read([int(id)], [field])[0].get(field)
4670.104.1 by cpa-openerp
[FIX] Fixed issue default_get call twice.
736
        if res and res != 'None':
4422 by Antony Lesuisse
[FIX] correct implementation of binary widget image
737
            return base64.decodestring(res)
738
        else:
4454 by Antony Lesuisse
[FIX] binary image use 'rb' flags when opening the placeholder on windows
739
            return open(openobject.paths.addons('openerp','static','images','placeholder.png'),'rb').read()
4422 by Antony Lesuisse
[FIX] correct implementation of binary widget image
740
741
    @expose("json")
742
    def binary_image_delete(self, **kw):
743
        saved = kw.get('saved') or None
744
        model = kw.get('model')
745
        id = kw.get('id')
746
        if id:
747
            id = int(id)
748
        field = kw.get('field')
749
        if id:
750
            proxy = rpc.RPCProxy(model)
751
            proxy.write([id], {field: False})
752
        return {}
753
754
    @expose()
755
    def b64(self, **kw):
756
        #idea from http://dean.edwards.name/weblog/2005/06/base64-ie/
757
        try:
758
            qs = cherrypy.request.query_string
759
            content_type, data = qs.split(';')
760
            data_type, data = data.split(',')
761
            assert(data_type == 'base64')
762
            cherrypy.response.headers['Content-Type'] = content_type
763
            return base64.decodestring(data)
764
        except:
765
            raise cherrypy.HTTPError(400)   # Bad request
766
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
767
    @expose()
2055 by Amit Mendapara
* Generic validation schema generator for all Form controllers
768
    @validate(form=get_validation_schema)
2158 by ame (Tiny/Axelor)
* Added default error handler
769
    @error_handler(default_error_handler)
770
    @exception_handler(default_exception_handler)
771
    def filter(self, **kw):
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
772
        params, data = TinyDict.split(kw)
3161 by vda(Open ERP)
[IMP] Improved confirmation before switching to other options.
773
        if params.get('_terp_save_current_id'):
774
            ctx = dict((params.context or {}), **rpc.session.context)
3312 by vda(Open ERP)
[FIX] Fixed validation for form when create new records.
775
            if params.id:
776
                rpc.RPCProxy(params.model).write([params.id], data, ctx)
777
            else:
778
                id = rpc.RPCProxy(params.model).create(data, ctx)
779
                params.ids.append(id)
780
                params.count += 1
3161 by vda(Open ERP)
[IMP] Improved confirmation before switching to other options.
781
            
3901 by sma(Tiny)
[FIX] Set default limit=50.
782
        l = params.limit or 50
1005 by Amit Mendapara
* Reimplemented `TinyDict` to prevent name conflicts
783
        o = params.offset or 0
1110 by Amit Mendapara
* Reimplemented `filter` controller
784
        c = params.count or 0
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
785
1110 by Amit Mendapara
* Reimplemented `filter` controller
786
        id = params.id or False
787
        ids = params.ids or []
788
        filter_action = params.filter_action
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
789
1110 by Amit Mendapara
* Reimplemented `filter` controller
790
        if ids and filter_action == 'FIRST':
791
            o = 0
792
            id = ids[0]
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
793
1110 by Amit Mendapara
* Reimplemented `filter` controller
794
        if ids and filter_action == 'LAST':
795
            o = c - c % l
796
            id = ids[-1]
797
798
        if ids and filter_action == 'PREV':
799
            if id == ids[0]:
800
                o -= l
801
            elif id in ids:
802
                id = ids[ids.index(id)-1]
803
804
        if ids and filter_action == 'NEXT':
805
            if id == ids[-1]:
806
                o += l
807
            elif id in ids:
808
                id = ids[ids.index(id)+1]
3620 by Xavier Morel
[IMP] tests against True/False specifically should be identity tests (via is)
809
            elif id is False:
2801 by sma
[FIX] Fixed Button Next when create new record.
810
                o = 0
811
                id = ids[0]
1110 by Amit Mendapara
* Reimplemented `filter` controller
812
1173 by Amit Mendapara
* Improved `form` controller (remember notebook tab during navigation)
813
        if filter_action:
2169 by ame (Tiny/Axelor)
[IMP] Remember active page of notebooks.
814
            # remember the current page (tab) of notebooks
815
            cherrypy.session['remember_notebooks'] = True
1173 by Amit Mendapara
* Improved `form` controller (remember notebook tab during navigation)
816
1110 by Amit Mendapara
* Reimplemented `filter` controller
817
        if params.offset != o:
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
818
819
            domain = params.domain
1110 by Amit Mendapara
* Reimplemented `filter` controller
820
            if params.search_domain is not None:
821
                domain = params.search_domain
822
                data = params.search_data
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
823
2811 by sma
[FIX] Fixed context problem in search.
824
            ctx = params.context or {}
825
            ctx.update(rpc.session.context.copy())
826
            res = search(params.model, o, l, domain=domain, context=ctx, data=data)
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
827
1110 by Amit Mendapara
* Reimplemented `filter` controller
828
            o = res['offset']
829
            l = res['limit']
3621 by Xavier Morel
[FIX] Form.filter should not overwrite count on page change
830
            if not c: c = res['count']
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
831
1212 by Amit Mendapara
* Fixed `filter` controller
832
            params.search_domain = res['search_domain']
833
            params.search_data = res['search_data']
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
834
1110 by Amit Mendapara
* Reimplemented `filter` controller
835
            ids = res['ids']
836
            id = False
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
837
1110 by Amit Mendapara
* Reimplemented `filter` controller
838
            if ids and filter_action in ('FIRST', 'NEXT'):
839
                id = ids[0]
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
840
1110 by Amit Mendapara
* Reimplemented `filter` controller
841
            if ids and filter_action in ('LAST', 'PREV'):
842
                id = ids[-1]
843
844
        params.id = id
845
        params.ids = ids
846
        params.offset = o
847
        params.limit = l
848
        params.count = c
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
849
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
850
        return self.create(params)
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
851
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
852
    @expose()
853
    def find(self, **kw):
854
        kw['_terp_offset'] = None
855
        kw['_terp_limit'] = None
856
857
        kw['_terp_search_domain'] = None
858
        kw['_terp_search_data'] = None
2295.1.10 by ame (Tiny/Axelor)
[FIX] remember active page while searching.
859
        kw['_terp_filter_action'] = 'FIND'
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
860
861
        return self.filter(**kw)
862
863
    @expose()
864
    def first(self, **kw):
865
        kw['_terp_filter_action'] = 'FIRST'
1110 by Amit Mendapara
* Reimplemented `filter` controller
866
        return self.filter(**kw)
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
867
1110 by Amit Mendapara
* Reimplemented `filter` controller
868
    @expose()
869
    def last(self, **kw):
870
        kw['_terp_filter_action'] = 'LAST'
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
871
        return self.filter(**kw)
872
873
    @expose()
874
    def previous(self, **kw):
1110 by Amit Mendapara
* Reimplemented `filter` controller
875
        if '_terp_source' in kw:
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
876
            return self.previous_o2m(**kw)
877
878
        kw['_terp_filter_action'] = 'PREV'
1110 by Amit Mendapara
* Reimplemented `filter` controller
879
        return self.filter(**kw)
880
881
    @expose()
2094 by Navrang Oza
* Fixed navigation problem.
882
    def next(self, **kw):
1110 by Amit Mendapara
* Reimplemented `filter` controller
883
        if '_terp_source' in kw:
884
            return self.next_o2m(**kw)
885
886
        kw['_terp_filter_action'] = 'NEXT'
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
887
        return self.filter(**kw)
888
889
    @expose()
3161 by vda(Open ERP)
[IMP] Improved confirmation before switching to other options.
890
    @validate(form=get_validation_schema)
891
    @error_handler(default_error_handler)
892
    @exception_handler(default_exception_handler)
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
893
    def previous_o2m(self, **kw):
894
        params, data = TinyDict.split(kw)
3161 by vda(Open ERP)
[IMP] Improved confirmation before switching to other options.
895
        
896
        if params.get('_terp_save_current_id'):
897
            ctx = dict((params.context or {}), **rpc.session.context)
3312 by vda(Open ERP)
[FIX] Fixed validation for form when create new records.
898
            if params.id:
899
                rpc.RPCProxy(params.model).write([params.id], data, ctx)
900
            else:
901
                id = rpc.RPCProxy(params.model).create(data, ctx)
902
                params.ids.append(id)
903
                params.count += 1
3161 by vda(Open ERP)
[IMP] Improved confirmation before switching to other options.
904
        
1005 by Amit Mendapara
* Reimplemented `TinyDict` to prevent name conflicts
905
        current = params.chain_get(params.source or '') or params
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
906
        idx = -1
3161 by vda(Open ERP)
[IMP] Improved confirmation before switching to other options.
907
        
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
908
        if current.id:
909
            # save current record
910
            if params.editable:
911
                self.save(terp_save_only=True, **kw)
912
913
            idx = current.ids.index(current.id)
914
            idx = idx-1
915
916
            if idx == len(current.ids):
917
                idx = len(current.ids) -1
918
919
        if current.ids:
920
            current.id = current.ids[idx]
921
922
        return self.create(params)
923
924
    @expose()
925
    def next_o2m(self, **kw):
926
        params, data = TinyDict.split(kw)
1005 by Amit Mendapara
* Reimplemented `TinyDict` to prevent name conflicts
927
        c = params.count or 0
928
        current = params.chain_get(params.source or '') or params
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
929
930
        idx = 0
931
        if current.id:
932
933
            # save current record
934
            if params.editable:
935
                self.save(terp_save_only=True, **kw)
936
937
            idx = current.ids.index(current.id)
938
            idx = idx + 1
939
940
            if idx == len(current.ids):
941
                idx = 0
942
943
        if current.ids:
944
            current.id = current.ids[idx]
945
946
        return self.create(params)
947
948
    @expose()
3161 by vda(Open ERP)
[IMP] Improved confirmation before switching to other options.
949
    @validate(form=get_validation_schema)
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
950
    def switch(self, **kw):
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
951
        params, data = TinyDict.split(kw)
3161 by vda(Open ERP)
[IMP] Improved confirmation before switching to other options.
952
        if params.get('_terp_save_current_id'):
953
            ctx = dict((params.context or {}), **rpc.session.context)
3312 by vda(Open ERP)
[FIX] Fixed validation for form when create new records.
954
            if params.id:
955
                rpc.RPCProxy(params.model).write([params.id], data, ctx)
956
            else:
957
                id = rpc.RPCProxy(params.model).create(data, ctx)
958
                params.ids.append(id)
959
                params.count += 1
1054 by Amit Mendapara
* Fixed SWITCH problem
960
        # switch the view
1537 by Amit Mendapara
* switch controller cleanup (remove o2m related code)
961
        params.view_type = params.source_view_type
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
962
        return self.create(params)
963
964
    def do_action(self, name, adds={}, datas={}):
965
        params, data = TinyDict.split(datas)
966
967
        model = params.model
905 by Navrang Oza
* Fixed bug in on_change.
968
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
969
        id = params.id or False
2939.24.48 by sma(Tiny)
[FIX] sidebar wizard without wizard id.
970
        ids = params.selection or params.ids or []
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
971
841 by Amit Mendapara
* Better `view_id` selection from current view instead of original view...
972
        if params.view_type == 'form':
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
973
            #TODO: save current record
974
            ids = (id or []) and [id]
905 by Navrang Oza
* Fixed bug in on_change.
975
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
976
        if id and not ids:
977
            ids = [id]
978
979
        if len(ids):
2812 by ame (Tiny)
[IMP] initial work on addons
980
            import actions
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
981
            return actions.execute_by_keyword(name, adds=adds, model=model, id=id, ids=ids, report_type='pdf')
982
        else:
3859 by vda(Open ERP)
[FIX] Activated contextual menu actions.
983
            raise common.message(_("No record selected"))    
984
    
985
    @expose()
986
    def report(self, **kw):
987
        return self.do_action('client_print_multi', adds={'Print Screen': {'report_name':'printscreen.list',
988
                                                                           'name': _('Print Screen'),
989
                                                                           'type':'ir.actions.report.xml'}}, datas=kw)
990
    
1169 by Amit Mendapara
* Links (relate) on sidebar now opens in the same window
991
    @expose()
1414 by Amit Mendapara
* Now uses `Report Name` as filename while printing reports.
992
    def action(self, **kw):
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
993
        params, data = TinyDict.split(kw)
4670.2.59 by Olivier Dony
[FIX] actions: watch out for context_menu=None + another fix for actions execution
994
        context_menu = kw.get('context_menu') or False
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
995
2524.2.32 by ame (Tiny/Axelor)
[FIX] long URI problem (relate links) bug #381243
996
        id = params.id or False
997
        ids = params.selection or []
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
998
2524.2.32 by ame (Tiny/Axelor)
[FIX] long URI problem (relate links) bug #381243
999
        if not ids and id:
1000
            ids = [id]
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
1001
2524.2.32 by ame (Tiny/Axelor)
[FIX] long URI problem (relate links) bug #381243
1002
        if not id and ids:
1003
            id = ids[0]
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
1004
2524.2.32 by ame (Tiny/Axelor)
[FIX] long URI problem (relate links) bug #381243
1005
        domain = params.domain or []
4670.2.56 by Olivier Dony
[FIX] actions: fix side-effect of previous bugfix (thanks to S.Bidoul for the heads up!)
1006
        context = params.context or {}
3354 by sma(Tiny)
[FIX] Fixed action when data is empty.
1007
        action = {}
1008
1009
        if data.get('datas'):
1010
            action = eval(data.get('datas'))
3353 by sma(Tiny)
[FIX] Speed Improvement and Report actions to follow data dictionary instead of id.
1011
        type = action.get('type')
2524.2.32 by ame (Tiny/Axelor)
[FIX] long URI problem (relate links) bug #381243
1012
        act_id = params.action
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
1013
2524.2.32 by ame (Tiny/Axelor)
[FIX] long URI problem (relate links) bug #381243
1014
        if not act_id:
1015
            return self.do_action('client_action_multi', datas=kw)
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
1016
3353 by sma(Tiny)
[FIX] Speed Improvement and Report actions to follow data dictionary instead of id.
1017
        if type is None:
4670.2.56 by Olivier Dony
[FIX] actions: fix side-effect of previous bugfix (thanks to S.Bidoul for the heads up!)
1018
            action_type = rpc.RPCProxy('ir.actions.actions').read(act_id, ['type'], context)['type']
4670.2.59 by Olivier Dony
[FIX] actions: watch out for context_menu=None + another fix for actions execution
1019
            tmp_ctx = dict(context)
1020
            if action_type == 'ir.actions.report.xml':
1021
                # avoid reading large binary values that we won't even care about
1022
                tmp_ctx['bin_size'] = True
1023
            action = rpc.session.execute('object', 'execute', action_type, 'read', act_id, False, tmp_ctx)
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
1024
3725 by sma(Tiny)
[FIX] Fixed domain for actions.
1025
        if domain:
3726 by sma(Tiny)
[FIX] Minor changes before extend, check for basestring.
1026
            if isinstance(domain, basestring):
1027
                domain = eval(domain)
4177 by noz (Open ERP)
[FIX] Domain evaluated properly.
1028
            domain.extend(expr_eval(action.get('domain', '[]'), context))
3725 by sma(Tiny)
[FIX] Fixed domain for actions.
1029
            action['domain'] = ustr(domain)
1030
4670.66.1 by msh-openerp
[FIX]Fixed the issue of search view when new tab opened from act_window.
1031
        if context.get('search_view'):
1032
            context.pop('search_view')
4517 by sma(Tiny)
[FIX] context propagation during form action was incorrect and would lead to missing values at evaluation
1033
        action['form_context'] = context or {}
2812 by ame (Tiny)
[IMP] initial work on addons
1034
        import actions
3403 by sma(Tiny)
[IMP] Add close button tab/popup open from contextmenu.
1035
        return actions.execute(action, model=params.model, id=id, ids=ids, report_type='pdf', context_menu=context_menu)
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
1036
1037
    @expose()
1038
    def dashlet(self, **kw):
1039
        params, data = TinyDict.split(kw)
1005 by Amit Mendapara
* Reimplemented `TinyDict` to prevent name conflicts
1040
        current = params.chain_get(str(params.source) or '') or params
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
1041
1042
        return self.create(current)
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
1043
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
1044
    @expose('json')
1045
    def on_change(self, **kw):
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
1046
1291 by Amit Mendapara
* Improved `ONCHANGE` implementation (validators + reduced M2O Ajax calls).
1047
        data = kw.copy()
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
1048
1291 by Amit Mendapara
* Improved `ONCHANGE` implementation (validators + reduced M2O Ajax calls).
1049
        callback = data.pop('_terp_callback')
1050
        caller = data.pop('_terp_caller')
1051
        model = data.pop('_terp_model')
2092 by Amit Mendapara
* Fixed onchange.
1052
        context = data.pop('_terp_context')
4670.23.2 by Mohammed Shekha(Open ERP)
[FIX]Removed the trailing space from the branch.
1053
4670.23.1 by Mohammed Shekha(Open ERP)
[FIX]Fixed the issue of onChange and setDefault on Same field due to that change_default_get was not called.
1054
        change_default = False
1055
        if '_terp_change_default' in data:
1056
            change_default = data.pop('_terp_change_default')
2092 by Amit Mendapara
* Fixed onchange.
1057
1058
        try:
1059
            context = eval(context) # convert to python dict
1060
        except:
1061
            context = {}
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
1062
1291 by Amit Mendapara
* Improved `ONCHANGE` implementation (validators + reduced M2O Ajax calls).
1063
        match = re.match('^(.*?)\((.*)\)$', callback)
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
1064
1291 by Amit Mendapara
* Improved `ONCHANGE` implementation (validators + reduced M2O Ajax calls).
1065
        if not match:
3147 by noz
[FIX] Improved Error String (Removed ! from Error Messages).
1066
            raise common.error(_('Application Error'), _('Wrong on_change trigger: %s') % callback)
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
1067
1291 by Amit Mendapara
* Improved `ONCHANGE` implementation (validators + reduced M2O Ajax calls).
1068
        for k, v in data.items():
1069
            try:
1070
                data[k] = eval(v)
1071
            except:
1072
                pass
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
1073
1074
        result = {}
1075
1076
        prefix = ''
1077
        if '/' in caller:
1078
            prefix = caller.rsplit('/', 1)[0]
1079
2524.1.13 by ame (Tiny/Axelor)
* Improved Ajax validator (fixes onchange problem when there is some invalid value in the form)
1080
        ctx = TinyForm(**kw).to_python(safe=True)
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
1081
        pctx = ctx
1082
1083
        if prefix:
1005 by Amit Mendapara
* Reimplemented `TinyDict` to prevent name conflicts
1084
            ctx = ctx.chain_get(prefix)
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
1085
1086
            if '/' in prefix:
1291 by Amit Mendapara
* Improved `ONCHANGE` implementation (validators + reduced M2O Ajax calls).
1087
                pprefix = prefix.rsplit('/', 1)[0]
1088
                pctx = pctx.chain_get(pprefix)
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
1089
4307 by Xavier Morel
[FIX] don't send an empty dictionary if can't find a value to eval in the context in onchanges, makes no sense and breaks callbacks
1090
        ctx2 = dict(rpc.session.context,
1091
                    **context or {})
2092 by Amit Mendapara
* Fixed onchange.
1092
1005 by Amit Mendapara
* Reimplemented `TinyDict` to prevent name conflicts
1093
        ctx['parent'] = pctx
2092 by Amit Mendapara
* Fixed onchange.
1094
        ctx['context'] = ctx2
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
1095
1096
        func_name = match.group(1)
1097
        arg_names = [n.strip() for n in match.group(2).split(',')]
1098
4307 by Xavier Morel
[FIX] don't send an empty dictionary if can't find a value to eval in the context in onchanges, makes no sense and breaks callbacks
1099
        args = [utils.expr_eval(arg, ctx) for arg in arg_names]
1100
        # TODO: If the eval fails in expr_eval (because `arg` does not exist in `ctx`), it returns `{}`
1101
        # This is a value we don't want, but not sure where that behavior
1102
        # comes from/is used so in order not to risk breakage throughout
1103
        # patch it here
1104
        args = [(False if arg == {} else arg)
1105
                for arg in args]
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
1106
1107
        proxy = rpc.RPCProxy(model)
1108
4670.91.2 by msh-openerp
[FIX]Refixed the issue of id not passed one2many on_change.
1109
        ids = ctx.id and [ctx.id] or ctx.parent.id and [ctx.parent.id] or []
1016 by Navrang Oza
* Fixed navigation problem in view mode.
1110
1020 by Navrang Oza
* Displaying error messages if any during on_change.
1111
        try:
1112
            response = getattr(proxy, func_name)(ids, *args)
1113
        except Exception, e:
2939.25.24 by sma(Tiny)
[IMP] Improved maintenance stuff.
1114
             return dict(error=_ep.render())
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
1115
2448 by noz
* Fixed `on_change` when creating new record for inherited view.
1116
        if response is False: # response is False when creating new record for inherited view.
1117
            response = {}
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
1118
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
1119
        if 'value' not in response:
1120
            response['value'] = {}
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
1121
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
1122
        result.update(response)
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
1123
1291 by Amit Mendapara
* Improved `ONCHANGE` implementation (validators + reduced M2O Ajax calls).
1124
        # apply validators (transform values from python)
1125
        values = result['value']
1126
        values2 = {}
1127
        for k, v in values.items():
1128
            key = ((prefix or '') and prefix + '/') + k
2939.25.69 by Xavier Morel
[IMP] use os.path.splitext for file extensions management
1129
2939.24.74 by sma(Tiny)
[IMP] Improved reviewed code.
1130
            kind = data.get(key, {}).get('type', '')
1291 by Amit Mendapara
* Improved `ONCHANGE` implementation (validators + reduced M2O Ajax calls).
1131
2474.1.2 by noz
* Fixed onchange problem.
1132
            if key in data and key != 'id':
1291 by Amit Mendapara
* Improved `ONCHANGE` implementation (validators + reduced M2O Ajax calls).
1133
                values2[k] = data[key]
1134
                values2[k]['value'] = v
1135
            else:
1136
                values2[k] = {'value': v}
2939.25.69 by Xavier Morel
[IMP] use os.path.splitext for file extensions management
1137
2939.24.14 by sma(Tiny)
[FIX] Fixed price_accuracy for float (#459027).
1138
            if kind == 'float':
1139
                field = proxy.fields_get([k], ctx2)
1140
                digit = field[k].get('digits')
1141
                if digit: digit = digit[1]
1142
                values2[k]['digit'] = digit or 2
1291 by Amit Mendapara
* Improved `ONCHANGE` implementation (validators + reduced M2O Ajax calls).
1143
1324 by Amit Mendapara
* Reimplemented `TinyForm`, now also converts values from server to local.
1144
        values = TinyForm(**values2).from_python().make_plain()
1291 by Amit Mendapara
* Improved `ONCHANGE` implementation (validators + reduced M2O Ajax calls).
1145
1146
        # get name of m2o and reference fields
1147
        for k, v in values2.items():
1148
            kind = v.get('type')
1149
            relation = v.get('relation')
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
1150
1291 by Amit Mendapara
* Improved `ONCHANGE` implementation (validators + reduced M2O Ajax calls).
1151
            if relation and kind in ('many2one', 'reference') and values.get(k):
4021.1.2 by sma(Tiny)
[FIX] minor changes.
1152
                values[k] = [values[k], rpc.name_get(relation, values[k], context)]
1291 by Amit Mendapara
* Improved `ONCHANGE` implementation (validators + reduced M2O Ajax calls).
1153
2295.1.5 by ame (Tiny/Axelor)
[IMP] onchange (duplicate json value)
1154
        result['value'] = values
905 by Navrang Oza
* Fixed bug in on_change.
1155
1156
        # convert domains in string to prevent them being converted in JSON
1157
        if 'domain' in result:
1158
            for k in result['domain']:
1159
                result['domain'][k] = ustr(result['domain'][k])
4670.23.2 by Mohammed Shekha(Open ERP)
[FIX]Removed the trailing space from the branch.
1160
4670.23.1 by Mohammed Shekha(Open ERP)
[FIX]Fixed the issue of onChange and setDefault on Same field due to that change_default_get was not called.
1161
        if change_default:
1162
            value = data.get('_terp_value')
1163
            proxy = rpc.RPCProxy('ir.values')
1164
            values = proxy.get('default', '%s=%s' % (caller, value), [(model, False)], False, context)
1165
            for index, fname, value in values:
4670.23.2 by Mohammed Shekha(Open ERP)
[FIX]Removed the trailing space from the branch.
1166
                if fname not in result['value']:
4670.23.1 by Mohammed Shekha(Open ERP)
[FIX]Fixed the issue of onChange and setDefault on Same field due to that change_default_get was not called.
1167
                    result['value'][fname] = value
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
1168
        return result
1169
1170
    @expose('json')
1171
    def get_context_menu(self, model, field, kind="char", relation=None, value=None):
1172
1173
        defaults = []
1174
        actions = []
1175
        relates = []
1176
4454.1.4 by sma(Tiny)
[FIX] Fixed Open Resource for reference widget.
1177
        if kind == "many2one" or kind == "reference":
4350 by vda(Open ERP)
[FIX] Translation of default context menu labels.
1178
            defaults.append({'text': _('Open resource'), 'action': "new ManyToOne('%s').open_record('%s')" % (field, value)})
3938 by Fabien Meghazi
[IMP] Left click on icon of m2o should bring the contextual menu and the first option should be "Open this item"
1179
1180
        defaults += [
4350 by vda(Open ERP)
[FIX] Translation of default context menu labels.
1181
            {'text': _('Set to default value'), 'action': "set_to_default('%s', '%s')" % (field, model)},
1182
            {'text': _('Set as default'), 'action': "set_as_default('%s', '%s')"  % (field, model)}
3938 by Fabien Meghazi
[IMP] Left click on icon of m2o should bring the contextual menu and the first option should be "Open this item"
1183
        ]
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
1184
1185
        if kind=='many2one':
1186
1187
            act = (value or None) and "javascript: void(0)"
1188
4350 by vda(Open ERP)
[FIX] Translation of default context menu labels.
1189
            actions = [{'text': _('Action'), 'relation': relation, 'field': field, 'action': act and "do_action(this, true)"},
1190
                       {'text': _('Report'), 'action': act and "do_report('%s', '%s')" %(field, relation)}]
3859 by vda(Open ERP)
[FIX] Activated contextual menu actions.
1191
            
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
1192
            res = rpc.RPCProxy('ir.values').get('action', 'client_action_relate', [(relation, False)], False, rpc.session.context)
1193
            res = [x[2] for x in res]
1194
1195
            for x in res:
1196
                act = (value or None) and "javascript: void(0)"
1197
                x['string'] = x['name']
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
1198
                relates += [{'text': '... '+x['name'],
3860 by vda(Open ERP)
[FIX] Forgot to change attrs of function call for do_action.
1199
                             'action_id': x['id'],
1200
                             'field': field,
1201
                             'relation': relation,
1202
                             'action': act and "do_action(this, true)",
2524.2.32 by ame (Tiny/Axelor)
[FIX] long URI problem (relate links) bug #381243
1203
                             'domain': x.get('domain', []),
1204
                             'context': x.get('context', {})}]
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
1205
1206
        return dict(defaults=defaults, actions=actions, relates=relates)
1207
1208
    @expose('json')
1209
    def get_default_value(self, model, field):
1210
1211
        field = field.split('/')[-1]
905 by Navrang Oza
* Fixed bug in on_change.
1212
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
1213
        res = rpc.RPCProxy(model).default_get([field])
1214
        value = res.get(field)
905 by Navrang Oza
* Fixed bug in on_change.
1215
817 by Amit Mendapara
* Restructuring directory layout (TG convensions)...
1216
        return dict(value=value)
1217
2939.1.12 by noz at tinyerp
[IMP] Moved reset_notebook function back.
1218
    def reset_notebooks(self):
1219
        for name in cherrypy.request.cookie.keys():
1220
            if name.startswith('_notebook_'):
1221
                cherrypy.response.cookie[name] = 0
1222
2109 by Navrang Oza
* Default value associated to any field will change for that field on change (ex. zip and city).
1223
    @expose('json')
2115 by Amit Mendapara
* Improved change_default/on_change
1224
    def change_default_get(self, **kw):
1225
        params, data = TinyDict.split(kw)
1226
1227
        ctx = rpc.session.context.copy()
1228
        ctx.update(params.context or {})
1229
1230
        model = params.model
1231
        field = params.caller.split('/')[-1]
1232
        value = params.value or False
1233
1234
        proxy = rpc.RPCProxy('ir.values')
1235
        values = proxy.get('default', '%s=%s' % (field, value), [(model, False)], False, ctx)
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
1236
2109 by Navrang Oza
* Default value associated to any field will change for that field on change (ex. zip and city).
1237
        data = {}
1238
        for index, fname, value in values:
1239
            data[fname] = value
2327.1.30 by ame (Tiny/Axelor)
* removed trailing whitespace from py files.
1240
4670.2.63 by msh at openerp
[FIX] opw 19993
1241
        return dict(value=data)
2327.1.32 by ame (Tiny/Axelor)
* converted all subcontrollers
1242
2939.1.97 by noz at tinyerp
[IMP] Improved Shortcut Creation.
1243
    # Possible to create shortcut for particular object or not.
1244
    def can_shortcut_create(self):
3922.1.2 by Xavier Morel
[FIX] don't display shortcuts star *everywhere*
1245
        """ We only handle creating shortcuts to menu actions (for now
1246
        anyway), and those go through the execute routine, so only match
1247
        execute()d actions concerning ir.ui.menu. And trees, just because
1248
        """
4451 by Xavier Morel
[FIX] shortcut icons rely on the content of the 'data' parameter, re-add it into cherrypy.request.params
1249
        action_data = cherrypy.request.params.get('data', {})
2939.1.97 by noz at tinyerp
[IMP] Improved Shortcut Creation.
1250
        return (rpc.session.is_logged() and
1251
                rpc.session.active_id and
3922.1.2 by Xavier Morel
[FIX] don't display shortcuts star *everywhere*
1252
                ((cherrypy.request.path_info == '/openerp/execute'
1253
                  and action_data.get('model') == 'ir.ui.menu')
1254
                # FIXME: hack hack hack
3925 by Fabien Meghazi
FIX: fixed hack hack hack
1255
                 or cherrypy.request.params.get('_terp_source_view_type') == 'tree'))
2939.1.97 by noz at tinyerp
[IMP] Improved Shortcut Creation.
1256
2524.4.15 by noz
[IMP] Implemented `Submenu` in sidebar.
1257
    @expose()
1258
    def action_submenu(self, **kw):
1259
        params, data = TinyDict.split(kw)
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
1260
2524.4.41 by noz at tinyerp
[MERGE] Merge with trunk (rev 2846).
1261
        import actions
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
1262
2524.4.15 by noz
[IMP] Implemented `Submenu` in sidebar.
1263
        act_id = rpc.session.execute('object', 'execute', 'ir.model.data', 'search', [('name','=', params.action_id)])
1264
        res_model = rpc.session.execute('object', 'execute', 'ir.model.data', 'read', act_id, ['res_id'])
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
1265
2524.4.15 by noz
[IMP] Implemented `Submenu` in sidebar.
1266
        res = rpc.session.execute('object', 'execute', 'ir.actions.act_window', 'read', res_model[0]['res_id'], False)
2938.1.2 by Xavier Morel
[imp] Cleanup stray whitespace (lines of whitespace, extra whitespace after end of lines, ...)
1267
2524.4.15 by noz
[IMP] Implemented `Submenu` in sidebar.
1268
        if res:
1269
            return actions.execute(res, model=params.model, id=params.id, context=rpc.session.context.copy())
2327.1.32 by ame (Tiny/Axelor)
* converted all subcontrollers
1270
1796 by Amit Mendapara
* Added vim settings to all python and js files
1271
# vim: ts=4 sts=4 sw=4 si et
3677 by olt at tinyerp
[FIX] 'add/remove shortcut' button was not there after switching view
1272