diff --git a/addons/account/models/chart_template.py b/addons/account/models/chart_template.py
index c41db44bf0..3ba19d482f 100644
--- a/addons/account/models/chart_template.py
+++ b/addons/account/models/chart_template.py
@@ -143,7 +143,7 @@ def update_taxes_from_templates(cr, chart_template_xmlid):
outdated_taxes = []
for company in companies:
template_to_tax = _get_template_to_tax_xmlid_mapping(company)
- templates = env['account.tax.template'].search([("chart_template_id", "=", chart_template_id)])
+ templates = env['account.tax.template'].with_context(active_test=False).search([("chart_template_id", "=", chart_template_id)])
for template in templates:
tax = env["account.tax"].browse(template_to_tax.get(template.id))
if not tax or not _is_tax_and_template_same(template, tax):
diff --git a/addons/l10n_fr_fec/wizard/account_fr_fec.py b/addons/l10n_fr_fec/wizard/account_fr_fec.py
index 3e700a192e..5d43efe551 100644
--- a/addons/l10n_fr_fec/wizard/account_fr_fec.py
+++ b/addons/l10n_fr_fec/wizard/account_fr_fec.py
@@ -231,7 +231,8 @@ class AccountFrFec(models.TransientModel):
and (unaffected_earnings_results[11] != '0,00'
or unaffected_earnings_results[12] != '0,00')):
#search an unaffected earnings account
- unaffected_earnings_account = self.env['account.account'].search([('user_type_id', '=', self.env.ref('account.data_unaffected_earnings').id)], limit=1)
+ unaffected_earnings_account = self.env['account.account'].search([('user_type_id', '=', self.env.ref('account.data_unaffected_earnings').id),
+ ('company_id', '=', company.id)], limit=1)
if unaffected_earnings_account:
unaffected_earnings_results[4] = unaffected_earnings_account.code
unaffected_earnings_results[5] = unaffected_earnings_account.name
diff --git a/addons/l10n_sg/__manifest__.py b/addons/l10n_sg/__manifest__.py
index 02e9b566e0..bb6df94903 100644
--- a/addons/l10n_sg/__manifest__.py
+++ b/addons/l10n_sg/__manifest__.py
@@ -6,7 +6,7 @@
{
'name': 'Singapore - Accounting',
'author': 'Tech Receptives',
- 'version': '2.0',
+ 'version': '2.1',
'category': 'Accounting/Localizations/Account Charts',
'description': """
Singapore accounting chart and localization.
diff --git a/addons/l10n_sg/data/account_data.xml b/addons/l10n_sg/data/account_data.xml
index b7f9af41d1..99b2e54688 100644
--- a/addons/l10n_sg/data/account_data.xml
+++ b/addons/l10n_sg/data/account_data.xml
@@ -9,6 +9,9 @@
TAX 7%
+
+ TAX 8%
+
diff --git a/addons/l10n_sg/data/account_tax_data.xml b/addons/l10n_sg/data/account_tax_data.xml
index 649eebe054..ae8b80a3e0 100644
--- a/addons/l10n_sg/data/account_tax_data.xml
+++ b/addons/l10n_sg/data/account_tax_data.xml
@@ -72,6 +72,43 @@
]"/>
+
+ Sales Tax 8% DS
+ 8% DS
+
+ 8
+ percent
+ sale
+
+
+
+
+
+
Sales Tax 0% ESN33
0% ESN33
@@ -206,6 +243,43 @@
]"/>
+
+ Sales Tax 8% SR
+ 8% SR
+
+ 8
+ percent
+ sale
+
+
+
+
+
+
Sales Tax SRCA-S
SRCA-S
@@ -276,6 +350,43 @@
]"/>
+
+ Sales Tax 8% SRCA-C
+ 8% SRCA-C
+
+ 8
+ percent
+ sale
+
+
+
+
+
+
@@ -315,6 +426,43 @@
]"/>
+
+ Purchase Tax 8% TX-N33
+ 8% TX-N33
+
+ 8
+ percent
+ purchase
+
+
+
+
+
+
Purchase Tax 7% TX-E33
7% TX-E33
@@ -352,6 +500,43 @@
]"/>
+
+ Purchase Tax 8% TX-E33
+ 8% TX-E33
+
+ 8
+ percent
+ purchase
+
+
+
+
+
+
Purchase Tax 7% BL
7% BL
@@ -385,6 +570,39 @@
]"/>
+
+ Purchase Tax 8% BL
+ 8% BL
+
+ 8
+ percent
+ purchase
+
+
+
+
+
+
Purchase Tax 7% IM
7% IM
@@ -422,6 +640,43 @@
]"/>
+
+ Purchase Tax 8% IM
+ 8% IM
+
+ 8
+ percent
+ purchase
+
+
+
+
+
+
Purchase Tax 7% TX-RE
7% TX-RE
@@ -459,6 +714,43 @@
]"/>
+
+ Purchase Tax 8% TX-RE
+ 8% TX-RE
+
+ 8
+ percent
+ purchase
+
+
+
+
+
+
Purchase Tax 7% IGDS
7% IGDS
@@ -496,6 +788,43 @@
]"/>
+
+ Purchase Tax 8% IGDS
+ 8% IGDS
+
+ 8
+ percent
+ purchase
+
+
+
+
+
+
Purchase Tax 0% NR
0% NR
@@ -692,6 +1021,43 @@
]"/>
+
+ Purchase Tax 8% TX8
+ 8% TX8
+
+ 8
+ percent
+ purchase
+
+
+
+
+
+
Purchase Tax 7% TXCA
7% TXCA
@@ -728,5 +1094,42 @@
}),
]"/>
+
+
+ Purchase Tax 8% TXCA
+ 8% TXCA
+
+ 8
+ percent
+ purchase
+
+
+
+
+
diff --git a/addons/l10n_sg/data/l10n_sg_chart_data.xml b/addons/l10n_sg/data/l10n_sg_chart_data.xml
index 3e36763777..eed72f4a6b 100644
--- a/addons/l10n_sg/data/l10n_sg_chart_data.xml
+++ b/addons/l10n_sg/data/l10n_sg_chart_data.xml
@@ -316,7 +316,7 @@
- Purchase Tax Account 7% TX-N33
+ Purchase Tax Account 8% TX-N33
101260
@@ -324,7 +324,7 @@
- Purchase Tax Account 7% TX-E33
+ Purchase Tax Account 8% TX-E33
101270
@@ -332,7 +332,7 @@
- Purchase Tax Account 7% BL
+ Purchase Tax Account 8% BL
101280
@@ -340,7 +340,7 @@
- Purchase Tax Account 7% IM
+ Purchase Tax Account 8% IM
101290
@@ -348,7 +348,7 @@
- Purchase Tax Account 7% TX-RE
+ Purchase Tax Account 8% TX-RE
101300
@@ -356,7 +356,7 @@
- Purchase Tax Account 7% IGDS
+ Purchase Tax Account 8% IGDS
101310
@@ -404,7 +404,7 @@
- Purchase Tax Account 7% TX7
+ Purchase Tax Account 8% TX8
101370
@@ -412,7 +412,7 @@
- Purchase Tax Account 7% TXCA
+ Purchase Tax Account 8% TXCA
101380
@@ -708,7 +708,7 @@
- Sales Tax Account 7% DS
+ Sales Tax Account 8% DS
201180
@@ -740,7 +740,7 @@
- Sales Tax Account 7% SR
+ Sales Tax Account 8% SR
201220
@@ -756,7 +756,7 @@
- Sales Tax Account 7% SRCA-C
+ Sales Tax Account 8% SRCA-C
201240
diff --git a/addons/l10n_sg/migrations/2.1/post-migrate_update_tax.py b/addons/l10n_sg/migrations/2.1/post-migrate_update_tax.py
new file mode 100644
index 0000000000..6e9b576d51
--- /dev/null
+++ b/addons/l10n_sg/migrations/2.1/post-migrate_update_tax.py
@@ -0,0 +1,6 @@
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+from flectra.addons.account.models.chart_template import update_taxes_from_templates
+
+
+def migrate(cr, version):
+ update_taxes_from_templates(cr, 'l10n_sg.sg_chart_template')
diff --git a/addons/l10n_za/data/account.account.template.csv b/addons/l10n_za/data/account.account.template.csv
index 17fbef2b79..25fbcc5b77 100644
--- a/addons/l10n_za/data/account.account.template.csv
+++ b/addons/l10n_za/data/account.account.template.csv
@@ -109,4 +109,4 @@ id,code,name,user_type_id/id,reconcile,chart_template_id/id
620040,620040,Land and buildings Depreciation,account.data_account_type_depreciation,False,default_chart_template
620050,620050,Motor vehicles Depreciation,account.data_account_type_depreciation,False,default_chart_template
620060,620060,Office equipment (inc computer equipment) Depreciation,account.data_account_type_depreciation,False,default_chart_template
-620070,620070,Plant and machinery Depreciation,account.data_account_type_depreciation,False,default_chart_template
\ No newline at end of file
+620070,620070,Plant and machinery Depreciation,account.data_account_type_depreciation,False,default_chart_template
\ No newline at end of file
diff --git a/addons/mrp/models/stock_move.py b/addons/mrp/models/stock_move.py
index 60a0537b72..42ce2424da 100644
--- a/addons/mrp/models/stock_move.py
+++ b/addons/mrp/models/stock_move.py
@@ -238,6 +238,7 @@ class StockMove(models.Model):
def _action_confirm(self, merge=True, merge_into=False):
moves = self.action_explode()
+ merge_into = merge_into and merge_into.action_explode()
# we go further with the list of ids potentially changed by action_explode
return super(StockMove, moves)._action_confirm(merge=merge, merge_into=merge_into)
@@ -257,20 +258,23 @@ class StockMove(models.Model):
if not bom:
moves_ids_to_return.add(move.id)
continue
- if move.picking_id.immediate_transfer:
+ if move.picking_id.immediate_transfer or float_is_zero(move.product_uom_qty, precision_rounding=move.product_uom.rounding):
factor = move.product_uom._compute_quantity(move.quantity_done, bom.product_uom_id) / bom.product_qty
else:
factor = move.product_uom._compute_quantity(move.product_uom_qty, bom.product_uom_id) / bom.product_qty
boms, lines = bom.sudo().explode(move.product_id, factor, picking_type=bom.picking_type_id)
for bom_line, line_data in lines:
- if move.picking_id.immediate_transfer:
+ if move.picking_id.immediate_transfer or float_is_zero(move.product_uom_qty, precision_rounding=move.product_uom.rounding):
phantom_moves_vals_list += move._generate_move_phantom(bom_line, 0, line_data['qty'])
else:
phantom_moves_vals_list += move._generate_move_phantom(bom_line, line_data['qty'], 0)
# delete the move with original product which is not relevant anymore
moves_ids_to_unlink.add(move.id)
- self.env['stock.move'].browse(moves_ids_to_unlink).sudo().unlink()
+ move_to_unlink = self.env['stock.move'].browse(moves_ids_to_unlink).sudo()
+ move_to_unlink.quantity_done = 0
+ move_to_unlink._action_cancel()
+ move_to_unlink.unlink()
if phantom_moves_vals_list:
phantom_moves = self.env['stock.move'].create(phantom_moves_vals_list)
phantom_moves._adjust_procure_method()
@@ -319,7 +323,8 @@ class StockMove(models.Model):
if bom_line.product_id.type in ['product', 'consu']:
vals = self.copy_data(default=self._prepare_phantom_move_values(bom_line, product_qty, quantity_done))
if self.state == 'assigned':
- vals['state'] = 'assigned'
+ for v in vals:
+ v['state'] = 'assigned'
return vals
@api.model
diff --git a/addons/mrp/tests/test_stock.py b/addons/mrp/tests/test_stock.py
index 3486e17368..1bcb41a415 100644
--- a/addons/mrp/tests/test_stock.py
+++ b/addons/mrp/tests/test_stock.py
@@ -348,3 +348,46 @@ class TestKitPicking(common.TestMrpCommon):
self.assertEqual(len(picking.move_lines), 7)
for move_line in picking.move_lines:
self.assertEqual(move_line.product_qty, self.expected_quantities[move_line.product_id])
+
+ def test_add_sml_with_kit_to_confirmed_picking(self):
+ warehouse = self.env['stock.warehouse'].search([('company_id', '=', self.env.company.id)], limit=1)
+ customer_location = self.env.ref('stock.stock_location_customers')
+ stock_location = warehouse.lot_stock_id
+ in_type = warehouse.in_type_id
+
+ self.bom_4.type = 'phantom'
+ kit = self.bom_4.product_id
+ compo = self.bom_4.bom_line_ids.product_id
+ product = self.env['product.product'].create({'name': 'Super Product', 'type': 'product'})
+
+ receipt = self.env['stock.picking'].create({
+ 'picking_type_id': in_type.id,
+ 'location_id': customer_location.id,
+ 'location_dest_id': stock_location.id,
+ 'move_lines': [(0, 0, {
+ 'name': product.name,
+ 'product_id': product.id,
+ 'product_uom_qty': 1,
+ 'product_uom': product.uom_id.id,
+ 'location_id': customer_location.id,
+ 'location_dest_id': stock_location.id,
+ })]
+ })
+ receipt.action_confirm()
+
+ receipt.move_line_ids.qty_done = 1
+ receipt.move_line_ids = [(0, 0, {
+ 'product_id': kit.id,
+ 'qty_done': 1,
+ 'product_uom_id': kit.uom_id.id,
+ 'location_id': customer_location.id,
+ 'location_dest_id': stock_location.id,
+ })]
+
+ receipt.button_validate()
+
+ self.assertEqual(receipt.state, 'done')
+ self.assertRecordValues(receipt.move_lines, [
+ {'product_id': product.id, 'quantity_done': 1, 'state': 'done'},
+ {'product_id': compo.id, 'quantity_done': 1, 'state': 'done'},
+ ])
diff --git a/addons/mrp_account/tests/test_valuation_layers.py b/addons/mrp_account/tests/test_valuation_layers.py
index 4c6c7f71c5..03b3500bc7 100644
--- a/addons/mrp_account/tests/test_valuation_layers.py
+++ b/addons/mrp_account/tests/test_valuation_layers.py
@@ -276,3 +276,35 @@ class TestMrpValuationStandard(TestMrpValuationCommon):
self.assertEqual(self.product1.quantity_svl, 2)
self._make_out_move(self.product1, 1)
self.assertEqual(self.product1.value_svl, 15)
+
+ def test_validate_draft_kit(self):
+ """
+ Create a draft receipt, add a kit to its move lines and directly
+ validate it. From client side, such a behaviour is possible with
+ the Barcode app.
+ """
+ self.component.product_tmpl_id.categ_id.property_cost_method = 'average'
+ self.product1.type = 'consu'
+ self.bom.type = 'phantom'
+ self.component.standard_price = 1424
+
+ receipt = self.env['stock.picking'].create({
+ 'location_id': self.customer_location.id,
+ 'location_dest_id': self.stock_location.id,
+ 'picking_type_id': self.picking_type_in.id,
+ 'move_line_ids': [(0, 0, {
+ 'product_id': self.product1.id,
+ 'qty_done': 1,
+ 'product_uom_id': self.product1.uom_id.id,
+ 'location_id': self.customer_location.id,
+ 'location_dest_id': self.stock_location.id,
+ })]
+ })
+ receipt.button_validate()
+
+ self.assertEqual(receipt.state, 'done')
+ self.assertRecordValues(receipt.move_lines, [
+ {'product_id': self.component.id, 'quantity_done': 1, 'state': 'done'},
+ ])
+ self.assertEqual(self.component.qty_available, 1)
+ self.assertEqual(self.component.value_svl, 1424)
diff --git a/addons/snailmail/static/src/scss/snailmail_external_layout_asset.scss b/addons/snailmail/static/src/scss/snailmail_external_layout_asset.scss
index 2bff2d495c..8af3492646 100644
--- a/addons/snailmail/static/src/scss/snailmail_external_layout_asset.scss
+++ b/addons/snailmail/static/src/scss/snailmail_external_layout_asset.scss
@@ -1,14 +1,12 @@
/* Modifications for the Light and Boxed document layouts */
.article.o_report_layout_standard.o_company_1_layout, .article.o_report_layout_boxed.o_company_1_layout {
> .pt-5 {
+ padding-top: 0 !important;
> .address.row {
- width: 100% !important;
- height: 62mm !important;
+ width: 117% !important;
+ height: 68mm !important;
+ margin-top: -4mm !important;
line-height: 1.1em;
- margin-top: -13mm;
- > div[name="address"] {
- padding-top: 5mm;
- }
}
}
}
@@ -16,39 +14,36 @@
/* Modifications for Clean document layouts */
.article.o_report_layout_clean.o_company_1_layout {
> .address.row {
- width: 100% !important;
- height: 62mm !important;
+ width: 117% !important;
+ height: 68mm !important;
+ margin-top: -4mm !important;
line-height: 1.1em;
- > div[name="address"] {
- padding-top: 15mm !important;
- }
}
}
/* Modification for background document layouts */
.o_company_1_layout.article.o_report_layout_background {
> .address.row {
- background-color: #ffffff !important;
- width: 103% !important;
- height: 62mm !important;
+ width: 117% !important;
+ height: 68mm !important;
+ margin-top: -4mm !important;
line-height: 1.1em;
- > div[name="address"] {
- padding-top: 8mm !important;
- }
}
}
div .address.row > div[name="address"] {
position: relative !important;
- width: 103mm !important;
+ margin-left: 48.5% !important;
background-color: #ffffff;
- > address {
- width: 100% !important;
- position: absolute !important;
- bottom: 0 !important;
- padding-left: 3mm;
- padding-top: 3mm;
- height: 33mm;
- max-height: 33mm;
+ > address, div {
+ > address {
+ width: 100% !important;
+ position: absolute !important;
+ bottom: 0 !important;
+ padding-left: 3mm;
+ padding-top: 3mm;
+ height: 33mm;
+ max-height: 33mm;
+ }
}
}
diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py
index 7412297498..064dba504e 100644
--- a/addons/stock/models/stock_move.py
+++ b/addons/stock/models/stock_move.py
@@ -1515,8 +1515,8 @@ class StockMove(models.Model):
return extra_move | self
def _action_done(self, cancel_backorder=False):
- self.filtered(lambda move: move.state == 'draft')._action_confirm() # MRP allows scrapping draft moves
- moves = self.exists().filtered(lambda x: x.state not in ('done', 'cancel'))
+ moves = self.filtered(lambda move: move.state == 'draft')._action_confirm() # MRP allows scrapping draft moves
+ moves = (self | moves).exists().filtered(lambda x: x.state not in ('done', 'cancel'))
moves_todo = self.env['stock.move']
# Cancel moves where necessary ; we should do it before creating the extra moves because
diff --git a/addons/stock_account/models/stock_move.py b/addons/stock_account/models/stock_move.py
index b4d8c9b77e..d223927d93 100644
--- a/addons/stock_account/models/stock_move.py
+++ b/addons/stock_account/models/stock_move.py
@@ -256,6 +256,9 @@ class StockMove(models.Model):
res = super(StockMove, self)._action_done(cancel_backorder=cancel_backorder)
+ # '_action_done' might have deleted some exploded stock moves
+ valued_moves = {value_type: moves.exists() for value_type, moves in valued_moves.items()}
+
# '_action_done' might have created an extra move to be valued
for move in res - self:
for valued_type in self._get_valued_types():
diff --git a/addons/website/static/src/js/editor/snippets.options.js b/addons/website/static/src/js/editor/snippets.options.js
index 052afa111d..a0a12bf612 100644
--- a/addons/website/static/src/js/editor/snippets.options.js
+++ b/addons/website/static/src/js/editor/snippets.options.js
@@ -1585,17 +1585,6 @@ options.registry.sizing_x = options.registry.sizing.extend({
});
options.registry.layout_column = options.Class.extend({
- /**
- * @override
- */
- start: function () {
- // Needs to be done manually for now because _computeWidgetVisibility
- // doesn't go through this option for buttons inside of a select.
- // TODO: improve this.
- this.$el.find('we-button[data-name="zero_cols_opt"]')
- .toggleClass('d-none', !this.$target.is('.s_allow_columns'));
- return this._super(...arguments);
- },
//--------------------------------------------------------------------------
// Options
@@ -1640,6 +1629,20 @@ options.registry.layout_column = options.Class.extend({
}
return this._super(...arguments);
},
+ /**
+ * @override
+ */
+ _computeWidgetVisibility(widgetName, params) {
+ if (widgetName === 'zero_cols_opt') {
+ // Note: "s_allow_columns" indicates containers which may have
+ // bare content (without columns) and are allowed to have columns.
+ // By extension, we only show the "None" option on elements that
+ // were marked as such as they were allowed to have bare content in
+ // the first place.
+ return this.$target.is('.s_allow_columns');
+ }
+ return this._super(...arguments);
+ },
/**
* Adds new columns which are clones of the last column or removes the
* last x columns.