[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) 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\'') cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = \'account_move_line_journal_id_period_id_index\'')
if not cr.fetchone(): 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',)) cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = %s', ('account_move_line_date_id_index',))
if not cr.fetchone(): if not cr.fetchone():
cr.execute('CREATE INDEX account_move_line_date_id_index ON account_move_line (date DESC, id desc)') 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.type IN %s)\
AND account_account.active\ AND account_account.active\
AND ((l.reconcile_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 (l.partner_id=res_partner.id)\ AND (l.partner_id=res_partner.id)\
AND (l.date <= %s)\ AND (l.date <= %s)\
AND ' + self.query + ' \ 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 (account_account.type IN %s)\
AND (l.partner_id IN %s)\ AND (l.partner_id IN %s)\
AND ((l.reconcile_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 ' + self.query + '\
AND account_account.active\ AND account_account.active\
AND (l.date <= %s)\ 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 (COALESCE(l.date_maturity, l.date) < %s)\
AND (l.partner_id IN %s)\ AND (l.partner_id IN %s)\
AND ((l.reconcile_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 '+ self.query + '\
AND account_account.active\ AND account_account.active\
AND (l.date <= %s)\ 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 (COALESCE(l.date_maturity,l.date) > %s)\
AND (l.partner_id IN %s)\ AND (l.partner_id IN %s)\
AND ((l.reconcile_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 '+ self.query + '\
AND account_account.active\ AND account_account.active\
AND (l.date <= %s)\ 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 (account_account.type IN %s)
AND (l.partner_id IN %s) AND (l.partner_id IN %s)
AND ((l.reconcile_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 ''' + self.query + '''
AND account_account.active AND account_account.active
AND ''' + dates_query + ''' 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 (l.partner_id IS NULL)\
AND (account_account.type IN %s)\ AND (account_account.type IN %s)\
AND ((l.reconcile_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 ' + self.query + '\
AND (l.date <= %s)\ AND (l.date <= %s)\
AND account_account.active ',(tuple(move_state), tuple(self.ACCOUNT_TYPE), self.date_from, self.date_from,)) 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 (account_account.type IN %s)\
AND (COALESCE(l.date_maturity, l.date) < %s)\ AND (COALESCE(l.date_maturity, l.date) < %s)\
AND ((l.reconcile_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 '+ self.query + '\
AND account_account.active ', (tuple(move_state), tuple(self.ACCOUNT_TYPE), self.date_from, self.date_from)) AND account_account.active ', (tuple(move_state), tuple(self.ACCOUNT_TYPE), self.date_from, self.date_from))
t = self.cr.fetchall() 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 (account_account.type IN %s)\
AND (COALESCE(l.date_maturity,l.date) > %s)\ AND (COALESCE(l.date_maturity,l.date) > %s)\
AND ((l.reconcile_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 '+ self.query + '\
AND account_account.active ', (tuple(move_state), tuple(self.ACCOUNT_TYPE), self.date_from, self.date_from)) AND account_account.active ', (tuple(move_state), tuple(self.ACCOUNT_TYPE), self.date_from, self.date_from))
t = self.cr.fetchall() 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 (account_account.type IN %s)\
AND (l.partner_id IS NULL)\ AND (l.partner_id IS NULL)\
AND ((l.reconcile_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 '+ self.query + '\
AND account_account.active\ AND account_account.active\
AND ' + dates_query + '\ AND ' + dates_query + '\
@@ -694,6 +694,28 @@ class account_analytic_account(osv.osv):
} }
return invoice 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): def _prepare_invoice_lines(self, cr, uid, contract, fiscal_position_id, context=None):
fpos_obj = self.pool.get('account.fiscal.position') fpos_obj = self.pool.get('account.fiscal.position')
fiscal_position = None 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) fiscal_position = fpos_obj.browse(cr, uid, fiscal_position_id, context=context)
invoice_lines = [] invoice_lines = []
for line in contract.recurring_invoice_line_ids: for line in contract.recurring_invoice_line_ids:
values = self._prepare_invoice_line(cr, uid, line, fiscal_position, context=context)
res = line.product_id invoice_lines.append((0, 0, values))
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)],
}))
return invoice_lines return invoice_lines
def _prepare_invoice(self, cr, uid, contract, context=None): def _prepare_invoice(self, cr, uid, contract, context=None):
+1 -1
View File
@@ -899,7 +899,7 @@ class account_voucher(osv.osv):
else: else:
currency_id = journal.company_id.currency_id.id 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({ vals['value'].update({
'currency_id': currency_id, 'currency_id': currency_id,
'payment_rate_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) validation.update(data)
return validation 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): 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 """ retrieve and sign in the user corresponding to provider and validated access token
:param provider: oauth provider id (int) :param provider: oauth provider id (int)
@@ -70,18 +84,7 @@ class res_users(osv.Model):
return None return None
state = simplejson.loads(params['state']) state = simplejson.loads(params['state'])
token = state.get('t') token = state.get('t')
oauth_uid = validation['user_id'] values = self._generate_signup_values(cr, uid, provider, validation, params, context=context)
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,
}
try: try:
_, login, _ = self.signup(cr, uid, values, token, context=context) _, login, _ = self.signup(cr, uid, values, token, context=context)
return login return login
+1 -1
View File
@@ -96,7 +96,7 @@ class calendar_attendee(osv.Model):
'email': fields.char('Email', help="Email of Invited Person"), 'email': fields.char('Email', help="Email of Invited Person"),
'availability': fields.selection([('free', 'Free'), ('busy', 'Busy')], 'Free/Busy', readonly="True"), 'availability': fields.selection([('free', 'Free'), ('busy', 'Busy')], 'Free/Busy', readonly="True"),
'access_token': fields.char('Invitation Token'), '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 = { _defaults = {
'state': 'needsAction', 'state': 'needsAction',
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<openerp> <openerp>
<data> <data noupdate="1">
<record id="event_subscription" model="mail.template"> <record id="event_subscription" model="mail.template">
<field name="name">Event subscription</field> <field name="name">Event subscription</field>
+1 -1
View File
@@ -3,7 +3,7 @@
<data> <data>
<record model="ir.ui.view" id="res_partner_form_ro"> <record model="ir.ui.view" id="res_partner_form_ro">
<field name="name">res.partner.form.ro</field> <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="model">res.partner</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="property_account_position" position="after"> <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.addons.payment_ogone.data import ogone
from openerp.osv import osv, fields from openerp.osv import osv, fields
from openerp.tools import float_round, DEFAULT_SERVER_DATE_FORMAT 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 from openerp.tools.safe_eval import safe_eval
_logger = logging.getLogger(__name__) _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): 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') base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url')
acquirer = self.browse(cr, uid, id, context=context) acquirer = self.browse(cr, uid, id, context=context)
ogone_tx_values = dict(tx_values) ogone_tx_values = dict(tx_values)
temp_ogone_tx_values = { temp_ogone_tx_values = {
'PSPID': acquirer.ogone_pspid, 'PSPID': acquirer.ogone_pspid,
'ORDERID': tx_values['reference'], '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 '', 'CURRENCY': tx_values['currency'] and tx_values['currency'].name or '',
'LANGUAGE': partner_values['lang'], 'LANGUAGE': partner_values['lang'],
'CN': partner_values['name'], 'CN': partner_values['name'],
@@ -31,7 +31,7 @@
<td><span t-field="line.product_id"/></td> <td><span t-field="line.product_id"/></td>
<td class="text-right"> <td class="text-right">
<t t-if="o.state != 'cancel' and o.statement_ids"> <t t-if="o.state != 'cancel' and o.statement_ids">
<span t-esc="'%.f' % line.qty"/> <span t-field="line.qty"/>
</t> </t>
</td> </td>
<td class="text-right"> <td class="text-right">
+1 -1
View File
@@ -81,7 +81,7 @@ class procurement_rule(osv.osv):
return [] return []
_columns = { _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"), 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."), '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"), '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 = { _columns = {
'buy_to_resupply': fields.boolean('Purchase to resupply this warehouse', 'buy_to_resupply': fields.boolean('Purchase to resupply this warehouse',
help="When products are bought, they can be delivered to 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 = { _defaults = {
'buy_to_resupply': True, 'buy_to_resupply': True,
+1 -1
View File
@@ -18,7 +18,7 @@
<field name="inherit_id" ref="stock.view_picking_internal_search"/> <field name="inherit_id" ref="stock.view_picking_internal_search"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//field[@name='product_id']" position="before"> <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> </xpath>
</field> </field>
</record> </record>
+23
View File
@@ -573,8 +573,31 @@ class sale_order(osv.osv):
return True return True
def action_button_confirm(self, cr, uid, ids, context=None): 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.' 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') 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 return True
def action_wait(self, cr, uid, ids, context=None): def action_wait(self, cr, uid, ids, context=None):
+1 -1
View File
@@ -435,7 +435,7 @@
<search string="Search Sales Order"> <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"/> <filter icon="terp-dolar_ok!" string="To Invoice" domain="[('invoiced','&lt;&gt;', 1),('state','=','done')]" help="Sales Order Lines ready to be invoiced"/>
<separator/> <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/> <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"/> <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"/> <field name="order_id"/>
-5
View File
@@ -360,8 +360,3 @@ msgstr ""
msgid "days" msgid "days"
msgstr "" 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 = [] location_ids = []
if context.get('location', False): if context.get('location', False):
if type(context['location']) == type(1): if isinstance(context['location'], (int, long)):
location_ids = [context['location']] location_ids = [context['location']]
elif type(context['location']) in (type(''), type(u'')): elif isinstance(context['location'], basestring):
domain = [('complete_name','ilike',context['location'])] domain = [('complete_name','ilike',context['location'])]
if context.get('force_company', False): if context.get('force_company', False):
domain += [('company_id', '=', context['force_company'])] domain += [('company_id', '=', context['force_company'])]
@@ -85,7 +85,15 @@ class product_product(osv.osv):
location_ids = context['location'] location_ids = context['location']
else: else:
if context.get('warehouse', False): 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: else:
wids = warehouse_obj.search(cr, uid, [], context=context) wids = warehouse_obj.search(cr, uid, [], context=context)
+1 -1
View File
@@ -213,7 +213,7 @@ class stock_location_route(osv.osv):
_order = 'sequence' _order = 'sequence'
_columns = { _columns = {
'name': fields.char('Route Name', required=True), 'name': fields.char('Route Name', required=True, translate=True),
'sequence': fields.integer('Sequence'), 'sequence': fields.integer('Sequence'),
'pull_ids': fields.one2many('procurement.rule', 'route_id', 'Procurement Rules', copy=True), '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."), '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> <header>
<button name="action_confirm" states="draft" string="Mark as Todo" type="object" class="oe_highlight" groups="base.group_user"/> <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="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="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_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')]}"/> <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 LEFT JOIN
product_template ON product_template.id = product_product.product_tmpl_id 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 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 AND stock_quant_move_rel.move_id = stock_move.id AND (
(source_location.company_id is not null and dest_location.company_id is null) or source_location.company_id != dest_location.company_id) (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 ) UNION
(SELECT (SELECT
'-' || stock_move.id::text || '-' || quant.id::text AS id, '-' || stock_move.id::text || '-' || quant.id::text AS id,
@@ -176,8 +179,11 @@ class stock_history(osv.osv):
LEFT JOIN LEFT JOIN
product_template ON product_template.id = product_product.product_tmpl_id 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 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 AND stock_quant_move_rel.move_id = stock_move.id AND (
(dest_location.company_id is not null and source_location.company_id is null) or dest_location.company_id != source_location.company_id) (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 AS foo
GROUP BY move_id, location_id, company_id, product_id, product_categ_id, date, price_unit_on_quant, source 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] user_input = user_input_obj.browse(cr, uid, [user_input_id], context=context)[0]
else: else:
try: 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 except IndexError: # Invalid token
return request.website.render("website.403") return request.website.render("website.403")
else: 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 # Do not open expired survey
errpage = self._check_deadline(cr, uid, user_input, context=context) errpage = self._check_deadline(cr, uid, user_input, context=context)
@@ -140,11 +140,11 @@ class WebsiteSurvey(http.Controller):
# Load the user_input # Load the user_input
try: 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 except IndexError: # Invalid token
return request.website.render("website.403") return request.website.render("website.403")
else: 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 # Do not display expired survey (even if some pages have already been
# displayed -- There's a time for everything!) # displayed -- There's a time for everything!)
@@ -189,9 +189,9 @@ class WebsiteSurvey(http.Controller):
# Fetch previous answers # Fetch previous answers
if page: 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: 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) previous_answers = user_input_line_obj.browse(cr, uid, ids, context=context)
# Return non empty answers in a JSON compatible format # Return non empty answers in a JSON compatible format
@@ -231,7 +231,7 @@ class WebsiteSurvey(http.Controller):
ret = {} ret = {}
# Fetch answers # 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) previous_answers = user_input_line_obj.browse(cr, uid, ids, context=context)
# Compute score for each question # Compute score for each question
@@ -268,14 +268,15 @@ class WebsiteSurvey(http.Controller):
user_input_line_obj = request.registry['survey.user_input_line'] user_input_line_obj = request.registry['survey.user_input_line']
try: 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 except KeyError: # Invalid token
return request.website.render("website.403") 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: for question in questions:
answer_tag = "%s_%s_%s" % (survey.id, page_id, question.id) 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' 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) 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} vals = {'last_displayed_page_id': page_id}
@@ -283,7 +284,7 @@ class WebsiteSurvey(http.Controller):
vals.update({'state': 'done'}) vals.update({'state': 'done'})
else: else:
vals.update({'state': 'skip'}) 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']) ret['redirect'] = '/survey/fill/%s/%s' % (survey.id, post['token'])
if go_back: if go_back:
ret['redirect'] += '/prev' 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({ instance.web.form.Many2ManyDataSet = instance.web.DataSetStatic.extend({
get_context: function() { get_context: function() {
this.context = this.m2m.build_context(); this.context = this.m2m.build_context();
var self = this;
_.each(arguments, function(context) {
self.context.add(context);
});
return this.context; return this.context;
} }
}); });
+1 -1
View File
@@ -132,7 +132,7 @@ class Website(openerp.addons.web.controllers.main.Home):
pages = 0 pages = 0
first_page = None first_page = None
locs = request.website.enumerate_pages() locs = request.website.sudo(user=request.website.user_id.id).enumerate_pages()
while True: while True:
start = pages * LOC_PER_SITEMAP start = pages * LOC_PER_SITEMAP
values = { values = {
+1 -5
View File
@@ -184,12 +184,8 @@ msgstr ""
#. module: website_forum #. module: website_forum
#: view:website:website_forum.header #: view:website:website_forum.header
msgid "Ask a Question"
msgstr ""
#. module: website_forum
#: field:forum.forum,karma_ask:0 #: field:forum.forum,karma_ask:0
msgid "Ask a question" msgid "Ask a Question"
msgstr "" msgstr ""
#. module: website_forum #. module: website_forum
+1 -23
View File
@@ -810,33 +810,11 @@ class website_sale(http.Controller):
if (not order.amount_total and not tx): if (not order.amount_total and not tx):
# Orders are confirmed by payment transactions, but there is none for free orders, # Orders are confirmed by payment transactions, but there is none for free orders,
# (e.g. free events), so confirm immediately # (e.g. free events), so confirm immediately
order.action_button_confirm() order.with_context(dict(context, send_email=True)).action_button_confirm()
# send by email
email_act = sale_order_obj.action_quotation_send(cr, SUPERUSER_ID, [order.id], context=request.context)
elif tx and tx.state == 'cancel': elif tx and tx.state == 'cancel':
# cancel the quotation # cancel the quotation
sale_order_obj.action_cancel(cr, SUPERUSER_ID, [order.id], context=request.context) 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 # clean context and session, then redirect to the confirmation page
request.website.sale_reset(context=context) 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): if hasattr(self, tx_find_method_name):
tx = getattr(self, tx_find_method_name)(cr, uid, data, context=context) 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']: 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 return res
@@ -44,7 +44,6 @@ $('.oe_website_sale').each(function () {
$(oe_website_sale).find(".oe_cart input.js_quantity").on("change", function () { $(oe_website_sale).find(".oe_cart input.js_quantity").on("change", function () {
var $input = $(this); var $input = $(this);
if ($input.data('update_change')) { if ($input.data('update_change')) {
console.log($input.val()+ "+++");
return; return;
} }
var value = parseInt($input.val(), 10); var value = parseInt($input.val(), 10);
@@ -81,7 +80,6 @@ $('.oe_website_sale').each(function () {
.then(function (data) { .then(function (data) {
$input.data('update_change', false); $input.data('update_change', false);
if (value !== parseInt($input.val(), 10)) { if (value !== parseInt($input.val(), 10)) {
console.log($input.val()+ "***");
$input.trigger('change'); $input.trigger('change');
return; return;
} }
+2 -2
View File
@@ -485,9 +485,9 @@
<xpath expr="//div[@id='product_full_description']" position="after"> <xpath expr="//div[@id='product_full_description']" position="after">
<div class="container mt32" t-if="product.alternative_product_ids"> <div class="container mt32" t-if="product.alternative_product_ids">
<h3>Suggested alternatives:</h3> <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"> <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'> <div class='mt16 text-center'>
<span t-field="product.image_small" t-field-options='{"widget": "image", "class": "img-rounded shadow" }'/> <span t-field="product.image_small" t-field-options='{"widget": "image", "class": "img-rounded shadow" }'/>
<h5> <h5>
+25 -2
View File
@@ -1,13 +1,15 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from . import switcher
from . import pygments_override from . import pygments_override
import collections from . import switcher
from . import translator
import sphinx.environment import sphinx.environment
import sphinx.builders.html import sphinx.builders.html
from docutils import nodes from docutils import nodes
def setup(app): def setup(app):
app.set_translator('html', translator.BootstrapTranslator)
switcher.setup(app) switcher.setup(app)
app.add_config_value('odoo_cover_default', None, 'env') app.add_config_value('odoo_cover_default', None, 'env')
app.add_config_value('odoo_cover_external', {}, 'env') app.add_config_value('odoo_cover_external', {}, 'env')
@@ -47,6 +49,27 @@ def navbarify(node, navbar=None):
link.attributes['data-toggle'] = 'dropdown' link.attributes['data-toggle'] = 'dropdown'
# list_item.bullet_list # list_item.bullet_list
list_item.children[1]['classes'].append('dropdown-menu') 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( def resolve_content_toctree(
environment, docname, builder, toctree, prune=True, maxdepth=0, environment, docname, builder, toctree, prune=True, maxdepth=0,
+14 -7
View File
@@ -9,10 +9,11 @@
{% set classes = [] %} {% set classes = [] %}
{% if pagename == master_doc %} {% if pagename == master_doc %}
{% set classes = classes + ['index'] %} {% set classes = classes + ['index'] %}
{% endif %} {% endif %}
{% if 'code-column' in meta %} {% if 'code-column' in meta %}
{% set classes = classes + ['has_code_col'] %} {% set classes = classes + ['has_code_col'] %}
{% endif %} {% endif %}
{%- block doctype -%} {%- block doctype -%}
@@ -46,7 +47,7 @@
{%- block header -%} {%- block header -%}
<header class="{{ ' '.join(classes) }}"> <header class="{{ ' '.join(classes) }}">
<figure class="card top"> <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> </figure>
</header> </header>
<nav id="main_navbar" class="navbar {{ ' '.join(classes) }}"> <nav id="main_navbar" class="navbar {{ ' '.join(classes) }}">
@@ -82,17 +83,22 @@
</li> </li>
</ul> </ul>
{% endif %} {% endif %}
{{ toctree(titles_only=True, maxdepth=2, includehidden=True, {{ toctree(titles_only=True, maxdepth=2, includehidden=True, collapse=False, navbar='main') }}
collapse=False, navbar='main') }}
</nav> </nav>
</div> </div>
</nav> </nav>
{%- endblock -%} {%- endblock -%}
{%- block content -%} {%- 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 %} {% if pagename != master_doc %}
<div class="row"> <div class="row">
{% if 'has-toc' not in meta %}
<aside> <aside>
<div class="navbar-aside text-center"> <div class="navbar-aside text-center">
<div class="logo_box"> <div class="logo_box">
@@ -107,7 +113,8 @@
{% endif %} {% endif %}
</div> </div>
</aside> </aside>
<article class="doc-body"> {% endif %}
<article class="doc-body {% if 'has-toc' in meta %}doc-toc{% endif %}">
{% endif %} {% endif %}
{% block body %} {% endblock %} {% block body %} {% endblock %}
{% if pagename != master_doc %}</article> {% if pagename != master_doc %}</article>
+3 -5
View File
@@ -34,7 +34,6 @@ body, header {
// @w-size-large : 1170px; // @w-size-large : 1170px;
// @w-size-xlarge : 1440px; // @w-size-xlarge : 1440px;
#main_navbar{ #main_navbar{
.container-fluid { .container-fluid {
// @media screen and (min-width: @w-size-medium){ // @media screen and (min-width: @w-size-medium){
@@ -62,7 +61,6 @@ header{
margin-bottom: 0; margin-bottom: 0;
overflow: hidden; overflow: hidden;
position: relative; position: relative;
margin-bottom: 0px;
padding-top: 50%; padding-top: 50%;
padding-bottom: 15%; padding-bottom: 15%;
@@ -120,6 +118,9 @@ main{
padding-left: 30px; padding-left: 30px;
@media (min-width: @w-size-medium) { @media (min-width: @w-size-medium) {
width: 75%; width: 75%;
&.doc-toc {
width: 100%;
}
} }
> *{ > *{
max-width: 100%; max-width: 100%;
@@ -129,9 +130,6 @@ main{
} }
main.has_code_col{ main.has_code_col{
width: 1440px;
@media (max-width:@w-size-xlarge) { @media (max-width:@w-size-xlarge) {
width: 100%; 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); @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 { html {
font-family: sans-serif; font-family: sans-serif;
-ms-text-size-adjust: 100%; -ms-text-size-adjust: 100%;
@@ -256,809 +254,6 @@ th {
border: 1px solid #ddd !important; 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; -webkit-box-sizing: border-box;
-moz-box-sizing: border-box; -moz-box-sizing: border-box;
@@ -9337,7 +8532,6 @@ header {
margin-bottom: 0; margin-bottom: 0;
overflow: hidden; overflow: hidden;
position: relative; position: relative;
margin-bottom: 0px;
padding-top: 50%; padding-top: 50%;
padding-bottom: 15%; padding-bottom: 15%;
} }
@@ -9405,13 +8599,13 @@ main article.doc-body {
main article.doc-body { main article.doc-body {
width: 75%; width: 75%;
} }
main article.doc-body.doc-toc {
width: 100%;
}
} }
main article.doc-body > * { main article.doc-body > * {
max-width: 100%; max-width: 100%;
} }
main.has_code_col {
width: 1440px;
}
@media (max-width: 1440px) { @media (max-width: 1440px) {
main.has_code_col { main.has_code_col {
width: 100%; width: 100%;
+51 -8
View File
@@ -144,6 +144,13 @@ class BootstrapTranslator(nodes.NodeVisitor, object):
addnodes.versionmodified)): addnodes.versionmodified)):
# Never compact paragraphs in document or compound. # Never compact paragraphs in document or compound.
return False 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) first = isinstance(node.parent[0], nodes.label)
for child in parent.children[first:]: for child in parent.children[first:]:
# only first paragraph can be compact # only first paragraph can be compact
@@ -349,6 +356,19 @@ class BootstrapTranslator(nodes.NodeVisitor, object):
attrs = {'src': uri, 'class': 'img-responsive'} attrs = {'src': uri, 'class': 'img-responsive'}
if 'alt' in node: if 'alt' in node:
attrs['alt'] = node['alt'] 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? # todo: explicit width/height/scale?
self.body.append(self.starttag(node, 'img', **attrs)) self.body.append(self.starttag(node, 'img', **attrs))
def depart_image(self, node): pass def depart_image(self, node): pass
@@ -364,6 +384,18 @@ class BootstrapTranslator(nodes.NodeVisitor, object):
def visit_legend(self, node): pass def visit_legend(self, node): pass
def depart_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): def visit_table(self, node):
self.body.append(self.starttag(node, 'table', CLASS='table')) self.body.append(self.starttag(node, 'table', CLASS='table'))
def depart_table(self, node): 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']) entries = [(title, ref)] if not toc else ((e[0], e[1]) for e in toc[0]['entries'])
for subtitle, subref in entries: for subtitle, subref in entries:
baseuri = self.builder.get_target_uri(node['parent'])
if subref in env.metadata: if subref in env.metadata:
cover = env.metadata[subref].get('banner', conf.odoo_cover_default) cover = env.metadata[subref].get('banner', conf.odoo_cover_default)
elif subref in conf.odoo_cover_external: elif subref in conf.odoo_cover_external:
cover = conf.odoo_cover_external[subref] cover = conf.odoo_cover_external[subref]
else: else:
cover = conf.odoo_cover_default_external cover = conf.odoo_cover_default_external
banner = '_static/' + cover
base, ext = os.path.splitext(banner) if cover:
small = "{}.small{}".format(base, ext) banner = '_static/' + cover
if os.path.isfile(urllib.url2pathname(small)): base, ext = os.path.splitext(banner)
banner = small small = "{}.small{}".format(base, ext)
baseuri = self.builder.get_target_uri(node['parent']) 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""" self.body.append(u"""
<div class="col-sm-6 col-md-3"> <div class="col-sm-6 col-md-3">
<figure class="card"> <figure class="card">
<a href="{link}" class="card-img"> <a href="{link}" class="card-img">
<span style="background-image: url('{banner}')"></span> <span style="{style}"></span>
<figcaption>{title}</figcaption> <figcaption>{title}</figcaption>
</a> </a>
</figure> </figure>
@@ -615,7 +655,7 @@ class BootstrapTranslator(nodes.NodeVisitor, object):
""".format( """.format(
link=subref if util.url_re.match(subref) else util.relative_uri( link=subref if util.url_re.match(subref) else util.relative_uri(
baseuri, self.builder.get_target_uri(subref)), 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]), 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) self.body.append('</%s>' % t)
# Keep non-HTML raw text out of output: # Keep non-HTML raw text out of output:
raise nodes.SkipNode 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 # The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes. # a list of builtin themes.
html_theme = 'odoo' html_theme = 'odoo'
html_translator_class = 'odoo.translator.BootstrapTranslator'
odoo_cover_default = 'banners/installing_odoo.jpg' odoo_cover_default = 'banners/installing_odoo.jpg'
odoo_cover_external = { 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) result[attach.id] = self._file_read(cr, uid, attach.store_fname, bin_size)
else: else:
result[attach.id] = attach.db_datas result[attach.id] = attach.db_datas
if bin_size:
result[attach.id] = int(result[attach.id] or 0)
return result return result
def _data_set(self, cr, uid, id, name, value, arg, context=None): 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 import werkzeug
from lxml import etree, html from lxml import etree, html
from PIL import Image from PIL import Image
import psycopg2
import openerp.http import openerp.http
import openerp.tools import openerp.tools
@@ -1281,14 +1282,18 @@ class AssetsBundle(object):
def set_cache(self, type, content): def set_cache(self, type, content):
ira = self.registry['ir.attachment'] 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) 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'), datas=content.encode('utf8').encode('base64'),
type='binary', type='binary',
name=url, name=url,
url=url, url=url,
), context=self.context) ), context=self.context)
except psycopg2.Error:
pass
def css_message(self, message): def css_message(self, message):
# '\A' == css content carriage return # '\A' == css content carriage return
@@ -1545,22 +1550,27 @@ class PreprocessedCSS(StylesheetAsset):
def to_html(self): def to_html(self):
if self.url: if self.url:
ira = self.registry['ir.attachment'] try:
url = self.html_url % self.url ira = self.registry['ir.attachment']
domain = [('type', '=', 'binary'), ('url', '=', url)] url = self.html_url % self.url
ira_id = ira.search(self.cr, openerp.SUPERUSER_ID, domain, context=self.context) domain = [('type', '=', 'binary'), ('url', '=', url)]
datas = self.content.encode('utf8').encode('base64') with self.cr.savepoint():
if ira_id: ira_id = ira.search(self.cr, openerp.SUPERUSER_ID, domain, context=self.context)
# TODO: update only if needed datas = self.content.encode('utf8').encode('base64')
ira.write(self.cr, openerp.SUPERUSER_ID, ira_id, {'datas': datas}, context=self.context) if ira_id:
else: # TODO: update only if needed
ira.create(self.cr, openerp.SUPERUSER_ID, dict( ira.write(self.cr, openerp.SUPERUSER_ID, [ira_id], {'datas': datas},
datas=datas, context=self.context)
mimetype='text/css', else:
type='binary', ira.create(self.cr, openerp.SUPERUSER_ID, dict(
name=url, datas=datas,
url=url, mimetype='text/css',
), context=self.context) type='binary',
name=url,
url=url,
), context=self.context)
except psycopg2.Error:
pass
return super(PreprocessedCSS, self).to_html() return super(PreprocessedCSS, self).to_html()
def get_source(self): def get_source(self):
+2 -1
View File
@@ -1081,6 +1081,7 @@
<field name="name">Poland</field> <field name="name">Poland</field>
<field name="code">pl</field> <field name="code">pl</field>
<field name="image" type="base64" file="base/static/img/country_flags/pl.png"></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"/> <field name="currency_id" ref="PLN"/>
</record> </record>
<record id="pm" model="res.country"> <record id="pm" model="res.country">
@@ -1408,7 +1409,7 @@
<field name="name">United States</field> <field name="name">United States</field>
<field name="code">us</field> <field name="code">us</field>
<field name="image" type="base64" file="base/static/img/country_flags/us.png"></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"/> <field name="currency_id" ref="USD"/>
</record> </record>
<record id="uy" model="res.country"> <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') reads = self.read(cr, uid, ids, ['name','symbol'], context=context, load='_classic_write')
return [(x['id'], tools.ustr(x['name'])) for x in reads] 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 @api.v8
def round(self, amount): def round(self, amount):
""" Return `amount` rounded according to currency `self`. """ """ Return `amount` rounded according to currency `self`. """
@@ -265,7 +265,7 @@ class test_selection_function(CreatorCase):
def test_empty(self): def test_empty(self):
self.assertEqual( self.assertEqual(
self.export(False), self.export(False),
[[False]]) [[None]])
def test_value(self): def test_value(self):
# FIXME: selection functions export the *value* itself # FIXME: selection functions export the *value* itself
@@ -278,7 +278,7 @@ class test_selection_function(CreatorCase):
# fucking hell # fucking hell
self.assertEqual( self.assertEqual(
self.export(0), self.export(0),
[[False]]) [[None]])
class test_m2o(CreatorCase): class test_m2o(CreatorCase):
model_name = 'export.many2one' model_name = 'export.many2one'
+11 -6
View File
@@ -1092,6 +1092,11 @@ class _String(Field):
_column_translate = property(attrgetter('translate')) _column_translate = property(attrgetter('translate'))
_related_translate = property(attrgetter('translate')) _related_translate = property(attrgetter('translate'))
_description_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): class Char(_String):
@@ -1212,7 +1217,7 @@ class Date(Field):
def convert_to_export(self, value, env): def convert_to_export(self, value, env):
if value and env.context.get('export_raw_data'): 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) return bool(value) and ustr(value)
@@ -1281,7 +1286,7 @@ class Datetime(Field):
def convert_to_export(self, value, env): def convert_to_export(self, value, env):
if value and env.context.get('export_raw_data'): 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) return bool(value) and ustr(value)
def convert_to_display_name(self, value, record=None): def convert_to_display_name(self, value, record=None):
@@ -1390,7 +1395,7 @@ class Selection(Field):
def convert_to_export(self, value, env): def convert_to_export(self, value, env):
if not isinstance(self.selection, list): if not isinstance(self.selection, list):
# FIXME: this reproduces an existing buggy behavior! # FIXME: this reproduces an existing buggy behavior!
return value return value or None
for item in self._description_selection(env): for item in self._description_selection(env):
if item[0] == value: if item[0] == value:
return item[1] return item[1]
@@ -1427,7 +1432,7 @@ class Reference(Selection):
return "%s,%s" % (value._name, value.id) if value else False return "%s,%s" % (value._name, value.id) if value else False
def convert_to_export(self, value, env): 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): def convert_to_display_name(self, value, record=None):
return ustr(value and value.display_name) return ustr(value and value.display_name)
@@ -1567,7 +1572,7 @@ class Many2one(_Relational):
return value.id return value.id
def convert_to_export(self, value, env): 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): def convert_to_display_name(self, value, record=None):
return ustr(value.display_name) return ustr(value.display_name)
@@ -1673,7 +1678,7 @@ class _RelationalMulti(_Relational):
return result return result
def convert_to_export(self, value, env): 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): def convert_to_display_name(self, value, record=None):
raise NotImplementedError() raise NotImplementedError()
+2 -1
View File
@@ -50,6 +50,7 @@ import re
import time import time
from collections import defaultdict, MutableMapping from collections import defaultdict, MutableMapping
from inspect import getmembers, currentframe from inspect import getmembers, currentframe
from operator import itemgetter
import babel.dates import babel.dates
import dateutil.relativedelta import dateutil.relativedelta
@@ -5401,7 +5402,7 @@ class BaseModel(object):
recs = self.search([('id', 'in', self.ids)]) recs = self.search([('id', 'in', self.ids)])
return self.browse(reversed(recs._ids)) if reverse else recs return self.browse(reversed(recs._ids)) if reverse else recs
else: 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): def update(self, values):
""" Update record `self[0]` with ``values``. """ """ Update record `self[0]` with ``values``. """
+2
View File
@@ -1069,6 +1069,8 @@ def get_nice_size(value):
size = value size = value
elif value: # this is supposed to be a string elif value: # this is supposed to be a string
size = len(value) size = len(value)
if size < 12: # suppose human size
return value
return tools.human_size(size) return tools.human_size(size)
# See http://www.w3.org/TR/2000/REC-xml-20001006#NT-Char # 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', 'id_ID': u'Indonesian / Bahasa Indonesia',
'it_IT': u'Italian / Italiano', 'it_IT': u'Italian / Italiano',
'ja_JP': u'Japanese / 日本語', 'ja_JP': u'Japanese / 日本語',
'ka_GE': u'Georgian / ქართული ენა',
'kab_DZ': u'Kabyle / Taqbaylit', 'kab_DZ': u'Kabyle / Taqbaylit',
'ko_KP': u'Korean (KP) / 한국어 (KP)', 'ko_KP': u'Korean (KP) / 한국어 (KP)',
'ko_KR': u'Korean (KR) / 한국어 (KR)', 'ko_KR': u'Korean (KR) / 한국어 (KR)',