Merge remote-tracking branch 'odoo/master' into master-sass-in-bundles-fme

This commit is contained in:
Fabien Meghazi 2014-07-01 14:26:40 +02:00
commit 4042135bc4
71 changed files with 5124 additions and 4089 deletions

View File

@ -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','&lt;=', time.strftime('%%Y-%%m-%%d')),('date','&gt;=',time.strftime('%%Y-01-01'))]" help="year"/>
<filter string="This Year" name="year" domain="['|', ('date', '=', False), '&amp;',('date','&lt;=', time.strftime('%%Y-12-31')),('date','&gt;=',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>

View File

@ -10,22 +10,22 @@
<div class="row mt32 mb32">
<div class="col-xs-3">
<strong>Chart of Tax:</strong>
<p t-esc="account"/>
<p t-esc="get_account(data)"/>
</div>
<div class="col-xs-3" t-if="fiscalyear">
<div class="col-xs-3">
<strong>Fiscal Year:</strong>
<p t-esc="fiscalyear"/>
<p t-esc="get_fiscalyear(data)"/>
</div>
<div class="col-xs-3" t-if="period_from and period_to">
<div class="col-xs-3">
<strong>Periods:</strong>
<p>
Start Period: <span t-esc="period_from"/><br/>
End Period: <span t-esc="period_to"/>
Start Period: <span t-esc="get_start_period(data)"/><br/>
End Period: <span t-esc="get_end_period(data)"/>
</p>
</div>
<div class="col-xs-3">
<strong>Based On:</strong>
<p t-esc="based_on"/>
<p t-esc="get_basedon(data)"/>
</div>
</div>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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">

View File

@ -5,7 +5,7 @@
<record id="config_google_drive_client_id" model="ir.config_parameter">
<field name="key">google_drive_client_id</field>
<field name="value">598905559630.apps.googleusercontent.com</field>
<field name="group_ids" eval="[(4, ref('base.group_user'))]" />
<field name="group_ids" eval="[(4, ref('base.group_system'))]" />
</record>
<record id="config_google_drive_client_secret" model="ir.config_parameter">

View File

@ -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','&lt;&gt;',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>

View File

@ -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','&lt;=', time.strftime('%%Y-12-31')),('date_create','&gt;=',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"/>

View File

@ -12,8 +12,9 @@
}
}
/* button */
.oe_systray #oe_topbar_im_icon {
.oe_systray #oe_topbar_imbutton_icon {
color: white;
margin-right: 10px;
}
.oe_topbar_item.oe_topbar_imbutton .oe_e {
position: relative;

View File

@ -104,6 +104,7 @@
this.manager.set("bottom_offset", $('.oe_chat_button').outerHeight()); // TODO correct the value (no hardcode damned !)
// override the notification default function
this.manager.notification = function(notif){
alert(notif);
}
}
return this.chat();

View File

@ -116,11 +116,9 @@
<!-- IM module -->
<script type="text/javascript" src="/bus/static/src/js/bus.js"></script>
<script type="text/javascript" src="/im_chat/static/src/js/im_chat.js"></script>
<script type="text/javascript" src="/im_livechat/static/lib/jquery-achtung/src/ui.achtung.js"></script>
<script type="text/javascript" src="/im_livechat/static/src/js/im_livechat.js"></script>
<!-- CSS -->
<link rel="stylesheet" href="/im_chat/static/src/css/im_common.css"></link>
<link rel="stylesheet" href="/im_livechat/static/lib/jquery-achtung/src/ui.achtung.css"></link>
</template>
<!-- the js code to initialize the LiveSupport object -->

5
addons/l10n_ro/__init__.py Normal file → Executable file
View File

@ -1,8 +1,9 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2012 TOTAL PC SYSTEMS (<http://www.erpsystems.ro>). All Rights Reserved
# @author - Fekete Mihai <feketemihai@gmail.com>
# Copyright (C) 2011 TOTAL PC SYSTEMS (http://www.www.erpsystems.ro).
# Copyright (C) 2009 (<http://www.filsystem.ro>)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by

20
addons/l10n_ro/__openerp__.py Normal file → Executable file
View File

@ -1,8 +1,9 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2012 (<http://www.erpsystems.ro>). All Rights Reserved
# @author - Fekete Mihai <feketemihai@gmail.com>
# Copyright (C) 2011 TOTAL PC SYSTEMS (http://www.www.erpsystems.ro).
# Copyright (C) 2009 (<http://www.filsystem.ro>)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -26,14 +27,21 @@
"category" : "Localization/Account Charts",
"depends" : ['account','account_chart','base_vat'],
"description": """
This is the module to manage the accounting chart, VAT structure and Registration Number for Romania in OpenERP.
This is the module to manage the Accounting Chart, VAT structure, Fiscal Position and Tax Mapping.
It also adds the Registration Number for Romania in OpenERP.
================================================================================================================
Romanian accounting chart and localization.
""",
"demo_xml" : [],
"data" : ['partner_view.xml','account_tax_code_template.xml','account_chart.xml','account_tax_template.xml','l10n_chart_ro_wizard.xml'],
"auto_install": False,
"demo" : [],
"data" : ['partner_view.xml',
'account_chart.xml',
'account_tax_code_template.xml',
'account_chart_template.xml',
'account_tax_template.xml',
'fiscal_position_template.xml',
'l10n_chart_ro_wizard.xml',
],
"installable": True,
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

5811
addons/l10n_ro/account_chart.xml Normal file → Executable file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="0">
<!-- Chart template -->
<record id="ro_chart_template" model="account.chart.template">
<field name="name">Romania - Chart of Accounts</field>
<field name="account_root_id" ref="pcg_0"/>
<field name="tax_code_root_id" ref="vat_code_tax"/>
<field name="bank_account_view_id" ref="ro_pcg_cash"/>
<field name="property_account_receivable" ref="ro_pcg_recv"/> <!-- 4111 -->
<field name="property_account_payable" ref="ro_pcg_pay"/> <!-- 4011 -->
<field name="property_account_expense_categ" ref="ro_pcg_expense"/> <!-- 607 -->
<field name="property_account_income_categ" ref="ro_pcg_sale"/> <!-- 707 -->
<field name="currency_id" ref="base.RON"/>
</record>
</data>
</openerp>

441
addons/l10n_ro/account_tax_code_template.xml Normal file → Executable file
View File

@ -5,182 +5,285 @@
#
# Tax Code Template Configuration
#
<record model="account.tax.code.template" id="vat_code_tax">
<field name="name">Decont TVA</field>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_tva">
<field name="name">TVA COLECTATA</field>
<field name="code">b)</field>
<field name="parent_id" ref="vat_code_tax"/>
</record>
<record model="account.tax.code.template" id="vat_code_tax">
<field name="name">Decont TVA</field>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_tva">
<field name="name">TVA COLECTATA</field>
<field name="code">b)</field>
<field name="parent_id" ref="vat_code_tax"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_tva24">
<field name="name">TVA 24%</field>
<field name="code">TVA colectata 24%</field>
<field name="parent_id" ref="vat_code_tvac_tva"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_tva19">
<field name="name">TVA 19%</field>
<field name="code">TVA colectata 19%</field>
<field name="parent_id" ref="vat_code_tvac_tva"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_tva09">
<field name="name">TVA 9%</field>
<field name="code">TVA colectata 9%</field>
<field name="parent_id" ref="vat_code_tvac_tva"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_tva05">
<field name="name">TVA 5%</field>
<field name="code">TVA colectata 5%</field>
<field name="parent_id" ref="vat_code_tvac_tva"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_tva24">
<field name="name">TVA 24%</field>
<field name="code">TVA colectata 24%</field>
<field name="parent_id" ref="vat_code_tvac_tva"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_tva19">
<field name="name">TVA 19%</field>
<field name="code">TVA colectata 19%</field>
<field name="parent_id" ref="vat_code_tvac_tva"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_tva09">
<field name="name">TVA 9%</field>
<field name="code">TVA colectata 9%</field>
<field name="parent_id" ref="vat_code_tvac_tva"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_tva05">
<field name="name">TVA 5%</field>
<field name="code">TVA colectata 5%</field>
<field name="parent_id" ref="vat_code_tvac_tva"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_tvaTI">
<field name="name">TVA Taxare inversa</field>
<field name="code">TVA</field>
<field name="parent_id" ref="vat_code_tvac_tva"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_tva00">
<field name="name">TVA 0%</field>
<field name="code">TVA colectata 0%</field>
<field name="parent_id" ref="vat_code_tvac_tva"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_tva00">
<field name="name">TVA 0%</field>
<field name="code">TVA colectata 0%</field>
<field name="parent_id" ref="vat_code_tvac_tva"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_baza">
<field name="name">BAZA TVA COLECTAT</field>
<field name="code">a)</field>
<field name="parent_id" ref="vat_code_tax"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_baza24">
<field name="name">Baza TVA 24%</field>
<field name="code">TVA colectata 24%(Baza)</field>
<field name="parent_id" ref="vat_code_tvac_baza"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_baza19">
<field name="name">Baza TVA 19%</field>
<field name="code">TVA colectata 19%(Baza)</field>
<field name="parent_id" ref="vat_code_tvac_baza"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_baza09">
<field name="name">Baza TVA 9%</field>
<field name="code">TVA colectata 9%(Baza)</field>
<field name="parent_id" ref="vat_code_tvac_baza"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_baza05">
<field name="name">Baza TVA 5%</field>
<field name="code">TVA colectata 5%(Baza)</field>
<field name="parent_id" ref="vat_code_tvac_baza"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_baza">
<field name="name">BAZA TVA COLECTAT</field>
<field name="code">a)</field>
<field name="parent_id" ref="vat_code_tax"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_baza24">
<field name="name">Baza TVA 24%</field>
<field name="code">TVA colectata 24%(Baza)</field>
<field name="parent_id" ref="vat_code_tvac_baza"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_baza19">
<field name="name">Baza TVA 19%</field>
<field name="code">TVA colectata 19%(Baza)</field>
<field name="parent_id" ref="vat_code_tvac_baza"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_baza09">
<field name="name">Baza TVA 9%</field>
<field name="code">TVA colectata 9%(Baza)</field>
<field name="parent_id" ref="vat_code_tvac_baza"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_baza05">
<field name="name">Baza TVA 5%</field>
<field name="code">TVA colectata 5%(Baza)</field>
<field name="parent_id" ref="vat_code_tvac_baza"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_baza00">
<field name="name">Baza TVA 0%</field>
<field name="code">TVA colectata 0%(Baza)</field>
<field name="parent_id" ref="vat_code_tvac_baza"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_bazaTI">
<field name="name">Baza TVA Taxare inversa</field>
<field name="code">Baza</field>
<field name="parent_id" ref="vat_code_tvac_baza"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvad_tva">
<field name="name">TVA DEDUCTIBILA</field>
<field name="code">d)</field>
<field name="parent_id" ref="vat_code_tax"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvad_tva24">
<field name="name">TVA 24%</field>
<field name="code">TVA deductibila 24%</field>
<field name="parent_id" ref="vat_code_tvad_tva"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvad_tva19">
<field name="name">TVA 19%</field>
<field name="code">TVA deductibila 19%</field>
<field name="parent_id" ref="vat_code_tvad_tva"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvad_tva09">
<field name="name">TVA 9%</field>
<field name="code">TVA deductibila 9%</field>
<field name="parent_id" ref="vat_code_tvad_tva"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvad_tva05">
<field name="name">TVA 5%</field>
<field name="code">TVA deductibila 5%</field>
<field name="parent_id" ref="vat_code_tvad_tva"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_baza00">
<field name="name">Baza TVA 0%</field>
<field name="code">TVA colectata 0%(Baza)</field>
<field name="parent_id" ref="vat_code_tvac_baza"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvad_tva00">
<field name="name">TVA 0%</field>
<field name="code">TVA deductibila 0%</field>
<field name="parent_id" ref="vat_code_tvad_tva"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvad_baza">
<field name="name">BAZA TVA DEDUCTIBIL</field>
<field name="code">c)</field>
<field name="parent_id" ref="vat_code_tax"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvad_baza24">
<field name="name">Baza TVA 24%</field>
<field name="code">TVA deductibila 24%(Baza)</field>
<field name="parent_id" ref="vat_code_tvad_baza"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvad_baza19">
<field name="name">Baza TVA 19%</field>
<field name="code">TVA deductibila 19%(Baza)</field>
<field name="parent_id" ref="vat_code_tvad_baza"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvad_baza09">
<field name="name">Baza TVA 9%</field>
<field name="code">TVA deductibila 9%(Baza)</field>
<field name="parent_id" ref="vat_code_tvad_baza"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvad_baza05">
<field name="name">Baza TVA 5%</field>
<field name="code">TVA deductibila 5%(Baza)</field>
<field name="parent_id" ref="vat_code_tvad_baza"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvad_baza00">
<field name="name">Baza TVA 0%</field>
<field name="code">TVA deductibila 0%(Baza)</field>
<field name="parent_id" ref="vat_code_tvad_baza"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvati_baza">
<field name="name">BAZA TVA TAXARE INVERSA</field>
<field name="code">e)</field>
<field name="parent_id" ref="vat_code_tax"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_bazaTI">
<field name="name">Baza TVA Taxare inversa</field>
<field name="code">Baza TVA Taxare inversa</field>
<field name="parent_id" ref="vat_code_tvati_baza"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvati">
<field name="name">TVA TAXARE INVERSA</field>
<field name="code">f)</field>
<field name="parent_id" ref="vat_code_tax"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_tvaTI">
<field name="name">TVA Taxare inversa</field>
<field name="code">TVA Taxare inversa</field>
<field name="parent_id" ref="vat_code_tvati"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvad_tva">
<field name="name">TVA DEDUCTIBILA</field>
<field name="code">d)</field>
<field name="parent_id" ref="vat_code_tax"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvad_tva24">
<field name="name">TVA 24%</field>
<field name="code">TVA deductibila 24%</field>
<field name="parent_id" ref="vat_code_tvad_tva"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvad_tva19">
<field name="name">TVA 19%</field>
<field name="code">TVA deductibila 19%</field>
<field name="parent_id" ref="vat_code_tvad_tva"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvad_tva09">
<field name="name">TVA 9%</field>
<field name="code">TVA deductibila 9%</field>
<field name="parent_id" ref="vat_code_tvad_tva"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvad_tva05">
<field name="name">TVA 5%</field>
<field name="code">TVA deductibila 5%</field>
<field name="parent_id" ref="vat_code_tvad_tva"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvad_tva00">
<field name="name">TVA 0%</field>
<field name="code">TVA deductibila 0%</field>
<field name="parent_id" ref="vat_code_tvad_tva"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvad_baza">
<field name="name">BAZA TVA DEDUCTIBIL</field>
<field name="code">c)</field>
<field name="parent_id" ref="vat_code_tax"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvad_baza24">
<field name="name">Baza TVA 24%</field>
<field name="code">TVA deductibila 24%(Baza)</field>
<field name="parent_id" ref="vat_code_tvad_baza"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvad_baza19">
<field name="name">Baza TVA 19%</field>
<field name="code">TVA deductibila 19%(Baza)</field>
<field name="parent_id" ref="vat_code_tvad_baza"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvad_baza09">
<field name="name">Baza TVA 9%</field>
<field name="code">TVA deductibila 9%(Baza)</field>
<field name="parent_id" ref="vat_code_tvad_baza"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvad_baza05">
<field name="name">Baza TVA 5%</field>
<field name="code">TVA deductibila 5%(Baza)</field>
<field name="parent_id" ref="vat_code_tvad_baza"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvad_baza00">
<field name="name">Baza TVA 0%</field>
<field name="code">TVA deductibila 0%(Baza)</field>
<field name="parent_id" ref="vat_code_tvad_baza"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvaneex_baza">
<field name="name">BAZA TVA NEEXIGIBIL</field>
<field name="code">e)</field>
<field name="parent_id" ref="vat_code_tax"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvaneexc_baza">
<field name="name">Baza TVA neexigibil - colectat</field>
<field name="code">TVA neexigibil - colectat (Baza)</field>
<field name="parent_id" ref="vat_code_tvaneex_baza"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvaneexd_baza">
<field name="name">Baza TVA neexigibil - deductibil</field>
<field name="code">TVA neexigibil - deductibil (Baza)</field>
<field name="parent_id" ref="vat_code_tvaneex_baza"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvaneex">
<field name="name">TVA NEEXIGIBIL</field>
<field name="code">f)</field>
<field name="parent_id" ref="vat_code_tax"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvaneexc">
<field name="name">TVA neexigibil - colectat</field>
<field name="code">TVA neexigibil - colectat</field>
<field name="parent_id" ref="vat_code_tvaneex"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvaneexd">
<field name="name">TVA neexigibil - deductibil</field>
<field name="code">TVA neexigibil - deductibil</field>
<field name="parent_id" ref="vat_code_tvaneex"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvati_baza">
<field name="name">BAZA TVA TAXARE INVERSA</field>
<field name="code">e)</field>
<field name="parent_id" ref="vat_code_tax"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_bazaTI">
<field name="name">Baza TVA Taxare inversa</field>
<field name="code">Baza TVA Taxare inversa</field>
<field name="parent_id" ref="vat_code_tvati_baza"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvati">
<field name="name">TVA TAXARE INVERSA</field>
<field name="code">f)</field>
<field name="parent_id" ref="vat_code_tax"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_tvaTI">
<field name="name">TVA Taxare inversa</field>
<field name="code">TVA Taxare inversa</field>
<field name="parent_id" ref="vat_code_tvati"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvanex_baza">
<field name="name">BAZA TVA NEEXIGIBILA</field>
<field name="code">g)</field>
<field name="parent_id" ref="vat_code_tax"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_nex_baza">
<field name="name">Baza TVA Neexigibil Colectat</field>
<field name="code">Baza TVA Neexigibil Colectat</field>
<field name="parent_id" ref="vat_code_tvanex_baza"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvad_nex_baza">
<field name="name">Baza TVA Neexigibil Deductibil</field>
<field name="code">Baza TVA Neexigibil Deductibil</field>
<field name="parent_id" ref="vat_code_tvanex_baza"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvanex">
<field name="name">TVA NEEXIGIBILA</field>
<field name="code">h)</field>
<field name="parent_id" ref="vat_code_tax"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_nex">
<field name="name">TVA Neexigibil Colectat</field>
<field name="code">TVA Neexigibil Colectat</field>
<field name="parent_id" ref="vat_code_tvanex"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvad_nex">
<field name="name">TVA Neexigibil Deductibil</field>
<field name="code">TVA Neexigibil Deductibil</field>
<field name="parent_id" ref="vat_code_tvanex"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvatisc_baza">
<field name="name">BAZA TVA TAXARE INTRACOMUNITARA SCUTITA</field>
<field name="code">i)</field>
<field name="parent_id" ref="vat_code_tax"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_bazaTISC">
<field name="name">Baza TVA Taxare intracomunitara scutita</field>
<field name="code">Baza TVA Taxare intracomunitara scutita</field>
<field name="parent_id" ref="vat_code_tvatisc_baza"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvatisc">
<field name="name">TVA TAXARE INTRACOMUNITARA SCUTITA</field>
<field name="code">j)</field>
<field name="parent_id" ref="vat_code_tax"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_tvaTISC">
<field name="name">TVA Taxare intracomunitara scutita</field>
<field name="code">TVA Taxare intracomunitara scutita</field>
<field name="parent_id" ref="vat_code_tvatisc"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvatine_baza">
<field name="name">BAZA TVA TAXARE INTRACOMUNITARA NEIMPOZABILA</field>
<field name="code">k)</field>
<field name="parent_id" ref="vat_code_tax"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_bazaTINE">
<field name="name">Baza TVA Taxare intracomunitara neimpozabila</field>
<field name="code">Baza TVA Taxare intracomunitara neimpozabila</field>
<field name="parent_id" ref="vat_code_tvatine_baza"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvatine">
<field name="name">TVA TAXARE INTRACOMUNITARA NEIMPOZABILA</field>
<field name="code">l)</field>
<field name="parent_id" ref="vat_code_tax"/>
</record>
<record model="account.tax.code.template" id="vat_code_tvac_tvaTINE">
<field name="name">TVA Taxare intracomunitara neimpozabila</field>
<field name="code">TVA Taxare intracomunitara neimpozabila</field>
<field name="parent_id" ref="vat_code_tvatine"/>
</record>
</data>
</openerp>

