[MERGE] latust trunk

bzr revid: abo@openerp.com-20120810140856-xl6sj3xu9t4bee6c
This commit is contained in:
Antonin Bourguignon 2012-08-10 16:08:56 +02:00
commit f2fd44d85b
50 changed files with 1023 additions and 634 deletions

View File

@ -169,7 +169,7 @@ class account_cash_statement(osv.osv):
return result
_columns = {
'total_entry_encoding': fields.function(_get_sum_entry_encoding, string="Total Cash Transactions",
'total_entry_encoding': fields.function(_get_sum_entry_encoding, string="Total Transactions",
store = {
'account.bank.statement': (lambda self, cr, uid, ids, context=None: ids, ['line_ids','move_line_ids'], 10),
'account.bank.statement.line': (_get_statement_from_line, ['amount'], 10),

View File

@ -347,7 +347,7 @@
<field name="invoice_line" nolabel="1" widget="one2many_list" context="{'type': type}">
<tree string="Invoice Lines" editable="bottom">
<field name="invoice_line_tax_id" invisible="1"/>
<field name="product_id" invisible="1"/>
<field name="product_id" />
<field name="name"/>
<field name="account_id" groups="account.group_account_user"
domain="[('company_id', '=', parent.company_id), ('journal_id', '=', parent.journal_id), ('type', '&lt;&gt;', 'view')]"

View File

@ -1,8 +1,9 @@
# -*- coding: utf-8 -*-
##############################################################################
#
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
# Copyright (C) 2010-2012 OpenERP s.a. (<http://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
@ -15,11 +16,11 @@
# 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/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import board
import wizard
import controllers
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -3,6 +3,7 @@
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
# Copyright (C) 2010-2012 OpenERP s.a. (<http://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
@ -35,15 +36,19 @@ The user can also publish notes.
'depends': ['base'],
'update_xml': [
'security/ir.model.access.csv',
'wizard/board_menu_create_view.xml',
'board_view.xml',
'board_data_admin.xml',
'board_data_home.xml',
'board_mydashboard_view.xml'
],
'demo_xml': [
'board_demo.xml'
"js": [
'static/src/js/dashboard.js',
],
"css": [
'static/src/css/dashboard.css',
],
'qweb': [
"static/src/xml/*.xml",
],
'installable': True,
'auto_install': False,
'certificate': '0076912305725',

View File

@ -3,6 +3,7 @@
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
# Copyright (C) 2010-2012 OpenERP s.a. (<http://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
@ -19,75 +20,58 @@
#
##############################################################################
from operator import itemgetter
from textwrap import dedent
from osv import fields, osv
import time
import tools
class board_board(osv.osv):
"""
Board
"""
_name = 'board.board'
_description = "Board"
_auto = False
_columns = {}
def create_view(self, cr, uid, ids, context=None):
"""
Create view
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of Board's IDs
@return: arch of xml view.
"""
arch = """<?xml version="1.0"?>
<form string="My Board" version="7.0">
<board style="1-1">
<column/>
<column/>
</board>
</form>"""
return arch
@tools.cache()
def list(self, cr, uid, context=None):
Actions = self.pool.get('ir.actions.act_window')
Menus = self.pool.get('ir.ui.menu')
IrValues = self.pool.get('ir.values')
act_ids = Actions.search(cr, uid, [('res_model', '=', self._name)], context=context)
refs = ['%s,%s' % (Actions._name, act_id) for act_id in act_ids]
# cannot search "action" field on menu (non stored function field without search_fnct)
irv_ids = IrValues.search(cr, uid, [
('model', '=', 'ir.ui.menu'),
('key', '=', 'action'),
('key2', '=', 'tree_but_open'),
('value', 'in', refs),
], context=context)
menu_ids = map(itemgetter('res_id'), IrValues.read(cr, uid, irv_ids, ['res_id'], context=context))
menu_names = Menus.name_get(cr, uid, menu_ids, context=context)
return [dict(id=m[0], name=m[1]) for m in menu_names]
def _clear_list_cache(self):
self.list.clear_cache(self)
def create(self, cr, user, vals, context=None):
"""
create new record.
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param vals: dictionary of values for every field.
dictionary must use this form: {name_of_the_field: value, ...}
@return: id of new created record of board.board.
"""
return 0
if not 'name' in vals:
return False
id = super(board_board, self).create(cr, user, vals, context=context)
view_id = self.pool.get('ir.ui.view').create(cr, user, {
'name': vals['name'],
'model': 'board.board',
'priority': 16,
'type': 'form',
'arch': self.create_view(cr, user, id, context=context),
})
super(board_board, self).write(cr, user, [id], {'view_id': view_id}, context)
return id
def fields_view_get(self, cr, user, view_id=None, view_type='form', context=None,\
toolbar=False, submenu=False):
def fields_view_get(self, cr, user, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
"""
Overrides orm field_view_get.
@return: Dictionary of Fields, arch and toolbar.
"""
res = {}
res = super(board_board, self).fields_view_get(cr, user, view_id, view_type,\
context, toolbar=toolbar, submenu=submenu)
res = super(board_board, self).fields_view_get(cr, user, view_id, view_type,
context, toolbar=toolbar, submenu=submenu)
vids = self.pool.get('ir.ui.view.custom').search(cr, user,\
[('user_id', '=', user), ('ref_id' ,'=', view_id)])
CustView = self.pool.get('ir.ui.view.custom')
vids = CustView.search(cr, user, [('user_id', '=', user), ('ref_id', '=', view_id)], context=context)
if vids:
view_id = vids[0]
arch = self.pool.get('ir.ui.view.custom').browse(cr, user, view_id, context=context)
arch = CustView.browse(cr, user, view_id, context=context)
res['custom_view_id'] = view_id
res['arch'] = arch.arch
res['arch'] = self._arch_preprocessing(cr, user, res['arch'], context=context)
@ -98,10 +82,10 @@ class board_board(osv.osv):
from lxml import etree
def remove_unauthorized_children(node):
for child in node.iterchildren():
if child.tag=='action' and child.get('invisible'):
if child.tag == 'action' and child.get('invisible'):
node.remove(child)
else:
child=remove_unauthorized_children(child)
child = remove_unauthorized_children(child)
return node
def encode(s):
@ -110,16 +94,84 @@ class board_board(osv.osv):
return s
archnode = etree.fromstring(encode(arch))
return etree.tostring(remove_unauthorized_children(archnode),pretty_print=True)
return etree.tostring(remove_unauthorized_children(archnode), pretty_print=True)
class board_create(osv.osv_memory):
def board_create(self, cr, uid, ids, context=None):
assert len(ids) == 1
this = self.browse(cr, uid, ids[0], context=context)
view_arch = dedent("""<?xml version="1.0"?>
<form string="%s" version="7.0">
<board style="2-1">
<column/>
<column/>
</board>
</form>
""".strip() % (this.name,))
view_id = self.pool.get('ir.ui.view').create(cr, uid, {
'name': this.name,
'model': 'board.board',
'priority': 16,
'type': 'form',
'arch': view_arch,
}, context=context)
action_id = self.pool.get('ir.actions.act_window').create(cr, uid, {
'name': this.name,
'view_type': 'form',
'view_mode': 'form',
'res_model': 'board.board',
'usage': 'menu',
'view_id': view_id,
'help': dedent('''<div class="oe_empty_custom_dashboard">
<p>
<b>This dashboard is empty.</b>
</p><p>
To add the first report into this dashboard, go to any
menu, switch to list or graph view, and click <i>'Add to
Dashboard'</i> in the extended search options.
</p><p>
You can filter and group data before inserting into the
dashboard using the search options.
</p>
</div>
''')
}, context=context)
menu_id = self.pool.get('ir.ui.menu').create(cr, uid, {
'name': this.name,
'parent_id': this.menu_parent_id.id,
'action': 'ir.actions.act_window,%s' % (action_id,)
}, context=context)
self.pool.get('board.board')._clear_list_cache()
return {
'type': 'ir.actions.client',
'tag': 'reload',
'params': {
'menu_id': menu_id
},
}
def _default_menu_parent_id(self, cr, uid, context=None):
_, menu_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'menu_reporting_dashboard')
return menu_id
_name = "board.create"
_description = "Board Creation"
_columns = {
'name': fields.char('Dashboard', size=64, required=True),
'view_id': fields.many2one('ir.ui.view', 'Board View'),
'name': fields.char('Board Name', size=64, required=True),
'menu_parent_id': fields.many2one('ir.ui.menu', 'Parent Menu', required=True),
}
# the following lines added to let the button on dashboard work.
_defaults = {
'name':lambda *args: 'Dashboard'
'menu_parent_id': _default_menu_parent_id,
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
</data>
</openerp>

View File

@ -1,41 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- neat client actions that can be used in dashboards to display res_widgets -->
<record id="action_application_tiles" model="ir.actions.client">
<field name="name">Applications Tiles</field>
<field name="tag">board.home.applications</field>
</record>
<record id="action_res_widgets_tweets" model="ir.actions.client">
<field name="name">Tweets Widget</field>
<field name="tag">board.home.widgets</field>
<field name="params" eval="{'widget_id': ref('base.openerp_favorites_twitter_widget')}"/>
</record>
<record id="action_res_widgets_events" model="ir.actions.client">
<field name="name">Events Widget</field>
<field name="tag">board.home.widgets</field>
<field name="params" eval="{'widget_id': ref('base.events_widget')}"/>
</record>
<record id="action_res_widgets_facebook" model="ir.actions.client">
<field name="name">Facebook Widget</field>
<field name="tag">board.home.widgets</field>
<field name="params" eval="{'widget_id': ref('base.facebook_widget')}"/>
</record>
<record id="action_res_widgets_note" model="ir.actions.client">
<field name="name">Note Widget</field>
<field name="tag">board.home.widgets</field>
<field name="params" eval="{'widget_id': ref('base.note_widget')}"/>
</record>
<record id="action_res_widgets_map" model="ir.actions.client">
<field name="name">Google Maps Widget</field>
<field name="tag">board.home.widgets</field>
<field name="params" eval="{'widget_id': ref('base.google_maps_widget')}"/>
</record>
<record id="action_res_widgets_currency_converter" model="ir.actions.client">
<field name="name">Currency Converter Widget</field>
<field name="tag">board.home.widgets</field>
<field name="params" eval="{'widget_id': ref('base.currency_converter_widget')}"/>
</record>
</data>
</openerp>

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
</data>
</openerp>

View File

@ -1,6 +1,6 @@
<?xml version="1.0"?>
<openerp>
<data>
<data noupdate="1">
<!--My Dashboard-->
<record model="ir.ui.view" id="board_my_dash_view">
<field name="name">My Dashboard</field>

View File

@ -1,64 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- Board Search View -->
<record id="view_board_search" model="ir.ui.view">
<field name="name">board.board.search</field>
<field name="model">board.board</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Dashboard">
<field name="name" string="Dashboard"/>
</search>
</field>
</record>
<!-- Board Tree View -->
<record id="view_board_tree" model="ir.ui.view">
<field name="name">board.board.tree</field>
<field name="model">board.board</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Dashboard">
<field name="name"/>
</tree>
</field>
</record>
<!-- Board Form View -->
<record id="view_board_form" model="ir.ui.view">
<field name="name">board.board.form</field>
<field name="model">board.board</field>
<record id="view_board_create" model="ir.ui.view">
<field name="name">board.create.form</field>
<field name="model">board.create</field>
<field name="type">form</field>
<field eval="1" name="priority"/>
<field name="arch" type="xml">
<form string="Dashboard" version="7.0">
<header>
<button name="%(action_board_menu_create)d" string="Create Menu" type="action" class="oe_highlight"/>
</header>
<sheet>
<group>
<field name="name"/>
<field name="view_id" invisible="1"/>
</group>
</sheet>
</form>
<form string="Create New Dashboard" version="7.0">
<group colspan="4">
<field name="name"/>
<field name="menu_parent_id"/>
</group>
<footer>
<button string="Create" name="board_create" type="object" class="oe_highlight"/>
or
<button string="Cancel" class="oe_link" special="cancel"/>
</footer>
</form>
</field>
</record>
<!-- Action for DashBoard Definition form -->
<record id="action_view_board_list_form" model="ir.actions.act_window">
<field name="name">Dashboard Definition</field>
<field name="res_model">board.board</field>
<record id="action_board_create" model="ir.actions.act_window">
<field name="name">Create Board</field>
<field name="res_model">board.create</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="view_board_search"/>
<field name="view_mode">form</field>
<field name="view_id" ref="view_board_create"/>
<field name="target">new</field>
</record>
<menuitem action="action_view_board_list_form"
id="menu_view_board_form" parent="base.menu_reporting_config"
<menuitem action="action_board_create"
id="menu_board_create" parent="base.menu_reporting_config"
groups="base.group_no_one"
sequence="2"/>
</data>
</openerp>

View File

@ -0,0 +1,55 @@
# -*- coding: utf-8 -*-
from xml.etree import ElementTree
try:
import openerp.addons.web.common.http as openerpweb
from openerp.addons.web.common import nonliterals
from openerp.addons.web.controllers.main import load_actions_from_ir_values
except ImportError:
import web.common.http as openerpweb # noqa
from web.common import nonliterals # noqa
from web.controllers.main import load_actions_from_ir_values # noqa
class Board(openerpweb.Controller):
_cp_path = '/board'
@openerpweb.jsonrequest
def add_to_dashboard(self, req, menu_id, action_id, context_to_save, domain, view_mode, name=''):
# FIXME move this method to board.board model
to_eval = nonliterals.CompoundContext(context_to_save)
to_eval.session = req.session
ctx = dict((k, v) for k, v in to_eval.evaluate().iteritems()
if not k.startswith('search_default_'))
ctx['dashboard_merge_domains_contexts'] = False # TODO: replace this 6.1 workaround by attribute on <action/>
domain = nonliterals.CompoundDomain(domain)
domain.session = req.session
domain = domain.evaluate()
dashboard_action = load_actions_from_ir_values(req, 'action', 'tree_but_open', [('ir.ui.menu', menu_id)], False)
if dashboard_action:
action = dashboard_action[0][2]
if action['res_model'] == 'board.board' and action['views'][0][1] == 'form':
# Maybe should check the content instead of model board.board ?
view_id = action['views'][0][0]
board = req.session.model(action['res_model']).fields_view_get(view_id, 'form')
if board and 'arch' in board:
xml = ElementTree.fromstring(board['arch'])
column = xml.find('./board/column')
if column is not None:
new_action = ElementTree.Element('action', {
'name': str(action_id),
'string': name,
'view_mode': view_mode,
'context': str(ctx),
'domain': str(domain)
})
column.insert(0, new_action)
arch = ElementTree.tostring(xml, 'utf-8')
return req.session.model('ir.ui.view.custom').create({
'user_id': req.session._uid,
'ref_id': view_id,
'arch': arch
}, req.session.eval_context(req.context))
return False

View File

@ -1,3 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_board_board all,board.board,model_board_board,,1,0,0,0
access_board_board system,board.board system,model_board_board,base.group_system,1,1,1,1

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_board_board all board.board model_board_board 1 0 0 0
access_board_board system board.board system model_board_board base.group_system 1 1 1 1

View File

@ -0,0 +1,73 @@
.openerp .oe_dashboard_links {
text-align: right;
margin: 0 4px 6px 0;
}
.openerp .oe_dashboard {
width: 100%;
}
.openerp .oe_dashboard .oe_action {
margin: 0 8px 8px 0;
background-color: white;
border: 1px solid;
border-color: #e5e5e5 #dbdbdb #d2d2d2;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
-moz-box-shadow: 0 0 2px rgba(0, 0, 0, 0.2);
-webkit-box-shadow: 0 0 2px rgba(0, 0, 0, 0.2);
box-shadow: 0 0 2px rgba(0, 0, 0, 0.2);
}
.openerp .oe_dashboard .oe_action .oe_header {
font-size: 16px;
vertical-align: middle;
margin: 0;
padding: 12px;
-moz-border-radius: 3px 3px 0 0;
-webkit-border-radius: 3px 3px 0 0;
border-radius: 3px 3px 0 0;
}
.openerp .oe_dashboard .oe_action .oe_header:hover {
cursor: move;
}
.openerp .oe_dashboard .oe_action .oe_header .oe_icon {
float: right;
cursor: pointer;
color: #b3b3b3;
}
.openerp .oe_dashboard .oe_action .oe_header .oe_icon:hover {
color: #666666;
text-decoration: none;
}
.openerp .oe_dashboard .oe_action .oe_header .oe_close:after {
content: "×";
margin-left: 4px;
}
.openerp .oe_dashboard .oe_action .oe_header .oe_minimize:after {
content: "-";
margin-left: 4px;
}
.openerp .oe_dashboard .oe_action .oe_header .oe_maximize:after {
content: "+";
margin-left: 4px;
}
.openerp .oe_dashboard .oe_action .oe_header_empty {
padding-top: 0;
padding-bottom: 2px;
}
.openerp .oe_dashboard .oe_action .oe_button_create {
margin-left: 4px;
padding: 0 4px 0 4px;
height: 16px !important;
}
.openerp .oe_dashboard .oe_action .oe_content {
padding: 0 12px 12px 12px;
}
.openerp .oe_dashboard .oe_action .oe_content .oe_view_manager_header {
display: none;
}
.openerp .oe_dashboard .oe_action .oe_content .oe_list_content > thead {
border-bottom: 1px;
}
.openerp .oe_dashboard .oe_action .oe_content .oe_list_content > tbody tr:nth-child(odd) {
background: transparent;
}

View File

@ -0,0 +1,83 @@
@mixin radius($radius: 5px)
-moz-border-radius: $radius
-webkit-border-radius: $radius
border-radius: $radius
@mixin box-shadow($bsval: 0px 1px 4px #777)
-moz-box-shadow: $bsval
-webkit-box-shadow: $bsval
box-shadow: $bsval
.openerp
.oe_dashboard_links
text-align: right
margin: 0 4px 6px 0
.oe_dashboard
width: 100%
.oe_action
margin: 0 8px 8px 0
background-color: white
border: 1px solid
border-color: #e5e5e5 #dbdbdb #d2d2d2
@include radius(3px)
@include box-shadow(0 0 2px rgba(0,0,0,0.2))
.oe_header
font-size: 16px
vertical-align: middle
margin: 0
padding: 12px
@include radius(3px 3px 0 0)
//border-bottom: 1px dotted #dbdbdb
//@include radius(2px 2px 0 0)
//@include vertical-gradient(#FCFCFC, #DEDEDE)
&:hover
cursor: move
.oe_icon
float: right
cursor: pointer
color: #b3b3b3
&:hover
color: #666
text-decoration: none
.oe_close:after
content: "×"
margin-left: 4px
.oe_minimize:after
content: "-"
margin-left: 4px
.oe_maximize:after
content: "+"
margin-left: 4px
.oe_header_empty
padding-top: 0
padding-bottom: 2px
.oe_button_create
margin-left: 4px
padding: 0 4px 0 4px
height: 16px !important
//.oe_rename
//float: left
//padding-right: 4px
//position: relative
//top: 1px
//.oe_input
//height: 16px;
//position: relative;
//top: 2px;
//.ui-sortable-placeholder
//border: 1px dotted black;
//visibility: visible !important;
//height: 50px !important;
//*
//visibility: hidden;
.oe_content
padding: 0 12px 12px 12px
.oe_view_manager_header
display: none
.oe_list_content
> thead
border-bottom: 1px
> tbody
tr:nth-child(odd)
background: transparent

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -0,0 +1,378 @@
openerp.board = function(instance) {
var QWeb = instance.web.qweb,
_t = instance.web._t;
if (!instance.board) {
/** @namespace */
instance.board = {};
}
instance.web.form.DashBoard = instance.web.form.FormWidget.extend({
init: function(view, node) {
this._super(view, node);
this.form_template = 'DashBoard';
this.actions_attrs = {};
this.action_managers = [];
},
start: function() {
var self = this;
this._super.apply(this, arguments);
this.$element.find('.oe_dashboard_column').sortable({
connectWith: '.oe_dashboard_column',
handle: '.oe_header',
scroll: false
}).disableSelection().bind('sortstop', self.do_save_dashboard);
// Events
this.$element.find('.oe_dashboard_link_reset').click(this.on_reset);
this.$element.find('.oe_dashboard_link_change_layout').click(this.on_change_layout);
this.$element.delegate('.oe_dashboard_column .oe_fold', 'click', this.on_fold_action);
this.$element.delegate('.oe_dashboard_column .oe_close', 'click', this.on_close_action);
// Init actions
_.each(this.node.children, function(column, column_index) {
_.each(column.children, function(action, action_index) {
delete(action.attrs.width);
delete(action.attrs.height);
delete(action.attrs.colspan);
var action_id = _.str.toNumber(action.attrs.name);
if (!_.isNaN(action_id)) {
self.rpc('/web/action/load', {action_id: action_id}, function(result) {
self.on_load_action(result, column_index + '_' + action_index, action.attrs);
});
}
});
});
},
on_reset: function() {
this.rpc('/web/view/undo_custom', {
view_id: this.view.fields_view.view_id,
reset: true
}, this.do_reload);
},
on_change_layout: function() {
var self = this;
var qdict = {
current_layout : this.$element.find('.oe_dashboard').attr('data-layout')
};
var $dialog = instance.web.dialog($('<div>'), {
modal: true,
title: _t("Edit Layout"),
width: 'auto',
height: 'auto'
}).html(QWeb.render('DashBoard.layouts', qdict));
$dialog.find('li').click(function() {
var layout = $(this).attr('data-layout');
$dialog.dialog('destroy');
self.do_change_layout(layout);
});
},
do_change_layout: function(new_layout) {
var $dashboard = this.$element.find('.oe_dashboard');
var current_layout = $dashboard.attr('data-layout');
if (current_layout != new_layout) {
var clayout = current_layout.split('-').length,
nlayout = new_layout.split('-').length,
column_diff = clayout - nlayout;
if (column_diff > 0) {
var $last_column = $();
$dashboard.find('.oe_dashboard_column').each(function(k, v) {
if (k >= nlayout) {
$(v).find('.oe_action').appendTo($last_column);
} else {
$last_column = $(v);
}
});
}
$dashboard.toggleClass('oe_dashboard_layout_' + current_layout + ' oe_dashboard_layout_' + new_layout);
$dashboard.attr('data-layout', new_layout);
this.do_save_dashboard();
}
},
on_fold_action: function(e) {
var $e = $(e.currentTarget),
$action = $e.parents('.oe_action:first'),
id = parseInt($action.attr('data-id'), 10);
if ($e.is('.oe_minimize')) {
$action.data('action_attrs').fold = '1';
} else {
delete($action.data('action_attrs').fold);
}
$e.toggleClass('oe_minimize oe_maximize');
$action.find('.oe_content').toggle();
this.do_save_dashboard();
},
on_close_action: function(e) {
if (confirm(_t("Are you sure you want to remove this item ?"))) {
$(e.currentTarget).parents('.oe_action:first').remove();
this.do_save_dashboard();
}
},
do_save_dashboard: function() {
var self = this;
var board = {
form_title : this.view.fields_view.arch.attrs.string,
style : this.$element.find('.oe_dashboard').attr('data-layout'),
columns : []
};
this.$element.find('.oe_dashboard_column').each(function() {
var actions = [];
$(this).find('.oe_action').each(function() {
var action_id = $(this).attr('data-id'),
new_attrs = _.clone($(this).data('action_attrs'));
if (new_attrs.domain) {
new_attrs.domain = new_attrs.domain_string;
delete(new_attrs.domain_string);
}
if (new_attrs.context) {
new_attrs.context = new_attrs.context_string;
delete(new_attrs.context_string);
}
actions.push(new_attrs);
});
board.columns.push(actions);
});
var arch = QWeb.render('DashBoard.xml', board);
this.rpc('/web/view/add_custom', {
view_id: this.view.fields_view.view_id,
arch: arch
}, function() {
self.$element.find('.oe_dashboard_link_reset').show();
});
},
on_load_action: function(result, index, action_attrs) {
var self = this,
action = result.result,
view_mode = action_attrs.view_mode;
if (action_attrs.context && action_attrs.context['dashboard_merge_domains_contexts'] === false) {
// TODO: replace this 6.1 workaround by attribute on <action/>
action.context = action_attrs.context || {};
action.domain = action_attrs.domain || [];
} else {
if (action_attrs.context) {
action.context = _.extend((action.context || {}), action_attrs.context);
}
if (action_attrs.domain) {
action.domain = action.domain || [];
action.domain.unshift.apply(action.domain, action_attrs.domain);
}
}
var action_orig = _.extend({ flags : {} }, action);
if (view_mode && view_mode != action.view_mode) {
action.views = _.map(view_mode.split(','), function(mode) {
mode = mode === 'tree' ? 'list' : mode;
return _(action.views).find(function(view) { return view[1] == mode; })
|| [false, mode];
});
}
action.flags = {
search_view : false,
sidebar : false,
views_switcher : false,
action_buttons : false,
pager: false,
low_profile: true,
display_title: false,
list: {
selectable: false
}
};
var am = new instance.web.ActionManager(this),
// FIXME: ideally the dashboard view shall be refactored like kanban.
$action = $('#' + this.view.element_id + '_action_' + index);
$action.parent().data('action_attrs', action_attrs);
this.action_managers.push(am);
am.appendTo($action);
am.do_action(action);
am.do_action = function (action) {
self.do_action(action);
};
if (action_attrs.creatable && action_attrs.creatable !== 'false') {
var action_id = parseInt(action_attrs.creatable, 10);
$action.parent().find('button.oe_dashboard_button_create').click(function() {
if (isNaN(action_id)) {
action_orig.flags.default_view = 'form';
self.do_action(action_orig);
} else {
self.rpc('/web/action/load', {
action_id: action_id
}, function(result) {
result.result.flags = result.result.flags || {};
result.result.flags.default_view = 'form';
self.do_action(result.result);
});
}
});
}
if (am.inner_widget) {
am.inner_widget.on_mode_switch.add(function(mode) {
var new_views = [];
_.each(action_orig.views, function(view) {
new_views[view[1] === mode ? 'unshift' : 'push'](view);
});
if (!new_views.length || new_views[0][1] !== mode) {
new_views.unshift([false, mode]);
}
action_orig.views = new_views;
action_orig.res_id = am.inner_widget.dataset.ids[am.inner_widget.dataset.index];
self.do_action(action_orig);
});
}
},
renderElement: function() {
this._super();
var check = _.detect(this.node.children, function(column, column_index) {
return _.detect(column.children,function(element){
return element.tag === "action"? element: false;
});
});
if (!check) {
return this.no_result();
}
// We should start with three columns available
for (var i = this.node.children.length; i < 3; i++) {
this.node.children.push({
tag: 'column',
attrs: {},
children: []
});
}
var rendered = QWeb.render(this.form_template, this);
this.$element.html(rendered);
},
no_result: function() {
if (this.view.options.action.help) {
this.$element.append(
$('<div class="oe_view_nocontent">')
.append($('<div>').html(this.view.options.action.help || " "))
);
}
},
do_reload: function() {
var view_manager = this.view.getParent(),
action_manager = view_manager.getParent();
this.view.destroy();
action_manager.do_action(view_manager.action);
}
});
instance.web.form.DashBoardLegacy = instance.web.form.DashBoard.extend({
renderElement: function() {
if (this.node.tag == 'hpaned') {
this.node.attrs.style = '2-1';
} else if (this.node.tag == 'vpaned') {
this.node.attrs.style = '1';
}
this.node.tag = 'board';
_.each(this.node.children, function(child) {
if (child.tag.indexOf('child') == 0) {
child.tag = 'column';
var actions = [], first_child = child.children[0];
if (first_child && first_child.tag == 'vpaned') {
_.each(first_child.children, function(subchild) {
actions.push.apply(actions, subchild.children);
});
child.children = actions;
}
}
});
this._super(this);
}
});
instance.web.form.tags.add('hpaned', 'instance.web.form.DashBoardLegacy');
instance.web.form.tags.add('vpaned', 'instance.web.form.DashBoardLegacy');
instance.web.form.tags.add('board', 'instance.web.form.DashBoard');
instance.board.AddToDashboard = instance.web.search.Input.extend({
template: 'SearchView.addtodashboard',
_in_drawer: true,
start: function () {
var self = this;
this.$element
.on('click', 'h4', this.proxy('show_option'))
.on('submit', 'form', function (e) {
e.preventDefault();
self.add_dashboard();
});
return this.load_data().then(this.proxy("render_data"));
},
load_data:function(){
var board = new instance.web.Model('board.board');
return board.call('list');
},
_x:function() {
if (!instance.webclient) { return $.Deferred().reject(); }
var dashboard_menu = instance.webclient.menu.data.data.children;
return new instance.web.Model('ir.model.data')
.query(['res_id'])
.filter([['name','=','menu_reporting_dashboard']])
.first().pipe(function (result) {
var menu = _(dashboard_menu).chain()
.pluck('children')
.flatten(true)
.find(function (child) { return child.id === result.res_id; })
.value();
return menu ? menu.children : [];
});
},
render_data: function(dashboard_choices){
var selection = instance.web.qweb.render(
"SearchView.addtodashboard.selection", {
selections: dashboard_choices});
this.$("input").before(selection)
},
add_dashboard: function(){
var self = this;
var getParent = this.getParent();
var view_parent = this.getParent().getParent();
if (! view_parent.action || ! this.$element.find("select").val()) {
this.do_warn("Can't find dashboard action");
return;
}
var data = getParent.build_search_data();
var context = new instance.web.CompoundContext(getParent.dataset.get_context() || []);
var domain = new instance.web.CompoundDomain(getParent.dataset.get_domain() || []);
_.each(data.contexts, context.add, context);
_.each(data.domains, domain.add, domain);
this.rpc('/board/add_to_dashboard', {
menu_id: this.$element.find("select").val(),
action_id: view_parent.action.id,
context_to_save: context,
domain: domain,
view_mode: view_parent.active_view,
name: this.$element.find("input").val()
}, function(r) {
if (r === false) {
self.do_warn("Could not add filter to dashboard");
} else {
self.$element.toggleClass('oe_opened');
self.do_notify("Filter added to dashboard", '');
}
});
},
show_option:function(){
this.$element.toggleClass('oe_opened');
if (! this.$element.hasClass('oe_opened'))
return;
this.$("input").val(this.getParent().fields_view.name || "" );
}
});
instance.web.SearchView.include({
add_common_inputs: function() {
this._super();
(new instance.board.AddToDashboard(this));
}
});
};

View File

@ -0,0 +1,80 @@
<template>
<t t-name="DashBoard">
<div class="oe_dashboard_links">
<button type="button" class="button oe_dashboard_link_reset" title="Reset Layout.." t-att-style="view.fields_view.custom_view_id ? null : 'display: none'">
<img src="/board/static/src/img/layout_2-1.png" width="16" height="16"/>
<span> Reset </span>
</button>
<button type="button" class="button oe_dashboard_link_change_layout" title="Change Layout..">
<img src="/board/static/src/img/layout_1-1-1.png" width="16" height="16"/>
<span> Change Layout </span>
</button>
</div>
<table t-att-data-layout="node.attrs.style" t-attf-class="oe_dashboard oe_dashboard_layout_#{node.attrs.style}" cellspacing="0" cellpadding="0" border="0">
<tr>
<td t-foreach="node.children" t-as="column" t-if="column.tag == 'column'"
t-att-id="view.element_id + '_column_' + column_index" t-attf-class="oe_dashboard_column index_#{column_index}">
<t t-foreach="column.children" t-as="action" t-if="action.tag == 'action'" t-call="DashBoard.action"/>
</td>
</tr>
</table>
</t>
<t t-name="DashBoard.action">
<div t-att-data-id="action.attrs.name" class="oe_action">
<h2 t-attf-class="oe_header #{action.attrs.string ? '' : 'oe_header_empty'}">
<t t-esc="action.attrs.string"/>
<t t-if="!action.attrs.string">&amp;nbsp;</t>
<button t-if="action.attrs.creatable and action.attrs.creatable !== 'false'" class="oe_button oe_button_create">Create</button>
<span class='oe_icon oe_close'></span>
<span class='oe_icon oe_minimize oe_fold' t-if="!action.attrs.fold"></span>
<span class='oe_icon oe_maximize oe_fold' t-if="action.attrs.fold"></span>
</h2>
<div t-attf-id="#{view.element_id}_action_#{column_index}_#{action_index}" class="oe_content" t-att-style="action.attrs.fold ? 'display: none' : null"></div>
</div>
</t>
<t t-name="DashBoard.layouts">
<div class="oe_dashboard_layout_selector">
<p>
<strong>Choose dashboard layout</strong>
</p>
<ul>
<li t-foreach="'1 1-1 1-1-1 1-2 2-1'.split(' ')" t-as="layout" t-att-data-layout="layout">
<img t-attf-src="/board/static/src/img/layout_#{layout}.png"/>
<img t-if="layout == current_layout"
src="/web/static/src/img/icons/gtk-apply.png" width="16" height="16" class="oe_dashboard_selected_layout"/>
</li>
</ul>
</div>
</t>
<t t-name="DashBoard.xml">
<form t-att-string="form_title" version="7.0">
<board t-att-style="style">
<column t-foreach="columns" t-as="column">
<action t-foreach="column" t-as="action" t-att="action"/>
</column>
</board>
</form>
</t>
<div t-name="HomeWidget" class="oe_dashboard_home_widget"/>
<t t-name="HomeWidget.content">
<h3><t t-esc="widget.title"/></h3>
<iframe width="100%" frameborder="0" t-att-src="url"/>
</t>
<div t-name="SearchView.addtodashboard" class="oe_searchview_dashboard">
<h4>Add to Dashboard</h4>
<form>
<p><input placeholder="Title of new dashboard item"/></p>
<button class="oe_apply" type="submit">Add</button>
</form>
</div>
<t t-name="SearchView.addtodashboard.selection">
<select>
<option t-foreach="selections" t-as="element"
t-att-value="element.id ">
<t t-esc="element.name"/></option>
</select>
</t>
</template>

View File

@ -1,25 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# 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/>.
#
##############################################################################
import board_menu_create
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,102 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# 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/>.
#
##############################################################################
from osv import fields, osv
from tools.translate import _
class board_menu_create(osv.osv_memory):
"""
Create Menu
"""
def view_init(self, cr, uid, fields, context=None):
"""
This function checks for precondition before wizard executes
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param fields: List of fields for default value
@param context: A standard dictionary for contextual values
check dashboard view on menu name field.
@return: False
"""
data = context and context.get('active_id', False) or False
if data:
return False
def board_menu_create(self, cr, uid, ids, context=None):
"""
Create Menu.
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of Board Menu Create's IDs
@return: Dictionary {}.
"""
if context is None:
context = {}
context_id = context and context.get('active_id', False) or False
if context_id:
board = self.pool.get('board.board').browse(cr, uid, context_id, context=context)
action_id = self.pool.get('ir.actions.act_window').create(cr, uid, {
'name': board.name,
'view_type': 'form',
'view_mode': 'form',
'res_model': 'board.board',
'view_id': board.view_id.id,
'help': _('''<div class="oe_empty_custom_dashboard">
<p>
<b>This dashboard is empty.</b>
</p><p>
To add the first report into this dashboard, go to any
menu, switch to list or graph view, and click <i>'Add to
Dashboard'</i> in the extended search options.
</p><p>
You can filter and group data before inserting into the
dashboard using the search options.
</p>
</div>
''')
})
obj_menu = self.pool.get('ir.ui.menu')
#start Loop
for data in self.browse(cr, uid, ids, context=context):
obj_menu.create(cr, uid, {
'name': data.menu_name,
'parent_id': data.menu_parent_id.id,
'action': 'ir.actions.act_window,' + str(action_id)
}, context=context)
#End Loop
return {'type': 'ir.actions.act_window_close'}
_name = "board.menu.create"
_description = "Menu Create"
_columns = {
'menu_name': fields.char('Menu Name', size=64, required=True),
'menu_parent_id': fields.many2one('ir.ui.menu', 'Parent Menu', required=True),
}
board_menu_create()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!--Board menu create wizard -->
<record id="view_board_menu_create" model="ir.ui.view">
<field name="name">board.menu.create.form</field>
<field name="model">board.menu.create</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Create Menu For Dashboard" version="7.0">
<group colspan="4" string="Menu Information">
<field name="menu_name"/>
<field name="menu_parent_id"/>
</group>
<footer>
<button string="Create Menu" name="board_menu_create" type="object" class="oe_highlight"/>
or
<button string="Cancel" class="oe_link" special="cancel"/>
</footer>
</form>
</field>
</record>
<!-- Action for Board Menu create wizard. -->
<record id="action_board_menu_create" model="ir.actions.act_window">
<field name="name">Create Board Menu</field>
<field name="res_model">board.menu.create</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="view_board_menu_create"/>
<field name="target">new</field>
</record>
</data>
</openerp>

View File

@ -41,7 +41,7 @@
<!--
CRM CASE STAGE
-->
-->
<!-- Stage Search view -->
<record id="crm_lead_stage_search" model="ir.ui.view">
@ -77,7 +77,7 @@
<!--
LEADS/OPPORTUNITIES CATEGORIES
-->
-->
<!-- Categories Form View -->
<record id="crm_lead_categ_action" model="ir.actions.act_window">
@ -105,7 +105,7 @@
<!--
LEADS
-->
-->
<act_window
id="act_crm_opportunity_crm_phonecall_new"
name="Phone calls"
@ -343,11 +343,7 @@
<div class="oe_kanban_bottom_right">
<a t-if="record.priority.raw_value == 1" type="object" name="set_normal_priority" class="oe_e oe_star_on">7</a>
<a t-if="record.priority.raw_value != 1" type="object" name="set_high_priority" class="oe_e oe_star_off">7</a>
<!--
<t t-if="record.date_deadline.raw_value and record.date_deadline.raw_value lt (new Date())" t-set="red">oe_kaban_status_red</t>
<span t-attf-class="oe_kanban_status #{red}"> </span>
-->
<img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value and record.user_id.raw_value[0])" t-att-title="record.user_id.value" width="24" height="24" class="oe_kanban_avatar"/>
<img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value)" t-att-title="record.user_id.value" width="24" height="24" class="oe_kanban_avatar"/>
</div>
<div class="oe_kanban_footer_left">
<t t-if="record.needaction_pending.raw_value"><span class="oe_kanban_mail_new">New</span></t>
@ -356,14 +352,6 @@
</div>
<div class="oe_clear"></div>
</div>
<!--
<div class="oe_kanban_right">
<a name="case_mark_lost" string="Mark Lost" states="open,pending" type="object" icon="kanban-stop" />
<a name="case_pending" string="Pending" states="draft,open" type="object" icon="kanban-pause" />
<a name="case_open" string="Open" states="pending" type="object" icon="gtk-media-play" />
<a name="case_mark_won" string="Mark Won" states="open,pending" type="object" icon="kanban-apply" />
</div>
-->
</t>
</templates>
</kanban>
@ -417,7 +405,7 @@
<!--
OPPORTUNITY
-->
-->
<!-- Opportunities Form View -->
<record model="ir.ui.view" id="crm_case_form_view_oppor">
@ -429,15 +417,11 @@
<form string="Opportunities" version="7.0">
<header>
<button name="case_mark_won" string="Mark Won" type="object"
states="open" class="oe_highlight"/>
<button name="case_mark_won" string="Mark Won" type="object"
states="draft,pending"/>
states="draft,open,pending" class="oe_highlight"/>
<button name="case_mark_lost" string="Mark Lost" type="object"
states="draft,open" class="oe_highlight"/>
<button name="case_escalate" string="Escalate" type="object"
states="open" />
<button name="case_mark_lost" string="Mark Lost" type="object"
states="draft,open"/>
<button name="case_cancel" string="Cancel" type="object"
states="draft"/>
<field name="stage_id" widget="statusbar" clickable="True"/>
</header>
<sheet>
@ -517,6 +501,7 @@
<group>
<label for="contact_name" />
<div>
<field name="contact_name" class="oe_inline"/>
<field name="title" placeholder="Title" domain="[('domain', '=', 'contact')]" options='{"no_open": true}' class="oe_inline"/>
</div>
<field name="function" />

View File

@ -310,7 +310,7 @@
<a type="object" name="set_priority" args="['1']">
<img t-attf-src="/web/static/src/img/icons/star-#{priority == 1 ? 'on' : 'off'}.png" width="16" height="16" title="Excellent"/>
</a>
<img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value[0])" t-att-title="record.user_id.value" width="24" height="24" class="oe_kanban_avatar"/>
<img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value)" t-att-title="record.user_id.value" width="24" height="24" class="oe_kanban_avatar"/>
</div>
</div>

View File

@ -7,8 +7,8 @@
<field name="type">form</field>
<field name="inherit_id" ref="base_calendar.view_crm_meeting_form"/>
<field name="arch" type="xml">
<field name="categ_id" position="replace">
<field name="categ_id" widget="selection" domain="[('user_id', 'in', [uid, False])]"/>
<field name="categ_ids" position="attributes">
<attribute name="domain">[('user_id', 'in', [uid, False])]</attribute>
</field>
</field>
</record>

View File

@ -51,7 +51,6 @@ Main features:
'wizard/pos_confirm.xml',
'wizard/pos_discount.xml',
'wizard/pos_open_statement.xml',
'wizard/pos_close_statement.xml',
'wizard/pos_payment_report_user_view.xml',
'wizard/pos_sales_user.xml',
'wizard/pos_receipt_view.xml',

View File

@ -195,23 +195,17 @@ class pos_session(osv.osv):
required=True,
select=1,
domain="[('state', '=', 'active')]",
# readonly=True,
# states={'draft' : [('readonly', False)]}
),
'name' : fields.char('Session ID', size=32,
required=True,
# readonly=True,
# states={'draft' : [('readonly', False)]}
),
'name' : fields.char('Session ID', size=32, required=True, readonly=True),
'user_id' : fields.many2one('res.users', 'Responsible',
required=True,
select=1,
# readonly=True,
# states={'draft' : [('readonly', False)]}
readonly=True,
states={'opening_control' : [('readonly', False)]}
),
'start_at' : fields.datetime('Opening Date'),
'stop_at' : fields.datetime('Closing Date'),
'start_at' : fields.datetime('Opening Date', readonly=True),
'stop_at' : fields.datetime('Closing Date', readonly=True),
'state' : fields.selection(POS_SESSION_STATE, 'State',
required=True, readonly=True,
@ -281,7 +275,7 @@ class pos_session(osv.osv):
for session in self.browse(cr, uid, ids, context=None):
# open if there is no session in 'opening_control', 'opened', 'closing_control' for one user
domain = [
('state', '!=', 'closed'),
('state', 'not in', ('closed','closing_control')),
('user_id', '=', uid)
]
count = self.search_count(cr, uid, domain, context=context)
@ -344,7 +338,7 @@ class pos_session(osv.osv):
record.write(values, context=context)
for st in record.statement_ids:
st.button_open(context=context)
return True
return self.open_frontend_cb(cr, uid, ids, context=context)
def wkf_action_opening_control(self, cr, uid, ids, context=None):
return self.write(cr, uid, ids, {'state' : 'opening_control'}, context=context)
@ -352,7 +346,7 @@ class pos_session(osv.osv):
def wkf_action_closing_control(self, cr, uid, ids, context=None):
for session in self.browse(cr, uid, ids, context=context):
for statement in session.statement_ids:
if not statement.journal_id.closing_control:
if statement.id <> session.cash_register_id.id:
if statement.balance_end<>statement.balance_end_real:
self.pool.get('account.bank.statement').write(cr, uid,
[statement.id], {'balance_end_real': statement.balance_end})
@ -377,7 +371,7 @@ class pos_session(osv.osv):
name= _('Point of Sale Loss')
if not account_id:
raise osv.except_osv( _('Error!'),
_("Please set your profit and loss accounts on your payment method '%s'.") % (st.journal_id.name,))
_("Please set your profit and loss accounts on your payment method '%s'. This will allow OpenERP to post the difference of %.2f in your ending balance. To close this session, you can update the 'Closing Cash Control' to avoid any difference.") % (st.journal_id.name,st.difference))
bsl.create(cr, uid, {
'statement_id': st.id,
'amount': st.difference,
@ -388,7 +382,15 @@ class pos_session(osv.osv):
getattr(st, 'button_confirm_%s' % st.journal_id.type)(context=context)
self._confirm_orders(cr, uid, ids, context=context)
return self.write(cr, uid, ids, {'state' : 'closed'}, context=context)
self.write(cr, uid, ids, {'state' : 'closed'}, context=context)
obj = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'point_of_sale', 'menu_point_root')[1]
return {
'type' : 'ir.actions.client',
'name' : 'Point of Sale Menu',
'tag' : 'reload',
'params' : {'menu_id': obj},
}
def _confirm_orders(self, cr, uid, ids, context=None):
wf_service = netsvc.LocalService("workflow")
@ -413,10 +415,8 @@ class pos_session(osv.osv):
def open_frontend_cb(self, cr, uid, ids, context=None):
if not context:
context = {}
if not ids:
return {}
context.update({'session_id' : ids[0]})
return {
'type' : 'ir.actions.client',

View File

@ -15,7 +15,7 @@
</data>
<data>
<record model="pos.config" id="pos_config_main">
<field name="name">Main PoS</field>
<field name="name">Main</field>
</record>
</data>

View File

@ -3,9 +3,9 @@
<data>
<!-- Top menu item -->
<menuitem name="PoS Backend"
<menuitem name="Point of Sale"
id="menu_point_root"
groups="group_pos_manager"
groups="group_pos_manager,group_pos_user"
sequence="140"/>
<record id="categ_others" model="pos.category">
@ -32,7 +32,7 @@
<group col="4" colspan="4">
<field name="name"/>
<field name="date_order"/>
<field name="session_id" required="1" />
<field name="session_id" required="1"/>
<field name="partner_id" on_change="onchange_partner_id(partner_id)" context="{'search_default_customer':1}" attrs="{'readonly': [('state','=','invoiced')]}"/>
</group>
<notebook colspan="4">
@ -61,14 +61,14 @@
<group class="oe_subtotal_footer">
<field name="amount_tax"/>
<field name="amount_total"/>
<button name="button_dummy" string="Update" icon="gtk-execute" states="draft" />
<button name="button_dummy" string="Update" icon="gtk-execute" states="draft"/>
</group>
</page>
<page string="Payments">
<field name="statement_ids" colspan="4" nolabel="1">
<tree editable="bottom" string="Statement lines">
<field name="journal_id"/>
<field name="statement_id" />
<field name="statement_id"/>
<field name="amount"/>
</tree>
<form string="Statement lines" version="7.0">
@ -155,8 +155,8 @@
</field>
</record>
<menuitem name="Daily Operations" id="menu_point_of_sale" parent="menu_point_root" sequence="10" />
<menuitem parent="menu_point_of_sale" id="menu_point_ofsale" action="action_pos_pos_form" sequence="1" groups="group_pos_manager,group_pos_user"/>
<menuitem name="Daily Operations" id="menu_point_of_sale" parent="menu_point_root" sequence="10"/>
<menuitem parent="menu_point_of_sale" id="menu_point_ofsale" action="action_pos_pos_form" sequence="2" groups="group_pos_manager,group_pos_user"/>
<menuitem name="Products" id="menu_point_of_sale_product" parent="menu_point_root" sequence="15" />
<record id="product_normal_action" model="ir.actions.act_window">
@ -764,18 +764,6 @@
</record>
<!-- Top menu item -->
<!--
right now it's not possible to directly call a client action
from a menuitem, so we can't use this shortcut element and
use an explicit record element instead
-->
<record id="menu_point_root_touchscreen" model="ir.ui.menu">
<field name="name">Point of Sale</field>
<field name="action" ref="action_pos_pos"/>
<field name="groups_id" eval="[(6, 0, [ref('point_of_sale.group_pos_manager'), ref('point_of_sale.group_pos_user')])]"/>
<field name="sequence">150</field>
</record>
<record model="ir.ui.view" id="view_pos_config_form">
<field name="name">pos.config.form.view</field>
<field name="model">pos.config</field>
@ -896,81 +884,93 @@
<field name="arch" type="xml">
<form string="Point of Sale Session" version="7.0">
<header>
<button name="open" type="workflow" string="Validate &amp; Open Session" states="opening_control" />
<button name="cashbox_control" type="workflow" string="End of Session" states="opened" />
<button name="close" type="workflow" string="Validate &amp; Close" states="closing_control,opened" />
<button name="open" type="workflow" string="Validate &amp; Open Session" states="opening_control" class="oe_highlight"/>
<button name="cashbox_control" type="workflow" string="End of Session" states="opened"
class="oe_highlight"/>
<button name="close" type="workflow" string="Validate Closing &amp; Post Entries" states="closing_control"
class="oe_highlight"/>
<button name="open_frontend_cb" type="object" string="Start Selling" states="opened"/>
<div class="oe_right">
<field name="state" widget="statusbar" statusbar_visible="opening_control,opened,closing_control,closed" nolabel="1"/>
</div>
</header>
<sheet>
<group>
<field name="config_id"/>
<div class="oe_right oe_button_box">
<button name="%(action_pos_box_in)d" string="Put Money In" type="action" states="opened,closing_control"/>
<button name="%(action_pos_box_out)d" string="Take Money Out" type="action" states="opened,closing_control"/>
</div>
<h1 class="oe_title">
Point of Sale Session:
<field name="name" attrs="{'invisible': [('name','=','/')]}" class="oe_inline"/>
</h1>
<field name="config_id" invisible="1"/>
<field name="has_opening_control" invisible="1" />
<field name="has_closing_control" invisible="1" />
<group>
<button name="%(action_pos_box_in)d" string="Put Money In" type="action" states="opened"/>
<button name="%(action_pos_box_out)d" string="Take Money Out" type="action" states="opened"/>
<button name="open_frontend_cb" type="object" string="Open Point Of Sale" states="opened" />
</group>
<newline/>
<field name="user_id"/>
<field name="name"/>
<newline/>
<field name="start_at" attrs="{'insivible' : [('state', '=', 'opening_control')]}"/>
<field name="stop_at" attrs="{'insivible' : [('state', '=', 'opening_control')]}"/>
<separator string="Cash Control" colspan="4"/>
<field name="cash_register_id" invisible="1" />
<field name="opening_details_ids" colspan="4" nolabel="1" attrs="{'invisible' : [('state', 'not in', ('opening_control',))]}">
<tree string="Opening Cashbox Lines" editable="bottom">
<field name="pieces" readonly="1" />
<field name="number_opening" string="Opening Unit Numbers" on_change="on_change_sub_opening(pieces, number_opening, parent.balance_end)" />
<field name="subtotal_opening" string="Opening Subtotal" sum="Total"/>
</tree>
</field>
<group>
<group>
<field name="user_id"/>
</group>
<group>
<field name="start_at" attrs="{'invisible' : [('state', '=', 'opening_control')]}"/>
<field name="stop_at" attrs="{'invisible' : [('state', '&lt;&gt;', 'closed')]}"/>
</group>
<newline/>
<field name="details_ids" colspan="4" nolabel="1" attrs="{'invisible': [('state', '=', 'opening_control')]}">
<tree string="Cashbox Lines" editable="bottom">
<field name="pieces" readonly="1" />
<field name="number_opening" readonly="1"/>
<field name="subtotal_opening"/>
<field name="number_closing"/>
<field name="subtotal_closing"/>
</tree>
</field>
<group col="4" colspan="4">
<group col="2" colspan="2">
<separator string="Cash Balance" colspan="2"/>
<field name="cash_register_balance_start" readonly="1" string="Opening Cash Control"/>
<field name="cash_register_total_entry_encoding" attrs="{'invisible' : [('state', '=', 'opening_control')]}" string="+ Transactions"/>
<field name="cash_register_balance_end" attrs="{'invisible' : [('state', '=', 'opening_control')]}" string="= Theorical Cash Closing"/>
</group>
<group col="2" colspan="2" attrs="{'invisible' : [('state', '=', 'opening_control')]}">
<separator string="Cash Closing Balance" colspan="2"/>
<field name="cash_register_balance_end_real"/>
<field name="cash_register_difference" />
</group>
<group string="Opening Cash Control">
<field name="opening_details_ids" nolabel="1" colspan="2" attrs="{'readonly' : [('state', 'not in', ('opening_control',))]}">
<tree string="Opening Cashbox Lines" editable="bottom">
<field name="pieces" readonly="1" />
<field name="number_opening" string="Opening Unit Numbers" on_change="on_change_sub_opening(pieces, number_opening)" />
<field name="subtotal_opening" string="Opening Subtotal" sum="Total"/>
</tree>
</field>
</group>
<group string="Closing Cash Control" attrs="{'invisible': [('state', '=', 'opening_control')]}">
<field name="details_ids" nolabel="1" colspan="2">
<tree string="Cashbox Lines" editable="bottom">
<field name="pieces" readonly="1" />
<field name="number_closing"/>
<field name="subtotal_closing"/>
</tree>
</field>
</group>
<separator string="Summary by Payment Methods" colspan="4" attrs="{'invisible' : [('state', '=', 'opening_control')]}"/>
<field name="statement_ids" colspan="4" nolabel="1" attrs="{'invisible' : [('state', '=', 'opening_control')]}">
<tree string="Statements">
<field name="name" />
<field name="journal_id" />
<field name="balance_start" />
<field name="total_entry_encoding" />
<field name="balance_end_real" />
<field name="difference" />
<field name="currency" />
<field name="state" />
</tree>
</field>
<div>
<group class="oe_subtotal_footer oe_right">
<field name="cash_register_balance_start" readonly="1" string="Opening Balance" class="oe_subtotal_footer_separator"/>
<field name="cash_register_total_entry_encoding" attrs="{'invisible' : [('state', '=', 'opening_control')]}" string="+ Transactions"/>
<field name="cash_register_balance_end" attrs="{'invisible' : [('state', '=', 'opening_control')]}" string="= Theorical Balance"/>
</group>
<div attrs="{'invisible' : [('state', '&lt;&gt;', 'opening_control')]}" class="oe_view_nocontent" groups="point_of_sale.group_pos_manager">
<p class="oe_view_nocontent_create">
You can define another list of available currencies on the
<i>Cash Registers</i> tab of the <b><field name="cash_register_id" class="oe_inline"/></b>
payment method.
</p>
</div>
</div>
<group class="oe_subtotal_footer oe_right" attrs="{'invisible' : [('state', '=', 'opening_control')]}">
<field name="cash_register_balance_end_real" class="oe_subtotal_footer_separator"/>
<field name="cash_register_difference" class="oe_subtotal_footer_separator"/>
</group>
</group>
<separator string="Summary by Payment Methods" attrs="{'invisible' : [('state', '=', 'opening_control')]}"/>
<field name="statement_ids" attrs="{'invisible' : [('state', '=', 'opening_control')]}">
<tree string="Statements">
<field name="name" />
<field name="journal_id" />
<field name="balance_start" />
<field name="total_entry_encoding" />
<field name="balance_end_real" />
<field name="difference" />
<field name="currency" />
<field name="state" />
</tree>
</field>
</sheet>
</form>
</field>
@ -987,6 +987,7 @@
<field name="user_id" />
<field name="start_at" />
<field name="stop_at" />
<field name="state" />
</tree>
</field>
</record>
@ -1021,18 +1022,11 @@
<field name="search_view_id" ref="view_pos_session_search" />
</record>
<menuitem
parent="menu_point_rep"
action="action_pos_session"
id="menu_pos_session"
sequence="0"
groups="group_pos_manager"/>
<menuitem
parent="menu_point_of_sale"
action="action_pos_session"
id="menu_pos_session_all"
sequence="0"
sequence="1"
groups="group_pos_manager"/>
<record id="view_pos_order_filter" model="ir.ui.view">
@ -1060,7 +1054,9 @@
</field>
</record>
<menuitem action="action_pos_session_opening" parent="menu_point_of_sale" id="menu_pos_session_opening" sequence="0" />
<menuitem action="action_pos_session_opening"
parent="menu_point_of_sale"
id="menu_pos_session_opening" sequence="0"/>
</data>
</openerp>

View File

@ -875,7 +875,7 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
},
close: function() {
this.pos.barcode_reader.disconnect();
return new instance.web.Model("ir.model.data").get_func("search_read")([['name', '=', 'action_pos_close_statement']], ['res_id']).pipe(
return new instance.web.Model("ir.model.data").get_func("search_read")([['name', '=', 'action_client_pos_menu']], ['res_id']).pipe(
_.bind(function(res) {
return this.rpc('/web/action/load', {'action_id': res[0]['res_id']}).pipe(_.bind(function(result) {
var action = result.result;

View File

@ -22,7 +22,6 @@
import pos_confirm
import pos_discount
import pos_open_statement
import pos_close_statement
import pos_details
import pos_sales_user
import pos_sales_user_today

View File

@ -1,76 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# 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/>.
#
##############################################################################
from osv import osv
from tools.translate import _
class pos_close_statement(osv.osv_memory):
_name = 'pos.close.statement'
_description = 'Close Statements'
def cancel_wizard(self, cr, uid, ids, context=None):
if context.get('cancel_action'):
return context['cancel_action']
def close_statement(self, cr, uid, ids, context=None):
"""
Close the statements
@param self: The object pointer.
@param cr: A database cursor
@param uid: ID of the user currently logged in
@param context: A standard dictionary
@return : Blank Dictionary
"""
context = context or {}
mod_obj = self.pool.get('ir.model.data')
statement_obj = self.pool.get('account.bank.statement')
journal_obj = self.pool.get('account.journal')
j_ids = journal_obj.search(cr, uid, [('journal_user','=',1)], context=context)
ids = statement_obj.search(cr, uid, [('state', '!=', 'confirm'), ('user_id', '=', uid), ('journal_id', 'in', j_ids)], context=context)
if not ids:
raise osv.except_osv(_('Message'), _('Cash registers are already closed.'))
for statement in statement_obj.browse(cr, uid, ids, context=context):
statement_obj.write(cr, uid, [statement.id], {
'balance_end_real': statement.balance_end
}, context=context)
if not statement.journal_id.check_dtls:
statement_obj.button_confirm_cash(cr, uid, [statement.id], context=context)
tree_res = mod_obj.get_object_reference(cr, uid, 'point_of_sale', 'view_cash_statement_pos_tree')
tree_id = tree_res and tree_res[1] or False
form_res = mod_obj.get_object_reference(cr, uid, 'account', 'view_bank_statement_form2')
form_id = form_res and form_res[1] or False
search_res = mod_obj.get_object_reference(cr, uid, 'account', 'view_account_bank_statement_filter')
return {
'domain': str([('id', 'in', ids)]),
'name': _('Close Cash Registers'),
'view_type': 'form',
'view_mode': 'tree,form',
'search_view_id': search_res and search_res[1] or False,
'res_model': 'account.bank.statement',
'views': [(tree_id, 'tree'), (form_id, 'form')],
'type': 'ir.actions.act_window'
}
pos_close_statement()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,45 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- Point of Sale Confirm -->
<record id="view_pos_close_statement" model="ir.ui.view">
<field name="name">Close Statements</field>
<field name="model">pos.close.statement</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Close Cash Registers" version="7.0">
<header>
<button name="close_statement" string="Yes"
type="object" class="oe_highlight" />
<button type="object" name="cancel_wizard"
string="No" invisible="not context.get('cancel_action')" class="oe_highlight" />
or
<button string="Cancel" class="oe_link" special="cancel" />
</header>
<separator string="Do you want to close your cash registers?"/>
<label string="OpenERP will close all cash registers he can close automatically without validation. He will also open all cash registers for which you have to control the ending balance before closing manually."/>
</form>
</field>
</record>
<!--
<act_window name="Close Statements"
res_model="pos.close.statement"
src_model="account.bank.statement"
view_mode="form"
target="new"
key2="client_action_multi"
id="act_pos_open_statement"/>
-->
<record id="action_pos_close_statement" model="ir.actions.act_window">
<field name="name">Close Cash Register</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">pos.close.statement</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</data>
</openerp>

View File

@ -10,8 +10,26 @@ class pos_session_opening(osv.osv_memory):
_columns = {
'pos_config_id' : fields.many2one('pos.config', 'Point of Sale', required=True),
'pos_session_id' : fields.many2one('pos.session', 'PoS Session'),
'pos_state' : fields.char('Session State'),
}
def open_ui(self, cr, uid, ids, context=None):
context = context or {}
data = self.browse(cr, uid, ids[0], context=context)
context['active_id'] = data.pos_session_id.id
return {
'type' : 'ir.actions.client',
'name' : 'Start Point Of Sale',
'tag' : 'pos.ui',
'context' : context
}
def open_existing_session_cb_close(self, cr, uid, ids, context=None):
wf_service = netsvc.LocalService("workflow")
wizard = self.browse(cr, uid, ids[0], context=context)
wf_service.trg_validate(uid, 'pos.session', wizard.pos_session_id.id, 'cashbox_control', cr)
return self.open_session_cb(cr, uid, ids, context)
def open_session_cb(self, cr, uid, ids, context=None):
assert len(ids) == 1, "you can open only one session at a time"
proxy = self.pool.get('pos.session')
@ -42,18 +60,21 @@ class pos_session_opening(osv.osv_memory):
}
def on_change_config(self, cr, uid, ids, config_id, context=None):
result = {
'pos_session_id': False,
'pos_state': False
}
if not config_id:
return {}
return {'value': result}
proxy = self.pool.get('pos.session')
session_ids = proxy.search(cr, uid, [
('state', '<>', 'closed'),
('config_id', '=', config_id),
], context=context)
return {
'value' : {
'pos_session_id' : session_ids and session_ids[0] or False,
}
}
if session_ids:
result['pos_state'] = proxy.browse(cr, uid, session_ids[0], context=context).state
result['pos_session_id'] = session_ids[0]
return {'value' : result}
def default_get(self, cr, uid, fieldnames, context=None):
so = self.pool.get('pos.session')
@ -63,9 +84,10 @@ class pos_session_opening(osv.osv_memory):
else:
current_user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
result = current_user.pos_config and current_user.pos_config.id or False
if not result:
r = self.pool.get('pos.config').search(cr, uid, [], context=context)
result = r and r[0] or False
return {
'pos_config_id' : result,
'pos_session_id': session_ids and session_ids[0] or False
'pos_config_id' : result
}
pos_session_opening()

View File

@ -7,28 +7,54 @@
<field name="arch" type="xml">
<form string="PoS Session Opening" version="7.0">
<separator string="Select your Point of Sale" colspan="4" />
<field name="pos_config_id" on_change="on_change_config(pos_config_id)" widget="selection" domain="[('state','=','active')]"/>
<field name="pos_session_id" invisible="1"/>
<group colspan="4">
<button special="cancel" icon="gtk-cancel" string="Cancel" />
<button name="open_existing_session_cb" type="object" string="Open Session" icon="gtk-ok"
attrs="{'invisible' : [('pos_session_id', '=', False)]}"
/>
<button name="open_session_cb" type="object" string="New Session" icon="gtk-ok"
attrs="{'invisible' : [('pos_session_id', '!=', False)]}"
/>
<group>
<field name="pos_config_id" on_change="on_change_config(pos_config_id)"
widget="selection" domain="[('state','=','active')]"
class="oe_inline"/>
</group>
<field name="pos_session_id" invisible="1"/>
<field name="pos_state" invisible="1"/>
<button name="open_ui" type="object" string="Start Selling"
attrs="{'invisible' : [('pos_state', 'not in', ('opened',))]}"
class="oe_highlight"
/>
<button name="open_existing_session_cb" type="object" string="Open Session"
attrs="{'invisible' : [('pos_state', 'not in', ('opening_control',))]}"
class="oe_highlight"
/>
<button name="open_existing_session_cb_close" type="object" string="Close Session"
attrs="{'invisible' : [('pos_state', 'not in', ('opened',))]}"
/>
<button name="open_existing_session_cb" type="object" string="Close Session"
attrs="{'invisible' : [('pos_state', 'not in', ('closing_control',))]}"
class="oe_highlight"
/>
<button name="open_session_cb" type="object" string="New Session"
attrs="{'invisible' : ['|', ('pos_state', '!=', False),('pos_config_id','=',False)]}"
class="oe_highlight"
/>
<div attrs="{'invisible' : ['|', ('pos_state', '!=', False),('pos_config_id','=',False)]}" class="oe_view_nocontent">
<p class="oe_view_nocontent_create">
Click to start a session.
</p><p>
You will first have to control your cash amount in your cash register.
Then you will be able to open the session and start selling with the touchscreen
interface.
</p>
</div>
</form>
</field>
</record>
<record id="action_pos_session_opening" model="ir.actions.act_window">
<field name="name">Open/Close a Session</field>
<field name="name">Your Session</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">pos.session.opening</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="target">inline</field>
</record>
</data>
</openerp>

View File

@ -49,7 +49,7 @@
<t t-if="record.date_deadline.raw_value and record.date_deadline.raw_value lt (new Date())">
<span t-attf-class="oe_kanban_status oe_kaban_status_red"> </span>
</t>
<img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value[0])" t-att-title="record.user_id.value" width="24" height="24" class="oe_kanban_avatar"/>
<img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value)" t-att-title="record.user_id.value" width="24" height="24" class="oe_kanban_avatar"/>
</div>
</div>
</div>

View File

@ -788,7 +788,7 @@ class task(base_stage, osv.osv):
}),
'user_id': fields.many2one('res.users', 'Assigned to'),
'delegated_user_id': fields.related('child_ids', 'user_id', type='many2one', relation='res.users', string='Delegated To'),
'partner_id': fields.many2one('res.partner', 'Partner'),
'partner_id': fields.many2one('res.partner', 'Contact'),
'work_ids': fields.one2many('project.task.work', 'task_id', 'Work done'),
'manager_id': fields.related('project_id', 'analytic_account_id', 'user_id', type='many2one', relation='res.users', string='Project Manager'),
'company_id': fields.many2one('res.company', 'Company'),

View File

@ -71,7 +71,7 @@
<!-- Categories -->
<record id="project_category_01" model="project.category">
<field name="name">Partner's suggestion</field>
<field name="name">Contact's suggestion</field>
</record>
<record id="project_category_02" model="project.category">
<field name="name">Feature request</field>

View File

@ -171,10 +171,10 @@
<separator/>
<filter string="Project(s) Manager" domain="[('user_id','=',uid)]" help="Projects in which I am a manager" icon="terp-personal"/>
<field name="user_id" string="Project Manager"/>
<field name="partner_id" string="Partner"/>
<field name="partner_id" string="Contact"/>
<group expand="0" string="Group By...">
<filter string="Manager" name="Manager" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>
<filter string="Partner" name="Partner" icon="terp-partner" domain="[]" context="{'group_by':'partner_id'}"/>
<filter string="Contact" name="Partner" icon="terp-partner" domain="[]" context="{'group_by':'partner_id'}"/>
<filter string="Parent" name="Parent" help="Parent" icon="terp-folder-blue" domain = "[]" context="{'group_by':'parent_id'}"/>
</group>
</search>
@ -549,7 +549,7 @@
<a t-if="record.kanban_state.raw_value === 'blocked'" type="object" string="Blocked" name="set_kanban_state_normal" class="oe_kanban_status oe_kanban_status_red"> </a>
<a t-if="record.priority.raw_value == 1" type="object" string="Priority" name="set_normal_priority" class="oe_e oe_star_on">7</a>
<a t-if="record.priority.raw_value != 1" type="object" string="Priority" name="set_high_priority" class="oe_e oe_star_off">7</a>
<img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value[0])" t-att-title="record.user_id.value" width="24" height="24" class="oe_kanban_avatar"/>
<img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value)" t-att-title="record.user_id.value" width="24" height="24" class="oe_kanban_avatar"/>
</div>
<div class="oe_kanban_footer_left">
<span groups="project.group_time_work_estimation_tasks" title="Remaining hours">

View File

@ -53,7 +53,7 @@ class report_project_task_user(osv.osv):
'month':fields.selection([('01','January'), ('02','February'), ('03','March'), ('04','April'), ('05','May'), ('06','June'), ('07','July'), ('08','August'), ('09','September'), ('10','October'), ('11','November'), ('12','December')], 'Month', readonly=True),
'state': fields.selection([('draft', 'Draft'), ('open', 'In Progress'), ('pending', 'Pending'), ('cancelled', 'Cancelled'), ('done', 'Done')],'Status', readonly=True),
'company_id': fields.many2one('res.company', 'Company', readonly=True, groups="base.group_multi_company"),
'partner_id': fields.many2one('res.partner', 'Partner', readonly=True),
'partner_id': fields.many2one('res.partner', 'Contact', readonly=True),
}
_order = 'name desc, project_id'

View File

@ -80,7 +80,7 @@
<group expand="1" string="Group By...">
<filter string="Project" name="project" icon="terp-folder-violet" context="{'group_by':'project_id'}"/>
<filter string="Task" icon="terp-stock_align_left_24" context="{'group_by':'name'}" />
<filter string="Partner" icon="terp-partner" context="{'group_by':'partner_id'}" />
<filter string="Contact" icon="terp-partner" context="{'group_by':'partner_id'}" />
<filter string="Assigned to" name="User" icon="terp-personal" context="{'group_by':'user_id'}" />
<filter string="Status" icon="terp-stock_effects-object-colorize" context="{'group_by':'state'}"/>
<filter string="Company" icon="terp-go-home" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>

View File

@ -219,7 +219,7 @@ class project_issue(base_stage, osv.osv):
'section_id': fields.many2one('crm.case.section', 'Sales Team', \
select=True, help='Sales team to which Case belongs to.\
Define Responsible user and Email account for mail gateway.'),
'partner_id': fields.many2one('res.partner', 'Partner', select=1),
'partner_id': fields.many2one('res.partner', 'Contact', select=1),
'company_id': fields.many2one('res.company', 'Company'),
'description': fields.text('Description'),
'state': fields.related('stage_id', 'state', type="selection", store=True,

View File

@ -210,7 +210,7 @@
<field name="project_id"/>
<group expand="0" string="Group By..." >
<filter string="Responsible" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>
<filter string="Partner" icon="terp-partner" domain="[]" context="{'group_by':'partner_id'}"/>
<filter string="Contact" icon="terp-partner" domain="[]" context="{'group_by':'partner_id'}"/>
<filter string="Project" icon="terp-folder-violet" domain="[]" context="{'group_by':'project_id'}"/>
<filter string="Version" icon="terp-gtk-jump-to-rtl" domain="[]" context="{'group_by':'version_id'}"/>
<filter string="Category" icon="terp-stock_symbol-selection" domain="[]" context="{'group_by':'categ_id'}"/>
@ -298,7 +298,7 @@
<t t-if="record.date_deadline.raw_value and record.date_deadline.raw_value lt (new Date())">
<span t-attf-class="oe_kanban_status oe_kaban_status_red"> </span>
</t>
<img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value[0])" t-att-title="record.user_id.value" width="24" height="24" class="oe_kanban_avatar"/>
<img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value)" t-att-title="record.user_id.value" width="24" height="24" class="oe_kanban_avatar"/>
</div>
</div>
</div>

View File

@ -63,7 +63,7 @@ class project_issue_report(osv.osv):
'project_id':fields.many2one('project.project', 'Project',readonly=True),
'version_id': fields.many2one('project.issue.version', 'Version'),
'user_id' : fields.many2one('res.users', 'Assigned to',readonly=True),
'partner_id': fields.many2one('res.partner','Partner',domain="[('object_id.model', '=', 'project.issue')]"),
'partner_id': fields.many2one('res.partner','Contact',domain="[('object_id.model', '=', 'project.issue')]"),
'channel_id': fields.many2one('crm.case.channel', 'Channel',readonly=True),
'task_id': fields.many2one('project.task', 'Task',domain="[('object_id.model', '=', 'project.issue')]" ),
'email': fields.integer('# Emails', size=128, readonly=True),

View File

@ -62,7 +62,7 @@
<field name="version_id"/>
<group expand="1" string="Group By...">
<filter string="Assigned to" name="Responsible" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}" />
<filter string="Partner" icon="terp-partner" context="{'group_by':'partner_id'}" />
<filter string="Contact" icon="terp-partner" context="{'group_by':'partner_id'}" />
<filter string="Sale Team" icon="terp-personal+" domain="[]" context="{'group_by':'section_id'}" />
<filter string="Project" name="project" icon="terp-folder-violet" context="{'group_by':'project_id'}" />
<filter string="Task" icon="terp-stock_align_left_24" domain="[]" context="{'group_by':'task_id'}"/>

View File

@ -36,7 +36,7 @@
<field name="inherit_id" ref="analytic_contract_project.project_invoice_form"/>
<field name="arch" type="xml">
<field name="partner_id" position="replace">
<field name="partner_id" on_change="onchange_partner_id(partner_id)" string="Customer" attrs="{'required':[('to_invoice','!=',False)]}"/>
<field name="partner_id" on_change="onchange_partner_id(partner_id)" string="Contact" attrs="{'required':[('to_invoice','!=',False)]}"/>
</field>
</field>
</record>

View File

@ -9,8 +9,9 @@
<field name="inherit_id" ref="crm.crm_case_form_view_oppor"/>
<field name="arch" type="xml">
<data>
<xpath expr="/form/header/button[@name='case_mark_won']" position="before">
<button string="Convert to Quote" name="%(action_crm_make_sale)d" type="action" class="oe_highlight"/>
<xpath expr="/form/header/button[@name='case_mark_lost']" position="after">
<button states="done" string="Convert to Quote" name="%(action_crm_make_sale)d" type="action" class="oe_highlight"/>
<button states="draft,open,pending" string="Convert to Quote" name="%(action_crm_make_sale)d" type="action"/>
</xpath>
</data>
</field>