From 4f9fc188d398f45280ddbf9c61ecfad1ea476e92 Mon Sep 17 00:00:00 2001
From: Jorge Pinna Puissant
Date: Tue, 29 Jan 2019 12:34:48 +0000
Subject: [PATCH 01/17] [FIX] stock: Warning in picking on product with serial
number
In stock.picking, in mode show detailed operation, add a product with
unique serial number tracking.
Before this commit, a warning about the qty is raised. This warning,
must be raised only if the qty is different from 1.
However this is not the case,
the warning is raised at each modification of the line.
This issue occurs since the rounding given to the float_compare is 0.0,
because self.move_id.product_id is not set.
Float_compare with a 0.0 rounding always return different, hence the bug.
Now, the warning is only raised when the qty is different from 1.
OPW-1932044
OPW-1931378
closes odoo/odoo#30651
closes odoo/odoo#30851
---
addons/stock/models/stock_move_line.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/addons/stock/models/stock_move_line.py b/addons/stock/models/stock_move_line.py
index 6fe34e6bc96..870de679a38 100644
--- a/addons/stock/models/stock_move_line.py
+++ b/addons/stock/models/stock_move_line.py
@@ -141,7 +141,7 @@ class StockMoveLine(models.Model):
"""
res = {}
if self.qty_done and self.product_id.tracking == 'serial':
- if float_compare(self.qty_done, 1.0, precision_rounding=self.move_id.product_id.uom_id.rounding) != 0:
+ if float_compare(self.qty_done, 1.0, precision_rounding=self.product_id.uom_id.rounding) != 0:
message = _('You can only process 1.0 %s for products with unique serial number.') % self.product_id.uom_id.name
res['warning'] = {'title': _('Warning'), 'message': message}
return res
From a21864c36cfc9a10108fc499a6b950bcd6dc5b3a Mon Sep 17 00:00:00 2001
From: Nans Lefebvre
Date: Mon, 4 Feb 2019 09:09:08 +0000
Subject: [PATCH 02/17] [FIX] purchase: fix mail templates
Activate multi-company, deactivate the common contact book.
Create a PO P with user U1 in company A. Switch to company B.
User U2 in company A tries to send P by email.
Rendering of the template fails, because it tries to access object.create_uid,
which breaks multi-company record rules.
The signature was not working because it used user_id, a non-existing field,
instead of create_uid.
opw 1930521
closes odoo/odoo#30868
---
addons/purchase/data/mail_template_data.xml | 15 ++++++++++-----
addons/purchase/i18n/purchase.pot | 11 ++++++++---
2 files changed, 18 insertions(+), 8 deletions(-)
diff --git a/addons/purchase/data/mail_template_data.xml b/addons/purchase/data/mail_template_data.xml
index ceb19ec9763..65b63e324f7 100644
--- a/addons/purchase/data/mail_template_data.xml
+++ b/addons/purchase/data/mail_template_data.xml
@@ -5,7 +5,7 @@
RFQ - Send by Email
- ${(object.create_uid.email and '"%s" <%s>' % (object.create_uid.name, object.create_uid.email) or '')|safe}
+ ${(object.sudo().create_uid.email and '"%s" <%s>' % (object.sudo().create_uid.name, object.sudo().create_uid.email) or '')|safe}
${object.company_id.name} Order (Ref ${object.name or 'n/a' })
${object.partner_id.id}
@@ -32,11 +32,11 @@ amounting in ${format_amount(object.amount_total, object.currency_id)}
from ${object.company_id.name}.
-Do not hesitate to contact us, further you have any question.
+Do not hesitate to contact us if you have any further question.
Best regards,
-% if object.user_id and object.user_id.signature:
- ${object.user_id.signature | safe}
+% if object.sudo().create_uid and object.sudo().create_uid.signature:
+ ${object.sudo().create_uid.signature | safe}
% endif
]]>
@@ -46,7 +46,7 @@ from ${object.company_id.name}.
Purchase Order - Send by Email
- ${(object.create_uid.email and '"%s" <%s>' % (object.create_uid.name, object.create_uid.email) or '')|safe}
+ ${(object.sudo().create_uid.email and '"%s" <%s>' % (object.sudo().create_uid.name, object.sudo().create_uid.email) or '')|safe}
${object.company_id.name} Order (Ref ${object.name or 'n/a' })
${object.partner_id.id}
@@ -74,6 +74,11 @@ from ${object.company_id.name}.
You can reply to this email if you have any questions.
Thank you,
+
+% if object.sudo().create_uid and object.sudo().create_uid.signature:
+ ${object.sudo().create_uid.signature | safe}
+% endif
+
]]>
diff --git a/addons/purchase/i18n/purchase.pot b/addons/purchase/i18n/purchase.pot
index ceea31343a4..c11326da530 100644
--- a/addons/purchase/i18n/purchase.pot
+++ b/addons/purchase/i18n/purchase.pot
@@ -36,11 +36,11 @@ msgid "\n"
"from ${object.company_id.name}.\n"
"\n"
"\n"
-"Do not hesitate to contact us, further you have any question.
\n"
+"Do not hesitate to contact us if you have any further question.
\n"
"Best regards,
\n"
"\n"
-"% if object.user_id and object.user_id.signature:\n"
-" ${object.user_id.signature | safe}\n"
+"% if object.sudo().create_uid and object.sudo().create_uid.signature:\n"
+" ${object.sudo().create_uid.signature | safe}\n"
"% endif\n"
"
\n"
""
@@ -68,6 +68,11 @@ msgid "\n"
"\n"
"You can reply to this email if you have any questions.
\n"
"Thank you,
\n"
+"\n"
+"% if object.sudo().create_uid and object.sudo().create_uid.signature:\n"
+" ${object.sudo().create_uid.signature | safe}\n"
+"% endif\n"
+"
\n"
""
msgstr ""
From d89f4d6ec26806389922351eb8e575754b3f60e0 Mon Sep 17 00:00:00 2001
From: "Atchuthan, Sodexis"
Date: Thu, 24 May 2018 10:22:28 +0000
Subject: [PATCH 03/17] [FIX] stock: set picking_type_id to readonly except in
draft state
Before this commit, the customer is allowed to change picking type after the
stock.picking record is moved from draft.
But it doesn't make the changes in the stock moves and operations as the
procurements are already created for initial demand.
To avoid confusing the user, it can now only be modified in draft state.
Authored by SodexisTeam
opw 1848252
opw-1934814
closes odoo/odoo#30865
---
addons/stock/models/stock_picking.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py
index 3e3e99c931e..c1f5f98ba09 100644
--- a/addons/stock/models/stock_picking.py
+++ b/addons/stock/models/stock_picking.py
@@ -241,7 +241,8 @@ class Picking(models.Model):
picking_type_id = fields.Many2one(
'stock.picking.type', 'Picking Type',
required=True,
- states={'done': [('readonly', True)], 'cancel': [('readonly', True)]})
+ readonly=True,
+ states={'draft': [('readonly', False)]})
picking_type_code = fields.Selection([
('incoming', 'Vendors'),
('outgoing', 'Customers'),
From c7c938996f783cbb187697b9f36c8359b2c4733f Mon Sep 17 00:00:00 2001
From: Nicolas Martinelli
Date: Wed, 6 Feb 2019 10:24:09 +0000
Subject: [PATCH 04/17] [FIX] account: analytic cost
- Set a cost of 12.34 for product P
- Create manually a new analytic entry
- Choose product P
- Set desired quantity
The analytic amount is set to 12.00.
This is because `move_id` is empty, therefore `currency_id` is empty as
well and `decimal_places` is zero
opw-1924184
closes odoo/odoo#30869
---
addons/account/models/account_analytic_line.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/addons/account/models/account_analytic_line.py b/addons/account/models/account_analytic_line.py
index 20b44c04dbb..5f001ad34dd 100644
--- a/addons/account/models/account_analytic_line.py
+++ b/addons/account/models/account_analytic_line.py
@@ -44,7 +44,7 @@ class AccountAnalyticLine(models.Model):
# Compute based on pricetype
amount_unit = self.product_id.price_compute('standard_price', uom=unit)[self.product_id.id]
amount = amount_unit * self.unit_amount or 0.0
- result = round(amount, self.currency_id.decimal_places) * -1
+ result = round(amount, self.currency_id.decimal_places if self.currency_id else 2) * -1
self.amount = result
self.general_account_id = account
self.product_uom_id = unit
From 845a6a9e08293a955127ec587397bbf7bec27116 Mon Sep 17 00:00:00 2001
From: Josse Colpaert
Date: Fri, 1 Feb 2019 17:33:50 +0000
Subject: [PATCH 05/17] [FIX] stock: lot in multiple locations
- Activate:
'Track lots or serial numbers'
'Manage several Warehouses, each one composed by several stock locations'
'Advanced routing of products using rules'
- In the main warehouse, activate Pick + Ship
- In Stock Locations, create 'WH/Stock/Shelf 3' and 'WH/Stock/Shelf 4'
(1 and 2 already exist, use the same config)
- Create a new product 'Foo', activate Tracking By Lots
- On Foo, use 4 times the "Update Qty on Hand" (order is important):
Add 1 on Shelf 2, create a lot
Add 1 on Shelf 1, use the same lot
Add 3 on Shelf 4, use the same lot
Add 1 on Shelf 3, use the same lot
- Create a SO, set a partner
- Ensure that YourCompany is used as warehouse
- Add several SO lines (order is important)
a line with 1 product Foo
a second line with 1 product Foo
a third line with 4 products Foo
- Confirm the SO, you now have 2 deliveries, 1 Pick, 1 Out
- Open the Pick, all moves should be available, you should have:
4 operations:
Shelf 2, quantity 1
Shelf 4, quantity 3
Shelf 1, quantity 1
Shelf 3, quantity 1
3 moves:
A, quantity 1
B, quantity 1
C, quantity 4
- On each operation, select the lot created before and set the quantity
to be fully done
- Validate the Pick
The moves end up like this:
- Move A with qty 1: is done and linked with a quant of 1
- Move B with qty 1: is done and linked with no quant
- Move C with qty 4: is done and linked with a quant of 1, a quant of 3,
a quant of 1 (sum is 5)
In the Out picking, the move linked with the source move (B) with no
quant stays in "Waiting another move" even if the source move is done.
This outgoing move will never be available.
In the method `recompute_remaining_qty`, we loop on operations, and
match them wih the moves. However, the operation with the largest
quantity (Shelf 4, quantity 3) is processed before the move with the
highest quantity (C, quantity 4). Therefore, when we later loop on move
C, `qty_assign_cmp` is larger than zero, which sets `need_rereserve` and
ultimately triggers `rereserve_quants` in `do_transfer`.
A first part of the fix is to check for the location of the quants when
matching moves and operations. This fixes the original issue, but
inconsistencies can still arise since a quant which is taken partially.
therefore, we make sure to never take more than the quantity on the
link.
opw-1932624
closes odoo/odoo#30857
---
addons/stock/models/stock_move.py | 14 ++++++++------
addons/stock/models/stock_picking.py | 2 +-
2 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py
index c170d2cc5fa..43a51a03831 100644
--- a/addons/stock/models/stock_move.py
+++ b/addons/stock/models/stock_move.py
@@ -868,13 +868,15 @@ class StockMove(models.Model):
false_quants += [reserved_quant]
elif float_compare(lot_quantities.get(reserved_quant.lot_id.id, 0), 0, precision_rounding=rounding) > 0:
if float_compare(lot_quantities[reserved_quant.lot_id.id], reserved_quant.qty, precision_rounding=rounding) >= 0:
- lot_quantities[reserved_quant.lot_id.id] -= reserved_quant.qty
- quants_taken += [(reserved_quant, reserved_quant.qty)]
- qty_on_link -= reserved_quant.qty
+ qty_taken = min(reserved_quant.qty, qty_on_link)
+ lot_quantities[reserved_quant.lot_id.id] -= qty_taken
+ quants_taken += [(reserved_quant, qty_taken)]
+ qty_on_link -= qty_taken
else:
- quants_taken += [(reserved_quant, lot_quantities[reserved_quant.lot_id.id])]
- lot_quantities[reserved_quant.lot_id.id] = 0
- qty_on_link -= lot_quantities[reserved_quant.lot_id.id]
+ qty_taken = min(qty_on_link, lot_quantities[reserved_quant.lot_id.id])
+ quants_taken += [(reserved_quant, qty_taken)]
+ lot_quantities[reserved_quant.lot_id.id] -= qty_taken
+ qty_on_link -= qty_taken
lot_move_qty[move.id] = qty_on_link
remaining_move_qty[move.id] -= prout_move_qty[move]
diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py
index c1f5f98ba09..3d381ac064c 100644
--- a/addons/stock/models/stock_picking.py
+++ b/addons/stock/models/stock_picking.py
@@ -737,7 +737,7 @@ class Picking(models.Model):
flag = quant.package_id == ops.package_id
else:
flag = not quant.package_id.id
- flag = flag and (ops.owner_id.id == quant.owner_id.id)
+ flag = flag and (ops.owner_id.id == quant.owner_id.id) and (ops.location_id.id == quant.location_id.id)
if flag:
if not lot_qty:
max_qty_on_link = min(quant.qty, qty_to_assign)
From 80460c40d9785f3e24fbc9464cc7e117f56f446f Mon Sep 17 00:00:00 2001
From: "Lucas Perais (lpe)"
Date: Wed, 6 Feb 2019 10:34:57 +0000
Subject: [PATCH 06/17] [FIX] account, purchase, sale: notification with right
lang
Have a partner in French while you operate in English
Click on 'send by email' on a invoice/sale order/purchase order
Before this commit:
- The body of the mail is translated in the partner's language
- but the notification header/footer surrounding the body was not
This is because:
- mail templates apply to a model
- in the case of the notification header/footer, this model is 'mail.message'
- mail.message doesn't have a lang field
- at the notification rendering time, we don't have easy (and generic) access
to the "real" model or to the lang (let alone to which lang to apply) that we need
After this commit, the notification is translated but:
the lang to get is hardcoded, and is the one on the partner of the inv/so/po
and is un-coupled from the dynamic lang on the proper inv/so/po template
This patch is hackish at several levels, I suggest that a generic solution is found in master
If no other solution is found until then, then the patch may be forward-ported
OPW 1935091
closes odoo/odoo#30873
---
addons/account/models/account_invoice.py | 2 +-
addons/purchase/models/purchase.py | 3 ++-
addons/sale/wizard/mail_compose_message.py | 2 +-
3 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py
index 5f2d83c5035..576f9d9e551 100644
--- a/addons/account/models/account_invoice.py
+++ b/addons/account/models/account_invoice.py
@@ -1834,5 +1834,5 @@ class MailComposeMessage(models.TransientModel):
invoice = self.env['account.invoice'].browse(context['default_res_id'])
if not invoice.sent:
invoice.sent = True
- self = self.with_context(mail_post_autofollow=True)
+ self = self.with_context(mail_post_autofollow=True, lang=invoice.partner_id.lang)
return super(MailComposeMessage, self).send_mail(auto_commit=auto_commit)
diff --git a/addons/purchase/models/purchase.py b/addons/purchase/models/purchase.py
index 53eeaffa2e3..8962513fd02 100644
--- a/addons/purchase/models/purchase.py
+++ b/addons/purchase/models/purchase.py
@@ -1131,6 +1131,7 @@ class MailComposeMessage(models.TransientModel):
@api.multi
def send_mail(self, auto_commit=False):
if self._context.get('default_model') == 'purchase.order' and self._context.get('default_res_id'):
- self = self.with_context(mail_post_autofollow=True)
+ order = self.env['purchase.order'].browse(self._context['default_res_id'])
+ self = self.with_context(mail_post_autofollow=True, lang=order.partner_id.lang)
self.mail_purchase_order_on_send()
return super(MailComposeMessage, self).send_mail(auto_commit=auto_commit)
diff --git a/addons/sale/wizard/mail_compose_message.py b/addons/sale/wizard/mail_compose_message.py
index 9ec46b48308..0291d3f848c 100644
--- a/addons/sale/wizard/mail_compose_message.py
+++ b/addons/sale/wizard/mail_compose_message.py
@@ -13,5 +13,5 @@ class MailComposeMessage(models.TransientModel):
order = self.env['sale.order'].browse([self._context['default_res_id']])
if order.state == 'draft':
order.with_context(tracking_disable=True).state = 'sent'
- self = self.with_context(mail_post_autofollow=True)
+ self = self.with_context(mail_post_autofollow=True, lang=order.partner_id.lang)
return super(MailComposeMessage, self).send_mail(auto_commit=auto_commit)
From fa97d6ab1573515e6485b169df1e1f6b709275de Mon Sep 17 00:00:00 2001
From: Nicolas Martinelli
Date: Wed, 6 Feb 2019 14:11:50 +0000
Subject: [PATCH 07/17] [FIX] purchase: supplier on parent company
- Create a product and set a contact as the vendor (for instance, Arthur
Gomez from Asustek in the runbot)
- Set a specific name and code for the supplier
- Create a RFQ for this vendor (Arthur Gomez - the contact person)
- Add the product, confirm the RFQ
On the product, the company (Asustek) is automatically added as vendor,
but there is no vendor name and code.
opw-1929745
closes odoo/odoo#30891
---
addons/purchase/models/purchase.py | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/addons/purchase/models/purchase.py b/addons/purchase/models/purchase.py
index 295c434c4e2..8f80e112b32 100644
--- a/addons/purchase/models/purchase.py
+++ b/addons/purchase/models/purchase.py
@@ -448,6 +448,16 @@ class PurchaseOrder(models.Model):
'currency_id': currency.id,
'delay': 0,
}
+ # In case the order partner is a contact address, a new supplierinfo is created on
+ # the parent company. In this case, we keep the product name and code.
+ seller = line.product_id._select_seller(
+ partner_id=line.partner_id,
+ quantity=line.product_qty,
+ date=line.order_id.date_order and line.order_id.date_order[:10],
+ uom_id=line.product_uom)
+ if seller:
+ supplierinfo['product_name'] = seller.product_name
+ supplierinfo['product_code'] = seller.product_code
vals = {
'seller_ids': [(0, 0, supplierinfo)],
}
From 2a881865e88ad3c1f7ca52f0ec4e61b8745c3eec Mon Sep 17 00:00:00 2001
From: Carel
Date: Wed, 6 Feb 2019 10:52:00 +0000
Subject: [PATCH 08/17] [CLA] signature for Carel van Dam
closes odoo/odoo#30876
---
doc/cla/individual/carelvd.md | 11 +++++++++++
1 file changed, 11 insertions(+)
create mode 100644 doc/cla/individual/carelvd.md
diff --git a/doc/cla/individual/carelvd.md b/doc/cla/individual/carelvd.md
new file mode 100644
index 00000000000..e4570a18845
--- /dev/null
+++ b/doc/cla/individual/carelvd.md
@@ -0,0 +1,11 @@
+South Africa, 05/02/2019
+
+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,
+
+Carel van Dam carelvdam@gmail.com https://github.com/carelvd
From 37220d02a4d86e0f9a1d4658770a2d673605de13 Mon Sep 17 00:00:00 2001
From: Jorge Pinna Puissant
Date: Fri, 1 Feb 2019 13:15:04 +0000
Subject: [PATCH 09/17] [FIX] payment_authorize: add new card verification In
the e-comerce, when the user try to add a new card in this payment methods.
Before this commit, to validate the card, besides of the creation of the
payment token, an amount of $1.5 id charged and refunded.
During the refunded an error was raised. This error arrives because:
payments made via Authorize.net are settled and allowed to be refunded
only on the next day.
https://account.authorize.net/help/Miscellaneous/FAQ/Frequently_Asked_Questions.htm#Refund
The original transaction that you wish to refund must have a status of Settled Successfully.
You cannot issue refunds against unsettled, voided, declined or errored transactions.
This means, we can't refund directly after the payment.
Now, we only create the payment token. As Authorize.net verify the card
during the creation of the token, a new verification is not needed.
OPW-1927754
closes odoo/odoo#30905
---
addons/payment_authorize/controllers/main.py | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/addons/payment_authorize/controllers/main.py b/addons/payment_authorize/controllers/main.py
index 9614327401a..a5f55f07afe 100644
--- a/addons/payment_authorize/controllers/main.py
+++ b/addons/payment_authorize/controllers/main.py
@@ -77,13 +77,14 @@ class AuthorizeController(http.Controller):
'id': token.id,
'short_name': token.short_name,
'3d_secure': False,
- 'verified': False,
+ 'verified': True, #Authorize.net does a transaction type of Authorization Only
+ #As Authorize.net already verify this card, we do not verify this card again.
}
-
- if verify_validity != False:
- token.validate()
- res['verified'] = token.verified
-
+ #token.validate() don't work with Authorize.net.
+ #Payments made via Authorize.net are settled and allowed to be refunded only on the next day.
+ #https://account.authorize.net/help/Miscellaneous/FAQ/Frequently_Asked_Questions.htm#Refund
+ #The original transaction that you wish to refund must have a status of Settled Successfully.
+ #You cannot issue refunds against unsettled, voided, declined or errored transactions.
return res
@http.route(['/payment/authorize/s2s/create'], type='http', auth='public')
From c47dc928f6ec67f0e76c8b7907d7f62ae2452d89 Mon Sep 17 00:00:00 2001
From: Arnold Moyaux
Date: Tue, 5 Feb 2019 15:05:34 +0000
Subject: [PATCH 10/17] [FIX] stock: warehouse_selectable skip warehouse_ids
Usecase to reproduce:
- Create a route with a warehouse_ids
- Uncheck warehouse_selectable on route
- Create a picking that use the route
It should fail since the route is not applicable.
It happens because _search_rule only check for route with warehouse_ids
but it do not check for warehouse_selectable. We can't fix _search_rule
since stock_warehouse.py creates multi step delivery and reception
routes without warehouse_selectable thus it would break existing configuration.
Instead create an onchange on warehouse_selectable that remove
warehouse_ids on route.
partial backport of commit a35df8d37170790257876a54aa54f2c3ab596c44
closes odoo/odoo#30844
---
addons/stock/models/stock_location.py | 5 +++++
addons/stock/models/stock_warehouse.py | 1 +
2 files changed, 6 insertions(+)
diff --git a/addons/stock/models/stock_location.py b/addons/stock/models/stock_location.py
index bce2de0ecd2..b3903df88b7 100644
--- a/addons/stock/models/stock_location.py
+++ b/addons/stock/models/stock_location.py
@@ -170,6 +170,11 @@ class Route(models.Model):
categ_ids = fields.Many2many('product.category', 'stock_location_route_categ', 'route_id', 'categ_id', 'Product Categories')
warehouse_ids = fields.Many2many('stock.warehouse', 'stock_route_warehouse', 'route_id', 'warehouse_id', 'Warehouses')
+ @api.onchange('warehouse_selectable')
+ def _onchange_warehouse_selectable(self):
+ if not self.warehouse_selectable:
+ self.warehouse_ids = []
+
def write(self, values):
'''when a route is deactivated, deactivate also its pull and push rules'''
res = super(Route, self).write(values)
diff --git a/addons/stock/models/stock_warehouse.py b/addons/stock/models/stock_warehouse.py
index 3394c3a1e7b..dc8766954de 100644
--- a/addons/stock/models/stock_warehouse.py
+++ b/addons/stock/models/stock_warehouse.py
@@ -467,6 +467,7 @@ class Warehouse(models.Model):
'name': self._format_routename(route_type=route_type),
'product_categ_selectable': True,
'product_selectable': False,
+ 'warehouse_selectable': True,
'company_id': self.company_id.id,
'sequence': 10,
}
From f9a80a6e84ec3dd9e47f547e44c3bce1d134bda0 Mon Sep 17 00:00:00 2001
From: "Lucas Perais (lpe)"
Date: Thu, 24 Jan 2019 16:39:41 +0000
Subject: [PATCH 11/17] [FIX] web: calendar: take locale to format dates
Backport of d9fed5381a78c19ce14ddc8b9233f60d53c65453
Before this commit, when opening the calendar view with a specific locale
in the "week" view
the days were translated but the date format was wrong and fell back to english
This was because the translated terms were passed explicitly, but the locale did not
get passed
After this commit, we do what it takes to pass the locale to fullcalendar
and the dates are formatted with the right pattern
Also, there may be a bug in fullcalendar, because just passing the locale in the options
won't work, it should be instanciated first in fullcalendar's "locales cache"
OPW 1922092
OPW 1934127
closes odoo/odoo#30909
---
.../js/views/calendar/calendar_renderer.js | 6 +++
.../web/static/tests/views/calendar_tests.js | 48 +++++++++++++++++++
2 files changed, 54 insertions(+)
diff --git a/addons/web/static/src/js/views/calendar/calendar_renderer.js b/addons/web/static/src/js/views/calendar/calendar_renderer.js
index 6565cbb8385..4c0fabadfdf 100644
--- a/addons/web/static/src/js/views/calendar/calendar_renderer.js
+++ b/addons/web/static/src/js/views/calendar/calendar_renderer.js
@@ -317,6 +317,11 @@ return AbstractRenderer.extend({
this.$calendar = this.$(".o_calendar_widget");
+ // This seems like a workaround but apparently passing the locale
+ // in the options is not enough. We should initialize it beforehand
+ var locale = moment.locale();
+ $.fullCalendar.locale(locale);
+
//Documentation here : http://arshaw.com/fullcalendar/docs/
var fc_options = $.extend({}, this.state.fc_options, {
eventDrop: function (event) {
@@ -370,6 +375,7 @@ return AbstractRenderer.extend({
},
height: 'parent',
unselectAuto: false,
+ locale: locale, // reset locale when fullcalendar has already been instanciated before now
});
this.$calendar.fullCalendar(fc_options);
diff --git a/addons/web/static/tests/views/calendar_tests.js b/addons/web/static/tests/views/calendar_tests.js
index 00cdfa24dd2..fad84cc43c3 100644
--- a/addons/web/static/tests/views/calendar_tests.js
+++ b/addons/web/static/tests/views/calendar_tests.js
@@ -6,6 +6,7 @@ var CalendarRenderer = require('web.CalendarRenderer');
var fieldUtils = require('web.field_utils');
var mixins = require('web.mixins');
var testUtils = require('web.test_utils');
+var time = require('web.time');
var session = require('web.session');
@@ -2146,6 +2147,53 @@ QUnit.module('Views', {
calendar.destroy();
});
+ QUnit.test('fullcalendar initializes with right locale', function (assert) {
+ assert.expect(1);
+
+ // Do not forward port this part in versions >= saas11.3
+ testUtils.patch(time, {
+ getLangDateFormat: function () {
+ return 'DD/MM';
+ },
+ });
+
+ var initialLocale = moment.locale();
+ // This will set the locale to zz
+ moment.defineLocale('zz', {
+ longDateFormat: {
+ L: 'DD/MM/YYYY'
+ },
+ weekdaysShort: ["zz1.", "zz2.", "zz3.", "zz4.", "zz5.", "zz6.", "zz7."],
+ });
+
+ var calendar = createView({
+ View: CalendarView,
+ model: 'event',
+ data: this.data,
+ arch: ' '+
+ ''+
+ '',
+ archs: archs,
+ viewOptions: {
+ initialDate: initialDate,
+ action: {views: [{viewID: 1, type: 'kanban'}, {viewID: 43, type: 'form'}]}
+ },
+
+ });
+
+ assert.strictEqual(calendar.$('.fc-day-header:first').text(), "zz1. 11/12",
+ 'The day should be in the given locale specific format');
+
+ moment.locale(initialLocale);
+ // Do not forward port this part in versions >= saas11.3
+ testUtils.unpatch(time);
+
+ calendar.destroy();
+ });
+
});
});
From 0757ba3c639000edba89448a3a542a9f9c225538 Mon Sep 17 00:00:00 2001
From: RomainLibert
Date: Thu, 7 Feb 2019 15:25:13 +0000
Subject: [PATCH 12/17] [FIX] fleet: fix _get_default_state method
If fleet.vehicle_state_active is not found in the system then the method
will raise an error, hence it won't allow creating any fleet.vehicle
closes odoo/odoo#30925
---
addons/fleet/models/fleet.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/addons/fleet/models/fleet.py b/addons/fleet/models/fleet.py
index 364b44fff16..538142ad2bb 100644
--- a/addons/fleet/models/fleet.py
+++ b/addons/fleet/models/fleet.py
@@ -143,7 +143,7 @@ class FleetVehicle(models.Model):
def _get_default_state(self):
state = self.env.ref('fleet.vehicle_state_active', raise_if_not_found=False)
- return state and state.id or False
+ return state if state and state.id else False
name = fields.Char(compute="_compute_vehicle_name", store=True)
active = fields.Boolean(default=True)
From be689c53c13330832510c8cef332ac862d4ed5e8 Mon Sep 17 00:00:00 2001
From: qsm-odoo
Date: Wed, 6 Feb 2019 17:25:36 +0000
Subject: [PATCH 13/17] [FIX] web_editor: review drag and drop in the editor
When dropping a snippet into a page, it is dropped in the drop-zone
which is the nearest of the user cursor. When moving a snippet, that
condition did not apply and the user was required to put the cursor at
the exact location of the drop-zone.
Also, for both drag and drop features, the drop zones which appeared
were not displayed correctly for full width columns, which made dropping
sometimes impossible when multiple col-*-12 were below each other.
task-1937758
closes odoo/odoo#30899
---
.../static/src/js/snippets.editor.js | 36 ++++++++++++++++---
.../static/src/less/web_editor.ui.less | 4 +--
2 files changed, 33 insertions(+), 7 deletions(-)
diff --git a/addons/web_editor/static/src/js/snippets.editor.js b/addons/web_editor/static/src/js/snippets.editor.js
index 97830d2ae8e..17c0c2ffb85 100644
--- a/addons/web_editor/static/src/js/snippets.editor.js
+++ b/addons/web_editor/static/src/js/snippets.editor.js
@@ -615,6 +615,10 @@ data.Class = Widget.extend({
var self = this;
var zone_template = $("");
+ function isFullWidth($elem) {
+ return $elem.parent().width() === $elem.outerWidth(true);
+ }
+
if ($selector_children) {
$selector_children.each(function () {
var $zone = $(this);
@@ -632,7 +636,10 @@ data.Class = Widget.extend({
'display': 'inline-block'
});
} else if (float === "left" || float === "right") {
- $drop.addClass("oe_vertical").css('height', Math.max(Math.min($zone.outerHeight(), $zone.children().last().outerHeight()), 30));
+ $drop.css('float', float);
+ if (!isFullWidth($zone)) {
+ $drop.addClass("oe_vertical").css('height', Math.max(Math.min($zone.outerHeight(), $zone.children().last().outerHeight()), 30));
+ }
}
$drop = $drop.clone();
@@ -647,7 +654,10 @@ data.Class = Widget.extend({
'display': 'inline-block'
});
} else if (float === "left" || float === "right") {
- $drop.addClass("oe_vertical").css('height', Math.max(Math.min($zone.outerHeight(), $zone.children().first().outerHeight()), 30));
+ $drop.css('float', float);
+ if (!isFullWidth($zone)) {
+ $drop.addClass("oe_vertical").css('height', Math.max(Math.min($zone.outerHeight(), $zone.children().first().outerHeight()), 30));
+ }
}
if (test) {
$drop.css({'float': 'none', 'display': 'inline-block'});
@@ -668,14 +678,20 @@ data.Class = Widget.extend({
if($zone.prev('.oe_drop_zone:visible').length === 0) {
$drop = zone_template.clone();
if (float === "left" || float === "right") {
- $drop.addClass("oe_vertical").css('height', Math.max(Math.min($zone.outerHeight(), $zone.prev().outerHeight() || Infinity), 30));
+ $drop.css('float', float);
+ if (!isFullWidth($zone)) {
+ $drop.addClass("oe_vertical").css('height', Math.max(Math.min($zone.outerHeight(), $zone.prev().outerHeight() || Infinity), 30));
+ }
}
$zone.before($drop);
}
if($zone.next('.oe_drop_zone:visible').length === 0) {
$drop = zone_template.clone();
if (float === "left" || float === "right") {
- $drop.addClass("oe_vertical").css('height', Math.max(Math.min($zone.outerHeight(), $zone.next().outerHeight() || Infinity), 30));
+ $drop.css('float', float);
+ if (!isFullWidth($zone)) {
+ $drop.addClass("oe_vertical").css('height', Math.max(Math.min($zone.outerHeight(), $zone.next().outerHeight() || Infinity), 30));
+ }
}
$zone.after($drop);
}
@@ -862,6 +878,7 @@ data.Editor = Class.extend({
},
_drag_and_drop_start: function () {
var self = this;
+ this.dropped = false;
self.buildingBlock.editor_busy = true;
self.size = {
width: self.$target.width(),
@@ -890,9 +907,18 @@ data.Editor = Class.extend({
self._drag_and_drop_after_insert_dropzone();
self._drag_and_drop_active_drop_zone($('.oe_drop_zone'));
},
- _drag_and_drop_stop: function () {
+ _drag_and_drop_stop: function (ev, ui) {
var self = this;
+ // TODO lot of this is duplicated code of the d&d feature of snippets
+ if (!this.dropped) {
+ var $el = $.nearest({x: ui.position.left, y: ui.position.top}, '.oe_drop_zone').first();
+ if ($el.length) {
+ $el.after(this.$target);
+ this.dropped = true;
+ }
+ }
+
$(".oe_drop_zone").droppable('destroy').remove();
var prev = this.$target.first()[0].previousSibling;
diff --git a/addons/web_editor/static/src/less/web_editor.ui.less b/addons/web_editor/static/src/less/web_editor.ui.less
index 02094adf754..965a0ca820e 100644
--- a/addons/web_editor/static/src/less/web_editor.ui.less
+++ b/addons/web_editor/static/src/less/web_editor.ui.less
@@ -264,12 +264,12 @@ html[lang] > body.editor_enable [data-oe-translation-state] {
}
&.oe_vertical {
- border: 2px dashed @odoo-brand-primary;
+ border: @odoo-dropzone-border;
border-left: none;
border-right: none;
width: @odoo-dropzone-size;
- float: left;
+ height: 100%;
margin: 0 -@odoo-dropzone-size/2;
&:after {
From a02e2778172f7de54cca58babb26151030b5b9dc Mon Sep 17 00:00:00 2001
From: qdp-odoo
Date: Mon, 2 Jul 2018 08:38:31 +0000
Subject: [PATCH 14/17] [IMP] account: keep numbering of reset-to-draft
payments
Was github issue #25441
opw-1935427
closes odoo/odoo#30918
---
addons/account/models/account_payment.py | 38 +++++++++++++-----------
1 file changed, 20 insertions(+), 18 deletions(-)
diff --git a/addons/account/models/account_payment.py b/addons/account/models/account_payment.py
index 0e19cd13b55..3bca6023403 100644
--- a/addons/account/models/account_payment.py
+++ b/addons/account/models/account_payment.py
@@ -276,7 +276,7 @@ class account_payment(models.Model):
self.payment_difference = self._compute_total_invoices_amount() - self.amount
company_id = fields.Many2one(store=True)
- name = fields.Char(readonly=True, copy=False, default="Draft Payment") # The name is attributed upon post()
+ name = fields.Char(readonly=True, copy=False) # The name is attributed upon post()
state = fields.Selection([('draft', 'Draft'), ('posted', 'Posted'), ('sent', 'Sent'), ('reconciled', 'Reconciled'), ('cancelled', 'Cancelled')], readonly=True, default='draft', copy=False, string="Status")
payment_type = fields.Selection(selection_add=[('transfer', 'Internal Transfer')])
@@ -494,23 +494,25 @@ class account_payment(models.Model):
if any(inv.state != 'open' for inv in rec.invoice_ids):
raise ValidationError(_("The payment cannot be processed because the invoice is not open!"))
- # Use the right sequence to set the name
- if rec.payment_type == 'transfer':
- sequence_code = 'account.payment.transfer'
- else:
- if rec.partner_type == 'customer':
- if rec.payment_type == 'inbound':
- sequence_code = 'account.payment.customer.invoice'
- if rec.payment_type == 'outbound':
- sequence_code = 'account.payment.customer.refund'
- if rec.partner_type == 'supplier':
- if rec.payment_type == 'inbound':
- sequence_code = 'account.payment.supplier.refund'
- if rec.payment_type == 'outbound':
- sequence_code = 'account.payment.supplier.invoice'
- rec.name = self.env['ir.sequence'].with_context(ir_sequence_date=rec.payment_date).next_by_code(sequence_code)
- if not rec.name and rec.payment_type != 'transfer':
- raise UserError(_("You have to define a sequence for %s in your company.") % (sequence_code,))
+ # keep the name in case of a payment reset to draft
+ if not rec.name:
+ # Use the right sequence to set the name
+ if rec.payment_type == 'transfer':
+ sequence_code = 'account.payment.transfer'
+ else:
+ if rec.partner_type == 'customer':
+ if rec.payment_type == 'inbound':
+ sequence_code = 'account.payment.customer.invoice'
+ if rec.payment_type == 'outbound':
+ sequence_code = 'account.payment.customer.refund'
+ if rec.partner_type == 'supplier':
+ if rec.payment_type == 'inbound':
+ sequence_code = 'account.payment.supplier.refund'
+ if rec.payment_type == 'outbound':
+ sequence_code = 'account.payment.supplier.invoice'
+ rec.name = self.env['ir.sequence'].with_context(ir_sequence_date=rec.payment_date).next_by_code(sequence_code)
+ if not rec.name and rec.payment_type != 'transfer':
+ raise UserError(_("You have to define a sequence for %s in your company.") % (sequence_code,))
# Create the journal entry
amount = rec.amount * (rec.payment_type in ('outbound', 'transfer') and 1 or -1)
From f5107b10f5658f51c5cc07c6f3b7e7b0f38bf8d3 Mon Sep 17 00:00:00 2001
From: Nans Lefebvre
Date: Thu, 7 Feb 2019 21:45:30 +0000
Subject: [PATCH 15/17] [FIX] mrp: fix singleton error in _update_raw_move
Commit bfb0f1e2a5d3a921bef89718e06c5f68da4f43ac
did a very good job not seeing that the lines only used move[0],
and called move.field directly.
This could result, for certain BoMs, in traceback.
opw 1928677
closes odoo/odoo#30938
---
addons/mrp/models/mrp_production.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py
index 45eb460a25b..0adfcea608a 100644
--- a/addons/mrp/models/mrp_production.py
+++ b/addons/mrp/models/mrp_production.py
@@ -455,7 +455,7 @@ class MrpProduction(models.Model):
move[0].with_context(do_not_unreserve=True).write({'product_uom_qty': quantity})
move[0]._recompute_state()
move[0]._action_assign()
- move.unit_factor = quantity / move.raw_material_production_id.product_qty
+ move[0].unit_factor = quantity / move[0].raw_material_production_id.product_qty
elif quantity < 0: # Do not remove 0 lines
if move[0].quantity_done > 0:
raise UserError(_('Lines need to be deleted, but can not as you still have some quantities to consume in them. '))
From d9f9d32f4e7d2408ee6245238a82b24e1fac864f Mon Sep 17 00:00:00 2001
From: Alex Tuyls
Date: Thu, 7 Feb 2019 14:14:37 +0000
Subject: [PATCH 16/17] [FIX] sale_mrp: incorrect search of BOM in multicompany
In following configuration:
- We have two companies: A and B
- We have a shared product X
- We set a BOM of type KIT for this product X for company B only (the field company on a BOM is mandatory)
- We set no BOM for product X for company A because in company A we sell the product as a regular product
When we sell product X in company A, as a normal stockable product, the invoicing behavior is the same as
when we would sell KIT products. This is because we don't check the SO company when searching the associated
BOM.
closes odoo/odoo#30927
---
addons/sale_mrp/models/sale_mrp.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/addons/sale_mrp/models/sale_mrp.py b/addons/sale_mrp/models/sale_mrp.py
index 9b33c89f57c..68600642c9b 100644
--- a/addons/sale_mrp/models/sale_mrp.py
+++ b/addons/sale_mrp/models/sale_mrp.py
@@ -14,7 +14,7 @@ class SaleOrderLine(models.Model):
# In the case of a kit, we need to check if all components are shipped. Since the BOM might
# have changed, we don't compute the quantities but verify the move state.
- bom = self.env['mrp.bom']._bom_find(product=self.product_id)
+ bom = self.env['mrp.bom']._bom_find(product=self.product_id,company_id=self.company_id.id)
if bom and bom.type == 'phantom':
moves = self.move_ids.filtered(lambda m: m.picking_id and m.picking_id.state != 'cancel')
bom_delivered = all([move.state == 'done' for move in moves])
From d260c53d12180bf3c2f4f06cf4cdcfb554fd4ba5 Mon Sep 17 00:00:00 2001
From: Florent de Labarre
Date: Tue, 5 Feb 2019 13:24:00 +0000
Subject: [PATCH 17/17] [FIX] l10n_fr_fec: wrong formatting
The exported CSV contains unexpected `b` characters.
opw-1937282
closes odoo/odoo#30838
---
addons/l10n_fr_fec/wizard/account_fr_fec.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/addons/l10n_fr_fec/wizard/account_fr_fec.py b/addons/l10n_fr_fec/wizard/account_fr_fec.py
index bd8e4cc44c0..032baf2d971 100644
--- a/addons/l10n_fr_fec/wizard/account_fr_fec.py
+++ b/addons/l10n_fr_fec/wizard/account_fr_fec.py
@@ -265,7 +265,7 @@ class AccountFrFec(models.TransientModel):
for row in self._cr.fetchall():
listrow = list(row)
account_id = listrow.pop()
- w.writerow([s.encode("utf-8") for s in listrow])
+ w.writerow(listrow)
# LINES
sql_query = '''