[MERGE] forward port branch saas-14 up to aab0908818
This commit is contained in:
@@ -18,24 +18,26 @@ class TaxAdjustments(models.TransientModel):
|
|||||||
debit_account_id = fields.Many2one('account.account', string='Debit account', required=True, domain=[('deprecated', '=', False)])
|
debit_account_id = fields.Many2one('account.account', string='Debit account', required=True, domain=[('deprecated', '=', False)])
|
||||||
credit_account_id = fields.Many2one('account.account', string='Credit account', required=True, domain=[('deprecated', '=', False)])
|
credit_account_id = fields.Many2one('account.account', string='Credit account', required=True, domain=[('deprecated', '=', False)])
|
||||||
amount = fields.Monetary(currency_field='company_currency_id', required=True)
|
amount = fields.Monetary(currency_field='company_currency_id', required=True)
|
||||||
|
adjustment_type = fields.Selection([('debit', 'Adjustment in favor of the Estate'), ('credit', 'Adjustment in your favor')], string="Adjustment Type", store=False, required=True)
|
||||||
company_currency_id = fields.Many2one('res.currency', readonly=True, default=lambda self: self.env.user.company_id.currency_id)
|
company_currency_id = fields.Many2one('res.currency', readonly=True, default=lambda self: self.env.user.company_id.currency_id)
|
||||||
tax_id = fields.Many2one('account.tax', string='Adjustment Tax', ondelete='restrict', domain=[('type_tax_use', '=', 'none'), ('tax_adjustment', '=', True)], required=True)
|
tax_id = fields.Many2one('account.tax', string='Adjustment Tax', ondelete='restrict', domain=[('type_tax_use', '=', 'none'), ('tax_adjustment', '=', True)], required=True)
|
||||||
|
|
||||||
@api.multi
|
@api.multi
|
||||||
def _create_move(self):
|
def _create_move(self):
|
||||||
|
adjustment_type = self.env.context.get('adjustment_type', (self.amount > 0.0 and 'debit' or 'credit'))
|
||||||
debit_vals = {
|
debit_vals = {
|
||||||
'name': self.reason,
|
'name': self.reason,
|
||||||
'debit': self.amount,
|
'debit': abs(self.amount),
|
||||||
'credit': 0.0,
|
'credit': 0.0,
|
||||||
'account_id': self.debit_account_id.id,
|
'account_id': self.debit_account_id.id,
|
||||||
'tax_line_id': self.tax_id.id,
|
'tax_line_id': adjustment_type == 'debit' and self.tax_id.id or False,
|
||||||
}
|
}
|
||||||
credit_vals = {
|
credit_vals = {
|
||||||
'name': self.reason,
|
'name': self.reason,
|
||||||
'debit': 0.0,
|
'debit': 0.0,
|
||||||
'credit': self.amount,
|
'credit': abs(self.amount),
|
||||||
'account_id': self.credit_account_id.id,
|
'account_id': self.credit_account_id.id,
|
||||||
'tax_line_id': self.tax_id.id,
|
'tax_line_id': adjustment_type == 'credit' and self.tax_id.id or False,
|
||||||
}
|
}
|
||||||
vals = {
|
vals = {
|
||||||
'journal_id': self.journal_id.id,
|
'journal_id': self.journal_id.id,
|
||||||
@@ -48,6 +50,13 @@ class TaxAdjustments(models.TransientModel):
|
|||||||
return move.id
|
return move.id
|
||||||
|
|
||||||
@api.multi
|
@api.multi
|
||||||
|
def create_move_debit(self):
|
||||||
|
return self.with_context(adjustment_type='debit').create_move()
|
||||||
|
|
||||||
|
@api.multi
|
||||||
|
def create_move_credit(self):
|
||||||
|
return self.with_context(adjustment_type='credit').create_move()
|
||||||
|
|
||||||
def create_move(self):
|
def create_move(self):
|
||||||
#create the adjustment move
|
#create the adjustment move
|
||||||
move_id = self._create_move()
|
move_id = self._create_move()
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
<group>
|
<group>
|
||||||
<group>
|
<group>
|
||||||
<field name="amount"/>
|
<field name="amount"/>
|
||||||
|
<field name="adjustment_type"/>
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<field name="tax_id" widget="selection"/>
|
<field name="tax_id" widget="selection"/>
|
||||||
@@ -26,8 +27,14 @@
|
|||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
<footer>
|
<footer>
|
||||||
<button name="create_move" string="Create and post move" type="object" default_focus="1" class="oe_highlight"/>
|
<div attrs="{'invisible': [('adjustment_type', '=', 'credit')]}">
|
||||||
|
<button name="create_move_debit" string="Create and post move" type="object" default_focus="1" class="oe_highlight"/>
|
||||||
<button string="Cancel" class="btn btn-default" special="cancel" />
|
<button string="Cancel" class="btn btn-default" special="cancel" />
|
||||||
|
</div>
|
||||||
|
<div attrs="{'invisible': [('adjustment_type', '!=', 'credit')]}">
|
||||||
|
<button name="create_move_credit" string="Create and post move" type="object" default_focus="1" class="oe_highlight"/>
|
||||||
|
<button string="Cancel" class="btn btn-default" special="cancel" />
|
||||||
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
</form>
|
</form>
|
||||||
</field>
|
</field>
|
||||||
|
|||||||
@@ -411,7 +411,7 @@ class AccountAssetAsset(models.Model):
|
|||||||
@api.model
|
@api.model
|
||||||
def create(self, vals):
|
def create(self, vals):
|
||||||
asset = super(AccountAssetAsset, self.with_context(mail_create_nolog=True)).create(vals)
|
asset = super(AccountAssetAsset, self.with_context(mail_create_nolog=True)).create(vals)
|
||||||
asset.compute_depreciation_board()
|
asset.sudo().compute_depreciation_board()
|
||||||
return asset
|
return asset
|
||||||
|
|
||||||
@api.multi
|
@api.multi
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
<span t-field="l.user_id.partner_id.name"/>
|
<span t-field="l.user_id.partner_id.name"/>
|
||||||
</td>
|
</td>
|
||||||
<td >
|
<td >
|
||||||
<span t-field="l.name"/>
|
<span t-field="l.name" t-options="{'widget': 'text'}"/>
|
||||||
</td>
|
</td>
|
||||||
<td t-if="show_task or show_project">
|
<td t-if="show_task or show_project">
|
||||||
<t t-if="show_project"><span t-field="l.project_id.name"/></t>
|
<t t-if="show_project"><span t-field="l.project_id.name"/></t>
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ class PaymentTransactionStripe(models.Model):
|
|||||||
@api.multi
|
@api.multi
|
||||||
def stripe_s2s_do_transaction(self, **kwargs):
|
def stripe_s2s_do_transaction(self, **kwargs):
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
result = self._create_stripe_charge(acquirer_ref=self.payment_token_id.acquirer_ref)
|
result = self._create_stripe_charge(acquirer_ref=self.payment_token_id.acquirer_ref, email=self.partner_email)
|
||||||
return self._stripe_s2s_validate_tree(result)
|
return self._stripe_s2s_validate_tree(result)
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
|
|||||||
@@ -1152,7 +1152,8 @@ exports.Orderline = Backbone.Model.extend({
|
|||||||
if (unit.rounding) {
|
if (unit.rounding) {
|
||||||
this.quantity = round_pr(quant, unit.rounding);
|
this.quantity = round_pr(quant, unit.rounding);
|
||||||
var decimals = this.pos.dp['Product Unit of Measure'];
|
var decimals = this.pos.dp['Product Unit of Measure'];
|
||||||
this.quantityStr = formats.format_value(round_di(this.quantity, decimals), { type: 'float', digits: [69, decimals]});
|
this.quantity = round_di(this.quantity, decimals)
|
||||||
|
this.quantityStr = formats.format_value(this.quantity, { type: 'float', digits: [69, decimals]});
|
||||||
} else {
|
} else {
|
||||||
this.quantity = round_pr(quant, 1);
|
this.quantity = round_pr(quant, 1);
|
||||||
this.quantityStr = this.quantity.toFixed(0);
|
this.quantityStr = this.quantity.toFixed(0);
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
<!-- This is a test account for testing with test cards and cannot be used in a live environment -->
|
<!-- This is a test account for testing with test cards and cannot be used in a live environment -->
|
||||||
<record id="pos_mercury_configuration" model="pos_mercury.configuration">
|
<record id="pos_mercury_configuration" model="pos_mercury.configuration">
|
||||||
<field name="name">Mercury Demo</field>
|
<field name="name">Mercury Demo</field>
|
||||||
<field name="merchant_id">334160</field>
|
<field name="merchant_id">755847002</field>
|
||||||
<field name="merchant_pwd">81303DUR</field>
|
<field name="merchant_pwd">xyz</field>
|
||||||
</record>
|
</record>
|
||||||
</data>
|
</data>
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from odoo import models, fields, api, _
|
from odoo import models, fields, api, _
|
||||||
|
from odoo.tools.float_utils import float_compare
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -71,8 +72,9 @@ class PosOrder(models.Model):
|
|||||||
statement_id = super(PosOrder, self).add_payment(data)
|
statement_id = super(PosOrder, self).add_payment(data)
|
||||||
statement_lines = self.env['account.bank.statement.line'].search([('statement_id', '=', statement_id),
|
statement_lines = self.env['account.bank.statement.line'].search([('statement_id', '=', statement_id),
|
||||||
('pos_statement_id', '=', self.id),
|
('pos_statement_id', '=', self.id),
|
||||||
('journal_id', '=', data['journal']),
|
('journal_id', '=', data['journal'])])
|
||||||
('amount', '=', data['amount'])])
|
statement_lines = statement_lines.filtered(lambda line: float_compare(line.amount, data['amount'],
|
||||||
|
precision_rounding=line.journal_currency_id.rounding) == 0)
|
||||||
|
|
||||||
# we can get multiple statement_lines when there are >1 credit
|
# we can get multiple statement_lines when there are >1 credit
|
||||||
# card payments with the same amount. In that case it doesn't
|
# card payments with the same amount. In that case it doesn't
|
||||||
|
|||||||
@@ -63,7 +63,11 @@ class MercuryTransaction(models.Model):
|
|||||||
'SOAPAction': 'http://www.mercurypay.com/CreditTransaction',
|
'SOAPAction': 'http://www.mercurypay.com/CreditTransaction',
|
||||||
}
|
}
|
||||||
|
|
||||||
r = urllib2.Request('https://w1.mercurypay.com/ws/ws.asmx', data=xml_transaction, headers=headers)
|
url = 'https://w1.mercurypay.com/ws/ws.asmx'
|
||||||
|
if self.env['ir.config_parameter'].sudo().get_param('pos_mercury.enable_test_env'):
|
||||||
|
url = 'https://w1.mercurycert.net/ws/ws.asmx'
|
||||||
|
|
||||||
|
r = urllib2.Request(url, data=xml_transaction, headers=headers)
|
||||||
try:
|
try:
|
||||||
u = urllib2.urlopen(r, timeout=65)
|
u = urllib2.urlopen(r, timeout=65)
|
||||||
response = werkzeug.utils.unescape(u.read())
|
response = werkzeug.utils.unescape(u.read())
|
||||||
|
|||||||
@@ -39,6 +39,9 @@ class AccountInvoice(models.Model):
|
|||||||
def _onchange_delivery_address(self):
|
def _onchange_delivery_address(self):
|
||||||
addr = self.partner_id.address_get(['delivery'])
|
addr = self.partner_id.address_get(['delivery'])
|
||||||
self.partner_shipping_id = addr and addr.get('delivery')
|
self.partner_shipping_id = addr and addr.get('delivery')
|
||||||
|
if self.env.context.get('type', 'out_invoice') == 'out_invoice':
|
||||||
|
company = self.company_id or self.env.user.company_id
|
||||||
|
self.comment = company.with_context(lang=self.partner_id.lang).sale_note
|
||||||
|
|
||||||
@api.multi
|
@api.multi
|
||||||
def action_invoice_paid(self):
|
def action_invoice_paid(self):
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class SaleAdvancePaymentInv(models.TransientModel):
|
|||||||
|
|
||||||
account_id = False
|
account_id = False
|
||||||
if self.product_id.id:
|
if self.product_id.id:
|
||||||
account_id = self.product_id.property_account_income_id.id
|
account_id = self.product_id.property_account_income_id.id or self.product_id.categ_id.property_account_income_categ_id.id
|
||||||
if not account_id:
|
if not account_id:
|
||||||
inc_acc = ir_property_obj.get('property_account_income_categ_id', 'product.category')
|
inc_acc = ir_property_obj.get('property_account_income_categ_id', 'product.category')
|
||||||
account_id = order.fiscal_position_id.map_account(inc_acc).id if inc_acc else False
|
account_id = order.fiscal_position_id.map_account(inc_acc).id if inc_acc else False
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template id="report_location_barcode">
|
<template id="report_location_barcode">
|
||||||
<t t-call="report.basic_layout">
|
<t t-call="report.html_container">
|
||||||
<div t-foreach="[docs[x:x+4] for x in xrange(0, len(docs), 4)]" t-as="page_docs" class="page page_stock_location_barcodes">
|
<div t-foreach="[docs[x:x+4] for x in xrange(0, len(docs), 4)]" t-as="page_docs" class="page article page_stock_location_barcodes">
|
||||||
<t t-foreach="page_docs" t-as="o">
|
<t t-foreach="page_docs" t-as="o">
|
||||||
<t t-if="o.barcode"><t t-set="content" t-value="o.barcode"/></t>
|
<t t-if="o.barcode"><t t-set="content" t-value="o.barcode"/></t>
|
||||||
<t t-if="not o.barcode"><t t-set="content" t-value="o.name"/></t>
|
<t t-if="not o.barcode"><t t-set="content" t-value="o.name"/></t>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
|
import datetime
|
||||||
from odoo import api, fields, models
|
from odoo import api, fields, models
|
||||||
|
|
||||||
|
|
||||||
class MakeProcurement(models.TransientModel):
|
class MakeProcurement(models.TransientModel):
|
||||||
_name = 'make.procurement'
|
_name = 'make.procurement'
|
||||||
_description = 'Make Procurements'
|
_description = 'Make Procurements'
|
||||||
@@ -64,9 +64,14 @@ class MakeProcurement(models.TransientModel):
|
|||||||
""" Creates procurement order for selected product. """
|
""" Creates procurement order for selected product. """
|
||||||
ProcurementOrder = self.env['procurement.order']
|
ProcurementOrder = self.env['procurement.order']
|
||||||
for wizard in self:
|
for wizard in self:
|
||||||
|
# we set the time to noon to avoid the date to be changed because of timezone issues
|
||||||
|
date = fields.Datetime.from_string(wizard.date_planned)
|
||||||
|
date = date + datetime.timedelta(hours=12)
|
||||||
|
date = fields.Datetime.to_string(date)
|
||||||
|
|
||||||
procurement = ProcurementOrder.create({
|
procurement = ProcurementOrder.create({
|
||||||
'name': 'INT: %s' % (self.env.user.login),
|
'name': 'INT: %s' % (self.env.user.login),
|
||||||
'date_planned': wizard.date_planned,
|
'date_planned': date,
|
||||||
'product_id': wizard.product_id.id,
|
'product_id': wizard.product_id.id,
|
||||||
'product_qty': wizard.qty,
|
'product_qty': wizard.qty,
|
||||||
'product_uom': wizard.uom_id.id,
|
'product_uom': wizard.uom_id.id,
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class StockWarehouseOrderpoint(models.Model):
|
|||||||
date = interval[1]
|
date = interval[1]
|
||||||
res_intervals += [(date, group), ]
|
res_intervals += [(date, group), ]
|
||||||
else:
|
else:
|
||||||
return [(now_date, None)]
|
return [(False, None)]
|
||||||
return res_intervals
|
return res_intervals
|
||||||
|
|
||||||
def _get_previous_dates(self, start_date=False):
|
def _get_previous_dates(self, start_date=False):
|
||||||
|
|||||||
@@ -85,11 +85,13 @@ class LandedCost(models.Model):
|
|||||||
raise UserError(_('Cost and adjustments lines do not match. You should maybe recompute the landed costs.'))
|
raise UserError(_('Cost and adjustments lines do not match. You should maybe recompute the landed costs.'))
|
||||||
|
|
||||||
for cost in self:
|
for cost in self:
|
||||||
move = self.env['account.move'].create({
|
move = self.env['account.move']
|
||||||
|
move_vals = {
|
||||||
'journal_id': cost.account_journal_id.id,
|
'journal_id': cost.account_journal_id.id,
|
||||||
'date': cost.date,
|
'date': cost.date,
|
||||||
'ref': cost.name
|
'ref': cost.name,
|
||||||
})
|
'line_ids': [],
|
||||||
|
}
|
||||||
for line in cost.valuation_adjustment_lines.filtered(lambda line: line.move_id):
|
for line in cost.valuation_adjustment_lines.filtered(lambda line: line.move_id):
|
||||||
per_unit = line.final_cost / line.quantity
|
per_unit = line.final_cost / line.quantity
|
||||||
diff = per_unit - line.former_cost_per_unit
|
diff = per_unit - line.former_cost_per_unit
|
||||||
@@ -134,8 +136,9 @@ class LandedCost(models.Model):
|
|||||||
for quant in line.move_id.quant_ids:
|
for quant in line.move_id.quant_ids:
|
||||||
if quant.location_id.usage != 'internal':
|
if quant.location_id.usage != 'internal':
|
||||||
qty_out += quant.qty
|
qty_out += quant.qty
|
||||||
line._create_accounting_entries(move, qty_out)
|
move_vals['line_ids'] += line._create_accounting_entries(move, qty_out)
|
||||||
move.assert_balanced()
|
|
||||||
|
move = move.create(move_vals)
|
||||||
cost.write({'state': 'done', 'account_move_id': move.id})
|
cost.write({'state': 'done', 'account_move_id': move.id})
|
||||||
move.post()
|
move.post()
|
||||||
return True
|
return True
|
||||||
@@ -336,11 +339,10 @@ class AdjustmentLines(models.Model):
|
|||||||
Generate the account.move.line values to track the landed cost.
|
Generate the account.move.line values to track the landed cost.
|
||||||
Afterwards, for the goods that are already out of stock, we should create the out moves
|
Afterwards, for the goods that are already out of stock, we should create the out moves
|
||||||
"""
|
"""
|
||||||
AccountMoveLine = self.env['account.move.line'].with_context(check_move_validity=False, recompute=False)
|
AccountMoveLine = []
|
||||||
|
|
||||||
base_line = {
|
base_line = {
|
||||||
'name': self.name,
|
'name': self.name,
|
||||||
'move_id': move.id,
|
|
||||||
'product_id': self.product_id.id,
|
'product_id': self.product_id.id,
|
||||||
'quantity': self.quantity,
|
'quantity': self.quantity,
|
||||||
}
|
}
|
||||||
@@ -354,8 +356,8 @@ class AdjustmentLines(models.Model):
|
|||||||
# negative cost, reverse the entry
|
# negative cost, reverse the entry
|
||||||
debit_line['credit'] = -diff
|
debit_line['credit'] = -diff
|
||||||
credit_line['debit'] = -diff
|
credit_line['debit'] = -diff
|
||||||
AccountMoveLine.create(debit_line)
|
AccountMoveLine.append([0, 0, debit_line])
|
||||||
AccountMoveLine.create(credit_line)
|
AccountMoveLine.append([0, 0, credit_line])
|
||||||
|
|
||||||
# Create account move lines for quants already out of stock
|
# Create account move lines for quants already out of stock
|
||||||
if qty_out > 0:
|
if qty_out > 0:
|
||||||
@@ -375,8 +377,8 @@ class AdjustmentLines(models.Model):
|
|||||||
# negative cost, reverse the entry
|
# negative cost, reverse the entry
|
||||||
debit_line['credit'] = -diff
|
debit_line['credit'] = -diff
|
||||||
credit_line['debit'] = -diff
|
credit_line['debit'] = -diff
|
||||||
AccountMoveLine.create(debit_line)
|
AccountMoveLine.append([0, 0, debit_line])
|
||||||
AccountMoveLine.create(credit_line)
|
AccountMoveLine.append([0, 0, credit_line])
|
||||||
|
|
||||||
# TDE FIXME: oh dear
|
# TDE FIXME: oh dear
|
||||||
if self.env.user.company_id.anglo_saxon_accounting:
|
if self.env.user.company_id.anglo_saxon_accounting:
|
||||||
@@ -396,7 +398,7 @@ class AdjustmentLines(models.Model):
|
|||||||
# negative cost, reverse the entry
|
# negative cost, reverse the entry
|
||||||
debit_line['credit'] = -diff
|
debit_line['credit'] = -diff
|
||||||
credit_line['debit'] = -diff
|
credit_line['debit'] = -diff
|
||||||
AccountMoveLine.create(debit_line)
|
AccountMoveLine.append([0, 0, debit_line])
|
||||||
AccountMoveLine.create(credit_line)
|
AccountMoveLine.append([0, 0, credit_line])
|
||||||
|
|
||||||
return True
|
return AccountMoveLine
|
||||||
|
|||||||
@@ -921,9 +921,10 @@ var CalendarView = View.extend({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
var res_id = parseInt(id).toString() === id ? parseInt(id) : id;
|
||||||
new form_common.FormViewDialog(this, {
|
new form_common.FormViewDialog(this, {
|
||||||
res_model: this.model,
|
res_model: this.model,
|
||||||
res_id: parseInt(id).toString() === id ? parseInt(id) : id,
|
res_id: res_id,
|
||||||
context: this.dataset.get_context(),
|
context: this.dataset.get_context(),
|
||||||
title: title,
|
title: title,
|
||||||
view_id: +this.open_popup_action,
|
view_id: +this.open_popup_action,
|
||||||
@@ -935,7 +936,7 @@ var CalendarView = View.extend({
|
|||||||
}},
|
}},
|
||||||
|
|
||||||
{text: _t("Delete"), close: true, click: function() {
|
{text: _t("Delete"), close: true, click: function() {
|
||||||
self.remove_event(id);
|
self.remove_event(res_id);
|
||||||
}},
|
}},
|
||||||
|
|
||||||
{text: _t("Close"), close: true}
|
{text: _t("Close"), close: true}
|
||||||
|
|||||||
@@ -1856,12 +1856,17 @@ $.summernote.pluginEvents.indent = function (event, editor, layoutInfo, outdent)
|
|||||||
var $dom = $(ancestor);
|
var $dom = $(ancestor);
|
||||||
|
|
||||||
if (!dom.isList(ancestor)) {
|
if (!dom.isList(ancestor)) {
|
||||||
|
// to indent a selection, we indent the child nodes of the common
|
||||||
|
// ancestor that contains this selection
|
||||||
$dom = $(dom.node(ancestor)).children();
|
$dom = $(dom.node(ancestor)).children();
|
||||||
}
|
}
|
||||||
if (!$dom.length) {
|
if (!$dom.not('br').length) {
|
||||||
$dom = $(dom.ancestor(r.sc, dom.isList) || dom.ancestor(r.sc, dom.isCell));
|
// if selection is inside a list, we indent its list items
|
||||||
|
$dom = $(dom.ancestor(r.sc, dom.isList));
|
||||||
if (!$dom.length) {
|
if (!$dom.length) {
|
||||||
$dom = $(r.sc).closest(options.styleTags.join(','));
|
// if the selection is contained in a single HTML node, we indent
|
||||||
|
// the first ancestor 'content block' (P, H1, PRE, ...) or TD
|
||||||
|
$dom = $(r.sc).closest(options.styleTags.join(',')+',td');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import os.path
|
||||||
|
|
||||||
|
try:
|
||||||
|
import GeoIP # Legacy
|
||||||
|
except ImportError:
|
||||||
|
GeoIP = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
import geoip2
|
||||||
|
import geoip2.database
|
||||||
|
except ImportError:
|
||||||
|
geoip2 = None
|
||||||
|
|
||||||
|
class GeoIPResolver(object):
|
||||||
|
def __init__(self, fname):
|
||||||
|
self.fname = fname
|
||||||
|
try:
|
||||||
|
self._db = geoip2.database.Reader(fname)
|
||||||
|
self.version = 2
|
||||||
|
except Exception:
|
||||||
|
try:
|
||||||
|
self._db = GeoIP.open(fname, GeoIP.GEOIP_STANDARD)
|
||||||
|
self.version = 1
|
||||||
|
assert self._db.database_info is not None
|
||||||
|
except Exception:
|
||||||
|
raise ValueError('Invalid GeoIP database: %r' % fname)
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
if self.version == 2:
|
||||||
|
self._db.close()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def open(cls, fname):
|
||||||
|
if not GeoIP and not geoip2:
|
||||||
|
return None
|
||||||
|
if not os.path.exists(fname):
|
||||||
|
return None
|
||||||
|
return GeoIPResolver(fname)
|
||||||
|
|
||||||
|
def resolve(self, ip):
|
||||||
|
if self.version == 1:
|
||||||
|
return self._db.record_by_addr(ip) or {}
|
||||||
|
elif self.version == 2:
|
||||||
|
try:
|
||||||
|
r = self._db.city(ip)
|
||||||
|
except (ValueError, geoip2.errors.AddressNotFoundError):
|
||||||
|
return {}
|
||||||
|
return {
|
||||||
|
'city': r.city.name,
|
||||||
|
'country_code': r.country.iso_code,
|
||||||
|
'country_name': r.country.name,
|
||||||
|
'region': r.subdivisions[0].iso_code if r.subdivisions else None,
|
||||||
|
'time_zone': r.location.time_zone,
|
||||||
|
}
|
||||||
|
|
||||||
|
# compat
|
||||||
|
def record_by_addr(self, addr):
|
||||||
|
return self.resolve(addr)
|
||||||
@@ -14,7 +14,7 @@ import odoo
|
|||||||
from odoo import api, models
|
from odoo import api, models
|
||||||
from odoo import SUPERUSER_ID
|
from odoo import SUPERUSER_ID
|
||||||
from odoo.http import request
|
from odoo.http import request
|
||||||
from odoo.tools import config
|
from odoo.tools import config, ustr
|
||||||
from odoo.exceptions import QWebException
|
from odoo.exceptions import QWebException
|
||||||
from odoo.tools.safe_eval import safe_eval
|
from odoo.tools.safe_eval import safe_eval
|
||||||
|
|
||||||
@@ -22,6 +22,8 @@ from odoo.addons.base import ir
|
|||||||
from odoo.addons.website.models.website import slug, url_for, _UNSLUG_RE
|
from odoo.addons.website.models.website import slug, url_for, _UNSLUG_RE
|
||||||
|
|
||||||
|
|
||||||
|
from ..geoipresolver import GeoIPResolver
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# global resolver (GeoIP API is thread-safe, for multithreaded workers)
|
# global resolver (GeoIP API is thread-safe, for multithreaded workers)
|
||||||
@@ -100,25 +102,18 @@ class Http(models.AbstractModel):
|
|||||||
if odoo._geoip_resolver is not None:
|
if odoo._geoip_resolver is not None:
|
||||||
cls._geoip_resolver = odoo._geoip_resolver
|
cls._geoip_resolver = odoo._geoip_resolver
|
||||||
return
|
return
|
||||||
|
geofile = config.get('geoip_database')
|
||||||
try:
|
try:
|
||||||
import GeoIP
|
odoo._geoip_resolver = GeoIPResolver.open(geofile) or False
|
||||||
# updated database can be downloaded on MaxMind website
|
except Exception as e:
|
||||||
# http://dev.maxmind.com/geoip/legacy/install/city/
|
logger.warning('Cannot load GeoIP: %s', ustr(e))
|
||||||
geofile = config.get('geoip_database')
|
|
||||||
if os.path.exists(geofile):
|
|
||||||
odoo._geoip_resolver = GeoIP.open(geofile, GeoIP.GEOIP_STANDARD)
|
|
||||||
else:
|
|
||||||
odoo._geoip_resolver = False
|
|
||||||
logger.warning('GeoIP database file %r does not exists, apt-get install geoip-database-contrib or download it from http://dev.maxmind.com/geoip/legacy/install/city/', geofile)
|
|
||||||
except ImportError:
|
|
||||||
odoo._geoip_resolver = False
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _geoip_resolve(cls):
|
def _geoip_resolve(cls):
|
||||||
if 'geoip' not in request.session:
|
if 'geoip' not in request.session:
|
||||||
record = {}
|
record = {}
|
||||||
if odoo._geoip_resolver and request.httprequest.remote_addr:
|
if odoo._geoip_resolver and request.httprequest.remote_addr:
|
||||||
record = odoo._geoip_resolver.record_by_addr(request.httprequest.remote_addr) or {}
|
record = odoo._geoip_resolver.resolve(request.httprequest.remote_addr) or {}
|
||||||
request.session['geoip'] = record
|
request.session['geoip'] = record
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ tour.register('event_buy_tickets', {
|
|||||||
{
|
{
|
||||||
content: "Last step",
|
content: "Last step",
|
||||||
trigger: '.oe_website_sale:contains("Thank you for your order")',
|
trigger: '.oe_website_sale:contains("Thank you for your order")',
|
||||||
|
timeout: 30000,
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -21,7 +21,11 @@ odoo.define('website_form.animation', function (require) {
|
|||||||
return $.when(this._super.apply(this, arguments), def);
|
return $.when(this._super.apply(this, arguments), def);
|
||||||
},
|
},
|
||||||
|
|
||||||
start: function() {
|
start: function(editable_mode) {
|
||||||
|
if (editable_mode) {
|
||||||
|
this.stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
var self = this;
|
var self = this;
|
||||||
this.templates_loaded = ajax.loadXML('/website_form/static/src/xml/website_form.xml', qweb);
|
this.templates_loaded = ajax.loadXML('/website_form/static/src/xml/website_form.xml', qweb);
|
||||||
this.$target.find('.o_website_form_send').on('click',function(e) {self.send(e);});
|
this.$target.find('.o_website_form_send').on('click',function(e) {self.send(e);});
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ tour.register('shop_buy_product', {
|
|||||||
{
|
{
|
||||||
content: "finish",
|
content: "finish",
|
||||||
trigger: '.oe_website_sale:contains("Thank you for your order")',
|
trigger: '.oe_website_sale:contains("Thank you for your order")',
|
||||||
|
timeout: 30000,
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -599,7 +599,7 @@ class Module(models.Model):
|
|||||||
res = [0, 0] # [update, add]
|
res = [0, 0] # [update, add]
|
||||||
|
|
||||||
default_version = modules.adapt_version('1.0')
|
default_version = modules.adapt_version('1.0')
|
||||||
known_mods = self.search([])
|
known_mods = self.with_context(lang=None).search([])
|
||||||
known_mods_names = {mod.name: mod for mod in known_mods}
|
known_mods_names = {mod.name: mod for mod in known_mods}
|
||||||
|
|
||||||
# iterate through detected modules and update/create them in db
|
# iterate through detected modules and update/create them in db
|
||||||
|
|||||||
@@ -1385,7 +1385,7 @@
|
|||||||
<field name="name">Sudan</field>
|
<field name="name">Sudan</field>
|
||||||
<field name="code">sd</field>
|
<field name="code">sd</field>
|
||||||
<field file="base/static/img/country_flags/sd.png" name="image" type="base64" />
|
<field file="base/static/img/country_flags/sd.png" name="image" type="base64" />
|
||||||
<field name="currency_id" ref="SDD" />
|
<field name="currency_id" ref="SDG" />
|
||||||
<field eval="249" name="phone_code" />
|
<field eval="249" name="phone_code" />
|
||||||
</record>
|
</record>
|
||||||
<record id="se" model="res.country">
|
<record id="se" model="res.country">
|
||||||
|
|||||||
@@ -1016,6 +1016,7 @@
|
|||||||
<field name="active" eval="False"/>
|
<field name="active" eval="False"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<!-- no longer in use since 2007 -->
|
||||||
<record id="SDD" model="res.currency">
|
<record id="SDD" model="res.currency">
|
||||||
<field name="name">SDD</field>
|
<field name="name">SDD</field>
|
||||||
<field name="symbol">£Sd</field>
|
<field name="symbol">£Sd</field>
|
||||||
@@ -1023,6 +1024,13 @@
|
|||||||
<field name="active" eval="False"/>
|
<field name="active" eval="False"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<record id="SDG" model="res.currency">
|
||||||
|
<field name="name">SDG</field>
|
||||||
|
<field name="symbol">ج.س.</field>
|
||||||
|
<field name="rounding">0.01</field>
|
||||||
|
<field name="active" eval="False"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
<record id="LKR" model="res.currency">
|
<record id="LKR" model="res.currency">
|
||||||
<field name="name">LKR</field>
|
<field name="name">LKR</field>
|
||||||
<field name="symbol">Rs</field>
|
<field name="symbol">Rs</field>
|
||||||
|
|||||||
@@ -877,6 +877,12 @@
|
|||||||
<field name="rate">544.44</field>
|
<field name="rate">544.44</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<record forcecreate="0" id="rateSDG" model="res.currency.rate">
|
||||||
|
<field name="currency_id" ref="SDG" />
|
||||||
|
<field name="name">2010-01-01</field>
|
||||||
|
<field name="rate">3.1999</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
<record forcecreate="0" id="rateLKR" model="res.currency.rate">
|
<record forcecreate="0" id="rateLKR" model="res.currency.rate">
|
||||||
<field name="currency_id" ref="LKR" />
|
<field name="currency_id" ref="LKR" />
|
||||||
<field name="name">2010-01-01</field>
|
<field name="name">2010-01-01</field>
|
||||||
|
|||||||
@@ -255,7 +255,7 @@ class configmanager(object):
|
|||||||
type="int")
|
type="int")
|
||||||
group.add_option("--unaccent", dest="unaccent", my_default=False, action="store_true",
|
group.add_option("--unaccent", dest="unaccent", my_default=False, action="store_true",
|
||||||
help="Use the unaccent function provided by the database when available.")
|
help="Use the unaccent function provided by the database when available.")
|
||||||
group.add_option("--geoip-db", dest="geoip_database", my_default='/usr/share/GeoIP/GeoLiteCity.dat',
|
group.add_option("--geoip-db", dest="geoip_database", my_default='/usr/share/GeoIP/GeoLite2-City.mmdb',
|
||||||
help="Absolute path to the GeoIP database file.")
|
help="Absolute path to the GeoIP database file.")
|
||||||
parser.add_option_group(group)
|
parser.add_option_group(group)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user