[IMP] Survey Kanban view
[REM] Unused code in survey.py [REF] Code cleaning bzr revid: rim@openerp.com-20131129084914-z76feeg813q38l25
This commit is contained in:
parent
92b55fe2a5
commit
65c9704954
|
@ -20,3 +20,5 @@
|
|||
##############################################################################
|
||||
|
||||
import main
|
||||
|
||||
# vim: exp and tab: smartindent: tabstop=4: softtabstop=4: shiftwidth=4:
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
from openerp.addons.web import http
|
||||
from openerp.addons.web.http import request
|
||||
from openerp.addons.website.models import website
|
||||
from openerp.osv import fields
|
||||
from openerp import SUPERUSER_ID
|
||||
|
||||
import werkzeug
|
||||
|
@ -37,22 +36,22 @@ class WebsiteSurvey(http.Controller):
|
|||
|
||||
# Survey list
|
||||
@website.route(['/survey/',
|
||||
'/survey/list/'],
|
||||
type='http', auth='public', multilang=True)
|
||||
'/survey/list/'],
|
||||
type='http', auth='public', multilang=True)
|
||||
def list_surveys(self, **post):
|
||||
'''Lists all the public surveys'''
|
||||
cr, uid, context = request.cr, request.uid, request.context
|
||||
survey_obj = request.registry['survey.survey']
|
||||
survey_ids = survey_obj.search(cr, uid, [('state', '=', 'open'),
|
||||
('page_ids', '!=', 'None')],
|
||||
context=context)
|
||||
('page_ids', '!=', 'None')],
|
||||
context=context)
|
||||
surveys = survey_obj.browse(cr, uid, survey_ids, context=context)
|
||||
return request.website.render('survey.list', {'surveys': surveys})
|
||||
|
||||
# Survey start
|
||||
@website.route(['/survey/start/<model("survey.survey"):survey>',
|
||||
'/survey/start/<model("survey.survey"):survey>/<string:token>'],
|
||||
type='http', auth='public', multilang=True)
|
||||
type='http', auth='public', multilang=True)
|
||||
def start_survey(self, survey, token=None, **post):
|
||||
cr, uid, context = request.cr, request.uid, request.context
|
||||
survey_obj = request.registry['survey.survey']
|
||||
|
@ -220,28 +219,13 @@ class WebsiteSurvey(http.Controller):
|
|||
else:
|
||||
# Store answers into database
|
||||
user_input_obj = request.registry['survey.user_input']
|
||||
user_input_line_obj = request.registry['survey.user_input_line']
|
||||
try:
|
||||
user_input_id = user_input_obj.search(cr, uid, [('token', '=', post['token'])], context=context)[0]
|
||||
except KeyError: # Invalid token
|
||||
return request.website.render("website.403")
|
||||
|
||||
user_input_obj.write(cr, uid, [user_input_id], {'state': 'skip'}, context=context)
|
||||
for question in questions:
|
||||
answer_tag = "%s_%s_%s" % (survey.id, page_id, question.id)
|
||||
vals = {
|
||||
'user_input_id': user_input_id,
|
||||
'question_id': question.id,
|
||||
'page_id': page_id,
|
||||
'survey_id': survey.id,
|
||||
}
|
||||
if answer_tag in post:
|
||||
if question.type == 'textbox':
|
||||
vals.update({'answer_type': 'text', 'value_text': post[answer_tag]})
|
||||
pass
|
||||
else:
|
||||
vals.update({'skipped': True})
|
||||
user_input_line_obj.create(cr, uid, vals, context=context)
|
||||
user_input_obj.save_lines(cr, uid, user_input_id, question, post, answer_tag, context=context)
|
||||
ret['redirect'] = '/survey/fill/%s/%s' % (survey.id, post['token'])
|
||||
return json.dumps(ret)
|
||||
|
||||
|
@ -282,7 +266,7 @@ class WebsiteSurvey(http.Controller):
|
|||
try:
|
||||
checker = getattr(self, 'validate_' + question.type)
|
||||
except AttributeError:
|
||||
_logger.warning(question.type + ": This type of question has no validation method")
|
||||
_logger.error(question.type + ": This type of question has no validation method")
|
||||
return {}
|
||||
else:
|
||||
return checker(question, post, answer_tag)
|
||||
|
@ -403,11 +387,4 @@ class WebsiteSurvey(http.Controller):
|
|||
# problems = []
|
||||
# return problems
|
||||
|
||||
|
||||
def dict_keys_startswith(self, dictionary, string):
|
||||
'''Returns a dictionary containing the elements of <dict> whose keys start
|
||||
with <string>.
|
||||
|
||||
.. note::
|
||||
This function uses dictionary comprehensions (Python >= 2.7)'''
|
||||
return {k: dictionary[k] for k in filter(lambda key: key.startswith(string), dictionary.keys())}
|
||||
# vim: exp and tab: smartindent: tabstop=4: softtabstop=4: shiftwidth=4:
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
}
|
||||
.openerp .oe_kanban_survey .oe_kanban_status,
|
||||
.openerp .oe_kanban_survey .oe_kanban_status_green,
|
||||
.openerp .oe_kanban_survey .oe_kanban_status_darkgreen,
|
||||
.openerp .oe_kanban_survey .oe_kanban_status_salmon,
|
||||
.openerp .oe_kanban_survey .oe_kanban_status_red {
|
||||
display: block;
|
||||
height: 10px;
|
||||
|
@ -25,8 +25,8 @@
|
|||
.openerp .oe_kanban_survey .oe_kanban_status_green {
|
||||
background-color: green;
|
||||
}
|
||||
.openerp .oe_kanban_survey .oe_kanban_status_darkgreen {
|
||||
background-color: darkgreen;
|
||||
.openerp .oe_kanban_survey .oe_kanban_status_salmon {
|
||||
background-color: salmon;
|
||||
}
|
||||
.openerp .oe_kanban_survey .oe_kanban_status_red {
|
||||
background-color: red;
|
||||
|
@ -34,3 +34,12 @@
|
|||
.openerp .oe_kanban_survey .oe_inactive {
|
||||
color: #aaaaaa;
|
||||
}
|
||||
|
||||
.openerp .oe_kanban_survey .oe_stats_box {
|
||||
width: 100px;
|
||||
display: inline-block;
|
||||
margin: 2px 5px 0px 5px;
|
||||
text-align: center;
|
||||
border: 1px solid rgba(0, 0, 0, 0.16);
|
||||
background-color: #FFFFFF;
|
||||
}
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
* OpenERP, Open Source Management Solution
|
||||
* Copyright (C) 2004-TODAY OpenERP S.A. <http://www.openerp.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
console.debug("[survey] Custom JS for survey is loading...");
|
||||
|
|
|
@ -19,10 +19,14 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
from urlparse import urljoin
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.tools.translate import _
|
||||
from urlparse import urljoin
|
||||
|
||||
import uuid
|
||||
import logging
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class survey_survey(osv.osv):
|
||||
|
@ -251,16 +255,6 @@ class survey_survey(osv.osv):
|
|||
pass
|
||||
return super(survey_survey, self).write(cr, uid, ids, vals, context=None)
|
||||
|
||||
# def unlink(self, cr, uid, ids, context=None):
|
||||
# ''' Delete survey and linked email templates (if any) '''
|
||||
# email_template_ids = list()
|
||||
# for survey in self.browse(cr, uid, ids, context=context):
|
||||
# email_template_ids.append(survey.email_template_id.id)
|
||||
# if email_template_ids:
|
||||
# self.pool.get('email.template').unlink(cr, uid, email_template_ids,
|
||||
# context=context)
|
||||
# return super(survey_survey, self).unlink(cr, uid, ids, context=context)
|
||||
|
||||
|
||||
class survey_page(osv.osv):
|
||||
'''A page for a survey.
|
||||
|
@ -293,21 +287,6 @@ class survey_page(osv.osv):
|
|||
|
||||
# Public methods #
|
||||
|
||||
# def survey_save(self, cr, uid, ids, context=None):
|
||||
# if context is None:
|
||||
# context = {}
|
||||
# surv_name_wiz = self.pool.get('survey.question.wiz')
|
||||
# surv_name_wiz.write(cr, uid, [context.get('wizard_id', False)],
|
||||
# {'transfer': True, 'page_no': context.get('page_number', 0)})
|
||||
# return {
|
||||
# 'view_type': 'form',
|
||||
# 'view_mode': 'form',
|
||||
# 'res_model': 'survey.question.wiz',
|
||||
# 'type': 'ir.actions.act_window',
|
||||
# 'target': 'new',
|
||||
# 'context': context
|
||||
# }
|
||||
|
||||
def copy(self, cr, uid, ids, default=None, context=None):
|
||||
vals = {}
|
||||
current_rec = self.read(cr, uid, ids, context=context)
|
||||
|
@ -371,7 +350,7 @@ class survey_question(osv.osv):
|
|||
'Number of columns'),
|
||||
'display_mode': fields.selection([('columns', 'Columns'),
|
||||
('dropdown', 'Dropdown menu')],
|
||||
'Display mode'),
|
||||
'Display mode'),
|
||||
|
||||
# Comments
|
||||
'comments_allowed': fields.boolean('Allow comments',
|
||||
|
@ -391,7 +370,7 @@ class survey_question(osv.osv):
|
|||
('is_decimal', 'Must be a decimal number'),
|
||||
#('is_date', 'Must be a date'),
|
||||
('is_email', 'Must be an email address')],
|
||||
'Validation type'),
|
||||
'Validation type', translate=True),
|
||||
'validation_length_min': fields.integer('Minimum length'),
|
||||
'validation_length_max': fields.integer('Maximum length'),
|
||||
'validation_min_float_value': fields.float('Minimum value'),
|
||||
|
@ -400,7 +379,9 @@ class survey_question(osv.osv):
|
|||
'validation_max_int_value': fields.integer('Maximum value'),
|
||||
'validation_min_date': fields.date('Start date range'),
|
||||
'validation_max_date': fields.date('End date range'),
|
||||
'validation_error_msg': fields.char("Error message", oldname='validation_valid_err_msg'),
|
||||
'validation_error_msg': fields.char('Error message',
|
||||
oldname='validation_valid_err_msg',
|
||||
translate=True),
|
||||
|
||||
# Constraints on number of answers
|
||||
'constr_mandatory': fields.boolean('Mandatory question',
|
||||
|
@ -440,13 +421,6 @@ class survey_question(osv.osv):
|
|||
('validation_date', 'CHECK (validation_min_date <= validation_max_date)', 'Max date cannot be smaller than min date!')
|
||||
]
|
||||
|
||||
def on_change_page_id(self, cr, uid, ids, page_id, context=None):
|
||||
if page_id:
|
||||
page = self.pool.get('survey.page').browse(cr, uid, page_id,
|
||||
context=context)
|
||||
return {'survey_id': page.survey_id and page.survey_id.id}
|
||||
return {'value': {}}
|
||||
|
||||
# def write(self, cr, uid, ids, vals, context=None):
|
||||
# questions = self.read(cr, uid, ids, ['answer_choice_ids', 'type',
|
||||
# 'required_type', 'req_ans', 'minimum_req_ans', 'maximum_req_ans',
|
||||
|
@ -577,18 +551,20 @@ class survey_user_input(osv.osv):
|
|||
|
||||
_columns = {
|
||||
'survey_id': fields.many2one('survey.survey', 'Survey', required=True,
|
||||
readonly=1, ondelete='restrict'),
|
||||
readonly=1, ondelete='restrict'),
|
||||
'date_create': fields.datetime('Creation Date', required=True,
|
||||
readonly=1),
|
||||
readonly=1),
|
||||
'deadline': fields.date("Deadline",
|
||||
help="Date by which the person can take part to the survey",
|
||||
oldname="date_deadline"),
|
||||
help="Date by which the person can take part to the survey",
|
||||
oldname="date_deadline"),
|
||||
'type': fields.selection([('manually', 'Manually'), ('link', 'Link')],
|
||||
'Answer Type', required=1, readonly=1, oldname="response_type"),
|
||||
'Answer Type', required=1, readonly=1,
|
||||
oldname="response_type"),
|
||||
'state': fields.selection([('new', 'Not started yet'),
|
||||
('skip', 'Partially completed'),
|
||||
('done', 'Completed')], 'Status',
|
||||
readonly=True),
|
||||
('skip', 'Partially completed'),
|
||||
('done', 'Completed')],
|
||||
'Status',
|
||||
readonly=True),
|
||||
'test_entry': fields.boolean('Test entry', readonly=1),
|
||||
'token': fields.char("Identification token", readonly=1, required=1),
|
||||
|
||||
|
@ -598,7 +574,7 @@ class survey_user_input(osv.osv):
|
|||
|
||||
# The answers !
|
||||
'user_input_line_ids': fields.one2many('survey.user_input_line',
|
||||
'user_input_id', 'Answers'),
|
||||
'user_input_id', 'Answers'),
|
||||
}
|
||||
_defaults = {
|
||||
'date_create': fields.datetime.now,
|
||||
|
@ -649,13 +625,48 @@ class survey_user_input(osv.osv):
|
|||
|
||||
# raise osv.except_osv(_('Warning!'), _('You must enter one or more answers for question "%s" of page %s .') % (vals['question'], page.title))
|
||||
|
||||
|
||||
def do_clean_emptys(self, cr, uid, automatic=False, context=None):
|
||||
''' Remove empty user inputs that have been created manually '''
|
||||
empty_user_input_ids = self.search(cr, uid,
|
||||
[('type', '=', 'manually'), ('state', '=', 'new')], context=context)
|
||||
empty_user_input_ids = self.search(cr, uid, [('type', '=', 'manually'),
|
||||
('state', '=', 'new')],
|
||||
context=context)
|
||||
if empty_user_input_ids:
|
||||
self.unlink(cr, uid, empty_user_input_ids, context=context)
|
||||
self.unlink(cr, uid, empty_user_input_ids, context=context)
|
||||
|
||||
def save_lines(self, cr, uid, user_input_id, question, post, answer_tag,
|
||||
context=None):
|
||||
try:
|
||||
saver = getattr(self, 'save_' + question.type)
|
||||
except AttributeError:
|
||||
_logger.error(question.type + ": This type of question has no saving function")
|
||||
return False
|
||||
else:
|
||||
return saver(cr, uid, user_input_id, question, post, answer_tag, context=context)
|
||||
# i f of question type select right saving meth
|
||||
# user_input_obj.write(cr, uid, [user_input_id], {'state': 'skip'}, context=context)
|
||||
|
||||
# vals = {
|
||||
# 'user_input_id': user_input_id,
|
||||
# 'question_id': question.id,
|
||||
# 'page_id': page_id,
|
||||
# 'survey_id': survey.id,
|
||||
# }
|
||||
# if answer_tag in post:
|
||||
# user_input_obj.save_lines(cr,uid,context=context)
|
||||
# if question.type == 'textbox':
|
||||
# vals.update({'answer_type': 'text', 'value_text': post[answer_tag]})
|
||||
# pass
|
||||
# else:
|
||||
# vals.update({'skipped': True})
|
||||
# user_input_line_obj.create(cr, uid, vals, context=context)
|
||||
|
||||
#here store answers
|
||||
|
||||
# def save_textbox(self, cr, uid, user_input_id, question, post, answer_tag, context=None):
|
||||
|
||||
|
||||
# return True
|
||||
|
||||
|
||||
def action_survey_resent(self, cr, uid, ids, context=None):
|
||||
record = self.browse(cr, uid, ids[0], context=context)
|
||||
|
@ -712,17 +723,6 @@ class survey_user_input(osv.osv):
|
|||
'context': context
|
||||
}
|
||||
|
||||
def name_get(self, cr, uid, ids, context=None):
|
||||
if not len(ids):
|
||||
return []
|
||||
reads = self.read(cr, uid, ids, ['partner_id', 'date_create'],
|
||||
context=context)
|
||||
res = []
|
||||
for record in reads:
|
||||
name = (record['partner_id'] and record['partner_id'][1] or '') + ' (' + record['date_create'].split('.')[0] + ')'
|
||||
res.append((record['id'], name))
|
||||
return res
|
||||
|
||||
def copy(self, cr, uid, id, default=None, context=None):
|
||||
raise osv.except_osv(_('Warning!'), _('You cannot duplicate this \
|
||||
element!'))
|
||||
|
@ -734,21 +734,22 @@ class survey_user_input_line(osv.osv):
|
|||
_rec_name = 'date_create'
|
||||
_columns = {
|
||||
'user_input_id': fields.many2one('survey.user_input', 'User Input',
|
||||
ondelete='cascade', required=1),
|
||||
ondelete='cascade', required=1),
|
||||
'question_id': fields.many2one('survey.question', 'Question',
|
||||
ondelete='restrict'),
|
||||
ondelete='restrict'),
|
||||
'page_id': fields.related('question_id', 'page_id', type='many2one',
|
||||
relation='survey.page', string="Page"),
|
||||
relation='survey.page', string="Page"),
|
||||
'survey_id': fields.related('user_input_id', 'survey_id',
|
||||
type="many2one", relation="survey.survey", string='Survey'),
|
||||
type="many2one", relation="survey.survey",
|
||||
string='Survey'),
|
||||
'date_create': fields.datetime('Create Date', required=1), # drop
|
||||
'skipped': fields.boolean('Skipped'),
|
||||
'answer_type': fields.selection([('text', 'Text'),
|
||||
('number', 'Number'),
|
||||
('date', 'Date'),
|
||||
('free_text', 'Free Text'),
|
||||
('suggestion', 'Suggestion')],
|
||||
'Answer Type'),
|
||||
('number', 'Number'),
|
||||
('date', 'Date'),
|
||||
('free_text', 'Free Text'),
|
||||
('suggestion', 'Suggestion')],
|
||||
'Answer Type'),
|
||||
'value_text': fields.char("Text answer"),
|
||||
'value_number': fields.float("Numerical answer"),
|
||||
'value_date': fields.datetime("Date answer"),
|
||||
|
@ -760,4 +761,12 @@ class survey_user_input_line(osv.osv):
|
|||
'date_create': fields.datetime.now
|
||||
}
|
||||
|
||||
def dict_keys_startswith(self, dictionary, string):
|
||||
'''Returns a dictionary containing the elements of <dict> whose keys start
|
||||
with <string>.
|
||||
|
||||
.. note::
|
||||
This function uses dictionary comprehensions (Python >= 2.7)'''
|
||||
return {k: dictionary[k] for k in filter(lambda key: key.startswith(string), dictionary.keys())}
|
||||
|
||||
# vim: exp and tab: smartindent: tabstop=4: softtabstop=4: shiftwidth=4:
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
from openerp.osv.orm import except_orm
|
||||
from openerp.tools import mute_logger
|
||||
from time import time
|
||||
|
||||
w
|
||||
|
||||
class test_survey_answer():
|
||||
|
||||
|
@ -115,3 +115,5 @@ class test_survey_answer():
|
|||
# self.assertEqual(self.survey_browse.state, 'close', 'Survey should be in cancel state')
|
||||
|
||||
# # sur_question = self.on_change_type(cr, uid, [ref("survey_Initial_partner_feedback")], 'multiple_textboxes_diff_type')
|
||||
|
||||
# vim: exp and tab: smartindent: tabstop=4: softtabstop=4: shiftwidth=4:
|
||||
|
|
|
@ -242,8 +242,6 @@
|
|||
<field name="public_url"/>
|
||||
<templates>
|
||||
<div t-name="kanban-box" t-attf-class="oe_kanban_color_#{kanban_getcolor(record.color.raw_value)} oe_kanban_card oe_kanban_survey oe_kanban_global_click">
|
||||
<span class="oe_survey_fill">
|
||||
</span>
|
||||
<div class="oe_dropdown_toggle oe_dropdown_kanban" t-if="widget.view.is_action_enabled('edit')">
|
||||
<span class="oe_e">i</span>
|
||||
<ul class="oe_dropdown_menu">
|
||||
|
@ -262,11 +260,17 @@
|
|||
<a t-if="record.state.raw_value === 'draft'" title="Draft" class="oe_kanban_status"> </a>
|
||||
<a t-if="record.state.raw_value === 'open'" title="Open" class="oe_kanban_status_green"> </a>
|
||||
<a t-if="record.state.raw_value === 'close'" title="Closed" class="oe_kanban_status_red"> </a>
|
||||
<a t-if="record.state.raw_value === 'cancel'" title="Cancelled" class="oe_kanban_status_salmon"> </a>
|
||||
</span>
|
||||
<h3 class="oe_kanban_ellipsis"><t t-esc="record.title.raw_value.toString()"></t></h3>
|
||||
<div>tot started surveys</div>
|
||||
<div>tot sent surveys</div>
|
||||
<div>tot completed surveys</div>
|
||||
<div><p>
|
||||
<ul>
|
||||
<li>Opening: <field name="date_open"/></li>
|
||||
<li>Closing: <field name="date_close"/></li>
|
||||
</ul>
|
||||
</p></div>
|
||||
<div class="oe_stats_box"><span><field name="tot_start_survey"/></span><br/>started</div>
|
||||
<div class="oe_stats_box"><span><field name="tot_comp_survey"/></span><br/>completed</div>
|
||||
</div>
|
||||
</div>
|
||||
</templates>
|
||||
|
@ -395,26 +399,16 @@
|
|||
</group>
|
||||
|
||||
<!-- Labels -->
|
||||
<group colspan="4" nolabel="1" attrs="{'invisible':[('type','not in',['simple_choice', 'multiple_choice'])]}">
|
||||
<group colspan="4" nolabel="1" attrs="{'invisible':[('type','not in',['simple_choice', 'multiple_choice', 'matrix'])]}">
|
||||
<field name="display_mode" string="Display mode" attrs="{'invisible':[('type','not in',['simple_choice'])]}"/>
|
||||
<field name="column_nb" string="Number of columns" attrs="{'invisible':[('display_mode','=','dropdown'), ('type','=','simple_choice')]}"/>
|
||||
<field name="labels_ids" colspan="4" nolabel="1" context="{'default_question_id': active_id}">
|
||||
<tree string="Answer choices" editable="bottom">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="value" />
|
||||
</tree>
|
||||
</field>
|
||||
</group>
|
||||
|
||||
<!-- Sub-questions -->
|
||||
<group colspan="4" attrs="{'invisible':[('type','not in',['matrix'])]}">
|
||||
<field name="labels_ids" colspan="4" nolabel="1" context="{'default_question_id': active_id}">
|
||||
<tree editable="bottom">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="value" string="Columns labels"/>
|
||||
<field name="value" string="Answer choices"/>
|
||||
</tree>
|
||||
</field>
|
||||
<field name="labels_ids_2" colspan="4" nolabel="1" context="{'default_question_id_2': active_id}">
|
||||
<field name="labels_ids_2" colspan="4" nolabel="1" context="{'default_question_id_2': active_id}" attrs="{'invisible':[('type','not in',['matrix'])]}">
|
||||
<tree editable="bottom">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="value" string="Rows labels"/>
|
||||
|
|
|
@ -19,11 +19,12 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
import re
|
||||
from openerp.osv import osv
|
||||
from openerp.osv import fields
|
||||
from datetime import datetime
|
||||
from openerp.tools.translate import _
|
||||
from datetime import datetime
|
||||
|
||||
import re
|
||||
import uuid
|
||||
|
||||
emails_split = re.compile(r"[;,\n\r]+")
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
from openerp.osv import fields, osv
|
||||
from openerp.tools.translate import _
|
||||
|
||||
|
||||
class survey_print_statistics(osv.osv_memory):
|
||||
_name = 'survey.print.statistics'
|
||||
_columns = {
|
||||
|
|
Loading…
Reference in New Issue