Merge remote-tracking branch 'odoo/master' into master-allow-translate-on-noedit-sle
This commit is contained in:
@@ -714,7 +714,7 @@ class account_journal(osv.osv):
|
||||
_name = "account.journal"
|
||||
_description = "Journal"
|
||||
_columns = {
|
||||
'with_last_closing_balance' : fields.boolean('Opening With Last Closing Balance'),
|
||||
'with_last_closing_balance': fields.boolean('Opening With Last Closing Balance', help="For cash or bank journal, this option should be unchecked when the starting balance should always set to 0 for new documents."),
|
||||
'name': fields.char('Journal Name', required=True),
|
||||
'code': fields.char('Code', size=5, required=True, help="The code will be displayed on reports."),
|
||||
'type': fields.selection([('sale', 'Sale'),('sale_refund','Sale Refund'), ('purchase', 'Purchase'), ('purchase_refund','Purchase Refund'), ('cash', 'Cash'), ('bank', 'Bank and Checks'), ('general', 'General'), ('situation', 'Opening/Closing Situation')], 'Type', size=32, required=True,
|
||||
@@ -745,7 +745,7 @@ class account_journal(osv.osv):
|
||||
|
||||
_defaults = {
|
||||
'cash_control' : False,
|
||||
'with_last_closing_balance' : False,
|
||||
'with_last_closing_balance' : True,
|
||||
'user_id': lambda self, cr, uid, context: uid,
|
||||
'company_id': lambda self, cr, uid, c: self.pool.get('res.users').browse(cr, uid, uid, c).company_id.id,
|
||||
}
|
||||
|
||||
@@ -439,7 +439,7 @@
|
||||
<field name="internal_account_id" domain="[('type','!=','view')]"/>
|
||||
</group>
|
||||
<group string="Miscellaneous">
|
||||
<field name="with_last_closing_balance"/>
|
||||
<field name="with_last_closing_balance" attrs="{'invisible': [('type', 'not in', ['bank', 'cash'])]}"/>
|
||||
<field name="cash_control" attrs="{'invisible':[('type','not in', ('cash',))]}"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
@@ -15,44 +15,63 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Custom reports (aka filters) -->
|
||||
<record id="filter_invoice_salespersons" model="ir.filters">
|
||||
<field name="name">By Salespersons</field>
|
||||
<field name="model_id">account.invoice.report</field>
|
||||
<field name="domain">[]</field>
|
||||
<field name="user_id" eval="False"/>
|
||||
<field name="context">{'group_by': ['date:month', 'user_id']}</field>
|
||||
</record>
|
||||
<record id="filter_invoice_product" model="ir.filters">
|
||||
<field name="name">By Product</field>
|
||||
<field name="model_id">account.invoice.report</field>
|
||||
<field name="domain">[]</field>
|
||||
<field name="user_id" eval="False"/>
|
||||
<field name="context">{'group_by': ['date:month', 'product_id'], 'set_visible':True, 'residual_invisible':True}</field>
|
||||
</record>
|
||||
<record id="filter_invoice_product_category" model="ir.filters">
|
||||
<field name="name">By Product Category</field>
|
||||
<field name="model_id">account.invoice.report</field>
|
||||
<field name="domain">[]</field>
|
||||
<field name="user_id" eval="False"/>
|
||||
<field name="context">{'group_by': ['date:month', 'categ_id'], 'residual_invisible':True}</field>
|
||||
</record>
|
||||
<record id="filter_invoice_refund" model="ir.filters">
|
||||
<field name="name">By Refund</field>
|
||||
<field name="model_id">account.invoice.report</field>
|
||||
<field name="domain">[('type', '=', 'out_refund')]</field>
|
||||
<field name="user_id" eval="False"/>
|
||||
<field name="context">{'group_by': ['date:month', 'user_id']}</field>
|
||||
</record>
|
||||
<record id="filter_invoice_country" model="ir.filters">
|
||||
<field name="name">By Country</field>
|
||||
<field name="model_id">account.invoice.report</field>
|
||||
<field name="domain">[]</field>
|
||||
<field name="user_id" eval="False"/>
|
||||
<field name="context">{'group_by': ['date:month', 'country_id']}</field>
|
||||
</record>
|
||||
|
||||
<record id="view_account_invoice_report_search" model="ir.ui.view">
|
||||
<field name="name">account.invoice.report.search</field>
|
||||
<field name="model">account.invoice.report</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Invoices Analysis">
|
||||
<field name="date"/>
|
||||
<filter icon="terp-go-year" string="Year" name="year" domain="['|',('date', '=', False),'&',('date','<=', time.strftime('%%Y-%%m-%%d')),('date','>=',time.strftime('%%Y-01-01'))]" help="year"/>
|
||||
<filter string="This Year" name="year" domain="['|', ('date', '=', False), '&',('date','<=', time.strftime('%%Y-12-31')),('date','>=',time.strftime('%%Y-01-01'))]"/>
|
||||
<separator/>
|
||||
<filter string="Draft" icon="terp-document-new" domain="[('state','=','draft')]" help = "Draft Invoices"/>
|
||||
<filter string="Pro-forma" icon="terp-gtk-media-pause" domain="['|', ('state','=','proforma'),('state','=','proforma2')]" help = "Pro-forma Invoices"/>
|
||||
<filter string="Invoiced" name="current" icon="terp-check" domain="[('state','not in', ('draft','cancel','proforma','proforma2'))]" help = "Open and Paid Invoices"/>
|
||||
<filter string="To Invoice" domain="[('state','=','draft')]" help = "Draft Invoices"/>
|
||||
<filter string="Pro-forma" domain="['|', ('state','=','proforma'),('state','=','proforma2')]"/>
|
||||
<filter string="Invoiced" name="current" domain="[('state','not in', ('draft','cancel','proforma','proforma2'))]"/>
|
||||
<separator/>
|
||||
<filter icon="terp-personal" string="Customer" name="customer" domain="['|', ('type','=','out_invoice'),('type','=','out_refund')]" help="Customer Invoices And Refunds"/>
|
||||
<filter icon="terp-personal" string="Supplier" domain="['|', ('type','=','in_invoice'),('type','=','in_refund')]" help="Supplier Invoices And Refunds"/>
|
||||
<filter string="Customer" name="customer" domain="['|', ('type','=','out_invoice'),('type','=','out_refund')]"/>
|
||||
<filter string="Supplier" domain="['|', ('type','=','in_invoice'),('type','=','in_refund')]"/>
|
||||
<separator/>
|
||||
<filter icon="terp-dolar" string="Invoice" domain="['|', ('type','=','out_invoice'),('type','=','in_invoice')]" help="Customer And Supplier Invoices"/>
|
||||
<filter icon="terp-dolar_ok!" string="Refund" domain="['|', ('type','=','out_refund'),('type','=','in_refund')]" help="Customer And Supplier Refunds"/>
|
||||
<filter string="Invoice" domain="['|', ('type','=','out_invoice'),('type','=','in_invoice')]"/>
|
||||
<filter string="Refund" domain="['|', ('type','=','out_refund'),('type','=','in_refund')]"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="user_id" />
|
||||
<field name="categ_id" filter_domain="[('categ_id', 'child_of', self)]"/>
|
||||
<group expand="1" string="Group By">
|
||||
<filter string="Partner" name="partner_id" context="{'group_by':'partner_id','residual_visible':True}"/>
|
||||
<filter string="Commercial Partner" name="commercial_partner_id" context="{'group_by':'commercial_partner_id','residual_visible':True}"/>
|
||||
<filter string="Commercial Partner's Country" name="country_id" context="{'group_by':'country_id'}"/>
|
||||
<filter string="Salesperson" name='user' icon="terp-personal" context="{'group_by':'user_id'}"/>
|
||||
<filter string="Due Month" icon="terp-go-today" context="{'group_by':'date_due'}"/>
|
||||
<filter string="Period" icon="terp-go-month" context="{'group_by':'period_id'}"/>
|
||||
<filter string="Product" icon="terp-accessories-archiver" context="{'group_by':'product_id','set_visible':True,'residual_invisible':True}"/>
|
||||
<filter string="Category of Product" name="category_product" icon="terp-stock_symbol-selection" context="{'group_by':'categ_id','residual_invisible':True}"/>
|
||||
<filter string="Status" icon="terp-stock_effects-object-colorize" context="{'group_by':'state'}"/>
|
||||
<filter string="Type" icon="terp-stock_symbol-selection" context="{'group_by':'type'}"/>
|
||||
<filter string="Journal" icon="terp-folder-orange" context="{'group_by':'journal_id'}"/>
|
||||
<filter string="Account" icon="terp-folder-orange" context="{'group_by':'account_line_id'}"/>
|
||||
<filter string="Company" icon="terp-go-home" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>
|
||||
<filter string="Invoice Date (day)" name="day" icon="terp-go-today" context="{'group_by':'date:day'}" help="Group by Invoice Date"/>
|
||||
<filter string="Invoice Date (month)" name="month" icon="terp-go-month" context="{'group_by':'date:month'}" help="Group by month of Invoice Date"/>
|
||||
<filter string="Invoice Date (year)" name="group_year" icon="terp-go-year" context="{'group_by':'date:year'}" help="Group by year of Invoice Date"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -222,13 +222,13 @@
|
||||
<field name="create_date"/>
|
||||
<field name="name"/>
|
||||
<field name="contact_name"/>
|
||||
<field name="country_id" invisible="context.get('invisible_country', True)"/>
|
||||
<field name="country_id"/>
|
||||
<field name="email_from"/>
|
||||
<field name="phone"/>
|
||||
<field name="stage_id"/>
|
||||
<field name="user_id" invisible="1"/>
|
||||
<field name="partner_id" invisible="1"/>
|
||||
<field name="section_id" invisible="context.get('invisible_section', True)" groups="base.group_multi_salesteams"/>
|
||||
<field name="section_id" groups="base.group_multi_salesteams"/>
|
||||
<field name="probability" invisible="1"/>
|
||||
<field name="type_id" invisible="1"/>
|
||||
<field name="referred" invisible="1"/>
|
||||
@@ -326,44 +326,31 @@
|
||||
<search string="Search Leads">
|
||||
<field name="name" string="Lead / Customer" filter_domain="['|','|','|',('partner_name','ilike',self),('email_from','ilike',self),('contact_name','ilike',self),('name','ilike',self)]"/>
|
||||
<field name="categ_ids" string="Tag" filter_domain="[('categ_ids', 'ilike', self)]"/>
|
||||
<field name="section_id" context="{'invisible_section': False}" groups="base.group_multi_salesteams"/>
|
||||
<field name="section_id" groups="base.group_multi_salesteams"/>
|
||||
<field name="user_id"/>
|
||||
<field name="partner_id" operator="child_of"/>
|
||||
<field name="create_date"/>
|
||||
<field name="country_id" context="{'invisible_country': False}"/>
|
||||
<field name="country_id"/>
|
||||
<separator/>
|
||||
<filter string="My Leads"
|
||||
domain="[('user_id','=',uid)]"
|
||||
help="Leads that are assigned to me"/>
|
||||
<filter string="Unassigned" name="unassigned"
|
||||
domain="[('user_id','=', False)]"
|
||||
help="No salesperson"/>
|
||||
<filter string="My Leads"
|
||||
domain="[('user_id','=',uid)]" context="{'invisible_section': False}"
|
||||
help="Leads that are assigned to me"/>
|
||||
<filter string="My Team(s)" groups="base.group_multi_salesteams"
|
||||
domain="[('section_id.member_ids', 'in', [uid])]" context="{'invisible_section': False}"
|
||||
help="Leads that are assigned to any sales teams I am member of"/>
|
||||
<filter string="Dead" name="dead"
|
||||
domain="[('probability', '=', '0'), ('stage_id.fold', '=', True)]"/>
|
||||
<filter string="Unread Messages" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<separator />
|
||||
<filter string="New Mail" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<separator />
|
||||
<filter string="Available for mass mailing"
|
||||
name='not_opt_out' domain="[('opt_out', '=', False)]"
|
||||
help="Leads that did not ask not to be included in mass mailing campaigns"/>
|
||||
<separator />
|
||||
<group expand="0" string="Group By">
|
||||
<filter string="Salesperson" domain="[]" context="{'group_by':'user_id'}"/>
|
||||
<filter string="Team" domain="[]" context="{'group_by':'section_id'}" groups="base.group_multi_salesteams"/>
|
||||
<filter string="Sales Team" domain="[]" context="{'group_by':'section_id'}" groups="base.group_multi_salesteams"/>
|
||||
<filter string="Stage" domain="[]" context="{'group_by':'stage_id'}"/>
|
||||
<filter string="Customer" help="Partner" domain="[]" context="{'group_by':'partner_id'}"/>
|
||||
<filter string="Country" domain="[]" context="{'group_by':'country_id'}"/>
|
||||
<filter string="Referrer" domain="[]" context="{'group_by':'referred'}"/>
|
||||
<filter string="Campaign" domain="[]" context="{'group_by':'type_id'}"/>
|
||||
<filter string="Channel" domain="[]" context="{'group_by':'channel_id'}"/>
|
||||
<filter string="Creation" domain="[]" context="{'group_by':'create_date'}"/>
|
||||
<filter string="Last Post (weekly)" name="group_message_last_post" domain="[]" context="{'group_by':'message_last_post:week'}"/>
|
||||
</group>
|
||||
<group string="Display">
|
||||
<filter string="Countries" context="{'invisible_country': False}" help="Countries"/>
|
||||
<filter string="Sales Team" context="{'invisible_section': False}" domain="[]" help="Sales Team" groups="base.group_multi_salesteams"/>
|
||||
<filter string="Expected Closing" domain="[]" context="{'group_by':'date_deadline:week'}"/>
|
||||
<filter string="Last Message" name="group_message_last_post" domain="[]" context="{'group_by':'message_last_post:week'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
@@ -523,7 +510,7 @@
|
||||
<field name="create_date"/>
|
||||
<field name="name" string="Opportunity"/>
|
||||
<field name="partner_id" string="Customer"/>
|
||||
<field name="country_id" invisible="context.get('invisible_country', True)"/>
|
||||
<field name="country_id"/>
|
||||
<field name="date_action"/>
|
||||
<field name="title_action"/>
|
||||
<field name="channel_id" invisible="1"/>
|
||||
@@ -531,7 +518,7 @@
|
||||
<field name="stage_id"/>
|
||||
<field name="planned_revenue" sum="Expected Revenues"/>
|
||||
<field name="probability" avg="Avg. of Probability"/>
|
||||
<field name="section_id" invisible="context.get('invisible_section', True)" groups="base.group_multi_salesteams"/>
|
||||
<field name="section_id" groups="base.group_multi_salesteams"/>
|
||||
<field name="user_id"/>
|
||||
<field name="referred" invisible="1"/>
|
||||
<field name="priority" invisible="1"/>
|
||||
@@ -551,7 +538,7 @@
|
||||
<search string="Search Opportunities">
|
||||
<field name="name" string="Opportunity" filter_domain="['|','|','|',('partner_id','ilike',self),('partner_name','ilike',self),('email_from','ilike',self),('name', 'ilike', self)]"/>
|
||||
<field name="categ_ids" string="Tag" filter_domain="[('categ_ids', 'ilike', self)]"/>
|
||||
<field name="section_id" context="{'invisible_section': False}" groups="base.group_multi_salesteams"/>
|
||||
<field name="section_id" groups="base.group_multi_salesteams"/>
|
||||
<field name="user_id"/>
|
||||
<field name="partner_id" operator="child_of"/>
|
||||
<field name="stage_id" domain="[]"/>
|
||||
@@ -561,34 +548,21 @@
|
||||
domain="[('probability', '=', 100), ('stage_id.fold', '=', True)]"/>
|
||||
<filter string="Lost" name="lost"
|
||||
domain="[('probability', '=', 0), ('stage_id.fold', '=', True)]"/>
|
||||
<separator/>
|
||||
<filter string="My Opportunities" name="assigned_to_me"
|
||||
domain="[('user_id', '=', uid)]"
|
||||
help="Opportunities that are assigned to me"/>
|
||||
<filter string="Unassigned" name="unassigned"
|
||||
domain="[('user_id','=', False)]" help="No salesperson"/>
|
||||
<filter string="My Opportunities" name="assigned_to_me"
|
||||
domain="[('user_id', '=', uid)]" context="{'invisible_section': False}"
|
||||
help="Opportunities that are assigned to me"/>
|
||||
<filter string="My Team(s)"
|
||||
domain="[('section_id.member_ids', 'in', [uid])]" context="{'invisible_section': False}"
|
||||
help="Opportunities that are assigned to any sales teams I am member of" groups="base.group_multi_salesteams"/>
|
||||
<filter string="Unread Messages" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<separator/>
|
||||
<filter string="New Mail" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<group expand="0" string="Group By" colspan="16">
|
||||
<filter string="Salesperson" domain="[]" context="{'group_by':'user_id'}"/>
|
||||
<filter string="Team" domain="[]" context="{'group_by':'section_id'}" groups="base.group_multi_salesteams"/>
|
||||
<filter string="Stage" domain="[]" context="{'group_by':'stage_id'}"/>
|
||||
<filter string="Customer" help="Partner" domain="[]" context="{'group_by':'partner_id'}"/>
|
||||
<filter string="Country" domain="[]" context="{'group_by':'country_id'}"/>
|
||||
<filter string="Priority" domain="[]" context="{'group_by':'priority'}"/>
|
||||
<filter string="Expected Closing" domain="[]" context="{'group_by':'date_deadline'}"/>
|
||||
<filter string="Referrer" domain="[]" context="{'group_by':'referred'}"/>
|
||||
<filter string="Campaign" domain="[]" context="{'group_by':'type_id'}"/>
|
||||
<filter string="Channel" domain="[]" context="{'group_by':'channel_id'}"/>
|
||||
<filter string="Creation" domain="[]" context="{'group_by':'create_date'}"/>
|
||||
<filter string="Last Update Month" domain="[]" context="{'group_by':'write_date'}"/>
|
||||
<filter string="Last Post (weekly)" name="group_message_last_post" domain="[]" context="{'group_by':'message_last_post:week'}"/>
|
||||
</group>
|
||||
<group string="Display">
|
||||
<filter string="Sales Team" context="{'invisible_section': False}" domain="[]" help="Sales Team" groups="base.group_multi_salesteams"/>
|
||||
<filter string="Countries" context="{'invisible_country': False}" help="Countries"/>
|
||||
<filter string="Last Message" name="group_message_last_post" domain="[]" context="{'group_by':'message_last_post:week'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
|
||||
@@ -170,29 +170,29 @@
|
||||
<field name="model">crm.phonecall</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Phonecalls">
|
||||
<field name="name" string="Phonecalls"/>
|
||||
<field name="date"/>
|
||||
<field name="state"/>
|
||||
<separator/>
|
||||
<filter icon="terp-gtk-go-back-rtl" string="To Do" name="current" domain="[('state','=','open')]"/>
|
||||
<separator/>
|
||||
<filter string="Unassigned Phonecalls" icon="terp-personal-" domain="[('user_id','=',False)]" help="Unassigned Phonecalls"/>
|
||||
<filter string="Unread Messages" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<separator/>
|
||||
<filter string="Phone Calls Assigned to Me or My Team(s)" icon="terp-personal+" domain="['|', ('section_id.user_id','=',uid), ('user_id', '=', uid)]"
|
||||
help="Phone Calls Assigned to the current user or with a team having the current user as team leader"/>
|
||||
<field name="partner_id" operator="child_of"/>
|
||||
<field name="user_id"/>
|
||||
<field name="opportunity_id"/>
|
||||
<field name="section_id" string="Sales Team"
|
||||
<field name="name" string="Phonecalls"/>
|
||||
<field name="date"/>
|
||||
<field name="state"/>
|
||||
<filter string="My Phonecalls" domain="[('user_id', '=', uid)]"/>
|
||||
<filter string="My Team" domain="[('section_id.user_id', '=', uid)]"/>
|
||||
<filter string="Unassigned" domain="[('user_id','=',False)]"/>
|
||||
<separator/>
|
||||
<filter string="To Do" name="current" domain="[('state','=','open')]"/>
|
||||
<separator/>
|
||||
<filter string="New Mail" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<separator/>
|
||||
<field name="partner_id" operator="child_of"/>
|
||||
<field name="user_id"/>
|
||||
<field name="opportunity_id"/>
|
||||
<field name="section_id" string="Sales Team"
|
||||
groups="base.group_multi_salesteams"/>
|
||||
<group expand="0" string="Group By">
|
||||
<filter string="Partner" icon="terp-partner" domain="[]" context="{'group_by':'partner_id'}"/>
|
||||
<filter string="Responsible" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>
|
||||
<filter string="Creation" icon="terp-go-month" help="Creation Date" domain="[]" context="{'group_by':'create_date'}"/>
|
||||
<filter string="Calls Month" icon="terp-go-month" domain="[]" context="{'group_by':'date'}" help="Calls Date by Month"/>
|
||||
</group>
|
||||
</search>
|
||||
<group expand="0" string="Group By">
|
||||
<filter string="Partner" domain="[]" context="{'group_by':'partner_id'}"/>
|
||||
<filter string="Responsible" domain="[]" context="{'group_by':'user_id'}"/>
|
||||
<filter string="Creation" help="Creation Date" domain="[]" context="{'group_by':'create_date'}"/>
|
||||
<filter string="Month" domain="[]" context="{'group_by':'date'}" help="Calls Date by Month"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<!-- Leads by user and section Graph View -->
|
||||
|
||||
<!-- Leads by user and section Graph View -->
|
||||
<record id="view_report_crm_lead_graph" model="ir.ui.view">
|
||||
<field name="name">crm.lead.report.graph</field>
|
||||
<field name="model">crm.lead.report</field>
|
||||
@@ -38,8 +37,23 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Leads by user and section Search View -->
|
||||
<!-- Custom reports (aka filters) -->
|
||||
<record id="filter_leads_salesperson" model="ir.filters">
|
||||
<field name="name">By Salespersons</field>
|
||||
<field name="model_id">crm.lead.report</field>
|
||||
<field name="domain">[]</field>
|
||||
<field name="user_id" eval="False"/>
|
||||
<field name="context">{'group_by': ['create_date:month', user_id']}</field>
|
||||
</record>
|
||||
<record id="filter_leads_country" model="ir.filters">
|
||||
<field name="name">By Country</field>
|
||||
<field name="model_id">crm.lead.report</field>
|
||||
<field name="domain">[]</field>
|
||||
<field name="user_id" eval="False"/>
|
||||
<field name="context">{'group_by': ['create_date:month', 'country_id']}</field>
|
||||
</record>
|
||||
|
||||
<!-- Leads by user and section Search View -->
|
||||
<record id="view_report_crm_lead_filter" model="ir.ui.view">
|
||||
<field name="name">crm.lead.report.select</field>
|
||||
<field name="model">crm.lead.report</field>
|
||||
@@ -54,11 +68,6 @@
|
||||
domain="[('probability', '=', 100), ('stage_id.on_change', '=', 1)]"/>
|
||||
<filter string="Lost" name="lost"
|
||||
domain="[('probability', '=', 0), ('stage_id.sequence', '!=', 1)]"/>
|
||||
<separator/>
|
||||
<filter string="My Sales Team(s)" icon="terp-personal+" context="{'invisible_section': False}" domain="[('section_id.user_id','=',uid)]"
|
||||
help="Leads/Opportunities that are assigned to one of the sale teams I manage" groups="base.group_multi_salesteams"/>
|
||||
<separator/>
|
||||
<filter icon="terp-personal" string="My Case(s)" help="Leads/Opportunities that are assigned to me" domain="[('user_id','=',uid)]"/>
|
||||
<field name="section_id" context="{'invisible_section': False}"
|
||||
groups="base.group_multi_salesteams"/>
|
||||
<field name="user_id" string="Salesperson"/>
|
||||
@@ -79,26 +88,6 @@
|
||||
<field name="opening_date"/>
|
||||
<field name="date_closed"/>
|
||||
</group>
|
||||
<group expand="1" string="Group By">
|
||||
<filter string="Salesperson" domain="[]" context="{'group_by':'user_id'}" />
|
||||
<filter string="Sales Team" domain="[]" context="{'group_by':'section_id'}" groups="base.group_multi_salesteams"/>
|
||||
<filter string="Partner" context="{'group_by':'partner_id'}" />
|
||||
<filter string="Country" context="{'group_by':'country_id'}" />
|
||||
<filter string="Company" domain="[]" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>
|
||||
<filter string="Type" domain="[]" context="{'group_by':'type'}"/>
|
||||
<filter string="Stage" domain="[]" context="{'group_by':'stage_id'}"/>
|
||||
<filter string="Priority" domain="[]" context="{'group_by':'priority'}" />
|
||||
<filter string="Campaign" domain="[]" context="{'group_by':'type_id'}" />
|
||||
<filter string="Channel" domain="[]" context="{'group_by':'channel_id'}" />
|
||||
<separator orientation="vertical" />
|
||||
<filter string="Creation date (day)" domain="[]" context="{'group_by':'create_date:day'}"/>
|
||||
<filter string="Creation date (week)" domain="[]" context="{'group_by':'create_date:week'}"/>
|
||||
<filter string="Creation date (month)" domain="[]" context="{'group_by':'create_date:month'}" name="month"/>
|
||||
<filter string="Creation date (year)" domain="[]" context="{'group_by':'create_date:year'}"/>
|
||||
<separator orientation="vertical" />
|
||||
<filter string="Exp. Closing" domain="[]" context="{'group_by':'date_deadline'}"/>
|
||||
<filter string="Last Stage Update" context="{'group_by':'date_last_stage_update'}" />
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -59,13 +59,10 @@
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="inherit_id" ref="crm.view_crm_case_opportunities_filter"/>
|
||||
<field name="arch" type="xml">
|
||||
<filter string="Team" position="after">
|
||||
<filter string="Assigned Partner" icon="terp-personal" domain="[]" context="{'group_by':'partner_assigned_id'}"/>
|
||||
<filter string="Assigned Month" icon="terp-go-month"
|
||||
domain="[]" context="{'group_by':'date_assign'}"/>
|
||||
|
||||
<filter string="Customer" position="after">
|
||||
<filter string="Assigned Partner" domain="[]" context="{'group_by':'partner_assigned_id'}"/>
|
||||
</filter>
|
||||
<filter string="My Team(s)" position="after">
|
||||
<filter name="unassigned" position="after">
|
||||
<filter string="My Assigned Partners" domain="[('partner_assigned_id.user_id', '=', uid)]"/>
|
||||
</filter>
|
||||
<field name="partner_id" position="after">
|
||||
@@ -131,10 +128,10 @@
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="inherit_id" ref="crm.view_crm_case_leads_filter"/>
|
||||
<field name="arch" type="xml">
|
||||
<filter string="Team" position="after">
|
||||
<filter string="Assigned Partner" icon="terp-personal" domain="[]" context="{'group_by':'partner_assigned_id'}"/>
|
||||
<filter string="Customer" position="after">
|
||||
<filter string="Assigned Partner" domain="[]" context="{'group_by':'partner_assigned_id'}"/>
|
||||
</filter>
|
||||
<filter string="My Team(s)" position="after">
|
||||
<filter name="unassigned" position="after">
|
||||
<filter string="My Assigned Partners" domain="[('partner_assigned_id.user_id', '=', uid)]"/>
|
||||
</filter>
|
||||
<field name="partner_id" position="after">
|
||||
|
||||
@@ -193,14 +193,13 @@
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Applicants">
|
||||
<field name="partner_name" filter_domain="['|','|',('name','ilike',self),('partner_name','ilike',self),('email_from','ilike',self)]" string="Subject / Applicant"/>
|
||||
<filter string="Unassigned" domain="[('user_id', '=', False)]"/>
|
||||
<filter string="My" domain="[('user_id', '=', uid)]"/>
|
||||
<separator/>
|
||||
<filter string="Unread Messages" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<filter string="Unassigned" domain="[('user_id', '=', False)]"/>
|
||||
<separator/>
|
||||
<filter string="Next Actions" context="{'invisible_next_action':False, 'invisible_next_date':False}"
|
||||
domain="[('date_action','<>',False)]" help="Filter and view on next actions and date"/>
|
||||
|
||||
<separator/>
|
||||
<filter string="New Mail" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<field name="job_id"/>
|
||||
<field name="department_id"/>
|
||||
<field name="user_id"/>
|
||||
@@ -210,15 +209,9 @@
|
||||
<separator/>
|
||||
<group expand="0" string="Group By">
|
||||
<filter string="Responsible" domain="[]" context="{'group_by':'user_id'}"/>
|
||||
<filter string="Department" domain="[]" context="{'group_by':'department_id'}"/>
|
||||
<filter string="Job" domain="[]" context="{'group_by':'job_id'}"/>
|
||||
<filter string="Degree" domain="[]" context="{'group_by':'type_id'}"/>
|
||||
<filter string="Availability" domain="[]" context="{'group_by':'availability'}"/>
|
||||
<filter string="Appreciation" domain="[]" context="{'group_by':'priority'}"/>
|
||||
<filter string="Last Stage" help="Match this group by with a specific stage filter in order to analyse the recruitment process" context="{'group_by':'last_stage_id'}"/>
|
||||
<filter string="Stage" domain="[]" context="{'group_by':'stage_id'}"/>
|
||||
<filter string="Source" domain="[]" context="{'group_by':'source_id'}"/>
|
||||
<filter string="Creation Month" domain="[]" context="{'group_by':'create_date'}"/>
|
||||
<filter string="Last Stage Update" context="{'group_by':'date_last_stage_update'}"/>
|
||||
</group>
|
||||
</search>
|
||||
|
||||
@@ -12,6 +12,29 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Custom reports (aka filters) -->
|
||||
<record id="filter_recruitment_report_recruiter" model="ir.filters">
|
||||
<field name="name">By Recruiter</field>
|
||||
<field name="model_id">hr.recruitment.report</field>
|
||||
<field name="domain">[]</field>
|
||||
<field name="user_id" eval="False"/>
|
||||
<field name="context">{'group_by': ['date_create:month', 'user_id']}</field>
|
||||
</record>
|
||||
<record id="filter_recruitment_report_job" model="ir.filters">
|
||||
<field name="name">By Job</field>
|
||||
<field name="model_id">hr.recruitment.report</field>
|
||||
<field name="domain">[]</field>
|
||||
<field name="user_id" eval="False"/>
|
||||
<field name="context">{'group_by': ['date_create:month', 'job_id']}</field>
|
||||
</record>
|
||||
<record id="filter_recruitment_report_departmnet" model="ir.filters">
|
||||
<field name="name">By Department</field>
|
||||
<field name="model_id">hr.recruitment.report</field>
|
||||
<field name="domain">[]</field>
|
||||
<field name="user_id" eval="False"/>
|
||||
<field name="context">{'group_by': ['date_create:month', 'department_id']}</field>
|
||||
</record>
|
||||
|
||||
<record id="view_hr_recruitment_report_search" model="ir.ui.view">
|
||||
<field name="name">hr.recruitment.report.search</field>
|
||||
<field name="model">hr.recruitment.report</field>
|
||||
@@ -20,11 +43,13 @@
|
||||
<field name="job_id"/>
|
||||
<field name="department_id"/>
|
||||
<field name="user_id"/>
|
||||
<filter string="New" domain="[('sequence', '=', 1)]"/>
|
||||
<filter string="This Year" name="year" domain="[('date_create','<=', time.strftime('%%Y-12-31')),('date_create','>=',time.strftime('%%Y-01-01'))]"/>
|
||||
<separator/>
|
||||
<filter string="Unassigned" domain="[('user_id', '=', False)]"/>
|
||||
<filter string="My" domain="[('user_id', '=', uid)]"/>
|
||||
<separator/>
|
||||
<filter string="New" domain="[('sequence', '=', 1)]"/>
|
||||
<separator/>
|
||||
<group expand="0" string="Extended Filters...">
|
||||
<field name="priority"/>
|
||||
<field name="stage_id"/>
|
||||
@@ -32,21 +57,6 @@
|
||||
<field name="date_create"/>
|
||||
<field name="date_closed"/>
|
||||
</group>
|
||||
<group expand="1" string="Group By ...">
|
||||
<filter string="Responsible" name='User' context="{'group_by':'user_id'}"/>
|
||||
<filter string="Company" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>
|
||||
<filter string="Partner" context="{'group_by':'partner_id'}" />
|
||||
<filter string="Jobs" name="job" context="{'group_by':'job_id'}"/>
|
||||
<filter string="Department" name="department" context="{'group_by':'department_id'}"/>
|
||||
<filter string="Degree" name="degree" context="{'group_by':'type_id'}"/>
|
||||
<filter string="Last Stage" help="Match this group by with a specific stage filter in order to analyse the recruitment process" context="{'group_by':'last_stage_id'}"/>
|
||||
<filter string="Stage" context="{'group_by':'stage_id'}" />
|
||||
<filter string="Last Stage Update" context="{'group_by':'date_last_stage_update'}" />
|
||||
<filter string="Creation Date (day)" context="{'group_by':'date_create:day'}" help="Creation Date"/>
|
||||
<filter string="Creation Date (week)" context="{'group_by':'date_create:week'}" help="Creation Date"/>
|
||||
<filter string="Creation Date (month)" context="{'group_by':'date_create:month'}" help="Creation Date"/>
|
||||
<filter string="Creation Date (year)" context="{'group_by':'date_create:year'}" help="Creation Date"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
@@ -56,7 +66,7 @@
|
||||
<field name="res_model">hr.recruitment.report</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">graph</field>
|
||||
<field name="context">{'group_by_no_leaf':1,'group_by':[]}</field>
|
||||
<field name="context">{'search_default_year': 1, 'group_by_no_leaf':1,'group_by':[]}</field>
|
||||
<field name="search_view_id" ref="view_hr_recruitment_report_search"/>
|
||||
</record>
|
||||
<menuitem action="action_hr_recruitment_report_all" id="menu_hr_recruitment_report_all" parent="hr.menu_hr_reporting" sequence="0"/>
|
||||
|
||||
@@ -18,29 +18,24 @@
|
||||
<search string="Tasks">
|
||||
<field name="name" string="Tasks"/>
|
||||
<field name="categ_ids"/>
|
||||
<filter string="Unassigned" name="unassigned" domain="[('user_id', '=', False)]"/>
|
||||
<filter string="New" name="draft" domain="[('stage_id.sequence', '<=', 1)]"/>
|
||||
<separator/>
|
||||
<filter string="My Tasks" domain="[('user_id','=',uid)]"/>
|
||||
<separator/>
|
||||
<filter string="Unread Messages" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<separator/>
|
||||
<filter string="Deadlines" context="{'deadline_visible': False}" domain="[('date_deadline','<>',False)]"
|
||||
help="Show only tasks having a deadline"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="project_id"/>
|
||||
<field name="reviewer_id"/>
|
||||
<field name="user_id"/>
|
||||
<field name="stage_id" domain="[]"/>
|
||||
<filter string="My Tasks" domain="[('user_id','=',uid)]"/>
|
||||
<filter string="Unassigned" name="unassigned" domain="[('user_id', '=', False)]"/>
|
||||
<separator/>
|
||||
<filter string="New" name="draft" domain="[('stage_id.sequence', '<=', 1)]"/>
|
||||
<separator/>
|
||||
<filter string="New Mail" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<group expand="0" string="Group By">
|
||||
<filter string="Reviewers" name="group_reviewer_id" domain="[]" context="{'group_by':'reviewer_id'}"/>
|
||||
<filter string="Users" name="group_user_id" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>
|
||||
<filter string="Project" name="group_project_id" icon="terp-folder-violet" domain="[]" context="{'group_by':'project_id'}"/>
|
||||
<filter string="Stage" name="group_stage_id" icon="terp-stage" domain="[]" context="{'group_by':'stage_id'}"/>
|
||||
<filter string="Last Stage Update" icon="terp-go-month" domain="[]" context="{'group_by':'date_last_stage_update'}"/>
|
||||
<filter string="Deadline" icon="terp-gnome-cpu-frequency-applet+" domain="[]" context="{'group_by':'date_deadline'}"/>
|
||||
<filter string="Start Month" icon="terp-go-month" domain="[]" context="{'group_by':'date_start'}"/>
|
||||
<filter string="End Month" icon="terp-go-month" domain="[]" context="{'group_by':'date_end'}" groups="base.group_no_one"/>
|
||||
<filter string="Last Message" name="group_message_last_post" domain="[]" context="{'group_by':'message_last_post:week'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
@@ -190,15 +185,14 @@
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Project">
|
||||
<field name="name" string="Project Name"/>
|
||||
<filter icon="terp-mail-message-new" string="Unread Messages" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<filter string="Open" name="Current" domain="[('state', '=','open')]"/>
|
||||
<filter string="Pending" name="Pending" domain="[('state', '=','pending')]"/>
|
||||
<filter string="Template" name="Template" domain="[('state', '=','template')]"/>
|
||||
<separator/>
|
||||
<filter icon="terp-check" string="Open" name="Current" domain="[('state', '=','open')]" help="Open Projects"/>
|
||||
<filter icon="gtk-media-pause" string="Pending" name="Pending" domain="[('state', '=','pending')]" help="Pending Projects"/>
|
||||
<filter icon="gtk-media-pause" string="Template" name="Template" domain="[('state', '=','template')]" help="Templates of Projects"/>
|
||||
<filter string="Member" domain="['|',('user_id', '=', uid),('members', '=', uid)]"/>
|
||||
<filter string="Manager" domain="[('user_id','=',uid)]"/>
|
||||
<separator/>
|
||||
<filter icon="terp-personal+" string="Member" domain="['|',('user_id', '=', uid),('members', '=', uid)]" help="Projects in which I am a member."/>
|
||||
<separator/>
|
||||
<filter string="Project(s) Manager" domain="[('user_id','=',uid)]" help="Projects in which I am a manager" icon="terp-personal"/>
|
||||
<filter string="New Mail" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<field name="user_id" string="Project Manager"/>
|
||||
<field name="partner_id" string="Contact" filter_domain="[('partner_id', 'child_of', self)]"/>
|
||||
<group expand="0" string="Group By">
|
||||
|
||||
@@ -30,6 +30,7 @@ class report_project_task_user(osv.osv):
|
||||
_columns = {
|
||||
'name': fields.char('Task Summary', readonly=True),
|
||||
'user_id': fields.many2one('res.users', 'Assigned To', readonly=True),
|
||||
'reviewer_id': fields.many2one('res.users', 'Reviewer', readonly=True),
|
||||
'date_start': fields.date('Assignation Date', readonly=True),
|
||||
'no_of_days': fields.integer('# of Days', size=128, readonly=True),
|
||||
'date_end': fields.date('Ending Date', readonly=True),
|
||||
@@ -71,6 +72,7 @@ class report_project_task_user(osv.osv):
|
||||
-- sum(cast(to_char(date_trunc('day',t.date_end) - date_trunc('day',t.date_start),'DD') as int)) as no_of_days,
|
||||
abs((extract('epoch' from (t.write_date-t.date_start)))/(3600*24)) as no_of_days,
|
||||
t.user_id,
|
||||
t.reviewer_id,
|
||||
progress as progress,
|
||||
t.project_id,
|
||||
t.effective_hours as hours_effective,
|
||||
@@ -103,6 +105,7 @@ class report_project_task_user(osv.osv):
|
||||
date_deadline,
|
||||
date_last_stage_update,
|
||||
t.user_id,
|
||||
t.reviewer_id,
|
||||
t.project_id,
|
||||
t.priority,
|
||||
name,
|
||||
|
||||
@@ -21,6 +21,22 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Custom reports (aka filters) -->
|
||||
<record id="filter_task_report_responsible" model="ir.filters">
|
||||
<field name="name">By Responsible</field>
|
||||
<field name="model_id">report.project.task.user</field>
|
||||
<field name="domain">[]</field>
|
||||
<field name="user_id" eval="False"/>
|
||||
<field name="context">{'group_by': ['project_id', 'user_id']}</field>
|
||||
</record>
|
||||
<record id="filter_task_report_reviewer" model="ir.filters">
|
||||
<field name="name">By Reviewer</field>
|
||||
<field name="model_id">report.project.task.user</field>
|
||||
<field name="domain">[]</field>
|
||||
<field name="user_id" eval="False"/>
|
||||
<field name="context">{'group_by': ['project_id', 'reviewer_id']}</field>
|
||||
</record>
|
||||
|
||||
<record id="view_task_project_user_search" model="ir.ui.view">
|
||||
<field name="name">report.project.task.user.search</field>
|
||||
<field name="model">report.project.task.user</field>
|
||||
@@ -34,25 +50,14 @@
|
||||
<field name="user_id"/>
|
||||
<field name="partner_id" filter_domain="[('partner_id', 'child_of', self)]"/>
|
||||
<field name="stage_id"/>
|
||||
<filter string="Unassigned" name="unassigned" domain="[('user_id','=',False)]"/>
|
||||
<filter string="New" name="new" domain="[('stage_id.sequence', '=', 1)]"/>
|
||||
<separator/>
|
||||
<filter string="My Task" domain="[('user_id','=',uid)]" />
|
||||
<filter string="Unassigned" name="unassigned" domain="[('user_id','=',False)]"/>
|
||||
<separator/>
|
||||
<filter string="New" name="new" domain="[('stage_id.sequence', '<=', 1)]"/>
|
||||
<group expand="0" string="Extended Filters...">
|
||||
<field name="priority"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
<group expand="1" string="Group By">
|
||||
<filter string="Project" name="project" context="{'group_by':'project_id'}"/>
|
||||
<filter string="Task" context="{'group_by':'name'}" />
|
||||
<filter string="Contact" context="{'group_by':'partner_id'}" />
|
||||
<filter string="Assigned to" name="User" context="{'group_by':'user_id'}" />
|
||||
<filter string="Company" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>
|
||||
<filter string="Assignation date (day)" context="{'group_by':'date_start:day'}" help="Creation Date"/>
|
||||
<filter string="Assignation date (month)" context="{'group_by':'date_start:month'}" help="Creation Date"/>
|
||||
<filter string="Assignation date (year)" context="{'group_by':'date_start:year'}" help="Creation Date"/>
|
||||
<filter string="Last Stage Update" context="{'group_by':'date_last_stage_update'}" help="Last Stage Update"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -142,24 +142,23 @@
|
||||
<field name="name" string="Issue" filter_domain="['|', '|', '|', ('partner_id','child_of',self), ('description','ilike',self),('email_from','ilike',self),('name','ilike',self)]"/>
|
||||
<field name="id"/>
|
||||
<field name="partner_id" operator="child_of"/>
|
||||
<filter string="Unassigned" name="unassigned" domain="[('user_id', '=', False)]"/>
|
||||
<filter string="New" name="draft" domain="[('stage_id.sequence', '=', 1)]"/>
|
||||
<separator/>
|
||||
<filter string="Unread Messages" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<separator/>
|
||||
<field name="user_id"/>
|
||||
<field name="project_id"/>
|
||||
<field name="categ_ids"/>
|
||||
<field name="stage_id" domain="[]"/>
|
||||
<filter string="My Issues" domain="[('user_id','=',uid)]"/>
|
||||
<filter string="Unassigned" name="unassigned" domain="[('user_id', '=', False)]"/>
|
||||
<separator/>
|
||||
<filter string="New" name="draft" domain="[('stage_id.sequence', '=', 1)]"/>
|
||||
<separator/>
|
||||
<filter string="New Mail" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<group expand="0" string="Group By" >
|
||||
<filter string="Responsible" name="group_user_id" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>
|
||||
<filter string="Contact" name="group_partner_id" icon="terp-partner" domain="[]" context="{'group_by':'partner_id'}"/>
|
||||
<filter string="Project" name="group_project_id" icon="terp-folder-violet" domain="[]" context="{'group_by':'project_id'}"/>
|
||||
<filter string="Version" name="group_version" icon="terp-gtk-jump-to-rtl" domain="[]" context="{'group_by':'version_id'}"/>
|
||||
<filter string="Priority" name="group_priority" icon="terp-rating-rated" domain="[]" context="{'group_by':'priority'}"/>
|
||||
<filter string="Stage" name="group_stage_id" icon="terp-stage" domain="[]" context="{'group_by':'stage_id'}"/>
|
||||
<filter string="Creation Month" name="group_create_date" icon="terp-go-month" domain="[]" context="{'group_by':'create_date'}"/>
|
||||
<filter string="Last Post (weekly)" name="group_message_last_post" domain="[]" context="{'group_by':'message_last_post:week'}"/>
|
||||
<filter string="Last Message" name="group_message_last_post" domain="[]" context="{'group_by':'message_last_post:week'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
|
||||
@@ -13,6 +13,22 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Custom reports (aka filters) -->
|
||||
<record id="filter_issue_report_responsible" model="ir.filters">
|
||||
<field name="name">By Responsible</field>
|
||||
<field name="model_id">project.issue.report</field>
|
||||
<field name="domain">[]</field>
|
||||
<field name="user_id" eval="False"/>
|
||||
<field name="context">{'group_by': ['project_id', 'user_id']}</field>
|
||||
</record>
|
||||
<record id="filter_issue_report_reviewer" model="ir.filters">
|
||||
<field name="name">By Reviewer</field>
|
||||
<field name="model_id">project.issue.report</field>
|
||||
<field name="domain">[]</field>
|
||||
<field name="user_id" eval="False"/>
|
||||
<field name="context">{'group_by': ['project_id', 'reviewer_id']}</field>
|
||||
</record>
|
||||
|
||||
<record id="view_project_issue_report_filter" model="ir.ui.view">
|
||||
<field name="name">project.issue.report.select</field>
|
||||
<field name="model">project.issue.report</field>
|
||||
@@ -24,25 +40,10 @@
|
||||
<field name="partner_id" filter_domain="[('partner_id', 'child_of', self)]"/>
|
||||
<field name="version_id"/>
|
||||
<field name="stage_id"/>
|
||||
<filter string="My Task" domain="[('user_id','=',uid)]" />
|
||||
<filter string="Unassigned" name="unassigned" domain="[('user_id','=',False)]"/>
|
||||
<filter string="New" name="new" domain="[('stage_id.sequence', '=', 1)]"/>
|
||||
<filter string="Done" name="done" domain="[('stage_id.fold', '=', True)]"
|
||||
help="Tasks beloging to a folded stage"/>
|
||||
<group expand="1" string="Group By">
|
||||
<filter string="Assigned to" name="Responsible" icon="terp-personal" domain="[]" context="{'group_by':'user_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'}" groups="base.group_multi_salesteams"/>
|
||||
<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'}"/>
|
||||
<filter string="Version" icon="terp-stock_symbol-selection" domain="[]" context="{'group_by':'version_id'}"/>
|
||||
<filter string="Priority" icon="terp-rating-rated" domain="[]" context="{'group_by':'priority'}" />
|
||||
<filter string="Stage" icon="terp-stage" domain="[]" context="{'group_by':'stage_id'}"/>
|
||||
<filter string="Company" icon="terp-go-home" domain="[]" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>
|
||||
<filter string="Day" icon="terp-go-today" domain="[]" context="{'group_by':'day'}" help="Creation Date"/>
|
||||
<filter string="Month" icon="terp-go-month" domain="[]" context="{'group_by':'month'}" help="Creation Date"/>
|
||||
<filter string="Year" icon="terp-go-year" domain="[]" context="{'group_by':'name'}" help="Creation Date"/>
|
||||
<filter string="Last Stage Update" context="{'group_by':'date_last_stage_update'}"/>
|
||||
</group>
|
||||
<separator/>
|
||||
<filter string="New" name="new" domain="[('stage_id.sequence', '<=', 1)]"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -41,8 +41,8 @@
|
||||
<field name="model">project.project</field>
|
||||
<field name="inherit_id" ref="project.view_project_project_filter"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr='//filter[@string="Project(s) Manager"]' position='after'>
|
||||
<filter icon="terp-camera_test" string="Billable" domain="[('to_invoice','!=', False)]" help="Billable Project"/>
|
||||
<xpath expr='//filter[@string="Template"]' position='after'>
|
||||
<filter string="Billable" domain="[('to_invoice','!=', False)]"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -305,18 +305,16 @@
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Purchase Order">
|
||||
<field name="name" string="Reference"/>
|
||||
<filter icon="terp-document-new" name="draft" string="Quotations" domain="[('state','=','draft')]" help="Purchase order which are in draft state"/>
|
||||
<filter icon="terp-check" name="approved" string="Approved" domain="[('state','in',('approved','done'))]" help="Approved purchase order"/>
|
||||
<filter icon="terp-emblem-important" name="exception" string="Exception" domain="[('state','in',('except_invoice','except_picking'))]" help="Purchase order which are in the exception state"/>
|
||||
<separator/>
|
||||
<filter icon="terp-gtk-go-back-rtl" name="not_invoiced" string="Not Invoiced" domain="[('invoice_ids','=', False)]" help="Purchase orders that include lines not invoiced."/>
|
||||
<field name="partner_id" operator="child_of"/>
|
||||
<field name="product_id"/>
|
||||
<field name="create_uid"/>
|
||||
<filter name="draft" string="Quotations" domain="[('state','=','draft')]"/>
|
||||
<filter name="approved" string="Approved" domain="[('state','in',('approved','done'))]"/>
|
||||
<filter name="exception" string="Exception" domain="[('state','in',('except_invoice','except_picking'))]"/>
|
||||
<separator/>
|
||||
<filter name="not_invoiced" string="Not Invoiced" domain="[('invoice_ids','=', False)]" help="Purchase orders that include lines not invoiced."/>
|
||||
<group expand="0" string="Group By">
|
||||
<filter string="Supplier" icon="terp-partner" domain="[]" context="{'group_by':'partner_id'}"/>
|
||||
<filter string="Source" icon="terp-gtk-jump-to-rtl" domain="[]" context="{'group_by':'origin'}"/>
|
||||
<filter string="Status" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'state'}"/>
|
||||
<filter string="Order Date" icon="terp-go-month" domain="[]" context="{'group_by':'date_order'}"/>
|
||||
<filter string="Expected Date" icon="terp-go-month" domain="[]" context="{'group_by':'minimum_planned_date'}"/>
|
||||
</group>
|
||||
@@ -330,20 +328,18 @@
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Purchase Order">
|
||||
<field name="name" string="Reference"/>
|
||||
<filter icon="terp-mail-message-new" string="Unread Messages" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<separator/>
|
||||
<filter icon="terp-document-new" name="draft" string="Quotations" domain="[('state','in',('draft','sent'))]" help="Purchase orders that haven't yet been confirmed"/>
|
||||
<filter icon="terp-check" name="approved" string="Purchase Orders" domain="[('state','not in',('draft','cancel'))]" help="Approved purchase orders"/>
|
||||
<filter icon="terp-emblem-important" name="exception" string="Exception" domain="[('state','in',('except_invoice','except_picking'))]" help="Purchase orders which are in exception state"/>
|
||||
<separator/>
|
||||
<filter icon="terp-gtk-go-back-rtl" name="not_invoiced" string="Not Invoiced" domain="[('invoice_ids','=', False)]" help="Purchase orders that include lines not invoiced."/>
|
||||
<field name="partner_id" operator="child_of"/>
|
||||
<field name="product_id"/>
|
||||
<field name="create_uid"/>
|
||||
<filter name="draft" string="Quotations" domain="[('state','in',('draft','sent'))]"/>
|
||||
<filter name="approved" string="Purchase Orders" domain="[('state','not in',('draft','cancel'))]"/>
|
||||
<filter name="exception" string="Exception" domain="[('state','in',('except_invoice','except_picking'))]"/>
|
||||
<separator/>
|
||||
<filter name="not_invoiced" string="Not Invoiced" domain="[('invoice_ids','=', False)]"/>
|
||||
<separator/>
|
||||
<filter string="New Mail" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<group expand="0" string="Group By">
|
||||
<filter string="Supplier" icon="terp-partner" domain="[]" context="{'group_by':'partner_id'}"/>
|
||||
<filter string="Source" icon="terp-gtk-jump-to-rtl" domain="[]" context="{'group_by':'origin'}"/>
|
||||
<filter string="Status" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'state'}"/>
|
||||
<filter string="Order Month" icon="terp-go-month" domain="[]" context="{'group_by':'date_order'}"/>
|
||||
<filter string="Expected Month" icon="terp-go-month" domain="[]" context="{'group_by':'minimum_planned_date'}"/>
|
||||
</group>
|
||||
|
||||
@@ -36,22 +36,6 @@
|
||||
<field name="date_approve"/>
|
||||
<field name="expected_date"/>
|
||||
</group>
|
||||
<newline/>
|
||||
<group expand="1" string="Group By">
|
||||
<filter string="Supplier" name="group_partner_id" icon="terp-personal" context="{'group_by':'partner_id'}"/>
|
||||
<filter string="Responsible" name="Responsible" icon="terp-personal" context="{'group_by':'user_id'}"/>
|
||||
<filter string="Validated by" icon="terp-personal" context="{'group_by':'validator'}"/>
|
||||
<filter string="Product" name="group_product_id" icon="terp-accessories-archiver" context="{'group_by':'product_id'}"/>
|
||||
<filter string="Category" name="group_category_id" icon="terp-stock_symbol-selection" context="{'group_by':'category_id'}"/>
|
||||
<filter string="Warehouse" icon="terp-go-home" context="{'group_by':'picking_type_id'}"/>
|
||||
<filter string="Reference UOM" name="group_product_uom" icon="terp-mrp" context="{'group_by':'product_uom'}"/>
|
||||
<filter string="Destination" icon="terp-gtk-jump-to-ltr" context="{'group_by':'location_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"/>
|
||||
<filter string="Order Date (day)" icon="terp-go-today" context="{'group_by':'date:day'}" help="Order of Day"/>
|
||||
<filter string="Order Date (month)" icon="terp-go-month" context="{'group_by':'date:month'}" help="Order of Day"/>
|
||||
<filter string="Order Date (year)" icon="terp-go-year" context="{'group_by':'date:year'}" help="Order of Day"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -14,6 +14,29 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Custom reports (aka filters) -->
|
||||
<record id="filter_sale_report_salespersons" model="ir.filters">
|
||||
<field name="name">By Salespersons</field>
|
||||
<field name="model_id">sale.report</field>
|
||||
<field name="domain">[]</field>
|
||||
<field name="user_id" eval="False"/>
|
||||
<field name="context">{'group_by': ['date:month', 'user_id']}</field>
|
||||
</record>
|
||||
<record id="filter_sale_report_salesteam" model="ir.filters">
|
||||
<field name="name">By Salesteam</field>
|
||||
<field name="model_id">sale.report</field>
|
||||
<field name="domain">[]</field>
|
||||
<field name="user_id" eval="False"/>
|
||||
<field name="context">{'group_by': ['date:month', 'section_id']}</field>
|
||||
</record>
|
||||
<record id="filter_isale_report_product" model="ir.filters">
|
||||
<field name="name">By Product</field>
|
||||
<field name="model_id">sale.report</field>
|
||||
<field name="domain">[]</field>
|
||||
<field name="user_id" eval="False"/>
|
||||
<field name="context">{'group_by': ['date:month', 'product_id']}</field>
|
||||
</record>
|
||||
|
||||
<record id="view_order_product_search" model="ir.ui.view">
|
||||
<field name="name">sale.report.search</field>
|
||||
<field name="model">sale.report</field>
|
||||
@@ -21,10 +44,12 @@
|
||||
<search string="Sales Analysis">
|
||||
<field name="date"/>
|
||||
<field name="date_confirm"/>
|
||||
<filter icon="terp-document-new" name="Quotations" domain="[('state','in',('draft','sent'))]"/>
|
||||
<filter icon="terp-check" name="Sales" string="Sales" domain="[('state','not in',('draft','sent','cancel'))]"/>
|
||||
<filter string="This Year" name="year" domain="[('date','<=', time.strftime('%%Y-12-31')),('date','>=',time.strftime('%%Y-01-01'))]"/>
|
||||
<separator/>
|
||||
<filter icon="terp-personal" string="My Sales" help="My Sales" domain="[('user_id','=',uid)]"/>
|
||||
<filter name="Quotations" domain="[('state','in',('draft','sent'))]"/>
|
||||
<filter name="Sales" string="Sales" domain="[('state','not in',('draft','sent','cancel'))]"/>
|
||||
<separator/>
|
||||
<filter string="My Sales" help="My Sales" domain="[('user_id','=',uid)]"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="product_id"/>
|
||||
<field name="user_id"/>
|
||||
@@ -32,20 +57,6 @@
|
||||
<field name="categ_id"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
<group expand="1" string="Group By">
|
||||
<filter string="Salesperson" icon="terp-personal" name="User" context="{'group_by':'user_id'}"/>
|
||||
<filter string="Sales Team" context="{'group_by':'section_id'}" groups="base.group_multi_salesteams"/>
|
||||
<filter string="Partner" icon="terp-partner" name="Customer" context="{'group_by':'partner_id'}"/>
|
||||
<filter string="Product" icon="terp-accessories-archiver" context="{'group_by':'product_id','set_visible':True}"/>
|
||||
<filter string="Reference Unit of Measure" icon="terp-mrp" context="{'group_by':'product_uom'}"/>
|
||||
<filter string="Category of Product" icon="terp-stock_symbol-selection" name="Category" context="{'group_by':'categ_id'}"/>
|
||||
<filter string="Analytic Account" icon="terp-folder-green" context="{'group_by':'analytic_account_id'}" groups="analytic.group_analytic_accounting"/>
|
||||
<filter string="Status" icon="terp-stock_effects-object-colorize" context="{'group_by':'state'}"/>
|
||||
<filter string="Company" icon="terp-go-home" groups="base.group_multi_company" context="{'group_by':'company_id'}"/>
|
||||
<filter string="Order Date (day)" icon="terp-go-today" context="{'group_by':'date:day'}" help="Ordered date of the sales order"/>
|
||||
<filter string="Order Date (month)" icon="terp-go-today" context="{'group_by':'date:month'}" help="Ordered date of the sales order"/>
|
||||
<filter string="Order Date (year)" icon="terp-go-today" context="{'group_by':'date:year'}" help="Ordered date of the sales order"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
@@ -57,7 +68,7 @@
|
||||
<field name="view_mode">graph</field>
|
||||
<field name="search_view_id" ref="view_order_product_search"/>
|
||||
<field name="view_id" ref="view_order_product_graph"/>
|
||||
<field name="context">{'search_default_Sales':1, 'group_by_no_leaf':1,'group_by':[]}</field>
|
||||
<field name="context">{'search_default_Sales':1, 'search_default_year': 1, 'group_by_no_leaf':1,'group_by':[]}</field>
|
||||
<field name="help">This report performs analysis on your quotations and sales orders. Analysis check your sales revenues and sort it by different group criteria (salesman, partner, product, etc.) Use this report to perform analysis on sales not having invoiced yet. If you want to analyse your turnover, you should use the Invoice Analysis report in the Accounting application.</field>
|
||||
</record>
|
||||
|
||||
|
||||
+11
-13
@@ -246,24 +246,22 @@
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Sales Order">
|
||||
<field name="name" string="Sales Order" filter_domain="['|',('name','ilike',self),('client_order_ref','ilike',self)]"/>
|
||||
<filter icon="terp-mail-message-new" string="Unread Messages" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<separator/>
|
||||
<filter icon="terp-document-new" string="Quotations" name="draft" domain="[('state','in',('draft','sent'))]" help="Sales Order that haven't yet been confirmed"/>
|
||||
<filter icon="terp-check" string="Sales" name="sales" domain="[('state','in',('manual','progress'))]"/>
|
||||
<filter icon="terp-dolar_ok!" string="To Invoice" domain="[('state','=','manual')]" help="Sales Order ready to be invoiced"/>
|
||||
<filter icon="terp-dolar_ok!" string="Done" domain="[('state','=','done')]" help="Sales Order done"/>
|
||||
<separator/>
|
||||
<filter string="My" domain="[('user_id','=',uid)]" help="My Sales Orders" icon="terp-personal" name="my_sale_orders_filter"/>
|
||||
<field name="partner_id" operator="child_of"/>
|
||||
<field name="user_id"/>
|
||||
<field name="section_id" string="Sales Team" groups="base.group_multi_salesteams"/>
|
||||
<field name="project_id"/>
|
||||
<filter string="My" domain="[('user_id','=',uid)]" name="my_sale_orders_filter"/>
|
||||
<separator/>
|
||||
<filter string="Quotations" name="draft" domain="[('state','in',('draft','sent'))]" help="Sales Order that haven't yet been confirmed"/>
|
||||
<filter string="Sales" name="sales" domain="[('state','in',('manual','progress'))]"/>
|
||||
<filter string="To Invoice" domain="[('state','=','manual')]" help="Sales Order ready to be invoiced"/>
|
||||
<filter string="Done" domain="[('state','=','done')]" help="Sales Order done"/>
|
||||
<separator/>
|
||||
<filter string="New Mail" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<group expand="0" string="Group By">
|
||||
<filter string="Customer" icon="terp-personal" domain="[]" context="{'group_by':'partner_id'}"/>
|
||||
<filter string="Salesperson" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>
|
||||
<filter string="Status" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'state'}"/>
|
||||
<filter string="Order Month" icon="terp-go-month" domain="[]" context="{'group_by':'date_order'}"/>
|
||||
<filter string="My Sales Team(s)" icon="terp-personal+" domain="[('section_id.user_id','=',uid)]" help="My Sales Team(s)" groups="base.group_multi_salesteams"/>
|
||||
<filter string="Salesperson" domain="[]" context="{'group_by':'user_id'}"/>
|
||||
<filter string="Customer" domain="[]" context="{'group_by':'partner_id'}"/>
|
||||
<filter string="Order Month" domain="[]" context="{'group_by':'date_order'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
<separator/>
|
||||
<filter icon="terp-accessories-archiver" string="Picked" domain="[('shipped','=',True)]"/>
|
||||
</filter>
|
||||
<xpath expr="//group/filter[@string='Status']" position="after">
|
||||
<filter string="Warehouse" context="{'group_by':'warehouse_id'}"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
|
||||
@@ -49,6 +49,9 @@ else:
|
||||
env = jinja2.Environment(loader=loader, autoescape=True)
|
||||
env.filters["json"] = simplejson.dumps
|
||||
|
||||
# 1 week cache for asset bundles as advised by Google Page Speed
|
||||
BUNDLE_MAXAGE = 60 * 60 * 24 * 7
|
||||
|
||||
#----------------------------------------------------------
|
||||
# OpenERP Web helpers
|
||||
#----------------------------------------------------------
|
||||
@@ -551,37 +554,31 @@ class Home(http.Controller):
|
||||
def login(self, db, login, key, redirect="/web", **kw):
|
||||
return login_and_redirect(db, login, key, redirect_url=redirect)
|
||||
|
||||
@http.route('/web/js/<xmlid>', type='http', auth="public")
|
||||
def js_bundle(self, xmlid, **kw):
|
||||
# manifest backward compatible mode, to be removed
|
||||
values = {'manifest_list': manifest_list}
|
||||
@http.route([
|
||||
'/web/js/<xmlid>',
|
||||
'/web/js/<xmlid>/<version>',
|
||||
], type='http', auth='public')
|
||||
def js_bundle(self, xmlid, version=None, **kw):
|
||||
try:
|
||||
assets_html = request.render(xmlid, lazy=False, qcontext=values)
|
||||
bundle = AssetsBundle(xmlid)
|
||||
except QWebTemplateNotFound:
|
||||
return request.not_found()
|
||||
bundle = AssetsBundle(xmlid, assets_html, debug=request.debug)
|
||||
|
||||
response = request.make_response(
|
||||
bundle.js(), [('Content-Type', 'application/javascript')])
|
||||
response = request.make_response(bundle.js(), [('Content-Type', 'application/javascript')])
|
||||
return make_conditional(response, bundle.last_modified, max_age=BUNDLE_MAXAGE)
|
||||
|
||||
# TODO: check that we don't do weird lazy overriding of __call__ which break body-removal
|
||||
return make_conditional(
|
||||
response, bundle.last_modified, bundle.checksum, max_age=60*60*24)
|
||||
|
||||
@http.route('/web/css/<xmlid>', type='http', auth='public')
|
||||
def css_bundle(self, xmlid, **kw):
|
||||
values = {'manifest_list': manifest_list} # manifest backward compatible mode, to be removed
|
||||
@http.route([
|
||||
'/web/css/<xmlid>',
|
||||
'/web/css/<xmlid>/<version>',
|
||||
], type='http', auth='public')
|
||||
def css_bundle(self, xmlid, version=None, **kw):
|
||||
try:
|
||||
assets_html = request.render(xmlid, lazy=False, qcontext=values)
|
||||
bundle = AssetsBundle(xmlid)
|
||||
except QWebTemplateNotFound:
|
||||
return request.not_found()
|
||||
bundle = AssetsBundle(xmlid, assets_html, debug=request.debug)
|
||||
|
||||
response = request.make_response(
|
||||
bundle.css(), [('Content-Type', 'text/css')])
|
||||
|
||||
return make_conditional(
|
||||
response, bundle.last_modified, bundle.checksum, max_age=60*60*24)
|
||||
response = request.make_response(bundle.css(), [('Content-Type', 'text/css')])
|
||||
return make_conditional(response, bundle.last_modified, max_age=BUNDLE_MAXAGE)
|
||||
|
||||
class WebClient(http.Controller):
|
||||
|
||||
|
||||
@@ -75,15 +75,22 @@ var Tour = {
|
||||
if (!tour) {
|
||||
Tour.error(null, "Can't run '"+tour_id+"' (tour undefined)");
|
||||
}
|
||||
console.log("Tour '"+tour_id+"' Begin from run method");
|
||||
var state = Tour.getState();
|
||||
if (state) {
|
||||
if (state.mode === "test") {
|
||||
Tour.error(false, "An other running tour has been detected all tours are now killed.");
|
||||
} else {
|
||||
Tour.endTour();
|
||||
}
|
||||
}
|
||||
this.time = new Date().getTime();
|
||||
if (tour.path && !window.location.href.match(new RegExp("("+Tour.getLang()+")?"+tour.path+"#?$", "i"))) {
|
||||
var href = Tour.getLang()+tour.path;
|
||||
console.log("Tour '"+tour_id+"' Begin from run method (redirection to "+href+")");
|
||||
Tour.saveState(tour.id, mode || tour.mode, -1, 0);
|
||||
$(document).one("ajaxStop", Tour.running);
|
||||
window.location.href = href;
|
||||
} else {
|
||||
console.log("Tour '"+tour_id+"' Begin from run method");
|
||||
Tour.saveState(tour.id, mode || tour.mode, 0, 0);
|
||||
Tour.running();
|
||||
}
|
||||
@@ -358,6 +365,7 @@ var Tour = {
|
||||
clearTimeout(Tour.timer);
|
||||
clearTimeout(Tour.testtimer);
|
||||
Tour.closePopover();
|
||||
console.log("Tour reset");
|
||||
},
|
||||
running: function () {
|
||||
var state = Tour.getState();
|
||||
@@ -398,6 +406,8 @@ var Tour = {
|
||||
};
|
||||
|
||||
function checkNext () {
|
||||
if (!Tour.getState()) return;
|
||||
|
||||
Tour.autoTogglePopover();
|
||||
|
||||
clearTimeout(Tour.timer);
|
||||
@@ -476,6 +486,8 @@ var Tour = {
|
||||
clearTimeout(Tour.testtimer);
|
||||
|
||||
function autoStep () {
|
||||
if (!Tour.getState()) return;
|
||||
|
||||
if (!step) return;
|
||||
|
||||
if (step.autoComplete) {
|
||||
@@ -502,6 +514,7 @@ var Tour = {
|
||||
|
||||
// trigger after for step like: mouseenter, next step click on button display with mouseenter
|
||||
setTimeout(function () {
|
||||
if (!Tour.getState()) return;
|
||||
$element.trigger($.Event("mouseup", { srcElement: $element[0] }));
|
||||
$element.trigger($.Event("mouseleave", { srcElement: $element[0] }));
|
||||
}, 1000);
|
||||
@@ -518,6 +531,7 @@ var Tour = {
|
||||
$element.html(step.sampleText);
|
||||
}
|
||||
setTimeout(function () {
|
||||
if (!Tour.getState()) return;
|
||||
$element.trigger($.Event("keyup", { srcElement: $element }));
|
||||
$element.trigger($.Event("change", { srcElement: $element }));
|
||||
}, self.defaultDelay<<1);
|
||||
|
||||
@@ -23,9 +23,6 @@
|
||||
<script type="text/javascript" src="/web/static/lib/qweb/qweb2.js"></script>
|
||||
<script type="text/javascript" src="/web/static/src/js/openerpframework.js"></script>
|
||||
<script type="text/javascript" src="/web/static/src/js/tour.js"></script>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
openerp._modules = <t t-raw="modules"/>;
|
||||
</script>
|
||||
|
||||
<link rel="stylesheet" href="/web/static/lib/fontawesome/css/font-awesome.css"/>
|
||||
</template>
|
||||
@@ -85,6 +82,9 @@
|
||||
<script type="text/javascript" src="/web/static/lib/backbone/backbone.js"></script>
|
||||
|
||||
<!-- Internals -->
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
openerp._modules = <t t-raw="get_modules_order()"/>;
|
||||
</script>
|
||||
<link rel="stylesheet" href="/web/static/src/css/base.css"/>
|
||||
<link rel="stylesheet" href="/web/static/src/css/data_export.css"/>
|
||||
<link rel="stylesheet" href="/base/static/src/css/modules.css"/>
|
||||
|
||||
@@ -11,6 +11,6 @@ class TestUi(openerp.tests.HttpCase):
|
||||
def test_03_js_public(self):
|
||||
self.phantom_js('/',"console.log('ok')","console")
|
||||
def test_04_js_admin(self):
|
||||
self.phantom_js('/web',"console.log('ok')","openerp.client.action_manager.inner_widget.views.form", login='admin')
|
||||
self.phantom_js('/web',"console.log('ok')","openerp.client.action_manager.inner_widget", login='admin')
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -12,7 +12,6 @@ window.openerp.website.EditorBar.include({
|
||||
}
|
||||
var $menuItem = $($.parseHTML('<li><a href="#">'+tour.name+'</a></li>'));
|
||||
$menuItem.click(function () {
|
||||
openerp.Tour.reset();
|
||||
openerp.Tour.run(tour.id);
|
||||
});
|
||||
menu.append($menuItem);
|
||||
|
||||
@@ -278,6 +278,7 @@ class Post(osv.Model):
|
||||
'closed_date': fields.datetime('Closed on', readonly=True),
|
||||
# karma
|
||||
'karma_ask': fields.function(_get_post_karma_rights, string='Karma to ask', type='integer', multi='_get_post_karma_rights'),
|
||||
'karma_answer': fields.function(_get_post_karma_rights, string='Karma to answer', type='integer', multi='_get_post_karma_rights'),
|
||||
'karma_accept': fields.function(_get_post_karma_rights, string='Karma to accept this answer', type='integer', multi='_get_post_karma_rights'),
|
||||
'karma_edit': fields.function(_get_post_karma_rights, string='Karma to edit', type='integer', multi='_get_post_karma_rights'),
|
||||
'karma_close': fields.function(_get_post_karma_rights, string='Karma to close', type='integer', multi='_get_post_karma_rights'),
|
||||
@@ -288,6 +289,7 @@ class Post(osv.Model):
|
||||
'karma_comment_convert': fields.function(_get_post_karma_rights, string='karma to convert as a comment', type='integer', multi='_get_post_karma_rights'),
|
||||
# access rights
|
||||
'can_ask': fields.function(_get_post_karma_rights, string='Can Ask', type='boolean', multi='_get_post_karma_rights'),
|
||||
'can_answer': fields.function(_get_post_karma_rights, string='Can Answer', type='boolean', multi='_get_post_karma_rights'),
|
||||
'can_accept': fields.function(_get_post_karma_rights, string='Can Accept', type='boolean', multi='_get_post_karma_rights'),
|
||||
'can_edit': fields.function(_get_post_karma_rights, string='Can Edit', type='boolean', multi='_get_post_karma_rights'),
|
||||
'can_close': fields.function(_get_post_karma_rights, string='Can Close', type='boolean', multi='_get_post_karma_rights'),
|
||||
|
||||
@@ -592,9 +592,12 @@
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a t-attf-class="fa fa-edit #{not answer.can_edit and 'karma_required text-muted' or ''}"
|
||||
t-attf-data-karma="#{not answer.can_edit and answer.karma_edit or 0}"
|
||||
t-attf-href="/forum/#{slug(forum)}/post/#{slug(answer)}/edit"> Edit</a>
|
||||
<t t-call="website_forum.link_button">
|
||||
<t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(answer) + '/edit'"/>
|
||||
<t t-set="label" t-value="'Edit'"/>
|
||||
<t t-set="classes" t-value="'fa fa-edit'"/>
|
||||
<t t-set="karma" t-value="not answer.can_edit and answer.karma_edit or 0"/>
|
||||
</t>
|
||||
</li>
|
||||
<li>
|
||||
<t t-call="website_forum.link_button">
|
||||
|
||||
@@ -9,9 +9,13 @@ import math
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import textwrap
|
||||
import uuid
|
||||
import xml # FIXME use lxml and etree
|
||||
import itertools
|
||||
import lxml.html
|
||||
import werkzeug
|
||||
from subprocess import Popen, PIPE
|
||||
from urlparse import urlparse
|
||||
|
||||
import babel
|
||||
@@ -20,14 +24,13 @@ from PIL import Image
|
||||
|
||||
import openerp.http
|
||||
import openerp.tools
|
||||
import openerp.tools.func
|
||||
from openerp.tools.func import lazy_property
|
||||
import openerp.tools.lru
|
||||
from openerp.http import request
|
||||
from openerp.tools.safe_eval import safe_eval as eval
|
||||
from openerp.osv import osv, orm, fields
|
||||
from openerp.tools import html_escape as escape
|
||||
from openerp.tools.translate import _
|
||||
from openerp import SUPERUSER_ID
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -414,16 +417,15 @@ class QWeb(orm.AbstractModel):
|
||||
|
||||
def render_tag_call_assets(self, element, template_attributes, generated_attributes, qwebcontext):
|
||||
""" This special 't-call' tag can be used in order to aggregate/minify javascript and css assets"""
|
||||
name = template_attributes['call-assets']
|
||||
|
||||
# Backward compatibility hack for manifest usage
|
||||
qwebcontext['manifest_list'] = openerp.addons.web.controllers.main.manifest_list
|
||||
|
||||
d = qwebcontext.copy()
|
||||
d.context['inherit_branding'] = False
|
||||
content = self.render_tag_call(
|
||||
element, {'call': name}, generated_attributes, d)
|
||||
bundle = AssetsBundle(name, html=content)
|
||||
if element.childNodes:
|
||||
# An asset bundle is rendered in two differents contexts (when genereting html and
|
||||
# when generating the bundle itself) so they must be qwebcontext free
|
||||
# even '0' variable is forbidden
|
||||
template = qwebcontext.get('__template__')
|
||||
raise QWebException("t-call-assets cannot contain children nodes", template=template)
|
||||
xmlid = template_attributes['call-assets']
|
||||
cr, uid, context = [getattr(qwebcontext, attr) for attr in ('cr', 'uid', 'context')]
|
||||
bundle = AssetsBundle(xmlid, cr=cr, uid=uid, context=context, registry=self.pool)
|
||||
css = self.get_attr_bool(template_attributes.get('css'), default=True)
|
||||
js = self.get_attr_bool(template_attributes.get('js'), default=True)
|
||||
return bundle.to_html(css=css, js=js, debug=bool(qwebcontext.get('debug')))
|
||||
@@ -999,36 +1001,67 @@ def get_field_type(column, options):
|
||||
"""
|
||||
return options.get('widget', column._type)
|
||||
|
||||
class AssetError(Exception):
|
||||
pass
|
||||
class AssetNotFound(AssetError):
|
||||
pass
|
||||
|
||||
class AssetsBundle(object):
|
||||
# Sass installation:
|
||||
#
|
||||
# sudo gem install sass compass bootstrap-sass
|
||||
#
|
||||
# If the following error is encountered:
|
||||
# 'ERROR: Cannot load compass.'
|
||||
# Use this:
|
||||
# sudo gem install compass --pre
|
||||
cmd_sass = ['sass', '--stdin', '-t', 'compressed', '--unix-newlines', '--compass', '-r', 'bootstrap-sass']
|
||||
cache = openerp.tools.lru.LRU(32)
|
||||
rx_css_import = re.compile("(@import[^;{]+;?)", re.M)
|
||||
rx_sass_import = re.compile("""(@import\s?['"]([^'"]+)['"])""")
|
||||
rx_css_split = re.compile("\/\*\! ([a-f0-9-]+) \*\/")
|
||||
|
||||
def __init__(self, xmlid, html=None, debug=False):
|
||||
self.debug = debug
|
||||
def __init__(self, xmlid, debug=False, cr=None, uid=None, context=None, registry=None):
|
||||
self.xmlid = xmlid
|
||||
self.cr = request.cr if cr is None else cr
|
||||
self.uid = request.uid if uid is None else uid
|
||||
self.context = request.context if context is None else context
|
||||
self.registry = request.registry if registry is None else registry
|
||||
self.javascripts = []
|
||||
self.stylesheets = []
|
||||
self.css_errors = []
|
||||
self.remains = []
|
||||
self._checksum = None
|
||||
if html:
|
||||
self.parse(html)
|
||||
|
||||
def parse(self, html):
|
||||
fragments = lxml.html.fragments_fromstring(html)
|
||||
context = self.context.copy()
|
||||
context['inherit_branding'] = False
|
||||
self.html = self.registry['ir.ui.view'].render(self.cr, self.uid, xmlid, context=context)
|
||||
self.parse()
|
||||
|
||||
def parse(self):
|
||||
fragments = lxml.html.fragments_fromstring(self.html)
|
||||
for el in fragments:
|
||||
if isinstance(el, basestring):
|
||||
self.remains.append(el)
|
||||
elif isinstance(el, lxml.html.HtmlElement):
|
||||
src = el.get('src')
|
||||
href = el.get('href')
|
||||
src = el.get('src', '')
|
||||
href = el.get('href', '')
|
||||
atype = el.get('type')
|
||||
media = el.get('media')
|
||||
if el.tag == 'style':
|
||||
self.stylesheets.append(StylesheetAsset(source=el.text))
|
||||
if atype == 'text/sass' or src.endswith('.sass'):
|
||||
self.stylesheets.append(SassAsset(self, inline=el.text, media=media))
|
||||
else:
|
||||
self.stylesheets.append(StylesheetAsset(self, inline=el.text, media=media))
|
||||
elif el.tag == 'link' and el.get('rel') == 'stylesheet' and self.can_aggregate(href):
|
||||
self.stylesheets.append(StylesheetAsset(url=href))
|
||||
if href.endswith('.sass') or atype == 'text/sass':
|
||||
self.stylesheets.append(SassAsset(self, url=href, media=media))
|
||||
else:
|
||||
self.stylesheets.append(StylesheetAsset(self, url=href, media=media))
|
||||
elif el.tag == 'script' and not src:
|
||||
self.javascripts.append(JavascriptAsset(source=el.text))
|
||||
self.javascripts.append(JavascriptAsset(self, inline=el.text))
|
||||
elif el.tag == 'script' and self.can_aggregate(src):
|
||||
self.javascripts.append(JavascriptAsset(url=src))
|
||||
self.javascripts.append(JavascriptAsset(self, url=src))
|
||||
else:
|
||||
self.remains.append(lxml.html.tostring(el))
|
||||
else:
|
||||
@@ -1041,10 +1074,13 @@ class AssetsBundle(object):
|
||||
def can_aggregate(self, url):
|
||||
return not urlparse(url).netloc and not url.startswith(('/web/css', '/web/js'))
|
||||
|
||||
def to_html(self, sep='\n ', css=True, js=True, debug=False):
|
||||
def to_html(self, sep=None, css=True, js=True, debug=False):
|
||||
if sep is None:
|
||||
sep = '\n '
|
||||
response = []
|
||||
if debug:
|
||||
if css:
|
||||
if css and self.stylesheets:
|
||||
self.compile_sass()
|
||||
for style in self.stylesheets:
|
||||
response.append(style.to_html())
|
||||
if js:
|
||||
@@ -1052,41 +1088,56 @@ class AssetsBundle(object):
|
||||
response.append(jscript.to_html())
|
||||
else:
|
||||
if css and self.stylesheets:
|
||||
response.append('<link href="/web/css/%s" rel="stylesheet"/>' % self.xmlid)
|
||||
if js and self.javascripts:
|
||||
response.append('<script type="text/javascript" src="/web/js/%s"></script>' % self.xmlid)
|
||||
response.append('<link href="/web/css/%s/%s" rel="stylesheet"/>' % (self.xmlid, self.version))
|
||||
if js:
|
||||
response.append('<script type="text/javascript" src="/web/js/%s/%s"></script>' % (self.xmlid, self.version))
|
||||
response.extend(self.remains)
|
||||
return sep + sep.join(response)
|
||||
|
||||
@openerp.tools.func.lazy_property
|
||||
@lazy_property
|
||||
def last_modified(self):
|
||||
"""Returns last modified date of linked files"""
|
||||
return max(itertools.chain(
|
||||
(asset.last_modified for asset in self.javascripts),
|
||||
(asset.last_modified for asset in self.stylesheets),
|
||||
[datetime.datetime(1970, 1, 1)],
|
||||
))
|
||||
|
||||
@openerp.tools.func.lazy_property
|
||||
@lazy_property
|
||||
def version(self):
|
||||
return self.checksum[0:7]
|
||||
|
||||
@lazy_property
|
||||
def checksum(self):
|
||||
checksum = hashlib.new('sha1')
|
||||
for asset in itertools.chain(self.javascripts, self.stylesheets):
|
||||
checksum.update(asset.content.encode("utf-8"))
|
||||
return checksum.hexdigest()
|
||||
"""
|
||||
Not really a full checksum.
|
||||
We compute a SHA1 on the rendered bundle + max linked files last_modified date
|
||||
"""
|
||||
check = self.html + str(self.last_modified)
|
||||
return hashlib.sha1(check).hexdigest()
|
||||
|
||||
def js(self):
|
||||
key = 'js_' + self.checksum
|
||||
key = 'js_%s' % self.xmlid
|
||||
if key in self.cache and self.cache[key][0] != self.version:
|
||||
# Invalidate cache on version mismach
|
||||
self.cache.pop(key)
|
||||
if key not in self.cache:
|
||||
content =';\n'.join(asset.minify() for asset in self.javascripts)
|
||||
self.cache[key] = content
|
||||
if self.debug:
|
||||
return "/*\n%s\n*/\n" % '\n'.join(
|
||||
[asset.url for asset in self.javascripts if asset.url]) + self.cache[key]
|
||||
return self.cache[key]
|
||||
self.cache[key] = (self.version, content)
|
||||
return self.cache[key][1]
|
||||
|
||||
def css(self):
|
||||
key = 'css_' + self.checksum
|
||||
key = 'css_%s' % self.xmlid
|
||||
if key in self.cache and self.cache[key][0] != self.version:
|
||||
# Invalidate cache on version mismach
|
||||
self.cache.pop(key)
|
||||
if key not in self.cache:
|
||||
self.compile_sass()
|
||||
content = '\n'.join(asset.minify() for asset in self.stylesheets)
|
||||
|
||||
if self.css_errors:
|
||||
msg = '\n'.join(self.css_errors)
|
||||
content += self.css_message(msg.replace('\n', '\\A '))
|
||||
|
||||
# move up all @import rules to the top
|
||||
matches = []
|
||||
def push(matchobj):
|
||||
@@ -1097,89 +1148,200 @@ class AssetsBundle(object):
|
||||
|
||||
matches.append(content)
|
||||
content = u'\n'.join(matches)
|
||||
self.cache[key] = content
|
||||
if self.debug:
|
||||
return "/*\n%s\n*/\n" % '\n'.join(
|
||||
[asset.url for asset in self.javascripts if asset.url]) + self.cache[key]
|
||||
return self.cache[key]
|
||||
if self.css_errors:
|
||||
return content
|
||||
self.cache[key] = (self.version, content)
|
||||
|
||||
return self.cache[key][1]
|
||||
|
||||
def css_message(self, message):
|
||||
return """
|
||||
body:before {
|
||||
background: #ffc;
|
||||
width: 100%%;
|
||||
font-size: 14px;
|
||||
font-family: monospace;
|
||||
white-space: pre;
|
||||
content: "%s";
|
||||
}
|
||||
""" % message.replace('"', '\\"')
|
||||
|
||||
def compile_sass(self):
|
||||
"""
|
||||
Checks if the bundle contains any sass content, then compiles it to css.
|
||||
Css compilation is done at the bundle level and not in the assets
|
||||
because they are potentially interdependant.
|
||||
"""
|
||||
sass = [asset for asset in self.stylesheets if isinstance(asset, SassAsset)]
|
||||
if not sass:
|
||||
return
|
||||
source = '\n'.join([asset.get_source() for asset in sass])
|
||||
|
||||
# move up all @import rules to the top and exclude file imports
|
||||
imports = []
|
||||
def push(matchobj):
|
||||
ref = matchobj.group(2)
|
||||
line = '@import "%s"' % ref
|
||||
if '.' not in ref and line not in imports and not ref.startswith(('.', '/', '~')):
|
||||
imports.append(line)
|
||||
return ''
|
||||
source = re.sub(self.rx_sass_import, push, source)
|
||||
imports.append(source)
|
||||
source = u'\n'.join(imports)
|
||||
|
||||
try:
|
||||
compiler = Popen(self.cmd_sass, stdin=PIPE, stdout=PIPE, stderr=PIPE)
|
||||
except Exception:
|
||||
msg = "Could not find 'sass' program needed to compile sass/scss files"
|
||||
_logger.error(msg)
|
||||
self.css_errors.append(msg)
|
||||
return
|
||||
result = compiler.communicate(input=source.encode('utf-8'))
|
||||
if compiler.returncode:
|
||||
error = self.get_sass_error(result[1], source=source)
|
||||
_logger.warning(error)
|
||||
self.css_errors.append(error)
|
||||
return
|
||||
compiled = result[0].strip().decode('utf8')
|
||||
fragments = self.rx_css_split.split(compiled)[1:]
|
||||
while fragments:
|
||||
asset_id = fragments.pop(0)
|
||||
asset = next(asset for asset in sass if asset.id == asset_id)
|
||||
asset._content = fragments.pop(0)
|
||||
|
||||
def get_sass_error(self, stderr, source=None):
|
||||
# TODO: try to find out which asset the error belongs to
|
||||
error = stderr.split('Load paths')[0].replace(' Use --trace for backtrace.', '')
|
||||
error += "This error occured while compiling the bundle '%s' containing:" % self.xmlid
|
||||
for asset in self.stylesheets:
|
||||
if isinstance(asset, SassAsset):
|
||||
error += '\n - %s' % (asset.url if asset.url else '<inline sass>')
|
||||
return error
|
||||
|
||||
class WebAsset(object):
|
||||
def __init__(self, source=None, url=None):
|
||||
self.source = source
|
||||
html_url = '%s'
|
||||
|
||||
def __init__(self, bundle, inline=None, url=None):
|
||||
self.id = str(uuid.uuid4())
|
||||
self.bundle = bundle
|
||||
self.inline = inline
|
||||
self.url = url
|
||||
self._irattach = None
|
||||
self.cr = bundle.cr
|
||||
self.uid = bundle.uid
|
||||
self.registry = bundle.registry
|
||||
self.context = bundle.context
|
||||
self._content = None
|
||||
self.filename = None
|
||||
self.last_modified = None
|
||||
if source:
|
||||
self.last_modified = datetime.datetime(1970, 1, 1)
|
||||
if url:
|
||||
module = filter(None, self.url.split('/'))[0]
|
||||
self._filename = None
|
||||
self._ir_attach = None
|
||||
name = '<inline asset>' if inline else url
|
||||
self.name = "%s defined in bundle '%s'" % (name, bundle.xmlid)
|
||||
if not inline and not url:
|
||||
raise Exception("An asset should either be inlined or url linked")
|
||||
|
||||
def stat(self):
|
||||
if not (self.inline or self._filename or self._ir_attach):
|
||||
addon = filter(None, self.url.split('/'))[0]
|
||||
try:
|
||||
# Test url against modules static assets
|
||||
mpath = openerp.http.addons_manifest[module]['addons_path']
|
||||
self.filename = mpath + self.url.replace('/', os.path.sep)
|
||||
self.last_modified = datetime.datetime.fromtimestamp(os.path.getmtime(self.filename))
|
||||
mpath = openerp.http.addons_manifest[addon]['addons_path']
|
||||
self._filename = mpath + self.url.replace('/', os.path.sep)
|
||||
except Exception:
|
||||
try:
|
||||
# Test url against ir.attachments
|
||||
fields = ['__last_update', 'datas', 'mimetype']
|
||||
domain = [('type', '=', 'binary'), ('url', '=', self.url)]
|
||||
attach = request.registry['ir.attachment'].search_read(request.cr, SUPERUSER_ID, domain, ['__last_update', 'datas', 'mimetype'], context=request.context)
|
||||
self._irattach = attach[0]
|
||||
server_format = openerp.tools.misc.DEFAULT_SERVER_DATETIME_FORMAT
|
||||
try:
|
||||
self.last_modified = datetime.datetime.strptime(attach[0]['__last_update'], server_format + '.%f')
|
||||
except ValueError:
|
||||
self.last_modified = datetime.datetime.strptime(attach[0]['__last_update'], server_format)
|
||||
ira = self.registry['ir.attachment']
|
||||
attach = ira.search_read(self.cr, self.uid, domain, fields, context=self.context)
|
||||
self._ir_attach = attach[0]
|
||||
except Exception:
|
||||
raise KeyError("Could not find asset '%s' for '%s' addon" % (self.url, module))
|
||||
raise AssetNotFound("Could not find %s" % self.name)
|
||||
|
||||
@openerp.tools.func.lazy_property
|
||||
def to_html():
|
||||
raise NotImplementedError()
|
||||
|
||||
@lazy_property
|
||||
def last_modified(self):
|
||||
try:
|
||||
self.stat()
|
||||
if self._filename:
|
||||
return datetime.datetime.fromtimestamp(os.path.getmtime(self._filename))
|
||||
elif self._ir_attach:
|
||||
server_format = openerp.tools.misc.DEFAULT_SERVER_DATETIME_FORMAT
|
||||
last_update = self._ir_attach['__last_update']
|
||||
try:
|
||||
return datetime.datetime.strptime(last_update, server_format + '.%f')
|
||||
except ValueError:
|
||||
return datetime.datetime.strptime(last_update, server_format)
|
||||
except Exception:
|
||||
pass
|
||||
return datetime.datetime(1970, 1, 1)
|
||||
|
||||
@property
|
||||
def content(self):
|
||||
if self.source:
|
||||
return self.source
|
||||
if self._irattach:
|
||||
return self._irattach['datas'].decode('base64')
|
||||
return self.get_content()
|
||||
if not self._content:
|
||||
self._content = self.inline or self._fetch_content()
|
||||
return self._content
|
||||
|
||||
def get_content(self):
|
||||
with open(self.filename, 'rb') as fp:
|
||||
return fp.read().decode('utf-8')
|
||||
def _fetch_content(self):
|
||||
""" Fetch content from file or database"""
|
||||
try:
|
||||
self.stat()
|
||||
if self._filename:
|
||||
with open(self._filename, 'rb') as fp:
|
||||
return fp.read().decode('utf-8')
|
||||
else:
|
||||
return self._ir_attach['datas'].decode('base64')
|
||||
except UnicodeDecodeError:
|
||||
raise AssetError('%s is not utf-8 encoded.' % self.name)
|
||||
except IOError:
|
||||
raise AssetNotFound('File %s does not exist.' % self.name)
|
||||
except:
|
||||
raise AssetError('Could not get content for %s.' % self.name)
|
||||
|
||||
def minify(self):
|
||||
return self.content
|
||||
|
||||
def with_header(self, content=None):
|
||||
if content is None:
|
||||
content = self.content
|
||||
return '\n/* %s */\n%s' % (self.name, content)
|
||||
|
||||
class JavascriptAsset(WebAsset):
|
||||
def minify(self):
|
||||
return rjsmin(self.content)
|
||||
return self.with_header(rjsmin(self.content))
|
||||
|
||||
def _fetch_content(self):
|
||||
try:
|
||||
return super(JavascriptAsset, self)._fetch_content()
|
||||
except AssetError, e:
|
||||
return "console.error(%s);" % json.dumps(e.message)
|
||||
|
||||
def to_html(self):
|
||||
if self.url:
|
||||
return '<script type="text/javascript" src="%s"></script>' % self.url
|
||||
return '<script type="text/javascript" src="%s"></script>' % (self.html_url % self.url)
|
||||
else:
|
||||
return '<script type="text/javascript" charset="utf-8">%s</script>' % self.source
|
||||
return '<script type="text/javascript" charset="utf-8">%s</script>' % self.with_header()
|
||||
|
||||
class StylesheetAsset(WebAsset):
|
||||
rx_import = re.compile(r"""@import\s+('|")(?!'|"|/|https?://)""", re.U)
|
||||
rx_url = re.compile(r"""url\s*\(\s*('|"|)(?!'|"|/|https?://|data:)""", re.U)
|
||||
rx_sourceMap = re.compile(r'(/\*# sourceMappingURL=.*)', re.U)
|
||||
rx_charset = re.compile(r'(@charset "[^"]+";)', re.U)
|
||||
|
||||
def _get_content(self):
|
||||
with open(self.filename, 'rb') as fp:
|
||||
firstline = fp.readline()
|
||||
m = re.match(r'@charset "([^"]+)";', firstline)
|
||||
if m:
|
||||
encoding = m.group(1)
|
||||
else:
|
||||
encoding = "utf-8"
|
||||
# "reinject" first line as it's not @charset
|
||||
fp.seek(0)
|
||||
def __init__(self, *args, **kw):
|
||||
self.media = kw.pop('media', None)
|
||||
super(StylesheetAsset, self).__init__(*args, **kw)
|
||||
|
||||
return fp.read().decode(encoding)
|
||||
@property
|
||||
def content(self):
|
||||
content = super(StylesheetAsset, self).content
|
||||
if self.media:
|
||||
content = '@media %s { %s }' % (self.media, content)
|
||||
return content
|
||||
|
||||
def get_content(self):
|
||||
content = self._get_content()
|
||||
if self.url:
|
||||
def _fetch_content(self):
|
||||
try:
|
||||
content = super(StylesheetAsset, self)._fetch_content()
|
||||
web_dir = os.path.dirname(self.url)
|
||||
|
||||
content = self.rx_import.sub(
|
||||
@@ -1191,6 +1353,12 @@ class StylesheetAsset(WebAsset):
|
||||
r"url(\1%s/" % (web_dir,),
|
||||
content,
|
||||
)
|
||||
|
||||
# remove charset declarations, we only support utf-8
|
||||
content = self.rx_charset.sub('', content)
|
||||
except AssetError, e:
|
||||
self.bundle.css_errors.append(e.message)
|
||||
return ''
|
||||
return content
|
||||
|
||||
def minify(self):
|
||||
@@ -1201,13 +1369,61 @@ class StylesheetAsset(WebAsset):
|
||||
# space
|
||||
content = re.sub(r'\s+', ' ', content)
|
||||
content = re.sub(r' *([{}]) *', r'\1', content)
|
||||
return content
|
||||
return self.with_header(content)
|
||||
|
||||
def to_html(self):
|
||||
media = (' media="%s"' % werkzeug.utils.escape(self.media)) if self.media else ''
|
||||
if self.url:
|
||||
href = self.html_url % self.url
|
||||
return '<link rel="stylesheet" href="%s" type="text/css"%s/>' % (href, media)
|
||||
else:
|
||||
return '<style type="text/css"%s>%s</style>' % (media, self.with_header())
|
||||
|
||||
class SassAsset(StylesheetAsset):
|
||||
html_url = '%s.css'
|
||||
rx_indent = re.compile(r'^( +|\t+)', re.M)
|
||||
indent = None
|
||||
reindent = ' '
|
||||
|
||||
def minify(self):
|
||||
return self.with_header()
|
||||
|
||||
def to_html(self):
|
||||
if self.url:
|
||||
return '<link rel="stylesheet" href="%s" type="text/css"/>' % self.url
|
||||
else:
|
||||
return '<style type="text/css">%s</style>' % self.source
|
||||
ira = self.registry['ir.attachment']
|
||||
url = self.html_url % self.url
|
||||
domain = [('type', '=', 'binary'), ('url', '=', self.url)]
|
||||
ira_id = ira.search(self.cr, self.uid, domain, context=self.context)
|
||||
if ira_id:
|
||||
# TODO: update only if needed
|
||||
ira.write(self.cr, openerp.SUPERUSER_ID, [ira_id], {'datas': self.content}, context=self.context)
|
||||
else:
|
||||
ira.create(self.cr, openerp.SUPERUSER_ID, dict(
|
||||
datas=self.content.encode('utf8').encode('base64'),
|
||||
mimetype='text/css',
|
||||
type='binary',
|
||||
name=url,
|
||||
url=url,
|
||||
), context=self.context)
|
||||
return super(SassAsset, self).to_html()
|
||||
|
||||
def get_source(self):
|
||||
content = textwrap.dedent(self.inline or self._fetch_content())
|
||||
|
||||
def fix_indent(m):
|
||||
ind = m.group()
|
||||
if self.indent is None:
|
||||
self.indent = ind
|
||||
if self.indent == self.reindent:
|
||||
# Don't reindent the file if identation is the final one (reindent)
|
||||
raise StopIteration()
|
||||
return ind.replace(self.indent, self.reindent)
|
||||
|
||||
try:
|
||||
content = self.rx_indent.sub(fix_indent, content)
|
||||
except StopIteration:
|
||||
pass
|
||||
return "/*! %s */\n%s" % (self.id, content)
|
||||
|
||||
def rjsmin(script):
|
||||
""" Minify js with a clever regex.
|
||||
|
||||
@@ -519,7 +519,7 @@ class view(osv.osv):
|
||||
if context is None: context = {}
|
||||
if root_id is None:
|
||||
root_id = source_id
|
||||
sql_inherit = self.pool['ir.ui.view'].get_inheriting_views_arch(cr, uid, source_id, model, context=context)
|
||||
sql_inherit = self.get_inheriting_views_arch(cr, uid, source_id, model, context=context)
|
||||
for (specs, view_id) in sql_inherit:
|
||||
specs_tree = etree.fromstring(specs.encode('utf-8'))
|
||||
if context.get('inherit_branding'):
|
||||
@@ -986,10 +986,15 @@ class view(osv.osv):
|
||||
)
|
||||
qcontext.update(values)
|
||||
|
||||
# TODO: remove this as soon as the following branch is merged
|
||||
# lp:~openerp-dev/openerp-web/trunk-module-closure-style-msh
|
||||
from openerp.addons.web.controllers.main import module_boot
|
||||
qcontext['modules'] = simplejson.dumps(module_boot()) if request else None
|
||||
# TODO: This helper can be used by any template that wants to embedd the backend.
|
||||
# It is currently necessary because the ir.ui.view bundle inheritance does not
|
||||
# match the module dependency graph.
|
||||
def get_modules_order():
|
||||
if request:
|
||||
from openerp.addons.web.controllers.main import module_boot
|
||||
return simplejson.dumps(module_boot())
|
||||
return '[]'
|
||||
qcontext['get_modules_order'] = get_modules_order
|
||||
|
||||
def loader(name):
|
||||
return self.read_template(cr, uid, name, context=context)
|
||||
|
||||
Reference in New Issue
Block a user