393
addons/l10n_ro/account_tax_template.xml Normal file → Executable file
View File

@ -1,170 +1,239 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="0">
<record id="tvac_00" model="account.tax.template">
<field name="chart_template_id" ref="romania_chart_template"/>
<field name="name">TVA colectat 0%</field>
<field name="amount">0.000000</field>
<field name="type">percent</field>
<field name="account_collected_id" ref="pcg_4427"/>
<field name="account_paid_id" ref="pcg_4427"/>
<field name="base_code_id" ref="vat_code_tvac_baza00"/>
<field name="base_sign">1.00</field>
<field name="tax_code_id" ref="vat_code_tvac_tva00"/>
<field name="tax_sign">1.00</field>
<field name="ref_base_code_id" ref="vat_code_tvac_baza00"/>
<field name="ref_base_sign">-1.00</field>
<field name="ref_tax_code_id" ref="vat_code_tvac_tva00"/>
<field name="ref_tax_sign">-1.00</field>
</record>
<record id="tvac_05" model="account.tax.template">
<field name="chart_template_id" ref="romania_chart_template"/>
<field name="name">TVA colectat 5%</field>
<field name="amount">0.050000</field>
<field name="type">percent</field>
<field name="account_collected_id" ref="pcg_4427"/>
<field name="account_paid_id" ref="pcg_4427"/>
<field name="base_code_id" ref="vat_code_tvac_baza05"/>
<field name="tax_code_id" ref="vat_code_tvac_tva05"/>
<field name="ref_base_code_id" ref="vat_code_tvac_baza05"/>
<field name="ref_tax_code_id" ref="vat_code_tvac_tva05"/>
<field name="ref_base_sign">-1.00</field>
<field name="ref_tax_sign">-1.00</field>
<field name="base_sign">1.00</field>
<field name="tax_sign">1.00</field>
</record>
<record id="tvac_09" model="account.tax.template">
<field name="chart_template_id" ref="romania_chart_template"/>
<field name="name">TVA colectat 9%</field>
<field name="amount">0.090000</field>
<field name="type">percent</field>
<field name="account_collected_id" ref="pcg_4427"/>
<field name="account_paid_id" ref="pcg_4427"/>
<field name="base_code_id" ref="vat_code_tvac_baza09"/>
<field name="tax_code_id" ref="vat_code_tvac_tva09"/>
<field name="ref_base_code_id" ref="vat_code_tvac_baza09"/>
<field name="ref_tax_code_id" ref="vat_code_tvac_tva09"/>
<field name="ref_base_sign">-1.00</field>
<field name="ref_tax_sign">-1.00</field>
<field name="base_sign">1.00</field>
<field name="tax_sign">1.00</field>
</record>
<record id="tvac_19" model="account.tax.template">
<field name="chart_template_id" ref="romania_chart_template"/>
<field name="name">TVA colectat 19%</field>
<field name="amount">0.190000</field>
<field name="type">percent</field>
<field name="account_collected_id" ref="pcg_4427"/>
<field name="account_paid_id" ref="pcg_4427"/>
<field name="base_code_id" ref="vat_code_tvac_baza19"/>
<field name="tax_code_id" ref="vat_code_tvac_tva19"/>
<field name="ref_base_code_id" ref="vat_code_tvac_baza19"/>
<field name="ref_tax_code_id" ref="vat_code_tvac_tva19"/>
<field name="ref_base_sign">-1.00</field>
<field name="ref_tax_sign">-1.00</field>
<field name="base_sign">1.00</field>
<field name="tax_sign">1.00</field>
</record>
<record id="tvac_00" model="account.tax.template">
<field name="chart_template_id" ref="ro_chart_template"/>
<field name="name">TVA colectat 0%</field>
<field name="amount">0.000000</field>
<field name="type">percent</field>
<field name="type_tax_use">sale</field>
<field name="account_collected_id" ref="pcg_4427"/>
<field name="account_paid_id" ref="pcg_4427"/>
<field name="base_code_id" ref="vat_code_tvac_baza00"/>
<field name="base_sign">1.00</field>
<field name="tax_code_id" ref="vat_code_tvac_tva00"/>
<field name="tax_sign">1.00</field>
<field name="ref_base_code_id" ref="vat_code_tvac_baza00"/>
<field name="ref_base_sign">-1.00</field>
<field name="ref_tax_code_id" ref="vat_code_tvac_tva00"/>
<field name="ref_tax_sign">-1.00</field>
</record>
<record id="tvac_05" model="account.tax.template">
<field name="chart_template_id" ref="ro_chart_template"/>
<field name="name">TVA colectat 5%</field>
<field name="amount">0.050000</field>
<field name="type">percent</field>
<field name="type_tax_use">sale</field>
<field name="account_collected_id" ref="pcg_4427"/>
<field name="account_paid_id" ref="pcg_4427"/>
<field name="base_code_id" ref="vat_code_tvac_baza05"/>
<field name="tax_code_id" ref="vat_code_tvac_tva05"/>
<field name="ref_base_code_id" ref="vat_code_tvac_baza05"/>
<field name="ref_tax_code_id" ref="vat_code_tvac_tva05"/>
<field name="ref_base_sign">-1.00</field>
<field name="ref_tax_sign">-1.00</field>
<field name="base_sign">1.00</field>
<field name="tax_sign">1.00</field>
</record>
<record id="tvac_09" model="account.tax.template">
<field name="chart_template_id" ref="ro_chart_template"/>
<field name="name">TVA colectat 9%</field>
<field name="amount">0.090000</field>
<field name="type">percent</field>
<field name="type_tax_use">sale</field>
<field name="account_collected_id" ref="pcg_4427"/>
<field name="account_paid_id" ref="pcg_4427"/>
<field name="base_code_id" ref="vat_code_tvac_baza09"/>
<field name="tax_code_id" ref="vat_code_tvac_tva09"/>
<field name="ref_base_code_id" ref="vat_code_tvac_baza09"/>
<field name="ref_tax_code_id" ref="vat_code_tvac_tva09"/>
<field name="ref_base_sign">-1.00</field>
<field name="ref_tax_sign">-1.00</field>
<field name="base_sign">1.00</field>
<field name="tax_sign">1.00</field>
</record>
<record id="tvac_19" model="account.tax.template">
<field name="chart_template_id" ref="ro_chart_template"/>
<field name="name">TVA colectat 19%</field>
<field name="amount">0.190000</field>
<field name="type">percent</field>
<field name="type_tax_use">sale</field>
<field name="account_collected_id" ref="pcg_4427"/>
<field name="account_paid_id" ref="pcg_4427"/>
<field name="base_code_id" ref="vat_code_tvac_baza19"/>
<field name="tax_code_id" ref="vat_code_tvac_tva19"/>
<field name="ref_base_code_id" ref="vat_code_tvac_baza19"/>
<field name="ref_tax_code_id" ref="vat_code_tvac_tva19"/>
<field name="ref_base_sign">-1.00</field>
<field name="ref_tax_sign">-1.00</field>
<field name="base_sign">1.00</field>
<field name="tax_sign">1.00</field>
</record>
<record id="tvac_24" model="account.tax.template">
<field name="chart_template_id" ref="ro_chart_template"/>
<field name="name">TVA colectat 24%</field>
<field name="amount">0.240000</field>
<field name="type">percent</field>
<field name="type_tax_use">sale</field>
<field name="account_collected_id" ref="pcg_4427"/>
<field name="account_paid_id" ref="pcg_4427"/>
<field name="base_code_id" ref="vat_code_tvac_baza24"/>
<field name="tax_code_id" ref="vat_code_tvac_tva24"/>
<field name="ref_base_code_id" ref="vat_code_tvac_baza24"/>
<field name="ref_tax_code_id" ref="vat_code_tvac_tva24"/>
<field name="ref_base_sign">-1.00</field>
<field name="ref_tax_sign">-1.00</field>
<field name="base_sign">1.00</field>
<field name="tax_sign">1.00</field>
</record>
<record id="tvad_00" model="account.tax.template">
<field name="chart_template_id" ref="ro_chart_template"/>
<field name="name">TVA deductibil 0%</field>
<field name="amount">0.000000</field>
<field name="type">percent</field>
<field name="type_tax_use">purchase</field>
<field name="account_collected_id" ref="pcg_4426"/>
<field name="account_paid_id" ref="pcg_4426"/>
<field name="base_code_id" ref="vat_code_tvad_baza00"/>
<field name="base_sign">1.00</field>
<field name="tax_code_id" ref="vat_code_tvad_tva00"/>
<field name="tax_sign">1.00</field>
<field name="ref_base_code_id" ref="vat_code_tvad_baza00"/>
<field name="ref_base_sign">-1.00</field>
<field name="ref_tax_code_id" ref="vat_code_tvad_tva00"/>
<field name="ref_tax_sign">-1.00</field>
</record>
<record id="tvad_05" model="account.tax.template">
<field name="chart_template_id" ref="ro_chart_template"/>
<field name="name">TVA deductibil 5%</field>
<field name="amount">0.050000</field>
<field name="type">percent</field>
<field name="type_tax_use">purchase</field>
<field name="account_collected_id" ref="pcg_4426"/>
<field name="account_paid_id" ref="pcg_4426"/>
<field name="base_code_id" ref="vat_code_tvad_baza05"/>
<field name="tax_code_id" ref="vat_code_tvad_tva05"/>
<field name="ref_base_code_id" ref="vat_code_tvad_baza05"/>
<field name="ref_tax_code_id" ref="vat_code_tvad_tva05"/>
<field name="ref_base_sign">-1.00</field>
<field name="ref_tax_sign">-1.00</field>
<field name="base_sign">1.00</field>
<field name="tax_sign">1.00</field>
</record>
<record id="tvad_09" model="account.tax.template">
<field name="chart_template_id" ref="ro_chart_template"/>
<field name="name">TVA deductibil 9%</field>
<field name="amount">0.090000</field>
<field name="type">percent</field>
<field name="type_tax_use">purchase</field>
<field name="account_collected_id" ref="pcg_4426"/>
<field name="account_paid_id" ref="pcg_4426"/>
<field name="base_code_id" ref="vat_code_tvad_baza09"/>
<field name="tax_code_id" ref="vat_code_tvad_tva09"/>
<field name="ref_base_code_id" ref="vat_code_tvad_baza09"/>
<field name="ref_tax_code_id" ref="vat_code_tvad_tva09"/>
<field name="ref_base_sign">-1.00</field>
<field name="ref_tax_sign">-1.00</field>
<field name="base_sign">1.00</field>
<field name="tax_sign">1.00</field>
</record>
<record id="tvad_19" model="account.tax.template">
<field name="chart_template_id" ref="ro_chart_template"/>
<field name="name">TVA deductibil 19%</field>
<field name="amount">0.190000</field>
<field name="type">percent</field>
<field name="type_tax_use">purchase</field>
<field name="account_collected_id" ref="pcg_4426"/>
<field name="account_paid_id" ref="pcg_4426"/>
<field name="base_code_id" ref="vat_code_tvad_baza19"/>
<field name="tax_code_id" ref="vat_code_tvad_tva19"/>
<field name="ref_base_code_id" ref="vat_code_tvad_baza19"/>
<field name="ref_tax_code_id" ref="vat_code_tvad_tva19"/>
<field name="ref_base_sign">-1.00</field>
<field name="ref_tax_sign">-1.00</field>
<field name="base_sign">1.00</field>
<field name="tax_sign">1.00</field>
</record>
<record id="tvad_24" model="account.tax.template">
<field name="chart_template_id" ref="ro_chart_template"/>
<field name="name">TVA deductibil 24%</field>
<field name="amount">0.240000</field>
<field name="type">percent</field>
<field name="type_tax_use">purchase</field>
<field name="account_collected_id" ref="pcg_4426"/>
<field name="account_paid_id" ref="pcg_4426"/>
<field name="base_code_id" ref="vat_code_tvad_baza24"/>
<field name="tax_code_id" ref="vat_code_tvad_tva24"/>
<field name="ref_base_code_id" ref="vat_code_tvad_baza24"/>
<field name="ref_tax_code_id" ref="vat_code_tvad_tva24"/>
<field name="ref_base_sign">-1.00</field>
<field name="ref_tax_sign">-1.00</field>
<field name="base_sign">1.00</field>
<field name="tax_sign">1.00</field>
</record>
<record id="tvati" model="account.tax.template">
<field name="chart_template_id" ref="ro_chart_template"/>
<field name="name">TVA Taxare Inversa</field>
<field name="amount">0.000000</field>
<field name="type">percent</field>
<field name="type_tax_use">sale</field>
<field name="account_collected_id" ref="pcg_4426"/>
<field name="account_paid_id" ref="pcg_4426"/>
<field name="base_code_id" ref="vat_code_tvac_bazaTI"/>
<field name="base_sign">1.00</field>
<field name="tax_code_id" ref="vat_code_tvac_tvaTI"/>
<field name="tax_sign">1.00</field>
<field name="ref_base_code_id" ref="vat_code_tvac_bazaTI"/>
<field name="ref_base_sign">-1.00</field>
<field name="ref_tax_code_id" ref="vat_code_tvac_tvaTI"/>
<field name="ref_tax_sign">-1.00</field>
</record>
<record id="tvac_24" model="account.tax.template">
<field name="chart_template_id" ref="romania_chart_template"/>
<field name="name">TVA colectat 24%</field>
<field name="amount">0.240000</field>
<field name="type">percent</field>
<field name="account_collected_id" ref="pcg_4427"/>
<field name="account_paid_id" ref="pcg_4427"/>
<field name="base_code_id" ref="vat_code_tvac_baza24"/>
<field name="tax_code_id" ref="vat_code_tvac_tva24"/>
<field name="ref_base_code_id" ref="vat_code_tvac_baza24"/>
<field name="ref_tax_code_id" ref="vat_code_tvac_tva24"/>
<field name="ref_base_sign">-1.00</field>
<field name="ref_tax_sign">-1.00</field>
<field name="base_sign">1.00</field>
<field name="tax_sign">1.00</field>
</record>
<record id="tvatisc" model="account.tax.template">
<field name="chart_template_id" ref="ro_chart_template"/>
<field name="name">TVA Taxare Intracomunitara Scutita</field>
<field name="amount">0.000000</field>
<field name="type">percent</field>
<field name="type_tax_use">all</field>
<field name="account_collected_id" ref="pcg_4426"/>
<field name="account_paid_id" ref="pcg_4426"/>
<field name="base_code_id" ref="vat_code_tvac_bazaTISC"/>
<field name="base_sign">1.00</field>
<field name="tax_code_id" ref="vat_code_tvac_tvaTISC"/>
<field name="tax_sign">1.00</field>
<field name="ref_base_code_id" ref="vat_code_tvac_bazaTISC"/>
<field name="ref_base_sign">-1.00</field>
<field name="ref_tax_code_id" ref="vat_code_tvac_tvaTISC"/>
<field name="ref_tax_sign">-1.00</field>
</record>
<record id="tvad_00" model="account.tax.template">
<field name="chart_template_id" ref="romania_chart_template"/>
<field name="name">TVA deductibil 0%</field>
<field name="amount">0.000000</field>
<field name="type">percent</field>
<field name="account_collected_id" ref="pcg_4426"/>
<field name="account_paid_id" ref="pcg_4426"/>
<field name="base_code_id" ref="vat_code_tvad_baza00"/>
<field name="base_sign">1.00</field>
<field name="tax_code_id" ref="vat_code_tvad_tva00"/>
<field name="tax_sign">1.00</field>
<field name="ref_base_code_id" ref="vat_code_tvad_baza00"/>
<field name="ref_base_sign">-1.00</field>
<field name="ref_tax_code_id" ref="vat_code_tvad_tva00"/>
<field name="ref_tax_sign">-1.00</field>
</record>
<record id="tvad_05" model="account.tax.template">
<field name="chart_template_id" ref="romania_chart_template"/>
<field name="name">TVA deductibil 5%</field>
<field name="amount">0.050000</field>
<field name="type">percent</field>
<field name="account_collected_id" ref="pcg_4426"/>
<field name="account_paid_id" ref="pcg_4426"/>
<field name="base_code_id" ref="vat_code_tvad_baza05"/>
<field name="tax_code_id" ref="vat_code_tvad_tva05"/>
<field name="ref_base_code_id" ref="vat_code_tvad_baza05"/>
<field name="ref_tax_code_id" ref="vat_code_tvad_tva05"/>
<field name="ref_base_sign">-1.00</field>
<field name="ref_tax_sign">-1.00</field>
<field name="base_sign">1.00</field>
<field name="tax_sign">1.00</field>
</record>
<record id="tvad_09" model="account.tax.template">
<field name="chart_template_id" ref="romania_chart_template"/>
<field name="name">TVA deductibil 9%</field>
<field name="amount">0.090000</field>
<field name="type">percent</field>
<field name="account_collected_id" ref="pcg_4426"/>
<field name="account_paid_id" ref="pcg_4426"/>
<field name="base_code_id" ref="vat_code_tvad_baza09"/>
<field name="tax_code_id" ref="vat_code_tvad_tva09"/>
<field name="ref_base_code_id" ref="vat_code_tvad_baza09"/>
<field name="ref_tax_code_id" ref="vat_code_tvad_tva09"/>
<field name="ref_base_sign">-1.00</field>
<field name="ref_tax_sign">-1.00</field>
<field name="base_sign">1.00</field>
<field name="tax_sign">1.00</field>
</record>
<record id="tvad_19" model="account.tax.template">
<field name="chart_template_id" ref="romania_chart_template"/>
<field name="name">TVA deductibil 19%</field>
<field name="amount">0.190000</field>
<field name="type">percent</field>
<field name="account_collected_id" ref="pcg_4426"/>
<field name="account_paid_id" ref="pcg_4426"/>
<field name="base_code_id" ref="vat_code_tvad_baza19"/>
<field name="tax_code_id" ref="vat_code_tvad_tva19"/>
<field name="ref_base_code_id" ref="vat_code_tvad_baza19"/>
<field name="ref_tax_code_id" ref="vat_code_tvad_tva19"/>
<field name="ref_base_sign">-1.00</field>
<field name="ref_tax_sign">-1.00</field>
<field name="base_sign">1.00</field>
<field name="tax_sign">1.00</field>
</record>
<record id="tvad_24" model="account.tax.template">
<field name="chart_template_id" ref="romania_chart_template"/>
<field name="name">TVA deductibil 24%</field>
<field name="amount">0.240000</field>
<field name="type">percent</field>
<field name="account_collected_id" ref="pcg_4426"/>
<field name="account_paid_id" ref="pcg_4426"/>
<field name="base_code_id" ref="vat_code_tvad_baza24"/>
<field name="tax_code_id" ref="vat_code_tvad_tva24"/>
<field name="ref_base_code_id" ref="vat_code_tvad_baza24"/>
<field name="ref_tax_code_id" ref="vat_code_tvad_tva24"/>
<field name="ref_base_sign">-1.00</field>
<field name="ref_tax_sign">-1.00</field>
<field name="base_sign">1.00</field>
<field name="tax_sign">1.00</field>
</record>
<record id="tvatine" model="account.tax.template">
<field name="chart_template_id" ref="ro_chart_template"/>
<field name="name">TVA Taxare Intracomunitara Neimpozabila</field>
<field name="amount">0.000000</field>
<field name="type">percent</field>
<field name="type_tax_use">all</field>
<field name="account_collected_id" ref="pcg_4426"/>
<field name="account_paid_id" ref="pcg_4426"/>
<field name="base_code_id" ref="vat_code_tvac_bazaTINE"/>
<field name="base_sign">1.00</field>
<field name="tax_code_id" ref="vat_code_tvac_tvaTINE"/>
<field name="tax_sign">1.00</field>
<field name="ref_base_code_id" ref="vat_code_tvac_bazaTINE"/>
<field name="ref_base_sign">-1.00</field>
<field name="ref_tax_code_id" ref="vat_code_tvac_tvaTINE"/>
<field name="ref_tax_sign">-1.00</field>
</record>
</data>
</openerp>

View File

