[MERGE] forward port of branch 8.0 up to 222b2d3
This commit is contained in:
@@ -430,7 +430,11 @@ class account_bank_statement(osv.osv):
|
||||
for statement in self.browse(cr, uid, ids, context=context):
|
||||
for st_line in statement.line_ids:
|
||||
if st_line.bank_account_id and st_line.partner_id and st_line.bank_account_id.partner_id.id != st_line.partner_id.id:
|
||||
self.pool.get('res.partner.bank').write(cr, uid, [st_line.bank_account_id.id], {'partner_id': st_line.partner_id.id}, context=context)
|
||||
# Update the partner informations of the bank account, possibly overriding existing ones
|
||||
bank_obj = self.pool.get('res.partner.bank')
|
||||
bank_vals = bank_obj.onchange_partner_id(cr, uid, [st_line.bank_account_id.id], st_line.partner_id.id, context=context)['value']
|
||||
bank_vals.update({'partner_id': st_line.partner_id.id})
|
||||
bank_obj.write(cr, uid, [st_line.bank_account_id.id], bank_vals, context=context)
|
||||
|
||||
class account_bank_statement_line(osv.osv):
|
||||
|
||||
@@ -659,7 +663,8 @@ class account_bank_statement_line(osv.osv):
|
||||
mv_line_pool = self.pool.get('account.move.line')
|
||||
domain = self._domain_move_lines_for_reconciliation(cr, uid, st_line, excluded_ids=excluded_ids, str=str, additional_domain=additional_domain, context=context)
|
||||
|
||||
# Get move lines ; in case of a partial reconciliation, only consider one line
|
||||
# Get move lines ; in case of a partial reconciliation, only keep one line (the first whose amount is greater than
|
||||
# the residual amount because it is presumably the invoice, which is the relevant item in this situation)
|
||||
filtered_lines = []
|
||||
reconcile_partial_ids = []
|
||||
actual_offset = offset
|
||||
@@ -668,7 +673,9 @@ class account_bank_statement_line(osv.osv):
|
||||
lines = mv_line_pool.browse(cr, uid, line_ids, context=context)
|
||||
make_one_more_loop = False
|
||||
for line in lines:
|
||||
if line.reconcile_partial_id and line.reconcile_partial_id.id in reconcile_partial_ids:
|
||||
if line.reconcile_partial_id and \
|
||||
(line.reconcile_partial_id.id in reconcile_partial_ids or \
|
||||
abs(line.debit - line.credit) < abs(line.amount_residual)):
|
||||
#if we filtered a line because it is partially reconciled with an already selected line, we must do one more loop
|
||||
#in order to get the right number of items in the pager
|
||||
make_one_more_loop = True
|
||||
|
||||
@@ -643,7 +643,7 @@ class account_invoice(models.Model):
|
||||
partner = invoice.partner_id
|
||||
if partner.lang:
|
||||
ctx['lang'] = partner.lang
|
||||
for taxe in account_invoice_tax.compute(invoice).values():
|
||||
for taxe in account_invoice_tax.compute(invoice.with_context(ctx)).values():
|
||||
account_invoice_tax.create(taxe)
|
||||
# dummy write on self to trigger recomputations
|
||||
return self.with_context(ctx).write({'invoice_line': []})
|
||||
|
||||
@@ -783,7 +783,7 @@ class account_move_line(osv.osv):
|
||||
ret_line = {
|
||||
'id': line.id,
|
||||
'name': line.name != '/' and line.move_id.name + ': ' + line.name or line.move_id.name,
|
||||
'ref': line.move_id.ref,
|
||||
'ref': line.move_id.ref or '',
|
||||
# For reconciliation between statement transactions and already registered payments (eg. checks)
|
||||
'already_paid': line.account_id.type == 'liquidity',
|
||||
'account_code': line.account_id.code,
|
||||
@@ -1378,6 +1378,8 @@ class account_move_line(osv.osv):
|
||||
}
|
||||
self.create(cr, uid, data, context)
|
||||
#create the Tax movement
|
||||
if not tax['amount']:
|
||||
continue
|
||||
data = {
|
||||
'move_id': vals['move_id'],
|
||||
'name': tools.ustr(vals['name'] or '') + ' ' + tools.ustr(tax['name'] or ''),
|
||||
@@ -1395,7 +1397,8 @@ class account_move_line(osv.osv):
|
||||
self.create(cr, uid, data, context)
|
||||
del vals['account_tax_id']
|
||||
|
||||
if check and not context.get('novalidate') and (context.get('recompute', True) or journal.entry_posted):
|
||||
recompute = journal.env.recompute and context.get('recompute', True)
|
||||
if check and not context.get('novalidate') and (recompute or journal.entry_posted):
|
||||
tmp = move_obj.validate(cr, uid, [vals['move_id']], context)
|
||||
if journal.entry_posted and tmp:
|
||||
move_obj.button_validate(cr,uid, [vals['move_id']], context)
|
||||
|
||||
@@ -615,7 +615,8 @@
|
||||
<field name="amount" attrs="{'readonly' : [('journal_entry_ids', '!=', [])] }"/>
|
||||
<field name="amount_currency" groups="base.group_multi_currency" attrs="{'readonly' : [('journal_entry_ids', '!=', [])] }"/>
|
||||
<field name="currency_id" groups="base.group_multi_currency" attrs="{'readonly' : [('journal_entry_ids', '!=', [])] }"/>
|
||||
<field name="bank_account_id" groups="base.group_no_one"/>
|
||||
<field name="bank_account_id" groups="base.group_no_one" attrs="{'readonly' : [('journal_entry_id', '!=', False)] }"
|
||||
domain="['|', ('partner_id', '=', partner_id), ('partner_id', '=', False)]"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
|
||||
@@ -7,6 +7,7 @@ import openerp
|
||||
import openerp.service.report
|
||||
import uuid
|
||||
import collections
|
||||
import babel.dates
|
||||
from werkzeug.exceptions import BadRequest
|
||||
from datetime import datetime, timedelta
|
||||
from dateutil import parser
|
||||
@@ -1441,7 +1442,16 @@ class calendar_event(osv.Model):
|
||||
return invitation
|
||||
|
||||
def get_interval(self, cr, uid, ids, date, interval, tz=None, context=None):
|
||||
#Function used only in calendar_event_data.xml for email template
|
||||
''' Format and localize some dates to be used in email templates
|
||||
|
||||
:param string date: date/time to be formatted
|
||||
:param string interval: Among 'day', 'month', 'dayname' and 'time' indicating the desired formatting
|
||||
:param string tz: Timezone indicator (optional)
|
||||
|
||||
:return unicode: Formatted date or time (as unicode string, to prevent jinja2 crash)
|
||||
|
||||
(Function used only in calendar_event_data.xml) '''
|
||||
|
||||
date = openerp.fields.Datetime.from_string(date)
|
||||
|
||||
if tz:
|
||||
@@ -1449,14 +1459,23 @@ class calendar_event(osv.Model):
|
||||
date = date.replace(tzinfo=pytz.timezone('UTC')).astimezone(timezone)
|
||||
|
||||
if interval == 'day':
|
||||
res = str(date.day)
|
||||
# Day number (1-31)
|
||||
res = unicode(date.day)
|
||||
|
||||
elif interval == 'month':
|
||||
res = date.strftime('%B') + " " + str(date.year)
|
||||
# Localized month name and year
|
||||
res = babel.dates.format_date(date=date, format='MMMM y', locale=context.get('lang', 'en_US'))
|
||||
|
||||
elif interval == 'dayname':
|
||||
res = date.strftime('%A')
|
||||
# Localized day name
|
||||
res = babel.dates.format_date(date=date, format='EEEE', locale=context.get('lang', 'en_US'))
|
||||
|
||||
elif interval == 'time':
|
||||
# Localized time
|
||||
|
||||
dummy, format_time = self.get_date_formats(cr, uid, context=context)
|
||||
res = date.strftime(format_time + " %Z")
|
||||
res = tools.ustr(date.strftime(format_time + " %Z"))
|
||||
|
||||
return res
|
||||
|
||||
def search(self, cr, uid, args, offset=0, limit=0, order=None, context=None, count=False):
|
||||
|
||||
@@ -212,13 +212,20 @@ class google_calendar(osv.AbstractModel):
|
||||
type = 'dateTime'
|
||||
vstype = 'date'
|
||||
attendee_list = []
|
||||
|
||||
for attendee in event.attendee_ids:
|
||||
attendee_list.append({
|
||||
'email': attendee.email or 'NoEmail@mail.com',
|
||||
'displayName': attendee.partner_id.name,
|
||||
'responseStatus': attendee.state or 'needsAction',
|
||||
})
|
||||
|
||||
reminders = []
|
||||
for alarm in event.alarm_ids:
|
||||
reminders.append({
|
||||
"method": "email" if alarm.type == "email" else "popup",
|
||||
"minutes": alarm.duration_minutes
|
||||
})
|
||||
|
||||
data = {
|
||||
"summary": event.name or '',
|
||||
"description": event.description or '',
|
||||
@@ -233,6 +240,10 @@ class google_calendar(osv.AbstractModel):
|
||||
'timeZone': 'UTC'
|
||||
},
|
||||
"attendees": attendee_list,
|
||||
"reminders": {
|
||||
"overrides": reminders,
|
||||
"useDefault": "false"
|
||||
},
|
||||
"location": event.location or '',
|
||||
"visibility": event['class'] or 'public',
|
||||
}
|
||||
@@ -244,7 +255,6 @@ class google_calendar(osv.AbstractModel):
|
||||
|
||||
if not self.get_need_synchro_attendee(cr, uid, context=context):
|
||||
data.pop("attendees")
|
||||
|
||||
return data
|
||||
|
||||
def create_an_event(self, cr, uid, event, context=None):
|
||||
@@ -286,7 +296,7 @@ class google_calendar(osv.AbstractModel):
|
||||
|
||||
registry = openerp.modules.registry.RegistryManager.get(request.session.db)
|
||||
with registry.cursor() as cur:
|
||||
self.pool['res.users'].write(cur, uid, [uid], {'google_calendar_token': False, 'google_calendar_token_validity': False}, context=context)
|
||||
self.pool['res.users'].write(cur, SUPERUSER_ID, [uid], {'google_calendar_token': False, 'google_calendar_token_validity': False}, context=context)
|
||||
|
||||
raise self.pool.get('res.config.settings').get_config_warning(cr, _(error_msg), context=context)
|
||||
raise
|
||||
@@ -400,14 +410,16 @@ class google_calendar(osv.AbstractModel):
|
||||
calendar_event = self.pool['calendar.event']
|
||||
res_partner_obj = self.pool['res.partner']
|
||||
calendar_attendee_obj = self.pool['calendar.attendee']
|
||||
calendar_alarm_obj = self.pool['calendar.alarm']
|
||||
user_obj = self.pool['res.users']
|
||||
myPartnerID = user_obj.browse(cr, uid, uid, context).partner_id.id
|
||||
attendee_record = []
|
||||
alarm_record = []
|
||||
partner_record = [(4, myPartnerID)]
|
||||
result = {}
|
||||
|
||||
if single_event_dict.get('attendees', False):
|
||||
for google_attendee in single_event_dict['attendees']:
|
||||
if self.get_need_synchro_attendee(cr, uid, context=context):
|
||||
for google_attendee in single_event_dict.get('attendees', []):
|
||||
if type == "write":
|
||||
for oe_attendee in event['attendee_ids']:
|
||||
if oe_attendee.email == google_attendee['email']:
|
||||
@@ -415,22 +427,41 @@ class google_calendar(osv.AbstractModel):
|
||||
google_attendee['found'] = True
|
||||
continue
|
||||
|
||||
if google_attendee.get('found', False):
|
||||
if google_attendee.get('found'):
|
||||
continue
|
||||
if self.get_need_synchro_attendee(cr, uid, context=context):
|
||||
attendee_id = res_partner_obj.search(cr, uid, [('email', '=', google_attendee['email'])], context=context)
|
||||
if not attendee_id:
|
||||
data = {
|
||||
'email': google_attendee['email'],
|
||||
'customer': False,
|
||||
'name': google_attendee.get("displayName", False) or google_attendee['email']
|
||||
}
|
||||
attendee_id = [res_partner_obj.create(cr, uid, data, context=context)]
|
||||
attendee = res_partner_obj.read(cr, uid, attendee_id[0], ['email'], context=context)
|
||||
partner_record.append((4, attendee.get('id')))
|
||||
attendee['partner_id'] = attendee.pop('id')
|
||||
attendee['state'] = google_attendee['responseStatus']
|
||||
attendee_record.append((0, 0, attendee))
|
||||
|
||||
attendee_id = res_partner_obj.search(cr, uid, [('email', '=', google_attendee['email'])], context=context)
|
||||
if not attendee_id:
|
||||
data = {
|
||||
'email': google_attendee['email'],
|
||||
'customer': False,
|
||||
'name': google_attendee.get("displayName", False) or google_attendee['email']
|
||||
}
|
||||
attendee_id = [res_partner_obj.create(cr, uid, data, context=context)]
|
||||
attendee = res_partner_obj.read(cr, uid, attendee_id[0], ['email'], context=context)
|
||||
partner_record.append((4, attendee.get('id')))
|
||||
attendee['partner_id'] = attendee.pop('id')
|
||||
attendee['state'] = google_attendee['responseStatus']
|
||||
attendee_record.append((0, 0, attendee))
|
||||
for google_alarm in single_event_dict.get('reminders', {}).get('overrides', []):
|
||||
alarm_id = calendar_alarm_obj.search(
|
||||
cr,
|
||||
uid,
|
||||
[
|
||||
('type', '=', google_alarm['method'] if google_alarm['method'] == 'email' else 'notification'),
|
||||
('duration_minutes', '=', google_alarm['minutes'])
|
||||
],
|
||||
context=context
|
||||
)
|
||||
if not alarm_id:
|
||||
data = {
|
||||
'type': google_alarm['method'] if google_alarm['method'] == 'email' else 'notification',
|
||||
'duration': google_alarm['minutes'],
|
||||
'interval': 'minutes',
|
||||
'name': "%s minutes - %s" % (google_alarm['minutes'], google_alarm['method'])
|
||||
}
|
||||
alarm_id = [calendar_alarm_obj.create(cr, uid, data, context=context)]
|
||||
alarm_record.append(alarm_id[0])
|
||||
|
||||
UTC = pytz.timezone('UTC')
|
||||
if single_event_dict.get('start') and single_event_dict.get('end'): # If not cancelled
|
||||
@@ -458,6 +489,7 @@ class google_calendar(osv.AbstractModel):
|
||||
result.update({
|
||||
'attendee_ids': attendee_record,
|
||||
'partner_ids': list(set(partner_record)),
|
||||
'alarm_ids': [(6, 0, alarm_record)],
|
||||
|
||||
'name': single_event_dict.get('summary', 'Event'),
|
||||
'description': single_event_dict.get('description', False),
|
||||
@@ -666,7 +698,7 @@ class google_calendar(osv.AbstractModel):
|
||||
cr.rollback()
|
||||
registry = openerp.modules.registry.RegistryManager.get(request.session.db)
|
||||
with registry.cursor() as cur:
|
||||
self.pool['res.users'].write(cur, uid, [uid], {'google_calendar_last_sync_date': False}, context=context)
|
||||
self.pool['res.users'].write(cur, SUPERUSER_ID, [uid], {'google_calendar_last_sync_date': False}, context=context)
|
||||
error_key = simplejson.loads(str(e))
|
||||
error_key = error_key.get('error', {}).get('message', 'nc')
|
||||
error_msg = "Google is lost... the next synchro will be a full synchro. \n\n %s" % error_key
|
||||
@@ -943,7 +975,7 @@ class calendar_event(osv.Model):
|
||||
_inherit = "calendar.event"
|
||||
|
||||
def get_fields_need_update_google(self, cr, uid, context=None):
|
||||
return ['name', 'description', 'allday', 'date', 'date_end', 'stop', 'attendee_ids', 'location', 'class', 'active']
|
||||
return ['name', 'description', 'allday', 'date', 'date_end', 'stop', 'attendee_ids', 'alarm_ids', 'location', 'class', 'active']
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
if context is None:
|
||||
|
||||
@@ -847,18 +847,20 @@ result = rules.NET > categories.NET * 0.10''',
|
||||
rule = self.browse(cr, uid, rule_id, context=context)
|
||||
if rule.amount_select == 'fix':
|
||||
try:
|
||||
return rule.amount_fix, eval(rule.quantity, localdict), 100.0
|
||||
return rule.amount_fix, float(eval(rule.quantity, localdict)), 100.0
|
||||
except:
|
||||
raise UserError(_('Wrong quantity defined for salary rule %s (%s).') % (rule.name, rule.code))
|
||||
elif rule.amount_select == 'percentage':
|
||||
try:
|
||||
return eval(rule.amount_percentage_base, localdict), eval(rule.quantity, localdict), rule.amount_percentage
|
||||
return (float(eval(rule.amount_percentage_base, localdict)),
|
||||
float(eval(rule.quantity, localdict)),
|
||||
rule.amount_percentage)
|
||||
except:
|
||||
raise UserError(_('Wrong percentage base or quantity defined for salary rule %s (%s).') % (rule.name, rule.code))
|
||||
else:
|
||||
try:
|
||||
eval(rule.amount_python_compute, localdict, mode='exec', nocopy=True)
|
||||
return localdict['result'], 'result_qty' in localdict and localdict['result_qty'] or 1.0, 'result_rate' in localdict and localdict['result_rate'] or 100.0
|
||||
return float(localdict['result']), 'result_qty' in localdict and localdict['result_qty'] or 1.0, 'result_rate' in localdict and localdict['result_rate'] or 100.0
|
||||
except:
|
||||
raise UserError(_('Wrong python code defined for salary rule %s (%s).') % (rule.name, rule.code))
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<tr class="oe_timesheet_total">
|
||||
<td>
|
||||
<div class="oe_timesheet_weekly_adding_tot">
|
||||
<div class="oe_timesheet_weekly_adding"><button class="oe_timesheet_button_add">Add a Line</button></div>
|
||||
<div t-if="!widget.get('effective_readonly')" class="oe_timesheet_weekly_adding"><button class="oe_timesheet_button_add">Add a Line</button></div>
|
||||
<div class="oe_timesheet_weekly_tottot"><span>Total</span></div>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
<!-- Template rendering all the scripts required to execute the Livechat from a page containing Odoo -->
|
||||
<template id="internal_loader" name="All the scripts to launch the LiveSupport from an internal Web Page">
|
||||
<!-- css style -->
|
||||
<link t-att-href="'%s/web/css/im_livechat.internal_lib' % (url)" rel="stylesheet"/>
|
||||
<link property='stylesheet' t-att-href="'%s/web/css/im_livechat.internal_lib' % (url)" rel="stylesheet"/>
|
||||
<!-- js of all the required lib (internal and external) -->
|
||||
<script t-att-src="'%s/web/js/im_livechat.internal_lib' % (url)" type="text/javascript" />
|
||||
<!-- the loader -->
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
import wizard
|
||||
import models
|
||||
@@ -0,0 +1,85 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Odoo, Open Source Business Applications
|
||||
# Copyright (C) 2015 Odoo S.A. <http://www.odoo.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
{
|
||||
'name': 'EU Mini One Stop Shop (MOSS)',
|
||||
'version': '1.0',
|
||||
'author': 'Odoo SA',
|
||||
'website': 'http://www.odoo.com',
|
||||
'category': '',
|
||||
'description': """
|
||||
EU Mini One Stop Shop (MOSS) VAT for telecommunications, broadcasting and electronic services
|
||||
=============================================================================================
|
||||
|
||||
As of January 1rst, 2015, telecommunications, broadcasting
|
||||
and electronic services sold within the European Union
|
||||
have to be always taxed in the country where the customer
|
||||
belongs. In order to simplify the application of this EU
|
||||
directive, the Mini One Stop Shop (MOSS) registration scheme
|
||||
allows businesses to make a unique tax declaration.
|
||||
|
||||
This module makes it possible by helping with the creation
|
||||
of the required EU fiscal positions and taxes in order to
|
||||
automatically apply and record the required taxes.
|
||||
|
||||
This module installs a wizard to help setup fiscal positions
|
||||
and taxes for selling electronic services inside EU.
|
||||
|
||||
The wizard lets you select:
|
||||
- the EU countries to which you are selling these
|
||||
services
|
||||
- your national VAT tax for services, to be mapped
|
||||
to the target country's tax
|
||||
- optionally: a template fiscal position, in order
|
||||
to copy the account mapping. Should be your
|
||||
existing B2C Intra-EU fiscal position. (defaults
|
||||
to no account mapping)
|
||||
- optionally: an account to use for collecting the
|
||||
tax amounts (defaults to the account used by your
|
||||
national VAT tax for services)
|
||||
|
||||
It creates the corresponding fiscal positions and taxes,
|
||||
automatically applicable for EU sales with a customer
|
||||
in the selected countries.
|
||||
The wizard can be run again for adding more countries.
|
||||
|
||||
The wizard creates a separate Chart of Taxes for collecting the
|
||||
VAT amounts of the MOSS declaration, so extracting the MOSS
|
||||
data should be easy.
|
||||
Look for a Chart of Taxes named "EU MOSS VAT Chart" in the
|
||||
Taxes Report menu (Generic Accounting Report).
|
||||
|
||||
References
|
||||
++++++++++
|
||||
- Directive 2008/8/EC
|
||||
- Council Implementing Regulation (EU) No 1042/2013
|
||||
|
||||
""",
|
||||
'depends': ['account_accountant'],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'wizard/wizard.xml',
|
||||
'wizard/l10n_eu_service.service_tax_rate.csv'
|
||||
],
|
||||
'test': [],
|
||||
'demo': [],
|
||||
'auto_install': False,
|
||||
'installable': True,
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * l10n_eu_service
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 8.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-02-17 14:34+0000\n"
|
||||
"PO-Revision-Date: 2015-02-17 14:34+0000\n"
|
||||
"Last-Translator: <>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: field:l10n_eu_service.wizard,done_country_ids:0
|
||||
msgid "Already Supported"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: code:addons/l10n_eu_service/wizard/wizard.py:128
|
||||
#, python-format
|
||||
msgid "Base - VAT for EU Services to %(country_name)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: view:l10n_eu_service.wizard:l10n_eu_service.eu_service_view
|
||||
msgid "Based on the options selected below, this wizard will create one\n"
|
||||
" fiscal position mapping for each EU country to which you are selling\n"
|
||||
" services.\n"
|
||||
" Each fiscal position will automatically map your national VAT tax for\n"
|
||||
" services to the corresponding VAT tax in the country your customer\n"
|
||||
" belongs to."
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: view:l10n_eu_service.wizard:l10n_eu_service.eu_service_view
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: field:l10n_eu_service.wizard,chart_id:0
|
||||
msgid "Chart of Accounts"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: field:l10n_eu_service.service_tax_rate,country_id:0
|
||||
msgid "Country"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: view:l10n_eu_service.wizard:l10n_eu_service.eu_service_view
|
||||
msgid "Create Fiscal Positions and Taxes"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: model:ir.model,name:l10n_eu_service.model_l10n_eu_service_wizard
|
||||
msgid "Create fiscal positions for EU Service VAT"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: field:l10n_eu_service.service_tax_rate,create_uid:0
|
||||
#: field:l10n_eu_service.wizard,create_uid:0
|
||||
msgid "Created by"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: field:l10n_eu_service.service_tax_rate,create_date:0
|
||||
#: field:l10n_eu_service.wizard,create_date:0
|
||||
msgid "Created on"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: view:l10n_eu_service.wizard:l10n_eu_service.eu_service_view
|
||||
msgid "Current EU B2C Fiscal Position, if any"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: field:l10n_eu_service.wizard,todo_country_ids:0
|
||||
msgid "EU Customers From"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: code:addons/l10n_eu_service/wizard/wizard.py:110
|
||||
#, python-format
|
||||
msgid "EU MOSS VAT Chart - %(company)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: field:l10n_eu_service.wizard,fiscal_position_id:0
|
||||
msgid "Fiscal Position"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: field:l10n_eu_service.service_tax_rate,id:0
|
||||
#: field:l10n_eu_service.wizard,id:0
|
||||
msgid "ID"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: code:addons/l10n_eu_service/wizard/wizard.py:161
|
||||
#, python-format
|
||||
msgid "Intra-EU B2C in %(country_name)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: view:l10n_eu_service.wizard:l10n_eu_service.eu_service_view
|
||||
msgid "Keep empty to use current Service VAT account"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: field:l10n_eu_service.service_tax_rate,write_uid:0
|
||||
#: field:l10n_eu_service.wizard,write_uid:0
|
||||
msgid "Last Updated by"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: field:l10n_eu_service.service_tax_rate,write_date:0
|
||||
#: field:l10n_eu_service.wizard,write_date:0
|
||||
msgid "Last Updated on"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: help:l10n_eu_service.wizard,account_collected_id:0
|
||||
msgid "Optional account to use for collecting tax amounts when selling services in each EU country selected below. If not set, the current collecting account of your Service VAT will be used."
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: help:l10n_eu_service.wizard,fiscal_position_id:0
|
||||
msgid "Optional fiscal position to use as template for general account mapping. Should usually be your current Intra-EU B2B fiscal position. If not set, no general account mapping will be configured for EU fiscal positions."
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: help:l10n_eu_service.wizard,tax_id:0
|
||||
msgid "Select your current VAT tax for services. This is the tax that will be mapped to the corresponding VAT tax in each EU country selected below."
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: field:l10n_eu_service.wizard,tax_id:0
|
||||
msgid "Service VAT"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: view:account.config.settings:l10n_eu_service.view_account_config_settings_inherit
|
||||
#: model:ir.actions.act_window,name:l10n_eu_service.action_eu_service
|
||||
#: view:l10n_eu_service.wizard:l10n_eu_service.eu_service_view
|
||||
msgid "Setup EU MOSS Taxes"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: field:l10n_eu_service.wizard,account_collected_id:0
|
||||
msgid "Tax Collection Account"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: code:addons/l10n_eu_service/wizard/wizard.py:36
|
||||
#, python-format
|
||||
msgid "The Europe country group cannot be found. Please update the base module."
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: field:l10n_eu_service.service_tax_rate,rate:0
|
||||
msgid "VAT Rate"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: code:addons/l10n_eu_service/wizard/wizard.py:132
|
||||
#, python-format
|
||||
msgid "VAT for EU Services to %(country_name)s"
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: view:l10n_eu_service.wizard:l10n_eu_service.eu_service_view
|
||||
msgid "You can use the wizard again later to add more countries."
|
||||
msgstr ""
|
||||
|
||||
#. module: l10n_eu_service
|
||||
#: view:l10n_eu_service.wizard:l10n_eu_service.eu_service_view
|
||||
msgid "or"
|
||||
msgstr ""
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
import eu_service_tax_rate
|
||||
@@ -0,0 +1,7 @@
|
||||
from openerp import fields, models, api
|
||||
|
||||
class service_tax_rate(models.Model):
|
||||
_name = "l10n_eu_service.service_tax_rate"
|
||||
|
||||
country_id = fields.Many2one('res.country', string='Country')
|
||||
rate = fields.Float(string="VAT Rate")
|
||||
@@ -0,0 +1,3 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_l10n_eu_service_service_tax_rate,access_l10n_eu_service_service_tax_rate,model_l10n_eu_service_service_tax_rate,,1,0,0,0
|
||||
access_l10n_eu_service_service_tax_rate,access_l10n_eu_service_service_tax_rate,model_l10n_eu_service_service_tax_rate,account.group_account_manager,1,1,1,1
|
||||
|
@@ -0,0 +1 @@
|
||||
import wizard
|
||||
@@ -0,0 +1,30 @@
|
||||
id,country_id:id,rate
|
||||
eu_rate_at,base.at,0.21
|
||||
eu_rate_be,base.be,0.21
|
||||
eu_rate_bg,base.bg,0.20
|
||||
eu_rate_hr,base.hr,0.25
|
||||
eu_rate_cy,base.cy,0.21
|
||||
eu_rate_cz,base.cz,0.21
|
||||
eu_rate_dk,base.dk,0.25
|
||||
eu_rate_ee,base.ee,0.20
|
||||
eu_rate_fi,base.fi,0.24
|
||||
eu_rate_fr,base.fr,0.20
|
||||
eu_rate_de,base.de,0.19
|
||||
eu_rate_gr,base.gr,0.23
|
||||
eu_rate_hu,base.hu,0.27
|
||||
eu_rate_ie,base.ie,0.23
|
||||
eu_rate_it,base.it,0.22
|
||||
eu_rate_lv,base.lv,0.21
|
||||
eu_rate_lt,base.lt,0.21
|
||||
eu_rate_lu,base.lu,0.17
|
||||
eu_rate_mt,base.mt,0.18
|
||||
eu_rate_nl,base.nl,0.21
|
||||
eu_rate_pl,base.pl,0.23
|
||||
eu_rate_pt,base.pt,0.23
|
||||
eu_rate_ro,base.ro,0.24
|
||||
eu_rate_pt,base.pt,0.23
|
||||
eu_rate_sk,base.sk,0.20
|
||||
eu_rate_si,base.si,0.22
|
||||
eu_rate_es,base.es,0.21
|
||||
eu_rate_se,base.se,0.24
|
||||
eu_rate_uk,base.uk,0.20
|
||||
|
@@ -0,0 +1,177 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Odoo, Open Source Business Applications
|
||||
# Copyright (C) 2015 Odoo S.A. <http://www.odoo.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.exceptions import Warning
|
||||
from openerp import fields, models, api
|
||||
from openerp.tools.translate import _
|
||||
|
||||
class l10n_eu_service(models.TransientModel):
|
||||
|
||||
"""Create fiscal positions for EU Service VAT"""
|
||||
|
||||
_name = "l10n_eu_service.wizard"
|
||||
_description = __doc__
|
||||
|
||||
def _get_eu_res_country_group(self):
|
||||
eu_group = self.env.ref("base.europe", raise_if_not_found=False)
|
||||
if not eu_group:
|
||||
raise Warning(_('The Europe country group cannot be found. '
|
||||
'Please update the base module.'))
|
||||
return eu_group
|
||||
|
||||
def _default_chart_id(self):
|
||||
user = self.env.user
|
||||
return self.env['account.account'].search(
|
||||
[('company_id', '=', user.company_id.id), ('parent_id', '=', False)], limit=1)
|
||||
|
||||
def _default_fiscal_position_id(self):
|
||||
user = self.env.user
|
||||
eu_id = self._get_eu_res_country_group()
|
||||
return self.env['account.fiscal.position'].search(
|
||||
[('company_id', '=', user.company_id.id), ('vat_required', '=', True),
|
||||
('country_group_id.id', '=', eu_id.id)], limit=1)
|
||||
|
||||
def _default_tax_id(self):
|
||||
user = self.env.user
|
||||
return self.env['account.tax'].search(
|
||||
[('company_id', '=', user.company_id.id), ('type_tax_use', '=', 'sale'),
|
||||
('type', '=', 'percent'), ('account_collected_id', '!=', False),
|
||||
('tax_code_id', '!=', False)], limit=1, order='amount desc')
|
||||
|
||||
def _default_done_country_ids(self):
|
||||
user = self.env.user
|
||||
eu_country_group = self._get_eu_res_country_group()
|
||||
return eu_country_group.country_ids - self._default_todo_country_ids() - user.company_id.country_id
|
||||
|
||||
def _default_todo_country_ids(self):
|
||||
user = self.env.user
|
||||
eu_country_group = self._get_eu_res_country_group()
|
||||
eu_fiscal = self.env['account.fiscal.position'].search(
|
||||
[('country_id', 'in', eu_country_group.country_ids.ids),
|
||||
('vat_required', '=', False), ('auto_apply', '=', True),
|
||||
('company_id', '=', user.company_id.id)])
|
||||
return eu_country_group.country_ids - eu_fiscal.mapped('country_id') - user.company_id.country_id
|
||||
|
||||
chart_id = fields.Many2one(
|
||||
"account.account", string="Chart of Accounts", required=True, default=_default_chart_id)
|
||||
company_id = fields.Many2one(
|
||||
'res.company', string='Company', required=True,
|
||||
related='chart_id.company_id', readonly=True)
|
||||
fiscal_position_id = fields.Many2one(
|
||||
'account.fiscal.position', string='Fiscal Position', default=_default_fiscal_position_id,
|
||||
help="Optional fiscal position to use as template for general account mapping. "
|
||||
"Should usually be your current Intra-EU B2B fiscal position. "
|
||||
"If not set, no general account mapping will be configured for EU fiscal positions.")
|
||||
tax_id = fields.Many2one(
|
||||
'account.tax', string='Service VAT', required=True, default=_default_tax_id,
|
||||
help="Select your current VAT tax for services. This is the tax that will be mapped "
|
||||
"to the corresponding VAT tax in each EU country selected below.")
|
||||
account_collected_id = fields.Many2one(
|
||||
"account.account", string="Tax Collection Account",
|
||||
help="Optional account to use for collecting tax amounts when selling services in "
|
||||
"each EU country selected below. If not set, the current collecting account of "
|
||||
"your Service VAT will be used.")
|
||||
done_country_ids = fields.Many2many(
|
||||
'res.country', 'l10n_eu_service_country_rel_done', default=_default_done_country_ids,
|
||||
string='Already Supported')
|
||||
todo_country_ids = fields.Many2many(
|
||||
'res.country', 'l10n_eu_service_country_rel_todo', default=_default_todo_country_ids,
|
||||
string='EU Customers From', required=True)
|
||||
|
||||
@api.multi
|
||||
def generate_eu_service(self):
|
||||
imd = self.env['ir.model.data']
|
||||
tax_code = self.env['account.tax.code']
|
||||
tax_rate = self.env["l10n_eu_service.service_tax_rate"]
|
||||
account_tax = self.env['account.tax']
|
||||
fpos = self.env['account.fiscal.position']
|
||||
chart_xid = 'l10n_eu_service.tax_chart_service_eu_company_%s' % self.company_id.name
|
||||
chart = self.env.ref(chart_xid, raise_if_not_found=False)
|
||||
if not chart:
|
||||
vals = {
|
||||
'name': _("EU MOSS VAT Chart - %(company)s") % {'company': self.company_id.name},
|
||||
'company_id': self.company_id.id,
|
||||
'parent_id': False
|
||||
}
|
||||
chart_id = tax_code.create(vals).id
|
||||
vals_data = {
|
||||
'name': 'tax_chart_service_eu_company_%s'%(self.company_id.name),
|
||||
'model': 'account.tax.code',
|
||||
'module': 'l10n_eu_service',
|
||||
'res_id': chart_id,
|
||||
'noupdate': True, # Don't drop it when module is updated
|
||||
}
|
||||
imd.create(vals_data)
|
||||
else:
|
||||
chart_id = chart.id
|
||||
for country in self.todo_country_ids:
|
||||
format_params = {'country_name': country.name}
|
||||
tx_base_code_data = {
|
||||
'name': _("Base - VAT for EU Services to %(country_name)s") % format_params,
|
||||
'code': "BASE-EU-VAT-%s" % country.code,
|
||||
'parent_id': chart_id,
|
||||
}
|
||||
tax_name = _("VAT for EU Services to %(country_name)s") % format_params
|
||||
tx_code_data = {
|
||||
'name': tax_name,
|
||||
'code': "EU-VAT-%s" % country.code,
|
||||
'parent_id': chart_id,
|
||||
}
|
||||
tx_base_code = tax_code.create(tx_base_code_data)
|
||||
tx_code = tax_code.create(tx_code_data)
|
||||
#create a new tax based on the selected service tax
|
||||
data_tax = {
|
||||
'name': tax_name,
|
||||
'amount': tax_rate.search([('country_id', '=', country.id)]).rate,
|
||||
'base_code_id': self.tax_id.base_code_id.id,
|
||||
'account_collected_id': self.account_collected_id.id or self.tax_id.account_collected_id.id,
|
||||
'account_paid_id': self.account_collected_id.id or self.tax_id.account_collected_id.id,
|
||||
'type_tax_use': 'sale',
|
||||
'base_code_id': tx_base_code.id,
|
||||
'ref_base_code_id': tx_base_code.id,
|
||||
'tax_code_id': tx_code.id,
|
||||
'ref_tax_code_id': tx_code.id,
|
||||
'ref_base_sign': -1,
|
||||
'ref_tax_sign': -1,
|
||||
'description': "EU-VAT-%s-S" % country.code
|
||||
}
|
||||
tax = account_tax.create(data_tax)
|
||||
if self.fiscal_position_id:
|
||||
account_ids = [(6, 0, self.fiscal_position_id.account_ids.ids)]
|
||||
else:
|
||||
account_ids = False
|
||||
#create a fiscal position for the country
|
||||
fiscal_pos_name = _("Intra-EU B2C in %(country_name)s") % {'country_name': country.name}
|
||||
fiscal_pos_name += " (EU-VAT-%s)" % country.code
|
||||
data_fiscal = {
|
||||
'name': fiscal_pos_name,
|
||||
'company_id': self.chart_id.company_id.id,
|
||||
'vat_required': False,
|
||||
'auto_apply': True,
|
||||
'country_id': country.id,
|
||||
'account_ids': account_ids,
|
||||
'tax_ids': [(0, 0, {'tax_src_id': self.tax_id.id, 'tax_dest_id': tax.id})],
|
||||
}
|
||||
fpos.create(data_fiscal)
|
||||
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="eu_service_view" model="ir.ui.view">
|
||||
<field name="name">l10n_eu_service.wizard.form</field>
|
||||
<field name="model">l10n_eu_service.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string='Setup EU MOSS Taxes'>
|
||||
<p>
|
||||
Based on the options selected below, this wizard will create one
|
||||
fiscal position mapping for each EU country to which you are selling
|
||||
services.
|
||||
Each fiscal position will automatically map your national VAT tax for
|
||||
services to the corresponding VAT tax in the country your customer
|
||||
belongs to.
|
||||
<br/>
|
||||
You can use the wizard again later to add more countries.
|
||||
</p>
|
||||
<group>
|
||||
<field name="chart_id" domain="[('parent_id','=', False)]"
|
||||
context="{'company_id': company_id}" options="{'no_create': True}"/>
|
||||
<field name="company_id" invisible="1"/>
|
||||
<field name="fiscal_position_id" domain="[('company_id','=', company_id)]"
|
||||
options="{'no_create': True}"
|
||||
placeholder="Current EU B2C Fiscal Position, if any"/>
|
||||
<field name="tax_id"
|
||||
domain="[('type_tax_use', '=', 'sale'),
|
||||
('type', '=', 'percent'),
|
||||
('account_collected_id', '!=', False),
|
||||
('tax_code_id', '!=', False),
|
||||
('company_id','=', company_id)]"
|
||||
options="{'no_create': True}"/>
|
||||
<field name="account_collected_id"
|
||||
placeholder="Keep empty to use current Service VAT account"/>
|
||||
<field name="done_country_ids" widget="many2many_tags" readonly="1"
|
||||
attrs="{'invisible': [('done_country_ids', '=', [(6, False, [])])]}"/>
|
||||
<field name="todo_country_ids" widget="many2many_tags"
|
||||
domain="[('country_group_ids', 'in', %(base.europe)d)]"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button string="Create Fiscal Positions and Taxes"
|
||||
name="generate_eu_service" type="object" class="oe_highlight"/>
|
||||
or
|
||||
<button string="Cancel" class="oe_link" special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_eu_service" model="ir.actions.act_window">
|
||||
<field name="name">Setup EU MOSS Taxes</field>
|
||||
<field name="res_model">l10n_eu_service.wizard</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="eu_service_view"/>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
<record id="open_l10n_eu_service" model="ir.actions.todo">
|
||||
<field name="action_id" ref="action_eu_service"/>
|
||||
<field name="type">automatic</field>
|
||||
<field name="state">open</field>
|
||||
</record>
|
||||
|
||||
<record id="view_account_config_settings_inherit" model="ir.ui.view">
|
||||
<field name="name">account settings</field>
|
||||
<field name="model">account.config.settings</field>
|
||||
<field name="inherit_id" ref="account.view_account_config_settings"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="default_sale_tax" position="after">
|
||||
<button type="action" name="%(action_eu_service)d"
|
||||
string="Setup EU MOSS Taxes" class="oe_link"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1332,7 +1332,7 @@ Cuentas del plan
|
||||
|
||||
<record id="cuenta1121001000" model="account.account.template">
|
||||
<field name="code">1121001000</field>
|
||||
<field name="reconcile" eval="False"/>
|
||||
<field name="reconcile" eval="True"/>
|
||||
<field name="parent_id" ref="cuenta1121"/>
|
||||
<field name="type">receivable</field>
|
||||
<field name="user_type" ref="account_type_receivable"/>
|
||||
@@ -1341,7 +1341,7 @@ Cuentas del plan
|
||||
|
||||
<record id="cuenta1122001000" model="account.account.template">
|
||||
<field name="code">1122001000</field>
|
||||
<field name="reconcile" eval="False"/>
|
||||
<field name="reconcile" eval="True"/>
|
||||
<field name="parent_id" ref="cuenta1122"/>
|
||||
<field name="type">receivable</field>
|
||||
<field name="user_type" ref="account_type_receivable"/>
|
||||
@@ -1359,7 +1359,7 @@ Cuentas del plan
|
||||
|
||||
<record id="cuenta1122004000" model="account.account.template">
|
||||
<field name="code">1122004000</field>
|
||||
<field name="reconcile" eval="False"/>
|
||||
<field name="reconcile" eval="True"/>
|
||||
<field name="parent_id" ref="cuenta1122"/>
|
||||
<field name="type">receivable</field>
|
||||
<field name="user_type" ref="account_type_receivable"/>
|
||||
@@ -1368,7 +1368,7 @@ Cuentas del plan
|
||||
|
||||
<record id="cuenta1122005000" model="account.account.template">
|
||||
<field name="code">1122005000</field>
|
||||
<field name="reconcile" eval="False"/>
|
||||
<field name="reconcile" eval="True"/>
|
||||
<field name="parent_id" ref="cuenta1122"/>
|
||||
<field name="type">receivable</field>
|
||||
<field name="user_type" ref="account_type_receivable"/>
|
||||
@@ -1395,7 +1395,7 @@ Cuentas del plan
|
||||
|
||||
<record id="cuenta1125001000" model="account.account.template">
|
||||
<field name="code">1125001000</field>
|
||||
<field name="reconcile" eval="False"/>
|
||||
<field name="reconcile" eval="True"/>
|
||||
<field name="parent_id" ref="cuenta1125"/>
|
||||
<field name="type">receivable</field>
|
||||
<field name="user_type" ref="account_type_receivable"/>
|
||||
@@ -1413,7 +1413,7 @@ Cuentas del plan
|
||||
|
||||
<record id="cuenta1125003000" model="account.account.template">
|
||||
<field name="code">1125003000</field>
|
||||
<field name="reconcile" eval="False"/>
|
||||
<field name="reconcile" eval="True"/>
|
||||
<field name="parent_id" ref="cuenta1125"/>
|
||||
<field name="type">receivable</field>
|
||||
<field name="user_type" ref="account_type_receivable"/>
|
||||
@@ -1467,7 +1467,7 @@ Cuentas del plan
|
||||
|
||||
<record id="cuenta1128001000" model="account.account.template">
|
||||
<field name="code">1128001000</field>
|
||||
<field name="reconcile" eval="False"/>
|
||||
<field name="reconcile" eval="True"/>
|
||||
<field name="parent_id" ref="cuenta1128"/>
|
||||
<field name="type">receivable</field>
|
||||
<field name="user_type" ref="account_type_receivable"/>
|
||||
@@ -1530,7 +1530,7 @@ Cuentas del plan
|
||||
|
||||
<record id="cuenta1129009000" model="account.account.template">
|
||||
<field name="code">1129009000</field>
|
||||
<field name="reconcile" eval="False"/>
|
||||
<field name="reconcile" eval="True"/>
|
||||
<field name="parent_id" ref="cuenta1129"/>
|
||||
<field name="type">receivable</field>
|
||||
<field name="user_type" ref="account_type_receivable"/>
|
||||
@@ -1881,7 +1881,7 @@ Cuentas del plan
|
||||
|
||||
<record id="cuenta1271005000" model="account.account.template">
|
||||
<field name="code">1271005000</field>
|
||||
<field name="reconcile" eval="False"/>
|
||||
<field name="reconcile" eval="True"/>
|
||||
<field name="parent_id" ref="cuenta1271"/>
|
||||
<field name="type">receivable</field>
|
||||
<field name="user_type" ref="account_type_receivable"/>
|
||||
@@ -1944,7 +1944,7 @@ Cuentas del plan
|
||||
|
||||
<record id="cuenta2122001000" model="account.account.template">
|
||||
<field name="code">2122001000</field>
|
||||
<field name="reconcile" eval="False"/>
|
||||
<field name="reconcile" eval="True"/>
|
||||
<field name="parent_id" ref="cuenta2122"/>
|
||||
<field name="type">payable</field>
|
||||
<field name="user_type" ref="account_type_payable"/>
|
||||
@@ -1971,7 +1971,7 @@ Cuentas del plan
|
||||
|
||||
<record id="cuenta2122005000" model="account.account.template">
|
||||
<field name="code">2122005000</field>
|
||||
<field name="reconcile" eval="False"/>
|
||||
<field name="reconcile" eval="True"/>
|
||||
<field name="parent_id" ref="cuenta2122"/>
|
||||
<field name="type">payable</field>
|
||||
<field name="user_type" ref="account_type_payable"/>
|
||||
@@ -1980,7 +1980,7 @@ Cuentas del plan
|
||||
|
||||
<record id="cuenta2124001000" model="account.account.template">
|
||||
<field name="code">2124001000</field>
|
||||
<field name="reconcile" eval="False"/>
|
||||
<field name="reconcile" eval="True"/>
|
||||
<field name="parent_id" ref="cuenta2124"/>
|
||||
<field name="type">payable</field>
|
||||
<field name="user_type" ref="account_type_payable"/>
|
||||
@@ -1989,7 +1989,7 @@ Cuentas del plan
|
||||
|
||||
<record id="cuenta2151001000" model="account.account.template">
|
||||
<field name="code">2151001000</field>
|
||||
<field name="reconcile" eval="False"/>
|
||||
<field name="reconcile" eval="True"/>
|
||||
<field name="parent_id" ref="cuenta2151"/>
|
||||
<field name="type">payable</field>
|
||||
<field name="user_type" ref="account_type_payable"/>
|
||||
@@ -1998,7 +1998,7 @@ Cuentas del plan
|
||||
|
||||
<record id="cuenta2151002000" model="account.account.template">
|
||||
<field name="code">2151002000</field>
|
||||
<field name="reconcile" eval="False"/>
|
||||
<field name="reconcile" eval="True"/>
|
||||
<field name="parent_id" ref="cuenta2151"/>
|
||||
<field name="type">receivable</field>
|
||||
<field name="user_type" ref="account_type_receivable"/>
|
||||
@@ -2151,7 +2151,7 @@ Cuentas del plan
|
||||
|
||||
<record id="cuenta2175008000" model="account.account.template">
|
||||
<field name="code">2175008000</field>
|
||||
<field name="reconcile" eval="False"/>
|
||||
<field name="reconcile" eval="True"/>
|
||||
<field name="parent_id" ref="cuenta2175"/>
|
||||
<field name="type">payable</field>
|
||||
<field name="user_type" ref="account_type_payable"/>
|
||||
@@ -2205,7 +2205,7 @@ Cuentas del plan
|
||||
|
||||
<record id="cuenta2175014000" model="account.account.template">
|
||||
<field name="code">2175014000</field>
|
||||
<field name="reconcile" eval="False"/>
|
||||
<field name="reconcile" eval="True"/>
|
||||
<field name="parent_id" ref="cuenta2175"/>
|
||||
<field name="type">payable</field>
|
||||
<field name="user_type" ref="account_type_payable"/>
|
||||
@@ -2223,7 +2223,7 @@ Cuentas del plan
|
||||
|
||||
<record id="cuenta2175017000" model="account.account.template">
|
||||
<field name="code">2175017000</field>
|
||||
<field name="reconcile" eval="False"/>
|
||||
<field name="reconcile" eval="True"/>
|
||||
<field name="parent_id" ref="cuenta2175"/>
|
||||
<field name="type">payable</field>
|
||||
<field name="user_type" ref="account_type_payable"/>
|
||||
@@ -2232,7 +2232,7 @@ Cuentas del plan
|
||||
|
||||
<record id="cuenta2175018000" model="account.account.template">
|
||||
<field name="code">2175018000</field>
|
||||
<field name="reconcile" eval="False"/>
|
||||
<field name="reconcile" eval="True"/>
|
||||
<field name="parent_id" ref="cuenta2175"/>
|
||||
<field name="type">payable</field>
|
||||
<field name="user_type" ref="account_type_payable"/>
|
||||
|
||||
@@ -379,8 +379,15 @@ class PaymentTransaction(osv.Model):
|
||||
help='Reference of the customer in the acquirer database'),
|
||||
}
|
||||
|
||||
_sql_constraints = [
|
||||
('reference_uniq', 'UNIQUE(reference)', 'The payment transaction reference must be unique!'),
|
||||
def _check_reference(self, cr, uid, ids, context=None):
|
||||
transaction = self.browse(cr, uid, ids[0], context=context)
|
||||
if transaction.state not in ['cancel', 'error']:
|
||||
if self.search(cr, uid, [('reference', '=', transaction.reference), ('id', '!=', transaction.id)], context=context, count=True):
|
||||
return False
|
||||
return True
|
||||
|
||||
_constraints = [
|
||||
(_check_reference, 'The payment transaction reference must be unique!', ['reference', 'state']),
|
||||
]
|
||||
|
||||
_defaults = {
|
||||
|
||||
@@ -663,7 +663,8 @@ class product_template(osv.osv):
|
||||
for variant in all_variants:
|
||||
for value_id in variant_id.value_ids:
|
||||
temp_variants.append(variant + [int(value_id)])
|
||||
all_variants = temp_variants
|
||||
if temp_variants:
|
||||
all_variants = temp_variants
|
||||
|
||||
# adding an attribute with only one value should not recreate product
|
||||
# write this attribute on every product to make sure we don't lose them
|
||||
@@ -1107,6 +1108,9 @@ class product_product(osv.osv):
|
||||
if context is None:
|
||||
context={}
|
||||
|
||||
if default is None:
|
||||
default = {}
|
||||
|
||||
product = self.browse(cr, uid, id, context)
|
||||
if context.get('variant'):
|
||||
# if we copy a variant or create one, we keep the same template
|
||||
|
||||
@@ -1297,6 +1297,11 @@ class procurement_order(osv.osv):
|
||||
|
||||
def _get_product_supplier(self, cr, uid, procurement, context=None):
|
||||
''' returns the main supplier of the procurement's product given as argument'''
|
||||
supplierinfo = self.pool['product.supplierinfo']
|
||||
company_supplier = supplierinfo.search(cr, uid,
|
||||
[('product_tmpl_id', '=', procurement.product_id.product_tmpl_id.id), ('company_id', '=', procurement.company_id.id)], limit=1, context=context)
|
||||
if company_supplier:
|
||||
return supplierinfo.browse(cr, uid, company_supplier[0], context=context).name
|
||||
return procurement.product_id.seller_id
|
||||
|
||||
def _get_po_line_values_from_procs(self, cr, uid, procurements, partner, schedule_date, context=None):
|
||||
|
||||
@@ -1384,7 +1384,7 @@ instance.web.WebClient = instance.web.Client.extend({
|
||||
},
|
||||
update_logo: function() {
|
||||
var company = this.session.company_id;
|
||||
var img = this.session.url('/web/binary/company_logo' + (company ? '?company=' + company : ''));
|
||||
var img = this.session.url('/web/binary/company_logo' + '?db=' + this.session.db + (company ? '&company=' + company : ''));
|
||||
this.$('.oe_logo img').attr('src', '').attr('src', img);
|
||||
this.$('.oe_logo_edit').toggleClass('oe_logo_edit_admin', this.session.uid === 1);
|
||||
},
|
||||
|
||||
@@ -226,6 +226,7 @@
|
||||
var item = false;
|
||||
if (record) {
|
||||
item = record.attributes;
|
||||
this.dataset.select_id(record.get('id'));
|
||||
} else {
|
||||
record = this.make_empty_record(false);
|
||||
this.records.add(record, {
|
||||
|
||||
@@ -869,6 +869,10 @@ div.media_iframe_video .css_editable_mode_display {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
html[data-browser^="msie"] div.media_iframe_video iframe {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
/* Mobile view */
|
||||
@media (max-width: 768px) {
|
||||
img:not(.cke_iframe), .media_iframe_video, span.fa, i.fa {
|
||||
|
||||
@@ -685,6 +685,9 @@ div.media_iframe_video
|
||||
display: none
|
||||
z-index: 2
|
||||
|
||||
html[data-browser^="msie"] div.media_iframe_video iframe
|
||||
margin-left: 0
|
||||
|
||||
/* Mobile view */
|
||||
|
||||
@media (max-width: 768px)
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
/* --- Set the browser into the dom for css selectors --- */
|
||||
var browser;
|
||||
if ($.browser.webkit) browser = "webkit";
|
||||
else if ($.browser.safari) browser = "safari";
|
||||
else if ($.browser.opera) browser = "opera";
|
||||
else if ($.browser.msie || ($.browser.mozilla && +$.browser.version.replace(/^([0-9]+\.[0-9]+).*/, '\$1') < 20)) browser = "msie";
|
||||
else if ($.browser.mozilla) browser = "mozilla";
|
||||
browser += ","+$.browser.version;
|
||||
if (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase())) browser += ",mobile";
|
||||
document.documentElement.setAttribute('data-browser', browser);
|
||||
/* ---------------------------------------------------- */
|
||||
|
||||
var website = {};
|
||||
openerp.website = website;
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-6 mt16">
|
||||
<img class="img img-responsive shadow mb16" src="/website/static/src/img/text_image.png"/>
|
||||
<img class="img img-responsive shadow mb16" src="/website/static/src/img/text_image.png" alt="Odoo text and image block"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -59,7 +59,7 @@
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mt16">
|
||||
<img class="img img-responsive shadow mb16" src="/website/static/src/img/image_text.jpg"/>
|
||||
<img class="img img-responsive shadow mb16" src="/website/static/src/img/image_text.jpg" alt="Odoo image and text block"/>
|
||||
</div>
|
||||
<div class="col-md-6 mt16">
|
||||
<h3>A Section Subtitle</h3>
|
||||
@@ -84,7 +84,7 @@
|
||||
<div class="col-md-12 mb16 mt16">
|
||||
<div class="o_image_floating o_margin_l pull-right">
|
||||
<div class="o_container">
|
||||
<img class="img img-rounded img-responsive" src="/website/static/src/img/odoo.jpg"/>
|
||||
<img class="img img-rounded img-responsive" src="/website/static/src/img/odoo.jpg" alt="Odoo Members"/>
|
||||
<mark class="text-center"><a href="#"><strong>Click Here</strong></a></mark>
|
||||
</div>
|
||||
<div class="o_footer">
|
||||
@@ -214,7 +214,7 @@
|
||||
<h2>A Punchy Headline</h2>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<img class="img img-responsive" src="/website/static/src/img/big_picture.png" style="margin: 0 auto;"/>
|
||||
<img class="img img-responsive" src="/website/static/src/img/big_picture.png" style="margin: 0 auto;" alt="Odoo CMS - a big picture"/>
|
||||
</div>
|
||||
<div class="col-md-6 col-md-offset-3 mb16 mt16">
|
||||
<p class="text-center">
|
||||
@@ -239,7 +239,7 @@
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<img class="img img-rounded img-responsive" src="/website/static/src/img/desert_thumb.jpg"/>
|
||||
<img class="img img-rounded img-responsive" src="/website/static/src/img/desert_thumb.jpg" alt="Odoo - Sample 1 for three columns"/>
|
||||
<h4 class="mt16">Feature One</h4>
|
||||
<p>
|
||||
Adapt these three columns to fit you design need.
|
||||
@@ -248,7 +248,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<img class="img img-rounded img-responsive" src="/website/static/src/img/deers_thumb.jpg"/>
|
||||
<img class="img img-rounded img-responsive" src="/website/static/src/img/deers_thumb.jpg" alt="Odoo - Sample 2 for three columns"/>
|
||||
<h4 class="mt16">Feature Two</h4>
|
||||
<p>
|
||||
To add a fourth column, reduce the size of these
|
||||
@@ -258,7 +258,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<img class="img img-rounded img-responsive" src="/website/static/src/img/china_thumb.jpg"/>
|
||||
<img class="img img-rounded img-responsive" src="/website/static/src/img/china_thumb.jpg" alt="Odoo - Sample 3 for three columns"/>
|
||||
<h4 class="mt16">Feature Three</h4>
|
||||
<p>
|
||||
Delete the above image or replace it with a picture
|
||||
@@ -307,7 +307,7 @@
|
||||
<template id="s_image_floating" name="Image Floating">
|
||||
<div class="o_image_floating o_margin_l pull-right s_image_floating">
|
||||
<div class="o_container">
|
||||
<img class="img img-rounded img-responsive" src="/website/static/src/img/library/ipad.png"/>
|
||||
<img class="img img-rounded img-responsive" src="/website/static/src/img/library/ipad.png" alt="Odoo CMS- Sample image floating"/>
|
||||
<mark class="text-center"><a href="#"><strong>Click Here</strong></a></mark>
|
||||
</div>
|
||||
<div class="o_footer">
|
||||
@@ -538,19 +538,19 @@
|
||||
</blockquote>
|
||||
</div>
|
||||
<div class="col-md-2 col-md-offset-1">
|
||||
<img src="/website/static/src/img/openerp_logo.png" class="img img-responsive img-thumbnail"/>
|
||||
<img src="/website/static/src/img/openerp_logo.png" class="img img-responsive img-thumbnail" alt="OpenERP logo"/>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<img src="/website/static/src/img/openerp_logo.png" class="img img-responsive img-thumbnail"/>
|
||||
<img src="/website/static/src/img/openerp_logo.png" class="img img-responsive img-thumbnail" alt="OpenERP logo"/>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<img src="/website/static/src/img/openerp_logo.png" class="img img-responsive img-thumbnail"/>
|
||||
<img src="/website/static/src/img/openerp_logo.png" class="img img-responsive img-thumbnail" alt="OpenERP logo"/>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<img src="/website/static/src/img/openerp_logo.png" class="img img-responsive img-thumbnail"/>
|
||||
<img src="/website/static/src/img/openerp_logo.png" class="img img-responsive img-thumbnail" alt="OpenERP logo"/>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<img src="/website/static/src/img/openerp_logo.png" class="img img-responsive img-thumbnail"/>
|
||||
<img src="/website/static/src/img/openerp_logo.png" class="img img-responsive img-thumbnail" alt="OpenERP logo"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -167,8 +167,8 @@
|
||||
Create a <a href="http://www.odoo.com/page/website-builder">free website</a> with
|
||||
<a class="label label-danger" href="http://www.odoo.com/page/website-builder">Odoo</a>
|
||||
</div>
|
||||
<div class="pull-left text-muted">
|
||||
Copyright &copy; <span t-field="res_company.name">Company name</span>
|
||||
<div class="pull-left text-muted" itemscope="itemscope" itemtype="http://schema.org/Organization">
|
||||
Copyright &copy; <span t-field="res_company.name" itemprop="name">Company name</span>
|
||||
</div>
|
||||
</div>
|
||||
</xpath>
|
||||
@@ -363,7 +363,7 @@
|
||||
<a t-att-href="website.social_twitter" t-if="website.social_twitter"><i class="fa fa-twitter"/></a>
|
||||
<a t-att-href="website.social_linkedin" t-if="website.social_linkedin"><i class="fa fa-linkedin"/></a>
|
||||
<a t-att-href="website.social_youtube" t-if="website.social_youtube"><i class="fa fa-youtube-play"/></a>
|
||||
<a t-att-href="website.social_googleplus" t-if="website.social_googleplus"><i class="fa fa-google-plus-square"/></a>
|
||||
<a t-att-href="website.social_googleplus" t-if="website.social_googleplus" rel="publisher"><i class="fa fa-google-plus-square"/></a>
|
||||
<a t-att-href="website.social_github" t-if="website.social_github"><i class="fa fa-github"/></a>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
@@ -42,7 +42,7 @@ class sale_order(osv.Model):
|
||||
values['event_id'] = ticket.event_id.id
|
||||
values['event_ticket_id'] = ticket.id
|
||||
values['price_unit'] = ticket.price
|
||||
values['name'] = "%s: %s" % (ticket.event_id.name, ticket.name)
|
||||
values['name'] = "%s\n%s" % (ticket.event_id.display_name, ticket.name)
|
||||
|
||||
return values
|
||||
|
||||
|
||||
@@ -142,6 +142,8 @@ class sale_quote(http.Controller):
|
||||
order = request.registry.get('sale.order').browse(request.cr, SUPERUSER_ID, order_id)
|
||||
if token != order.access_token:
|
||||
return request.website.render('website.404')
|
||||
if order.state not in ['draft', 'sent']:
|
||||
return request.website.render('website.http_error', {'status_code': 'Forbidden', 'status_message': _('You cannot add options to a confirmed order.')})
|
||||
option_obj = request.registry.get('sale.order.option')
|
||||
option = option_obj.browse(request.cr, SUPERUSER_ID, option_id)
|
||||
|
||||
|
||||
@@ -457,7 +457,7 @@
|
||||
</div>
|
||||
</strong>
|
||||
</td>
|
||||
<td class="pull-right">
|
||||
<td class="pull-right" t-if="quotation.state in ['draft', 'sent']">
|
||||
<a t-attf-href="/quote/add_line/#{ option.id }/#{ quotation.id }/#{ quotation.access_token }" class="mb8 hidden-print">
|
||||
<span class="fa fa-shopping-cart"/>
|
||||
</a>
|
||||
|
||||
@@ -63,7 +63,7 @@ class sale_order(osv.Model):
|
||||
values['name'] = line.name
|
||||
else:
|
||||
product = self.pool.get('product.product').browse(cr, uid, product_id, context=context)
|
||||
values['name'] = product.description_sale or product.name
|
||||
values['name'] = "%s\n%s" % (product.display_name, product.description_sale)
|
||||
|
||||
values['product_id'] = product_id
|
||||
values['order_id'] = order_id
|
||||
|
||||
@@ -193,6 +193,79 @@
|
||||
height: 570px; }
|
||||
.col-md-9 .oe-height-8 {
|
||||
height: 760px; } }
|
||||
/* ---- Cart ---- */
|
||||
.oe_cart a span.visible-xs-inline, #modal_optional_products a span.visible-xs-inline {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.oe_cart a span.hidden-xs, #modal_optional_products a span.hidden-xs {
|
||||
display: inline !important;
|
||||
}
|
||||
|
||||
.oe_cart table td:first-child {
|
||||
min-width: 76px;
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
#modal_optional_products table:last-child td:last-child {
|
||||
overflow: hidden;
|
||||
}
|
||||
#modal_optional_products table:last-child td:nth-child(2) {
|
||||
width: 50%;
|
||||
}
|
||||
#modal_optional_products table:last-child td:nth-child(3) {
|
||||
width: 20%;
|
||||
}
|
||||
#modal_optional_products table:last-child td:last-child, #modal_optional_products table:last-child td:nth-last-child(2) {
|
||||
width: 15%;
|
||||
}
|
||||
}
|
||||
@media (max-width: 500px) {
|
||||
.oe_website_sale .oe_website_spinner {
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.oe_cart table, #modal_optional_products table {
|
||||
display: inline-block;
|
||||
}
|
||||
.oe_cart table thead, #modal_optional_products table thead {
|
||||
display: none;
|
||||
}
|
||||
.oe_cart table tbody, .oe_cart table tr, .oe_cart table td, #modal_optional_products table tbody, #modal_optional_products table tr, #modal_optional_products table td {
|
||||
float: left;
|
||||
width: 100% !important;
|
||||
display: inline-block;
|
||||
}
|
||||
.oe_cart table td:first-child, #modal_optional_products table td:first-child {
|
||||
display: none;
|
||||
}
|
||||
.oe_cart table td:nth-child(2), #modal_optional_products table td:nth-child(2) {
|
||||
border-top-style: double;
|
||||
border-top-width: 6px;
|
||||
}
|
||||
.oe_cart table td:last-child, #modal_optional_products table td:last-child {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.oe_cart table:last-child tr:last-child td:last-child, #modal_optional_products table:last-child tr:last-child td:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.oe_cart table td:last-child, .oe_cart table td:nth-last-child(2), #modal_optional_products table td:last-child, #modal_optional_products table td:nth-last-child(2) {
|
||||
width: 50% !important;
|
||||
height: 46px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#modal_optional_products table:last-child td:nth-child(3) > div {
|
||||
float: none !important;
|
||||
}
|
||||
|
||||
.oe_cart a span.hidden-xs, #modal_optional_products a span.hidden-xs {
|
||||
display: none !important;
|
||||
}
|
||||
.oe_cart a span.visible-xs-inline, #modal_optional_products a span.visible-xs-inline {
|
||||
display: inline !important;
|
||||
}
|
||||
}
|
||||
/* ---- Product list style ---- */
|
||||
@media (min-width: 400px) {
|
||||
.oe_product.oe_list {
|
||||
|
||||
@@ -218,6 +218,58 @@
|
||||
.oe-height-8
|
||||
height: 760px
|
||||
|
||||
/* ---- Cart ---- */
|
||||
.oe_cart, #modal_optional_products
|
||||
a span.visible-xs-inline
|
||||
display: none !important
|
||||
.oe_cart, #modal_optional_products
|
||||
a span.hidden-xs
|
||||
display: inline !important
|
||||
|
||||
.oe_cart table td:first-child
|
||||
min-width: 76px
|
||||
|
||||
@media (max-width: 992px)
|
||||
#modal_optional_products table:last-child
|
||||
td:last-child
|
||||
overflow: hidden
|
||||
td:nth-child(2)
|
||||
width: 50%
|
||||
td:nth-child(3)
|
||||
width: 20%
|
||||
td:last-child, td:nth-last-child(2)
|
||||
width: 15%
|
||||
@media (max-width: 500px)
|
||||
.oe_website_sale .oe_website_spinner
|
||||
margin: auto
|
||||
.oe_cart table, #modal_optional_products table
|
||||
display: inline-block
|
||||
thead
|
||||
display: none
|
||||
tbody, tr, td
|
||||
float: left
|
||||
width: 100% !important
|
||||
display: inline-block
|
||||
td:first-child
|
||||
display: none
|
||||
td:nth-child(2)
|
||||
border-top-style: double
|
||||
border-top-width: 6px
|
||||
td:last-child
|
||||
margin-bottom: 16px
|
||||
&:last-child tr:last-child td:last-child
|
||||
margin-bottom: 0
|
||||
td:last-child, td:nth-last-child(2)
|
||||
width: 50% !important
|
||||
height: 46px
|
||||
text-align: center
|
||||
#modal_optional_products table:last-child td:nth-child(3) > div
|
||||
float: none !important
|
||||
.oe_cart a, #modal_optional_products a
|
||||
span.hidden-xs
|
||||
display: none !important
|
||||
span.visible-xs-inline
|
||||
display: inline !important
|
||||
/* ---- Product list style ---- */
|
||||
|
||||
@media (min-width: 400px)
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
<!-- Product item used by /shop and /shop/cart -->
|
||||
|
||||
<template id="products_item" name="Product item">
|
||||
<form action="/shop/cart/update" method="post" style="display: inline-block;">
|
||||
<form action="/shop/cart/update" method="post">
|
||||
<div itemscope="itemscope" itemtype="http://schema.org/Product">
|
||||
<div class="ribbon-wrapper">
|
||||
<div class="ribbon btn btn-danger">Sale</div>
|
||||
@@ -616,7 +616,7 @@
|
||||
<strong t-esc="line.product_id.with_context(display_default_code=False).display_name"/>
|
||||
</a>
|
||||
</div>
|
||||
<div class="text-muted" t-field="line.name"/>
|
||||
<div class="text-muted" t-esc="'\n'.join(line.name.splitlines()[1:])"/>
|
||||
</td>
|
||||
<td class="text-center" name="price">
|
||||
<t t-if="(compute_currency(line.product_id.lst_price) - line.price_unit) > 1">
|
||||
@@ -653,7 +653,7 @@
|
||||
<t t-call="website_sale.total"/>
|
||||
<div class="clearfix"/>
|
||||
|
||||
<a t-if="not optional_products and website_sale_order and website_sale_order.website_order_line" class="btn btn-primary pull-right mb32" href="/shop/checkout">Process Checkout <span class="fa fa-long-arrow-right"/></a>
|
||||
<a t-if="not optional_products and website_sale_order and website_sale_order.website_order_line" class="btn btn-primary pull-right mb32" href="/shop/checkout"><span class="hidden-xs">Process Checkout</span><span class="visible-xs-inline">Checkout</span> <span class="fa fa-long-arrow-right"/></a>
|
||||
|
||||
<div class="oe_structure"/>
|
||||
</div>
|
||||
@@ -736,7 +736,7 @@
|
||||
|
||||
<template id="continue_shopping" inherit_id="website_sale.cart" customize_show="True" name="Continue Shopping Button">
|
||||
<xpath expr="//a[@href='/shop/checkout']" position="before">
|
||||
<a href="/shop" class="btn btn-default mb32"><span class="fa fa-long-arrow-left"/> Continue Shopping</a>
|
||||
<a href="/shop" class="btn btn-default mb32"><span class="fa fa-long-arrow-left"/> <span class="hidden-xs">Continue Shopping</span><span class="visible-xs-inline">Continue</span></a>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
"widget": "monetary",
|
||||
"from_currency": "website.currency_id",
|
||||
"display_currency": "user_id.partner_id.property_product_pricelist.currency_id"
|
||||
}'/><br/>
|
||||
}'/>
|
||||
<span class="oe_price" style="white-space: nowrap;"
|
||||
t-field="product.price"
|
||||
t-field-options='{
|
||||
@@ -134,8 +134,8 @@
|
||||
</table>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a class="btn btn-default a-submit js_goto_shop"><i class="fa fa-chevron-left"></i> Continue shopping</a>
|
||||
<a class="btn btn-primary pull-right a-submit"><i class="fa fa-shopping-cart fa-fw"></i> Proceed to checkout</a>
|
||||
<a class="btn btn-default a-submit js_goto_shop"><i class="fa fa-chevron-left"></i> <span class="hidden-xs">Continue Shopping</span><span class="visible-xs-inline">Continue</span></a>
|
||||
<a class="btn btn-primary pull-right a-submit"><i class="fa fa-shopping-cart fa-fw"></i> <span class="hidden-xs">Proceed to checkout</span><span class="visible-xs-inline">Checkout</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+7
-2
@@ -68,8 +68,13 @@ def visit_table(self, node):
|
||||
self._table_row_index = 0
|
||||
self.context.append(self.compact_p)
|
||||
self.compact_p = True
|
||||
classes = ' '.join({'table', self.settings.table_style}).strip()
|
||||
self.body.append(self.starttag(node, 'table', CLASS=classes))
|
||||
|
||||
classes = {self.settings.table_style}
|
||||
node_classes = node.get('classes', [])
|
||||
if 'no-table' in node_classes: node_classes.remove('no-table')
|
||||
else: classes.add('table')
|
||||
|
||||
self.body.append(self.starttag(node, 'table', CLASS=' '.join(classes).strip()))
|
||||
|
||||
def starttag_data(self, node, tagname, suffix='\n', empty=False, **attributes):
|
||||
attributes.update(
|
||||
|
||||
Vendored
+177
-168
@@ -6811,49 +6811,58 @@ td.field-body > ul {
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
@media (min-width: 992px) {
|
||||
.stripe .section > *,
|
||||
.stripe .section > .force-left {
|
||||
.stripe .section:not(.force-right) > *,
|
||||
.stripe .section:not(.force-right) > .force-left {
|
||||
width: 49%;
|
||||
float: left;
|
||||
clear: left;
|
||||
}
|
||||
.stripe .section > .force-right {
|
||||
.stripe .section:not(.force-right) > .force-right {
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
}
|
||||
.stripe .section > .force-right,
|
||||
.stripe .section > [class*=highlight] {
|
||||
.stripe .section:not(.force-right) > .force-right,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] {
|
||||
float: none;
|
||||
clear: none;
|
||||
margin-left: 50%;
|
||||
width: 50%;
|
||||
color: #eeeeee;
|
||||
}
|
||||
.stripe .section > .force-right a,
|
||||
.stripe .section > [class*=highlight] a {
|
||||
.stripe .section:not(.force-right) > .force-right legend,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] legend {
|
||||
color: inherit;
|
||||
}
|
||||
.stripe .section:not(.force-right) > .force-right input,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] input {
|
||||
color: inherit;
|
||||
background-color: #555555;
|
||||
}
|
||||
.stripe .section:not(.force-right) > .force-right a,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] a {
|
||||
color: #d9a8cc;
|
||||
}
|
||||
.stripe .section > .force-right code,
|
||||
.stripe .section > [class*=highlight] code,
|
||||
.stripe .section > .force-right .literal,
|
||||
.stripe .section > [class*=highlight] .literal {
|
||||
.stripe .section:not(.force-right) > .force-right code,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] code,
|
||||
.stripe .section:not(.force-right) > .force-right .literal,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .literal {
|
||||
color: #f9f2f4;
|
||||
background-color: #555555;
|
||||
}
|
||||
.stripe .section > .force-right:not(.highlight-json) .highlight,
|
||||
.stripe .section > [class*=highlight]:not(.highlight-json) .highlight {
|
||||
.stripe .section:not(.force-right) > .force-right:not(.highlight-json) .highlight,
|
||||
.stripe .section:not(.force-right) > [class*=highlight]:not(.highlight-json) .highlight {
|
||||
border-bottom-color: #777777;
|
||||
}
|
||||
.stripe .section > .force-right.admonition,
|
||||
.stripe .section > [class*=highlight].admonition {
|
||||
.stripe .section:not(.force-right) > .force-right.admonition,
|
||||
.stripe .section:not(.force-right) > [class*=highlight].admonition {
|
||||
margin-left: 51%;
|
||||
width: 49%;
|
||||
border-top-color: #777777;
|
||||
border-bottom-color: #777777;
|
||||
border-right-color: #777777;
|
||||
}
|
||||
.stripe .section > .force-right .highlight,
|
||||
.stripe .section > [class*=highlight] .highlight {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight {
|
||||
border-color: #555555;
|
||||
border-style: solid;
|
||||
border-width: 1px 0;
|
||||
@@ -6930,302 +6939,302 @@ td.field-body > ul {
|
||||
/* Name.Variable.Instance */
|
||||
/* Literal.Number.Integer.Long */
|
||||
}
|
||||
.stripe .section > .force-right .highlight .lineno,
|
||||
.stripe .section > [class*=highlight] .highlight .lineno {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .lineno,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .lineno {
|
||||
color: #586e75;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .c,
|
||||
.stripe .section > [class*=highlight] .highlight .c {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .c,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .c {
|
||||
color: #586e75;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .err,
|
||||
.stripe .section > [class*=highlight] .highlight .err {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .err,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .err {
|
||||
color: #cccccc;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .g,
|
||||
.stripe .section > [class*=highlight] .highlight .g {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .g,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .g {
|
||||
color: #cccccc;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .k,
|
||||
.stripe .section > [class*=highlight] .highlight .k {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .k,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .k {
|
||||
color: #859900;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .l,
|
||||
.stripe .section > [class*=highlight] .highlight .l {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .l,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .l {
|
||||
color: #cccccc;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .n,
|
||||
.stripe .section > [class*=highlight] .highlight .n {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .n,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .n {
|
||||
color: #cccccc;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .o,
|
||||
.stripe .section > [class*=highlight] .highlight .o {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .o,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .o {
|
||||
color: #859900;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .x,
|
||||
.stripe .section > [class*=highlight] .highlight .x {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .x,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .x {
|
||||
color: #cb4b16;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .p,
|
||||
.stripe .section > [class*=highlight] .highlight .p {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .p,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .p {
|
||||
color: #cccccc;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .cm,
|
||||
.stripe .section > [class*=highlight] .highlight .cm {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .cm,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .cm {
|
||||
color: #586e75;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .cp,
|
||||
.stripe .section > [class*=highlight] .highlight .cp {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .cp,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .cp {
|
||||
color: #859900;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .c1,
|
||||
.stripe .section > [class*=highlight] .highlight .c1 {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .c1,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .c1 {
|
||||
color: #586e75;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .cs,
|
||||
.stripe .section > [class*=highlight] .highlight .cs {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .cs,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .cs {
|
||||
color: #859900;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .gd,
|
||||
.stripe .section > [class*=highlight] .highlight .gd {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .gd,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .gd {
|
||||
color: #2aa198;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .ge,
|
||||
.stripe .section > [class*=highlight] .highlight .ge {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .ge,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .ge {
|
||||
color: #cccccc;
|
||||
font-style: italic;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .gr,
|
||||
.stripe .section > [class*=highlight] .highlight .gr {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .gr,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .gr {
|
||||
color: #dc322f;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .gh,
|
||||
.stripe .section > [class*=highlight] .highlight .gh {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .gh,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .gh {
|
||||
color: #cb4b16;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .gi,
|
||||
.stripe .section > [class*=highlight] .highlight .gi {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .gi,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .gi {
|
||||
color: #859900;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .go,
|
||||
.stripe .section > [class*=highlight] .highlight .go {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .go,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .go {
|
||||
color: #cccccc;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .gp,
|
||||
.stripe .section > [class*=highlight] .highlight .gp {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .gp,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .gp {
|
||||
color: #cccccc;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .gs,
|
||||
.stripe .section > [class*=highlight] .highlight .gs {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .gs,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .gs {
|
||||
color: #cccccc;
|
||||
font-weight: bold;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .gu,
|
||||
.stripe .section > [class*=highlight] .highlight .gu {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .gu,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .gu {
|
||||
color: #cb4b16;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .gt,
|
||||
.stripe .section > [class*=highlight] .highlight .gt {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .gt,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .gt {
|
||||
color: #cccccc;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .kc,
|
||||
.stripe .section > [class*=highlight] .highlight .kc {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .kc,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .kc {
|
||||
color: #cb4b16;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .kd,
|
||||
.stripe .section > [class*=highlight] .highlight .kd {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .kd,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .kd {
|
||||
color: #268bd2;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .kn,
|
||||
.stripe .section > [class*=highlight] .highlight .kn {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .kn,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .kn {
|
||||
color: #859900;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .kp,
|
||||
.stripe .section > [class*=highlight] .highlight .kp {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .kp,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .kp {
|
||||
color: #859900;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .kr,
|
||||
.stripe .section > [class*=highlight] .highlight .kr {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .kr,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .kr {
|
||||
color: #268bd2;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .kt,
|
||||
.stripe .section > [class*=highlight] .highlight .kt {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .kt,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .kt {
|
||||
color: #dc322f;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .ld,
|
||||
.stripe .section > [class*=highlight] .highlight .ld {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .ld,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .ld {
|
||||
color: #cccccc;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .m,
|
||||
.stripe .section > [class*=highlight] .highlight .m {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .m,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .m {
|
||||
color: #2aa198;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .s,
|
||||
.stripe .section > [class*=highlight] .highlight .s {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .s,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .s {
|
||||
color: #2aa198;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .na,
|
||||
.stripe .section > [class*=highlight] .highlight .na {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .na,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .na {
|
||||
color: #cccccc;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .nb,
|
||||
.stripe .section > [class*=highlight] .highlight .nb {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .nb,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .nb {
|
||||
color: #b58900;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .nc,
|
||||
.stripe .section > [class*=highlight] .highlight .nc {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .nc,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .nc {
|
||||
color: #268bd2;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .no,
|
||||
.stripe .section > [class*=highlight] .highlight .no {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .no,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .no {
|
||||
color: #cb4b16;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .nd,
|
||||
.stripe .section > [class*=highlight] .highlight .nd {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .nd,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .nd {
|
||||
color: #268bd2;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .ni,
|
||||
.stripe .section > [class*=highlight] .highlight .ni {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .ni,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .ni {
|
||||
color: #cb4b16;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .ne,
|
||||
.stripe .section > [class*=highlight] .highlight .ne {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .ne,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .ne {
|
||||
color: #cb4b16;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .nf,
|
||||
.stripe .section > [class*=highlight] .highlight .nf {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .nf,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .nf {
|
||||
color: #268bd2;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .nl,
|
||||
.stripe .section > [class*=highlight] .highlight .nl {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .nl,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .nl {
|
||||
color: #cccccc;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .nn,
|
||||
.stripe .section > [class*=highlight] .highlight .nn {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .nn,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .nn {
|
||||
color: #cccccc;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .nx,
|
||||
.stripe .section > [class*=highlight] .highlight .nx {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .nx,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .nx {
|
||||
color: #cccccc;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .py,
|
||||
.stripe .section > [class*=highlight] .highlight .py {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .py,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .py {
|
||||
color: #cccccc;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .nt,
|
||||
.stripe .section > [class*=highlight] .highlight .nt {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .nt,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .nt {
|
||||
color: #268bd2;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .nv,
|
||||
.stripe .section > [class*=highlight] .highlight .nv {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .nv,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .nv {
|
||||
color: #268bd2;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .ow,
|
||||
.stripe .section > [class*=highlight] .highlight .ow {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .ow,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .ow {
|
||||
color: #859900;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .w,
|
||||
.stripe .section > [class*=highlight] .highlight .w {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .w,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .w {
|
||||
color: #cccccc;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .mf,
|
||||
.stripe .section > [class*=highlight] .highlight .mf {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .mf,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .mf {
|
||||
color: #2aa198;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .mh,
|
||||
.stripe .section > [class*=highlight] .highlight .mh {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .mh,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .mh {
|
||||
color: #2aa198;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .mi,
|
||||
.stripe .section > [class*=highlight] .highlight .mi {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .mi,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .mi {
|
||||
color: #2aa198;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .mo,
|
||||
.stripe .section > [class*=highlight] .highlight .mo {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .mo,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .mo {
|
||||
color: #2aa198;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .sb,
|
||||
.stripe .section > [class*=highlight] .highlight .sb {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .sb,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .sb {
|
||||
color: #586e75;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .sc,
|
||||
.stripe .section > [class*=highlight] .highlight .sc {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .sc,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .sc {
|
||||
color: #2aa198;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .sd,
|
||||
.stripe .section > [class*=highlight] .highlight .sd {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .sd,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .sd {
|
||||
color: #cccccc;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .s2,
|
||||
.stripe .section > [class*=highlight] .highlight .s2 {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .s2,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .s2 {
|
||||
color: #2aa198;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .se,
|
||||
.stripe .section > [class*=highlight] .highlight .se {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .se,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .se {
|
||||
color: #cb4b16;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .sh,
|
||||
.stripe .section > [class*=highlight] .highlight .sh {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .sh,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .sh {
|
||||
color: #cccccc;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .si,
|
||||
.stripe .section > [class*=highlight] .highlight .si {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .si,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .si {
|
||||
color: #2aa198;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .sx,
|
||||
.stripe .section > [class*=highlight] .highlight .sx {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .sx,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .sx {
|
||||
color: #2aa198;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .sr,
|
||||
.stripe .section > [class*=highlight] .highlight .sr {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .sr,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .sr {
|
||||
color: #dc322f;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .s1,
|
||||
.stripe .section > [class*=highlight] .highlight .s1 {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .s1,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .s1 {
|
||||
color: #2aa198;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .ss,
|
||||
.stripe .section > [class*=highlight] .highlight .ss {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .ss,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .ss {
|
||||
color: #2aa198;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .bp,
|
||||
.stripe .section > [class*=highlight] .highlight .bp {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .bp,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .bp {
|
||||
color: #268bd2;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .vc,
|
||||
.stripe .section > [class*=highlight] .highlight .vc {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .vc,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .vc {
|
||||
color: #268bd2;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .vg,
|
||||
.stripe .section > [class*=highlight] .highlight .vg {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .vg,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .vg {
|
||||
color: #268bd2;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .vi,
|
||||
.stripe .section > [class*=highlight] .highlight .vi {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .vi,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .vi {
|
||||
color: #268bd2;
|
||||
}
|
||||
.stripe .section > .force-right .highlight .il,
|
||||
.stripe .section > [class*=highlight] .highlight .il {
|
||||
.stripe .section:not(.force-right) > .force-right .highlight .il,
|
||||
.stripe .section:not(.force-right) > [class*=highlight] .highlight .il {
|
||||
color: #2aa198;
|
||||
}
|
||||
.stripe .body > .section > .section {
|
||||
border-top: 1px solid #eeeeee;
|
||||
}
|
||||
.stripe .section > h1,
|
||||
.stripe .section > h2,
|
||||
.stripe .section > h3,
|
||||
.stripe .section > h4,
|
||||
.stripe .section > h5,
|
||||
.stripe .section > h6 {
|
||||
.stripe .section:not(.force-right) > h1,
|
||||
.stripe .section:not(.force-right) > h2,
|
||||
.stripe .section:not(.force-right) > h3,
|
||||
.stripe .section:not(.force-right) > h4,
|
||||
.stripe .section:not(.force-right) > h5,
|
||||
.stripe .section:not(.force-right) > h6 {
|
||||
max-width: 50%;
|
||||
}
|
||||
.stripe .section > h1,
|
||||
.stripe .section > h2,
|
||||
.stripe .section > h3,
|
||||
.stripe .section > h4,
|
||||
.stripe .section > h5,
|
||||
.stripe .section > h6,
|
||||
.stripe .section > .section {
|
||||
.stripe .section:not(.force-right) > h1,
|
||||
.stripe .section:not(.force-right) > h2,
|
||||
.stripe .section:not(.force-right) > h3,
|
||||
.stripe .section:not(.force-right) > h4,
|
||||
.stripe .section:not(.force-right) > h5,
|
||||
.stripe .section:not(.force-right) > h6,
|
||||
.stripe .section > .section:not(.force-right) {
|
||||
position: relative;
|
||||
width: auto;
|
||||
float: none;
|
||||
|
||||
+19
-9
@@ -610,24 +610,31 @@ td.field-body {
|
||||
// === columning only on medium+ ===
|
||||
@media (min-width: @screen-md-min) {
|
||||
// column 1
|
||||
.section > *,
|
||||
.section > .force-left {
|
||||
.section:not(.force-right) > *,
|
||||
.section:not(.force-right) > .force-left {
|
||||
width: 49%;
|
||||
float: left;
|
||||
clear: left;
|
||||
}
|
||||
// column 2
|
||||
.section > .force-right {
|
||||
.section:not(.force-right) > .force-right {
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
}
|
||||
.section > .force-right,
|
||||
.section > [class*=highlight] {
|
||||
.section:not(.force-right) > .force-right,
|
||||
.section:not(.force-right) > [class*=highlight] {
|
||||
float: none;
|
||||
clear: none;
|
||||
margin-left: 50%;
|
||||
width: 50%;
|
||||
color: @color-right;
|
||||
legend {
|
||||
color: inherit;
|
||||
}
|
||||
input {
|
||||
color: inherit;
|
||||
background-color: @gray;
|
||||
}
|
||||
a {
|
||||
color: lighten(@link-color, 30%);
|
||||
}
|
||||
@@ -728,13 +735,16 @@ td.field-body {
|
||||
.body > .section > .section {
|
||||
border-top: 1px solid @color-right;
|
||||
}
|
||||
.section > h1, .section > h2, .section > h3, .section > h4, .section > h5,
|
||||
.section > h6 {
|
||||
.section:not(.force-right) > h1, .section:not(.force-right) > h2,
|
||||
.section:not(.force-right) > h3, .section:not(.force-right) > h4,
|
||||
.section:not(.force-right) > h5, .section:not(.force-right) > h6 {
|
||||
max-width: 50%;
|
||||
|
||||
}
|
||||
.section > h1, .section > h2, .section > h3, .section > h4, .section > h5,
|
||||
.section > h6, .section > .section {
|
||||
.section:not(.force-right) > h1, .section:not(.force-right) > h2,
|
||||
.section:not(.force-right) > h3, .section:not(.force-right) > h4,
|
||||
.section:not(.force-right) > h5, .section:not(.force-right) > h6,
|
||||
.section > .section:not(.force-right) {
|
||||
position: relative;
|
||||
width: auto;
|
||||
float: none;
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
Belgium, 2015-02-13
|
||||
|
||||
Apertoso agrees to the terms of the Odoo Corporate Contributor License
|
||||
Agreement v1.0.
|
||||
|
||||
I declare that I am authorized and able to make this agreement and sign this
|
||||
declaration.
|
||||
|
||||
Signed,
|
||||
|
||||
Jos De Graeve Jos.DeGraeve@apertoso.be https://github.com/apertoso
|
||||
|
||||
List of contributors:
|
||||
|
||||
Jos De Graeve Jos.DeGraeve@apertoso.be https://github.com/JosDeGraeve
|
||||
Maarten De Wispelaere Maarten.DeWispelaere https://github.com/bitprocessor
|
||||
@@ -0,0 +1,11 @@
|
||||
Lisbon, 2015-02-16
|
||||
|
||||
I hereby agree to the terms of the Odoo Individual Contributor License
|
||||
Agreement v1.0.
|
||||
|
||||
I declare that I am authorized and able to make this agreement and sign this
|
||||
declaration.
|
||||
|
||||
Signed,
|
||||
|
||||
Daniel Reis dgreis@sapo.pt https://github.com/dreispt
|
||||
@@ -68,6 +68,10 @@ class format_address(object):
|
||||
doc = etree.fromstring(arch)
|
||||
for node in doc.xpath("//div[@class='address_format']"):
|
||||
tree = etree.fromstring(v % {'city': _('City'), 'zip': _('ZIP'), 'state': _('State')})
|
||||
for child in node.xpath("//field"):
|
||||
if child.attrib.get('modifiers'):
|
||||
for field in tree.xpath("//field[@name='%s']" % child.attrib.get('name')):
|
||||
field.attrib['modifiers'] = child.attrib.get('modifiers')
|
||||
node.getparent().replace(node, tree)
|
||||
arch = etree.tostring(doc)
|
||||
break
|
||||
|
||||
@@ -890,6 +890,19 @@ class Environment(object):
|
||||
if invalids:
|
||||
raise UserError('Invalid cache for fields\n' + pformat(invalids))
|
||||
|
||||
@property
|
||||
def recompute(self):
|
||||
return self.all.recompute
|
||||
|
||||
@contextmanager
|
||||
def norecompute(self):
|
||||
tmp = self.all.recompute
|
||||
self.all.recompute = False
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
self.all.recompute = tmp
|
||||
|
||||
|
||||
class Environments(object):
|
||||
""" A common object for all environments in a request. """
|
||||
@@ -897,6 +910,7 @@ class Environments(object):
|
||||
self.envs = WeakSet() # weak set of environments
|
||||
self.todo = {} # recomputations {field: [records]}
|
||||
self.mode = False # flag for draft/onchange
|
||||
self.recompute = True
|
||||
|
||||
def add(self, env):
|
||||
""" Add the environment `env`. """
|
||||
|
||||
+6
-5
@@ -3979,7 +3979,7 @@ class BaseModel(object):
|
||||
self.pool[model_name]._store_set_values(cr, user, todo, fields_to_recompute, context)
|
||||
|
||||
# recompute new-style fields
|
||||
if context.get('recompute', True):
|
||||
if recs.env.recompute and context.get('recompute', True):
|
||||
recs.recompute()
|
||||
|
||||
self.step_workflow(cr, user, ids, context=context)
|
||||
@@ -4226,7 +4226,7 @@ class BaseModel(object):
|
||||
# check Python constraints
|
||||
recs._validate_fields(vals)
|
||||
|
||||
if context.get('recompute', True):
|
||||
if recs.env.recompute and context.get('recompute', True):
|
||||
result += self._store_get_values(cr, user, [id_new],
|
||||
list(set(vals.keys() + self._inherits.values())),
|
||||
context)
|
||||
@@ -4239,7 +4239,7 @@ class BaseModel(object):
|
||||
# recompute new-style fields
|
||||
recs.recompute()
|
||||
|
||||
if self._log_create and context.get('recompute', True):
|
||||
if self._log_create and recs.env.recompute and context.get('recompute', True):
|
||||
message = self._description + \
|
||||
" '" + \
|
||||
self.name_get(cr, user, [id_new], context=context)[0][1] + \
|
||||
@@ -5635,12 +5635,13 @@ class BaseModel(object):
|
||||
field, recs = self.env.get_todo()
|
||||
# evaluate the fields to recompute, and save them to database
|
||||
names = [f.name for f in field.computed_fields if f.store]
|
||||
for rec, rec1 in zip(recs, recs.with_context(recompute=False)):
|
||||
for rec in recs:
|
||||
try:
|
||||
values = rec._convert_to_write({
|
||||
name: rec[name] for name in names
|
||||
})
|
||||
rec1._write(values)
|
||||
with rec.env.norecompute():
|
||||
rec._write(values)
|
||||
except MissingError:
|
||||
pass
|
||||
# mark the computed fields as done
|
||||
|
||||
+48
-47
@@ -736,57 +736,58 @@ class one2many(_column):
|
||||
result = []
|
||||
context = dict(context or {})
|
||||
context.update(self._context)
|
||||
context['recompute'] = False # recomputation is done by outer create/write
|
||||
if not values:
|
||||
return
|
||||
obj = obj.pool[self._obj]
|
||||
_table = obj._table
|
||||
for act in values:
|
||||
if act[0] == 0:
|
||||
act[2][self._fields_id] = id
|
||||
id_new = obj.create(cr, user, act[2], context=context)
|
||||
result += obj._store_get_values(cr, user, [id_new], act[2].keys(), context)
|
||||
elif act[0] == 1:
|
||||
obj.write(cr, user, [act[1]], act[2], context=context)
|
||||
elif act[0] == 2:
|
||||
obj.unlink(cr, user, [act[1]], context=context)
|
||||
elif act[0] == 3:
|
||||
inverse_field = obj._fields.get(self._fields_id)
|
||||
assert inverse_field, 'Trying to unlink the content of a o2m but the pointed model does not have a m2o'
|
||||
# if the model has on delete cascade, just delete the row
|
||||
if inverse_field.ondelete == "cascade":
|
||||
rec = obj.browse(cr, user, [], context=context)
|
||||
with rec.env.norecompute():
|
||||
_table = obj._table
|
||||
for act in values:
|
||||
if act[0] == 0:
|
||||
act[2][self._fields_id] = id
|
||||
id_new = obj.create(cr, user, act[2], context=context)
|
||||
result += obj._store_get_values(cr, user, [id_new], act[2].keys(), context)
|
||||
elif act[0] == 1:
|
||||
obj.write(cr, user, [act[1]], act[2], context=context)
|
||||
elif act[0] == 2:
|
||||
obj.unlink(cr, user, [act[1]], context=context)
|
||||
else:
|
||||
cr.execute('update '+_table+' set '+self._fields_id+'=null where id=%s', (act[1],))
|
||||
elif act[0] == 4:
|
||||
# table of the field (parent_model in case of inherit)
|
||||
field = obj.pool[self._obj]._fields[self._fields_id]
|
||||
field_model = field.base_field.model_name
|
||||
field_table = obj.pool[field_model]._table
|
||||
cr.execute("select 1 from {0} where id=%s and {1}=%s".format(field_table, self._fields_id), (act[1], id))
|
||||
if not cr.fetchone():
|
||||
# Must use write() to recompute parent_store structure if needed and check access rules
|
||||
obj.write(cr, user, [act[1]], {self._fields_id:id}, context=context or {})
|
||||
elif act[0] == 5:
|
||||
inverse_field = obj._fields.get(self._fields_id)
|
||||
assert inverse_field, 'Trying to unlink the content of a o2m but the pointed model does not have a m2o'
|
||||
# if the o2m has a static domain we must respect it when unlinking
|
||||
domain = self._domain(obj) if callable(self._domain) else self._domain
|
||||
extra_domain = domain or []
|
||||
ids_to_unlink = obj.search(cr, user, [(self._fields_id,'=',id)] + extra_domain, context=context)
|
||||
# If the model has cascade deletion, we delete the rows because it is the intended behavior,
|
||||
# otherwise we only nullify the reverse foreign key column.
|
||||
if inverse_field.ondelete == "cascade":
|
||||
obj.unlink(cr, user, ids_to_unlink, context=context)
|
||||
else:
|
||||
obj.write(cr, user, ids_to_unlink, {self._fields_id: False}, context=context)
|
||||
elif act[0] == 6:
|
||||
# Must use write() to recompute parent_store structure if needed
|
||||
obj.write(cr, user, act[2], {self._fields_id:id}, context=context or {})
|
||||
ids2 = act[2] or [0]
|
||||
cr.execute('select id from '+_table+' where '+self._fields_id+'=%s and id <> ALL (%s)', (id,ids2))
|
||||
ids3 = map(lambda x:x[0], cr.fetchall())
|
||||
obj.write(cr, user, ids3, {self._fields_id:False}, context=context or {})
|
||||
elif act[0] == 3:
|
||||
inverse_field = obj._fields.get(self._fields_id)
|
||||
assert inverse_field, 'Trying to unlink the content of a o2m but the pointed model does not have a m2o'
|
||||
# if the model has on delete cascade, just delete the row
|
||||
if inverse_field.ondelete == "cascade":
|
||||
obj.unlink(cr, user, [act[1]], context=context)
|
||||
else:
|
||||
cr.execute('update '+_table+' set '+self._fields_id+'=null where id=%s', (act[1],))
|
||||
elif act[0] == 4:
|
||||
# table of the field (parent_model in case of inherit)
|
||||
field = obj.pool[self._obj]._fields[self._fields_id]
|
||||
field_model = field.base_field.model_name
|
||||
field_table = obj.pool[field_model]._table
|
||||
cr.execute("select 1 from {0} where id=%s and {1}=%s".format(field_table, self._fields_id), (act[1], id))
|
||||
if not cr.fetchone():
|
||||
# Must use write() to recompute parent_store structure if needed and check access rules
|
||||
obj.write(cr, user, [act[1]], {self._fields_id:id}, context=context or {})
|
||||
elif act[0] == 5:
|
||||
inverse_field = obj._fields.get(self._fields_id)
|
||||
assert inverse_field, 'Trying to unlink the content of a o2m but the pointed model does not have a m2o'
|
||||
# if the o2m has a static domain we must respect it when unlinking
|
||||
domain = self._domain(obj) if callable(self._domain) else self._domain
|
||||
extra_domain = domain or []
|
||||
ids_to_unlink = obj.search(cr, user, [(self._fields_id,'=',id)] + extra_domain, context=context)
|
||||
# If the model has cascade deletion, we delete the rows because it is the intended behavior,
|
||||
# otherwise we only nullify the reverse foreign key column.
|
||||
if inverse_field.ondelete == "cascade":
|
||||
obj.unlink(cr, user, ids_to_unlink, context=context)
|
||||
else:
|
||||
obj.write(cr, user, ids_to_unlink, {self._fields_id: False}, context=context)
|
||||
elif act[0] == 6:
|
||||
# Must use write() to recompute parent_store structure if needed
|
||||
obj.write(cr, user, act[2], {self._fields_id:id}, context=context or {})
|
||||
ids2 = act[2] or [0]
|
||||
cr.execute('select id from '+_table+' where '+self._fields_id+'=%s and id <> ALL (%s)', (id,ids2))
|
||||
ids3 = map(lambda x:x[0], cr.fetchall())
|
||||
obj.write(cr, user, ids3, {self._fields_id:False}, context=context or {})
|
||||
return result
|
||||
|
||||
def search(self, cr, obj, args, name, value, offset=0, limit=None, uid=None, operator='like', context=None):
|
||||
|
||||
Reference in New Issue
Block a user