[MERGE] forward port of branch 8.0 up to 9654b54

This commit is contained in:
Christophe Simonis
2015-07-10 17:12:57 +02:00
44 changed files with 293 additions and 977 deletions
+2 -1
View File
@@ -624,7 +624,8 @@ class account_move_line(osv.osv):
res = super(account_move_line, self)._auto_init(cr, context=context)
cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = \'account_move_line_journal_id_period_id_index\'')
if not cr.fetchone():
cr.execute('CREATE INDEX account_move_line_journal_id_period_id_index ON account_move_line (journal_id, period_id)')
cr.execute('CREATE INDEX account_move_line_journal_id_period_id_index '
'ON account_move_line (journal_id, period_id, state, create_uid, id DESC)')
cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = %s', ('account_move_line_date_id_index',))
if not cr.fetchone():
cr.execute('CREATE INDEX account_move_line_date_id_index ON account_move_line (date DESC, id desc)')
@@ -75,7 +75,7 @@ class aged_trial_report(report_sxw.rml_parse, common_report_header):
AND (account_account.type IN %s)\
AND account_account.active\
AND ((l.reconcile_id IS NULL)\
OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s )))\
OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s AND not recon.opening_reconciliation)))\
AND (l.partner_id=res_partner.id)\
AND (l.date <= %s)\
AND ' + self.query + ' \
@@ -99,7 +99,7 @@ class aged_trial_report(report_sxw.rml_parse, common_report_header):
AND (account_account.type IN %s)\
AND (l.partner_id IN %s)\
AND ((l.reconcile_id IS NULL)\
OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s )))\
OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s AND not recon.opening_reconciliation)))\
AND ' + self.query + '\
AND account_account.active\
AND (l.date <= %s)\
@@ -119,7 +119,7 @@ class aged_trial_report(report_sxw.rml_parse, common_report_header):
AND (COALESCE(l.date_maturity, l.date) < %s)\
AND (l.partner_id IN %s)\
AND ((l.reconcile_id IS NULL)\
OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s )))\
OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s AND not recon.opening_reconciliation)))\
AND '+ self.query + '\
AND account_account.active\
AND (l.date <= %s)\
@@ -136,7 +136,7 @@ class aged_trial_report(report_sxw.rml_parse, common_report_header):
AND (COALESCE(l.date_maturity,l.date) > %s)\
AND (l.partner_id IN %s)\
AND ((l.reconcile_id IS NULL)\
OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s )))\
OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s AND not recon.opening_reconciliation)))\
AND '+ self.query + '\
AND account_account.active\
AND (l.date <= %s)\
@@ -168,7 +168,7 @@ class aged_trial_report(report_sxw.rml_parse, common_report_header):
AND (account_account.type IN %s)
AND (l.partner_id IN %s)
AND ((l.reconcile_id IS NULL)
OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s )))
OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s AND not recon.opening_reconciliation)))
AND ''' + self.query + '''
AND account_account.active
AND ''' + dates_query + '''
@@ -264,7 +264,7 @@ class aged_trial_report(report_sxw.rml_parse, common_report_header):
AND (l.partner_id IS NULL)\
AND (account_account.type IN %s)\
AND ((l.reconcile_id IS NULL) \
OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s )))\
OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s AND not recon.opening_reconciliation)))\
AND ' + self.query + '\
AND (l.date <= %s)\
AND account_account.active ',(tuple(move_state), tuple(self.ACCOUNT_TYPE), self.date_from, self.date_from,))
@@ -281,7 +281,7 @@ class aged_trial_report(report_sxw.rml_parse, common_report_header):
AND (account_account.type IN %s)\
AND (COALESCE(l.date_maturity, l.date) < %s)\
AND ((l.reconcile_id IS NULL)\
OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s )))\
OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s AND not recon.opening_reconciliation)))\
AND '+ self.query + '\
AND account_account.active ', (tuple(move_state), tuple(self.ACCOUNT_TYPE), self.date_from, self.date_from))
t = self.cr.fetchall()
@@ -296,7 +296,7 @@ class aged_trial_report(report_sxw.rml_parse, common_report_header):
AND (account_account.type IN %s)\
AND (COALESCE(l.date_maturity,l.date) > %s)\
AND ((l.reconcile_id IS NULL)\
OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s )))\
OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s AND not recon.opening_reconciliation)))\
AND '+ self.query + '\
AND account_account.active ', (tuple(move_state), tuple(self.ACCOUNT_TYPE), self.date_from, self.date_from))
t = self.cr.fetchall()
@@ -324,7 +324,7 @@ class aged_trial_report(report_sxw.rml_parse, common_report_header):
AND (account_account.type IN %s)\
AND (l.partner_id IS NULL)\
AND ((l.reconcile_id IS NULL)\
OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s )))\
OR (l.reconcile_id IN (SELECT recon.id FROM account_move_reconcile AS recon WHERE recon.create_date > %s AND not recon.opening_reconciliation)))\
AND '+ self.query + '\
AND account_account.active\
AND ' + dates_query + '\
@@ -694,6 +694,28 @@ class account_analytic_account(osv.osv):
}
return invoice
def _prepare_invoice_line(self, cr, uid, line, fiscal_position, context=None):
fpos_obj = self.pool.get('account.fiscal.position')
res = line.product_id
account_id = res.property_account_income.id
if not account_id:
account_id = res.categ_id.property_account_income_categ.id
account_id = fpos_obj.map_account(cr, uid, fiscal_position, account_id)
taxes = res.taxes_id or False
tax_id = fpos_obj.map_tax(cr, uid, fiscal_position, taxes)
values = {
'name': line.name,
'account_id': account_id,
'account_analytic_id': line.analytic_account_id.id,
'price_unit': line.price_unit or 0.0,
'quantity': line.quantity,
'uos_id': line.uom_id.id or False,
'product_id': line.product_id.id or False,
'invoice_line_tax_id': [(6, 0, tax_id)],
}
return values
def _prepare_invoice_lines(self, cr, uid, contract, fiscal_position_id, context=None):
fpos_obj = self.pool.get('account.fiscal.position')
fiscal_position = None
@@ -701,26 +723,8 @@ class account_analytic_account(osv.osv):
fiscal_position = fpos_obj.browse(cr, uid, fiscal_position_id, context=context)
invoice_lines = []
for line in contract.recurring_invoice_line_ids:
res = line.product_id
account_id = res.property_account_income.id
if not account_id:
account_id = res.categ_id.property_account_income_categ.id
account_id = fpos_obj.map_account(cr, uid, fiscal_position, account_id)
taxes = res.taxes_id or False
tax_id = fpos_obj.map_tax(cr, uid, fiscal_position, taxes)
invoice_lines.append((0, 0, {
'name': line.name,
'account_id': account_id,
'account_analytic_id': contract.id,
'price_unit': line.price_unit or 0.0,
'quantity': line.quantity,
'uos_id': line.uom_id.id or False,
'product_id': line.product_id.id or False,
'invoice_line_tax_id': [(6, 0, tax_id)],
}))
values = self._prepare_invoice_line(cr, uid, line, fiscal_position, context=context)
invoice_lines.append((0, 0, values))
return invoice_lines
def _prepare_invoice(self, cr, uid, contract, context=None):
+1 -1
View File
@@ -899,7 +899,7 @@ class account_voucher(osv.osv):
else:
currency_id = journal.company_id.currency_id.id
period_ids = self.pool['account.period'].find(cr, uid, context=dict(context, company_id=company_id))
period_ids = self.pool['account.period'].find(cr, uid, dt=date, context=dict(context, company_id=company_id))
vals['value'].update({
'currency_id': currency_id,
'payment_rate_currency_id': currency_id,
+15 -12
View File
@@ -46,6 +46,20 @@ class res_users(osv.Model):
validation.update(data)
return validation
def _generate_signup_values(self, cr, uid, provider, validation, params, context=None):
oauth_uid = validation['user_id']
email = validation.get('email', 'provider_%s_user_%s' % (provider, oauth_uid))
name = validation.get('name', email)
return {
'name': name,
'login': email,
'email': email,
'oauth_provider_id': provider,
'oauth_uid': oauth_uid,
'oauth_access_token': params['access_token'],
'active': True,
}
def _auth_oauth_signin(self, cr, uid, provider, validation, params, context=None):
""" retrieve and sign in the user corresponding to provider and validated access token
:param provider: oauth provider id (int)
@@ -70,18 +84,7 @@ class res_users(osv.Model):
return None
state = simplejson.loads(params['state'])
token = state.get('t')
oauth_uid = validation['user_id']
email = validation.get('email', 'provider_%s_user_%s' % (provider, oauth_uid))
name = validation.get('name', email)
values = {
'name': name,
'login': email,
'email': email,
'oauth_provider_id': provider,
'oauth_uid': oauth_uid,
'oauth_access_token': params['access_token'],
'active': True,
}
values = self._generate_signup_values(cr, uid, provider, validation, params, context=context)
try:
_, login, _ = self.signup(cr, uid, values, token, context=context)
return login
+1 -1
View File
@@ -96,7 +96,7 @@ class calendar_attendee(osv.Model):
'email': fields.char('Email', help="Email of Invited Person"),
'availability': fields.selection([('free', 'Free'), ('busy', 'Busy')], 'Free/Busy', readonly="True"),
'access_token': fields.char('Invitation Token'),
'event_id': fields.many2one('calendar.event', 'Meeting linked'),
'event_id': fields.many2one('calendar.event', 'Meeting linked', ondelete='cascade'),
}
_defaults = {
'state': 'needsAction',
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<openerp>
<data>
<data noupdate="1">
<record id="event_subscription" model="mail.template">
<field name="name">Event subscription</field>
+1 -1
View File
@@ -3,7 +3,7 @@
<data>
<record model="ir.ui.view" id="res_partner_form_ro">
<field name="name">res.partner.form.ro</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="inherit_id" ref="account.view_partner_property_form"/>
<field name="model">res.partner</field>
<field name="arch" type="xml">
<field name="property_account_position" position="after">
+2 -3
View File
@@ -17,7 +17,7 @@ from openerp.addons.payment_ogone.controllers.main import OgoneController
from openerp.addons.payment_ogone.data import ogone
from openerp.osv import osv, fields
from openerp.tools import float_round, DEFAULT_SERVER_DATE_FORMAT
from openerp.tools.float_utils import float_compare
from openerp.tools.float_utils import float_compare, float_repr
from openerp.tools.safe_eval import safe_eval
_logger = logging.getLogger(__name__)
@@ -148,12 +148,11 @@ class PaymentAcquirerOgone(osv.Model):
def ogone_form_generate_values(self, cr, uid, id, partner_values, tx_values, context=None):
base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url')
acquirer = self.browse(cr, uid, id, context=context)
ogone_tx_values = dict(tx_values)
temp_ogone_tx_values = {
'PSPID': acquirer.ogone_pspid,
'ORDERID': tx_values['reference'],
'AMOUNT': '%d' % int(float_round(tx_values['amount'], 2) * 100),
'AMOUNT': float_repr(float_round(tx_values['amount'], 2) * 100, 0),
'CURRENCY': tx_values['currency'] and tx_values['currency'].name or '',
'LANGUAGE': partner_values['lang'],
'CN': partner_values['name'],
@@ -31,7 +31,7 @@
<td><span t-field="line.product_id"/></td>
<td class="text-right">
<t t-if="o.state != 'cancel' and o.statement_ids">
<span t-esc="'%.f' % line.qty"/>
<span t-field="line.qty"/>
</t>
</td>
<td class="text-right">
+1 -1
View File
@@ -81,7 +81,7 @@ class procurement_rule(osv.osv):
return []
_columns = {
'name': fields.char('Name', required=True,
'name': fields.char('Name', required=True, translate=True,
help="This field will fill the packing origin and the name of its moves"),
'active': fields.boolean('Active', help="If unchecked, it will allow you to hide the rule without removing it."),
'group_propagation_option': fields.selection([('none', 'Leave Empty'), ('propagate', 'Propagate'), ('fixed', 'Fixed')], string="Propagation of Procurement Group"),
+1 -1
View File
@@ -228,7 +228,7 @@ class stock_warehouse(osv.osv):
_columns = {
'buy_to_resupply': fields.boolean('Purchase to resupply this warehouse',
help="When products are bought, they can be delivered to this warehouse"),
'buy_pull_id': fields.many2one('procurement.rule', 'BUY rule'),
'buy_pull_id': fields.many2one('procurement.rule', 'Buy rule'),
}
_defaults = {
'buy_to_resupply': True,
+1 -1
View File
@@ -18,7 +18,7 @@
<field name="inherit_id" ref="stock.view_picking_internal_search"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='product_id']" position="before">
<filter name="reception_to_invoice" string="Incoming Shipments to Invoice" domain="[('reception_to_invoice', '=', True)]"/>
<filter name="reception_to_invoice" string="Incoming Shipments to Invoice" domain="[('reception_to_invoice', '=', True), ('invoice_state', '!=', 'invoiced')]"/>
</xpath>
</field>
</record>
+23
View File
@@ -573,8 +573,31 @@ class sale_order(osv.osv):
return True
def action_button_confirm(self, cr, uid, ids, context=None):
if not context:
context = {}
assert len(ids) == 1, 'This option should only be used for a single id at a time.'
self.signal_workflow(cr, uid, ids, 'order_confirm')
if context.get('send_email'):
order_id = ids[0]
email_act = self.action_quotation_send(cr, uid, [order_id], context=context)
if email_act and email_act.get('context'):
composer_obj = self.pool['mail.compose.message']
composer_values = {}
email_ctx = email_act['context']
template_values = [
email_ctx.get('default_template_id'),
email_ctx.get('default_composition_mode'),
email_ctx.get('default_model'),
email_ctx.get('default_res_id'),
]
composer_values.update(composer_obj.onchange_template_id(cr, uid, None, *template_values, context=context).get('value', {}))
if not composer_values.get('email_from'):
composer_values['email_from'] = self.browse(cr, uid, order_id, context=context).company_id.email
for key in ['attachment_ids', 'partner_ids']:
if composer_values.get(key):
composer_values[key] = [(6, 0, composer_values[key])]
composer_id = composer_obj.create(cr, uid, composer_values, context=email_ctx)
composer_obj.send_mail(cr, uid, [composer_id], context=email_ctx)
return True
def action_wait(self, cr, uid, ids, context=None):
+1 -1
View File
@@ -435,7 +435,7 @@
<search string="Search Sales Order">
<filter icon="terp-dolar_ok!" string="To Invoice" domain="[('invoiced','&lt;&gt;', 1),('state','=','done')]" help="Sales Order Lines ready to be invoiced"/>
<separator/>
<filter string="Confirmed" domain="[('state', 'in', ['waiting_date','progress','manual', 'shipping_except', 'invoice_except', 'done'])]" name="confirmed"/>
<filter string="Confirmed" domain="[('state', 'in', ['confirmed', 'done'])]" name="confirmed"/>
<separator/>
<filter string="My Sales Order Lines" icon="terp-personnal" domain="[('salesman_id','=',uid)]" help="Sales Order Lines related to a Sales Order of mine"/>
<field name="order_id"/>
-5
View File
@@ -360,8 +360,3 @@ msgstr ""
msgid "days"
msgstr ""
#. module: sale_stock
#: view:sale.order:sale_stock.view_order_form_inherit
msgid "{\"shipping_except\":\"red\",\"invoice_except\":\"red\",\"waiting_date\":\"blue\"}"
msgstr ""
+11 -3
View File
@@ -74,9 +74,9 @@ class product_product(osv.osv):
location_ids = []
if context.get('location', False):
if type(context['location']) == type(1):
if isinstance(context['location'], (int, long)):
location_ids = [context['location']]
elif type(context['location']) in (type(''), type(u'')):
elif isinstance(context['location'], basestring):
domain = [('complete_name','ilike',context['location'])]
if context.get('force_company', False):
domain += [('company_id', '=', context['force_company'])]
@@ -85,7 +85,15 @@ class product_product(osv.osv):
location_ids = context['location']
else:
if context.get('warehouse', False):
wids = [context['warehouse']]
if isinstance(context['warehouse'], (int, long)):
wids = [context['warehouse']]
elif isinstance(context['warehouse'], basestring):
domain = [('name', 'ilike', context['warehouse'])]
if context.get('force_company', False):
domain += [('company_id', '=', context['force_company'])]
wids = warehouse_obj.search(cr, uid, domain, context=context)
else:
wids = context['warehouse']
else:
wids = warehouse_obj.search(cr, uid, [], context=context)
+1 -1
View File
@@ -213,7 +213,7 @@ class stock_location_route(osv.osv):
_order = 'sequence'
_columns = {
'name': fields.char('Route Name', required=True),
'name': fields.char('Route Name', required=True, translate=True),
'sequence': fields.integer('Sequence'),
'pull_ids': fields.one2many('procurement.rule', 'route_id', 'Procurement Rules', copy=True),
'active': fields.boolean('Active', help="If the active field is set to False, it will allow you to hide the route without removing it."),
+1 -1
View File
@@ -653,7 +653,7 @@
<header>
<button name="action_confirm" states="draft" string="Mark as Todo" type="object" class="oe_highlight" groups="base.group_user"/>
<button name="action_assign" states="confirmed" string="Check Availability" type="object" class="oe_highlight" groups="base.group_user"/>
<button name="rereserve_pick" states="partially_available" string="Recheck Availability" type="object" class="oe_highlight" groups="base.group_user"/>
<button name="rereserve_pick" states="waiting,partially_available" string="Recheck Availability" type="object" class="oe_highlight" groups="base.group_user"/>
<button name="force_assign" states="confirmed,waiting,partially_available" string="Force Availability" type="object" groups="base.group_user"/>
<button name="do_enter_transfer_details" states="assigned,partially_available" string="Transfer" groups="stock.group_stock_user" type="object" class="oe_highlight"/>
<button name="do_print_picking" string="Print Picking List" groups="stock.group_stock_user" type="object" attrs="{'invisible': ['|', ('picking_type_code', '=', 'outgoing'), ('state', '!=', 'assigned')]}"/>
@@ -150,8 +150,11 @@ class stock_history(osv.osv):
LEFT JOIN
product_template ON product_template.id = product_product.product_tmpl_id
WHERE quant.qty>0 AND stock_move.state = 'done' AND dest_location.usage in ('internal', 'transit') AND stock_quant_move_rel.quant_id = quant.id
AND stock_quant_move_rel.move_id = stock_move.id AND ((source_location.company_id is null and dest_location.company_id is not null) or
(source_location.company_id is not null and dest_location.company_id is null) or source_location.company_id != dest_location.company_id)
AND stock_quant_move_rel.move_id = stock_move.id AND (
(source_location.company_id is null and dest_location.company_id is not null) or
(source_location.company_id is not null and dest_location.company_id is null) or
source_location.company_id != dest_location.company_id or
source_location.usage not in ('internal', 'transit'))
) UNION
(SELECT
'-' || stock_move.id::text || '-' || quant.id::text AS id,
@@ -176,8 +179,11 @@ class stock_history(osv.osv):
LEFT JOIN
product_template ON product_template.id = product_product.product_tmpl_id
WHERE quant.qty>0 AND stock_move.state = 'done' AND source_location.usage in ('internal', 'transit') AND stock_quant_move_rel.quant_id = quant.id
AND stock_quant_move_rel.move_id = stock_move.id AND ((dest_location.company_id is null and source_location.company_id is not null) or
(dest_location.company_id is not null and source_location.company_id is null) or dest_location.company_id != source_location.company_id)
AND stock_quant_move_rel.move_id = stock_move.id AND (
(dest_location.company_id is null and source_location.company_id is not null) or
(dest_location.company_id is not null and source_location.company_id is null) or
dest_location.company_id != source_location.company_id or
dest_location.usage not in ('internal', 'transit'))
))
AS foo
GROUP BY move_id, location_id, company_id, product_id, product_categ_id, date, price_unit_on_quant, source
+12 -11
View File
@@ -105,11 +105,11 @@ class WebsiteSurvey(http.Controller):
user_input = user_input_obj.browse(cr, uid, [user_input_id], context=context)[0]
else:
try:
user_input_id = user_input_obj.search(cr, uid, [('token', '=', token)], context=context)[0]
user_input_id = user_input_obj.search(cr, SUPERUSER_ID, [('token', '=', token)], context=context)[0]
except IndexError: # Invalid token
return request.website.render("website.403")
else:
user_input = user_input_obj.browse(cr, uid, [user_input_id], context=context)[0]
user_input = user_input_obj.browse(cr, SUPERUSER_ID, [user_input_id], context=context)[0]
# Do not open expired survey
errpage = self._check_deadline(cr, uid, user_input, context=context)
@@ -140,11 +140,11 @@ class WebsiteSurvey(http.Controller):
# Load the user_input
try:
user_input_id = user_input_obj.search(cr, uid, [('token', '=', token)])[0]
user_input_id = user_input_obj.search(cr, SUPERUSER_ID, [('token', '=', token)])[0]
except IndexError: # Invalid token
return request.website.render("website.403")
else:
user_input = user_input_obj.browse(cr, uid, [user_input_id], context=context)[0]
user_input = user_input_obj.browse(cr, SUPERUSER_ID, [user_input_id], context=context)[0]
# Do not display expired survey (even if some pages have already been
# displayed -- There's a time for everything!)
@@ -189,9 +189,9 @@ class WebsiteSurvey(http.Controller):
# Fetch previous answers
if page:
ids = user_input_line_obj.search(cr, uid, [('user_input_id.token', '=', token), ('page_id', '=', page.id)], context=context)
ids = user_input_line_obj.search(cr, SUPERUSER_ID, [('user_input_id.token', '=', token), ('page_id', '=', page.id)], context=context)
else:
ids = user_input_line_obj.search(cr, uid, [('user_input_id.token', '=', token)], context=context)
ids = user_input_line_obj.search(cr, SUPERUSER_ID, [('user_input_id.token', '=', token)], context=context)
previous_answers = user_input_line_obj.browse(cr, uid, ids, context=context)
# Return non empty answers in a JSON compatible format
@@ -231,7 +231,7 @@ class WebsiteSurvey(http.Controller):
ret = {}
# Fetch answers
ids = user_input_line_obj.search(cr, uid, [('user_input_id.token', '=', token)], context=context)
ids = user_input_line_obj.search(cr, SUPERUSER_ID, [('user_input_id.token', '=', token)], context=context)
previous_answers = user_input_line_obj.browse(cr, uid, ids, context=context)
# Compute score for each question
@@ -268,14 +268,15 @@ class WebsiteSurvey(http.Controller):
user_input_line_obj = request.registry['survey.user_input_line']
try:
user_input_id = user_input_obj.search(cr, uid, [('token', '=', post['token'])], context=context)[0]
user_input_id = user_input_obj.search(cr, SUPERUSER_ID, [('token', '=', post['token'])], context=context)[0]
except KeyError: # Invalid token
return request.website.render("website.403")
user_input = user_input_obj.browse(cr, SUPERUSER_ID, user_input_id, context=context)
user_id = uid if user_input.type != 'link' else SUPERUSER_ID
for question in questions:
answer_tag = "%s_%s_%s" % (survey.id, page_id, question.id)
user_input_line_obj.save_lines(cr, uid, user_input_id, question, post, answer_tag, context=context)
user_input_line_obj.save_lines(cr, user_id, user_input_id, question, post, answer_tag, context=context)
user_input = user_input_obj.browse(cr, uid, user_input_id, context=context)
go_back = post['button_submit'] == 'previous'
next_page, _, last = survey_obj.next_page(cr, uid, user_input, page_id, go_back=go_back, context=context)
vals = {'last_displayed_page_id': page_id}
@@ -283,7 +284,7 @@ class WebsiteSurvey(http.Controller):
vals.update({'state': 'done'})
else:
vals.update({'state': 'skip'})
user_input_obj.write(cr, uid, user_input_id, vals, context=context)
user_input_obj.write(cr, user_id, user_input_id, vals, context=context)
ret['redirect'] = '/survey/fill/%s/%s' % (survey.id, post['token'])
if go_back:
ret['redirect'] += '/prev'
+4
View File
@@ -4909,6 +4909,10 @@ instance.web.form.FieldMany2Many = instance.web.form.AbstractField.extend(instan
instance.web.form.Many2ManyDataSet = instance.web.DataSetStatic.extend({
get_context: function() {
this.context = this.m2m.build_context();
var self = this;
_.each(arguments, function(context) {
self.context.add(context);
});
return this.context;
}
});
+1 -1
View File
@@ -132,7 +132,7 @@ class Website(openerp.addons.web.controllers.main.Home):
pages = 0
first_page = None
locs = request.website.enumerate_pages()
locs = request.website.sudo(user=request.website.user_id.id).enumerate_pages()
while True:
start = pages * LOC_PER_SITEMAP
values = {
+1 -5
View File
@@ -184,12 +184,8 @@ msgstr ""
#. module: website_forum
#: view:website:website_forum.header
msgid "Ask a Question"
msgstr ""
#. module: website_forum
#: field:forum.forum,karma_ask:0
msgid "Ask a question"
msgid "Ask a Question"
msgstr ""
#. module: website_forum
+1 -23
View File
@@ -810,33 +810,11 @@ class website_sale(http.Controller):
if (not order.amount_total and not tx):
# Orders are confirmed by payment transactions, but there is none for free orders,
# (e.g. free events), so confirm immediately
order.action_button_confirm()
# send by email
email_act = sale_order_obj.action_quotation_send(cr, SUPERUSER_ID, [order.id], context=request.context)
order.with_context(dict(context, send_email=True)).action_button_confirm()
elif tx and tx.state == 'cancel':
# cancel the quotation
sale_order_obj.action_cancel(cr, SUPERUSER_ID, [order.id], context=request.context)
# send the email
if email_act and email_act.get('context'):
composer_obj = request.registry['mail.compose.message']
composer_values = {}
email_ctx = email_act['context']
template_values = [
email_ctx.get('default_template_id'),
email_ctx.get('default_composition_mode'),
email_ctx.get('default_model'),
email_ctx.get('default_res_id'),
]
composer_values.update(composer_obj.onchange_template_id(cr, SUPERUSER_ID, None, *template_values, context=context).get('value', {}))
if not composer_values.get('email_from') and uid == request.website.user_id.id:
composer_values['email_from'] = request.website.user_id.company_id.email
for key in ['attachment_ids', 'partner_ids']:
if composer_values.get(key):
composer_values[key] = [(6, 0, composer_values[key])]
composer_id = composer_obj.create(cr, SUPERUSER_ID, composer_values, context=email_ctx)
composer_obj.send_mail(cr, SUPERUSER_ID, [composer_id], context=email_ctx)
# clean context and session, then redirect to the confirmation page
request.website.sale_reset(context=context)
+1 -1
View File
@@ -23,6 +23,6 @@ class PaymentTransaction(orm.Model):
if hasattr(self, tx_find_method_name):
tx = getattr(self, tx_find_method_name)(cr, uid, data, context=context)
if tx and tx.state == 'done' and tx.acquirer_id.auto_confirm == 'at_pay_confirm' and tx.sale_order_id and tx.sale_order_id.state in ['draft', 'sent']:
self.pool['sale.order'].action_button_confirm(cr, SUPERUSER_ID, [tx.sale_order_id.id], context=context)
self.pool['sale.order'].action_button_confirm(cr, SUPERUSER_ID, [tx.sale_order_id.id], context=dict(context, send_email=True))
return res
@@ -44,7 +44,6 @@ $('.oe_website_sale').each(function () {
$(oe_website_sale).find(".oe_cart input.js_quantity").on("change", function () {
var $input = $(this);
if ($input.data('update_change')) {
console.log($input.val()+ "+++");
return;
}
var value = parseInt($input.val(), 10);
@@ -81,7 +80,6 @@ $('.oe_website_sale').each(function () {
.then(function (data) {
$input.data('update_change', false);
if (value !== parseInt($input.val(), 10)) {
console.log($input.val()+ "***");
$input.trigger('change');
return;
}
+2 -2
View File
@@ -485,9 +485,9 @@
<xpath expr="//div[@id='product_full_description']" position="after">
<div class="container mt32" t-if="product.alternative_product_ids">
<h3>Suggested alternatives:</h3>
<div class='row mt16' style="margin-left: 15px !important;">
<div class='row mt16' style="">
<t t-foreach="product.alternative_product_ids" t-as="product">
<div class='col-md-2 thumbnail' style='width: 170px; margin-right: 16px;'>
<div class='col-md-2 thumbnail' style='width: 170px; height:130px; float:left; display:inline; margin-right: 10px;'>
<div class='mt16 text-center'>
<span t-field="product.image_small" t-field-options='{"widget": "image", "class": "img-rounded shadow" }'/>
<h5>
+25 -2
View File
@@ -1,13 +1,15 @@
# -*- coding: utf-8 -*-
from . import switcher
from . import pygments_override
import collections
from . import switcher
from . import translator
import sphinx.environment
import sphinx.builders.html
from docutils import nodes
def setup(app):
app.set_translator('html', translator.BootstrapTranslator)
switcher.setup(app)
app.add_config_value('odoo_cover_default', None, 'env')
app.add_config_value('odoo_cover_external', {}, 'env')
@@ -47,6 +49,27 @@ def navbarify(node, navbar=None):
link.attributes['data-toggle'] = 'dropdown'
# list_item.bullet_list
list_item.children[1]['classes'].append('dropdown-menu')
elif navbar is None:
for n in node.traverse(nodes.reference):
# list_item
# compact_paragraph
# reference <- starting point
# bullet_list
# list_item+
# if the current list item (GP of current node) has bullet list
# children, unref it
list_item = n.parent.parent
# only has a reference -> ignore
if len(list_item.children) < 2:
continue
# no subrefs -> ignore
if not list_item.children[1].children:
continue
# otherwise replace reference node by its own children
para = n.parent
para.remove(n)
para.extend(n.children)
def resolve_content_toctree(
environment, docname, builder, toctree, prune=True, maxdepth=0,
+14 -7
View File
@@ -9,10 +9,11 @@
{% set classes = [] %}
{% if pagename == master_doc %}
{% set classes = classes + ['index'] %}
{% set classes = classes + ['index'] %}
{% endif %}
{% if 'code-column' in meta %}
{% set classes = classes + ['has_code_col'] %}
{% set classes = classes + ['has_code_col'] %}
{% endif %}
{%- block doctype -%}
@@ -46,7 +47,7 @@
{%- block header -%}
<header class="{{ ' '.join(classes) }}">
<figure class="card top">
<span class="card-img" style="background-image: url('{{ pathto('_static/' + meta['banner'], True) }}');"></span>
<span class="card-img" {% if meta['banner'] %}style="background-image: url('{{ pathto('_static/' + meta['banner'], True) }}');"{% endif %}></span>
</figure>
</header>
<nav id="main_navbar" class="navbar {{ ' '.join(classes) }}">
@@ -82,17 +83,22 @@
</li>
</ul>
{% endif %}
{{ toctree(titles_only=True, maxdepth=2, includehidden=True,
collapse=False, navbar='main') }}
{{ toctree(titles_only=True, maxdepth=2, includehidden=True, collapse=False, navbar='main') }}
</nav>
</div>
</nav>
{%- endblock -%}
{%- block content -%}
<main class="container {{ ' '.join(classes) }}">
{% if 'code-column' in meta %}
{% set container = 'container-fluid' %}
{% else %}
{% set container = 'container' %}
{% endif %}
<main class="{{ container }} {{ ' '.join(classes) }}">
{% if pagename != master_doc %}
<div class="row">
{% if 'has-toc' not in meta %}
<aside>
<div class="navbar-aside text-center">
<div class="logo_box">
@@ -107,7 +113,8 @@
{% endif %}
</div>
</aside>
<article class="doc-body">
{% endif %}
<article class="doc-body {% if 'has-toc' in meta %}doc-toc{% endif %}">
{% endif %}
{% block body %} {% endblock %}
{% if pagename != master_doc %}</article>
+3 -5
View File
@@ -34,7 +34,6 @@ body, header {
// @w-size-large : 1170px;
// @w-size-xlarge : 1440px;
#main_navbar{
.container-fluid {
// @media screen and (min-width: @w-size-medium){
@@ -62,7 +61,6 @@ header{
margin-bottom: 0;
overflow: hidden;
position: relative;
margin-bottom: 0px;
padding-top: 50%;
padding-bottom: 15%;
@@ -120,6 +118,9 @@ main{
padding-left: 30px;
@media (min-width: @w-size-medium) {
width: 75%;
&.doc-toc {
width: 100%;
}
}
> *{
max-width: 100%;
@@ -129,9 +130,6 @@ main{
}
main.has_code_col{
width: 1440px;
@media (max-width:@w-size-xlarge) {
width: 100%;
}
+4 -810
View File
@@ -1,7 +1,5 @@
/*! normalize.css v3.0.2 | MIT License | git.io/normalize */
@import url(https://fonts.googleapis.com/css?family=Lato:300,400,900,300italic,400italic);
/*! normalize.css v3.0.2 | MIT License | git.io/normalize */
html {
font-family: sans-serif;
-ms-text-size-adjust: 100%;
@@ -256,809 +254,6 @@ th {
border: 1px solid #ddd !important;
}
}
@font-face {
font-family: 'Glyphicons Halflings';
src: url('../fonts/glyphicons-halflings-regular.eot');
src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
}
.glyphicon {
position: relative;
top: 1px;
display: inline-block;
font-family: 'Glyphicons Halflings';
font-style: normal;
font-weight: normal;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.glyphicon-asterisk:before {
content: "\2a";
}
.glyphicon-plus:before {
content: "\2b";
}
.glyphicon-euro:before,
.glyphicon-eur:before {
content: "\20ac";
}
.glyphicon-minus:before {
content: "\2212";
}
.glyphicon-cloud:before {
content: "\2601";
}
.glyphicon-envelope:before {
content: "\2709";
}
.glyphicon-pencil:before {
content: "\270f";
}
.glyphicon-glass:before {
content: "\e001";
}
.glyphicon-music:before {
content: "\e002";
}
.glyphicon-search:before {
content: "\e003";
}
.glyphicon-heart:before {
content: "\e005";
}
.glyphicon-star:before {
content: "\e006";
}
.glyphicon-star-empty:before {
content: "\e007";
}
.glyphicon-user:before {
content: "\e008";
}
.glyphicon-film:before {
content: "\e009";
}
.glyphicon-th-large:before {
content: "\e010";
}
.glyphicon-th:before {
content: "\e011";
}
.glyphicon-th-list:before {
content: "\e012";
}
.glyphicon-ok:before {
content: "\e013";
}
.glyphicon-remove:before {
content: "\e014";
}
.glyphicon-zoom-in:before {
content: "\e015";
}
.glyphicon-zoom-out:before {
content: "\e016";
}
.glyphicon-off:before {
content: "\e017";
}
.glyphicon-signal:before {
content: "\e018";
}
.glyphicon-cog:before {
content: "\e019";
}
.glyphicon-trash:before {
content: "\e020";
}
.glyphicon-home:before {
content: "\e021";
}
.glyphicon-file:before {
content: "\e022";
}
.glyphicon-time:before {
content: "\e023";
}
.glyphicon-road:before {
content: "\e024";
}
.glyphicon-download-alt:before {
content: "\e025";
}
.glyphicon-download:before {
content: "\e026";
}
.glyphicon-upload:before {
content: "\e027";
}
.glyphicon-inbox:before {
content: "\e028";
}
.glyphicon-play-circle:before {
content: "\e029";
}
.glyphicon-repeat:before {
content: "\e030";
}
.glyphicon-refresh:before {
content: "\e031";
}
.glyphicon-list-alt:before {
content: "\e032";
}
.glyphicon-lock:before {
content: "\e033";
}
.glyphicon-flag:before {
content: "\e034";
}
.glyphicon-headphones:before {
content: "\e035";
}
.glyphicon-volume-off:before {
content: "\e036";
}
.glyphicon-volume-down:before {
content: "\e037";
}
.glyphicon-volume-up:before {
content: "\e038";
}
.glyphicon-qrcode:before {
content: "\e039";
}
.glyphicon-barcode:before {
content: "\e040";
}
.glyphicon-tag:before {
content: "\e041";
}
.glyphicon-tags:before {
content: "\e042";
}
.glyphicon-book:before {
content: "\e043";
}
.glyphicon-bookmark:before {
content: "\e044";
}
.glyphicon-print:before {
content: "\e045";
}
.glyphicon-camera:before {
content: "\e046";
}
.glyphicon-font:before {
content: "\e047";
}
.glyphicon-bold:before {
content: "\e048";
}
.glyphicon-italic:before {
content: "\e049";
}
.glyphicon-text-height:before {
content: "\e050";
}
.glyphicon-text-width:before {
content: "\e051";
}
.glyphicon-align-left:before {
content: "\e052";
}
.glyphicon-align-center:before {
content: "\e053";
}
.glyphicon-align-right:before {
content: "\e054";
}
.glyphicon-align-justify:before {
content: "\e055";
}
.glyphicon-list:before {
content: "\e056";
}
.glyphicon-indent-left:before {
content: "\e057";
}
.glyphicon-indent-right:before {
content: "\e058";
}
.glyphicon-facetime-video:before {
content: "\e059";
}
.glyphicon-picture:before {
content: "\e060";
}
.glyphicon-map-marker:before {
content: "\e062";
}
.glyphicon-adjust:before {
content: "\e063";
}
.glyphicon-tint:before {
content: "\e064";
}
.glyphicon-edit:before {
content: "\e065";
}
.glyphicon-share:before {
content: "\e066";
}
.glyphicon-check:before {
content: "\e067";
}
.glyphicon-move:before {
content: "\e068";
}
.glyphicon-step-backward:before {
content: "\e069";
}
.glyphicon-fast-backward:before {
content: "\e070";
}
.glyphicon-backward:before {
content: "\e071";
}
.glyphicon-play:before {
content: "\e072";
}
.glyphicon-pause:before {
content: "\e073";
}
.glyphicon-stop:before {
content: "\e074";
}
.glyphicon-forward:before {
content: "\e075";
}
.glyphicon-fast-forward:before {
content: "\e076";
}
.glyphicon-step-forward:before {
content: "\e077";
}
.glyphicon-eject:before {
content: "\e078";
}
.glyphicon-chevron-left:before {
content: "\e079";
}
.glyphicon-chevron-right:before {
content: "\e080";
}
.glyphicon-plus-sign:before {
content: "\e081";
}
.glyphicon-minus-sign:before {
content: "\e082";
}
.glyphicon-remove-sign:before {
content: "\e083";
}
.glyphicon-ok-sign:before {
content: "\e084";
}
.glyphicon-question-sign:before {
content: "\e085";
}
.glyphicon-info-sign:before {
content: "\e086";
}
.glyphicon-screenshot:before {
content: "\e087";
}
.glyphicon-remove-circle:before {
content: "\e088";
}
.glyphicon-ok-circle:before {
content: "\e089";
}
.glyphicon-ban-circle:before {
content: "\e090";
}
.glyphicon-arrow-left:before {
content: "\e091";
}
.glyphicon-arrow-right:before {
content: "\e092";
}
.glyphicon-arrow-up:before {
content: "\e093";
}
.glyphicon-arrow-down:before {
content: "\e094";
}
.glyphicon-share-alt:before {
content: "\e095";
}
.glyphicon-resize-full:before {
content: "\e096";
}
.glyphicon-resize-small:before {
content: "\e097";
}
.glyphicon-exclamation-sign:before {
content: "\e101";
}
.glyphicon-gift:before {
content: "\e102";
}
.glyphicon-leaf:before {
content: "\e103";
}
.glyphicon-fire:before {
content: "\e104";
}
.glyphicon-eye-open:before {
content: "\e105";
}
.glyphicon-eye-close:before {
content: "\e106";
}
.glyphicon-warning-sign:before {
content: "\e107";
}
.glyphicon-plane:before {
content: "\e108";
}
.glyphicon-calendar:before {
content: "\e109";
}
.glyphicon-random:before {
content: "\e110";
}
.glyphicon-comment:before {
content: "\e111";
}
.glyphicon-magnet:before {
content: "\e112";
}
.glyphicon-chevron-up:before {
content: "\e113";
}
.glyphicon-chevron-down:before {
content: "\e114";
}
.glyphicon-retweet:before {
content: "\e115";
}
.glyphicon-shopping-cart:before {
content: "\e116";
}
.glyphicon-folder-close:before {
content: "\e117";
}
.glyphicon-folder-open:before {
content: "\e118";
}
.glyphicon-resize-vertical:before {
content: "\e119";
}
.glyphicon-resize-horizontal:before {
content: "\e120";
}
.glyphicon-hdd:before {
content: "\e121";
}
.glyphicon-bullhorn:before {
content: "\e122";
}
.glyphicon-bell:before {
content: "\e123";
}
.glyphicon-certificate:before {
content: "\e124";
}
.glyphicon-thumbs-up:before {
content: "\e125";
}
.glyphicon-thumbs-down:before {
content: "\e126";
}
.glyphicon-hand-right:before {
content: "\e127";
}
.glyphicon-hand-left:before {
content: "\e128";
}
.glyphicon-hand-up:before {
content: "\e129";
}
.glyphicon-hand-down:before {
content: "\e130";
}
.glyphicon-circle-arrow-right:before {
content: "\e131";
}
.glyphicon-circle-arrow-left:before {
content: "\e132";
}
.glyphicon-circle-arrow-up:before {
content: "\e133";
}
.glyphicon-circle-arrow-down:before {
content: "\e134";
}
.glyphicon-globe:before {
content: "\e135";
}
.glyphicon-wrench:before {
content: "\e136";
}
.glyphicon-tasks:before {
content: "\e137";
}
.glyphicon-filter:before {
content: "\e138";
}
.glyphicon-briefcase:before {
content: "\e139";
}
.glyphicon-fullscreen:before {
content: "\e140";
}
.glyphicon-dashboard:before {
content: "\e141";
}
.glyphicon-paperclip:before {
content: "\e142";
}
.glyphicon-heart-empty:before {
content: "\e143";
}
.glyphicon-link:before {
content: "\e144";
}
.glyphicon-phone:before {
content: "\e145";
}
.glyphicon-pushpin:before {
content: "\e146";
}
.glyphicon-usd:before {
content: "\e148";
}
.glyphicon-gbp:before {
content: "\e149";
}
.glyphicon-sort:before {
content: "\e150";
}
.glyphicon-sort-by-alphabet:before {
content: "\e151";
}
.glyphicon-sort-by-alphabet-alt:before {
content: "\e152";
}
.glyphicon-sort-by-order:before {
content: "\e153";
}
.glyphicon-sort-by-order-alt:before {
content: "\e154";
}
.glyphicon-sort-by-attributes:before {
content: "\e155";
}
.glyphicon-sort-by-attributes-alt:before {
content: "\e156";
}
.glyphicon-unchecked:before {
content: "\e157";
}
.glyphicon-expand:before {
content: "\e158";
}
.glyphicon-collapse-down:before {
content: "\e159";
}
.glyphicon-collapse-up:before {
content: "\e160";
}
.glyphicon-log-in:before {
content: "\e161";
}
.glyphicon-flash:before {
content: "\e162";
}
.glyphicon-log-out:before {
content: "\e163";
}
.glyphicon-new-window:before {
content: "\e164";
}
.glyphicon-record:before {
content: "\e165";
}
.glyphicon-save:before {
content: "\e166";
}
.glyphicon-open:before {
content: "\e167";
}
.glyphicon-saved:before {
content: "\e168";
}
.glyphicon-import:before {
content: "\e169";
}
.glyphicon-export:before {
content: "\e170";
}
.glyphicon-send:before {
content: "\e171";
}
.glyphicon-floppy-disk:before {
content: "\e172";
}
.glyphicon-floppy-saved:before {
content: "\e173";
}
.glyphicon-floppy-remove:before {
content: "\e174";
}
.glyphicon-floppy-save:before {
content: "\e175";
}
.glyphicon-floppy-open:before {
content: "\e176";
}
.glyphicon-credit-card:before {
content: "\e177";
}
.glyphicon-transfer:before {
content: "\e178";
}
.glyphicon-cutlery:before {
content: "\e179";
}
.glyphicon-header:before {
content: "\e180";
}
.glyphicon-compressed:before {
content: "\e181";
}
.glyphicon-earphone:before {
content: "\e182";
}
.glyphicon-phone-alt:before {
content: "\e183";
}
.glyphicon-tower:before {
content: "\e184";
}
.glyphicon-stats:before {
content: "\e185";
}
.glyphicon-sd-video:before {
content: "\e186";
}
.glyphicon-hd-video:before {
content: "\e187";
}
.glyphicon-subtitles:before {
content: "\e188";
}
.glyphicon-sound-stereo:before {
content: "\e189";
}
.glyphicon-sound-dolby:before {
content: "\e190";
}
.glyphicon-sound-5-1:before {
content: "\e191";
}
.glyphicon-sound-6-1:before {
content: "\e192";
}
.glyphicon-sound-7-1:before {
content: "\e193";
}
.glyphicon-copyright-mark:before {
content: "\e194";
}
.glyphicon-registration-mark:before {
content: "\e195";
}
.glyphicon-cloud-download:before {
content: "\e197";
}
.glyphicon-cloud-upload:before {
content: "\e198";
}
.glyphicon-tree-conifer:before {
content: "\e199";
}
.glyphicon-tree-deciduous:before {
content: "\e200";
}
.glyphicon-cd:before {
content: "\e201";
}
.glyphicon-save-file:before {
content: "\e202";
}
.glyphicon-open-file:before {
content: "\e203";
}
.glyphicon-level-up:before {
content: "\e204";
}
.glyphicon-copy:before {
content: "\e205";
}
.glyphicon-paste:before {
content: "\e206";
}
.glyphicon-alert:before {
content: "\e209";
}
.glyphicon-equalizer:before {
content: "\e210";
}
.glyphicon-king:before {
content: "\e211";
}
.glyphicon-queen:before {
content: "\e212";
}
.glyphicon-pawn:before {
content: "\e213";
}
.glyphicon-bishop:before {
content: "\e214";
}
.glyphicon-knight:before {
content: "\e215";
}
.glyphicon-baby-formula:before {
content: "\e216";
}
.glyphicon-tent:before {
content: "\26fa";
}
.glyphicon-blackboard:before {
content: "\e218";
}
.glyphicon-bed:before {
content: "\e219";
}
.glyphicon-apple:before {
content: "\f8ff";
}
.glyphicon-erase:before {
content: "\e221";
}
.glyphicon-hourglass:before {
content: "\231b";
}
.glyphicon-lamp:before {
content: "\e223";
}
.glyphicon-duplicate:before {
content: "\e224";
}
.glyphicon-piggy-bank:before {
content: "\e225";
}
.glyphicon-scissors:before {
content: "\e226";
}
.glyphicon-bitcoin:before {
content: "\e227";
}
.glyphicon-btc:before {
content: "\e227";
}
.glyphicon-xbt:before {
content: "\e227";
}
.glyphicon-yen:before {
content: "\00a5";
}
.glyphicon-jpy:before {
content: "\00a5";
}
.glyphicon-ruble:before {
content: "\20bd";
}
.glyphicon-rub:before {
content: "\20bd";
}
.glyphicon-scale:before {
content: "\e230";
}
.glyphicon-ice-lolly:before {
content: "\e231";
}
.glyphicon-ice-lolly-tasted:before {
content: "\e232";
}
.glyphicon-education:before {
content: "\e233";
}
.glyphicon-option-horizontal:before {
content: "\e234";
}
.glyphicon-option-vertical:before {
content: "\e235";
}
.glyphicon-menu-hamburger:before {
content: "\e236";
}
.glyphicon-modal-window:before {
content: "\e237";
}
.glyphicon-oil:before {
content: "\e238";
}
.glyphicon-grain:before {
content: "\e239";
}
.glyphicon-sunglasses:before {
content: "\e240";
}
.glyphicon-text-size:before {
content: "\e241";
}
.glyphicon-text-color:before {
content: "\e242";
}
.glyphicon-text-background:before {
content: "\e243";
}
.glyphicon-object-align-top:before {
content: "\e244";
}
.glyphicon-object-align-bottom:before {
content: "\e245";
}
.glyphicon-object-align-horizontal:before {
content: "\e246";
}
.glyphicon-object-align-left:before {
content: "\e247";
}
.glyphicon-object-align-vertical:before {
content: "\e248";
}
.glyphicon-object-align-right:before {
content: "\e249";
}
.glyphicon-triangle-right:before {
content: "\e250";
}
.glyphicon-triangle-left:before {
content: "\e251";
}
.glyphicon-triangle-bottom:before {
content: "\e252";
}
.glyphicon-triangle-top:before {
content: "\e253";
}
.glyphicon-console:before {
content: "\e254";
}
.glyphicon-superscript:before {
content: "\e255";
}
.glyphicon-subscript:before {
content: "\e256";
}
.glyphicon-menu-left:before {
content: "\e257";
}
.glyphicon-menu-right:before {
content: "\e258";
}
.glyphicon-menu-down:before {
content: "\e259";
}
.glyphicon-menu-up:before {
content: "\e260";
}
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
@@ -9337,7 +8532,6 @@ header {
margin-bottom: 0;
overflow: hidden;
position: relative;
margin-bottom: 0px;
padding-top: 50%;
padding-bottom: 15%;
}
@@ -9405,13 +8599,13 @@ main article.doc-body {
main article.doc-body {
width: 75%;
}
main article.doc-body.doc-toc {
width: 100%;
}
}
main article.doc-body > * {
max-width: 100%;
}
main.has_code_col {
width: 1440px;
}
@media (max-width: 1440px) {
main.has_code_col {
width: 100%;
+51 -8
View File
@@ -144,6 +144,13 @@ class BootstrapTranslator(nodes.NodeVisitor, object):
addnodes.versionmodified)):
# Never compact paragraphs in document or compound.
return False
for key, value in node.attlist():
# we can ignore a few specific classes, all other non-default
# attributes require that a <p> node remains
if key != 'classes' or value not in ([], ['first'], ['last'], ['first', 'last']):
return False
first = isinstance(node.parent[0], nodes.label)
for child in parent.children[first:]:
# only first paragraph can be compact
@@ -349,6 +356,19 @@ class BootstrapTranslator(nodes.NodeVisitor, object):
attrs = {'src': uri, 'class': 'img-responsive'}
if 'alt' in node:
attrs['alt'] = node['alt']
if 'align' in node:
if node['align'] == 'center':
attrs['class'] += ' center-block'
else:
doc = None
if node.source:
doc = node.source
if node.line:
doc += ':%d' % node.line
self.builder.app.warn(
"Unsupported alignment value \"%s\"" % node['align'],
location=doc
)
# todo: explicit width/height/scale?
self.body.append(self.starttag(node, 'img', **attrs))
def depart_image(self, node): pass
@@ -364,6 +384,18 @@ class BootstrapTranslator(nodes.NodeVisitor, object):
def visit_legend(self, node): pass
def depart_legend(self, node): pass
def visit_line(self, node):
self.body.append(self.starttag(node, 'div', CLASS='line'))
# ensure the line still takes the room it needs
if not len(node): self.body.append(u'<br />')
def depart_line(self, node):
self.body.append(u'</div>')
def visit_line_block(self, node):
self.body.append(self.starttag(node, 'div', CLASS='line-block'))
def depart_line_block(self, node):
self.body.append(u'</div>')
def visit_table(self, node):
self.body.append(self.starttag(node, 'table', CLASS='table'))
def depart_table(self, node):
@@ -591,23 +623,31 @@ class BootstrapTranslator(nodes.NodeVisitor, object):
entries = [(title, ref)] if not toc else ((e[0], e[1]) for e in toc[0]['entries'])
for subtitle, subref in entries:
baseuri = self.builder.get_target_uri(node['parent'])
if subref in env.metadata:
cover = env.metadata[subref].get('banner', conf.odoo_cover_default)
elif subref in conf.odoo_cover_external:
cover = conf.odoo_cover_external[subref]
else:
cover = conf.odoo_cover_default_external
banner = '_static/' + cover
base, ext = os.path.splitext(banner)
small = "{}.small{}".format(base, ext)
if os.path.isfile(urllib.url2pathname(small)):
banner = small
baseuri = self.builder.get_target_uri(node['parent'])
if cover:
banner = '_static/' + cover
base, ext = os.path.splitext(banner)
small = "{}.small{}".format(base, ext)
if os.path.isfile(urllib.url2pathname(small)):
banner = small
style = u"background-image: url('{}')".format(
util.relative_uri(baseuri, banner) or '#')
else:
style = u''
self.body.append(u"""
<div class="col-sm-6 col-md-3">
<figure class="card">
<a href="{link}" class="card-img">
<span style="background-image: url('{banner}')"></span>
<span style="{style}"></span>
<figcaption>{title}</figcaption>
</a>
</figure>
@@ -615,7 +655,7 @@ class BootstrapTranslator(nodes.NodeVisitor, object):
""".format(
link=subref if util.url_re.match(subref) else util.relative_uri(
baseuri, self.builder.get_target_uri(subref)),
banner=util.relative_uri(baseuri, banner) or '#',
style=style,
title=subtitle if subtitle else util.nodes.clean_astext(env.titles[subref]),
))
@@ -634,3 +674,6 @@ class BootstrapTranslator(nodes.NodeVisitor, object):
self.body.append('</%s>' % t)
# Keep non-HTML raw text out of output:
raise nodes.SkipNode
# internal node
def visit_substitution_definition(self, node): raise nodes.SkipNode
+9
View File
@@ -0,0 +1,9 @@
Poland, 2015-07-09
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,
Dariusz Żbikowski darek@krokus.com.pl https://github.com/zbik2607
-1
View File
@@ -92,7 +92,6 @@ pygments_style = 'odoo'
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'odoo'
html_translator_class = 'odoo.translator.BootstrapTranslator'
odoo_cover_default = 'banners/installing_odoo.jpg'
odoo_cover_external = {
-3
View File
@@ -206,9 +206,6 @@ class ir_attachment(osv.osv):
result[attach.id] = self._file_read(cr, uid, attach.store_fname, bin_size)
else:
result[attach.id] = attach.db_datas
if bin_size:
result[attach.id] = int(result[attach.id] or 0)
return result
def _data_set(self, cr, uid, id, name, value, arg, context=None):
+28 -18
View File
@@ -21,6 +21,7 @@ import babel.dates
import werkzeug
from lxml import etree, html
from PIL import Image
import psycopg2
import openerp.http
import openerp.tools
@@ -1281,14 +1282,18 @@ class AssetsBundle(object):
def set_cache(self, type, content):
ira = self.registry['ir.attachment']
ira.invalidate_bundle(self.cr, openerp.SUPERUSER_ID, type=type, xmlid=self.xmlid)
url = '/web/%s/%s/%s' % (type, self.xmlid, self.version)
ira.create(self.cr, openerp.SUPERUSER_ID, dict(
try:
with self.cr.savepoint():
ira.invalidate_bundle(self.cr, openerp.SUPERUSER_ID, type=type, xmlid=self.xmlid)
ira.create(self.cr, openerp.SUPERUSER_ID, dict(
datas=content.encode('utf8').encode('base64'),
type='binary',
name=url,
url=url,
), context=self.context)
except psycopg2.Error:
pass
def css_message(self, message):
# '\A' == css content carriage return
@@ -1545,22 +1550,27 @@ class PreprocessedCSS(StylesheetAsset):
def to_html(self):
if self.url:
ira = self.registry['ir.attachment']
url = self.html_url % self.url
domain = [('type', '=', 'binary'), ('url', '=', url)]
ira_id = ira.search(self.cr, openerp.SUPERUSER_ID, domain, context=self.context)
datas = self.content.encode('utf8').encode('base64')
if ira_id:
# TODO: update only if needed
ira.write(self.cr, openerp.SUPERUSER_ID, ira_id, {'datas': datas}, context=self.context)
else:
ira.create(self.cr, openerp.SUPERUSER_ID, dict(
datas=datas,
mimetype='text/css',
type='binary',
name=url,
url=url,
), context=self.context)
try:
ira = self.registry['ir.attachment']
url = self.html_url % self.url
domain = [('type', '=', 'binary'), ('url', '=', url)]
with self.cr.savepoint():
ira_id = ira.search(self.cr, openerp.SUPERUSER_ID, domain, context=self.context)
datas = self.content.encode('utf8').encode('base64')
if ira_id:
# TODO: update only if needed
ira.write(self.cr, openerp.SUPERUSER_ID, [ira_id], {'datas': datas},
context=self.context)
else:
ira.create(self.cr, openerp.SUPERUSER_ID, dict(
datas=datas,
mimetype='text/css',
type='binary',
name=url,
url=url,
), context=self.context)
except psycopg2.Error:
pass
return super(PreprocessedCSS, self).to_html()
def get_source(self):
+2 -1
View File
@@ -1081,6 +1081,7 @@
<field name="name">Poland</field>
<field name="code">pl</field>
<field name="image" type="base64" file="base/static/img/country_flags/pl.png"></field>
<field name="address_format" eval="'%(street)s\n%(street2)s\n%(zip)s %(city)s\n%(country_name)s'" />
<field name="currency_id" ref="PLN"/>
</record>
<record id="pm" model="res.country">
@@ -1408,7 +1409,7 @@
<field name="name">United States</field>
<field name="code">us</field>
<field name="image" type="base64" file="base/static/img/country_flags/us.png"></field>
<field name="address_format" eval="'%(street)s\n%(street2)s\n%(city)s, %(state_code)s %(zip)s\n%(country_name)s'" />
<field name="address_format" eval="'%(street)s\n%(street2)s\n%(city)s %(state_code)s %(zip)s\n%(country_name)s'" />
<field name="currency_id" ref="USD"/>
</record>
<record id="uy" model="res.country">
+10
View File
@@ -135,6 +135,16 @@ class res_currency(osv.osv):
reads = self.read(cr, uid, ids, ['name','symbol'], context=context, load='_classic_write')
return [(x['id'], tools.ustr(x['name'])) for x in reads]
def copy(self, cr, uid, id, default=None, context=None):
if context is None:
context = {}
if not default:
default = {}
default.update(name=_("%s (copy)")
% (self.browse(cr, uid, id, context=context).name))
return super(res_currency, self).copy(
cr, uid, id, default=default, context=context)
@api.v8
def round(self, amount):
""" Return `amount` rounded according to currency `self`. """
@@ -265,7 +265,7 @@ class test_selection_function(CreatorCase):
def test_empty(self):
self.assertEqual(
self.export(False),
[[False]])
[[None]])
def test_value(self):
# FIXME: selection functions export the *value* itself
@@ -278,7 +278,7 @@ class test_selection_function(CreatorCase):
# fucking hell
self.assertEqual(
self.export(0),
[[False]])
[[None]])
class test_m2o(CreatorCase):
model_name = 'export.many2one'
+11 -6
View File
@@ -1092,6 +1092,11 @@ class _String(Field):
_column_translate = property(attrgetter('translate'))
_related_translate = property(attrgetter('translate'))
_description_translate = property(attrgetter('translate'))
def convert_to_export(self, value, env):
if env.context.get('export_raw_data'):
return value if value else None
return bool(value) and ustr(value)
class Char(_String):
@@ -1212,7 +1217,7 @@ class Date(Field):
def convert_to_export(self, value, env):
if value and env.context.get('export_raw_data'):
return self.from_string(value)
return self.from_string(value) or None
return bool(value) and ustr(value)
@@ -1281,7 +1286,7 @@ class Datetime(Field):
def convert_to_export(self, value, env):
if value and env.context.get('export_raw_data'):
return self.from_string(value)
return self.from_string(value) or None
return bool(value) and ustr(value)
def convert_to_display_name(self, value, record=None):
@@ -1390,7 +1395,7 @@ class Selection(Field):
def convert_to_export(self, value, env):
if not isinstance(self.selection, list):
# FIXME: this reproduces an existing buggy behavior!
return value
return value or None
for item in self._description_selection(env):
if item[0] == value:
return item[1]
@@ -1427,7 +1432,7 @@ class Reference(Selection):
return "%s,%s" % (value._name, value.id) if value else False
def convert_to_export(self, value, env):
return bool(value) and value.name_get()[0][1]
return value.name_get()[0][1] if value else None
def convert_to_display_name(self, value, record=None):
return ustr(value and value.display_name)
@@ -1567,7 +1572,7 @@ class Many2one(_Relational):
return value.id
def convert_to_export(self, value, env):
return bool(value) and value.name_get()[0][1]
return value.name_get()[0][1] if value else None
def convert_to_display_name(self, value, record=None):
return ustr(value.display_name)
@@ -1673,7 +1678,7 @@ class _RelationalMulti(_Relational):
return result
def convert_to_export(self, value, env):
return bool(value) and ','.join(name for id, name in value.name_get())
return ','.join(name for id, name in value.name_get()) if value else None
def convert_to_display_name(self, value, record=None):
raise NotImplementedError()
+2 -1
View File
@@ -50,6 +50,7 @@ import re
import time
from collections import defaultdict, MutableMapping
from inspect import getmembers, currentframe
from operator import itemgetter
import babel.dates
import dateutil.relativedelta
@@ -5401,7 +5402,7 @@ class BaseModel(object):
recs = self.search([('id', 'in', self.ids)])
return self.browse(reversed(recs._ids)) if reverse else recs
else:
return self.browse(map(int, sorted(self, key=key, reverse=reverse)))
return self.browse(map(itemgetter('id'), sorted(self, key=key, reverse=reverse)))
def update(self, values):
""" Update record `self[0]` with ``values``. """
+2
View File
@@ -1069,6 +1069,8 @@ def get_nice_size(value):
size = value
elif value: # this is supposed to be a string
size = len(value)
if size < 12: # suppose human size
return value
return tools.human_size(size)
# See http://www.w3.org/TR/2000/REC-xml-20001006#NT-Char
+1
View File
@@ -518,6 +518,7 @@ ALL_LANGUAGES = {
'id_ID': u'Indonesian / Bahasa Indonesia',
'it_IT': u'Italian / Italiano',
'ja_JP': u'Japanese / 日本語',
'ka_GE': u'Georgian / ქართული ენა',
'kab_DZ': u'Kabyle / Taqbaylit',
'ko_KP': u'Korean (KP) / 한국어 (KP)',
'ko_KR': u'Korean (KR) / 한국어 (KR)',