[MERGE]with parent

bzr revid: dusan@ubuntu-20121129174503-8dctjtx0mbs6q1qi
This commit is contained in:
dusan
2012-11-29 18:45:03 +01:00
30 changed files with 326 additions and 230 deletions
+2 -2
View File
@@ -1381,8 +1381,8 @@ class account_invoice_line(osv.osv):
'origin': fields.char('Source Document', size=256, help="Reference of the document that produced this invoice."),
'sequence': fields.integer('Sequence', help="Gives the sequence of this line when displaying the invoice."),
'invoice_id': fields.many2one('account.invoice', 'Invoice Reference', ondelete='cascade', select=True),
'uos_id': fields.many2one('product.uom', 'Unit of Measure', ondelete='set null'),
'product_id': fields.many2one('product.product', 'Product', ondelete='set null'),
'uos_id': fields.many2one('product.uom', 'Unit of Measure', ondelete='set null', select=True),
'product_id': fields.many2one('product.product', 'Product', ondelete='set null', select=True),
'account_id': fields.many2one('account.account', 'Account', required=True, domain=[('type','<>','view'), ('type', '<>', 'closed')], help="The income or expense account related to the selected product."),
'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Product Price')),
'price_subtotal': fields.function(_amount_line, string='Subtotal', type="float",
+1 -1
View File
@@ -1238,7 +1238,7 @@
<separator/>
<filter string="Next Partner to Reconcile" help="Next Partner Entries to reconcile" name="next_partner" context="{'next_partner_only': 1}" icon="terp-gtk-jump-to-ltr" domain="[('account_id.reconcile','=',True),('reconcile_id','=',False)]"/>
<field name="move_id" string="Number (Move)"/>
<field name="account_id"/>
<field name="account_id" filter_domain="['|', ('name', 'ilike', self), ('code', 'ilike', self)]"/>
<field name="partner_id"/>
<field name="journal_id" context="{'journal_id':self}" widget="selection"/> <!-- it's important to keep widget='selection' in this filter viewbecause without that the value passed in the context is not the ID but the textual value (name) of the selected journal -->
<field name="period_id" context="{'period_id':self}" widget="selection"/> <!-- it's important to keep the widget='selection' in this field, for the same reason as explained above -->
+94 -120
View File
@@ -98,150 +98,124 @@ class account_invoice_report(osv.osv):
'partner_bank_id': fields.many2one('res.partner.bank', 'Bank Account',readonly=True),
'residual': fields.float('Total Residual', readonly=True),
'user_currency_residual': fields.function(_compute_amounts_in_user_currency, string="Total Residual", type='float', digits_compute=dp.get_precision('Account'), multi="_compute_amounts"),
'delay_to_pay': fields.float('Avg. Delay To Pay', readonly=True, group_operator="avg"),
'due_delay': fields.float('Avg. Due Delay', readonly=True, group_operator="avg"),
}
_order = 'date desc'
def _select(self):
select_str = """
SELECT min(ail.id) as id,
ai.date_invoice as date,
to_char(ai.date_invoice, 'YYYY') as year,
to_char(ai.date_invoice, 'MM') as month,
to_char(ai.date_invoice, 'YYYY-MM-DD') as day,
ail.product_id,
ai.partner_id as partner_id,
ai.payment_term as payment_term,
ai.period_id as period_id,
(case when u.uom_type not in ('reference') then
(select name from product_uom where uom_type='reference' and active and category_id=u.category_id LIMIT 1)
else
u.name
end) as uom_name,
ai.currency_id as currency_id,
ai.journal_id as journal_id,
ai.fiscal_position as fiscal_position,
ai.user_id as user_id,
ai.company_id as company_id,
count(ail.*) as nbr,
ai.type as type,
ai.state,
pt.categ_id,
ai.date_due as date_due,
ai.account_id as account_id,
ail.account_id as account_line_id,
ai.partner_bank_id as partner_bank_id,
sum(case when ai.type in ('out_refund','in_invoice') then
-ail.quantity / u.factor
else
ail.quantity / u.factor
end) as product_qty,
sum(case when ai.type in ('out_refund','in_invoice') then
-ail.price_subtotal
else
ail.price_subtotal
end) / cr.rate as price_total,
(case when ai.type in ('out_refund','in_invoice') then
sum(-ail.price_subtotal)
else
sum(ail.price_subtotal)
end) / (CASE WHEN sum(ail.quantity/u.factor) <> 0
THEN
(case when ai.type in ('out_refund','in_invoice')
then sum(-ail.quantity/u.factor)
else sum(ail.quantity/u.factor) end)
ELSE 1
END)
/ cr.rate as price_average,
cr.rate as currency_rate,
sum((select extract(epoch from avg(date_trunc('day',aml.date_created)-date_trunc('day',l.create_date)))/(24*60*60)::decimal(16,2)
from account_move_line as aml
left join account_invoice as a ON (a.move_id=aml.move_id)
left join account_invoice_line as l ON (a.id=l.invoice_id)
where a.id=ai.id)) as delay_to_pay,
sum((select extract(epoch from avg(date_trunc('day',a.date_due)-date_trunc('day',a.date_invoice)))/(24*60*60)::decimal(16,2)
from account_move_line as aml
left join account_invoice as a ON (a.move_id=aml.move_id)
left join account_invoice_line as l ON (a.id=l.invoice_id)
where a.id=ai.id)) as due_delay,
(case when ai.type in ('out_refund','in_invoice') then
-ai.residual
else
ai.residual
end)/ (CASE WHEN
(select count(l.id) from account_invoice_line as l
left join account_invoice as a ON (a.id=l.invoice_id)
where a.id=ai.id) <> 0
THEN
(select count(l.id) from account_invoice_line as l
left join account_invoice as a ON (a.id=l.invoice_id)
where a.id=ai.id)
ELSE 1
END) / cr.rate as residual
SELECT sub.id, sub.date, sub.year, sub.month, sub.day, sub.product_id, sub.partner_id,
sub.payment_term, sub.period_id, sub.uom_name, sub.currency_id, sub.journal_id,
sub.fiscal_position, sub.user_id, sub.company_id, sub.nbr, sub.type, sub.state,
sub.categ_id, sub.date_due, sub.account_id, sub.account_line_id, sub.partner_bank_id,
sub.product_qty, sub.price_total / cr.rate as price_total, sub.price_average /cr.rate as price_average,
cr.rate as currency_rate, sub.residual / cr.rate as residual
"""
return select_str
def _where(self):
where_str = """
WHERE cr.id in (select id from res_currency_rate cr2 where (cr2.currency_id = ai.currency_id)
and ((ai.date_invoice is not null and cr.name <= ai.date_invoice) or (ai.date_invoice is null and cr.name <= NOW())) order by name desc limit 1)
def _sub_select(self):
select_str = """
SELECT min(ail.id) AS id,
ai.date_invoice AS date,
to_char(ai.date_invoice::timestamp with time zone, 'YYYY'::text) AS year,
to_char(ai.date_invoice::timestamp with time zone, 'MM'::text) AS month,
to_char(ai.date_invoice::timestamp with time zone, 'YYYY-MM-DD'::text) AS day,
ail.product_id, ai.partner_id, ai.payment_term, ai.period_id,
CASE
WHEN u.uom_type::text <> 'reference'::text
THEN ( SELECT product_uom.name
FROM product_uom
WHERE product_uom.uom_type::text = 'reference'::text
AND product_uom.active
AND product_uom.category_id = u.category_id LIMIT 1)
ELSE u.name
END AS uom_name,
ai.currency_id, ai.journal_id, ai.fiscal_position, ai.user_id, ai.company_id,
count(ail.*) AS nbr,
ai.type, ai.state, pt.categ_id, ai.date_due, ai.account_id, ail.account_id AS account_line_id,
ai.partner_bank_id,
SUM(CASE
WHEN ai.type::text = ANY (ARRAY['out_refund'::character varying::text, 'in_invoice'::character varying::text])
THEN (- ail.quantity) / u.factor
ELSE ail.quantity / u.factor
END) AS product_qty,
SUM(CASE
WHEN ai.type::text = ANY (ARRAY['out_refund'::character varying::text, 'in_invoice'::character varying::text])
THEN - ail.price_subtotal
ELSE ail.price_subtotal
END) AS price_total,
CASE
WHEN ai.type::text = ANY (ARRAY['out_refund'::character varying::text, 'in_invoice'::character varying::text])
THEN SUM(- ail.price_subtotal)
ELSE SUM(ail.price_subtotal)
END / CASE
WHEN SUM(ail.quantity / u.factor) <> 0::numeric
THEN CASE
WHEN ai.type::text = ANY (ARRAY['out_refund'::character varying::text, 'in_invoice'::character varying::text])
THEN SUM((- ail.quantity) / u.factor)
ELSE SUM(ail.quantity / u.factor)
END
ELSE 1::numeric
END AS price_average,
CASE
WHEN ai.type::text = ANY (ARRAY['out_refund'::character varying::text, 'in_invoice'::character varying::text])
THEN - ai.residual
ELSE ai.residual
END / CASE
WHEN (( SELECT count(l.id) AS count
FROM account_invoice_line l
LEFT JOIN account_invoice a ON a.id = l.invoice_id
WHERE a.id = ai.id)) <> 0
THEN ( SELECT count(l.id) AS count
FROM account_invoice_line l
LEFT JOIN account_invoice a ON a.id = l.invoice_id
WHERE a.id = ai.id)
ELSE 1::bigint
END::numeric AS residual
"""
return where_str
return select_str
def _from(self):
from_str = """
FROM account_invoice_line as ail
left join account_invoice as ai ON (ai.id=ail.invoice_id)
left join product_product pr on (pr.id=ail.product_id)
left join product_template pt on (pt.id=pr.product_tmpl_id)
left join product_uom u on (u.id=ail.uos_id),
res_currency_rate cr
FROM account_invoice_line ail
JOIN account_invoice ai ON ai.id = ail.invoice_id
LEFT JOIN product_product pr ON pr.id = ail.product_id
left JOIN product_template pt ON pt.id = pr.product_tmpl_id
LEFT JOIN product_uom u ON u.id = ail.uos_id
"""
return from_str
def _group_by(self):
group_by_str = """
GROUP BY ail.product_id,
ai.date_invoice,
ai.id,
cr.rate,
to_char(ai.date_invoice, 'YYYY'),
to_char(ai.date_invoice, 'MM'),
to_char(ai.date_invoice, 'YYYY-MM-DD'),
ai.partner_id,
ai.payment_term,
ai.period_id,
u.name,
ai.currency_id,
ai.journal_id,
ai.fiscal_position,
ai.user_id,
ai.company_id,
ai.type,
ai.state,
pt.categ_id,
ai.date_due,
ai.account_id,
ail.account_id,
ai.partner_bank_id,
ai.residual,
ai.amount_total,
u.uom_type,
u.category_id
GROUP BY ail.product_id, ai.date_invoice, ai.id,
to_char(ai.date_invoice::timestamp with time zone, 'YYYY'::text),
to_char(ai.date_invoice::timestamp with time zone, 'MM'::text),
to_char(ai.date_invoice::timestamp with time zone, 'YYYY-MM-DD'::text),
ai.partner_id, ai.payment_term, ai.period_id, u.name, ai.currency_id, ai.journal_id,
ai.fiscal_position, ai.user_id, ai.company_id, ai.type, ai.state, pt.categ_id,
ai.date_due, ai.account_id, ail.account_id, ai.partner_bank_id, ai.residual,
ai.amount_total, u.uom_type, u.category_id
"""
return group_by_str
def init(self, cr):
# self._table = account_invoice_report
tools.drop_view_if_exists(cr, self._table)
cr.execute("CREATE or REPLACE VIEW %s as (%s %s %s %s)" % (
cr.execute("""CREATE or REPLACE VIEW %s as (
%s
FROM (
%s %s %s
) AS sub
JOIN res_currency_rate cr ON (cr.currency_id = sub.currency_id)
WHERE
cr.id IN (SELECT id
FROM res_currency_rate cr2
WHERE (cr2.currency_id = sub.currency_id)
AND ((sub.date IS NOT NULL AND cr.name <= sub.date)
OR (sub.date IS NULL AND cr.name <= NOW()))
ORDER BY name DESC LIMIT 1)
)""" % (
self._table,
self._select(), self._from(), self._where(), self._group_by()))
self._select(), self._sub_select(), self._from(), self._group_by()))
account_invoice_report()
@@ -30,8 +30,6 @@
<!-- <field name="reconciled" sum="# Reconciled"/> -->
<field name="user_currency_price_total" sum="Total Without Tax"/>
<field name="user_currency_residual" sum="Total Residual" invisible="context.get('residual_invisible',False)"/>
<field name="due_delay" sum="Avg. Due Delay" invisible="context.get('residual_invisible',False)"/>
<field name="delay_to_pay" sum="Avg. Delay To Pay" invisible="context.get('residual_invisible',False)"/>
</tree>
</field>
</record>
@@ -93,7 +91,7 @@
<field name="view_mode">tree,graph</field>
<field name="context">{'search_default_period':1,'search_default_current':1, 'search_default_year': 1, 'search_default_category_product':1, 'search_default_customer':1, 'group_by':[], 'group_by_no_leaf':1,}</field>
<field name="search_view_id" ref="view_account_invoice_report_search"/>
<field name="help">From this report, you can have an overview of the amount invoiced to your customer as well as payment delays. The tool search can also be used to personalise your Invoices reports and so, match this analysis to your needs.</field>
<field name="help">From this report, you can have an overview of the amount invoiced to your customer. The tool search can also be used to personalise your Invoices reports and so, match this analysis to your needs.</field>
</record>
@@ -21,6 +21,7 @@
import account_analytic_analysis
import cron_account_analytic_account
import res_config
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
@@ -40,6 +40,7 @@ Adds menu to show relevant information to each manager.You can also view the rep
'account_analytic_analysis_view.xml',
'account_analytic_analysis_menu.xml',
'account_analytic_analysis_cron.xml',
'res_config_view.xml',
],
'css': [
'static/src/css/analytic.css'
@@ -147,6 +147,18 @@
</field>
</record>
<record id="view_account_analytic_account_template_required" model="ir.ui.view">
<field name="name">account.analytic.account.form.template.required</field>
<field name="model">account.analytic.account</field>
<field name="groups_id" eval="[(6, 0, [ref('group_template_required')])]"/>
<field name="inherit_id" ref="analytic.view_account_analytic_account_form"/>
<field name="arch" type="xml">
<field name="template_id" position="attributes">
<attribute name="attrs">{'required': [('type','=','contract')], 'invisible': [('type','in',['view', 'normal','template'])]}</attribute>
</field>
</field>
</record>
<record id="template_of_contract_action" model="ir.actions.act_window">
<field name="name">Template of Contract</field>
<field name="type">ir.actions.act_window</field>
@@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Business Applications
# Copyright (C) 2004-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
# 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
class sale_configuration(osv.osv_memory):
_inherit = 'sale.config.settings'
_columns = {
'group_template_required': fields.boolean("Mandatory use of templates.",
implied_group='account_analytic_analysis.group_template_required',
help="Allows you to set the template field as required when creating an analytic account or a contract."),
}
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_sales_config" model="ir.ui.view">
<field name="name">sale settings</field>
<field name="model">sale.config.settings</field>
<field name="inherit_id" ref="sale.view_sales_config"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='module_analytic_user_function']" position="inside">
<div>
<field name="group_template_required" class="oe_inline"/>
<label for="group_template_required"/>
</div>
</xpath>
</field>
</record>
</data>
</openerp>
@@ -6,5 +6,12 @@
<field eval="[(4,ref('sale.group_analytic_accounting'))]" name="groups_id"/>
</record>
<record id="group_template_required" model="res.groups">
<field name="name">Mandatory use of templates in contracts</field>
<field name="category_id" ref="base.module_category_sales_management"/>
<field name="comment">the field template of the analytic accounts and contracts will be required.</field>
<field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
</record>
</data>
</openerp>
</openerp>
@@ -43,10 +43,10 @@
<field name="arch" type="xml">
<data>
<xpath expr="//page[@name='statement_line_ids']/field[@name='line_ids']/tree/field[@name='date']" position="after">
<field name="val_date"/>
</xpath>
<field name="val_date" invisible="1"/>
</xpath>
<xpath expr="//page[@name='statement_line_ids']/field[@name='line_ids']/tree/field[@name='amount']" position="after">
<field name="globalisation_id" string="Glob. Id"/>
<field name="globalisation_id" string="Glob. Id" invisible="1"/>
<field name="state" invisible="1"/>
</xpath>
<xpath expr="//page[@name='statement_line_ids']/field[@name='line_ids']/form/group/field[@name='date']" position="after">
@@ -213,7 +213,7 @@
<field name="inherit_id" ref="account.view_bank_statement_form"/>
<field name="arch" type="xml">
<xpath expr="//page[@name='statement_line_ids']/field[@name='line_ids']/tree/field[@name='amount']" position="after">
<field name="voucher_id" widget="many2onebutton" options="{'label':{'create':'Reconcile','edit':'Edit Reconciliation'}}" context="{'line_type': type, 'default_type': amount &lt; 0 and 'payment' or 'receipt', 'type': amount &lt; 0 and 'payment' or 'receipt', 'default_partner_id': partner_id, 'default_journal_id': parent.journal_id, 'default_amount': abs(amount), 'default_reference': ref, 'default_date': date, 'default_name': name, 'default_active': False}"/>
<field name="voucher_id" string="" widget="many2onebutton" options="{'label':{'create':'Reconcile','edit':'Edit Reconciliation'}}" context="{'line_type': type, 'default_type': amount &lt; 0 and 'payment' or 'receipt', 'type': amount &lt; 0 and 'payment' or 'receipt', 'default_partner_id': partner_id, 'default_journal_id': parent.journal_id, 'default_amount': abs(amount), 'default_reference': ref, 'default_date': date, 'default_name': name, 'default_active': False}"/>
</xpath>
<xpath expr="//page[@name='statement_line_ids']/field[@name='line_ids']/form/group/field[@name='sequence']" position="before">
<field name="voucher_id" widget="many2onebutton" options="{'label':{'create':'Reconcile','edit':'Edit Reconciliation'}}" context="{'line_type': type, 'default_type': amount &lt; 0 and 'payment' or 'receipt', 'type': amount &lt; 0 and 'payment' or 'receipt', 'default_partner_id': partner_id, 'default_journal_id': parent.journal_id, 'default_amount': abs(amount), 'default_reference': ref, 'default_date': date, 'default_name': name, 'default_active': False}"/>
+9 -2
View File
@@ -20,8 +20,10 @@
##############################################################################
import time
from datetime import datetime
from osv import fields, osv
import tools
from tools.translate import _
import decimal_precision as dp
@@ -199,9 +201,14 @@ class account_analytic_account(osv.osv):
return {}
res = {'value':{}}
template = self.browse(cr, uid, template_id, context=context)
res['value']['date_start'] = template.date_start
res['value']['date'] = template.date
if template.date_start and template.date:
from_dt = datetime.strptime(template.date_start, tools.DEFAULT_SERVER_DATE_FORMAT)
to_dt = datetime.strptime(template.date, tools.DEFAULT_SERVER_DATE_FORMAT)
timedelta = to_dt - from_dt
res['value']['date'] = datetime.strftime(datetime.now() + timedelta, tools.DEFAULT_SERVER_DATE_FORMAT)
res['value']['date_start'] = fields.date.today()
res['value']['quantity_max'] = template.quantity_max
res['value']['parent_id'] = template.parent_id and template.parent_id.id or False
res['value']['description'] = template.description
return res
+2 -2
View File
@@ -26,10 +26,10 @@
<field name="currency_id" attrs="{'invisible': ['|',('type', '&lt;&gt;', 'view'), ('company_id', '&lt;&gt;', False)]}"/>
</group>
<group>
<field name="code"/>
<field name="type" invisible="context.get('default_type', False)"/>
<field name="parent_id" on_change="on_change_parent(parent_id)" attrs="{'invisible': [('type','in',['contract','template'])]}"/>
<field name="template_id" on_change="on_change_template(template_id,context)" domain="[('type','=','template')]" attrs="{'invisible': [('type','in',['view', 'normal','template'])]}" context="{'default_type' : 'template'}"/>
<field name="code"/>
<field name="parent_id" on_change="on_change_parent(parent_id)" attrs="{'invisible': [('type','in',['contract'])]}"/>
<field name="company_id" on_change="on_change_company(company_id)" widget="selection" groups="base.group_multi_company" attrs="{'required': [('type','&lt;&gt;','view')]}"/>
</group>
</group>
@@ -52,6 +52,8 @@ openerp.auth_signup = function(instance) {
if (result.token) {
// switch to signup mode, set user name and login
this.$el.addClass("oe_login_signup");
self.$(".oe_signup_show").show();
self.$(".oe_signup_hide").hide();
this.$("form input[name=name]").val(result.name).attr("readonly", "readonly");
if (result.login) {
this.$("form input[name=login]").val(result.login).attr("readonly", "readonly");
-2
View File
@@ -81,7 +81,6 @@ class crm_lead_report(osv.osv):
'type_id':fields.many2one('crm.case.resource.type', 'Campaign', readonly=True),
'state': fields.selection(AVAILABLE_STATES, 'Status', size=16, readonly=True),
'company_id': fields.many2one('res.company', 'Company', readonly=True),
'email': fields.integer('# Emails', size=128, readonly=True),
'probability': fields.float('Probability',digits=(16,2),readonly=True, group_operator="avg"),
'planned_revenue': fields.float('Planned Revenue',digits=(16,2),readonly=True),
'probable_revenue': fields.float('Probable Revenue', digits=(16,2),readonly=True),
@@ -137,7 +136,6 @@ class crm_lead_report(osv.osv):
c.planned_revenue,
c.planned_revenue*(c.probability/100) as probable_revenue,
1 as nbr,
(SELECT count(id) FROM mail_message WHERE model='crm.lead' AND res_id=c.id AND email_from is not null) AS email,
date_trunc('day',c.create_date) as create_date,
extract('epoch' from (c.date_closed-c.create_date))/(3600*24) as delay_close,
abs(extract('epoch' from (c.date_deadline - c.date_closed))/(3600*24)) as delay_expected,
+1 -3
View File
@@ -25,7 +25,6 @@
<field name="partner_id" invisible="1"/>
<field name="country_id" invisible="1"/>
<field name="nbr" sum="# Leads"/>
<field name="email" sum="# Mails"/>
<field name="delay_open"/>
<field name="delay_close"/>
<field name="planned_revenue"/>
@@ -148,7 +147,6 @@
<field name="company_id" invisible="1" groups="base.group_multi_company"/>
<field name="nbr" string="#Opportunities" sum="#Opportunities"/>
<field name="planned_revenue" sum="Planned Revenues"/>
<field name="email" sum="# of Emails"/>
<field name="delay_open" sum='Delay to open'/>
<field name="delay_close" sum='Delay to close'/>
<field name="delay_expected"/>
@@ -167,7 +165,7 @@
<field name="context">{'search_default_year': 1,'search_default_lead': 1, "search_default_user":1, "search_default_this_month":1, 'group_by_no_leaf':1, 'group_by':[]}</field>
<field name="view_mode">tree,graph</field>
<field name="domain">[]</field>
<field name="help">Leads Analysis allows you to check different CRM related information. Check for treatment delays, number of responses given and emails sent. You can sort out your leads analysis by different groups to get accurate grained analysis.</field>
<field name="help">Leads Analysis allows you to check different CRM related information like the treatment delays or number of leads per state. You can sort out your leads analysis by different groups to get accurate grained analysis.</field>
</record>
<record model="ir.actions.act_window.view" id="action_report_crm_lead_tree">
<field name="sequence" eval="1"/>
+8
View File
@@ -206,6 +206,14 @@ class mail_message(osv.Model):
new_is_favorite = not (uid in message.get('favorite_user_ids'))
if new_is_favorite:
self.write(cr, SUPERUSER_ID, message.get('id'), {'favorite_user_ids': [(4, uid)]}, context=context)
# when setting a favorite, set the related notification as unread, or create an unread notification if not existing
notification_obj = self.pool.get('mail.notification')
pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=None)['partner_id'][0]
notif_id = notification_obj.search(cr, SUPERUSER_ID, [('message_id', '=', message.get('id')), ('partner_id', '=', pid)], context=context)
if notif_id:
notification_obj.write(cr, SUPERUSER_ID, notif_id, {'read': False}, context=context)
else:
notification_obj.create(cr, SUPERUSER_ID, {'message_id': message.get('id'), 'partner_id': pid, 'read': False}, context=context)
else:
self.write(cr, SUPERUSER_ID, message.get('id'), {'favorite_user_ids': [(3, uid)]}, context=context)
return new_is_favorite or False
+6 -3
View File
@@ -42,7 +42,8 @@
<field name="params" eval="&quot;{
'domain': [('partner_ids.user_ids', 'in', [uid])],
'view_mailbox': True,
'read_action': 'read', }&quot;"/>
'read_action': 'read',
'show_compose_message': False }&quot;"/>
<field name="help" type="html">
<p>
<b>No private message.</b>
@@ -64,7 +65,8 @@
<field name="params" eval="&quot;{
'domain': [('favorite_user_ids', 'in', [uid])],
'view_mailbox': True,
'read_action': 'read', }&quot;"/>
'read_action': 'read',
'compose_as_todo': True }&quot;"/>
<field name="help" type="html">
<p>
<b>No todo.</b>
@@ -84,7 +86,8 @@
}</field>
<field name="params" eval="&quot;{
'domain': ['|', ('notification_ids.partner_id.user_ids', 'in', [uid]), ('author_id.user_ids', 'in', [uid])],
'view_mailbox': True, }&quot;"/>
'view_mailbox': True,
'show_compose_message': False }&quot;"/>
<field name="help" type="html">
<p>
No message found and no message sent yet.
+24 -10
View File
@@ -48,7 +48,7 @@
.openerp .oe_mail .oe_msg{
position: relative;
background: #F4F5FA;
background: #EDEDF6;
border-radius: 2px;
margin-bottom: 2px;
min-height: 42px;
@@ -70,7 +70,7 @@
margin-left: 40px;
}
.openerp .oe_mail .oe_msg .oe_msg_footer{
padding-left: 4px;
margin-left: 4px;
padding-top: 3px;
overflow: hidden;
margin-bottom: 4px;
@@ -94,6 +94,10 @@
.openerp .oe_mail .oe_msg .oe_msg_content .oe_msg_body p {
margin-bottom: 0px;
}
.openerp .oe_mail .oe_msg .oe_msg_content .oe_msg_body * {
text-overflow:ellipsis;
word-wrap: break-word;
}
/* a) Indented Messages */
@@ -380,6 +384,10 @@
line-height: 12px;
vertical-align: middle;
}
.openerp .oe_mail .oe_msg_footer button.oe_post{
position: relative;
z-index: 2;
}
.openerp .oe_mail .oe_msg_footer button.oe_attach{
width: 24px;
overflow: hidden;
@@ -387,8 +395,9 @@
}
.openerp .oe_mail .oe_msg_footer button.oe_attach .oe_e{
position: relative;
top: -1px;
left: -9px;
top: -4px;
margin-left: -9px;
vertical-align: middle;
filter:none;
}
.openerp .oe_mail .oe_hidden_input_file, .openerp .oe_mail .oe_hidden_input_file form{
@@ -402,8 +411,9 @@
}
.openerp .oe_mail .oe_msg_footer button.oe_full .oe_e{
position: relative;
top: -1px;
left: -9px;
top: -4px;
margin-left: -9px;
vertical-align: middle;
filter:none;
}
.openerp .oe_mail button.oe_attach, .openerp .oe_mail button.oe_full{
@@ -418,13 +428,17 @@
color: #7C7BAD;
margin-left: -3px;
}
.openerp .oe_mail .oe_msg_footer .oe_attachment_file{
cursor: pointer;
}
.openerp .oe_mail .oe_msg_footer .oe_attachment_file .oe_form_binary_file{
display: inline-block;
margin-left: -47px;
height: 28px;
width: 52px;
margin-top: -6px;
margin-left: -122px;
height: 22px;
width: 128px;
margin-top: -4px;
filter:none;
cursor: pointer;
}
.openerp .oe_mail .oe_mail_list_recipients{
font-size: 12px;
+25 -21
View File
@@ -204,7 +204,7 @@ openerp.mail = function (session) {
this.subject = datasets.subject || false,
this.name = datasets.name || false,
this.record_name = datasets.record_name || false,
this.body = datasets.body || false,
this.body = datasets.body || '',
this.vote_nb = datasets.vote_nb || 0,
this.has_voted = datasets.has_voted || false,
this.is_favorite = datasets.is_favorite || false,
@@ -508,7 +508,6 @@ openerp.mail = function (session) {
res_model: 'mail.compose.message',
view_mode: 'form',
view_type: 'form',
action_from: 'mail.ThreadComposeMessage',
views: [[false, 'form']],
target: 'new',
context: context,
@@ -574,12 +573,7 @@ openerp.mail = function (session) {
var message = thread.create_message_object( data[0] );
// insert the message on dom
thread.insert_message( message, root ? undefined : self.$el, root );
if (thread.parent_message) {
self.$el.remove();
self.parent_thread.compose_message = null;
} else {
self.on_cancel();
}
self.on_cancel();
});
//session.web.unblockUI();
});
@@ -591,11 +585,11 @@ openerp.mail = function (session) {
*/
on_compose_expandable: function (event) {
if (!this.stay_open && (!this.show_composer || !this.$('textarea:not(.oe_compact)').val().match(/\S+/))) {
if ((!this.stay_open || (event && event.type == 'click')) && (!this.show_composer || !this.$('textarea:not(.oe_compact)').val().match(/\S+/))) {
this.show_composer = !this.show_composer || this.stay_open;
this.reinit();
}
if (!this.stay_open && this.show_composer) {
if (!this.stay_open && this.show_composer && (!event || event.type != 'blur')) {
this.$('textarea:not(.oe_compact):first').focus();
}
return true;
@@ -725,7 +719,7 @@ openerp.mail = function (session) {
on_message_reply:function (event) {
event.stopPropagation();
this.create_thread();
this.thread.on_compose_message();
this.thread.on_compose_message(event);
return false;
},
@@ -833,9 +827,10 @@ openerp.mail = function (session) {
return false;
},
/*The selected thread and all childs (messages/thread) became read
* @param {object} mouse envent
*/
/* Set the selected thread and all childs as read or unread, based on
* read parameter.
* @param {boolean} read_value
*/
on_message_read_unread: function (read_value) {
var self = this;
var messages = [this].concat(this.get_childs());
@@ -958,7 +953,7 @@ openerp.mail = function (session) {
this.options = options.options;
this.options.root_thread = (options.options.root_thread != undefined ? options.options.root_thread : this);
this.options.show_compose_message = this.options.show_compose_message && (this.options.display_indented_thread >= this.thread_level || !this.thread_level);
this.options.show_compose_message = this.options.show_compose_message && !this.thread_level;
// record options and data
this.parent_message= parent.thread!= undefined ? parent : false ;
@@ -995,7 +990,7 @@ openerp.mail = function (session) {
// add message composition form view
if (!this.compose_message) {
this.compose_message = new mail.ThreadComposeMessage(this, this, {
'context': this.context,
'context': this.options.compose_as_todo && !this.thread_level ? _.extend(this.context, { 'default_favorite_user_ids': [this.session.uid] }) : this.context,
'options': this.options,
});
if (!this.thread_level || this.thread_level > this.options.display_indented_thread) {
@@ -1136,9 +1131,9 @@ openerp.mail = function (session) {
* Call the on_compose_expandable method to allow the user to write his message.
* (Is call when a user click on "Reply" button)
*/
on_compose_message: function () {
on_compose_message: function (event) {
this.instantiate_compose_message();
this.compose_message.on_compose_expandable();
this.compose_message.on_compose_expandable(event);
return false;
},
@@ -1241,6 +1236,7 @@ openerp.mail = function (session) {
} else {
message.appendTo(self.$el);
}
message.$el.hide().fadeIn(500);
return message
},
@@ -1262,6 +1258,9 @@ openerp.mail = function (session) {
// insert the message on dom
thread.insert_message( message, typeof dom_insert_after == 'object' ? dom_insert_after : false);
});
if (!records.length && this.options.root_thread == this) {
this.no_message();
}
},
/**
@@ -1291,8 +1290,10 @@ openerp.mail = function (session) {
var messages = _.sortBy( this.messages, function (val) { return val.id; });
var it = _.indexOf( messages, message );
var msg_up = messages[it-1];
var msg_down = messages[it+1];
var msg_up = message.$el.prev('.oe_msg');
var msg_down = message.$el.next('.oe_msg');
var msg_up = msg_up.hasClass('oe_msg_expandable') ? _.find( this.messages, function (val) { return val.$el[0] == msg_up[0]; }) : false;
var msg_down = msg_down.hasClass('oe_msg_expandable') ? _.find( this.messages, function (val) { return val.$el[0] == msg_down[0]; }) : false;
var message_dom = [ ["id", "=", message.id] ];
@@ -1397,6 +1398,8 @@ openerp.mail = function (session) {
*... @param {Array} [message_ids] List of ids to fetch by the root thread.
* When you use this option, the domain is not used for the fetch root.
* @param {String} [no_message] Message to display when there are no message
* @param {Boolean} [show_link_partner] Display partner (authors, followers...) on link or not
* @param {Boolean} [compose_as_todo] The root composer mark automatically the message as todo
*/
init: function (parent, action) {
this._super(parent, action);
@@ -1414,8 +1417,10 @@ openerp.mail = function (session) {
'show_compose_message' : false,
'show_compact_message' : false,
'compose_placeholder': false,
'show_link_partner': true,
'view_inbox': false,
'message_ids': undefined,
'compose_as_todo' : false,
}, this.action.params);
this.action.params.help = this.action.help || false;
@@ -1441,7 +1446,6 @@ openerp.mail = function (session) {
});
this.thread.appendTo( this.$el );
this.thread.no_message();
if (this.action.params.show_compose_message) {
this.thread.instantiate_compose_message();
+22 -12
View File
@@ -34,14 +34,14 @@
<button class="oe_post">Post</button>
<t t-call="mail.compose_message.add_attachment"/>
<!--<a class="oe_cancel oe_e">X</a>-->
<button class="oe_full"><span class='oe_e'>&amp;ograve</span></button>
<button class="oe_full" title="Open the full mail composer"><span class='oe_e'>&amp;ograve</span></button>
</div>
</div>
</div>
<div t-if="widget.show_compact_message and !widget.show_composer" t-attf-class="oe_msg oe_msg_composer_compact #{widget.thread_level and widget.options.display_indented_thread > -1 ? 'oe_msg_indented' : ''}">
<textarea t-if="widget.options.compose_placeholder" class="field_text oe_compact" t-att-placeholder="widget.options.compose_placeholder"/>
<textarea t-if="!widget.options.compose_placeholder and !widget.options.view_mailbox" class="field_text oe_compact" placeholder="Write an internal note..."/>
<textarea t-if="!widget.options.compose_placeholder and widget.options.view_mailbox" class="field_text oe_compact" placeholder="Share to my followers..."/>
<textarea t-if="!widget.options.compose_placeholder and !widget.options.view_mailbox" class="field_text oe_compact" placeholder="Write to the followers of this document..."/>
<textarea t-if="!widget.options.compose_placeholder and widget.options.view_mailbox" class="field_text oe_compact" placeholder="Share with my followers..."/>
</div>
<span t-if="!(widget.show_compact_message and !widget.show_composer) and !widget.show_composer" class="oe_placeholder_compose"></span>
</t>
@@ -75,9 +75,11 @@
<t t-foreach='widget.attachment_ids' t-as='attachment'>
<t t-if="attachment.filetype !== 'webimage'">
<div t-attf-class="oe_attachment #{attachment.upload ? 'oe_uploading' : ''}">
<a t-att-href='attachment.url'><img t-att-src="'/mail/static/src/img/mimetypes/' + attachment.filetype + '.png'"></img></a>
<a t-att-href='attachment.url'>
<img t-att-src="'/mail/static/src/img/mimetypes/' + attachment.filetype + '.png'"></img>
<div class='oe_name'><t t-raw='attachment.name' /></div>
</a>
<div class='oe_delete oe_e' title="Delete this attachment" t-attf-data-id="{attachment.id}">[</div>
<div class='oe_name'><t t-raw='attachment.name' /></div>
<div class='oe_progress_bar'>
uploading
</div>
@@ -85,9 +87,11 @@
</t>
<t t-if="attachment.filetype === 'webimage'">
<div t-attf-class="oe_attachment oe_preview #{attachment.upload ? 'oe_uploading' : ''}">
<a t-att-href='attachment.url'><img t-att-src="widget.attachments_resize_image(attachment.id, [100,80])"></img></a>
<a t-att-href='attachment.url'>
<img t-att-src="widget.attachments_resize_image(attachment.id, [100,80])"></img>
<div class='oe_name'><t t-raw='attachment.name' /></div>
</a>
<div class='oe_delete oe_e'>[</div>
<div class='oe_name'><t t-raw='attachment.name' /></div>
<div class='oe_progress_bar'>
uploading
</div>
@@ -111,7 +115,11 @@
</t>
<t t-if="!widget.is_private and widget.partner_ids.length"> and </t>
<t t-set="inc" t-value="0"/>
<t t-if="widget.partner_ids.length" t-foreach="widget.partner_ids" t-as="partner"><span t-attf-class="oe_partner_follower #{inc>=3?'oe_hidden':''}"><t t-if="inc" t-raw="', '"/><a t-attf-href="#model=res.partner&amp;id=#{partner[0]}"><t t-raw="partner[1]"/></a></span><t t-set="inc" t-value="inc+1"/>
<t t-if="widget.partner_ids.length" t-foreach="widget.partner_ids" t-as="partner">
<span t-attf-class="oe_partner_follower #{inc>=3?'oe_hidden':''}"><t t-if="inc" t-raw="', '"/>
<a t-if="widget.options.show_link_partner" t-attf-href="#model=res.partner&amp;id=#{partner[0]}"><t t-raw="partner[1]"/></a>
<t t-if="!widget.options.show_link_partner" t-raw="partner[1]"/>
</span><t t-set="inc" t-value="inc+1"/>
</t>
<t t-if="widget.partner_ids.length>=3">
<span class="oe_more">, <a><t t-raw="widget.partner_ids.length-3"/> others...</a></span>
@@ -148,7 +156,7 @@
</td>
<td><div class="oe_view_manager_view_search" t-opentag="true"/></td>
</tr>
<tr class="oe_header_row" t-if="widget.action.params.view_inbox" >
<tr class="oe_header_row" t-if="widget.action.params.view_inbox and widget.action.params.show_compose_message" >
<td colspan="2">
<button type="button" class="oe_write_full oe_highlight">
Compose a new message
@@ -190,14 +198,15 @@
<div t-attf-class="oe_msg #{widget.thread_level and widget.options.display_indented_thread > -1 ? 'oe_msg_indented' : ''} oe_msg_#{widget.type}">
<div class='oe_msg_left'>
<a t-attf-href="#model=res.partner&amp;id=#{widget.author_id[0]}" t-att-title="widget.author_id[1]">
<a t-if="widget.options.show_link_partner" t-attf-href="#model=res.partner&amp;id=#{widget.author_id[0]}" t-att-title="widget.author_id[1]">
<img class="oe_msg_icon" t-att-src="widget.avatar"/>
</a>
<img t-if="!widget.options.show_link_partner" class="oe_msg_icon" t-att-src="widget.avatar"/>
</div>
<div class="oe_msg_center">
<div class='oe_msg_icons'>
<span class='oe_read' t-if="widget.options.show_read"><a title="Done" class="oe_e">X</a></span>
<span class='oe_read' t-if="widget.options.show_read"><a title="Done" class="oe_e">W</a></span>
<span class='oe_unread' t-if="widget.is_favorite and widget.options.show_unread"><a title="Set back to Todo" class="oe_e">v</a></span>
<span class='oe_unread' t-if="!widget.is_favorite and widget.options.show_unread"><a title="Set back to Inbox" class="oe_e">v</a></span>
<span class='oe_reply' t-if="widget.options.show_reply_button"><a title="Reply" class="oe_e">(</a></span>
@@ -217,7 +226,8 @@
<t t-if="widget.attachment_ids.length > 0">
<div class="oe_msg_attachment_list"></div>
</t>
<a t-if="widget.author_id" t-attf-href="#model=res.partner&amp;id=#{widget.author_id[0]}"><t t-raw="widget.author_id[1]"/></a>
<a t-if="widget.author_id and widget.options.show_link_partner" t-attf-href="#model=res.partner&amp;id=#{widget.author_id[0]}"><t t-raw="widget.author_id[1]"/></a>
<span t-if="widget.author_id and !widget.options.show_link_partner"><t t-raw="widget.author_id[1]"/></span>
<span class='oe_subtle'>•</span>
<span t-att-title="widget.date"><t t-raw="widget.timerelative"/></span>
<span class='oe_subtle'>•</span>
-5
View File
@@ -6,10 +6,5 @@
<field name="name">Notes / Fancy mode</field>
<field name="category_id" ref="base.module_category_hidden"/>
</record>
<record id="base.group_user" model="res.groups">
<field name="implied_ids" eval="[(4, ref('group_note_fancy'))]"/>
</record>
</data>
</openerp>
+1 -1
View File
@@ -546,7 +546,7 @@ class product_product(osv.osv):
'default_code' : fields.char('Internal Reference', size=64, select=True),
'active': fields.boolean('Active', help="If unchecked, it will allow you to hide the product without removing it."),
'variants': fields.char('Variants', size=64),
'product_tmpl_id': fields.many2one('product.template', 'Product Template', required=True, ondelete="cascade"),
'product_tmpl_id': fields.many2one('product.template', 'Product Template', required=True, ondelete="cascade", select=True),
'ean13': fields.char('EAN13 Barcode', size=13, help="International Article Number used for product identification."),
'packaging' : fields.one2many('product.packaging', 'product_id', 'Logistical Units', help="Gives the different ways to package the same product. This has no impact on the picking order and is mainly used if you use the EDI module."),
'price_extra': fields.float('Variant Price Extra', digits_compute=dp.get_precision('Product Price')),
+9 -11
View File
@@ -49,11 +49,17 @@ class project_task_type(osv.osv):
'fold': fields.boolean('Hide in views if empty',
help="This stage is not visible, for example in status bar or kanban view, when there are no records in that stage to display."),
}
def _get_default_project_id(self, cr, uid, ctx={}):
proj = ctx.get('default_project_id', False)
if type(proj) is int:
return [proj]
return proj
_defaults = {
'sequence': 1,
'state': 'open',
'fold': False,
'case_default': True,
'project_ids': _get_default_project_id
}
_order = 'sequence'
@@ -603,18 +609,13 @@ class task(base_stage, osv.osv):
stage_obj = self.pool.get('project.task.type')
order = stage_obj._order
access_rights_uid = access_rights_uid or uid
# lame way to allow reverting search, should just work in the trivial case
if read_group_order == 'stage_id desc':
order = '%s desc' % order
# retrieve section_id from the context and write the domain
# - ('id', 'in', 'ids'): add columns that should be present
# - OR ('case_default', '=', True), ('fold', '=', False): add default columns that are not folded
# - OR ('project_ids', 'in', project_id), ('fold', '=', False) if project_id: add project columns that are not folded
search_domain = []
project_id = self._resolve_project_id_from_context(cr, uid, context=context)
if project_id:
search_domain += ['|', ('project_ids', '=', project_id)]
search_domain += ['|', ('id', 'in', ids), ('case_default', '=', True)]
search_domain += [('id', 'in', ids)]
stage_ids = stage_obj._search(cr, uid, search_domain, order=order, access_rights_uid=access_rights_uid, context=context)
result = stage_obj.name_get(cr, access_rights_uid, stage_ids, context=context)
# restore order of the search
@@ -750,7 +751,7 @@ class task(base_stage, osv.osv):
'priority': fields.selection([('4','Very Low'), ('3','Low'), ('2','Medium'), ('1','Important'), ('0','Very important')], 'Priority', select=True),
'sequence': fields.integer('Sequence', select=True, help="Gives the sequence order when displaying a list of tasks."),
'stage_id': fields.many2one('project.task.type', 'Stage',
domain="['&', ('fold', '=', False), '|', ('project_ids', '=', project_id), ('case_default', '=', True)]"),
domain="['&', ('fold', '=', False), ('project_ids', '=', project_id)]"),
'state': fields.related('stage_id', 'state', type="selection", store=True,
selection=_TASK_STATE, string="Status", readonly=True,
help='The status is set to \'Draft\', when a case is created.\
@@ -936,14 +937,11 @@ class task(base_stage, osv.osv):
for task in cases:
if task.project_id:
section_ids.append(task.project_id.id)
# OR all section_ids and OR with case_default
search_domain = []
if section_ids:
search_domain += [('|')] * len(section_ids)
search_domain = [('|')] * (len(section_ids)-1)
for section_id in section_ids:
search_domain.append(('project_ids', '=', section_id))
search_domain.append(('case_default', '=', True))
# AND with the domain in parameter
search_domain += list(domain)
# perform search, return the first found
stage_ids = self.pool.get('project.task.type').search(cr, uid, search_domain, order=order, context=context)
+24 -11
View File
@@ -36,7 +36,11 @@
<field name="user_id" ref="base.user_demo"/>
<field name="description">Implement new website for Sale and Warehouse Management for a customer.</field>
<field name="alias_model">project.task</field>
<field name="type_ids" eval="[(6, 0, [ref('project_tt_analysis'),ref('project_tt_specification'),ref('project_tt_development'),ref('project_tt_testing'),ref('project_tt_deployment')])]"/>
</record>
<!-- We assign after so that default values applies -->
<record id="project_project_1" model="project.project">
<field name="type_ids" eval="[(4, ref('project_tt_analysis')) ,(4,ref('project_tt_specification')), (4,ref('project_tt_development')), (4,ref('project_tt_testing')), (4,ref('project_tt_deployment'))]"/>
</record>
<record id="project_project_2" model="project.project">
@@ -45,7 +49,11 @@
<field name="privacy_visibility">public</field>
<field name="user_id" ref="base.user_demo"/>
<field name="alias_model">project.task</field>
<field name="type_ids" eval="[(6, 0, [ref('project_tt_specification'),ref('project_tt_development'),ref('project_tt_testing'),ref('project_tt_merge'),ref('project_tt_deployment')])]"/>
</record>
<!-- We assign after so that default values applies -->
<record id="project_project_2" model="project.project">
<field name="type_ids" eval="[(4, ref('project_tt_specification')),(4,ref('project_tt_development')),(4,ref('project_tt_testing')),(4,ref('project_tt_merge')),(4,ref('project_tt_deployment'))]"/>
</record>
<record id="project_project_3" model="project.project">
@@ -55,10 +63,11 @@
<field name="user_id" ref="base.user_demo"/>
<field name="alias_model">project.task</field>
<field name="privacy_visibility">public</field>
<field name="members" eval="[(6, 0, [
ref('base.user_root'),
ref('base.user_demo')])]"/>
<field name="type_ids" eval="[(6, 0, [ref('project_tt_specification'),ref('project_tt_development'),ref('project_tt_testing'),ref('project_tt_merge'),ref('project_tt_deployment')])]"/>
<field name="members" eval="[(4, ref('base.user_root')), (4, ref('base.user_demo'))]"/>
</record>
<record id="project_project_3" model="project.project">
<field name="type_ids" eval="[(4, ref('project_tt_specification')),(4,ref('project_tt_development')),(4,ref('project_tt_testing')),(4,ref('project_tt_merge')),(4,ref('project_tt_deployment'))]"/>
</record>
<record id="project_project_4" model="project.project">
@@ -67,10 +76,11 @@
<field name="name">Website Design Templates</field>
<field name="user_id" ref="base.user_root"/>
<field name="alias_model">project.task</field>
<field name="type_ids" eval="[(6, 0, [ref('project_tt_design'),ref('project_tt_development'),ref('project_tt_testing')])]"/>
<field name="members" eval="[(6, 0, [
ref('base.user_root'),
ref('base.user_demo')])]"/>
<field name="members" eval="[(4, ref('base.user_root')), (4,ref('base.user_demo'))]"/>
</record>
<record id="project_project_4" model="project.project">
<field name="type_ids" eval="[(4, ref('project_tt_design')),(4,ref('project_tt_development')),(4,ref('project_tt_testing'))]"/>
</record>
<record id="project_project_5" model="project.project">
@@ -79,12 +89,15 @@
<field name="partner_id" ref="base.res_partner_7"/>
<field name="name">Data Import/Export Plugin</field>
<field name="alias_model">project.task</field>
<field name="type_ids" eval="[(6, 0, [ref('project_tt_development')])]"/>
<field name="members" eval="[(6, 0, [
ref('base.user_root'),
ref('base.user_demo')])]"/>
</record>
<record id="project_project_5" model="project.project">
<field name="type_ids" eval="[(4, ref('project_tt_development'))]"/>
</record>
<!-- Tasks -->
<record id="project_task_1" model="project.task">
+4 -6
View File
@@ -89,7 +89,7 @@ class project_issue(base_stage, osv.osv):
project_id = self._resolve_project_id_from_context(cr, uid, context=context)
if project_id:
search_domain += ['|', ('project_ids', '=', project_id)]
search_domain += ['|', ('id', 'in', ids), ('case_default', '=', True)]
search_domain += [('id', 'in', ids)]
# perform search
stage_ids = stage_obj._search(cr, uid, search_domain, order=order, access_rights_uid=access_rights_uid, context=context)
result = stage_obj.name_get(cr, access_rights_uid, stage_ids, context=context)
@@ -225,7 +225,7 @@ class project_issue(base_stage, osv.osv):
Define Responsible user and Email account for mail gateway.'),
'partner_id': fields.many2one('res.partner', 'Contact', select=1),
'company_id': fields.many2one('res.company', 'Company'),
'description': fields.text('Description'),
'description': fields.text('Private Note'),
'state': fields.related('stage_id', 'state', type="selection", store=True,
selection=_ISSUE_STATE, string="Status", readonly=True,
help='The status is set to \'Draft\', when a case is created.\
@@ -244,7 +244,7 @@ class project_issue(base_stage, osv.osv):
'priority': fields.selection(crm.AVAILABLE_PRIORITIES, 'Priority', select=True),
'version_id': fields.many2one('project.issue.version', 'Version'),
'stage_id': fields.many2one ('project.task.type', 'Stage',
domain="['&', ('fold', '=', False), '|', ('project_ids', '=', project_id), ('case_default', '=', True)]"),
domain="['&', ('fold', '=', False), ('project_ids', '=', project_id)]"),
'project_id':fields.many2one('project.project', 'Project'),
'duration': fields.float('Duration'),
'task_id': fields.many2one('project.task', 'Task', domain="[('project_id','=',project_id)]"),
@@ -442,11 +442,9 @@ class project_issue(base_stage, osv.osv):
# OR all section_ids and OR with case_default
search_domain = []
if section_ids:
search_domain += [('|')] * len(section_ids)
search_domain += [('|')] * (len(section_ids)-1)
for section_id in section_ids:
search_domain.append(('project_ids', '=', section_id))
search_domain.append(('case_default', '=', True))
# AND with the domain in parameter
search_domain += list(domain)
# perform search, return the first found
stage_ids = self.pool.get('project.task.type').search(cr, uid, search_domain, order=order, context=context)
+7 -7
View File
@@ -111,26 +111,26 @@
<field name="user_id"/>
<field name="partner_id" on_change="onchange_partner_id(partner_id, email_from)"/>
<field name="email_from"/>
</group>
<group>
<field name="priority" groups="base.group_user"/>
<label for="project_id" groups="base.group_user"/>
<div groups="base.group_user">
<field name="project_id" on_change="on_change_project(project_id)" class="oe_inline" context="{'default_use_issues':1}"/>
<button name="case_escalate" string="Escalate" type="object" states="draft,open,pending" class="oe_inline"/>
<button name="case_escalate" string="⇒ Escalate" type="object" states="draft,open,pending" class="oe_link"/>
</div>
</group>
<group>
<field name="categ_ids" widget="many2many_tags"/>
<field name="version_id" groups="base.group_user"/>
<field name="priority" groups="base.group_user"/>
<label for="task_id" groups="base.group_user"/>
<div groups="base.group_user">
<field name="task_id" on_change="onchange_task_id(task_id)" class="oe_inline" context="{'default_project_id':project_id}"/>
<field name="progress" widget="progressbar" attrs="{'invisible':[('task_id','=',False)]}" class="oe_inline"/>
</div>
<field name="categ_ids" widget="many2many_tags"/>
<field name="version_id" groups="base.group_user"/>
</group>
</group>
<notebook>
<page string="Description">
<field name="description" placeholder="Add a description..."/>
<field name="description" placeholder="Add an internal note..." groups="base.group_user"/>
</page>
<page string="Extra Info" groups="base.group_no_one">
<group col="4" colspan="4">
+2 -2
View File
@@ -86,13 +86,13 @@
your customer.
</p>
<group>
<label for="id" string="Contract Feature"/>
<label for="id" string="Contract Features"/>
<div>
<div>
<field name="module_account_analytic_analysis" on_change="onchange_timesheet(module_account_analytic_analysis)" class="oe_inline"/>
<label for="module_account_analytic_analysis"/>
</div>
<div attrs="{'invisible':[('module_account_analytic_analysis','=',False)]}">
<div name="module_analytic_user_function" attrs="{'invisible':[('module_account_analytic_analysis','=',False)]}">
<field name="module_analytic_user_function" class="oe_inline"/>
<label for="module_analytic_user_function"/>
</div>
@@ -27,7 +27,10 @@ class account_invoice_report(osv.osv):
}
def _select(self):
return super(account_invoice_report, self)._select() + ", ai.section_id as section_id"
return super(account_invoice_report, self)._select() + ", sub.section_id as section_id"
def _sub_select(self):
return super(account_invoice_report, self)._sub_select() + ", ai.section_id as section_id"
def _group_by(self):
return super(account_invoice_report, self)._group_by() + ", ai.section_id"