summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2015-08-24 18:19:19 +0200
committerChristophe Simonis <chs@odoo.com>2015-08-24 18:19:19 +0200
commit88c0ce0692ccf3b1302e15c4ebe34dbf2040be40 (patch)
tree5bb1749f69f96df22a92a747052dc2965e83430e /addons
parent878c3c9291ad69b530d24227cb25b38dbf10229b (diff)
parente16d495d8965522d90ddf5d5da234b1650a695f9 (diff)
[MERGE] forward port of branch saas-6 up to e16d495
Diffstat (limited to 'addons')
-rw-r--r--addons/account/models/account_invoice.py1
-rw-r--r--addons/account_analytic_plans/security/ir.model.access.csv2
-rw-r--r--addons/delivery/stock.py1
-rw-r--r--addons/hr_timesheet_invoice/hr_timesheet_invoice.py8
-rw-r--r--addons/mass_mailing/wizard/test_mailing.py1
-rw-r--r--addons/payment_ogone/models/ogone.py11
-rw-r--r--addons/point_of_sale/tools/posbox/overwrite_before_init/etc/default/keyboard10
-rwxr-xr-xaddons/point_of_sale/tools/posbox/overwrite_before_init/etc/init_posbox_image.sh10
-rw-r--r--addons/point_of_sale/tools/posbox/overwrite_before_init/etc/udev/rules.d/99-usb.rules2
-rw-r--r--addons/point_of_sale/tools/posbox/overwrite_before_init/home/pi/.inputrc53
-rw-r--r--addons/point_of_sale/tools/posbox/overwrite_before_init/home/pi/.vimrc27
-rw-r--r--addons/purchase/purchase.py12
-rw-r--r--addons/purchase_analytic_plans/purchase_analytic_plans_view.xml4
-rw-r--r--addons/purchase_requisition/static/src/js/web_addons.js2
-rw-r--r--addons/sale_contract/models/sale_contract.py1
-rw-r--r--addons/stock/product_view.xml2
-rw-r--r--addons/stock/report/report_stock_forecast.py46
-rw-r--r--addons/stock/stock.py4
-rw-r--r--addons/stock_dropshipping/stock_dropshipping.py9
-rw-r--r--addons/web/static/src/js/views/list_view.js1
-rw-r--r--addons/web/static/src/js/views/search_view.js2
-rw-r--r--addons/web_editor/static/lib/summernote/src/js/editing/History.js2
-rw-r--r--addons/web_editor/static/src/js/editor.js2
-rw-r--r--addons/web_editor/static/src/js/snippets.editor.js85
-rw-r--r--addons/web_editor/static/src/js/snippets.options.js26
-rw-r--r--addons/web_editor/static/src/js/summernote.js29
-rw-r--r--addons/web_editor/static/src/js/widgets.js18
-rw-r--r--addons/website/static/src/js/website.snippets.editor.js12
-rw-r--r--addons/website/static/src/js/website.snippets.gallery.js21
-rw-r--r--addons/website/static/src/js/website.theme.js54
-rw-r--r--addons/website_sale/models/product.py6
-rw-r--r--addons/website_sale/static/src/css/website_sale.css4
-rw-r--r--addons/website_sale/views/templates.xml8
33 files changed, 333 insertions, 143 deletions
diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py
index 804660ede8d..ea80678840a 100644
--- a/addons/account/models/account_invoice.py
+++ b/addons/account/models/account_invoice.py
@@ -574,6 +574,7 @@ class AccountInvoice(models.Model):
else:
line['currency_id'] = False
line['amount_currency'] = False
+ line['price'] = self.currency_id.round(line['price'])
if self.type in ('out_invoice', 'in_refund'):
total += line['price']
total_currency += line['amount_currency'] or line['price']
diff --git a/addons/account_analytic_plans/security/ir.model.access.csv b/addons/account_analytic_plans/security/ir.model.access.csv
index 9ba40d5c1c3..7a8d6e29067 100644
--- a/addons/account_analytic_plans/security/ir.model.access.csv
+++ b/addons/account_analytic_plans/security/ir.model.access.csv
@@ -2,5 +2,7 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_account_analytic_plan,account.analytic.plan,model_account_analytic_plan,account.group_account_user,1,1,1,1
access_account_analytic_plan_line,account.analytic.plan.line,model_account_analytic_plan_line,account.group_account_user,1,1,1,1
access_account_analytic_plan_instance,account.analytic.plan.instance,model_account_analytic_plan_instance,account.group_account_user,1,1,1,1
+access_account_analytic_plan_instance_group_user,account.analytic.plan.instance,model_account_analytic_plan_instance,base.group_user,1,0,0,0
access_account_analytic_plan_instance_line,account.analytic.plan.instance.line,model_account_analytic_plan_instance_line,account.group_account_user,1,1,1,1
+access_account_analytic_plan_instance_line_group_user,account.analytic.plan.instance.line,model_account_analytic_plan_instance_line,base.group_user,1,0,0,0
access_account_analytic_plan_line_invoice,account.analytic.plan.line.invoice,model_account_analytic_plan_line,account.group_account_user,1,1,1,1
diff --git a/addons/delivery/stock.py b/addons/delivery/stock.py
index 69238eee0be..1b028032432 100644
--- a/addons/delivery/stock.py
+++ b/addons/delivery/stock.py
@@ -48,6 +48,7 @@ class stock_picking(osv.osv):
"""
carrier_obj = self.pool.get('delivery.carrier')
grid_obj = self.pool.get('delivery.grid')
+ fpos_obj = self.pool['account.fiscal.position']
currency_obj = self.pool.get('res.currency')
if not picking.carrier_id or \
any(inv_line.product_id.id == picking.carrier_id.product_id.id
diff --git a/addons/hr_timesheet_invoice/hr_timesheet_invoice.py b/addons/hr_timesheet_invoice/hr_timesheet_invoice.py
index 7dffc8c042b..f040bf815d2 100644
--- a/addons/hr_timesheet_invoice/hr_timesheet_invoice.py
+++ b/addons/hr_timesheet_invoice/hr_timesheet_invoice.py
@@ -249,8 +249,10 @@ class account_analytic_line(osv.osv):
# key_id is either an account.analytic.account, either a res.partner
# don't really care, what's important is the analytic lines that
# will be used to create the invoice lines
-
- partner = analytic_line_ids[0].account_id.partner_id # will be the same for every line
+ account = analytic_lines[0].account_id
+ partner = account.partner_id # will be the same for every line
+ if (not partner) or not (currency_id):
+ raise UserError(_('Contract incomplete. Please fill in the Customer and Pricelist fields for %s.') % (account.name))
curr_invoice = self._prepare_cost_invoice(cr, uid, partner, company_id, currency_id, analytic_line_ids, group_by_partner, context=context)
invoice_context = dict(context,
@@ -265,8 +267,6 @@ class account_analytic_line(osv.osv):
invoice_lines_grouping = {}
for analytic_line in analytic_line_ids:
account = analytic_line.account_id
- if (not partner) or not (account.pricelist_id):
- raise UserError(_('Contract incomplete. Please fill in the Customer and Pricelist fields for %s.') % (account.name))
if not analytic_line.to_invoice:
raise UserError(_('Trying to invoice non invoiceable line for %s.') % (analytic_line.product_id.name))
diff --git a/addons/mass_mailing/wizard/test_mailing.py b/addons/mass_mailing/wizard/test_mailing.py
index 237e1521c19..c0601ea29d5 100644
--- a/addons/mass_mailing/wizard/test_mailing.py
+++ b/addons/mass_mailing/wizard/test_mailing.py
@@ -33,6 +33,7 @@ class TestMassMailing(osv.TransientModel):
'body_html': '',
'notification': True,
'mailing_id': mailing.id,
+ 'attachment_ids': [(4, attachment.id) for attachment in mailing.attachment_ids],
}
mail_mail_obj = Mail.browse(cr, uid, Mail.create(cr, uid, mail_values, context=context), context=context)
unsubscribe_url = Mail._get_unsubscribe_url(cr, uid, mail_mail_obj, test_mail, context=context)
diff --git a/addons/payment_ogone/models/ogone.py b/addons/payment_ogone/models/ogone.py
index 40bd0e2a974..a70dda7d35f 100644
--- a/addons/payment_ogone/models/ogone.py
+++ b/addons/payment_ogone/models/ogone.py
@@ -249,6 +249,9 @@ class PaymentTxOgone(osv.Model):
_logger.info(error_msg)
raise ValidationError(error_msg)
+ if not tx.acquirer_reference:
+ tx.acquirer_reference = pay_id
+
# alias was created on ogone server, store it
if alias:
method_obj = self.pool['payment.method']
@@ -380,7 +383,7 @@ class PaymentTxOgone(osv.Model):
_logger.info('Ogone: trying to validate an already validated tx (ref %s)', tx.reference)
return True
- status = int(tree.get('STATUS', '0'))
+ status = int(tree.get('STATUS') or 0)
if status in self._ogone_valid_tx_status:
tx.write({
'state': 'done',
@@ -401,11 +404,11 @@ class PaymentTxOgone(osv.Model):
'acquirer_reference': tree.get('PAYID'),
'html_3ds': str(tree.HTML_ANSWER).decode('base64')
})
- elif status in self._ogone_wait_tx_status and tries > 0:
- time.sleep(1500)
+ elif (not status or status in self._ogone_wait_tx_status) and tries > 0:
+ time.sleep(500)
tx.write({'acquirer_reference': tree.get('PAYID')})
tree = self._ogone_s2s_get_tx_status(tx)
- return self.ogone_s2s_validate(tx, tree, tries - 1)
+ return self._ogone_s2s_validate_tree(tx, tree, tries - 1)
else:
error = 'Ogone: feedback error: %(error_str)s\n\n%(error_code)s: %(error_msg)s' % {
'error_str': tree.get('NCERRORPLUS'),
diff --git a/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/default/keyboard b/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/default/keyboard
new file mode 100644
index 00000000000..2609b092bcc
--- /dev/null
+++ b/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/default/keyboard
@@ -0,0 +1,10 @@
+# KEYBOARD CONFIGURATION FILE
+
+# Consult the keyboard(5) manual page.
+
+XKBMODEL="pc105"
+XKBLAYOUT="us"
+XKBVARIANT=""
+XKBOPTIONS=""
+
+BACKSPACE="guess" \ No newline at end of file
diff --git a/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init_posbox_image.sh b/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init_posbox_image.sh
index 68b64fb94ca..781b599d51f 100755
--- a/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init_posbox_image.sh
+++ b/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init_posbox_image.sh
@@ -31,7 +31,7 @@ apt-get -y autoremove
apt-get update
apt-get -y dist-upgrade
-PKGS_TO_INSTALL="adduser postgresql-client python python-dateutil python-decorator python-docutils python-feedparser python-imaging python-jinja2 python-ldap python-libxslt1 python-lxml python-mako python-mock python-openid python-passlib python-psutil python-psycopg2 python-pybabel python-pychart python-pydot python-pyparsing python-pypdf python-reportlab python-requests python-simplejson python-tz python-unittest2 python-vatnumber python-vobject python-werkzeug python-xlwt python-yaml postgresql python-gevent python-serial python-pip python-dev localepurge vim mc mg"
+PKGS_TO_INSTALL="adduser postgresql-client python python-dateutil python-decorator python-docutils python-feedparser python-imaging python-jinja2 python-ldap python-libxslt1 python-lxml python-mako python-mock python-openid python-passlib python-psutil python-psycopg2 python-pybabel python-pychart python-pydot python-pyparsing python-pypdf python-reportlab python-requests python-simplejson python-tz python-unittest2 python-vatnumber python-vobject python-werkzeug python-xlwt python-yaml postgresql python-gevent python-serial python-pip python-dev localepurge vim mc mg screen"
apt-get -y install ${PKGS_TO_INSTALL}
@@ -48,14 +48,22 @@ pip install pyusb==1.0.0b1
pip install qrcode
pip install evdev
+groupadd usbusers
+usermod -a -G usbusers pi
usermod -a -G lp pi
sudo -u postgres createuser -s pi
mkdir /var/log/odoo
chown pi:pi /var/log/odoo
+echo "* * * * * rm /var/run/odoo/sessions/*" | crontab -
+
update-rc.d odoo defaults
+# https://www.raspberrypi.org/forums/viewtopic.php?p=79249
+# to not have "setting up console font and keymap" during boot take ages
+setupcon
+
# create dirs for ramdisks
create_ramdisk_dir () {
mkdir "${1}_ram"
diff --git a/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/udev/rules.d/99-usb.rules b/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/udev/rules.d/99-usb.rules
new file mode 100644
index 00000000000..7a282a8e6e1
--- /dev/null
+++ b/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/udev/rules.d/99-usb.rules
@@ -0,0 +1,2 @@
+SUBSYSTEM=="usb", GROUP="usbusers", MODE="0660"
+SUBSYSTEMS=="usb", GROUP="usbusers", MODE="0660" \ No newline at end of file
diff --git a/addons/point_of_sale/tools/posbox/overwrite_before_init/home/pi/.inputrc b/addons/point_of_sale/tools/posbox/overwrite_before_init/home/pi/.inputrc
new file mode 100644
index 00000000000..131b24148c2
--- /dev/null
+++ b/addons/point_of_sale/tools/posbox/overwrite_before_init/home/pi/.inputrc
@@ -0,0 +1,53 @@
+#
+set meta-flag on
+set convert-meta off
+set input-meta on
+set output-meta on
+set show-all-if-ambiguous on
+set visible-stats on
+set bell-style none
+# set bell-style visible
+#"\M-k": kill-whole-line
+#----------------------------------------------------------
+# arrows left/right/up/down
+"\e[C": forward-char
+"\e[D": backward-char
+"\e[A": previous-history
+"\e[B": next-history
+# ---------------------------------------------------------
+# pgup/pgdn
+"\e[6~": history-search-forward
+"\e[5~": history-search-backward
+#----------------------------------------------------------
+# insert,delete
+#"\e[2~": quoted-insert
+"\e[3~": delete-char
+# esc+delete, esc+backspace
+"\e\e[3~": kill-word
+"\e\C-h": backward-kill-word
+#----------------------------------------------------------
+# ctrl left/right (rxvt)
+"\eOc": forward-word
+"\eOd": backward-word
+# ctrl left/right (xterm)
+"\e[1;5C": forward-word
+"\e[1;5D": backward-word
+# ctrl left/right (unknown)
+#"\e[5C": forward-word
+#"\e[5D": backward-word
+#"\e\e[C": forward-word
+#"\e\e[D": backward-word
+# ---------------------------------------------------------
+# home/end (linux console)
+"\e[1~": beginning-of-line
+"\e[4~": end-of-line
+# home/end (rxvt)
+"\e[7~": beginning-of-line
+"\e[8~": end-of-line
+# home/end (xterm, freebsd console)
+"\e[H": beginning-of-line
+"\e[F": end-of-line
+# home/end (non RH/Debian xterm, unknown)
+"\eOH": beginning-of-line
+"\eOF": end-of-line
+"\eOw": end-of-line
diff --git a/addons/point_of_sale/tools/posbox/overwrite_before_init/home/pi/.vimrc b/addons/point_of_sale/tools/posbox/overwrite_before_init/home/pi/.vimrc
new file mode 100644
index 00000000000..9e65af338fa
--- /dev/null
+++ b/addons/point_of_sale/tools/posbox/overwrite_before_init/home/pi/.vimrc
@@ -0,0 +1,27 @@
+set all&
+set autoindent
+set backspace=2
+set nobackup
+set nocompatible
+set noerrorbells
+set noexpandtab
+set expandtab
+set number
+set hidden
+set history=500
+set hlsearch
+set ignorecase
+set modeline
+set ruler
+set shiftwidth=4
+set scrolloff=5
+set showcmd
+set showmode
+set tabstop=4
+set textwidth=0
+set visualbell
+set t_vb=
+set wrap
+set list
+set listchars=tab:~.,trail:.,extends:>,precedes:<
+set viminfo="NONE"
diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py
index 47fd47ef794..d7a0b109a38 100644
--- a/addons/purchase/purchase.py
+++ b/addons/purchase/purchase.py
@@ -746,8 +746,12 @@ class purchase_order(osv.osv):
#we don't round the price_unit, as we may want to store the standard price with more digits than allowed by the currency
price_unit = self.pool.get('res.currency').compute(cr, uid, order.currency_id.id, order.company_id.currency_id.id, price_unit, round=False, context=context)
res = []
+ if order.location_id.usage == 'customer':
+ name = order_line.product_id.with_context(dict(context or {}, lang=order.dest_address_id.lang)).name
+ else:
+ name = order_line.name or ''
move_template = {
- 'name': order_line.name or '',
+ 'name': name,
'product_id': order_line.product_id.id,
'product_uom': order_line.product_uom.id,
'product_uos': order_line.product_uom.id,
@@ -1478,6 +1482,9 @@ class procurement_order(osv.osv):
return qty, price
+ def update_origin_po(self, cr, uid, po, proc, context=None):
+ pass
+
def _get_grouping_dicts(self, cr, uid, ids, context=None):
"""
It will group the procurements according to the pos they should go into. That way, lines going to the same
@@ -1610,6 +1617,9 @@ class procurement_order(osv.osv):
po_obj.message_post(cr, uid, [add_purchase], body=msg, context=context)
po_obj.write(cr, uid, [add_purchase], {'order_line': line_values},context=context)
+ for procurement in procurements:
+ self.update_origin_po(cr, uid, po, procurement, context=context)
+
# Create new purchase orders
partner_obj = self.pool.get("res.partner")
diff --git a/addons/purchase_analytic_plans/purchase_analytic_plans_view.xml b/addons/purchase_analytic_plans/purchase_analytic_plans_view.xml
index 28ca76e8430..ea16ae891b3 100644
--- a/addons/purchase_analytic_plans/purchase_analytic_plans_view.xml
+++ b/addons/purchase_analytic_plans/purchase_analytic_plans_view.xml
@@ -8,7 +8,7 @@
<field name="inherit_id" ref="purchase.purchase_order_line_form"/>
<field name="arch" type="xml">
<field name="account_analytic_id" position="replace">
- <field name="analytics_id" context="{'journal_id':parent.journal_id, 'model': 'purchase_order'}" domain="[('plan_id','&lt;&gt;',False)]"/>
+ <field name="analytics_id" groups="purchase.group_analytic_accounting" context="{'journal_id':parent.journal_id, 'model': 'purchase_order'}" domain="[('plan_id','&lt;&gt;',False)]"/>
</field>
</field>
</record>
@@ -19,7 +19,7 @@
<field name="inherit_id" ref="purchase.purchase_order_form"/>
<field name="arch" type="xml">
<field name="account_analytic_id" position="replace">
- <field name="analytics_id" context="{'journal_id':parent.journal_id}" domain="[('plan_id','&lt;&gt;',False)]"/>
+ <field name="analytics_id" groups="purchase.group_analytic_accounting" context="{'journal_id':parent.journal_id}" domain="[('plan_id','&lt;&gt;',False)]"/>
</field>
</field>
</record>
diff --git a/addons/purchase_requisition/static/src/js/web_addons.js b/addons/purchase_requisition/static/src/js/web_addons.js
index d67c8ec146d..f2ea43423f0 100644
--- a/addons/purchase_requisition/static/src/js/web_addons.js
+++ b/addons/purchase_requisition/static/src/js/web_addons.js
@@ -24,7 +24,7 @@ var CompareListView = ListView.extend({
generate_purchase_order: function () {
var self = this;
new Model(self.dataset.model).call("generate_po",[self.dataset.context.tender_id,self.dataset.context]).then(function(result) {
- self.ViewManager.ActionManager.history_back();
+ self.ViewManager.action_manager.history_back();
});
},
});
diff --git a/addons/sale_contract/models/sale_contract.py b/addons/sale_contract/models/sale_contract.py
index 7fcd9f51bc5..f47b4b0673a 100644
--- a/addons/sale_contract/models/sale_contract.py
+++ b/addons/sale_contract/models/sale_contract.py
@@ -673,6 +673,7 @@ class account_analytic_account(osv.osv):
'fiscal_position_id': fpos_id,
'payment_term_id': partner_payment_term,
'company_id': contract.company_id.id or False,
+ 'user_id': contract.manager_id.id or uid,
'comment': _("This invoice covers the following period: %s - %s") % (next_date.date(), new_date.date()),
}
return invoice
diff --git a/addons/stock/product_view.xml b/addons/stock/product_view.xml
index 17162086c9f..4c717702d5c 100644
--- a/addons/stock/product_view.xml
+++ b/addons/stock/product_view.xml
@@ -139,7 +139,7 @@
</group>
</group>
<field name="product_manager" position="attributes">
- <attribute name="context">{'default_groups_ref': ['base.group_user', 'base.group_sale_manager', 'stock.group_stock_manager']}</attribute>
+ <attribute name="context" translation="off">{'default_groups_ref': ['base.group_user', 'base.group_sale_manager', 'stock.group_stock_manager']}</attribute>
</field>
<group name="procurement" position="after" >
<group string="Supply Chain Information" attrs="{'invisible': [('type', '=', 'service')]}" groups="base.group_user">
diff --git a/addons/stock/report/report_stock_forecast.py b/addons/stock/report/report_stock_forecast.py
index 61397d5a25c..1161e5fc209 100644
--- a/addons/stock/report/report_stock_forecast.py
+++ b/addons/stock/report/report_stock_forecast.py
@@ -17,36 +17,24 @@ class report_stock_forecast(models.Model):
def init(self, cr):
tools.drop_view_if_exists(cr, 'report_stock_forecast')
cr.execute("""CREATE or REPLACE VIEW report_stock_forecast AS (SELECT
- max(id) as id,
+ MIN(id) as id,
product_id as product_id,
date as date,
sum(product_qty) AS quantity,
- sum(sum(product_qty)) OVER(PARTITION BY product_id ORDER BY date ) AS cumulative_quantity
+ sum(sum(product_qty)) OVER (PARTITION BY product_id ORDER BY date) AS cumulative_quantity
FROM
(SELECT
- max(id) as id,
+ MIN(id) as id,
MAIN.product_id as product_id,
SUB.date as date,
CASE WHEN MAIN.date = SUB.date THEN sum(MAIN.product_qty) ELSE 0 END as product_qty
FROM
(SELECT
- max(sq.id) as id,
+ MIN(sq.id) as id,
sq.product_id,
- CASE WHEN sm.date < CURRENT_DATE
- THEN to_date(to_char(sm.date, 'YYYY/MM/DD'), 'YYYY/MM/DD')
- ELSE to_date(to_char(CURRENT_DATE, 'YYYY/MM/DD'), 'YYYY/MM/DD')
- END AS date,
+ date_trunc('week', to_date(to_char(CURRENT_DATE, 'YYYY/MM/DD'), 'YYYY/MM/DD')) as date,
SUM(sq.qty) AS product_qty
FROM
- (SELECT min(date_expected) AS date FROM stock_move AS sm
- LEFT JOIN
- stock_location source_location ON sm.location_id = source_location.id
- LEFT JOIN
- stock_location dest_location ON sm.location_dest_id = dest_location.id
- WHERE
- sm.state IN ('confirmed','assigned','waiting') AND
- (dest_location.usage = 'internal' AND source_location.usage != 'internal')
- or (source_location.usage = 'internal' AND dest_location.usage != 'internal')) AS sm,
stock_quant as sq
LEFT JOIN
product_product ON product_product.id = sq.product_id
@@ -57,9 +45,12 @@ class report_stock_forecast(models.Model):
GROUP BY date, sq.product_id
UNION ALL
SELECT
- max(sm.id) as id,
+ MIN(-sm.id) as id,
sm.product_id,
- to_date(to_char(sm.date_expected, 'YYYY/MM/DD'), 'YYYY/MM/DD') AS date,
+ CASE WHEN sm.date_expected > CURRENT_DATE
+ THEN date_trunc('week', to_date(to_char(sm.date_expected, 'YYYY/MM/DD'), 'YYYY/MM/DD'))
+ ELSE date_trunc('week', to_date(to_char(CURRENT_DATE, 'YYYY/MM/DD'), 'YYYY/MM/DD')) END
+ AS date,
SUM(sm.product_qty) AS product_qty
FROM
stock_move as sm
@@ -75,9 +66,12 @@ class report_stock_forecast(models.Model):
GROUP BY sm.date_expected,sm.product_id
UNION ALL
SELECT
- max(sm.id) as id,
+ MIN(-sm.id) as id,
sm.product_id,
- to_date(to_char(sm.date_expected, 'YYYY/MM/DD'), 'YYYY/MM/DD') AS date,
+ CASE WHEN sm.date_expected > CURRENT_DATE
+ THEN date_trunc('week', to_date(to_char(sm.date_expected, 'YYYY/MM/DD'), 'YYYY/MM/DD'))
+ ELSE date_trunc('week', to_date(to_char(CURRENT_DATE, 'YYYY/MM/DD'), 'YYYY/MM/DD')) END
+ AS date,
SUM(-(sm.product_qty)) AS product_qty
FROM
stock_move as sm
@@ -96,18 +90,18 @@ class report_stock_forecast(models.Model):
(SELECT DISTINCT date
FROM
(
- SELECT CURRENT_DATE AS DATE
+ SELECT date_trunc('week', CURRENT_DATE) AS DATE
UNION ALL
- SELECT to_date(to_char(sm.date_expected, 'YYYY/MM/DD'), 'YYYY/MM/DD') AS date
+ SELECT date_trunc('week', to_date(to_char(sm.date_expected, 'YYYY/MM/DD'), 'YYYY/MM/DD')) AS date
FROM stock_move sm
LEFT JOIN
stock_location source_location ON sm.location_id = source_location.id
LEFT JOIN
stock_location dest_location ON sm.location_dest_id = dest_location.id
WHERE
- sm.state IN ('confirmed','assigned','waiting') and
- (dest_location.usage = 'internal' AND source_location.usage != 'internal')
- or (source_location.usage = 'internal' AND dest_location.usage != 'internal')) AS DATE_SEARCH)
+ sm.state IN ('confirmed','assigned','waiting') and sm.date_expected > CURRENT_DATE and
+ ((dest_location.usage = 'internal' AND source_location.usage != 'internal')
+ or (source_location.usage = 'internal' AND dest_location.usage != 'internal'))) AS DATE_SEARCH)
SUB ON (SUB.date IS NOT NULL)
GROUP BY MAIN.product_id,SUB.date, MAIN.date
) AS FINAL
diff --git a/addons/stock/stock.py b/addons/stock/stock.py
index dad23b73223..1409ce1e907 100644
--- a/addons/stock/stock.py
+++ b/addons/stock/stock.py
@@ -3711,9 +3711,13 @@ class stock_warehouse(osv.osv):
self._handle_renaming(cr, uid, warehouse, name, vals.get('code', warehouse.code), context=context_with_inactive)
if warehouse.in_type_id:
seq_obj.write(cr, uid, warehouse.in_type_id.sequence_id.id, {'name': name + _(' Sequence in'), 'prefix': vals.get('code', warehouse.code) + '\IN\\'}, context=context)
+ if warehouse.out_type_id:
seq_obj.write(cr, uid, warehouse.out_type_id.sequence_id.id, {'name': name + _(' Sequence out'), 'prefix': vals.get('code', warehouse.code) + '\OUT\\'}, context=context)
+ if warehouse.pack_type_id:
seq_obj.write(cr, uid, warehouse.pack_type_id.sequence_id.id, {'name': name + _(' Sequence packing'), 'prefix': vals.get('code', warehouse.code) + '\PACK\\'}, context=context)
+ if warehouse.pick_type_id:
seq_obj.write(cr, uid, warehouse.pick_type_id.sequence_id.id, {'name': name + _(' Sequence picking'), 'prefix': vals.get('code', warehouse.code) + '\PICK\\'}, context=context)
+ if warehouse.int_type_id:
seq_obj.write(cr, uid, warehouse.int_type_id.sequence_id.id, {'name': name + _(' Sequence internal'), 'prefix': vals.get('code', warehouse.code) + '\INT\\'}, context=context)
if vals.get('resupply_wh_ids') and not vals.get('resupply_route_ids'):
for cmd in vals.get('resupply_wh_ids'):
diff --git a/addons/stock_dropshipping/stock_dropshipping.py b/addons/stock_dropshipping/stock_dropshipping.py
index d7f2fc54137..96a22e5dfae 100644
--- a/addons/stock_dropshipping/stock_dropshipping.py
+++ b/addons/stock_dropshipping/stock_dropshipping.py
@@ -43,3 +43,12 @@ class purchase_order(models.Model):
if not self.env.context.get('no_invoice_policy_check'):
self._check_invoice_policy()
super(purchase_order, self).wkf_confirm_order()
+
+class procurement_order(models.Model):
+ _inherit = 'procurement.order'
+
+ @api.model
+ def update_origin_po(self, po, proc):
+ super(procurement_order, self).update_origin_po(po, proc)
+ if proc.sale_line_id and not (proc.origin in po.origin):
+ po.sudo().write({'origin': po.origin+', '+proc.origin})
diff --git a/addons/web/static/src/js/views/list_view.js b/addons/web/static/src/js/views/list_view.js
index 63940726fca..34a483f8aa9 100644
--- a/addons/web/static/src/js/views/list_view.js
+++ b/addons/web/static/src/js/views/list_view.js
@@ -128,6 +128,7 @@ var ListView = View.extend( /** @lends instance.web.ListView# */ {
// the view's number of records per page (|| section)
this._limit = (this.options.limit ||
this.defaults.limit ||
+ parseInt(this.fields_view.arch.attrs.limit, 10) ||
(this.getParent().action || {}).limit ||
80);
},
diff --git a/addons/web/static/src/js/views/search_view.js b/addons/web/static/src/js/views/search_view.js
index cd0735d24ed..dba0f8045fa 100644
--- a/addons/web/static/src/js/views/search_view.js
+++ b/addons/web/static/src/js/views/search_view.js
@@ -423,7 +423,7 @@ var SearchView = Widget.extend(/** @lends instance.web.SearchView# */{
if (this.$buttons) {
var fields_def = new Model(this.dataset.model).call('fields_get', {
- context: this.dataset.context
+ context: this.dataset.get_context()
});
this.groupby_menu = new GroupByMenu(this, this.groupbys, fields_def);
diff --git a/addons/web_editor/static/lib/summernote/src/js/editing/History.js b/addons/web_editor/static/lib/summernote/src/js/editing/History.js
index 89834d52cb1..dc301bf957b 100644
--- a/addons/web_editor/static/lib/summernote/src/js/editing/History.js
+++ b/addons/web_editor/static/lib/summernote/src/js/editing/History.js
@@ -9,7 +9,7 @@ define(['summernote/core/range', 'summernote/core/dom'], function (range, dom) {
var makeSnapshot = function () {
var rng = range.create();
- var emptyBookmark = {s: {path: [0], offset: 0}, e: {path: [0], offset: 0}};
+ var emptyBookmark = {s: {path: [], offset: 0}, e: {path: [], offset: 0}};
return {
contents: $editable.html(),
diff --git a/addons/web_editor/static/src/js/editor.js b/addons/web_editor/static/src/js/editor.js
index f9255716697..4480101bf6a 100644
--- a/addons/web_editor/static/src/js/editor.js
+++ b/addons/web_editor/static/src/js/editor.js
@@ -144,6 +144,8 @@ editor.Class = Widget.extend({
d.resolve();
}).on('hidden.bs.modal', function () {
d.reject();
+ }).on('keydown.dismiss.bs.modal', function (event) {
+ event.stopImmediatePropagation();
});
d.always(function () {
$dialog.remove();
diff --git a/addons/web_editor/static/src/js/snippets.editor.js b/addons/web_editor/static/src/js/snippets.editor.js
index cc380833074..3de9b71d5f8 100644
--- a/addons/web_editor/static/src/js/snippets.editor.js
+++ b/addons/web_editor/static/src/js/snippets.editor.js
@@ -531,7 +531,8 @@ var BuildingBlock = Widget.extend({
this.snippets.push($snippet.get(0));
}
this.$active_snipped_id = $snippet;
- this.create_overlay(this.$active_snipped_id);
+ this.create_snippet_editor(this.$active_snipped_id);
+ this.cover_target($snippet.data('overlay'), $snippet);
this.snippet_focus($snippet);
}
this.$snippet.trigger('snippet-activated', $snippet);
@@ -539,13 +540,11 @@ var BuildingBlock = Widget.extend({
$snippet.trigger('snippet-activated', $snippet);
}
},
- create_overlay: function ($snippet) {
+ create_snippet_editor: function ($snippet) {
if (typeof $snippet.data("snippet-editor") === 'undefined') {
- var $targets = this.activate_overlay_zones($snippet);
- if (!$targets.length) return;
+ if (!this.activate_overlay_zones($snippet).length) return;
$snippet.data("snippet-editor", new Editor(this, $snippet));
}
- this.cover_target($snippet.data('overlay'), $snippet);
},
// activate drag and drop for the snippets in the snippet toolbar
@@ -657,22 +656,12 @@ var BuildingBlock = Widget.extend({
animation.start(true, $target);
- // drop_and_build_snippet
- self.create_overlay($target);
- if ($target.data("snippet-editor")) {
- $target.data("snippet-editor").drop_and_build_snippet();
- }
- for (var k in self.templateOptions) {
- self.templateOptions[k].selector.all($target).each(function () {
- var $snippet = $(this);
- self.create_overlay($snippet);
- if ($snippet.data("snippet-editor")) {
- $snippet.data("snippet-editor").drop_and_build_snippet();
- }
- });
- }
+ self.call_for_all_snippets($target, function (editor, $snippet) {
+ editor.drop_and_build_snippet();
+ });
+ self.create_snippet_editor($target);
+ self.cover_target($target.data('overlay'), $target);
$target.closest(".o_editable").trigger("content_changed");
- // end
self.make_active($target);
},0);
@@ -683,6 +672,20 @@ var BuildingBlock = Widget.extend({
});
},
+ // call a method on a snippet and all his children
+ call_for_all_snippets: function ($snippet, callback) {
+ var self = this;
+ $snippet.add(globalSelector.all($snippet)).each(function () {
+ var $snippet = $(this);
+ setTimeout(function () {
+ self.create_snippet_editor($snippet);
+ if ($snippet.data("snippet-editor")) {
+ callback.call(self, $snippet.data("snippet-editor"), $snippet);
+ }
+ });
+ });
+ },
+
// return the original snippet in the editor bar from a snippet id (string)
get_snippet_from_id: function(id){
return $('.oe_snippet').filter(function(){
@@ -845,14 +848,12 @@ var BuildingBlock = Widget.extend({
var timer;
$target.closest('.o_editable').on("content_changed", function (event) {
- if ($target.data('overlay') && $target.data('overlay').hasClass("oe_active")) {
- clearTimeout(timer);
- timer = setTimeout(function () {
- if ($target.data('overlay')) {
- self.cover_target($target.data('overlay'), $target);
- }
- },50);
- }
+ clearTimeout(timer);
+ timer = setTimeout(function () {
+ if ($target.data('overlay') && $target.data('overlay').hasClass("oe_active")) {
+ self.cover_target($target.data('overlay'), $target);
+ }
+ },50);
});
var resize = function () {
@@ -985,7 +986,9 @@ var Editor = Class.extend({
self.buildingBlock.editor_busy = false;
self.get_parent_block();
- setTimeout(function () {self.buildingBlock.create_overlay(self.$target);},0);
+ setTimeout(function () {
+ self.BuildingBlock.cover_target(self.$target.data('overlay'), self.$target);
+ },0);
},
load_style_options: function () {
@@ -1022,7 +1025,10 @@ var Editor = Class.extend({
get_parent_block: function () {
var self = this;
var $button = this.$overlay.find('.oe_snippet_parent');
- var $parent = globalSelector.closest(this.$target.parent());
+ var $parent = this.$target.parents().filter(function () { return $(this).data("snippet-editor"); });
+ if (!$parent.length) {
+ $parent = globalSelector.closest(this.$target.parent());
+ }
if ($parent.length) {
$button.removeClass("hidden");
$button.off("click").on('click', function (event) {
@@ -1056,12 +1062,13 @@ var Editor = Class.extend({
var $clone = this.$target.clone(false);
this.buildingBlock.parent.rte.historyRecordUndo(this.$target);
-
+
this.$target.after($clone);
- for (var i in this.styles){
- this.styles[i].on_clone($clone);
- }
- this.buildingBlock.create_overlay(this.$target);
+ this.BuildingBlock.call_for_all_snippets($clone, function (editor, $snippet) {
+ for (var i in editor.styles){
+ editor.styles[i].on_clone($snippet);
+ }
+ });
return false;
},
@@ -1072,9 +1079,11 @@ var Editor = Class.extend({
this.buildingBlock.parent.rte.historyRecordUndo(this.$target);
var index = _.indexOf(this.buildingBlock.snippets, this.$target.get(0));
- for (var i in this.styles){
- this.styles[i].on_remove();
- }
+ this.BuildingBlock.call_for_all_snippets(this.$target, function (editor, $snippet) {
+ for (var i in editor.styles){
+ editor.styles[i].on_remove();
+ }
+ });
delete this.buildingBlock.snippets[index];
var $editable = this.$target.closest(".o_editable");
diff --git a/addons/web_editor/static/src/js/snippets.options.js b/addons/web_editor/static/src/js/snippets.options.js
index 4dce2e358ed..df4ec303894 100644
--- a/addons/web_editor/static/src/js/snippets.options.js
+++ b/addons/web_editor/static/src/js/snippets.options.js
@@ -319,20 +319,20 @@ var colorpicker = Option.extend({
var background = Option.extend({
start: function ($change_target) {
- this.$bg = $change_target || this.$target;
+ this.$target = $change_target || this.$target;
this._super();
- var src = this.$bg.css("background-image").replace(/url\(['"]*|['"]*\)|^none$/g, "");
- if (this.$bg.hasClass('oe_custom_bg')) {
+ var src = this.$target.css("background-image").replace(/url\(['"]*|['"]*\)|^none$/g, "");
+ if (this.$target.hasClass('oe_custom_bg')) {
this.$el.find('li[data-choose_image]').data("background", src).attr("data-background", src);
}
},
background: function(type, value, $li) {
if (value && value.length) {
- this.$bg.attr("style", 'background-image: url(' + value + '); ' + (this.$bg.attr("style") || '').replace(/background-image:[^;]+/, '') );
- this.$bg.addClass("oe_img_bg");
+ this.$target.attr("style", 'background-image: url(' + value + '); ' + (this.$target.attr("style") || '').replace(/background-image:[^;]+/, '') );
+ this.$target.addClass("oe_img_bg");
} else {
- this.$bg.css("background-image", "");
- this.$bg.removeClass("oe_img_bg").removeClass("oe_custom_bg");
+ this.$target.css("background-image", "");
+ this.$target.removeClass("oe_img_bg").removeClass("oe_custom_bg");
}
},
select_class : function(type, value, $li) {
@@ -345,7 +345,7 @@ var background = Option.extend({
var self = this;
var $image = $('<img class="hidden"/>');
$image.attr("src", value);
- $image.appendTo(self.$bg);
+ $image.appendTo(self.$target);
var _editor = new widget.MediaDialog(null, $image[0]);
_editor.appendTo(document.body);
@@ -356,8 +356,8 @@ var background = Option.extend({
$image.remove();
self.$el.find('li[data-choose_image]').data("background", value).attr("data-background", value);
self.background(type, value,$li);
- self.$bg.addClass('oe_custom_bg');
- self.$bg.trigger("snippet-option-change", [self]);
+ self.$target.addClass('oe_custom_bg');
+ self.$target.trigger("snippet-option-change", [self]);
self.set_active();
});
_editor.on('cancel', self, function () {
@@ -366,9 +366,13 @@ var background = Option.extend({
},
set_active: function () {
var self = this;
- var src = this.$bg.css("background-image").replace(/url\(['"]*|['"]*\)|^none$/g, "");
+ var src = this.$target.css("background-image").replace(/url\(['"]*|['"]*\)|^none$/g, "");
this._super();
+ if (this.$target.hasClass('oe_custom_bg')) {
+ this.$el.find('li[data-choose_image]').data("background", src).attr("data-background", src);
+ }
+
this.$el.find('li[data-background]:not([data-background=""])')
.removeClass("active")
.each(function () {
diff --git a/addons/web_editor/static/src/js/summernote.js b/addons/web_editor/static/src/js/summernote.js
index 46b21aeec88..235bd6c3500 100644
--- a/addons/web_editor/static/src/js/summernote.js
+++ b/addons/web_editor/static/src/js/summernote.js
@@ -26,7 +26,7 @@ dom.hasContentAfter = function (node) {
var next;
while (node.nextSibling) {
next = node.nextSibling;
- if (next.tagName || next.textContent.match(/\S|\u00A0/) || dom.isBR(next)) return next;
+ if (next.tagName || dom.isVisibleText(next) || dom.isBR(next)) return next;
node = next;
}
};
@@ -34,7 +34,7 @@ dom.hasContentBefore = function (node) {
var prev;
while (node.previousSibling) {
prev = node.previousSibling;
- if (prev.tagName || prev.textContent.match(/\S|\u00A0/) || dom.isBR(prev)) return prev;
+ if (prev.tagName || dom.isVisibleText(prev) || dom.isBR(prev)) return prev;
node = prev;
}
};
@@ -138,7 +138,7 @@ dom.mergeFilter = function (prev, cur, parent) {
if (prev && prev.tagName === "P" && dom.isText(cur)) {
return true;
}
- if (prev && dom.isText(cur) && !cur.textContent.match(/\S|\u00A0/) && (dom.isText(prev) || prev.textContent.match(/\S|\u00A0/))) {
+ if (prev && dom.isText(cur) && !dom.isVisibleText(cur) && (dom.isText(prev) || dom.isVisibleText(prev))) {
return true;
}
if (prev && !dom.isBR(prev) && dom.isEqual(prev, cur) &&
@@ -382,7 +382,7 @@ dom.removeSpace = function (node, begin, so, end, eo) {
if (cur === end) add = false;
// remove begin empty text node
- if (node.childNodes.length > 1 && dom.isText(cur) && !cur.textContent.match(/\S|\u00A0/)) {
+ if (node.childNodes.length > 1 && dom.isText(cur) && !dom.isVisibleText(cur)) {
removed = true;
if (cur === begin) {
so = 0;
@@ -579,7 +579,7 @@ dom.removeBetween = function (sc, so, ec, eo, towrite) {
}
eo = so;
- if(!dom.isBR(sc) && !sc.textContent.match(/\S|\u00A0/) && !dom.isText(dom.hasContentBefore(sc)) && !dom.isText(dom.hasContentAfter(sc))) {
+ if(!dom.isBR(sc) && !dom.isVisibleText(sc) && !dom.isText(dom.hasContentBefore(sc)) && !dom.isText(dom.hasContentAfter(sc))) {
ancestor = dom.node(sc);
var text = document.createTextNode('\u00A0');
$(sc).before(text);
@@ -699,6 +699,9 @@ dom.isContentEditable = function (node) {
return $(node).closest('[contenteditable]').is('[contenteditable="true"]');
};
+dom.isPre = function (node) {
+ return node.tagName === "PRE";
+};
dom.isFont = function (node) {
var nodeName = node && node.nodeName.toUpperCase();
return node && (nodeName === "FONT" ||
@@ -1025,6 +1028,8 @@ $.summernote.pluginEvents.enter = function (event, editor, layoutInfo) {
}
var node = dom.node(r.sc);
+ var exist = r.sc.childNodes[r.so] || r.sc;
+ exist = dom.isVisibleText(exist) || dom.isBR(exist) ? exist : dom.hasContentAfter(exist) || (dom.hasContentBefore(exist) || exist);
var last = node;
while (node && dom.isSplitable(node) && !dom.isList(node)) {
last = node;
@@ -1042,7 +1047,7 @@ $.summernote.pluginEvents.enter = function (event, editor, layoutInfo) {
} while (node && dom.isBR(node));
// create an other br because the user can't see the new line with only br in a block
- if (!node) {
+ if (!node && (!br.nextElementSibling || !dom.isBR(br.nextElementSibling))) {
$(br).before($("<br/>")[0]);
}
node = br.nextSibling || br;
@@ -1051,7 +1056,11 @@ $.summernote.pluginEvents.enter = function (event, editor, layoutInfo) {
node = br;
} else if (!r.so && r.isOnList() && !r.sc.textContent.length && !dom.ancestor(r.sc, dom.isLi).nextElementSibling) {
// double enter on the end of a list = new line out of the list
- node = $('<p></p>').append(br).insertAfter(dom.ancestor(r.sc, dom.isList))[0];
+ $('<p></p>').append(br).insertAfter(dom.ancestor(r.sc, dom.isList));
+ node = br;
+ } else if (dom.isBR(exist) && $(r.sc).closest('blockquote, pre').length && !dom.hasContentAfter($(exist.parentNode).closest('blockquote *, pre *').length ? exist.parentNode : exist)) {
+ // double enter on the end of a blockquote & pre = new line out of the list
+ $('<p></p>').append(br).insertAfter($(r.sc).closest('blockquote, pre'));
node = br;
} else if (last === r.sc) {
if (dom.isBR(last)) {
@@ -1071,7 +1080,7 @@ $.summernote.pluginEvents.enter = function (event, editor, layoutInfo) {
$(cur).html(br);
}
}
- if (!node.textContent.match(/\S|\u00A0/)) {
+ if (!dom.isVisibleText(node)) {
node = dom.firstChild(node);
$(dom.node( dom.isBR(node) ? node.parentNode : node )).html(br);
node = br;
@@ -1105,7 +1114,7 @@ $.summernote.pluginEvents.visible = function (event, editor, layoutInfo) {
while (node.parentNode) {
if (dom.isForbiddenNode(node)) {
var text = node.previousSibling;
- if (text && dom.isText(text) && text.textContent.match(/\S|\u00A0/)) {
+ if (text && dom.isText(text) && dom.isVisibleText(text)) {
range.create(text, text.textContent.length, text, text.textContent.length).select();
} else {
text = node.parentNode.insertBefore(document.createTextNode( "." ), node);
@@ -1715,7 +1724,7 @@ $.summernote.pluginEvents.formatBlock = function (event, editor, layoutInfo, sTa
// fix by odoo because if you select a style in a li with no p tag all the ul is wrapped by the style tag
var nodes = dom.listBetween(r.sc, r.ec);
for (var i=0; i<nodes.length; i++) {
- if (dom.isBR(nodes[i]) || (dom.isText(nodes[i]) && nodes[i].textContent.match(/\S|\u00A0/)) || dom.isB(nodes[i]) || dom.isU(nodes[i]) || dom.isS(nodes[i]) || dom.isI(nodes[i]) || dom.isFont(nodes[i])) {
+ if (dom.isBR(nodes[i]) || (dom.isText(nodes[i]) && dom.isVisibleText(nodes[i])) || dom.isB(nodes[i]) || dom.isU(nodes[i]) || dom.isS(nodes[i]) || dom.isI(nodes[i]) || dom.isFont(nodes[i])) {
var ancestor = dom.ancestor(nodes[i], isFormatNode);
if (!ancestor) {
dom.wrap(nodes[i], sTagName);
diff --git a/addons/web_editor/static/src/js/widgets.js b/addons/web_editor/static/src/js/widgets.js
index acd8c859535..5e852a1c5ef 100644
--- a/addons/web_editor/static/src/js/widgets.js
+++ b/addons/web_editor/static/src/js/widgets.js
@@ -16,6 +16,7 @@ var dom = $.summernote.core.dom;
var Dialog = Widget.extend({
events: {
'hidden.bs.modal': 'destroy',
+ 'keydown.dismiss.bs.modal': 'stop_escape',
'click button.save': 'save',
'click button[data-dismiss="modal"]': 'cancel',
},
@@ -38,6 +39,11 @@ var Dialog = Widget.extend({
close: function () {
this.$el.modal('hide');
},
+ stop_escape: function(event) {
+ if($(".modal.in").length>0 && event.which == 27){
+ event.stopPropagation();
+ }
+ }
});
/**
@@ -251,6 +257,7 @@ var ImageDialog = Widget.extend({
//'change select.image-style': 'preview_image',
'click .existing-attachments [data-src]': 'select_existing',
'click .existing-attachment-remove': 'try_remove',
+ 'keydown.dismiss.bs.modal': function(){},
}),
init: function (parent, media, options) {
this._super();
@@ -339,7 +346,7 @@ var ImageDialog = Widget.extend({
return this.media;
},
clear: function () {
- this.media.className = this.media.className.replace(/(^|\s)(img(\s|$)|img-[^\s]*)/g, ' ');
+ this.media.className = this.media.className.replace(/(^|\s+)(img(\s|$)|img-(?!circle|rounded|thumbnail)[^\s]*)/g, ' ');
},
cancel: function () {
this.trigger('cancel');
@@ -609,6 +616,7 @@ var fontIconsDialog = Widget.extend({
$(".font-icons-icon").removeClass("font-icons-selected");
$(event.target).addClass("font-icons-selected");
},
+ 'keydown.dismiss.bs.modal': function(){},
}),
// extract list of font (like awsome) from the cheatsheet.
@@ -662,12 +670,14 @@ var fontIconsDialog = Widget.extend({
var icons = this.icons;
var style = this.media.attributes.style ? this.media.attributes.style.value : '';
var classes = (this.media.className||"").split(/\s+/);
+ var custom_classes = /^fa(-[1-5]x|spin|rotate-(9|18|27)0|flip-(horizont|vertic)al|fw|border)?$/;
var non_fa_classes = _.reject(classes, function (cls) {
- return self.getFont(cls);
+ return self.getFont(cls) || custom_classes.test(cls);
});
var final_classes = non_fa_classes.concat(this.get_fa_classes());
if (this.media.tagName !== "SPAN") {
var media = document.createElement('span');
+ $(media).data($(this.media).data());
$(this.media).replaceWith(media);
this.media = media;
style = style.replace(/\s*width:[^;]+/, '');
@@ -828,7 +838,8 @@ var VideoDialog = Widget.extend({
'change input#urlvideo': 'change_input',
'keyup input#urlvideo': 'change_input',
'change input#embedvideo': 'change_input',
- 'keyup input#embedvideo': 'change_input'
+ 'keyup input#embedvideo': 'change_input',
+ 'keydown.dismiss.bs.modal': function(){},
}),
init: function (parent, media) {
this._super();
@@ -842,7 +853,6 @@ var VideoDialog = Widget.extend({
if ($media.hasClass("media_iframe_video")) {
var src = $media.data('src');
this.$("input#urlvideo").val(src);
- this.$("#autoplay").attr("checked", src.indexOf('autoplay=1') != -1);
this.get_video();
} else {
this.add_class = "pull-left";
diff --git a/addons/website/static/src/js/website.snippets.editor.js b/addons/website/static/src/js/website.snippets.editor.js
index 9cc40247b89..61a7622ecbf 100644
--- a/addons/website/static/src/js/website.snippets.editor.js
+++ b/addons/website/static/src/js/website.snippets.editor.js
@@ -81,7 +81,7 @@ options.registry.slider = options.Class.extend({
this.$indicators.append('<li data-target="#' + this.id + '" data-slide-to="' + cycle + '"></li>');
// clone the best candidate from template to use new features
- var $snippets = this.BuildingBlock.$snippets;
+ var $snippets = this.buildingBlock.$snippets;
//since saas-6, all snippets must start by s_
var selection = this.$target.closest('[class*="s_"');
if (_.isUndefined(selection)) {
@@ -174,7 +174,7 @@ options.registry.carousel = options.registry.slider.extend({
};
this.$target.on('slid.bs.carousel', function () {
if(self.editor && self.editor.styles.background) {
- self.editor.styles.background.$bg = self.$target.find(".item.active");
+ self.editor.styles.background.$target = self.$target.find(".item.active");
self.editor.styles.background.set_active();
}
self.$target.carousel("pause");
@@ -264,9 +264,13 @@ options.registry.marginAndResize = options.Class.extend({
} else {
var xy = event['page'+XY];
var current = resize[2] || 0;
+ var margin_dir = {s:'bottom', n: 'top', w: 'left', e: 'right'}[compass];
+ var real_margin = parseInt(self.$target.css('margin-'+margin_dir));
_.each(resize[0], function (val, key) {
if (self.$target.hasClass(val)) {
current = key;
+ } else if (resize[1][key] === real_margin) {
+ current = key;
}
});
var begin = current;
@@ -362,12 +366,12 @@ options.registry.marginAndResize = options.Class.extend({
if (offset === 0) overlay_class+= " block-w-left";
var mb = _class.match(/mb([0-9-]+)/i);
- mb = mb ? +mb[1] : 0;
+ mb = mb ? +mb[1] : parseInt(this.$target.css('margin-bottom'));
if (mb >= 128) overlay_class+= " block-s-bottom";
else if (!mb) overlay_class+= " block-s-top";
var mt = _class.match(/mt([0-9-]+)/i);
- mt = mt ? +mt[1] : 0;
+ mt = mt ? +mt[1] : parseInt(this.$target.css('margin-top'));
if (mt >= 128) overlay_class+= " block-n-top";
else if (!mt) overlay_class+= " block-n-bottom";
diff --git a/addons/website/static/src/js/website.snippets.gallery.js b/addons/website/static/src/js/website.snippets.gallery.js
index 4eb09a4837b..fd6005456e2 100644
--- a/addons/website/static/src/js/website.snippets.gallery.js
+++ b/addons/website/static/src/js/website.snippets.gallery.js
@@ -38,13 +38,9 @@ options.registry.gallery = options.Class.extend({
this._temp_col = this.$el.find("data-columns").data("columns");
},
drop_and_build_snippet: function() {
- var uuid = 0;
- $(".carousel").each(function () {
- var id = parseInt(($(this).attr('id') || '0').replace(/[^0-9]/, ''));
- if (id > uuid) uuid = id;
- });
- this.$target.find('.carousel').attr('id', 'slideshow_'+ (uuid+1));
- this.$target.find('[data-target]').attr('data-target', '#slideshow_'+ (uuid+1));
+ var uuid = new Date().getTime();
+ this.$target.find('.carousel').attr('id', 'slideshow_' + uuid);
+ this.$target.find('[data-target]').attr('data-target', '#slideshow_' + uuid);
},
styling : function(type, value) {
var classes = this.$el.find('li[data-styling]').map(function () {
@@ -194,18 +190,13 @@ options.registry.gallery = options.Class.extend({
var self = this,
$imgs = $(this.get_imgs()),
- urls = $imgs.map(function() { return $(this).attr("src"); } ).get(),
- uuid = 0;
- $(".carousel").each(function () {
- var id = parseInt(($(this).attr('id') || '0').replace(/[^0-9]/, ''));
- if (id > uuid) uuid = id;
- });
+ urls = $imgs.map(function() { return $(this).attr("src"); } ).get();
var params = {
srcs : urls,
- index: 1,
+ index: 0,
title: "",
interval : this.$target.data("interval") || false,
- id: "slideshow_" + (uuid+1)
+ id: "slideshow_" + new Date().getTime()
},
$slideshow = $(qweb.render('website.gallery.slideshow', params));
this.replace($slideshow);
diff --git a/addons/website/static/src/js/website.theme.js b/addons/website/static/src/js/website.theme.js
index f0d45c169ac..7b10fd7ea13 100644
--- a/addons/website/static/src/js/website.theme.js
+++ b/addons/website/static/src/js/website.theme.js
@@ -29,6 +29,12 @@ var Theme = Widget.extend({
template: 'website.theme_customize',
events: {
'change input[data-xmlid],input[data-enable],input[data-disable]': 'change_selection',
+ 'click label:has(input[data-xmlid],input[data-enable],input[data-disable])': function (event) {
+ var self = this;
+ this.time_select = _.defer(function () {
+ self.on_select($(event.target).find('input'));
+ });
+ },
'click .close': 'close',
'click': 'click',
},
@@ -39,7 +45,7 @@ var Theme = Widget.extend({
this.flag = false;
this.$el.addClass("theme_customize_modal");
this.active_select_tags();
- this.$inputs = $("input[data-xmlid],input[data-enable],input[data-disable]");
+ this.$inputs = this.$("input[data-xmlid],input[data-enable],input[data-disable]");
setTimeout(function () {self.$el.addClass('in');}, 0);
this.keydown_escape = function (event) {
if (event.keyCode === 27) {
@@ -92,10 +98,10 @@ var Theme = Widget.extend({
self.$inputs.filter('[data-xmlid=""]').prop("checked", true).change();
self.$inputs.filter('[data-xmlid]:not([data-xmlid=""])').each(function () {
if (!_.difference(self.get_xml_ids($(this)), data[1]).length) {
- $(this).prop("checked", false).change();
+ $(this).prop("checked", false).trigger("change", true);
}
if (!_.difference(self.get_xml_ids($(this)), data[0]).length) {
- $(this).prop("checked", true).change();
+ $(this).prop("checked", true).trigger("change", true);
}
});
}).fail(function (d, error) {
@@ -174,9 +180,8 @@ var Theme = Widget.extend({
return $.Deferred();
}
},
- enable_disable: function (data, enable) {
- if (!data) return;
- this.$('#'+data.split(",").join(", #")).each(function () {
+ enable_disable: function ($inputs, enable) {
+ $inputs.each(function () {
var check = $(this).prop("checked");
var $label = $(this).closest("label");
$(this).prop("checked", enable);
@@ -187,21 +192,31 @@ var Theme = Widget.extend({
}
});
},
- change_selection: function (event) {
+ change_selection: function (event, init_mode) {
var self = this;
- if (this.$el.hasClass("loading")) return;
+ clearTimeout(this.time_select);
+ if (this.$el.hasClass("loading")) return; // prevent to change selection when css is loading
+
var $option = $(event.target),
+ $options = $option,
checked = $option.prop("checked");
if (checked) {
- this.enable_disable($option.data('enable'), true);
- this.enable_disable($option.data('disable'), false);
+ if($option.data('enable')) {
+ var $inputs = this.get_inputs($option.data('enable'));
+ $options = $options.add($inputs.filter(':not(:checked)'));
+ this.enable_disable($inputs, true);
+ }
+ if($option.data('disable')) {
+ var $inputs = this.get_inputs($option.data('disable'));
+ $options = $options.add($inputs.filter(':checked'));
+ this.enable_disable($inputs, false);
+ }
$option.closest("label").addClass("checked");
} else {
$option.closest("label").removeClass("checked");
}
- $option.prop("checked", checked);
var $enable = this.$inputs.filter('[data-xmlid]:checked');
$enable.closest("label").addClass("checked");
@@ -236,14 +251,25 @@ var Theme = Widget.extend({
clearTimeout(this.timer);
if (this.flag) {
- this.timer = setTimeout(function () {
+ this.timer = _.defer(function () {
+ if (!init_mode) self.on_select($options);
self.update_style(self.get_xml_ids($enable), self.get_xml_ids($disable), self.reload);
self.reload = false;
- },0);
+ });
} else {
- this.timer = setTimeout(function () { self.reload = false; },0);
+ this.timer = _.defer(function () {
+ if (!init_mode) self.on_select($options);
+ self.reload = false;
+ });
}
},
+ /* Method call when the user change the selection or click on an input
+ * @values: all changed inputs
+ */
+ on_select: function ($inputs) {
+ clearTimeout(this.time_select);
+ console.log($inputs.get());
+ },
click: function (event) {
if (!$(event.target).closest("#theme_customize_modal > *").length) {
this.close();
diff --git a/addons/website_sale/models/product.py b/addons/website_sale/models/product.py
index 4c2e4244608..c4fe2c28e0a 100644
--- a/addons/website_sale/models/product.py
+++ b/addons/website_sale/models/product.py
@@ -161,7 +161,7 @@ class product_template(osv.Model):
class product_product(osv.Model):
_inherit = "product.product"
- # Wrapper for call_kw with inherits
+ # Wrappers for call_kw with inherits
def open_website_url(self, cr, uid, ids, context=None):
template_id = self.browse(cr, uid, ids, context=context).product_tmpl_id.id
return self.pool['product.template'].open_website_url(cr, uid, [template_id], context=context)
@@ -170,6 +170,10 @@ class product_product(osv.Model):
template_id = self.browse(cr, uid, ids, context=context).product_tmpl_id.id
return self.pool['product.template'].website_publish_button(cr, uid, [template_id], context=context)
+ def website_publish_button(self, cr, uid, ids, context=None):
+ template_id = self.browse(cr, uid, ids, context=context).product_tmpl_id.id
+ return self.pool['product.template'].website_publish_button(cr, uid, [template_id], context=context)
+
class product_attribute(osv.Model):
_inherit = "product.attribute"
_columns = {
diff --git a/addons/website_sale/static/src/css/website_sale.css b/addons/website_sale/static/src/css/website_sale.css
index cc569925f5e..9f696a920d1 100644
--- a/addons/website_sale/static/src/css/website_sale.css
+++ b/addons/website_sale/static/src/css/website_sale.css
@@ -29,6 +29,10 @@
}
/* ---- Default Styles ---- */
+
+.o_alternative_product {
+ margin: auto;
+}
.oe_product {
position: relative;
}
diff --git a/addons/website_sale/views/templates.xml b/addons/website_sale/views/templates.xml
index 804da7e61bf..5768de061f4 100644
--- a/addons/website_sale/views/templates.xml
+++ b/addons/website_sale/views/templates.xml
@@ -517,12 +517,12 @@
<h3>Suggested alternatives:</h3>
<div class='row mt16' style="">
<t t-foreach="product.alternative_product_ids" t-as="product">
- <div class='col-md-2 thumbnail' style='width: 170px; height:130px; float:left; display:inline; margin-right: 10px;'>
- <div class='mt16 text-center'>
- <span t-field="product.image_small" t-field-options='{"widget": "image", "class": "img-rounded shadow" }'/>
+ <div class='col-md-2 thumbnail' style='width: 170px; height:130px; float:left; display:inline; margin-right: 10px; overflow:hidden;'>
+ <div class='mt16 text-center' style="height: 100%;">
+ <div t-field="product.image_small" t-field-options='{"widget": "image", "class": "img-rounded shadow o_alternative_product" }'/>
<h5>
<a t-attf-href="/shop/product/#{ slug(product) }" style="display: block">
- <span t-field='product.name' style="display: block"/>
+ <span t-att-title='product.name' t-field='product.name' style="display: block;"/>
</a>
</h5>
</div>