@ -0,0 +1,389 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="0">
<!-- Fiscal Position Templates -->
<record id="fiscal_position_template_1" model="account.fiscal.position.template">
<field name="name">Regim National</field>
<field name="chart_template_id" ref="ro_chart_template"/>
</record>
<record id="fiscal_position_template_2" model="account.fiscal.position.template">
<field name="name">Regim Taxare Inversa</field>
<field name="chart_template_id" ref="ro_chart_template"/>
</record>
<record id="fiscal_position_template_3" model="account.fiscal.position.template">
<field name="name">Regim Intra-Comunitar Bunuri</field>
<field name="chart_template_id" ref="ro_chart_template"/>
</record>
<record id="fiscal_position_template_4" model="account.fiscal.position.template">
<field name="name">Regim Intra-Comunitar Servicii</field>
<field name="chart_template_id" ref="ro_chart_template"/>
</record>
<record id="fiscal_position_template_5" model="account.fiscal.position.template">
<field name="name">Regim Intra-Comunitar Scutite</field>
<field name="chart_template_id" ref="ro_chart_template"/>
</record>
<record id="fiscal_position_template_6" model="account.fiscal.position.template">
<field name="name">Regim Intra-Comunitar Neimpozabile</field>
<field name="chart_template_id" ref="ro_chart_template"/>
</record>
<record id="fiscal_position_template_7" model="account.fiscal.position.template">
<field name="name">Regim Extra-Comunitar</field>
<field name="chart_template_id" ref="ro_chart_template"/>
</record>
<!-- account.fiscal.position.tax.template -->
<!-- Inverse taxation -->
<!-- Sales -->
<record id="afptt_inverse_1" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_2"/>
<field name="tax_src_id" ref="tvac_00"/>
<field name="tax_dest_id" ref="tvati"/>
</record>
<record id="afptt_inverse_2" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_2"/>
<field name="tax_src_id" ref="tvac_05"/>
<field name="tax_dest_id" ref="tvati"/>
</record>
<record id="afptt_inverse_3" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_2"/>
<field name="tax_src_id" ref="tvac_09"/>
<field name="tax_dest_id" ref="tvati"/>
</record>
<record id="afptt_inverse_4" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_2"/>
<field name="tax_src_id" ref="tvac_19"/>
<field name="tax_dest_id" ref="tvati"/>
</record>
<record id="afptt_inverse_5" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_2"/>
<field name="tax_src_id" ref="tvac_24"/>
<field name="tax_dest_id" ref="tvati"/>
</record>
<!-- Purchases -->
<record id="afptt_inverse_6" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_2"/>
<field name="tax_src_id" ref="tvad_00"/>
<field name="tax_dest_id" ref="tvad_00"/>
</record>
<record id="afptt_inverse_7" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_2"/>
<field name="tax_src_id" ref="tvad_00"/>
<field name="tax_dest_id" ref="tvac_00"/>
</record>
<record id="afptt_inverse_8" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_2"/>
<field name="tax_src_id" ref="tvad_05"/>
<field name="tax_dest_id" ref="tvad_05"/>
</record>
<record id="afptt_inverse_9" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_2"/>
<field name="tax_src_id" ref="tvad_05"/>
<field name="tax_dest_id" ref="tvac_05"/>
</record>
<record id="afptt_inverse_10" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_2"/>
<field name="tax_src_id" ref="tvad_09"/>
<field name="tax_dest_id" ref="tvad_09"/>
</record>
<record id="afptt_inverse_11" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_2"/>
<field name="tax_src_id" ref="tvad_09"/>
<field name="tax_dest_id" ref="tvac_09"/>
</record>
<record id="afptt_inverse_12" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_2"/>
<field name="tax_src_id" ref="tvad_19"/>
<field name="tax_dest_id" ref="tvad_19"/>
</record>
<record id="afptt_inverse_13" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_2"/>
<field name="tax_src_id" ref="tvad_19"/>
<field name="tax_dest_id" ref="tvac_19"/>
</record>
<record id="afptt_inverse_14" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_2"/>
<field name="tax_src_id" ref="tvad_24"/>
<field name="tax_dest_id" ref="tvad_24"/>
</record>
<record id="afptt_inverse_15" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_2"/>
<field name="tax_src_id" ref="tvad_24"/>
<field name="tax_dest_id" ref="tvac_24"/>
</record>
<!-- Intracomunitar Bunuri -->
<!-- Sales -->
<record id="afptt_intracom_1" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_3"/>
<field name="tax_src_id" ref="tvac_00"/>
<field name="tax_dest_id" ref="tvati"/>
</record>
<record id="afptt_intracom_2" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_3"/>
<field name="tax_src_id" ref="tvac_05"/>
<field name="tax_dest_id" ref="tvati"/>
</record>
<record id="afptt_intracom_3" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_3"/>
<field name="tax_src_id" ref="tvac_09"/>
<field name="tax_dest_id" ref="tvati"/>
</record>
<record id="afptt_intracom_4" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_3"/>
<field name="tax_src_id" ref="tvac_19"/>
<field name="tax_dest_id" ref="tvati"/>
</record>
<record id="afptt_intracom_5" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_3"/>
<field name="tax_src_id" ref="tvac_24"/>
<field name="tax_dest_id" ref="tvati"/>
</record>
<!-- Purchases -->
<record id="afptt_intracom_6" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_3"/>
<field name="tax_src_id" ref="tvad_00"/>
<field name="tax_dest_id" ref="tvad_00"/>
</record>
<record id="afptt_intracom_7" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_3"/>
<field name="tax_src_id" ref="tvad_00"/>
<field name="tax_dest_id" ref="tvac_00"/>
</record>
<record id="afptt_intracom_8" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_3"/>
<field name="tax_src_id" ref="tvad_05"/>
<field name="tax_dest_id" ref="tvad_05"/>
</record>
<record id="afptt_intracom_9" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_3"/>
<field name="tax_src_id" ref="tvad_05"/>
<field name="tax_dest_id" ref="tvac_05"/>
</record>
<record id="afptt_intracom_10" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_3"/>
<field name="tax_src_id" ref="tvad_09"/>
<field name="tax_dest_id" ref="tvad_09"/>
</record>
<record id="afptt_intracom_11" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_3"/>
<field name="tax_src_id" ref="tvad_09"/>
<field name="tax_dest_id" ref="tvac_09"/>
</record>
<record id="afptt_intracom_12" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_3"/>
<field name="tax_src_id" ref="tvad_19"/>
<field name="tax_dest_id" ref="tvad_19"/>
</record>
<record id="afptt_intracom_13" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_3"/>
<field name="tax_src_id" ref="tvad_19"/>
<field name="tax_dest_id" ref="tvac_19"/>
</record>
<record id="afptt_intracom_14" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_3"/>
<field name="tax_src_id" ref="tvad_24"/>
<field name="tax_dest_id" ref="tvad_24"/>
</record>
<record id="afptt_intracom_15" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_3"/>
<field name="tax_src_id" ref="tvad_24"/>
<field name="tax_dest_id" ref="tvac_24"/>
</record>
<!-- Intracomunitar Servicii -->
<!-- Sales -->
<record id="afptt_intracoms_1" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_4"/>
<field name="tax_src_id" ref="tvac_00"/>
<field name="tax_dest_id" ref="tvati"/>
</record>
<record id="afptt_intracoms_2" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_4"/>
<field name="tax_src_id" ref="tvac_05"/>
<field name="tax_dest_id" ref="tvati"/>
</record>
<record id="afptt_intracoms_3" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_4"/>
<field name="tax_src_id" ref="tvac_09"/>
<field name="tax_dest_id" ref="tvati"/>
</record>
<record id="afptt_intracoms_4" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_4"/>
<field name="tax_src_id" ref="tvac_19"/>
<field name="tax_dest_id" ref="tvati"/>
</record>
<record id="afptt_intracoms_5" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_4"/>
<field name="tax_src_id" ref="tvac_24"/>
<field name="tax_dest_id" ref="tvati"/>
</record>
<!-- Purchases -->
<record id="afptt_intracoms_6" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_4"/>
<field name="tax_src_id" ref="tvad_00"/>
<field name="tax_dest_id" ref="tvad_00"/>
</record>
<record id="afptt_intracoms_7" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_4"/>
<field name="tax_src_id" ref="tvad_00"/>
<field name="tax_dest_id" ref="tvac_00"/>
</record>
<record id="afptt_intracoms_8" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_4"/>
<field name="tax_src_id" ref="tvad_05"/>
<field name="tax_dest_id" ref="tvad_05"/>
</record>
<record id="afptt_intracoms_9" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_4"/>
<field name="tax_src_id" ref="tvad_05"/>
<field name="tax_dest_id" ref="tvac_05"/>
</record>
<record id="afptt_intracoms_10" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_4"/>
<field name="tax_src_id" ref="tvad_09"/>
<field name="tax_dest_id" ref="tvad_09"/>
</record>
<record id="afptt_intracoms_11" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_4"/>
<field name="tax_src_id" ref="tvad_09"/>
<field name="tax_dest_id" ref="tvac_09"/>
</record>
<record id="afptt_intracoms_12" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_4"/>
<field name="tax_src_id" ref="tvad_19"/>
<field name="tax_dest_id" ref="tvad_19"/>
</record>
<record id="afptt_intracoms_13" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_4"/>
<field name="tax_src_id" ref="tvad_19"/>
<field name="tax_dest_id" ref="tvac_19"/>
</record>
<record id="afptt_intracoms_14" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_4"/>
<field name="tax_src_id" ref="tvad_24"/>
<field name="tax_dest_id" ref="tvad_24"/>
</record>
<record id="afptt_intracoms_15" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_4"/>
<field name="tax_src_id" ref="tvad_24"/>
<field name="tax_dest_id" ref="tvac_24"/>
</record>
<!-- Intracomunitar Scutite -->
<!-- Sales -->
<record id="afptt_intracomsc_1" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_5"/>
<field name="tax_src_id" ref="tvac_00"/>
<field name="tax_dest_id" ref="tvatisc"/>
</record>
<record id="afptt_intracomsc_2" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_5"/>
<field name="tax_src_id" ref="tvac_05"/>
<field name="tax_dest_id" ref="tvatisc"/>
</record>
<record id="afptt_intracomsc_3" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_5"/>
<field name="tax_src_id" ref="tvac_09"/>
<field name="tax_dest_id" ref="tvatisc"/>
</record>
<record id="afptt_intracomsc_4" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_5"/>
<field name="tax_src_id" ref="tvac_19"/>
<field name="tax_dest_id" ref="tvatisc"/>
</record>
<record id="afptt_intracomsc_5" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_5"/>
<field name="tax_src_id" ref="tvac_24"/>
<field name="tax_dest_id" ref="tvatisc"/>
</record>
<!-- Purchases -->
<record id="afptt_intracomsc_6" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_5"/>
<field name="tax_src_id" ref="tvad_00"/>
<field name="tax_dest_id" ref="tvatisc"/>
</record>
<record id="afptt_intracomsc_7" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_5"/>
<field name="tax_src_id" ref="tvad_05"/>
<field name="tax_dest_id" ref="tvatisc"/>
</record>
<record id="afptt_intracomsc_8" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_5"/>
<field name="tax_src_id" ref="tvad_09"/>
<field name="tax_dest_id" ref="tvatisc"/>
</record>
<record id="afptt_intracomsc_9" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_5"/>
<field name="tax_src_id" ref="tvad_19"/>
<field name="tax_dest_id" ref="tvatisc"/>
</record>
<record id="afptt_intracomsc_10" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_5"/>
<field name="tax_src_id" ref="tvad_24"/>
<field name="tax_dest_id" ref="tvatisc"/>
</record>
<!-- Taxare Inversa - Neimpozabile -->
<!-- Sales -->
<record id="afptt_intracomne_1" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_6"/>
<field name="tax_src_id" ref="tvac_00"/>
<field name="tax_dest_id" ref="tvatine"/>
</record>
<record id="afptt_intracomne_2" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_6"/>
<field name="tax_src_id" ref="tvac_05"/>
<field name="tax_dest_id" ref="tvatine"/>
</record>
<record id="afptt_intracomne_3" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_6"/>
<field name="tax_src_id" ref="tvac_09"/>
<field name="tax_dest_id" ref="tvatine"/>
</record>
<record id="afptt_intracomne_4" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_6"/>
<field name="tax_src_id" ref="tvac_19"/>
<field name="tax_dest_id" ref="tvatine"/>
</record>
<record id="afptt_intracomne_5" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_6"/>
<field name="tax_src_id" ref="tvac_24"/>
<field name="tax_dest_id" ref="tvatine"/>
</record>
<!-- Purchases -->
<record id="afptt_intracomne_6" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_6"/>
<field name="tax_src_id" ref="tvad_00"/>
<field name="tax_dest_id" ref="tvatine"/>
</record>
<record id="afptt_intracomne_7" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_6"/>
<field name="tax_src_id" ref="tvad_05"/>
<field name="tax_dest_id" ref="tvatine"/>
</record>
<record id="afptt_intracomne_8" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_6"/>
<field name="tax_src_id" ref="tvad_09"/>
<field name="tax_dest_id" ref="tvatine"/>
</record>
<record id="afptt_intracomne_9" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_6"/>
<field name="tax_src_id" ref="tvad_19"/>
<field name="tax_dest_id" ref="tvatine"/>
</record>
<record id="afptt_intracomne_10" model="account.fiscal.position.tax.template">
<field name="position_id" ref="fiscal_position_template_6"/>
<field name="tax_src_id" ref="tvad_24"/>
<field name="tax_dest_id" ref="tvatine"/>
</record>
</data>
</openerp>

View File

@ -1,5 +1,6 @@
<openerp>
<data noupdate="1">
<record id="account.action_wizard_multi_chart_todo" model="ir.actions.todo">
<field name="state">open</field>
</record>

6
addons/l10n_ro/partner_view.xml Normal file → Executable file
View File

@ -3,12 +3,12 @@
<data>
<record model="ir.ui.view" id="res_partner_form_ro">
<field name="name">res.partner.form.ro</field>
<field name="inherit_id" ref="base_vat.view_partner_form"/>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="model">res.partner</field>
<field name="arch" type="xml">
<xpath expr="//div[@name='vat_info']" position="after">
<field name="property_account_position" position="after">
<field name="nrc" placeholder="e.g. J12/1234/2012" class="oe_inline"/>
</xpath>
</field>
</field>
</record>
</data>

30
addons/l10n_ro/res_partner.py Normal file → Executable file
View File

@ -1,8 +1,9 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2012 (<http://www.erpsystems.ro>). All Rights Reserved
# @author - Fekete Mihai <feketemihai@gmail.com>
# Copyright (C) 2011 TOTAL PC SYSTEMS (http://www.www.erpsystems.ro).
# Copyright (C) 2009 (<http://www.filsystem.ro>)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -25,34 +26,23 @@ class res_partner(osv.osv):
_name = "res.partner"
_inherit = "res.partner"
_columns = {
'nrc' : fields.char('NRC', size=16, help='Registration number at the Registry of Commerce'),
'nrc' : fields.char('NRC', help='Registration number at the Registry of Commerce'),
}
# The SQL constraints are no-ops but present only to display the right error message to the
# user when the partial unique indexes defined below raise errors/
# The real constraints need to be implemented with PARTIAL UNIQUE INDEXES (see auto_init),
# due to the way accounting data is delegated by contacts to their companies in OpenERP 7.0.
_sql_constraints = [
('vat_uniq', 'unique (id)', 'The vat of the partner must be unique !'),
('nrc_uniq', 'unique (id)', 'The code of the partner must be unique !')
]
def _auto_init(self, cr, context=None):
result = super(res_partner, self)._auto_init(cr, context=context)
# Real implementation of the vat/nrc constraints: only "commercial entities" need to have
# unique numbers, and the condition for being a commercial entity is "is_company or parent_id IS NULL".
# Contacts inside a company automatically have a copy of the company's commercial fields
# (see _commercial_fields()), so they are automatically consistent.
# Remove constrains for vat, nrc on "commercial entities" because is not mandatory by legislation
# Even that VAT numbers are unique, the NRC field is not unique, and there are certain entities that
# doesn't have a NRC number plus the formatting was changed few times, so we cannot have a base rule for
# checking if available and emmited by the Ministry of Finance, only online on their website.
cr.execute("""
DROP INDEX IF EXISTS res_partner_vat_uniq_for_companies;
DROP INDEX IF EXISTS res_partner_nrc_uniq_for_companies;
CREATE UNIQUE INDEX res_partner_vat_uniq_for_companies ON res_partner (vat) WHERE is_company OR parent_id IS NULL;
CREATE UNIQUE INDEX res_partner_nrc_uniq_for_companies ON res_partner (nrc) WHERE is_company OR parent_id IS NULL;
""")
return result
def _commercial_fields(self, cr, uid, context=None):
return super(res_partner, self)._commercial_fields(cr, uid, context=context) + ['nrc']
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -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', '&lt;=', 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','&lt;&gt;',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', '&lt;=', 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">

View File

@ -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,

View File

@ -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', '&lt;=', 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>

View File

@ -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>

View File

@ -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', '&lt;=', 1)]"/>
</search>
</field>
</record>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -50,7 +50,12 @@ class ReportController(Controller):
if data.get('options'):
options_data = simplejson.loads(data['options'])
if data.get('context'):
context.update(simplejson.loads(data['context']))
# Ignore 'lang' here, because the context in data is the one from the webclient *but* if
# the user explicitely wants to change the lang, this mechanism overwrites it.
data_context = simplejson.loads(data['context'])
if data_context.get('lang'):
del data_context['lang']
context.update(data_context)
if converter == 'html':
html = report_obj.get_html(cr, uid, docids, reportname, data=options_data, context=context)

View File

@ -34,10 +34,8 @@ import lxml.html
import cStringIO
import subprocess
from distutils.version import LooseVersion
try:
from pyPdf import PdfFileWriter, PdfFileReader
except ImportError:
PdfFileWriter = PdfFileReader = None
from functools import partial
from pyPdf import PdfFileWriter, PdfFileReader
_logger = logging.getLogger(__name__)
@ -71,23 +69,6 @@ class Report(osv.Model):
public_user = None
MINIMAL_HTML_PAGE = """
<base href="{base_url}">
<!DOCTYPE html>
<html style="height: 0;">
<head>
<link href="/report/static/src/css/reset.min.css" rel="stylesheet"/>
<link href="/web/static/lib/bootstrap/css/bootstrap.css" rel="stylesheet"/>
<link href="/website/static/src/css/website.css" rel="stylesheet"/>
<link href="/web/static/lib/fontawesome/css/font-awesome.css" rel="stylesheet"/>
<style type='text/css'>{css}</style>
{subst}
</head>
<body class="container" onload="subst()">
{body}
</body>
</html>"""
#--------------------------------------------------------------------------
# Extension of ir_ui_view.render with arguments frequently used in reports
#--------------------------------------------------------------------------
@ -133,7 +114,9 @@ class Report(osv.Model):
user = self.pool['res.users'].browse(cr, uid, uid)
website = None
if request and hasattr(request, 'website'):
website = request.website
if request.website is not None:
website = request.website
context.update(translatable=context.get('lang') != request.website.default_lang_code)
values.update(
time=time,
translate_doc=translate_doc,
@ -141,7 +124,7 @@ class Report(osv.Model):
user=user,
res_company=user.company_id,
website=website,
editable_no_editor=True,
editable_no_editor=_("The preferred way to edit a report is to use the HTML Editor"),
)
return view_obj.render(cr, uid, template, values, context=context)
@ -191,13 +174,16 @@ class Report(osv.Model):
paperformat = report.paperformat_id
# Preparing the minimal html pages
subst = "<script src='/report/static/src/js/subst.js'></script> "
css = '' # Will contain local css
headerhtml = []
contenthtml = []
footerhtml = []
base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url')
# Minimal page renderer
view_obj = self.pool['ir.ui.view']
render_minimal = partial(view_obj.render, cr, uid, 'report.minimal_layout', context=context)
# The received html report must be simplified. We convert it in a xml tree
# in order to extract headers, bodies and footers.
try:
@ -208,12 +194,12 @@ class Report(osv.Model):
for node in root.xpath("//div[@class='header']"):
body = lxml.html.tostring(node)
header = self.MINIMAL_HTML_PAGE.format(css=css, subst=subst, body=body, base_url=base_url)
header = render_minimal(dict(css=css, subst=True, body=body, base_url=base_url))
headerhtml.append(header)
for node in root.xpath("//div[@class='footer']"):
body = lxml.html.tostring(node)
footer = self.MINIMAL_HTML_PAGE.format(css=css, subst=subst, body=body, base_url=base_url)
footer = render_minimal(dict(css=css, subst=True, body=body, base_url=base_url))
footerhtml.append(footer)
for node in root.xpath("//div[@class='page']"):
@ -230,7 +216,7 @@ class Report(osv.Model):
reportid = False
body = lxml.html.tostring(node)
reportcontent = self.MINIMAL_HTML_PAGE.format(css=css, subst='', body=body, base_url=base_url)
reportcontent = render_minimal(dict(css=css, subst=False, body=body, base_url=base_url))
# FIXME: imo the best way to extract record id from html reports is by using the
# qweb branding. As website editor is not yet splitted in a module independant from
@ -254,11 +240,10 @@ class Report(osv.Model):
specific_paperformat_args[attribute[0]] = attribute[1]
# Run wkhtmltopdf process
pdf = self._generate_wkhtml_pdf(
return self._run_wkhtmltopdf(
cr, uid, headerhtml, footerhtml, contenthtml, context.get('landscape'),
paperformat, specific_paperformat_args, save_in_attachment
)
return pdf
def get_action(self, cr, uid, ids, report_name, data=None, context=None):
"""Return an action of type ir.actions.report.xml.
@ -329,7 +314,7 @@ class Report(osv.Model):
def _check_wkhtmltopdf(self):
return wkhtmltopdf_state
def _generate_wkhtml_pdf(self, cr, uid, headers, footers, bodies, landscape, paperformat, spec_paperformat_args=None, save_in_attachment=None):
def _run_wkhtmltopdf(self, cr, uid, headers, footers, bodies, landscape, paperformat, spec_paperformat_args=None, save_in_attachment=None):
"""Execute wkhtmltopdf as a subprocess in order to convert html given in input into a pdf
document.

View File

@ -1,55 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<template id="layout" inherit_id="web.layout" primary="True">
<!-- Add report attributes -->
<xpath expr="//html" position="attributes">
<attribute name="t-att-data-report-margin-top">data_report_margin_top if data_report_margin_top else None</attribute>
<attribute name="t-att-data-report-header-spacing">data_report_header_spacing if data_report_header_spacing else None</attribute>
<attribute name="t-att-data-report-dpi">data_report_dpi if data_report_dpi else None</attribute>
</xpath>
<!-- Add report style -->
<xpath expr="//head" position="inside">
<link href="/web/static/lib/bootstrap/css/bootstrap.css" rel="stylesheet"/>
<link href="/website/static/src/css/website.css" rel="stylesheet"/>
<link href="/web/static/lib/fontawesome/css/font-awesome.css" rel="stylesheet"/>
<style type="text/css">
<t t-call="report.style"/>
</style>
</xpath>
<!-- Remove conflicting style -->
<xpath expr="//head/link[@href='/web/static/src/css/full.css']" position="replace"></xpath>
</template>
<template id="html_container">
&lt;!DOCTYPE html&gt;
<html t-att-lang="lang and lang.replace('_', '-')"
t-att-data-editable="'1' if editable else None"
t-att-data-view-xmlid="xmlid if editable else None"
t-att-data-main-object="repr(main_object) if editable else None"
t-att-data-report-margin-top="data_report_margin_top if data_report_margin_top else None"
t-att-data-report-header-spacing="data_report_header_spacing if data_report_header_spacing else None"
t-att-data-report-dpi="data_report_dpi if data_report_dpi else None"
t-att-data-oe-company-name="res_company.name">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<t t-if="main_object and 'website_meta_title' in main_object">
<t t-set="title" t-value="main_object.website_meta_title"/>
</t>
<t t-if="not title and main_object and 'name' in main_object">
<t t-set="additional_title" t-value="main_object.name"/>
</t>
<meta name="description" t-att-value="main_object and 'website_meta_description' in main_object
and main_object.website_meta_description or website_meta_description"/>
<meta name="keywords" t-att-value="main_object and 'website_meta_keywords' in main_object
and main_object.website_meta_keywords or website_meta_keywords"/>
<link id="bootstrap_css" rel='stylesheet' href='/web/static/lib/bootstrap/css/bootstrap.css' t-ignore="true"/>
<link rel="stylesheet" type="text/css" href='/website/static/src/css/website.css'/>
<style type="text/css">
<t t-call="report.style"/>
</style>
<link rel='stylesheet' href='/web/static/lib/fontawesome/css/font-awesome.css'/>
<script type="text/javascript" src="/web/static/lib/es5-shim/es5-shim.min.js"></script>
<script type="text/javascript" src="/web/static/lib/underscore/underscore.js"></script>
<script type="text/javascript" src="/web/static/lib/underscore.string/lib/underscore.string.js"></script>
<script type="text/javascript" src="/web/static/lib/jquery/jquery.js"></script>
<script type="text/javascript" src="/web/static/lib/bootstrap/js/bootstrap.js"></script>
<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="/website/static/src/js/website.js"></script>
<script t-if="not translatable" type="text/javascript" src="/website/static/src/js/website.snippets.animation.js"></script>
<t t-raw="head or ''" name='layout_head'/>
</head>
<body class="container">
<div id="wrapwrap">
<t t-raw="0"/>
</div>
</body>
</html>
<t t-set="body_classname" t-value="'container'"/>
<t t-call="report.layout">
<t t-raw="0"/>
</t>
</template>
<template id="style">
@ -164,5 +140,25 @@
<t t-raw="0" />
</template>
<template id="minimal_layout">
<t t-raw="'&lt;base href=%s&gt;' % base_url"/>
&lt;!DOCTYPE html&gt;
<html style="height: 0;">
<head>
<link href="/report/static/src/css/reset.min.css" rel="stylesheet"/>
<link href="/web/static/lib/bootstrap/css/bootstrap.css" rel="stylesheet"/>
<link href="/website/static/src/css/website.css" rel="stylesheet"/>
<link href="/web/static/lib/fontawesome/css/font-awesome.css" rel="stylesheet"/>
<style type='text/css'><t t-raw="css"/></style>
<t t-if="subst is True">
<script src='/report/static/src/js/subst.js'></script>
</t>
</head>
<body class="container" onload="subst()">
<t t-raw="body"/>
</body>
</html>
</template>
</data>
</openerp>

View File

@ -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','&lt;=', time.strftime('%%Y-12-31')),('date','&gt;=',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>

View File

@ -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>

View File

@ -65,7 +65,7 @@
<tbody class="sale_tbody">
<tr t-foreach="o.order_line" t-as="l">
<td>
<span t-field="l.name"/>
<span t-field="l.name"/>
</td>
<td>
<span t-esc="', '.join(map(lambda x: x.name, l.tax_id))"/>

View File

@ -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>

View File

@ -1564,6 +1564,52 @@
-webkit-border-radius: 2px;
border-radius: 2px;
}
.openerp .oe_searchview .oe-autocomplete {
display: none;
position: absolute;
width: 300px;
background-color: white;
border: 1px solid #afafb6;
z-index: 666;
margin-top: 2px;
cursor: default;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
-moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
-webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
}
.openerp .oe_searchview .oe-autocomplete ul {
list-style-type: none;
padding-left: 0;
margin: 5px 0px;
}
.openerp .oe_searchview .oe-autocomplete ul li {
padding-left: 20px;
text-shadow: 0 0 0 white;
}
.openerp .oe_searchview .oe-autocomplete ul li span:first-child {
margin-right: 5px;
}
.openerp .oe_searchview .oe-autocomplete ul li span.oe-expand {
cursor: pointer;
}
.openerp .oe_searchview .oe-autocomplete ul li.oe-indent {
margin-left: 20px;
}
.openerp .oe_searchview .oe-autocomplete ul li.oe-selection-focus {
background-color: #7c7bad;
color: white;
}
.openerp .oe_searchview .oe-autocomplete ul li.oe-separator {
margin-top: 2px;
margin-bottom: 2px;
border-top: 1px solid #afafb6;
}
.openerp .oe_searchview .oe-autocomplete ul li.oe-separator:last-child {
display: none;
}
.openerp .oe_searchview_drawer_container {
overflow: auto;
}

View File

@ -1289,6 +1289,41 @@ $sheet-padding: 16px
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.4)
@include radius(2px)
.oe-autocomplete
display: none
position: absolute
width: 300px
background-color: white
border: 1px solid #afafb6
z-index: 666
margin-top: 2px
cursor: default
@include radius(3px)
@include box-shadow(0 1px 4px rgba(0, 0, 0, 0.3))
ul
list-style-type: none
padding-left: 0
margin: 5px 0px
li
padding-left: 20px
text-shadow: 0 0 0 white
span:first-child
margin-right: 5px
span.oe-expand
cursor: pointer
li.oe-indent
margin-left: 20px
li.oe-selection-focus
background-color: #7c7bad
color: white
li.oe-separator
margin-top: 2px
margin-bottom: 2px
border-top: 1px solid #afafb6
li.oe-separator:last-child
display: none
.oe_searchview_drawer_container
overflow: auto
.oe_searchview_drawer

View File

@ -1377,7 +1377,6 @@ instance.web.WebClient = instance.web.Client.extend({
var state = event.getState(true);
if(!state.action && state.menu_id) {
self.menu.is_bound.done(function() {
self.menu.do_reload();
self.menu.menu_click(state.menu_id);
});
} else {

View File

@ -350,7 +350,9 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
e.preventDefault();
break;
case $.ui.keyCode.RIGHT:
this.focusFollowing(e.target);
if (!this.autocomplete.is_expandable()) {
this.focusFollowing(e.target);
}
e.preventDefault();
break;
}
@ -484,53 +486,18 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
* Sets up search view's view-wide auto-completion widget
*/
setup_global_completion: function () {
var autocomplete = this.$el.autocomplete({
var self = this;
this.autocomplete = new instance.web.search.AutoComplete(this, {
source: this.proxy('complete_global_search'),
select: this.proxy('select_completion'),
focus: function (e) { e.preventDefault(); },
html: true,
autoFocus: true,
minLength: 1,
delay: 250,
}).data('autocomplete');
this.$el.on('input', function () {
this.$el.autocomplete('close');
}.bind(this));
// MonkeyPatch autocomplete instance
_.extend(autocomplete, {
_renderItem: function (ul, item) {
// item of completion list
var $item = $( "<li></li>" )
.data( "item.autocomplete", item )
.appendTo( ul );
if (item.facet !== undefined) {
// regular completion item
if (item.first) {
$item.css('borderTop', '1px solid #cccccc');
}
return $item.append(
(item.label)
? $('<a>').html(item.label)
: $('<a>').text(item.value));
}
return $item.text(item.label)
.css({
borderTop: '1px solid #cccccc',
margin: 0,
padding: 0,
zoom: 1,
'float': 'left',
clear: 'left',
width: '100%'
});
},
_value: function() {
delay: 0,
get_search_string: function () {
return self.$('div.oe_searchview_input').text();
},
width: this.$el.width(),
});
this.autocomplete.appendTo(this.$el);
},
/**
* Provide auto-completion result for req.term (an array to `resp`)
@ -546,12 +513,6 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
.value()).then(function () {
resp(_(arguments).chain()
.compact()
.map(function (completion) {
if (completion.length && completion[0].facet !== undefined) {
completion[0].first = true;
}
return completion;
})
.flatten(true)
.value());
});
@ -579,14 +540,9 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
childBlurred: function () {
var val = this.$el.val();
this.$el.val('');
var complete = this.$el.data('autocomplete');
if ((val && complete.term === undefined) || complete.previous) {
throw new Error("new jquery.ui version altering implementation" +
" details relied on");
}
delete complete.term;
this.$el.removeClass('oe_focused')
.trigger('blur');
this.autocomplete.close();
},
/**
* Call the renderFacets method with the correct arguments.
@ -846,13 +802,13 @@ instance.web.SearchViewDrawer = instance.web.Widget.extend({
var $first_col = this.$(".col-md-7"),
$snd_col = this.$(".col-md-5");
var add_custom_reports = in_drawer[0].appendTo($first_col),
var add_custom_filters = in_drawer[0].appendTo($first_col),
add_filters = in_drawer[1].appendTo($first_col),
add_rest = $.when.apply(null, _(in_drawer.slice(2)).invoke('appendTo', $snd_col)),
defaults_fetched = $.when.apply(null, _(this.inputs).invoke(
'facet_for_defaults', this.searchview.defaults));
return $.when(defaults_fetched, add_custom_reports, add_filters, add_rest);
return $.when(defaults_fetched, add_custom_filters, add_filters, add_rest);
},
/**
* Sets up thingie where all the mess is put?
@ -890,8 +846,10 @@ instance.web.SearchViewDrawer = instance.web.Widget.extend({
filters.push(new instance.web.search.Filter(item, group));
break;
case 'group':
self.add_separator();
self.make_widgets(item.children, fields,
new instance.web.search.Group(group, 'w', item));
self.add_separator();
break;
case 'field':
var field = this.make_field(
@ -907,6 +865,11 @@ instance.web.SearchViewDrawer = instance.web.Widget.extend({
group.push(new instance.web.search.FilterGroup(filters, this));
}
},
add_separator: function () {
if (!(_.last(this.inputs) instanceof instance.web.search.Separator))
new instance.web.search.Separator(this);
},
/**
* Creates a field for the provided field descriptor item (which comes
* from fields_view_get)
@ -937,7 +900,7 @@ instance.web.SearchViewDrawer = instance.web.Widget.extend({
add_common_inputs: function() {
// add custom filters to this.inputs
this.custom_filters = new instance.web.search.CustomReports(this);
this.custom_filters = new instance.web.search.CustomFilters(this);
// add Filters to this.inputs, need view.controls filled
(new instance.web.search.Filters(this));
(new instance.web.search.SaveFilter(this, this.custom_filters));
@ -1349,6 +1312,15 @@ instance.web.search.Filter = instance.web.search.Input.extend(/** @lends instanc
get_context: function () { },
get_domain: function () { },
});
instance.web.search.Separator = instance.web.search.Input.extend({
_in_drawer: false,
complete: function () {
return {is_separator: true};
}
});
instance.web.search.Field = instance.web.search.Input.extend( /** @lends instance.web.search.Field# */ {
template: 'SearchView.field',
default_operator: '=',
@ -1639,7 +1611,25 @@ instance.web.search.ManyToOneField = instance.web.search.CharField.extend({
this._super(view_section, field, parent);
this.model = new instance.web.Model(this.attrs.relation);
},
complete: function (needle) {
complete: function (value) {
if (_.isEmpty(value)) { return $.when(null); }
var label = _.str.sprintf(_.str.escapeHTML(
_t("Search %(field)s for: %(value)s")), {
field: '<em>' + _.escape(this.attrs.string) + '</em>',
value: '<strong>' + _.escape(value) + '</strong>'});
return $.when([{
label: label,
facet: {
category: this.attrs.string,
field: this,
values: [{label: value, value: value}]
},
expand: this.expand.bind(this),
}]);
},
expand: function (needle) {
var self = this;
// FIXME: "concurrent" searches (multiple requests, mis-ordered responses)
var context = instance.web.pyeval.eval(
@ -1652,13 +1642,12 @@ instance.web.search.ManyToOneField = instance.web.search.CharField.extend({
context: context
}).then(function (results) {
if (_.isEmpty(results)) { return null; }
return [{label: self.attrs.string}].concat(
_(results).map(function (result) {
return {
label: _.escape(result[1]),
facet: facet_from(self, result)
};
}));
return _(results).map(function (result) {
return {
label: _.escape(result[1]),
facet: facet_from(self, result)
};
});
});
},
facet_for: function (value) {
@ -1701,8 +1690,8 @@ instance.web.search.ManyToOneField = instance.web.search.CharField.extend({
}
});
instance.web.search.CustomReports = instance.web.search.Input.extend({
template: 'SearchView.CustomReports',
instance.web.search.CustomFilters = instance.web.search.Input.extend({
template: 'SearchView.Custom',
_in_drawer: true,
init: function () {
this.is_ready = $.Deferred();
@ -1721,11 +1710,15 @@ instance.web.search.CustomReports = instance.web.search.Input.extend({
self.clear_selection();
})
.on('reset', this.proxy('clear_selection'));
return this.model.call('get_filters', [this.view.model])
return this.model.call('get_filters', [this.view.model, this.get_action_id()])
.then(this.proxy('set_filters'))
.done(function () { self.is_ready.resolve(); })
.fail(function () { self.is_ready.reject.apply(self.is_ready, arguments); });
},
get_action_id: function(){
var action = instance.client.action_manager.inner_action;
if (action) return action.id;
},
/**
* Special implementation delaying defaults until CustomFilters is loaded
*/
@ -1745,9 +1738,11 @@ instance.web.search.CustomReports = instance.web.search.Input.extend({
* @return {String} mapping key corresponding to the filter
*/
key_for: function (filter) {
var user_id = filter.user_id;
var user_id = filter.user_id,
action_id = filter.action_id;
var uid = (user_id instanceof Array) ? user_id[0] : user_id;
return _.str.sprintf('(%s)%s', uid, filter.name);
var act_id = (action_id instanceof Array) ? action_id[0] : action_id;
return _.str.sprintf('(%s)(%s)%s', uid, act_id, filter.name);
},
/**
* Generates a :js:class:`~instance.web.search.Facet` descriptor from a
@ -1848,9 +1843,9 @@ instance.web.search.CustomReports = instance.web.search.Input.extend({
instance.web.search.SaveFilter = instance.web.search.Input.extend({
template: 'SearchView.SaveFilter',
_in_drawer: true,
init: function (parent, custom_reports) {
init: function (parent, custom_filters) {
this._super(parent);
this.custom_reports = custom_reports;
this.custom_filters = custom_filters;
},
start: function () {
var self = this;
@ -1894,13 +1889,14 @@ instance.web.search.SaveFilter = instance.web.search.Input.extend({
model_id: self.view.model,
context: results.context,
domain: results.domain,
is_default: set_as_default
is_default: set_as_default,
action_id: self.custom_filters.get_action_id()
};
// FIXME: current context?
return self.model.call('create_or_replace', [filter]).done(function (id) {
filter.id = id;
if (self.custom_reports) {
self.custom_reports.append_filter(filter);
if (self.custom_filters) {
self.custom_filters.append_filter(filter);
}
self.$el
.removeClass('oe_opened')
@ -2311,6 +2307,213 @@ instance.web.search.custom_filters = new instance.web.Registry({
'id': 'instance.web.search.ExtendedSearchProposition.Id'
});
instance.web.search.AutoComplete = instance.web.Widget.extend({
template: "SearchView.autocomplete",
// Parameters for autocomplete constructor:
//
// parent: this is used to detect keyboard events
//
// options.source: function ({term:query}, callback). This function will be called to
// obtain the search results corresponding to the query string. It is assumed that
// options.source will call callback with the results.
// options.delay: delay in millisecond before calling source. Useful if you don't want
// to make too many rpc calls
// options.select: function (ev, {item: {facet:facet}}). Autocomplete widget will call
// that function when a selection is made by the user
// options.get_search_string: function (). This function will be called by autocomplete
// to obtain the current search string.
init: function (parent, options) {
this._super(parent);
this.$input = parent.$el;
this.source = options.source;
this.delay = options.delay;
this.select = options.select,
this.get_search_string = options.get_search_string;
this.width = options.width || 400;
this.current_result = null;
this.searching = true;
this.search_string = null;
this.current_search = null;
},
start: function () {
var self = this;
this.$el.width(this.width);
this.$input.on('keyup', function (ev) {
if (ev.which === $.ui.keyCode.RIGHT) {
self.searching = true;
ev.preventDefault();
return;
}
if (!self.searching) {
self.searching = true;
return;
}
self.search_string = self.get_search_string();
if (self.search_string.length) {
var search_string = self.search_string;
setTimeout(function () { self.initiate_search(search_string);}, self.delay);
} else {
self.close();
}
});
this.$input.on('keydown', function (ev) {
switch (ev.which) {
case $.ui.keyCode.TAB:
case $.ui.keyCode.ENTER:
if (self.get_search_string().length) {
self.select_item(ev);
}
break;
case $.ui.keyCode.DOWN:
self.move('down');
self.searching = false;
ev.preventDefault();
break;
case $.ui.keyCode.UP:
self.move('up');
self.searching = false;
ev.preventDefault();
break;
case $.ui.keyCode.RIGHT:
self.searching = false;
var current = self.current_result
if (current && current.expand && !current.expanded) {
self.expand();
self.searching = true;
}
ev.preventDefault();
break;
case $.ui.keyCode.ESCAPE:
self.close();
self.searching = false;
break;
}
});
},
initiate_search: function (query) {
if (query === this.search_string && query !== this.current_search) {
this.search(query);
}
},
search: function (query) {
var self = this;
this.current_search = query;
this.source({term:query}, function (results) {
if (results.length) {
self.render_search_results(results);
self.focus_element(self.$('li:first-child'));
} else {
self.close();
}
});
},
render_search_results: function (results) {
var self = this;
var $list = this.$('ul');
$list.empty();
var render_separator = false;
results.forEach(function (result) {
if (result.is_separator) {
if (render_separator)
$list.append($('<li>').addClass('oe-separator'));
render_separator = false;
} else {
var $item = self.make_list_item(result).appendTo($list);
result.$el = $item;
render_separator = true;
}
});
this.show();
},
make_list_item: function (result) {
var self = this;
var $li = $('<li>')
.hover(function (ev) {self.focus_element($li);})
.mousedown(function (ev) {
if (ev.button === 0) { // left button
self.select(ev, {item: {facet: result.facet}});
self.close();
} else {
ev.preventDefault();
}
})
.data('result', result);
if (result.expand) {
var $expand = $('<span class="oe-expand">').text('▶').appendTo($li);
$expand.mousedown(function (ev) {
ev.preventDefault();
ev.stopPropagation();
if (result.expanded)
self.fold();
else
self.expand();
});
result.expanded = false;
}
if (result.indent) $li.addClass('oe-indent');
$li.append($('<span>').html(result.label));
return $li;
},
expand: function () {
var self = this;
this.current_result.expand(this.get_search_string()).then(function (results) {
(results || [{label: '(no result)'}]).reverse().forEach(function (result) {
result.indent = true;
var $li = self.make_list_item(result);
self.current_result.$el.after($li);
});
self.current_result.expanded = true;
self.current_result.$el.find('span.oe-expand').html('▼');
});
},
fold: function () {
var $next = this.current_result.$el.next();
while ($next.hasClass('oe-indent')) {
$next.remove();
$next = this.current_result.$el.next();
}
this.current_result.expanded = false;
this.current_result.$el.find('span.oe-expand').html('▶');
},
focus_element: function ($li) {
this.$('li').removeClass('oe-selection-focus');
$li.addClass('oe-selection-focus');
this.current_result = $li.data('result');
},
select_item: function (ev) {
if (this.current_result.facet) {
this.select(ev, {item: {facet: this.current_result.facet}});
this.close();
}
},
show: function () {
this.$el.show();
},
close: function () {
this.current_search = null;
this.search_string = null;
this.searching = true;
this.$el.hide();
},
move: function (direction) {
var $next;
if (direction === 'down') {
$next = this.$('li.oe-selection-focus').nextAll(':not(.oe-separator)').first();
if (!$next.length) $next = this.$('li:first-child');
} else {
$next = this.$('li.oe-selection-focus').prevAll(':not(.oe-separator)').first();
if (!$next.length) $next = this.$('li:not(.oe-separator)').last();
}
this.focus_element($next);
},
is_expandable: function () {
return !!this.$('.oe-selection-focus .oe-expand').length;
},
});
})();
// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:

View File

@ -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);

View File

@ -1653,9 +1653,9 @@
</div>
<div t-name="SearchView.CustomReports" class="oe_searchview_custom oe_searchview_section">
<div t-name="SearchView.Custom" class="oe_searchview_custom oe_searchview_section">
<dl class="dl-horizontal">
<dt><span class="oe_i">M</span> Custom Reports</dt>
<dt><span class="oe_i">M</span> Favorites</dt>
<dd><ul class="oe_searchview_custom_list"/></dd>
</dl>
</div>
@ -1720,6 +1720,10 @@
</select>
</t>
<div t-name="SearchView.autocomplete" class="oe-autocomplete">
<ul>
</ul>
</div>
<t t-name="ExportView">
<a id="exportview" href="javascript: void(0)" style="text-decoration: none;color: #3D3D3D;">Export</a>
</t>

View File

@ -171,6 +171,7 @@ var makeSearchView = function (instance, dummy_widget_attributes, defaults) {
dummy: {type: 'char', string: 'Dummy'}
};
};
instance.client = { action_manager: { inner_action: undefined } };
var dataset = new instance.web.DataSet(null, 'dummy.model');
var mock_parent = {getParent: function () {return null;}};
@ -558,7 +559,20 @@ openerp.testing.section('search.completions', {
new Date(2012, 4, 21, 21, 21, 21).getTime());
});
});
test("M2O", {asserts: 13}, function (instance, $s, mock) {
test("M2O complete", {asserts: 4}, function (instance, $s, mock) {
var view = {inputs: [], dataset: {get_context: function () {}}};
var f = new instance.web.search.ManyToOneField(
{attrs: {string: 'Dummy'}}, {relation: 'dummy.model'}, view);
return f.complete("bob")
.done(function (c) {
equal(c.length, 1, "should return one line");
var bob = c[0];
ok(bob.expand, "should return an expand callback");
ok(bob.facet, "should have a facet");
ok(bob.label, "should have a label");
});
});
test("M2O expand", {asserts: 11}, function (instance, $s, mock) {
mock('dummy.model:name_search', function (args, kwargs) {
deepEqual(args, []);
strictEqual(kwargs.name, 'bob');
@ -568,21 +582,18 @@ openerp.testing.section('search.completions', {
var view = {inputs: [], dataset: {get_context: function () {}}};
var f = new instance.web.search.ManyToOneField(
{attrs: {string: 'Dummy'}}, {relation: 'dummy.model'}, view);
return f.complete("bob")
return f.expand("bob")
.done(function (c) {
equal(c.length, 3, "should return results + title");
var title = c[0];
equal(title.label, f.attrs.string, "title should match field name");
ok(!title.facet, "title should not have a facet");
equal(c.length, 2, "should return results");
var f1 = new instance.web.search.Facet(c[1].facet);
equal(c[1].label, "choice 1");
var f1 = new instance.web.search.Facet(c[0].facet);
equal(c[0].label, "choice 1");
equal(f1.get('category'), f.attrs.string);
equal(f1.get('field'), f);
deepEqual(f1.values.toJSON(), [{label: 'choice 1', value: 42}]);
var f2 = new instance.web.search.Facet(c[2].facet);
equal(c[2].label, "choice @");
var f2 = new instance.web.search.Facet(c[1].facet);
equal(c[1].label, "choice @");
equal(f2.get('category'), f.attrs.string);
equal(f2.get('field'), f);
deepEqual(f2.values.toJSON(), [{label: 'choice @', value: 43}]);
@ -597,7 +608,7 @@ openerp.testing.section('search.completions', {
var view = {inputs: [], dataset: {get_context: function () {}}};
var f = new instance.web.search.ManyToOneField(
{attrs: {string: 'Dummy'}}, {relation: 'dummy.model'}, view);
return f.complete("bob")
return f.expand("bob")
.done(function (c) {
ok(!c, "no match should yield no completion");
});
@ -620,9 +631,9 @@ openerp.testing.section('search.completions', {
var f = new instance.web.search.ManyToOneField(
{attrs: {string: 'Dummy', domain: '[["foo", "=", "bar"]]'}},
{relation: 'dummy.model'}, view);
return f.complete("bob");
return f.expand("bob");
});
test("M2O custom operator", {asserts: 10}, function (instance, $s, mock) {
test("M2O custom operator", {asserts: 8}, function (instance, $s, mock) {
mock('dummy.model:name_search', function (args, kwargs) {
deepEqual(args, [], "should have no positional arguments");
// the operator is meant for the final search term generation, not the autocompletion
@ -635,15 +646,12 @@ openerp.testing.section('search.completions', {
{attrs: {string: 'Dummy', operator: 'ilike'}},
{relation: 'dummy.model'}, view);
return f.complete('bob')
return f.expand('bob')
.done(function (c) {
equal(c.length, 2, "should return result + title");
var title = c[0];
equal(title.label, f.attrs.string, "title should match field name");
ok(!title.facet, "title should not have a facet");
equal(c.length, 1, "should return result");
var f1 = new instance.web.search.Facet(c[1].facet);
equal(c[1].label, "Match");
var f1 = new instance.web.search.Facet(c[0].facet);
equal(c[0].label, "Match");
equal(f1.get('category'), f.attrs.string);
equal(f1.get('field'), f);
deepEqual(f1.values.toJSON(), [{label: 'Match', value: 42}]);
@ -1210,13 +1218,14 @@ openerp.testing.section('search.groupby', {
var view = makeSearchView(instance);
return view.appendTo($fix)
.done(function () {
// 3 filters, 3 filtergroups, 1 custom filter, 1 advanced, 1 Filters
// 3 filters, 3 filtergroups, 1 custom filter, 1 advanced, 1 Filters,
// and 1 SaveFilter widget
equal(view.drawer.inputs.length, 10, "should have 10 inputs total");
var groups = _.filter(view.drawer.inputs, function (f) {
return f instanceof instance.web.search.GroupbyGroup;
});
equal(groups.length, 3, "should have 3 GroupbyGroups");
groups[0].toggle(groups[0].filters[0]);
@ -1549,10 +1558,11 @@ openerp.testing.section('search.invisible', {
var done = $.Deferred();
view.complete_global_search({term: 'filter'}, function (compls) {
done.resolve();
strictEqual(compls.length, 2,
"should have 2 completions");
console.log("completions", compls);
strictEqual(compls.length, 5,
"should have 5 completions"); // 2 filters and 3 separators
deepEqual(_.pluck(compls, 'label'),
['Field 0', 'Filter on: Filter 0'],
[undefined, 'Field 0', 'Filter on: Filter 0', undefined, undefined],
"should complete on field 0 and filter 0");
});
return done;

View File

@ -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"/>
@ -184,7 +184,7 @@
<template id="web.menu_link">
<t t-set="debug_param" t-value="'?&amp;debug=' if debug else ''"/>
<a t-att-href="'/web%s#menu_id=%s&amp;action=%s' % (debug_param, menu['id'], menu['action'] and menu['action'].split(',')[1] or '')"
t-att-class="'oe_menu_toggler' if menu['children'] else 'oe_menu_leaf'"
t-att-class="'oe_menu_toggler' if menu.get('children') else 'oe_menu_leaf'"
t-att-data-menu="menu['id']"
t-att-data-action-model="menu['action'] and menu['action'].split(',')[0] or ''"
t-att-data-action-id="menu['action'] and menu['action'].split(',')[1] or ''">

View File

@ -151,7 +151,7 @@ class view(osv.osv):
user_id=self.pool.get("res.users").browse(cr, uid, uid),
translatable=context.get('lang') != request.website.default_lang_code,
editable=request.website.is_publisher(),
menu_data=self.pool['ir.ui.menu'].load_menus(cr, uid, context=context) if request.website.is_user() else None,
menu_data=self.pool['ir.ui.menu'].load_menus_root(cr, uid, context=context) if request.website.is_user() else None,
)
# add some values

View File

@ -244,7 +244,7 @@ class website(osv.osv):
return is_website_publisher
def is_user(self, cr, uid, ids, context=None):
return self.pool['res.users'].has_group(cr, request.uid, 'base.group_user')
return self.pool['res.users'].has_group(cr, uid, 'base.group_user')
def get_template(self, cr, uid, ids, template, context=None):
if isinstance(template, (int, long)):

View File

@ -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);

View File

@ -4,6 +4,7 @@
<!-- Front-end/Back-end integration -->
<template id="user_navbar" inherit_id="website.layout" groups="base.group_user">
<xpath expr="//body/div['id=wrawrap']" position="before">
<t t-if="website and menu_data">
<nav id="oe_main_menu_navbar" class="navbar navbar-inverse" role="navigation">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#oe_applications">
@ -79,6 +80,7 @@
</li>
</ul>
</nav>
</t>
</xpath>
</template>
</data>

View File

@ -57,7 +57,7 @@
<template id="layout" name="Main layout">&lt;!DOCTYPE html&gt;
<html t-att-lang="lang and lang.replace('_', '-')"
t-att-data-website-id="website.id if editable else None"
t-att-data-website-id="website.id if editable and website else None"
t-att-data-editable="'1' if editable else None"
t-att-data-editable-no-editor="editable_no_editor or None"
t-att-data-translatable="'1' if translatable else None"
@ -82,10 +82,10 @@
and main_object.website_meta_keywords or website_meta_keywords"/>
<title><t t-esc="title"/></title>
<t t-set="languages" t-value="website.get_languages()"/>
<t t-if="request.website_multilang">
<t t-set="languages" t-value="website.get_languages() if website else None"/>
<t t-if="request and request.website_multilang">
<t t-foreach="languages" t-as="lg">
<t t-set="force_lang" t-value="lg[0] if lg[0] != website.default_lang_code else None"/>
<t t-set="force_lang" t-value="lg[0] if website and lg[0] != website.default_lang_code else None"/>
<link rel="alternate" t-att-href="url_for(request.httprequest.path + '?' + keep_query(), lang=force_lang)" t-att-hreflang="lg[0].replace('_', '-').lower()" />
</t>
</t>
@ -150,7 +150,7 @@
</div>
</footer>
</div>
<t t-if="website.google_analytics_key">
<t t-if="website and website.google_analytics_key">
<script>
(function(b,o,i,l,e,r){b.GoogleAnalyticsObject=l;b[l]||(b[l]=
function(){(b[l].q=b[l].q||[]).push(arguments)});b[l].l=+new Date;

View File

@ -54,9 +54,11 @@
<field name="arch" type="xml">
<form string="Blog Post">
<sheet>
<h1><field name="name" placeholder="Name"/></h1>
<field name="tag_ids" widget="many2many_tags"/>
<field name="subtitle" placeholder="Blog Subtitle"/>
<group>
<field name="name" placeholder="Name"/>
<field name="tag_ids" widget="many2many_tags"/>
<field name="subtitle" placeholder="Blog Subtitle"/>
</group>
<group>
<field name="background_image"/>
<field name="blog_id"/>

View File

@ -12,7 +12,6 @@ from openerp.addons.web.controllers.main import login_redirect
from openerp.addons.web.http import request
from openerp.addons.website.controllers.main import Website as controllers
from openerp.addons.website.models.website import slug
from openerp.tools import html2plaintext
controllers = controllers()
@ -33,20 +32,12 @@ class WebsiteForum(http.Controller):
return msg
def _prepare_forum_values(self, forum=None, **kwargs):
Forum = request.registry['forum.forum']
user = request.registry['res.users'].browse(request.cr, request.uid, request.uid, context=request.context)
values = {'user': user,
'is_public_user': user.id == request.website.user_id.id,
'notifications': self._get_notifications(),
'header': kwargs.get('header', dict()),
'searches': kwargs.get('searches', dict()),
'can_edit_own': True,
'can_edit_all': user.karma > Forum._karma_modo_edit_all,
'can_close_own': user.karma > Forum._karma_modo_close_own,
'can_close_all': user.karma > Forum._karma_modo_close_all,
'can_unlink_own': user.karma > Forum._karma_modo_unlink_own,
'can_unlink_all': user.karma > Forum._karma_modo_unlink_all,
'can_unlink_comment': user.karma > Forum._karma_modo_unlink_comment,
}
if forum:
values['forum'] = forum
@ -55,14 +46,6 @@ class WebsiteForum(http.Controller):
values.update(kwargs)
return values
def _has_enough_karma(self, karma_name, uid=None):
Forum = request.registry['forum.forum']
karma = hasattr(Forum, karma_name) and getattr(Forum, karma_name) or 0
user = request.registry['res.users'].browse(request.cr, SUPERUSER_ID, uid or request.uid, context=request.context)
if user.karma < karma:
return False, {'error': 'not_enough_karma', 'karma': karma}
return True, {}
# Forum
# --------------------------------------------------
@ -244,10 +227,6 @@ class WebsiteForum(http.Controller):
@http.route('/forum/<model("forum.forum"):forum>/question/<model("forum.post"):question>/ask_for_close', type='http', auth="user", methods=['POST'], website=True)
def question_ask_for_close(self, forum, question, **post):
check_res = self._has_enough_karma(question.create_uid.id == request.uid and '_karma_modo_close_own' or '_karma_modo_close_all')
if not check_res[0]:
return werkzeug.utils.redirect("/forum/%s" % slug(forum))
cr, uid, context = request.cr, request.uid, request.context
Reason = request.registry['forum.post.reason']
reason_ids = Reason.search(cr, uid, [], context=context)
@ -272,42 +251,21 @@ class WebsiteForum(http.Controller):
@http.route('/forum/<model("forum.forum"):forum>/question/<model("forum.post"):question>/close', type='http', auth="user", methods=['POST'], website=True)
def question_close(self, forum, question, **post):
check_res = self._has_enough_karma(question.create_uid.id == request.uid and '_karma_modo_close_own' or '_karma_modo_close_all')
if not check_res[0]:
return werkzeug.utils.redirect("/forum/%s" % slug(forum))
request.registry['forum.post'].write(request.cr, request.uid, [question.id], {
'state': 'close',
'closed_uid': request.uid,
'closed_date': datetime.today().strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT),
'closed_reason_id': int(post.get('reason_id', False)),
}, context=request.context)
request.registry['forum.post'].close(request.cr, request.uid, [question.id], reason_id=int(post.get('reason_id', False)), context=request.context)
return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(question)))
@http.route('/forum/<model("forum.forum"):forum>/question/<model("forum.post"):question>/reopen', type='http', auth="user", methods=['POST'], website=True)
def question_reopen(self, forum, question, **kwarg):
check_res = self._has_enough_karma(question.create_uid.id == request.uid and '_karma_modo_close_own' or '_karma_modo_close_all')
if not check_res[0]:
return werkzeug.utils.redirect("/forum/%s" % slug(forum))
request.registry['forum.post'].write(request.cr, request.uid, [question.id], {'state': 'active'}, context=request.context)
return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(question)))
@http.route('/forum/<model("forum.forum"):forum>/question/<model("forum.post"):question>/delete', type='http', auth="user", methods=['POST'], website=True)
def question_delete(self, forum, question, **kwarg):
check_res = self._has_enough_karma(question.create_uid.id == request.uid and '_karma_modo_unlink_own' or '_karma_modo_unlink_all')
if not check_res[0]:
return werkzeug.utils.redirect("/forum/%s" % slug(forum))
request.registry['forum.post'].write(request.cr, request.uid, [question.id], {'active': False}, context=request.context)
return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(question)))
@http.route('/forum/<model("forum.forum"):forum>/question/<model("forum.post"):question>/undelete', type='http', auth="user", methods=['POST'], website=True)
def question_undelete(self, forum, question, **kwarg):
check_res = self._has_enough_karma(question.create_uid.id == request.uid and '_karma_modo_unlink_own' or '_karma_modo_unlink_all')
if not check_res[0]:
return werkzeug.utils.redirect("/forum/%s" % slug(forum))
request.registry['forum.post'].write(request.cr, request.uid, [question.id], {'active': True}, context=request.context)
return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(question)))
@ -349,11 +307,6 @@ class WebsiteForum(http.Controller):
return request.redirect('/')
if not request.session.uid:
return {'error': 'anonymous_user'}
user = request.registry['res.users'].browse(request.cr, SUPERUSER_ID, request.uid, context=request.context)
if post.parent_id.create_uid.id != uid and user.karma < request.registry['forum.forum']._karma_answer_accept_all:
return {'error': 'not_enough_karma', 'karma': request.registry['forum.forum']._karma_answer_accept_all}
if post.create_uid.id == user.id and user.karma < request.registry['forum.forum']._karma_answer_accept_own:
return {'error': 'not_enough_karma', 'karma': request.registry['forum.forum']._karma_answer_accept_own}
# set all answers to False, only one can be accepted
request.registry['forum.post'].write(cr, uid, [c.id for c in post.parent_id.child_ids], {'is_correct': False}, context=context)
@ -362,10 +315,6 @@ class WebsiteForum(http.Controller):
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/delete', type='http', auth="user", methods=['POST'], website=True)
def post_delete(self, forum, post, **kwargs):
check_res = self._has_enough_karma(post.create_uid.id == request.uid and '_karma_modo_unlink_own' or '_karma_modo_unlink_all')
if not check_res[0]:
return werkzeug.utils.redirect("/forum/%s" % slug(forum))
question = post.parent_id
request.registry['forum.post'].unlink(request.cr, request.uid, [post.id], context=request.context)
if question:
@ -374,10 +323,6 @@ class WebsiteForum(http.Controller):
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/edit', type='http', auth="user", website=True)
def post_edit(self, forum, post, **kwargs):
check_res = self._has_enough_karma(post.create_uid.id == request.uid and '_karma_modo_edit_own' or '_karma_modo_edit_all')
if not check_res[0]:
return werkzeug.utils.redirect("/forum/%s" % slug(forum))
tags = ""
for tag_name in post.tag_ids:
tags += tag_name.name + ","
@ -419,9 +364,6 @@ class WebsiteForum(http.Controller):
return {'error': 'anonymous_user'}
if request.uid == post.create_uid.id:
return {'error': 'own_post'}
check_res = self._has_enough_karma('_karma_upvote')
if not check_res[0]:
return check_res[1]
upvote = True if not post.user_vote > 0 else False
return request.registry['forum.post'].vote(request.cr, request.uid, [post.id], upvote=upvote, context=request.context)
@ -431,9 +373,6 @@ class WebsiteForum(http.Controller):
return {'error': 'anonymous_user'}
if request.uid == post.create_uid.id:
return {'error': 'own_post'}
check_res = self._has_enough_karma('_karma_downvote')
if not check_res[0]:
return check_res[1]
upvote = True if post.user_vote < 0 else False
return request.registry['forum.post'].vote(request.cr, request.uid, [post.id], upvote=upvote, context=request.context)
@ -625,26 +564,25 @@ class WebsiteForum(http.Controller):
# Messaging
# --------------------------------------------------
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/comment/<model("mail.message"):comment>/convert_to_answer', type='http', auth="public", methods=['POST'], website=True)
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/comment/<model("mail.message"):comment>/convert_to_answer', type='http', auth="user", methods=['POST'], website=True)
def convert_comment_to_answer(self, forum, post, comment, **kwarg):
body = comment.body
request.registry['mail.message'].unlink(request.cr, request.uid, [comment.id], context=request.context)
new_post_id = request.registry['forum.post'].convert_comment_to_answer(request.cr, request.uid, comment.id, context=request.context)
if not new_post_id:
return werkzeug.utils.redirect("/forum/%s" % slug(forum))
post = request.registry['forum.post'].browse(request.cr, request.uid, new_post_id, context=request.context)
question = post.parent_id if post.parent_id else post
for answer in question.child_ids:
if answer.create_uid.id == request.uid:
return self.post_comment(forum, answer, comment=html2plaintext(body))
return self.post_new(forum, question, content=body)
return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(question)))
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/convert_to_comment', type='http', auth="user", methods=['POST'], website=True)
def convert_answer_to_comment(self, forum, post, **kwarg):
values = {
'comment': html2plaintext(post.content),
}
question = post.parent_id
request.registry['forum.post'].unlink(request.cr, SUPERUSER_ID, [post.id], context=request.context)
return self.post_comment(forum, question, **values)
new_msg_id = request.registry['forum.post'].convert_answer_to_comment(request.cr, request.uid, post.id, context=request.context)
if not new_msg_id:
return werkzeug.utils.redirect("/forum/%s" % slug(forum))
return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(question)))
@http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/comment/<model("mail.message"):comment>/delete', type='json', auth="user", website=True)
def delete_comment(self, forum, post, comment, **kwarg):
request.registry['mail.message'].unlink(request.cr, SUPERUSER_ID, [comment.id], context=request.context)
return True
if not request.session.uid:
return {'error': 'anonymous_user'}
return request.registry['forum.post'].unlink(request.cr, request.uid, post.id, comment.id, context=request.context)

View File

@ -44,7 +44,7 @@
<record id="mt_question_new" model="mail.message.subtype">
<field name="name">New Question</field>
<field name="res_model">forum.post</field>
<field name="default" eval="False"/>
<field name="default" eval="True"/>
<field name="description">New Question</field>
</record>
<record id="mt_question_edit" model="mail.message.subtype">
@ -57,7 +57,7 @@
<record id="mt_forum_answer_new" model="mail.message.subtype">
<field name="name">New Answer</field>
<field name="res_model">forum.forum</field>
<field name="default" eval="False"/>
<field name="default" eval="True"/>
<field name="hidden" eval="False"/>
<field name="parent_id" eval="ref('mt_answer_new')"/>
<field name="relation_field">forum_id</field>

View File

@ -1,50 +1,63 @@
# -*- coding: utf-8 -*-
from datetime import datetime
import openerp
from openerp import tools
from openerp import SUPERUSER_ID
from openerp.addons.website.models.website import slug
from openerp.osv import osv, fields
from openerp.tools import html2plaintext
from openerp.tools.translate import _
class KarmaError(ValueError):
""" Karma-related error, used for forum and posts. """
pass
class Forum(osv.Model):
"""TDE TODO: set karma values for actions dynamic for a given forum"""
_name = 'forum.forum'
_description = 'Forums'
_inherit = ['mail.thread', 'website.seo.metadata']
# karma values
_karma_upvote = 5 # done
_karma_downvote = 50 # done
_karma_answer_accept_own = 20 # done
_karma_answer_accept_own_now = 50
_karma_answer_accept_all = 500
_karma_editor_link_files = 30 # done
_karma_editor_clickable_link = 50
_karma_comment = 1
_karma_modo_retag = 75
_karma_modo_flag = 100
_karma_modo_flag_see_all = 300
_karma_modo_unlink_comment = 750
_karma_modo_edit_own = 1 # done
_karma_modo_edit_all = 300 # done
_karma_modo_close_own = 100 # done
_karma_modo_close_all = 900 # done
_karma_modo_unlink_own = 500 # done
_karma_modo_unlink_all = 1000 # done
# karma generation
_karma_gen_quest_new = 2 # done
_karma_gen_upvote_quest = 5 # done
_karma_gen_downvote_quest = -2 # done
_karma_gen_upvote_ans = 10 # done
_karma_gen_downvote_ans = -2 # done
_karma_gen_ans_accept = 2 # done
_karma_gen_ans_accepted = 15 # done
_karma_gen_ans_flagged = -100
_columns = {
'name': fields.char('Name', required=True, translate=True),
'faq': fields.html('Guidelines'),
'description': fields.html('Description'),
# karma generation
'karma_gen_question_new': fields.integer('Karma earned for new questions'),
'karma_gen_question_upvote': fields.integer('Karma earned for upvoting a question'),
'karma_gen_question_downvote': fields.integer('Karma earned for downvoting a question'),
'karma_gen_answer_upvote': fields.integer('Karma earned for upvoting an answer'),
'karma_gen_answer_downvote': fields.integer('Karma earned for downvoting an answer'),
'karma_gen_answer_accept': fields.integer('Karma earned for accepting an anwer'),
'karma_gen_answer_accepted': fields.integer('Karma earned for having an answer accepted'),
'karma_gen_answer_flagged': fields.integer('Karma earned for having an answer flagged'),
# karma-based actions
'karma_ask': fields.integer('Karma to ask a new question'),
'karma_answer': fields.integer('Karma to answer a question'),
'karma_edit_own': fields.integer('Karma to edit its own posts'),
'karma_edit_all': fields.integer('Karma to edit all posts'),
'karma_close_own': fields.integer('Karma to close its own posts'),
'karma_close_all': fields.integer('Karma to close all posts'),
'karma_unlink_own': fields.integer('Karma to delete its own posts'),
'karma_unlink_all': fields.integer('Karma to delete all posts'),
'karma_upvote': fields.integer('Karma to upvote'),
'karma_downvote': fields.integer('Karma to downvote'),
'karma_answer_accept_own': fields.integer('Karma to accept an answer on its own questions'),
'karma_answer_accept_all': fields.integer('Karma to accept an answers to all questions'),
'karma_editor_link_files': fields.integer('Karma for linking files (Editor)'),
'karma_editor_clickable_link': fields.integer('Karma for clickable links (Editor)'),
'karma_comment_own': fields.integer('Karma to comment its own posts'),
'karma_comment_all': fields.integer('Karma to comment all posts'),
'karma_comment_convert_own': fields.integer('Karma to convert its own answers to comments and vice versa'),
'karma_comment_convert_all': fields.integer('Karma to convert all answers to answers and vice versa'),
'karma_comment_unlink_own': fields.integer('Karma to unlink its own comments'),
'karma_comment_unlink_all': fields.integer('Karma to unlinnk all comments'),
'karma_retag': fields.integer('Karma to change question tags'),
'karma_flag': fields.integer('Karma to flag a post as offensive'),
}
def _get_default_faq(self, cr, uid, context=None):
@ -56,6 +69,36 @@ class Forum(osv.Model):
_defaults = {
'description': 'This community is for professionals and enthusiasts of our products and services.',
'faq': _get_default_faq,
'karma_gen_question_new': 2,
'karma_gen_question_upvote': 5,
'karma_gen_question_downvote': -2,
'karma_gen_answer_upvote': 10,
'karma_gen_answer_downvote': -2,
'karma_gen_answer_accept': 2,
'karma_gen_answer_accepted': 15,
'karma_gen_answer_flagged': -100,
'karma_ask': 0,
'karma_answer': 0,
'karma_edit_own': 1,
'karma_edit_all': 300,
'karma_close_own': 100,
'karma_close_all': 500,
'karma_unlink_own': 500,
'karma_unlink_all': 1000,
'karma_upvote': 5,
'karma_downvote': 50,
'karma_answer_accept_own': 20,
'karma_answer_accept_all': 500,
'karma_editor_link_files': 20,
'karma_editor_clickable_link': 20,
'karma_comment_own': 1,
'karma_comment_all': 1,
'karma_comment_convert_own': 50,
'karma_comment_convert_all': 500,
'karma_comment_unlink_own': 50,
'karma_comment_unlink_all': 500,
'karma_retag': 75,
'karma_flag': 500,
}
def create(self, cr, uid, values, context=None):
@ -139,6 +182,36 @@ class Post(osv.Model):
res[post.id] = post.parent_id and post.parent_id.create_uid == post.create_uid or False
return res
def _get_post_karma_rights(self, cr, uid, ids, field_name, arg, context=None):
user = self.pool['res.users'].browse(cr, uid, uid, context=context)
res = dict.fromkeys(ids, False)
for post in self.browse(cr, uid, ids, context=context):
res[post.id] = {
'karma_ask': post.forum_id.karma_ask,
'karma_answer': post.forum_id.karma_answer,
'karma_accept': post.parent_id and post.parent_id.create_uid.id == uid and post.forum_id.karma_answer_accept_own or post.forum_id.karma_answer_accept_all,
'karma_edit': post.create_uid.id == uid and post.forum_id.karma_edit_own or post.forum_id.karma_edit_all,
'karma_close': post.create_uid.id == uid and post.forum_id.karma_close_own or post.forum_id.karma_close_all,
'karma_unlink': post.create_uid.id == uid and post.forum_id.karma_unlink_own or post.forum_id.karma_unlink_all,
'karma_upvote': post.forum_id.karma_upvote,
'karma_downvote': post.forum_id.karma_downvote,
'karma_comment': post.create_uid.id == uid and post.forum_id.karma_comment_own or post.forum_id.karma_comment_all,
'karma_comment_convert': post.create_uid.id == uid and post.forum_id.karma_comment_convert_own or post.forum_id.karma_comment_convert_all,
}
res[post.id].update({
'can_ask': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_ask'],
'can_answer': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_answer'],
'can_accept': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_accept'],
'can_edit': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_edit'],
'can_close': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_close'],
'can_unlink': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_unlink'],
'can_upvote': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_upvote'],
'can_downvote': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_downvote'],
'can_comment': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_comment'],
'can_comment_convert': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_comment_convert'],
})
return res
_columns = {
'name': fields.char('Title'),
'forum_id': fields.many2one('forum.forum', 'Forum', required=True),
@ -151,7 +224,7 @@ class Post(osv.Model):
'website_message_ids': fields.one2many(
'mail.message', 'res_id',
domain=lambda self: [
'&', ('model', '=', self._name), ('type', '=', 'comment')
'&', ('model', '=', self._name), ('type', 'in', ['email', 'comment'])
],
string='Post Messages', help="Comments on forum post",
),
@ -203,6 +276,28 @@ class Post(osv.Model):
'closed_reason_id': fields.many2one('forum.post.reason', 'Reason'),
'closed_uid': fields.many2one('res.users', 'Closed by', select=1),
'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'),
'karma_unlink': fields.function(_get_post_karma_rights, string='Karma to unlink', type='integer', multi='_get_post_karma_rights'),
'karma_upvote': fields.function(_get_post_karma_rights, string='Karma to upvote', type='integer', multi='_get_post_karma_rights'),
'karma_downvote': fields.function(_get_post_karma_rights, string='Karma to downvote', type='integer', multi='_get_post_karma_rights'),
'karma_comment': fields.function(_get_post_karma_rights, string='Karma to comment', type='integer', multi='_get_post_karma_rights'),
'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'),
'can_unlink': fields.function(_get_post_karma_rights, string='Can Unlink', type='boolean', multi='_get_post_karma_rights'),
'can_upvote': fields.function(_get_post_karma_rights, string='Can Upvote', type='boolean', multi='_get_post_karma_rights'),
'can_downvote': fields.function(_get_post_karma_rights, string='Can Downvote', type='boolean', multi='_get_post_karma_rights'),
'can_comment': fields.function(_get_post_karma_rights, string='Can Comment', type='boolean', multi='_get_post_karma_rights'),
'can_comment_convert': fields.function(_get_post_karma_rights, string='Can Convert to Comment', type='boolean', multi='_get_post_karma_rights'),
}
_defaults = {
@ -219,41 +314,93 @@ class Post(osv.Model):
context = {}
create_context = dict(context, mail_create_nolog=True)
post_id = super(Post, self).create(cr, uid, vals, context=create_context)
# post message + subtype depending on parent_id
if vals.get("parent_id"):
parent = self.browse(cr, SUPERUSER_ID, vals['parent_id'], context=context)
body = _('<p><a href="forum/%s/question/%s">New Answer Posted</a></p>' % (slug(parent.forum_id), slug(parent)))
self.message_post(cr, uid, parent.id, subject=_('Re: %s') % parent.name, body=body, subtype='website_forum.mt_answer_new', context=context)
post = self.browse(cr, SUPERUSER_ID, post_id, context=context) # SUPERUSER_ID to avoid read access rights issues when creating
# karma-based access
if post.parent_id and not post.can_ask:
raise KarmaError('Not enough karma to create a new question')
elif not post.parent_id and not post.can_answer:
raise KarmaError('Not enough karma to answer to a question')
# messaging and chatter
base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url')
if post.parent_id:
body = _(
'<p>A new answer for <i>%s</i> has been posted. <a href="%s/forum/%s/question/%s">Click here to access the post.</a></p>' %
(post.parent_id.name, base_url, slug(post.parent_id.forum_id), slug(post.parent_id))
)
self.message_post(cr, uid, post.parent_id.id, subject=_('Re: %s') % post.parent_id.name, body=body, subtype='website_forum.mt_answer_new', context=context)
else:
self.message_post(cr, uid, post_id, subject=vals.get('name', ''), body=_('New Question Created'), subtype='website_forum.mt_question_new', context=context)
self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [uid], self.pool['forum.forum']._karma_gen_quest_new, context=context)
body = _(
'<p>A new question <i>%s</i> has been asked on %s. <a href="%s/forum/%s/question/%s">Click here to access the question.</a></p>' %
(post.name, post.forum_id.name, base_url, slug(post.forum_id), slug(post))
)
self.message_post(cr, uid, post_id, subject=post.name, body=body, subtype='website_forum.mt_question_new', context=context)
self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [uid], post.forum_id.karma_gen_question_new, context=context)
return post_id
def write(self, cr, uid, ids, vals, context=None):
Forum = self.pool['forum.forum']
# update karma when accepting/rejecting answers
posts = self.browse(cr, uid, ids, context=context)
if 'state' in vals:
if vals['state'] in ['active', 'close'] and any(not post.can_close for post in posts):
raise KarmaError('Not enough karma to close or reopen a post.')
if 'active' in vals:
if any(not post.can_unlink for post in posts):
raise KarmaError('Not enough karma to delete or reactivate a post')
if 'is_correct' in vals:
if any(not post.can_accept for post in posts):
raise KarmaError('Not enough karma to accept or refuse an answer')
# update karma except for self-acceptance
mult = 1 if vals['is_correct'] else -1
for post in self.browse(cr, uid, ids, context=context):
if vals['is_correct'] != post.is_correct:
self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [post.create_uid.id], Forum._karma_gen_ans_accepted * mult, context=context)
self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [uid], Forum._karma_gen_ans_accept * mult, context=context)
if vals['is_correct'] != post.is_correct and post.create_uid.id != uid:
self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [post.create_uid.id], post.forum_id.karma_gen_answer_accepted * mult, context=context)
self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [uid], post.forum_id.karma_gen_answer_accept * mult, context=context)
if any(key not in ['state', 'active', 'is_correct', 'closed_uid', 'closed_date', 'closed_reason_id'] for key in vals.keys()) and any(not post.can_edit for post in posts):
raise KarmaError('Not enough karma to edit a post.')
res = super(Post, self).write(cr, uid, ids, vals, context=context)
# if post content modify, notify followers
if 'content' in vals or 'name' in vals:
for post in self.browse(cr, uid, ids, context=context):
for post in posts:
if post.parent_id:
body, subtype = _('Answer Edited'), 'website_forum.mt_answer_edit'
obj_id = post.parent_id.id
else:
body, subtype = _('Question Edited'), 'website_forum.mt_question_edit'
obj_id = post.id
self.message_post(cr, uid, obj_id, body=_(body), subtype=subtype, context=context)
self.message_post(cr, uid, obj_id, body=body, subtype=subtype, context=context)
return res
def close(self, cr, uid, ids, reason_id, context=None):
if any(post.parent_id for post in self.browse(cr, uid, ids, context=context)):
return False
return self.pool['forum.post'].write(cr, uid, ids, {
'state': 'close',
'closed_uid': uid,
'closed_date': datetime.today().strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT),
'closed_reason_id': reason_id,
}, context=context)
def unlink(self, cr, uid, ids, context=None):
posts = self.browse(cr, uid, ids, context=context)
if any(not post.can_unlink for post in posts):
raise KarmaError('Not enough karma to unlink a post')
# if unlinking an answer with accepted answer: remove provided karma
for post in posts:
if post.is_correct:
self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [post.create_uid.id], post.forum_id.karma_gen_answer_accepted * -1, context=context)
self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [uid], post.forum_id.karma_gen_answer_accept * -1, context=context)
return super(Post, self).unlink(cr, uid, ids, context=context)
def vote(self, cr, uid, ids, upvote=True, context=None):
posts = self.browse(cr, uid, ids, context=context)
if upvote and any(not post.can_upvote for post in posts):
raise KarmaError('Not enough karma to upvote.')
elif not upvote and any(not post.can_downvote for post in posts):
raise KarmaError('Not enough karma to downvote.')
Vote = self.pool['forum.post.vote']
vote_ids = Vote.search(cr, uid, [('post_id', 'in', ids), ('user_id', '=', uid)], context=context)
vote_ids = Vote.search(cr, uid, [('post_id', 'in', ids), ('user_id', '=', uid)], limit=1, context=context)
if vote_ids:
for vote in Vote.browse(cr, uid, vote_ids, context=context):
if upvote:
@ -267,6 +414,89 @@ class Post(osv.Model):
Vote.create(cr, uid, {'post_id': post_id, 'vote': new_vote}, context=context)
return {'vote_count': self._get_vote_count(cr, uid, ids, None, None, context=context)[ids[0]]}
def convert_answer_to_comment(self, cr, uid, id, context=None):
""" Tools to convert an answer (forum.post) to a comment (mail.message).
The original post is unlinked and a new comment is posted on the question
using the post create_uid as the comment's author. """
post = self.browse(cr, uid, id, context=context)
if not post.parent_id:
return False
# karma-based action check: use the post field that computed own/all value
if not post.can_comment_convert:
raise KarmaError('Not enough karma to convert an answer to a comment')
# post the message
question = post.parent_id
values = {
'author_id': post.create_uid.partner_id.id,
'body': html2plaintext(post.content),
'type': 'comment',
'subtype': 'mail.mt_comment',
'date': post.create_date,
}
message_id = self.pool['forum.post'].message_post(
cr, uid, question.id,
context=dict(context, mail_create_nosubcribe=True),
**values)
# unlink the original answer, using SUPERUSER_ID to avoid karma issues
self.pool['forum.post'].unlink(cr, SUPERUSER_ID, [post.id], context=context)
return message_id
def convert_comment_to_answer(self, cr, uid, message_id, default=None, context=None):
""" Tool to convert a comment (mail.message) into an answer (forum.post).
The original comment is unlinked and a new answer from the comment's author
is created. Nothing is done if the comment's author already answered the
question. """
comment = self.pool['mail.message'].browse(cr, SUPERUSER_ID, message_id, context=context)
post = self.pool['forum.post'].browse(cr, uid, comment.res_id, context=context)
user = self.pool['res.users'].browse(cr, uid, uid, context=context)
if not comment.author_id or not comment.author_id.user_ids: # only comment posted by users can be converted
return False
# karma-based action check: must check the message's author to know if own / all
karma_convert = comment.author_id.id == user.partner_id.id and post.forum_id.karma_comment_convert_own or post.forum_id.karma_comment_convert_all
can_convert = uid == SUPERUSER_ID or user.karma >= karma_convert
if not can_convert:
raise KarmaError('Not enough karma to convert a comment to an answer')
# check the message's author has not already an answer
question = post.parent_id if post.parent_id else post
post_create_uid = comment.author_id.user_ids[0]
if any(answer.create_uid.id == post_create_uid.id for answer in question.child_ids):
return False
# create the new post
post_values = {
'forum_id': question.forum_id.id,
'content': comment.body,
'parent_id': question.id,
}
# done with the author user to have create_uid correctly set
new_post_id = self.pool['forum.post'].create(cr, post_create_uid.id, post_values, context=context)
# delete comment
self.pool['mail.message'].unlink(cr, SUPERUSER_ID, [comment.id], context=context)
return new_post_id
def unlink_comment(self, cr, uid, id, message_id, context=None):
comment = self.pool['mail.message'].browse(cr, SUPERUSER_ID, message_id, context=context)
post = self.pool['forum.post'].browse(cr, uid, id, context=context)
user = self.pool['res.users'].browse(cr, SUPERUSER_ID, uid, context=context)
if not comment.model == 'forum.post' or not comment.res_id == id:
return False
# karma-based action check: must check the message's author to know if own or all
karma_unlink = comment.author_id.id == user.partner_id.id and post.forum_id.karma_comment_unlink_own or post.forum_id.karma_comment_unlink_all
can_unlink = uid == SUPERUSER_ID or user.karma >= karma_unlink
if not can_unlink:
raise KarmaError('Not enough karma to unlink a comment')
return self.pool['mail.message'].unlink(cr, SUPERUSER_ID, [message_id], context=context)
def set_viewed(self, cr, uid, ids, context=None):
cr.execute("""UPDATE forum_post SET views = views+1 WHERE id IN %s""", (tuple(ids),))
return True
@ -300,31 +530,31 @@ class Vote(osv.Model):
'vote': lambda *args: '1',
}
def _get_karma_value(self, old_vote, new_vote, up_karma, down_karma):
_karma_upd = {
'-1': {'-1': 0, '0': -1 * down_karma, '1': -1 * down_karma + up_karma},
'0': {'-1': 1 * down_karma, '0': 0, '1': up_karma},
'1': {'-1': -1 * up_karma + down_karma, '0': -1 * up_karma, '1': 0}
}
return _karma_upd[old_vote][new_vote]
def create(self, cr, uid, vals, context=None):
vote_id = super(Vote, self).create(cr, uid, vals, context=context)
if vals.get('vote', '1') == '1':
karma = self.pool['forum.forum']._karma_upvote
elif vals.get('vote', '1') == '-1':
karma = self.pool['forum.forum']._karma_downvote
post = self.pool['forum.post'].browse(cr, uid, vals['post_id'], context=context)
self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [post.create_uid.id], karma, context=context)
vote = self.browse(cr, uid, vote_id, context=context)
if vote.post_id.parent_id:
karma_value = self._get_karma_value('0', vote.vote, vote.post_id.forum_id.karma_gen_answer_upvote, vote.post_id.forum_id.karma_gen_answer_downvote)
else:
karma_value = self._get_karma_value('0', vote.vote, vote.post_id.forum_id.karma_gen_question_upvote, vote.post_id.forum_id.karma_gen_question_downvote)
self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [vote.post_id.create_uid.id], karma_value, context=context)
return vote_id
def write(self, cr, uid, ids, values, context=None):
def _get_karma_value(old_vote, new_vote, up_karma, down_karma):
_karma_upd = {
'-1': {'-1': 0, '0': -1 * down_karma, '1': -1 * down_karma + up_karma},
'0': {'-1': 1 * down_karma, '0': 0, '1': up_karma},
'1': {'-1': -1 * up_karma + down_karma, '0': -1 * up_karma, '1': 0}
}
return _karma_upd[old_vote][new_vote]
if 'vote' in values:
Forum = self.pool['forum.forum']
for vote in self.browse(cr, uid, ids, context=context):
if vote.post_id.parent_id:
karma_value = _get_karma_value(vote.vote, values['vote'], Forum._karma_gen_upvote_ans, Forum._karma_gen_downvote_ans)
karma_value = self._get_karma_value(vote.vote, values['vote'], vote.post_id.forum_id.karma_gen_answer_upvote, vote.post_id.forum_id.karma_gen_answer_downvote)
else:
karma_value = _get_karma_value(vote.vote, values['vote'], Forum._karma_gen_upvote_quest, Forum._karma_gen_downvote_quest)
karma_value = self._get_karma_value(vote.vote, values['vote'], vote.post_id.forum_id.karma_gen_question_upvote, vote.post_id.forum_id.karma_gen_question_downvote)
self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [vote.post_id.create_uid.id], karma_value, context=context)
res = super(Vote, self).write(cr, uid, ids, values, context=context)
return res

View File

@ -104,6 +104,14 @@ a.no-decoration {
height: 1.2em !important;
}
.oe_forum_alert {
position: absolute;
margin-top: -30px;
margin-left: 90px;
width: 300px;
z-index: 9999;
}
button.btn-link.text-muted {
color: #999999;
}

View File

@ -84,5 +84,12 @@ a.no-decoration
font: 1.2em "Helvetica Neue", Helvetica, Arial, sans-serif !important
height: 1.2em !important
.oe_forum_alert
position: absolute
margin-top: -30px
margin-left: 90px
width: 300px
z-index: 9999
button.btn-link.text-muted
color: #999

View File

@ -1,28 +1,37 @@
$(document).ready(function () {
$('.vote_up ,.vote_down').on('click', function (ev) {
$('.karma_required').on('click', function (ev) {
var karma = $(ev.currentTarget).data('karma');
if (karma) {
ev.preventDefault();
var $warning = $('<div class="alert alert-danger alert-dismissable oe_forum_alert" id="karma_alert">'+
'<button type="button" class="close notification_close" data-dismiss="alert" aria-hidden="true">&times;</button>'+
karma + ' karma is required to perform this action. You can earn karma by answering questions or having '+
'your answers upvoted by the community.</div>');
var vote_alert = $(ev.currentTarget).parent().find("#vote_alert");
if (vote_alert.length == 0) {
$(ev.currentTarget).parent().append($warning);
}
}
});
$('.vote_up,.vote_down').not('.karma_required').on('click', function (ev) {
ev.preventDefault();
var $link = $(ev.currentTarget);
openerp.jsonRpc($link.data('href'), 'call', {})
.then(function (data) {
if (data['error']){
if (data['error'] == 'own_post'){
var $warning = $('<div class="alert alert-danger alert-dismissable" id="vote_alert" style="position:absolute; margin-top: -30px; margin-left: 90px;">'+
var $warning = $('<div class="alert alert-danger alert-dismissable oe_forum_alert" id="vote_alert">'+
'<button type="button" class="close notification_close" data-dismiss="alert" aria-hidden="true">&times;</button>'+
'Sorry, you cannot vote for your own posts'+
'</div>');
} else if (data['error'] == 'anonymous_user'){
var $warning = $('<div class="alert alert-danger alert-dismissable" id="vote_alert" style="position:absolute; margin-top: -30px; margin-left: 90px;">'+
var $warning = $('<div class="alert alert-danger alert-dismissable oe_forum_alert" id="vote_alert">'+
'<button type="button" class="close notification_close" data-dismiss="alert" aria-hidden="true">&times;</button>'+
'Sorry you must be logged to vote'+
'</div>');
}
else if (data['error'] == 'not_enough_karma') {
var $warning = $('<div class="alert alert-danger alert-dismissable" id="vote_alert" style="max-width: 500px; position:absolute; margin-top: -30px; margin-left: 90px;">'+
'<button type="button" class="close notification_close" data-dismiss="alert" aria-hidden="true">&times;</button>'+
'Sorry, at least ' + data['karma'] + ' karma is required to vote. You can gain karma by answering questions and receiving votes.'+
'</div>');
}
vote_alert = $link.parent().find("#vote_alert");
if (vote_alert.length == 0) {
$link.parent().append($warning);
@ -44,21 +53,16 @@ $(document).ready(function () {
return true;
});
$('.accept_answer').on('click', function (ev) {
$('.accept_answer').not('.karma_required').on('click', function (ev) {
ev.preventDefault();
var $link = $(ev.currentTarget);
openerp.jsonRpc($link.data('href'), 'call', {}).then(function (data) {
if (data['error']) {
if (data['error'] == 'anonymous_user'){
if (data['error'] == 'anonymous_user') {
var $warning = $('<div class="alert alert-danger alert-dismissable" id="correct_answer_alert" style="position:absolute; margin-top: -30px; margin-left: 90px;">'+
'<button type="button" class="close notification_close" data-dismiss="alert" aria-hidden="true">&times;</button>'+
'Sorry, anonymous users cannot choose correct answer.'+
'</div>');
} else if (data['error'] == 'not_enough_karma') {
var $warning = $('<div class="alert alert-danger alert-dismissable" id="vote_alert" style="max-width: 500px; position:absolute; margin-top: -30px; margin-left: 90px;">'+
'<button type="button" class="close notification_close" data-dismiss="alert" aria-hidden="true">&times;</button>'+
'Sorry, at least ' + data['karma'] + ' karma is required to accept this answer. You can gain karma by answering questions and receiving votes.'+
'</div>');
}
correct_answer_alert = $link.parent().find("#correct_answer_alert");
if (correct_answer_alert.length == 0) {

View File

@ -24,6 +24,27 @@
<sheet>
<group>
<field name="name"/>
<field name="karma_ask"/>
<field name="karma_edit_own"/>
<field name="karma_edit_all"/>
<field name="karma_close_own"/>
<field name="karma_close_all"/>
<field name="karma_unlink_own"/>
<field name="karma_unlink_all"/>
</group>
<group>
<field name="karma_upvote"/>
<field name="karma_downvote"/>
<field name="karma_answer_accept_own"/>
<field name="karma_answer_accept_all"/>
<field name="karma_editor_link_files"/>
<field name="karma_editor_clickable_link"/>
<field name="karma_comment_own"/>
<field name="karma_comment_all"/>
<field name="karma_comment_convert_own"/>
<field name="karma_comment_convert_all"/>
<field name="karma_comment_unlink_own"/>
<field name="karma_comment_unlink_all"/>
</group>
</sheet>
<div class="oe_chatter">

View File

@ -25,7 +25,7 @@
<!-- helper -->
<template id="link_button">
<form method="POST" t-att-action="url">
<button t-attf-class="fa btn-link #{classes}">
<button t-attf-class="fa btn-link #{classes} #{karma and 'karma_required text-muted' or ''}" t-attf-data-karma="#{karma}">
<t t-esc="label"/></button>
</form>
</template>
@ -163,7 +163,7 @@
<div t-if="question.child_count&lt;=1" class="subtitle">Answer</div>
</div>
</div>
<div class="col-md-10">
<div class="col-md-10 clearfix">
<div class="question-name">
<a t-attf-href="/forum/#{ slug(forum) }/question/#{ slug(question) }" t-field="question.name"/>
<span t-if="not question.active"><b> [Deleted]</b></span>
@ -419,10 +419,12 @@
<template id="vote">
<div t-attf-class="box oe_grey">
<a t-attf-class="vote_up fa fa-thumbs-up no-decoration #{post.user_vote == 1 and 'text-success' or ''}"
<a t-attf-class="vote_up fa fa-thumbs-up no-decoration #{post.user_vote == 1 and 'text-success' or ''} #{((post.user_vote == 1 and not post.can_downvote) or not post.can_upvote) and 'karma_required' or ''}"
t-attf-data-karma="#{post.user_vote == 1 and post.karma_downvote or post.karma_upvote}"
t-attf-data-href="/forum/#{slug(post.forum_id)}/post/#{slug(post)}/upvote"/>
<span id="vote_count" t-esc="post.vote_count"/>
<a t-attf-class="vote_down fa fa-thumbs-down no-decoration #{post.user_vote == -1 and 'text-warning' or ''}"
<a t-attf-class="vote_down fa fa-thumbs-down no-decoration #{post.user_vote == -1 and 'text-warning' or ''} #{((post.user_vote == -1 and not post.can_upvote) or not post.can_downvote) and 'karma_required' or ''}"
t-attf-data-karma="#{post.user_vote == -1 and post.karma_uovote or post.karma_downvote}"
t-attf-data-href="/forum/#{slug(post.forum_id)}/post/#{slug(post)}/downvote"/>
<div t-if="vote_count &gt; 1" class="subtitle">
votes
@ -449,7 +451,7 @@
t-attf-class="favourite_question no-decoration fa fa-2x fa-star #{question.user_favourite and 'forum_favourite_question' or ''}"/>
</div>
</div>
<div style="col-md-10">
<div class="col-md-10">
<h1 class="mt0">
<a t-attf-href="/forum/#{ slug(forum) }/question/#{ slug(question) }" t-field="question.name"/>
<span t-if="not question.active"><b> [Deleted]</b></span>
@ -466,11 +468,12 @@
style="display: inline-block;"/></b>
</t>
<b>on <span t-field="question.closed_date"/></b>
<div t-if="question.state == 'close' and user.karma&gt;=500" class="mt16 mb24 text-center">
<div class="mt16 mb24 text-center">
<t t-call="website_forum.link_button">
<t t-set="url" t-value="'/forum/' + slug(forum) + '/question/' + slug(question) + '/reopen'"/>
<t t-set="label" t-value="'Reopen'"/>
<t t-set="classes" t-value="'fa-arrow-right'"/>
<t t-set="karma" t-value="not question.can_close and question.karma_close or 0"/>
</t>
</div>
</div>
@ -483,45 +486,52 @@
</t>
</div>
<ul class="list-inline" id="options">
<li t-if="user.id == question.create_uid.id or user.karma&gt;=50">
<a style="cursor: pointer" data-toggle="collapse" class="text-muted fa fa-comment-o"
t-attf-data-target="#comment#{ question._name.replace('.','') + '-' + str(question.id) }">
<li>
<a style="cursor: pointer" data-toggle="collapse"
t-attf-class="fa fa-comment-o #{not question.can_comment and 'karma_required text-muted' or ''}"
t-attf-data-karma="#{not question.can_comment and question.karma_comment or 0}"
t-attf-data-target="#comment#{ question._name.replace('.','') + '-' + str(question.id) }">
Comment
</a>
</li>
<li t-if="question.state != 'close' and ((user.id == question.create_uid.id and can_close_own) or can_close_all)">
<li t-if="question.state != 'close'">
<t t-call="website_forum.link_button">
<t t-set="url" t-value="'/forum/' + slug(forum) +'/question/' + slug(question) + '/ask_for_close'"/>
<t t-set="label" t-value="'Close'"/>
<t t-set="classes" t-vaoue="'text-muted fa-times'"/>
<t t-set="classes" t-value="'fa-times'"/>
<t t-set="karma" t-value="not question.can_close and question.karma_close or 0"/>
</t>
</li>
<li t-if="question.state == 'close' and ((user.id == question.create_uid.id and can_close_own) or can_close_all)">
<li t-if="question.state == 'close'">
<t t-call="website_forum.link_button">
<t t-set="url" t-value="'/forum/' + slug(forum) +'/question/' + slug(question) + '/reopen'"/>
<t t-set="label" t-value="'Reopen'"/>
<t t-set="classes" t-value="'text-muted fa-undo'"/>
<t t-set="classes" t-value="'fa-undo'"/>
<t t-set="karma" t-value="not question.can_close and question.karma_close or 0"/>
</t>
</li>
<li t-if="(user.id == question.create_uid.id and can_edit_own) or can_edit_all">
<li>
<t t-call="website_forum.link_button">
<t t-set="url" t-value="'/forum/' + slug(forum) +'/post/' + slug(question) + '/edit'"/>
<t t-set="label" t-value="'Edit'"/>
<t t-set="classes" t-value="'text-muted fa-edit'"/>
<t t-set="classes" t-value="'fa-edit'"/>
<t t-set="karma" t-value="not question.can_edit and question.karma_edit or 0"/>
</t>
</li>
<li t-if="question.active and ((user.id == question.create_uid.id and can_unlink_own) or can_unlink_all)">
<li t-if="question.active">
<t t-call="website_forum.link_button">
<t t-set="url" t-value="'/forum/' + slug(forum) +'/question/' + slug(question) + '/delete'"/>
<t t-set="label" t-value="'Delete'"/>
<t t-set="classes" t-value="'text-muted fa-trash-o'"/>
<t t-set="classes" t-value="'fa-trash-o'"/>
<t t-set="karma" t-value="not question.can_unlink and question.karma_unlink or 0"/>
</t>
</li>
<li t-if="not question.active and ((user.id == question.create_uid.id and can_unlink_own) or can_unlink_all)">
<li t-if="not question.active">
<t t-call="website_forum.link_button">
<t t-set="url" t-value="'/forum/' + slug(forum) +'/question/' + slug(question) + '/undelete'"/>
<t t-set="label" t-value="'Undelete'"/>
<t t-set="classes" t-value="'text-muted fa-trash-o'"/>
<t t-set="classes" t-value="'fa-trash-o'"/>
<t t-set="karma" t-value="not question.can_unlink and question.karma_unlink or 0"/>
</t>
</li>
</ul>
@ -565,7 +575,8 @@
<t t-set="post" t-value="answer"/>
</t>
<div class="text-muted mt8">
<a t-attf-class="accept_answer fa fa-2x fa-check-circle no-decoration #{answer.is_correct and 'oe_answer_true' or 'oe_answer_false'}"
<a t-attf-class="accept_answer fa fa-2x fa-check-circle no-decoration #{answer.is_correct and 'oe_answer_true' or 'oe_answer_false'} #{not answer.can_accept and 'karma_required' or ''}"
t-attf-data-karma="#{answer.karma_accept}"
t-attf-data-href="/forum/#{slug(question.forum_id)}/post/#{slug(answer)}/toggle_correct"/>
</div>
</div>
@ -573,26 +584,35 @@
<t t-raw="answer.content"/>
<div class="mt16">
<ul class="list-inline pull-right">
<li t-if="user.id == answer.create_uid.id or user.karma&gt;=50">
<a style="cursor: pointer" data-toggle="collapse" class="text-muted fa fa-comment-o"
t-attf-data-target="#comment#{ answer._name.replace('.','') + '-' + str(answer.id) }"> Comment
<li>
<a t-attf-class="fa fa-comment-o #{not answer.can_comment and 'karma_required text-muted' or ''}"
t-attf-data-karma="#{not answer.can_comment and answer.karma_comment or 0}"
style="cursor: pointer" data-toggle="collapse"
t-attf-data-target="#comment#{ answer._name.replace('.','') + '-' + str(answer.id) }"> Comment
</a>
</li>
<li t-if="(user.id == answer.create_uid.id and can_edit_own) or can_edit_all">
<a class="text-muted fa fa-edit" t-attf-href="/forum/#{slug(forum)}/post/#{slug(answer)}/edit"> Edit</a>
<li>
<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-if="(user.id == answer.create_uid.id and can_unlink_own) or can_unlink_all">
<li>
<t t-call="website_forum.link_button">
<t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(answer) + '/delete'"/>
<t t-set="label" t-value="'Delete'"/>
<t t-set="classes" t-value="'text-muted fa-trash-o'"/>
<t t-set="classes" t-value="'fa-trash-o'"/>
<t t-set="karma" t-value="not answer.can_unlink and answer.karma_unlink or 0"/>
</t>
</li>
<li t-if="user.id == answer.create_uid.id">
<li>
<t t-call="website_forum.link_button">
<t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(answer) + '/convert_to_comment'"/>
<t t-set="label" t-value="'Convert as a comment'"/>
<t t-set="classes" t-value="'text-muted fa-magic'"/>
<t t-set="classes" t-value="'fa-magic'"/>
<t t-set="karma" t-value="not answer.can_comment_convert and answer.karma_comment_convert or 0"/>
</t>
</li>
</ul>
@ -610,7 +630,8 @@
<t t-set="post" t-value="answer"/>
</t>
<div class="text-muted mt8">
<a t-attf-class="accept_answer fa fa-2x fa-check-circle no-decoration #{answer.is_correct and 'oe_answer_true' or 'oe_answer_false'}"
<a t-attf-class="accept_answer fa fa-2x fa-check-circle no-decoration #{answer.is_correct and 'oe_answer_true' or 'oe_answer_false'} #{not answer.can_accept and 'karma_required' or ''}"
t-attf-data-karma="#{answer.karma_accept}"
t-attf-data-href="/forum/#{slug(question.forum_id)}/post/#{slug(answer)}/toggle_correct"/>
</div>
</div>
@ -641,10 +662,12 @@
t-attf-data-href="/forum/#{slug(forum)}/post/#{slug(object)}/comment/#{slug(message)}/delete"
class="close comment_delete">&amp;times;</button>
<span t-field="message.body"/>
<t t-set="required_karma" t-value="message.author_id.id == user.partner_id.id and object.forum_id.karma_comment_convert_own or object.forum_id.karma_comment_convert_all"/>
<t t-call="website_forum.link_button">
<t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(object) + '/comment/' + slug(message) + '/convert_to_answer'"/>
<t t-set="label" t-value="'Convert as an answer'"/>
<t t-set="classes" t-value="'text-muted fa-magic pull-right'"/>
<t t-set="karma" t-value="user.karma&lt;required_karma and required_karma or 0"/>
<t t-set="classes" t-value="'fa-magic pull-right'"/>
</t>
<a t-attf-href="/forum/#{slug(forum)}/partner/#{message.author_id.id}"
t-field="message.author_id" t-field-options='{"widget": "contact", "country_image": true, "fields": ["name", "country_id"]}'

View File

@ -4,7 +4,7 @@
<template id="header" inherit_id="website.layout" name="LiveChat Import (internal) Scripts">
<xpath expr="//head" position="inside">
<t t-if="website.channel_id">
<t t-if="website and website.channel_id">
<t t-raw="website.channel_id.script_internal"/>
</t>
</xpath>

View File

@ -1,92 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<template id="editor_head" inherit_id="report.html_container" name="Editor" groups="base.group_website_publisher">
<template id="layout" inherit_id="website.layout" primary="True">
<!-- Add report attributes -->
<xpath expr="//html" position="attributes">
<attribute name="t-att-data-website-id">website.id if editable and website else None</attribute>
<attribute name="t-att-data-translatable">'1' if translatable else None</attribute>
<attribute name="t-att-data-report-margin-top">data_report_margin_top if data_report_margin_top else None</attribute>
<attribute name="t-att-data-report-header-spacing">data_report_header_spacing if data_report_header_spacing else None</attribute>
<attribute name="t-att-data-report-dpi">data_report_dpi if data_report_dpi else None</attribute>
</xpath>
<!-- Add report style -->
<xpath expr="//head" position="inside">
<style type="text/css">
<t t-call="report.style"/>
</style>
</xpath>
<xpath expr="//body" position="attributes">
<attribute name="style">padding-top: 51px;</attribute>
<attribute name="class">container</attribute>
</xpath>
<xpath expr="//body" position="inside">
<div id="website-top-navbar-placeholder" class="navbar navbar-inverse navbar-fixed-top hidden-xs">
<div class="navbar-header">
<form class="navbar-form navbar-left">
<button type="button" class="btn btn-primary">Edit</button>
</form>
</div>
<div class="collapse navbar-collapse navbar-edit-collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="#" onclick="return false;"><i class="fa fa-mobile" title="Mobile preview"/></a></li>
<li class="divider-vertical"/>
<li><a href="#" onclick="return false;"><span title="Promote page on the web">Promote</span></a></li>
<li class="dropdown">
<a href="#" onclick="return false;">Content <span class="caret"/></a>
</li>
<li class="dropdown">
<a href="#" onclick="return false;">Customize <span class="caret"/></a>
</li>
<li class="dropdown">
<a href="#" onclick="return false;">Help <span class="caret"/></a>
</li>
</ul>
</div>
</div>
<xpath expr="//header" position="replace"/>
<xpath expr="//footer" position="replace">
<ul class="list-inline js_language_selector mt16" t-if="(request and request.website_multilang and len(languages) &gt; 1) or (website and editable)">
<li t-foreach="languages" t-as="lg">
<a t-att-href="url_for(request.httprequest.path + '?' + keep_query(), lang=lg[0])"
t-att-data-default-lang="editable and 'true' if website and lg[0] == website.default_lang_code else None">
<t t-esc="lg[1].split('/').pop()"/>
</a>
</li>
<li groups="base.group_website_publisher">
<t t-set="url_return" t-value="url_for('', '[lang]') + '?' + keep_query()"/>
<a t-attf-href="/web#action=base.action_view_base_language_install&amp;website_id=#{website.id if website else ''}&amp;url_return=#{url_return}">
<i class="fa fa-plus-circle"/>
Add a language...
</a>
</li>
</ul>
</xpath>
<xpath expr='//t[@name="layout_head"]' position="before">
<link rel='stylesheet' href='/website/static/src/css/snippets.css'/>
<link rel='stylesheet' href='/website/static/src/css/editor.css'/>
</template>
<link rel="stylesheet" href="/web/static/lib/select2/select2.css"/>
<link rel="stylesheet" href="/website/static/lib/select2-bootstrap-css/select2-bootstrap.css"/>
<link rel='stylesheet' href="/web/static/lib/jquery.ui/css/smoothness/jquery-ui-1.9.1.custom.css"/>
<script type="text/javascript" src="/web/static/lib/select2/select2.js"></script>
<script type="text/javascript" src="/web/static/lib/ckeditor/ckeditor.js"></script>
<script type="text/javascript" src="/website/static/lib/ace/ace.js"></script>
<script type="text/javascript" src="/website/static/lib/vkbeautify/vkbeautify.0.99.00.beta.js"></script>
<script type="text/javascript" src="/web/static/lib/jquery.ui/js/jquery-ui-1.9.1.custom.js"></script>
<!-- mutation observers shim backed by mutation events (8 < IE < 11, Safari < 6, FF < 14, Chrome < 17) -->
<script type="text/javascript" src="/website/static/lib//jquery.mjs.nestedSortable/jquery.mjs.nestedSortable.js"></script>
<script type="text/javascript" src="/website/static/lib/MutationObservers/test/sidetable.js"></script>
<script type="text/javascript" src='/website/static/lib/nearest/jquery.nearest.js'></script>
<script type="text/javascript" src="/website/static/lib/MutationObservers/MutationObserver.js"></script>
<script type="text/javascript" src="/website/static/lib/jquery.placeholder/jquery.placeholder.js"></script>
<script type="text/javascript" src="/website/static/src/js/website.editor.js"></script>
<script type="text/javascript" src="/website/static/src/js/website.menu.js"></script>
<script type="text/javascript" src="/website/static/src/js/website.editor.newpage.js"></script> <!-- groups="base.group_website_designer" -->
<script type="text/javascript" src="/website/static/src/js/website.contentMenu.js"></script> <!-- groups="base.group_website_designer" -->
<script type="text/javascript" src="/website/static/src/js/website.mobile.js"></script>
<script type="text/javascript" src="/website/static/src/js/website.seo.js"></script>
<script type="text/javascript" src="/website/static/src/js/website.snippets.editor.js"></script>
<script type="text/javascript" src="/website/static/src/js/website.ace.js"></script>
<script type="text/javascript" src="/website/static/src/js/website.translator.js"></script>
<script type="text/javascript" src="/website/static/src/js/jQuery.transfo.js"></script>
</xpath>
<xpath expr='//body[@class="container"]/div[@id="wrapwrap"]' position="before">
<t t-set="languages" t-value="website.get_languages() if website else None"/>
<t t-if="languages">
<ul class="list-inline js_language_selector mt16" t-if="(len(languages) &gt; 1 or editable)">
<li t-foreach="languages" t-as="lg">
<a t-att-href="url_for('', lang=lg[0]) + '?' + keep_query()"
t-att-data-default-lang="editable and 'true' if lg[0] == website.default_lang_code else None">
<t t-esc="lg[1].split('/').pop()"/>
</a>
</li>
<li groups="base.group_website_publisher">
<t t-set="url_return" t-value="url_for('', '[lang]') + '?' + keep_query()"/>
<a t-attf-href="/web#action=base.action_view_base_language_install&amp;website_id=#{website.id}&amp;url_return=#{url_return}">
<i class="fa fa-plus-circle"/>
Add a language...
</a>
</li>
</ul>
<template id="website_html_container" inherit_id="report.html_container">
<xpath expr="//t[@t-call='report.layout']" position="replace">
<t t-call="website_report.layout">
<t t-raw="0"/>
</t>
</xpath>
</template>

View File

@ -55,6 +55,7 @@
},
{
waitNot: '.product_price .oe_currency_value:visible:containsExact(1.00)',
waitFor: '#snippet_structure',
element: '#wrap img.product_detail_img',
placement: 'top',
title: _t("Update image"),

View File

@ -68,7 +68,7 @@ def cmd_setup_git():
git_dir = os.getcwd()
if git_dir:
# push sane config for git < 2.0, and hooks
run('git','config','push.default','simple')
#run('git','config','push.default','simple')
# alias
run('git','config','alias.st','status')
# merge bzr style

View File

@ -36,15 +36,30 @@ class ir_filters(osv.osv):
default.update({'name':_('%s (copy)') % name})
return super(ir_filters, self).copy(cr, uid, id, default, context)
def get_filters(self, cr, uid, model):
def _get_action_domain(self, cr, uid, action_id=None):
"""Return a domain component for matching filters that are visible in the
same context (menu/view) as the given action."""
if action_id:
# filters specific to this menu + global ones
return [('action_id', 'in' , [action_id, False])]
# only global ones
return [('action_id', '=', False)]
def get_filters(self, cr, uid, model, action_id=None):
"""Obtain the list of filters available for the user on the given model.
:param action_id: optional ID of action to restrict filters to this action
plus global filters. If missing only global filters are returned.
The action does not have to correspond to the model, it may only be
a contextual action.
:return: list of :meth:`~osv.read`-like dicts containing the
``name``, ``is_default``, ``domain``, ``user_id`` (m2o tuple) and
``context`` of the matching ``ir.filters``.
``name``, ``is_default``, ``domain``, ``user_id`` (m2o tuple),
``action_id`` (m2o tuple) and ``context`` of the matching ``ir.filters``.
"""
# available filters: private filters (user_id=uid) and public filters (uid=NULL)
filter_ids = self.search(cr, uid,
# available filters: private filters (user_id=uid) and public filters (uid=NULL),
# and filters for the action (action_id=action_id) or global (action_id=NULL)
action_domain = self._get_action_domain(cr, uid, action_id)
filter_ids = self.search(cr, uid, action_domain +
[('model_id','=',model),('user_id','in',[uid, False])])
my_filters = self.read(cr, uid, filter_ids,
['name', 'is_default', 'domain', 'context', 'user_id'])
@ -66,7 +81,8 @@ class ir_filters(osv.osv):
:raises openerp.exceptions.Warning: if there is an existing default and
we're not updating it
"""
existing_default = self.search(cr, uid, [
action_domain = self._get_action_domain(cr, uid, vals.get('action_id'))
existing_default = self.search(cr, uid, action_domain + [
('model_id', '=', vals['model_id']),
('user_id', '=', False),
('is_default', '=', True)], context=context)
@ -83,7 +99,9 @@ class ir_filters(osv.osv):
def create_or_replace(self, cr, uid, vals, context=None):
lower_name = vals['name'].lower()
matching_filters = [f for f in self.get_filters(cr, uid, vals['model_id'])
action_id = vals.get('action_id')
current_filters = self.get_filters(cr, uid, vals['model_id'], action_id)
matching_filters = [f for f in current_filters
if f['name'].lower() == lower_name
# next line looks for matching user_ids (specific or global), i.e.
# f.user_id is False and vals.user_id is False or missing,
@ -92,18 +110,22 @@ class ir_filters(osv.osv):
if vals.get('is_default'):
if vals.get('user_id'):
act_ids = self.search(cr, uid, [
# Setting new default: any other default that belongs to the user
# should be turned off
action_domain = self._get_action_domain(cr, uid, action_id)
act_ids = self.search(cr, uid, action_domain + [
('model_id', '=', vals['model_id']),
('user_id', '=', vals['user_id']),
('is_default', '=', True),
], context=context)
self.write(cr, uid, act_ids, {'is_default': False}, context=context)
if act_ids:
self.write(cr, uid, act_ids, {'is_default': False}, context=context)
else:
self._check_global_default(
cr, uid, vals, matching_filters, context=None)
# When a filter exists for the same (name, model, user) triple, we simply
# replace its definition.
# replace its definition (considering action_id irrelevant here)
if matching_filters:
self.write(cr, uid, matching_filters[0]['id'], vals, context)
return matching_filters[0]['id']
@ -114,16 +136,17 @@ class ir_filters(osv.osv):
# Partial constraint, complemented by unique index (see below)
# Still useful to keep because it provides a proper error message when a violation
# occurs, as it shares the same prefix as the unique index.
('name_model_uid_unique', 'unique (name, model_id, user_id)', 'Filter names must be unique'),
('name_model_uid_unique', 'unique (name, model_id, user_id, action_id)', 'Filter names must be unique'),
]
def _auto_init(self, cr, context=None):
super(ir_filters, self)._auto_init(cr, context)
# Use unique index to implement unique constraint on the lowercase name (not possible using a constraint)
cr.execute("SELECT indexname FROM pg_indexes WHERE indexname = 'ir_filters_name_model_uid_unique_index'")
cr.execute("DROP INDEX IF EXISTS ir_filters_name_model_uid_unique_index") # drop old index w/o action
cr.execute("SELECT indexname FROM pg_indexes WHERE indexname = 'ir_filters_name_model_uid_unique_action_index'")
if not cr.fetchone():
cr.execute("""CREATE UNIQUE INDEX "ir_filters_name_model_uid_unique_index" ON ir_filters
(lower(name), model_id, COALESCE(user_id,-1))""")
cr.execute("""CREATE UNIQUE INDEX "ir_filters_name_model_uid_unique_action_index" ON ir_filters
(lower(name), model_id, COALESCE(user_id,-1), COALESCE(action_id,-1))""")
_columns = {
'name': fields.char('Filter Name', translate=True, required=True),
@ -133,7 +156,11 @@ class ir_filters(osv.osv):
'domain': fields.text('Domain', required=True),
'context': fields.text('Context', required=True),
'model_id': fields.selection(_list_all_models, 'Model', required=True),
'is_default': fields.boolean('Default filter')
'is_default': fields.boolean('Default filter'),
'action_id': fields.many2one('ir.actions.actions', 'Action', ondelete='cascade',
help="The menu action this filter applies to. "
"When left empty the filter applies to all menus "
"for this model.")
}
_defaults = {
'domain': '[]',
@ -141,5 +168,6 @@ class ir_filters(osv.osv):
'user_id': lambda self,cr,uid,context=None: uid,
'is_default': False
}
_order = 'model_id, name, id desc'
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -20,6 +20,7 @@
<field name="user_id"/>
<field name="model_id"/>
<field name="is_default"/>
<field name="action_id"/>
</group>
<group>
<field name="domain"/>
@ -37,6 +38,7 @@
<field name="model_id"/>
<field name="user_id"/>
<field name="is_default"/>
<field name="action_id"/>
<field name="domain" groups="base.group_no_one"/>
<field name="context" groups="base.group_no_one"/>
</tree>

View File

@ -349,6 +349,18 @@ class ir_ui_menu(osv.osv):
menu_domain = [('parent_id', '=', False)]
return self.search(cr, uid, menu_domain, context=context)
def load_menus_root(self, cr, uid, context=None):
fields = ['name', 'sequence', 'parent_id', 'action']
menu_root_ids = self.get_user_roots(cr, uid, context=context)
menu_roots = self.read(cr, uid, menu_root_ids, fields, context=context) if menu_root_ids else []
return {
'id': False,
'name': 'root',
'parent_id': [-1, ''],
'children': menu_roots,
'all_menu_ids': menu_root_ids,
}
def load_menus(self, cr, uid, context=None):
""" Loads all menu items (all applications and their sub-menus).

View File

@ -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)

View File

@ -1943,18 +1943,6 @@
<field name="rate">39.6622695</field>
</record>
<record id="ROL" model="res.currency">
<field name="name">ROL</field>
<field name="symbol">L</field>
<field name="rounding">0.01</field>
<field name="accuracy">4</field>
</record>
<record id="rateROL" model="res.currency.rate">
<field name="currency_id" ref="ROL" />
<field eval="time.strftime('%Y-01-01')" name="name"/>
<field name="rate">45638.59</field>
</record>
<record id="QAR" model="res.currency">
<field name="name">QAR</field>
<field name="symbol">QR</field>

View File

@ -5,10 +5,9 @@ from openerp import exceptions
from openerp.tests import common
def noid(d):
""" Removes `id` key from a dict so we don't have to keep these things
around when trying to match
"""
if 'id' in d: del d['id']
""" Removes values that are not relevant for the test comparisons """
d.pop('id', None)
d.pop('action_id', None)
return d
class FiltersCase(common.TransactionCase):

View File

@ -5,6 +5,7 @@ helpers and classes to write tests.
"""
import errno
import glob
import json
import logging
import os
@ -170,7 +171,6 @@ class HttpCase(TransactionCase):
self.session_id = self.session.sid
self.session.db = DB
openerp.http.root.session_store.save(self.session)
self.localstorage_path = mkdtemp()
# setup an url opener helper
self.opener = urllib2.OpenerDirector()
self.opener.add_handler(urllib2.UnknownHandler())
@ -181,7 +181,6 @@ class HttpCase(TransactionCase):
self.opener.addheaders.append(('Cookie', 'session_id=%s' % self.session_id))
def tearDown(self):
rmtree(self.localstorage_path)
self.registry.leave_test_mode()
super(HttpCase, self).tearDown()
@ -254,6 +253,11 @@ class HttpCase(TransactionCase):
def phantom_run(self, cmd, timeout):
_logger.info('phantom_run executing %s', ' '.join(cmd))
ls_glob = os.path.expanduser('~/.qws/share/data/Ofi Labs/PhantomJS/http_localhost_%s.*'%PORT)
for i in glob.glob(ls_glob):
_logger.info('phantomjs unlink localstorage %s', i)
os.unlink(i)
try:
phantom = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
except OSError:
@ -296,7 +300,6 @@ class HttpCase(TransactionCase):
# phantom.args[1] == options
cmd = [
'phantomjs',
'--local-storage-path', self.localstorage_path,
jsfile, phantomtest, json.dumps(options)
]
self.phantom_run(cmd, timeout)

View File

@ -116,6 +116,8 @@ function PhantomTest() {
phantom.exit(1);
} else {
console.log('loaded', url, status);
// clear localstorage leftovers
self.page.evaluate(function () { localStorage.clear() });
// process ready
waitFor(function() {
console.log("PhantomTest.run: wait for condition:", ready);