diff --git a/.tx/config b/.tx/config index 674a24a43df..c2a261b582b 100644 --- a/.tx/config +++ b/.tx/config @@ -142,6 +142,11 @@ file_filter = addons/base_import_module/i18n/.po source_file = addons/base_import_module/i18n/base_import_module.pot source_lang = en +[odoo-master.base_sparse_field] +file_filter = addons/base_sparse_field/i18n/.po +source_file = addons/base_sparse_field/i18n/base_sparse_field.pot +source_lang = en + [odoo-master.base_setup] file_filter = addons/base_setup/i18n/.po source_file = addons/base_setup/i18n/base_setup.pot @@ -892,6 +897,11 @@ file_filter = addons/website_sale/i18n/.po source_file = addons/website_sale/i18n/website_sale.pot source_lang = en +[odoo-master.website_sale_comparison] +file_filter = addons/website_sale_comparison/i18n/.po +source_file = addons/website_sale_comparison/i18n/website_sale_comparison.pot +source_lang = en + [odoo-master.website_sale_delivery] file_filter = addons/website_sale_delivery/i18n/.po source_file = addons/website_sale_delivery/i18n/website_sale_delivery.pot @@ -912,6 +922,11 @@ file_filter = addons/website_sale_stock/i18n/.po source_file = addons/website_sale_stock/i18n/website_sale_stock.pot source_lang = en +[odoo-master.website_sale_wishlist] +file_filter = addons/website_sale_wishlist/i18n/.po +source_file = addons/website_sale_wishlist/i18n/website_sale_wishlist.pot +source_lang = en + [odoo-master.website_slides] file_filter = addons/website_slides/i18n/.po source_file = addons/website_slides/i18n/website_slides.pot diff --git a/addons/account/models/account_bank_statement.py b/addons/account/models/account_bank_statement.py index 85bed6a05ad..5f1ae94b93a 100644 --- a/addons/account/models/account_bank_statement.py +++ b/addons/account/models/account_bank_statement.py @@ -910,7 +910,7 @@ class AccountBankStatementLine(models.Model): counterpart_moves = (counterpart_moves | move) # Create The payment - payment = False + payment = self.env['account.payment'] if abs(total)>0.00001: partner_id = self.partner_id and self.partner_id.id or False partner_type = False diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py index 37ec02186e9..522d459a47b 100644 --- a/addons/account/models/account_invoice.py +++ b/addons/account/models/account_invoice.py @@ -773,7 +773,7 @@ class AccountInvoice(models.Model): total_currency = 0 for line in invoice_move_lines: if self.currency_id != company_currency: - currency = self.currency_id.with_context(date=self.date_invoice or fields.Date.context_today(self)) + currency = self.currency_id.with_context(date=self.date or self.date_invoice or fields.Date.context_today(self)) if not (line.get('currency_id') and line.get('amount_currency')): line['currency_id'] = currency.id line['amount_currency'] = currency.round(line['price']) @@ -907,7 +907,6 @@ class AccountInvoice(models.Model): if not inv.date_invoice: inv.with_context(ctx).write({'date_invoice': fields.Date.context_today(self)}) - date_invoice = inv.date_invoice company_currency = inv.company_id.currency_id # create move lines (one per invoice line + eventual taxes and analytic lines) @@ -920,9 +919,9 @@ class AccountInvoice(models.Model): name = inv.name or '/' if inv.payment_term_id: - totlines = inv.with_context(ctx).payment_term_id.with_context(currency_id=company_currency.id).compute(total, date_invoice)[0] + totlines = inv.with_context(ctx).payment_term_id.with_context(currency_id=company_currency.id).compute(total, inv.date_invoice)[0] res_amount_currency = total_currency - ctx['date'] = date_invoice + ctx['date'] = inv.date or inv.date_invoice for i, t in enumerate(totlines): if inv.currency_id != company_currency: amount_currency = company_currency.with_context(ctx).compute(t[1], inv.currency_id) @@ -962,7 +961,7 @@ class AccountInvoice(models.Model): journal = inv.journal_id.with_context(ctx) line = inv.finalize_invoice_move_lines(line) - date = inv.date or date_invoice + date = inv.date or inv.date_invoice move_vals = { 'ref': inv.reference, 'line_ids': line, @@ -1578,6 +1577,12 @@ class AccountPaymentTerm(models.Model): result.append((last_date, dist)) return result + @api.multi + def unlink(self): + property_recs = self.env['ir.property'].search([('value_reference', 'in', ['account.payment.term,%s'%payment_term.id for payment_term in self])]) + property_recs.unlink() + return super(AccountPaymentTerm, self).unlink() + class AccountPaymentTermLine(models.Model): _name = "account.payment.term.line" diff --git a/addons/account/models/company.py b/addons/account/models/company.py index 44eee5432ae..584c1e44c99 100644 --- a/addons/account/models/company.py +++ b/addons/account/models/company.py @@ -57,10 +57,16 @@ Best Regards,''') if (date.month < last_month or (date.month == last_month and date.day <= last_day)): date = date.replace(month=last_month, day=last_day) else: - date = date.replace(month=last_month, day=last_day, year=date.year + 1) + if last_month == 2 and last_day == 29 and (date.year + 1) % 4 != 0: + date = date.replace(month=last_month, day=28, year=date.year + 1) + else: + date = date.replace(month=last_month, day=last_day, year=date.year + 1) date_to = date date_from = date + timedelta(days=1) - date_from = date_from.replace(year=date_from.year - 1) + if date_from.month == 2 and date_from.day == 29: + date_from = date_from.replace(day=28, year=date_from.year - 1) + else: + date_from = date_from.replace(year=date_from.year - 1) return {'date_from': date_from, 'date_to': date_to} def get_new_account_code(self, current_code, old_prefix, new_prefix, digits): diff --git a/addons/account/report/account_aged_partner_balance.py b/addons/account/report/account_aged_partner_balance.py index 3380f876d63..fd2fef466fb 100644 --- a/addons/account/report/account_aged_partner_balance.py +++ b/addons/account/report/account_aged_partner_balance.py @@ -198,7 +198,7 @@ class ReportAgedPartnerBalance(models.AbstractModel): @api.model def get_report_values(self, docids, data=None): if not data.get('form') or not self.env.context.get('active_model') or not self.env.context.get('active_id'): - raise UserError(_("Some data are missing, this report cannot be printed.")) + raise UserError(_("Form content is missing, this report cannot be printed.")) total = [] model = self.env.context.get('active_model') diff --git a/addons/account/report/account_balance.py b/addons/account/report/account_balance.py index e8280c90128..fd4ae5d0379 100644 --- a/addons/account/report/account_balance.py +++ b/addons/account/report/account_balance.py @@ -61,7 +61,7 @@ class ReportTrialBalance(models.AbstractModel): @api.model def get_report_values(self, docids, data=None): if not data.get('form') or not self.env.context.get('active_model'): - raise UserError(_("Some data are missing, this report cannot be printed.")) + raise UserError(_("Form content is missing, this report cannot be printed.")) self.model = self.env.context.get('active_model') docs = self.env[self.model].browse(self.env.context.get('active_ids', [])) diff --git a/addons/account/report/account_general_ledger.py b/addons/account/report/account_general_ledger.py index 1bd983a68ae..c817d300664 100644 --- a/addons/account/report/account_general_ledger.py +++ b/addons/account/report/account_general_ledger.py @@ -111,7 +111,7 @@ class ReportGeneralLedger(models.AbstractModel): @api.model def get_report_values(self, docids, data=None): if not data.get('form') or not self.env.context.get('active_model'): - raise UserError(_("Some data are missing, this report cannot be printed.")) + raise UserError(_("Form content is missing, this report cannot be printed.")) self.model = self.env.context.get('active_model') docs = self.env[self.model].browse(self.env.context.get('active_ids', [])) diff --git a/addons/account/report/account_journal.py b/addons/account/report/account_journal.py index 0bb9bcedb99..7ae49486fbf 100644 --- a/addons/account/report/account_journal.py +++ b/addons/account/report/account_journal.py @@ -97,7 +97,7 @@ class ReportJournal(models.AbstractModel): @api.model def get_report_values(self, docids, data=None): if not data.get('form'): - raise UserError(_("Some data are missing, this report cannot be printed.")) + raise UserError(_("Form content is missing, this report cannot be printed.")) target_move = data['form'].get('target_move', 'all') sort_selection = data['form'].get('sort_selection', 'date') diff --git a/addons/account/report/account_partner_ledger.py b/addons/account/report/account_partner_ledger.py index f22ef71527c..1775eba10ad 100644 --- a/addons/account/report/account_partner_ledger.py +++ b/addons/account/report/account_partner_ledger.py @@ -71,7 +71,7 @@ class ReportPartnerLedger(models.AbstractModel): @api.model def get_report_values(self, docids, data=None): if not data.get('form'): - raise UserError(_("Some data are missing, this report cannot be printed.")) + raise UserError(_("Form content is missing, this report cannot be printed.")) data['computed'] = {} diff --git a/addons/account/report/account_report_financial.py b/addons/account/report/account_report_financial.py index b0abf69de3d..803abe9b890 100644 --- a/addons/account/report/account_report_financial.py +++ b/addons/account/report/account_report_financial.py @@ -147,7 +147,7 @@ class ReportFinancial(models.AbstractModel): @api.model def get_report_values(self, docids, data=None): if not data.get('form') or not self.env.context.get('active_model') or not self.env.context.get('active_id'): - raise UserError(_("Some data are missing, this report cannot be printed.")) + raise UserError(_("Form content is missing, this report cannot be printed.")) self.model = self.env.context.get('active_model') docs = self.env[self.model].browse(self.env.context.get('active_id')) diff --git a/addons/account/views/web_planner_data.xml b/addons/account/views/web_planner_data.xml index 690d160f23e..d07827629c5 100644 --- a/addons/account/views/web_planner_data.xml +++ b/addons/account/views/web_planner_data.xml @@ -200,7 +200,7 @@

diff --git a/addons/account_bank_statement_import/account_bank_statement_import.py b/addons/account_bank_statement_import/account_bank_statement_import.py index 07ab4c7dc6e..9056b7af916 100644 --- a/addons/account_bank_statement_import/account_bank_statement_import.py +++ b/addons/account_bank_statement_import/account_bank_statement_import.py @@ -223,7 +223,7 @@ class AccountBankStatementImport(models.TransientModel): else: ignored_statement_lines_import_ids.append(line_vals['unique_import_id']) if 'balance_start' in st_vals: - st_vals['balance_start'] += line_vals['amount'] + st_vals['balance_start'] += float(line_vals['amount']) if len(filtered_st_lines) > 0: # Remove values that won't be used to create records diff --git a/addons/delivery/models/delivery_grid.py b/addons/delivery/models/delivery_grid.py index 49678160fec..8f5c0ab347e 100644 --- a/addons/delivery/models/delivery_grid.py +++ b/addons/delivery/models/delivery_grid.py @@ -58,7 +58,7 @@ class ProviderGrid(models.Model): price_unit = order.company_id.currency_id.with_context(date=order.date_order).compute(price_unit, order.pricelist_id.currency_id) return {'success': True, - 'price': self.fixed_price, + 'price': price_unit, 'error_message': False, 'warning_message': False} diff --git a/addons/fleet/views/fleet_vehicle_model_views.xml b/addons/fleet/views/fleet_vehicle_model_views.xml index da4027f01d7..20d66fd232b 100644 --- a/addons/fleet/views/fleet_vehicle_model_views.xml +++ b/addons/fleet/views/fleet_vehicle_model_views.xml @@ -126,7 +126,7 @@
- +

diff --git a/addons/fleet/views/fleet_vehicle_views.xml b/addons/fleet/views/fleet_vehicle_views.xml index 699d06a877b..4355823971e 100644 --- a/addons/fleet/views/fleet_vehicle_views.xml +++ b/addons/fleet/views/fleet_vehicle_views.xml @@ -183,7 +183,7 @@

- +
@@ -397,4 +397,4 @@ - \ No newline at end of file + diff --git a/addons/gamification/data/goal_base.xml b/addons/gamification/data/goal_base.xml index 06aede03c49..3b983ebd256 100644 --- a/addons/gamification/data/goal_base.xml +++ b/addons/gamification/data/goal_base.xml @@ -20,76 +20,242 @@ Simple Challenge Report Progress - - ${object.name} -

-

The following message contains the current progress for the challenge ${object.name}

- -% if object.visibility_mode == 'personal': - - - - - - - - % for line in ctx["challenge_lines"]: - = 100: - style="font-weight:bold;" - % endif - > - - - - - - % endfor -
GoalTargetCurrentCompleteness
${line['name']}${line['target']} - % if line['suffix']: - ${line['suffix']} - % endif - ${line['current']} - % if line['suffix']: - ${line['suffix']} - % endif - ${line['completeness']} %
-% else: - % for line in ctx["challenge_lines"]: - - - - - - - - - - - % for goal in line['goals']: - = 100: - style="font-weight:bold;" - % endif - > - - - - - - % endfor + + + + + +
${line['name']}
#PersonCompletenessCurrent
${goal['rank']}${goal['name']}${goal['completeness']}%${goal['current']}/${line['target']} - % if line['suffix']: - ${line['suffix']} - % endif -
+ +
+ + + + % if object.visibility_mode == 'ranking': + + % endif + +
+ + +

Leaderboard

+
+ + +
+ % if object.visibility_mode == 'personal': + Here is your current progress in the challenge ${object.name}. + + + + +
+

Personal Performance

+
+ + + + + + + + + + + + + + % for line in challenge_lines: + = 100: + style="font-weight:bold;" + % endif + > + + + + + + + + + % endfor + +
GoalsTargetCurrentCompleteness
+ ${line['name']} + % if line['suffix'] or line['monetary']: + (${line['full_suffix']}) + % endif + ${"%.2f" % line['target']} + % if line['suffix']: + ${line['suffix']} + % endif + ${"%.2f" % line['current']} + % if line['suffix']: + ${line['suffix']} + % endif + ${line['completeness']| int}%
+ % else: + + The following message contains the current progress for the challenge ${object.name}. + + % for line in challenge_lines: + + + + + +
+

Top Achievers for goal ${line['name']}

+
+ + % if len(line['goals'])>2: + + + +
+ + + % set top_goals = [line['goals'][1], line['goals'][0], line['goals'][2]] + % for goal in top_goals: + + % endfor + +
+ % if loop.index == 1: + % set extra_div = '
' + % set heightA = 95 + % set heightB = 75 + % set bgColor = '#b898b0' + % set fontSize = 50 + % set podiumPosition = '2' + % elif loop.index == 2: + % set extra_div = '' + % set heightA = 55 + % set heightB = 115 + % set bgColor = '#9A6C8E' + % set fontSize = 85 + % set podiumPosition = '1' + % elif loop.index == 3: + % set extra_div = '
' + % set heightA = 115 + % set heightB = 55 + % set bgColor = '#c8afc1' + % set fontSize = 35 + % set podiumPosition = '3' + % endif +
+
+ ${extra_div | safe} +
+ +
+
+ ${goal['name']} +
+
+ ${podiumPosition | safe} +
+
+

+ ${"%.2f" % goal['current']} + % if line['suffix'] or line['monetary']: + ${line['full_suffix']} + % endif +

+
+
+
+
+ % endif + + + + + +
+ + + + + + + + + + + + + + % for goal in line['goals']: + + % set tdBgColor = '#fff' + % set tdColor = 'gray' + % set mutedColor = '#AAAAAA' + % set tdPercentageColor = '#9A6C8E' + + + + + + + + + % endfor + +
RankNamePerformance + % if line['suffix']: + (${line['suffix']}) + % elif line['monetary']: + (${company.currency_id.symbol}) + % endif + Completeness
${goal['rank']+1} + ${goal['name']}${"%.2f" % goal['current']}
on ${"%.2f" % line['target']} +
${goal['completeness'] | int}%
+
+ % endfor + % endif +
+ + + + + + + +
+ + + + + +
+ ${company.name}
+ ${company.phone or ''} +
+ % if company.email: + ${company.email}
+ % endif + % if company.website: + + ${company.website} + + % endif +
+
+ Powered by Odoo. +
+
+
+ ]]> -

- - % endfor -% endif - ]]>
+
diff --git a/addons/hr/views/hr_views.xml b/addons/hr/views/hr_views.xml index e910db920e6..c5392a8f55d 100644 --- a/addons/hr/views/hr_views.xml +++ b/addons/hr/views/hr_views.xml @@ -177,7 +177,7 @@
- +
diff --git a/addons/hr_attendance/views/hr_employee_view.xml b/addons/hr_attendance/views/hr_employee_view.xml index 25b307b1c0d..b187f370f60 100644 --- a/addons/hr_attendance/views/hr_employee_view.xml +++ b/addons/hr_attendance/views/hr_employee_view.xml @@ -42,7 +42,7 @@
- +
diff --git a/addons/hr_expense/data/hr_expense_data.xml b/addons/hr_expense/data/hr_expense_data.xml index b922a38d43c..100282658a8 100644 --- a/addons/hr_expense/data/hr_expense_data.xml +++ b/addons/hr_expense/data/hr_expense_data.xml @@ -44,7 +44,7 @@ Submitted hr.expense.sheet Expense report submitted, waiting approval - + Paid diff --git a/addons/hr_expense/models/hr_expense.py b/addons/hr_expense/models/hr_expense.py index 70f44d413fb..cdcf25b491f 100644 --- a/addons/hr_expense/models/hr_expense.py +++ b/addons/hr_expense/models/hr_expense.py @@ -30,7 +30,8 @@ class HrExpense(models.Model): company_id = fields.Many2one('res.company', string='Company', readonly=True, states={'draft': [('readonly', False)], 'refused': [('readonly', False)]}, default=lambda self: self.env.user.company_id) currency_id = fields.Many2one('res.currency', string='Currency', readonly=True, states={'draft': [('readonly', False)], 'refused': [('readonly', False)]}, default=lambda self: self.env.user.company_id.currency_id) analytic_account_id = fields.Many2one('account.analytic.account', string='Analytic Account', states={'post': [('readonly', True)], 'done': [('readonly', True)]}, oldname='analytic_account') - account_id = fields.Many2one('account.account', string='Account', states={'post': [('readonly', True)], 'done': [('readonly', True)]}, default=lambda self: self.env['ir.property'].get('property_account_expense_categ_id', 'product.category')) + account_id = fields.Many2one('account.account', string='Account', states={'post': [('readonly', True)], 'done': [('readonly', True)]}, default=lambda self: self.env['ir.property'].get('property_account_expense_categ_id', 'product.category'), + help="An expense account is expected") description = fields.Text() payment_mode = fields.Selection([("own_account", "Employee (to reimburse)"), ("company_account", "Company")], default='own_account', states={'done': [('readonly', True)], 'post': [('readonly', True)]}, string="Payment By") attachment_number = fields.Integer(compute='_compute_attachment_number', string='Number of Attachments') @@ -419,10 +420,15 @@ class HrExpenseSheet(models.Model): @api.model def create(self, vals): + # Add the followers at creation, so they can be notified + if vals.get('employee_id'): + employee = self.env['hr.employee'].browse(vals['employee_id']) + users = self._get_users_to_subscribe(employee=employee) - self.env.user + vals['message_follower_ids'] = [] + for partner in users.mapped('partner_id'): + vals['message_follower_ids'] += self.env['mail.followers']._add_follower_command(self._name, [], {partner.id: None}, {})[0] sheet = super(HrExpenseSheet, self).create(vals) self.check_consistency() - if vals.get('employee_id'): - sheet._add_followers() return sheet @api.multi @@ -457,16 +463,20 @@ class HrExpenseSheet(models.Model): return 'hr_expense.mt_expense_paid' return super(HrExpenseSheet, self)._track_subtype(init_values) - def _add_followers(self): - user_ids = [] - employee = self.employee_id + def _get_users_to_subscribe(self, employee=False): + users = self.env['res.users'] + employee = employee or self.employee_id if employee.user_id: - user_ids.append(employee.user_id.id) + users |= employee.user_id if employee.parent_id: - user_ids.append(employee.parent_id.user_id.id) + users |= employee.parent_id.user_id if employee.department_id and employee.department_id.manager_id and employee.parent_id != employee.department_id.manager_id: - user_ids.append(employee.department_id.manager_id.user_id.id) - self.message_subscribe_users(user_ids=user_ids) + users |= employee.department_id.manager_id.user_id + return users + + def _add_followers(self): + users = self._get_users_to_subscribe() + self.message_subscribe_users(user_ids=users.ids) @api.onchange('employee_id') def _onchange_employee_id(self): diff --git a/addons/hr_expense/views/hr_expense_views.xml b/addons/hr_expense/views/hr_expense_views.xml index d00772c22c2..20d3fb741e1 100644 --- a/addons/hr_expense/views/hr_expense_views.xml +++ b/addons/hr_expense/views/hr_expense_views.xml @@ -60,7 +60,7 @@ - + diff --git a/addons/hr_holidays/report/holidays_summary_report.py b/addons/hr_holidays/report/holidays_summary_report.py index e9e166dc3a7..9d1def98339 100644 --- a/addons/hr_holidays/report/holidays_summary_report.py +++ b/addons/hr_holidays/report/holidays_summary_report.py @@ -109,7 +109,7 @@ class HrHolidaySummaryReport(models.AbstractModel): @api.model def get_report_values(self, docids, data=None): if not data.get('form'): - raise UserError(_("Some data are missing, this report cannot be printed.")) + raise UserError(_("Form content is missing, this report cannot be printed.")) holidays_report = self.env['ir.actions.report']._get_report_from_name('hr_holidays.report_holidayssummary') holidays = self.env['hr.holidays'].browse(self.ids) diff --git a/addons/hr_payroll/report/report_contribution_register.py b/addons/hr_payroll/report/report_contribution_register.py index 27b0612e5f1..5023b1213e3 100644 --- a/addons/hr_payroll/report/report_contribution_register.py +++ b/addons/hr_payroll/report/report_contribution_register.py @@ -31,7 +31,7 @@ class ContributionRegisterReport(models.AbstractModel): @api.model def get_report_values(self, docids, data=None): if not data.get('form'): - raise UserError(_("Some data are missing, this report cannot be printed.")) + raise UserError(_("Form content is missing, this report cannot be printed.")) register_ids = self.env.context.get('active_ids', []) contrib_registers = self.env['hr.contribution.register'].browse(register_ids) diff --git a/addons/im_livechat/views/im_livechat_channel_views.xml b/addons/im_livechat/views/im_livechat_channel_views.xml index 0513e7472ef..e5af9e925f2 100644 --- a/addons/im_livechat/views/im_livechat_channel_views.xml +++ b/addons/im_livechat/views/im_livechat_channel_views.xml @@ -36,7 +36,7 @@
- +
@@ -108,7 +108,7 @@
X
-

diff --git a/addons/l10n_fr/data/account_chart_template_data.xml b/addons/l10n_fr/data/account_chart_template_data.xml index 59fb761390d..aea92e3e02f 100644 --- a/addons/l10n_fr/data/account_chart_template_data.xml +++ b/addons/l10n_fr/data/account_chart_template_data.xml @@ -2928,6 +2928,7 @@ Coupons échus à l'encaissement 5111 + @@ -2935,6 +2936,7 @@ Chèques à encaisser 5112 + @@ -2942,6 +2944,7 @@ Effets à l'encaissement 5113 + @@ -2949,6 +2952,7 @@ Effets à l'escompte 5114 + diff --git a/addons/l10n_in_hr_payroll/report/report_hr_salary_employee_bymonth.py b/addons/l10n_in_hr_payroll/report/report_hr_salary_employee_bymonth.py index 16e17b2fbba..c1c426c1574 100644 --- a/addons/l10n_in_hr_payroll/report/report_hr_salary_employee_bymonth.py +++ b/addons/l10n_in_hr_payroll/report/report_hr_salary_employee_bymonth.py @@ -95,7 +95,7 @@ class ReportHrSalaryEmployeeBymonth(models.AbstractModel): @api.model def get_report_values(self, docids, data=None): if not data.get('form') or not self.env.context.get('active_model') or not self.env.context.get('active_id'): - raise UserError(_("Some data are missing, this report cannot be printed.")) + raise UserError(_("Form content is missing, this report cannot be printed.")) model = self.env.context.get('active_model') docs = self.env[model].browse(self.env.context.get('active_id')) diff --git a/addons/l10n_in_hr_payroll/report/report_hr_yearly_salary_detail.py b/addons/l10n_in_hr_payroll/report/report_hr_yearly_salary_detail.py index 38cee62d220..43e00295f33 100644 --- a/addons/l10n_in_hr_payroll/report/report_hr_yearly_salary_detail.py +++ b/addons/l10n_in_hr_payroll/report/report_hr_yearly_salary_detail.py @@ -130,7 +130,7 @@ class EmployeesYearlySalaryReport(models.AbstractModel): @api.model def get_report_values(self, docids, data=None): if not self.env.context.get('active_model') or not self.env.context.get('active_id'): - raise UserError(_("Some data are missing, this report cannot be printed.")) + raise UserError(_("Form content is missing, this report cannot be printed.")) model = self.env.context.get('active_model') docs = self.env[model].browse(self.env.context.get('active_id')) diff --git a/addons/mail/views/mail_channel_views.xml b/addons/mail/views/mail_channel_views.xml index f319b86122e..d31c585eb39 100644 --- a/addons/mail/views/mail_channel_views.xml +++ b/addons/mail/views/mail_channel_views.xml @@ -61,7 +61,7 @@
- +

#

diff --git a/addons/mass_mailing/models/mail_mail.py b/addons/mass_mailing/models/mail_mail.py index 1772cdaf1ff..e5072060fd5 100644 --- a/addons/mass_mailing/models/mail_mail.py +++ b/addons/mass_mailing/models/mail_mail.py @@ -60,15 +60,14 @@ class MailMail(models.Model): self.ensure_one() body = super(MailMail, self).send_get_mail_body(partner=partner) - links_blacklist = ['/unsubscribe_from_list'] - if self.mailing_id and body and self.statistics_ids: for match in re.findall(URL_REGEX, self.body_html): - href = match[0] url = match[1] - if not [s for s in links_blacklist if s in href]: + parsed = urlparse.urlparse(url, scheme='http') + + if parsed.scheme.startswith('http') and parsed.path.startswith('/r/'): new_href = href.replace(url, url + '/m/' + str(self.statistics_ids[0].id)) body = body.replace(href, new_href) diff --git a/addons/mass_mailing/models/mail_thread.py b/addons/mass_mailing/models/mail_thread.py index 8e515a664f8..ee5fb45f6eb 100644 --- a/addons/mass_mailing/models/mail_thread.py +++ b/addons/mass_mailing/models/mail_thread.py @@ -39,3 +39,13 @@ class MailThread(models.AbstractModel): message_ids = [x.strip() for x in decode_smtp_header(message['References']).split()] self.env['mail.mail.statistics'].set_replied(mail_message_ids=message_ids) return super(MailThread, self).message_route_process(message, message_dict, routes) + + @api.multi + def message_post_with_template(self, template_id, **kwargs): + # avoid having message send through `message_post*` methods being implicitly considered as + # mass-mailing + no_massmail = self.with_context( + default_mass_mailing_name=False, + default_mass_mailing_id=False, + ) + return super(MailThread, no_massmail).message_post_with_template(template_id, **kwargs) diff --git a/addons/mrp_repair/models/mrp_repair.py b/addons/mrp_repair/models/mrp_repair.py index a098d0b08fa..0fab1440d12 100644 --- a/addons/mrp_repair/models/mrp_repair.py +++ b/addons/mrp_repair/models/mrp_repair.py @@ -263,11 +263,12 @@ class Repair(models.Model): return self.env.ref('mrp_repair.action_report_mrp_repair_order').report_action(self) def action_repair_invoice_create(self): - self.action_invoice_create() - if self.invoice_method == 'b4repair': - self.action_repair_ready() - elif self.invoice_method == 'after_repair': - self.write({'state': 'done'}) + for repair in self: + repair.action_invoice_create() + if repair.invoice_method == 'b4repair': + repair.action_repair_ready() + elif repair.invoice_method == 'after_repair': + repair.write({'state': 'done'}) return True @api.multi diff --git a/addons/pad/py_etherpad/__init__.py b/addons/pad/py_etherpad/__init__.py index d1040cec852..fc9721eb9c8 100644 --- a/addons/pad/py_etherpad/__init__.py +++ b/addons/pad/py_etherpad/__init__.py @@ -30,7 +30,7 @@ class EtherpadLiteClient: params = arguments or {} params['apikey'] = self.apiKey - r = requests.get(url, data=params, timeout=self.TIMEOUT) + r = requests.post(url, data=params, timeout=self.TIMEOUT) r.raise_for_status() return self.handleResult(r.json()) diff --git a/addons/payment/views/payment_views.xml b/addons/payment/views/payment_views.xml index 82606809f5d..c626657bc42 100644 --- a/addons/payment/views/payment_views.xml +++ b/addons/payment/views/payment_views.xml @@ -140,7 +140,7 @@

- +

diff --git a/addons/payment_authorize/models/payment.py b/addons/payment_authorize/models/payment.py index dfa181b2e81..184f07cdc58 100644 --- a/addons/payment_authorize/models/payment.py +++ b/addons/payment_authorize/models/payment.py @@ -256,14 +256,14 @@ class TxAuthorize(models.Model): def authorize_s2s_capture_transaction(self): self.ensure_one() transaction = AuthorizeAPI(self.acquirer_id) - tree = transaction.capture(self.acquirer_reference, self.amount) + tree = transaction.capture(self.acquirer_reference or '', self.amount) return self._authorize_s2s_validate_tree(tree) @api.multi def authorize_s2s_void_transaction(self): self.ensure_one() transaction = AuthorizeAPI(self.acquirer_id) - tree = transaction.void(self.acquirer_reference) + tree = transaction.void(self.acquirer_reference or '') return self._authorize_s2s_validate_tree(tree) @api.multi diff --git a/addons/point_of_sale/models/pos_order.py b/addons/point_of_sale/models/pos_order.py index 482ca1d809a..f848a64cbe1 100644 --- a/addons/point_of_sale/models/pos_order.py +++ b/addons/point_of_sale/models/pos_order.py @@ -649,7 +649,7 @@ class PosOrder(models.Model): return_picking = Picking.create(return_vals) return_picking.message_post(body=message) - for line in order.lines.filtered(lambda l: l.product_id.type in ['product', 'consu'] and l.qty != 0): + for line in order.lines.filtered(lambda l: l.product_id.type in ['product', 'consu'] and not float_is_zero(l.qty, precision_digits=l.product_id.uom_id.rounding)): moves |= Move.create({ 'name': line.name, 'product_uom': line.product_id.uom_id.id, diff --git a/addons/point_of_sale/models/pos_session.py b/addons/point_of_sale/models/pos_session.py index 67d9ca973a0..d9f38720fd4 100644 --- a/addons/point_of_sale/models/pos_session.py +++ b/addons/point_of_sale/models/pos_session.py @@ -296,7 +296,7 @@ class PosSession(models.Model): if not self.ids: return {} for session in self.filtered(lambda s: s.user_id.id != self.env.uid): - raise UserError(_("You cannot use the session of another users. This session is owned by %s. " + raise UserError(_("You cannot use the session of another user. This session is owned by %s. " "Please first close this one to use this point of sale.") % session.user_id.name) return { 'type': 'ir.actions.act_url', diff --git a/addons/point_of_sale/static/src/js/chrome.js b/addons/point_of_sale/static/src/js/chrome.js index 150a6930835..3d95af17a61 100644 --- a/addons/point_of_sale/static/src/js/chrome.js +++ b/addons/point_of_sale/static/src/js/chrome.js @@ -270,7 +270,7 @@ var DebugWidget = PosBaseWidget.extend({ this.$('.button.delete_unpaid_orders').click(function(){ self.gui.show_popup('confirm',{ 'title': _t('Delete Unpaid Orders ?'), - 'body': _t('This operation will permanently destroy all unpaid orders from all sessions that have been put in the local storage. You will lose all the data and exit the point of sale. This operation cannot be undone.'), + 'body': _t('This operation will destroy all unpaid orders in the browser. You will lose all the unsaved data and exit the point of sale. This operation cannot be undone.'), confirm: function(){ self.pos.db.remove_all_unpaid_orders(); window.location = '/'; diff --git a/addons/point_of_sale/views/pos_order_report_view.xml b/addons/point_of_sale/views/pos_order_report_view.xml index 1ca45a9f5ce..f15704b891a 100644 --- a/addons/point_of_sale/views/pos_order_report_view.xml +++ b/addons/point_of_sale/views/pos_order_report_view.xml @@ -33,7 +33,7 @@ - + diff --git a/addons/product/views/product_template_views.xml b/addons/product/views/product_template_views.xml index f3316c537d9..96c3bfe333f 100644 --- a/addons/product/views/product_template_views.xml +++ b/addons/product/views/product_template_views.xml @@ -75,7 +75,7 @@
- +
diff --git a/addons/product/views/product_views.xml b/addons/product/views/product_views.xml index eef7edbe839..af0981744d1 100644 --- a/addons/product/views/product_views.xml +++ b/addons/product/views/product_views.xml @@ -349,7 +349,7 @@
- +
diff --git a/addons/purchase/models/purchase.py b/addons/purchase/models/purchase.py index 8b8cc4c250e..ff3728753fc 100644 --- a/addons/purchase/models/purchase.py +++ b/addons/purchase/models/purchase.py @@ -650,7 +650,7 @@ class PurchaseOrderLine(models.Model): move.state = 'draft' move.unlink() else: - raise UserError('You cannot decrease the ordered quantity below your receipt.\n' + raise UserError('You cannot decrease the ordered quantity below the received quantity.\n' 'Create a return first.') @api.multi diff --git a/addons/sale/models/sale_analytic.py b/addons/sale/models/sale_analytic.py index cad770f842d..733bd74bc2a 100644 --- a/addons/sale/models/sale_analytic.py +++ b/addons/sale/models/sale_analytic.py @@ -12,27 +12,20 @@ class SaleOrderLine(models.Model): @api.multi def _compute_analytic(self, domain=None): lines = {} + force_so_lines = self.env.context.get("force_so_lines") if not domain: + if not self.ids and not force_so_lines: + return True # To filter on analyic lines linked to an expense expense_type_id = self.env.ref('account.data_account_type_expenses', raise_if_not_found=False) expense_type_id = expense_type_id and expense_type_id.id - domain = [ - ('so_line', 'in', self.ids), - '|', - ('amount', '<', 0), - '&', - ('amount', '=', 0), - '|', - ('move_id', '=', False), - ('move_id.account_id.user_type_id', '=', expense_type_id) - ] + domain = [('so_line', 'in', self.ids), ('amount', '<=', 0.0)] data = self.env['account.analytic.line'].read_group( domain, ['so_line', 'unit_amount', 'product_uom_id'], ['product_uom_id', 'so_line'], lazy=False ) # If the unlinked analytic line was the last one on the SO line, the qty was not updated. - force_so_lines = self.env.context.get("force_so_lines") if force_so_lines: for line in force_so_lines: lines.setdefault(line, 0.0) diff --git a/addons/sale/models/sale_config_settings.py b/addons/sale/models/sale_config_settings.py index 50c0c2d80aa..e7c3f6eac54 100644 --- a/addons/sale/models/sale_config_settings.py +++ b/addons/sale/models/sale_config_settings.py @@ -138,7 +138,7 @@ class SaleConfigSettings(models.TransientModel): use_sale_note=self.env['ir.config_parameter'].sudo().get_param('sale.use_sale_note', default=False), auto_done_setting=self.env['ir.config_parameter'].sudo().get_param('sale.auto_done_setting'), default_deposit_product_id=self.env['ir.config_parameter'].sudo().get_param('sale.default_deposit_product_id'), - sale_show_tax=self.group_show_price_total and 'total' or 'subtotal', + sale_show_tax=self.env['ir.config_parameter'].sudo().get_param('sale.sale_show_tax', default='subtotal'), multi_sales_price=sale_pricelist_setting in ['percentage', 'formula'], multi_sales_price_method=sale_pricelist_setting in ['percentage', 'formula'] and sale_pricelist_setting or False, sale_pricelist_setting=sale_pricelist_setting, @@ -152,3 +152,4 @@ class SaleConfigSettings(models.TransientModel): self.env['ir.config_parameter'].sudo().set_param("sale.auto_done_setting", self.auto_done_setting) self.env['ir.config_parameter'].sudo().set_param("sale.default_deposit_product_id", self.default_deposit_product_id.id) self.env['ir.config_parameter'].sudo().set_param('sale.sale_pricelist_setting', self.sale_pricelist_setting) + self.env['ir.config_parameter'].sudo().set_param('sale.sale_show_tax', self.sale_show_tax) diff --git a/addons/sale/wizard/sale_make_invoice_advance.py b/addons/sale/wizard/sale_make_invoice_advance.py index fe4b541d1b7..01cf2225a95 100644 --- a/addons/sale/wizard/sale_make_invoice_advance.py +++ b/addons/sale/wizard/sale_make_invoice_advance.py @@ -113,6 +113,7 @@ class SaleAdvancePaymentInv(models.TransientModel): 'payment_term_id': order.payment_term_id.id, 'fiscal_position_id': order.fiscal_position_id.id or order.partner_id.property_account_position_id.id, 'team_id': order.team_id.id, + 'user_id': order.user_id.id, 'comment': order.note, }) invoice.compute_taxes() diff --git a/addons/sale_timesheet/models/sale_order.py b/addons/sale_timesheet/models/sale_order.py index 0254c3dbe0e..0db9b0c0632 100644 --- a/addons/sale_timesheet/models/sale_order.py +++ b/addons/sale_timesheet/models/sale_order.py @@ -140,20 +140,9 @@ class SaleOrderLine(models.Model): @api.multi def _compute_analytic(self, domain=None): - if not domain: + if not domain and self.ids: # To filter on analyic lines linked to an expense expense_type_id = self.env.ref('account.data_account_type_expenses', raise_if_not_found=False) expense_type_id = expense_type_id and expense_type_id.id - domain = [ - ('so_line', 'in', self.ids), - '|', - '|', - ('amount', '<', 0.0), - ('project_id', '!=', False), - '&', - ('amount', '=', 0), - '|', - ('move_id', '=', False), - ('move_id.account_id.user_type_id', '=', expense_type_id) - ] + domain = [('so_line', 'in', self.ids), '|', ('amount', '<=', 0.0), ('project_id', '!=', False)] return super(SaleOrderLine, self)._compute_analytic(domain=domain) diff --git a/addons/sales_team/views/crm_team_views.xml b/addons/sales_team/views/crm_team_views.xml index 27b14712f61..30bed47bd91 100644 --- a/addons/sales_team/views/crm_team_views.xml +++ b/addons/sales_team/views/crm_team_views.xml @@ -105,7 +105,7 @@
X
- +
diff --git a/addons/stock/models/product.py b/addons/stock/models/product.py index 4adc64a0880..6b43afdcaaa 100644 --- a/addons/stock/models/product.py +++ b/addons/stock/models/product.py @@ -21,8 +21,6 @@ OPERATORS = { class Product(models.Model): _inherit = "product.product" - reception_count = fields.Integer('Receipt', compute='_compute_reception_count') - delivery_count = fields.Integer('Delivery', compute='_compute_delivery_count') stock_quant_ids = fields.One2many('stock.quant', 'product_id', help='Technical: used to compute quantities.') stock_move_ids = fields.One2many('stock.move', 'product_id', help='Technical: used to compute quantities.') qty_available = fields.Float( @@ -78,26 +76,6 @@ class Product(models.Model): reordering_min_qty = fields.Float(compute='_compute_nbr_reordering_rules') reordering_max_qty = fields.Float(compute='_compute_nbr_reordering_rules') - def _compute_reception_count(self): - move_data = self.env['stock.move'].read_group([ - ('product_id', 'in', self.ids), - ('location_id.usage', '!=', 'internal'), - ('location_dest_id.usage', '=', 'internal'), - ('state', 'in', ('confirmed', 'assigned', 'pending'))], ['product_id'], ['product_id']) - res = dict((data['product_id'][0], data['product_id_count']) for data in move_data) - for move in self: - move.reception_count = res.get(move.id, 0) - - def _compute_delivery_count(self): - move_data = self.env['stock.move'].read_group([ - ('product_id', 'in', self.ids), - ('location_id.usage', '=', 'internal'), - ('location_dest_id.usage', '!=', 'internal'), - ('state', 'in', ('confirmed', 'assigned', 'pending'))], ['product_id'], ['product_id']) - res = dict((data['product_id'][0], data['product_id_count']) for data in move_data) - for move in self: - move.delivery_count = res.get(move.id, 0) - @api.depends('stock_quant_ids', 'stock_move_ids') def _compute_quantities(self): res = self._compute_quantities_dict(self._context.get('lot_id'), self._context.get('owner_id'), self._context.get('package_id'), self._context.get('from_date'), self._context.get('to_date')) @@ -365,6 +343,12 @@ class Product(models.Model): def action_view_routes(self): return self.mapped('product_tmpl_id').action_view_routes() + @api.multi + def write(self, values): + res = super(Product, self).write(values) + if 'active' in values and not values['active'] and self.mapped('orderpoint_ids').filtered(lambda r: r.active): + raise UserError(_('You still have some active reordering rules on this product. Please archive or delete them first.')) + return res class ProductTemplate(models.Model): _inherit = 'product.template' diff --git a/addons/stock/models/stock_inventory.py b/addons/stock/models/stock_inventory.py index 6cd3821fb90..866f3e2104c 100644 --- a/addons/stock/models/stock_inventory.py +++ b/addons/stock/models/stock_inventory.py @@ -408,19 +408,21 @@ class InventoryLine(models.Model): 'company_id': self.inventory_id.company_id.id, 'inventory_id': self.inventory_id.id, 'state': 'confirmed', - #'restrict_lot_id': self.prod_lot_id.id, 'restrict_partner_id': self.partner_id.id, 'location_id': location_id, 'location_dest_id': location_dest_id, - 'move_line_ids': [(0, 0, {'product_id': self.product_id.id, - 'lot_id': self.prod_lot_id.id, - 'product_uom_qty': 0, # bypass reservation here - 'product_uom_id': self.product_uom_id.id, - 'qty_done': qty, - 'package_id': out and self.package_id.id or False, - 'result_package_id': (not out) and self.package_id.id or False, - 'location_id': location_id, #TODO: owner stuff - 'location_dest_id': location_dest_id,})] + 'move_line_ids': [(0, 0, { + 'product_id': self.product_id.id, + 'lot_id': self.prod_lot_id.id, + 'product_uom_qty': 0, # bypass reservation here + 'product_uom_id': self.product_uom_id.id, + 'qty_done': qty, + 'package_id': out and self.package_id.id or False, + 'result_package_id': (not out) and self.package_id.id or False, + 'location_id': location_id, + 'location_dest_id': location_dest_id, + 'owner_id': self.partner_id.id, + })] } def _generate_moves(self): diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py index 68ef37c5e8c..077e8147917 100644 --- a/addons/stock/models/stock_move.py +++ b/addons/stock/models/stock_move.py @@ -52,7 +52,7 @@ class StockMove(models.Model): product_uom_qty = fields.Float( 'Initial Demand', digits=dp.get_precision('Product Unit of Measure'), - default=1.0, required=True, states={'done': [('readonly', True)]}, + default=0.0, required=True, states={'done': [('readonly', True)]}, help="This is the quantity of products from an inventory " "point of view. For moves in the state 'done', this is the " "quantity of products that were actually moved. For other " @@ -144,7 +144,6 @@ class StockMove(models.Model): string_availability_info = fields.Text( 'Availability', compute='_compute_string_qty_information', readonly=True, help='Show various information on stock availability for this move') - restrict_lot_id = fields.Many2one('stock.production.lot', 'Lot/Serial Number', help="Technical field used to depict a restriction on the lot/serial number of quants to consider when marking this move as 'done'") restrict_partner_id = fields.Many2one('res.partner', 'Owner ', help="Technical field used to depict a restriction on the ownership of quants to consider when marking this move as 'done'") route_ids = fields.Many2many('stock.location.route', 'stock_location_route_move', 'move_id', 'route_id', 'Destination route', help="Preferred route to be followed by the procurement order") warehouse_id = fields.Many2one('stock.warehouse', 'Warehouse', help="Technical field depicting the warehouse to consider for the route selection on the next procurement (if any).") @@ -179,9 +178,10 @@ class StockMove(models.Model): if self.user_has_groups('stock.group_stock_multi_locations'): multi_locations_enabled = move.location_id.child_ids or move.location_dest_id.child_ids has_package = move.move_line_ids.mapped('package_id') | move.move_line_ids.mapped('result_package_id') + consignment_enabled = self.user_has_groups('stock.group_tracking_owner') if move.picking_id.picking_type_id.show_operations is False\ and move.state not in ['cancel', 'draft', 'confirmed']\ - and (multi_locations_enabled or move.has_tracking != 'none' or len(move.move_line_ids) > 1 or has_package): + and (multi_locations_enabled or move.has_tracking != 'none' or len(move.move_line_ids) > 1 or has_package or consignment_enabled): move.show_details_visible = True else: move.show_details_visible = False @@ -498,8 +498,6 @@ class StockMove(models.Model): product = self.product_id.with_context(lang=self.partner_id.lang or self.env.user.lang) self.name = product.partner_ref self.product_uom = product.uom_id.id - if self.product_uom_qty: - self.product_uom_qty = 1.0 return {'domain': {'product_uom': [('category_id', '=', product.uom_id.category_id.id)]}} @api.onchange('date') @@ -646,7 +644,7 @@ class StockMove(models.Model): if move.picking_id and \ (move.picking_id.picking_type_id.use_existing_lots or move.picking_id.picking_type_id.use_create_lots) and \ move.product_id.tracking != 'none' and \ - not (move.restrict_lot_id or (move_line and (move_line.product_id and move_line.pack_lot_ids)) or (move_line and not move_line.product_id)): + not (move_line and (move_line.product_id and move_line.pack_lot_ids)) or (move_line and not move_line.product_id): raise UserError(_('You need to provide a Lot/Serial Number for product %s') % move.product_id.name) def _prepare_move_line_vals(self, quantity=None, reserved_quant=None): @@ -674,7 +672,7 @@ class StockMove(models.Model): ) return vals - def _increase_reserved_quantity(self, need, available_quantity, location_id, lot_id=None, package_id=None, owner_id=None, strict=True): + def _update_reserved_quantity(self, need, available_quantity, location_id, lot_id=None, package_id=None, owner_id=None, strict=True): """ Create or update move lines. """ self.ensure_one() @@ -689,7 +687,7 @@ class StockMove(models.Model): taken_quantity = min(available_quantity, need) # Find a candidate move line to update or create a new one. - quants = self.env['stock.quant']._increase_reserved_quantity( + quants = self.env['stock.quant']._update_reserved_quantity( self.product_id, location_id, taken_quantity, lot_id=lot_id, package_id=package_id, owner_id=owner_id, strict=strict ) @@ -733,7 +731,7 @@ class StockMove(models.Model): if available_quantity <= 0: continue need = move.product_qty - move.reserved_availability - taken_quantity = move._increase_reserved_quantity(need, available_quantity, move.location_id, strict=False) + taken_quantity = move._update_reserved_quantity(need, available_quantity, move.location_id, strict=False) if need == taken_quantity: move.state = 'assigned' else: @@ -770,7 +768,7 @@ class StockMove(models.Model): available_move_lines[(move_line.location_id, move_line.lot_id, move_line.result_package_id, move_line.owner_id)] -= move_line.product_qty for (location_id, lot_id, package_id, owner_id), quantity in available_move_lines.items(): need = move.product_qty - sum(move.move_line_ids.mapped('product_qty')) - taken_quantity = move._increase_reserved_quantity(need, quantity, location_id, lot_id, package_id, owner_id) + taken_quantity = move._update_reserved_quantity(need, quantity, location_id, lot_id, package_id, owner_id) if need - taken_quantity == 0.0: move.state = 'assigned' break @@ -931,11 +929,10 @@ class StockMove(models.Model): return vals @api.multi - def split(self, qty, restrict_lot_id=False, restrict_partner_id=False): + def split(self, qty, restrict_partner_id=False): """ Splits qty from move move into a new move :param qty: float. quantity to split (given in product UoM) - :param restrict_lot_id: optional production lot that can be given in order to force the new move to restrict its choice of quants to this lot. :param restrict_partner_id: optional partner that can be given in order to force the new move to restrict its choice of quants to the ones belonging to this partner. :param context: dictionay. can contains the special key 'source_location_id' in order to force the source location when copying the move :returns: id of the backorder move created """ diff --git a/addons/stock/models/stock_move_line.py b/addons/stock/models/stock_move_line.py index 5d4e24b24a9..c2768c11a27 100644 --- a/addons/stock/models/stock_move_line.py +++ b/addons/stock/models/stock_move_line.py @@ -99,16 +99,16 @@ class StockMoveLine(models.Model): Quant = self.env['stock.quant'] quantity = ml.product_uom_id._compute_quantity(ml.qty_done, ml.move_id.product_id.uom_id,rounding_method='HALF-UP') if ml.location_id.should_impact_quants() and ml.product_id.type == 'product': - available_qty = Quant._decrease_available_quantity(ml.product_id, ml.location_id, quantity, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id) + available_qty = Quant._update_available_quantity(ml.product_id, ml.location_id, -quantity, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id) if available_qty < 0 and ml.lot_id: # see if we can compensate the negative quants with some untracked quants untracked_qty = Quant._get_available_quantity(ml.product_id, ml.location_id, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id, strict=True) if untracked_qty: taken_from_untracked_qty = min(untracked_qty, abs(quantity)) - Quant._decrease_available_quantity(ml.product_id, ml.location_id, taken_from_untracked_qty, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id) - Quant._increase_available_quantity(ml.product_id, ml.location_id, taken_from_untracked_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id) + Quant._update_available_quantity(ml.product_id, ml.location_id, -taken_from_untracked_qty, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id) + Quant._update_available_quantity(ml.product_id, ml.location_id, taken_from_untracked_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id) if ml.location_dest_id.should_impact_quants() and ml.product_id.type == 'product': - Quant._increase_available_quantity(ml.product_id, ml.location_dest_id, quantity, lot_id=ml.lot_id, package_id=ml.result_package_id, owner_id=ml.owner_id) + Quant._update_available_quantity(ml.product_id, ml.location_dest_id, quantity, lot_id=ml.lot_id, package_id=ml.result_package_id, owner_id=ml.owner_id) next_moves = ml.move_id.move_dest_ids.filtered(lambda move: move.state not in ('done', 'cancel')) next_moves.do_unreserve() next_moves.action_assign() @@ -132,10 +132,10 @@ class StockMoveLine(models.Model): if ml.location_id.should_impact_quants() and ml.product_id.type == 'product': qty_to_decrease = ml.product_qty - ml.product_uom_id._compute_quantity(vals['product_uom_qty'], ml.product_id.uom_id, rounding_method='HALF-UP') try: - Quant._decrease_reserved_quantity(ml.product_id, ml.location_id, qty_to_decrease, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id) + Quant._update_reserved_quantity(ml.product_id, ml.location_id, -qty_to_decrease, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id) except UserError: if ml.lot_id: - Quant._decrease_reserved_quantity(ml.product_id, ml.location_id, qty_to_decrease, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id) + Quant._update_reserved_quantity(ml.product_id, ml.location_id, -qty_to_decrease, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id) else: raise @@ -156,24 +156,24 @@ class StockMoveLine(models.Model): for ml in self.filtered(lambda ml: ml.state in ['partially_available', 'assigned']): if ml.location_id.should_impact_quants() and ml.product_id.type == 'product': try: - Quant._decrease_reserved_quantity(ml.product_id, ml.location_id, ml.product_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id) + Quant._update_reserved_quantity(ml.product_id, ml.location_id, -ml.product_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id) except UserError: if ml.lot_id: - Quant._decrease_reserved_quantity(ml.product_id, ml.location_id, ml.product_qty, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id) + Quant._update_reserved_quantity(ml.product_id, ml.location_id, -ml.product_qty, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id) else: raise if updates.get('location_id', ml.location_id).should_impact_quants() and ml.product_id.type == 'product': new_product_qty = 0 try: - q = Quant._increase_reserved_quantity(ml.product_id, updates.get('location_id', ml.location_id), ml.product_qty, lot_id=updates.get('lot_id', ml.lot_id), + q = Quant._update_reserved_quantity(ml.product_id, updates.get('location_id', ml.location_id), ml.product_qty, lot_id=updates.get('lot_id', ml.lot_id), package_id=updates.get('package_id', ml.package_id), owner_id=updates.get('owner_id', ml.owner_id), strict=True) new_product_qty = sum([x[1] for x in q]) except UserError: if updates.get('lot_id'): # If we were not able to reserve on tracked quants, we can use untracked ones. try: - q = Quant._increase_reserved_quantity(ml.product_id, updates.get('location_id', ml.location_id), ml.product_qty, lot_id=False, + q = Quant._update_reserved_quantity(ml.product_id, updates.get('location_id', ml.location_id), ml.product_qty, lot_id=False, package_id=updates.get('package_id', ml.package_id), owner_id=updates.get('owner_id', ml.owner_id), strict=True) new_product_qty = sum([x[1] for x in q]) except UserError: @@ -188,10 +188,10 @@ class StockMoveLine(models.Model): for ml in self.filtered(lambda ml: ml.move_id.state == 'done'): # undo the original move line if ml.location_dest_id.should_impact_quants() and ml.product_id.type == 'product': - Quant._decrease_available_quantity(ml.product_id, ml.location_dest_id, ml.qty_done, lot_id=ml.lot_id, + Quant._update_available_quantity(ml.product_id, ml.location_dest_id, -ml.qty_done, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id) if ml.location_id.should_impact_quants() and ml.product_id.type == 'product': - Quant._increase_available_quantity(ml.product_id, ml.location_id, ml.qty_done, lot_id=ml.lot_id, + Quant._update_available_quantity(ml.product_id, ml.location_id, ml.qty_done, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id) # move what's been actually done @@ -206,17 +206,17 @@ class StockMoveLine(models.Model): quantity = ml.move_id.product_uom._compute_quantity(qty_done, ml.move_id.product_id.uom_id, rounding_method='HALF-UP') if location_id.should_impact_quants() and ml.product_id.type == 'product': ml._free_reservation(product_id, location_id, quantity, lot_id=lot_id, package_id=package_id, owner_id=owner_id) - available_qty = Quant._decrease_available_quantity(product_id, location_id, quantity, lot_id=lot_id, package_id=package_id, owner_id=owner_id) + available_qty = Quant._update_available_quantity(product_id, location_id, -quantity, lot_id=lot_id, package_id=package_id, owner_id=owner_id) if available_qty < 0 and lot_id: # see if we can compensate the negative quants with some untracked quants untracked_qty = Quant._get_available_quantity(product_id, location_id, lot_id=False, package_id=package_id, owner_id=owner_id, strict=True) if untracked_qty: taken_from_untracked_qty = min(untracked_qty, abs(available_qty)) - Quant._decrease_available_quantity(product_id, location_id, taken_from_untracked_qty, lot_id=False, package_id=package_id, owner_id=owner_id) - Quant._increase_available_quantity(product_id, location_id, taken_from_untracked_qty, lot_id=lot_id, package_id=package_id, owner_id=owner_id) + Quant._update_available_quantity(product_id, location_id, -taken_from_untracked_qty, lot_id=False, package_id=package_id, owner_id=owner_id) + Quant._update_available_quantity(product_id, location_id, taken_from_untracked_qty, lot_id=lot_id, package_id=package_id, owner_id=owner_id) ml._free_reservation(ml.product_id, location_id, untracked_qty, lot_id=False, package_id=package_id, owner_id=owner_id) if location_dest_id.should_impact_quants() and ml.product_id.type == 'product' and qty_done: - Quant._increase_available_quantity(product_id, location_dest_id, quantity, lot_id=lot_id, package_id=result_package_id, owner_id=owner_id) + Quant._update_available_quantity(product_id, location_dest_id, quantity, lot_id=lot_id, package_id=result_package_id, owner_id=owner_id) # Unreserve and reserve following move in order to have the real reserved quantity on move_line. next_moves |= ml.move_id.move_dest_ids.filtered(lambda move: move.state not in ('done', 'cancel')) res = super(StockMoveLine, self).write(vals) @@ -232,7 +232,7 @@ class StockMoveLine(models.Model): raise UserError(_('You can not delete pack operations of a done picking')) # Unlinking a pack operation should unreserve. if ml.location_id.should_impact_quants() and ml.product_id.type == 'product' and not float_is_zero(ml.product_qty, precision_digits=precision): - self.env['stock.quant']._decrease_reserved_quantity(ml.product_id, ml.location_id, ml.product_qty, lot_id=ml.lot_id, + self.env['stock.quant']._update_reserved_quantity(ml.product_id, ml.location_id, -ml.product_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id) return super(StockMoveLine, self).unlink() @@ -252,23 +252,23 @@ class StockMoveLine(models.Model): # unreserve what's been reserved if ml.location_id.should_impact_quants() and ml.product_id.type == 'product' and ml.product_qty: try: - Quant._decrease_reserved_quantity(ml.product_id, ml.location_id, ml.product_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id) + Quant._update_reserved_quantity(ml.product_id, ml.location_id, -ml.product_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id) except UserError: - Quant._decrease_reserved_quantity(ml.product_id, ml.location_id, ml.product_qty, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id) + Quant._update_reserved_quantity(ml.product_id, ml.location_id, -ml.product_qty, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id) # move what's been actually done quantity = ml.product_uom_id._compute_quantity(ml.qty_done, ml.move_id.product_id.uom_id, rounding_method='HALF-UP') if ml.location_id.should_impact_quants() and ml.product_id.type == 'product': - available_qty = Quant._decrease_available_quantity(ml.product_id, ml.location_id, quantity, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id) + available_qty = Quant._update_available_quantity(ml.product_id, ml.location_id, -quantity, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id) if available_qty < 0 and ml.lot_id: # see if we can compensate the negative quants with some untracked quants untracked_qty = Quant._get_available_quantity(ml.product_id, ml.location_id, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id, strict=True) if untracked_qty: taken_from_untracked_qty = min(untracked_qty, abs(quantity)) - Quant._decrease_available_quantity(ml.product_id, ml.location_id, taken_from_untracked_qty, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id) - Quant._increase_available_quantity(ml.product_id, ml.location_id, taken_from_untracked_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id) + Quant._update_available_quantity(ml.product_id, ml.location_id, -taken_from_untracked_qty, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id) + Quant._update_available_quantity(ml.product_id, ml.location_id, taken_from_untracked_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id) if ml.location_dest_id.should_impact_quants() and ml.product_id.type == 'product': - Quant._increase_available_quantity(ml.product_id, ml.location_dest_id, quantity, lot_id=ml.lot_id, package_id=ml.result_package_id, owner_id=ml.owner_id) + Quant._update_available_quantity(ml.product_id, ml.location_dest_id, quantity, lot_id=ml.lot_id, package_id=ml.result_package_id, owner_id=ml.owner_id) def _free_reservation(self, product_id, location_id, quantity, lot_id=None, package_id=None, owner_id=None): """ When editing a done move line or validating one with some forced quantities, it is diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py index eea788a7a15..46b937546f7 100644 --- a/addons/stock/models/stock_picking.py +++ b/addons/stock/models/stock_picking.py @@ -778,8 +778,6 @@ class Picking(models.Model): @api.multi def button_scrap(self): self.ensure_one() - # only stockable products are scrapeable - scrapeable_products = self.move_line_ids.mapped('product_id').filtered(lambda p: p.type == 'product') return { 'name': _('Scrap'), 'view_type': 'form', @@ -787,7 +785,7 @@ class Picking(models.Model): 'res_model': 'stock.scrap', 'view_id': self.env.ref('stock.stock_scrap_form_view2').id, 'type': 'ir.actions.act_window', - 'context': {'default_picking_id': self.id, 'product_ids': scrapeable_products.ids}, + 'context': {'default_picking_id': self.id, 'product_ids': self.move_line_ids.mapped('product_id').ids}, 'target': 'new', } diff --git a/addons/stock/models/stock_quant.py b/addons/stock/models/stock_quant.py index 73634b3ea18..15084292a5e 100644 --- a/addons/stock/models/stock_quant.py +++ b/addons/stock/models/stock_quant.py @@ -19,11 +19,8 @@ class StockQuant(models.Model): product_uom_id = fields.Many2one( 'product.uom', 'Unit of Measure', readonly=True, related='product_id.uom_id') - company_id = fields.Many2one( - 'res.company', 'Company', - default=lambda self: self.env['res.company']._company_default_get('stock.quant'), - help='The company to which the quants belong', - readonly=True, required=True) + company_id = fields.Many2one(related='location_id.company_id', + string='Company', store=True, readonly=True) location_id = fields.Many2one( 'stock.location', 'Location', auto_join=True, ondelete='restrict', readonly=True, required=True) @@ -50,8 +47,8 @@ class StockQuant(models.Model): @api.multi @api.constrains('product_id') def check_product_id(self): - if any(elem.product_id.type == 'consu' for elem in self): - raise ValidationError(_('Quants cannot be created for consumables.')) + if any(elem.product_id.type != 'product' for elem in self): + raise ValidationError(_('Quants cannot be created for consumables or services.')) @api.multi @api.constrains('quantity') @@ -88,7 +85,6 @@ class StockQuant(models.Model): removal_strategy_order = self._get_removal_strategy_order(removal_strategy) domain = [ ('product_id', '=', product_id.id), - ('location_id', 'child_of', location_id.id), ] if not strict: if lot_id: @@ -97,19 +93,15 @@ class StockQuant(models.Model): domain = expression.AND([[('package_id', '=', package_id.id)], domain]) if owner_id: domain = expression.AND([[('owner_id', '=', owner_id.id)], domain]) + domain = expression.AND([[('location_id', 'child_of', location_id.id)], domain]) else: domain = expression.AND([[('lot_id', '=', lot_id and lot_id.id or False)], domain]) domain = expression.AND([[('package_id', '=', package_id and package_id.id or False)], domain]) domain = expression.AND([[('owner_id', '=', owner_id and owner_id.id or False)], domain]) + domain = expression.AND([[('location_id', '=', location_id.id)], domain]) return self.search(domain, order=removal_strategy_order) - @api.model - def _get_quantity(self, product_id, location_id, lot_id=None, package_id=None, owner_id=None, strict=False): - self = self.sudo() - quants = self._gather(product_id, location_id, lot_id=lot_id, package_id=package_id, owner_id=owner_id, strict=strict) - return sum(quants.mapped('quantity')) - @api.model def _get_available_quantity(self, product_id, location_id, lot_id=None, package_id=None, owner_id=None, strict=False): """ Return the available quantity, i.e. the sum of `quantity` minus the sum of @@ -134,9 +126,9 @@ class StockQuant(models.Model): return sum(quants.mapped('quantity')) - sum(quants.mapped('reserved_quantity')) @api.model - def _increase_available_quantity(self, product_id, location_id, quantity, lot_id=None, package_id=None, owner_id=None, strict=True): + def _update_available_quantity(self, product_id, location_id, quantity, lot_id=None, package_id=None, owner_id=None): self = self.sudo() - quants = self._gather(product_id, location_id, lot_id=lot_id, package_id=package_id, owner_id=owner_id, strict=strict) + quants = self._gather(product_id, location_id, lot_id=lot_id, package_id=package_id, owner_id=owner_id, strict=True) for quant in quants: try: with self._cr.savepoint(): @@ -160,14 +152,10 @@ class StockQuant(models.Model): 'package_id': package_id and package_id.id, 'owner_id': owner_id and owner_id.id, }) - return self._get_available_quantity(product_id, location_id, lot_id=lot_id, package_id=package_id, owner_id=owner_id, strict=strict) + return self._get_available_quantity(product_id, location_id, lot_id=lot_id, package_id=package_id, owner_id=owner_id, strict=False) @api.model - def _decrease_available_quantity(self, product_id, location_id, quantity, lot_id=None, package_id=None, owner_id=None, strict=True): - return self._increase_available_quantity(product_id, location_id, -quantity, lot_id=lot_id, package_id=package_id, owner_id=owner_id, strict=strict) - - @api.model - def _increase_reserved_quantity(self, product_id, location_id, quantity, lot_id=None, package_id=None, owner_id=None, strict=False): + def _update_reserved_quantity(self, product_id, location_id, quantity, lot_id=None, package_id=None, owner_id=None, strict=False): """ Increase the reserved quantity, i.e. increase `reserved_quantity` for the set of quants sharing the combination of `product_id, location_id` if `strict` is set to False or sharing the *exact same characteristics* otherwise. Typically, this method is called when reserving @@ -209,19 +197,6 @@ class StockQuant(models.Model): break return reserved_quants - @api.model - def _decrease_reserved_quantity(self, product_id, location_id, quantity, lot_id=None, package_id=None, owner_id=None, strict=True): - """ Decrease the reserved quantity, i.e. decrease `reserved_quantity`, for the set of - quants sharing the *exact same characteristics* if `strict` is set to True or sharing the - combination of `product_id, location_id` otherwise. Typically, this method is called during - a move line's validation or a move line's unlink and `strict` should be `True` in these - cases, because the characteristics are known. - - :return: a list of tuples (quant, quantity_unreserved) showing on which quant the decrease - of reservation was done and how much the system was able to unreserve on it - """ - return self._increase_reserved_quantity(product_id, location_id, -quantity, lot_id=lot_id, package_id=package_id, owner_id=owner_id, strict=strict) - class QuantPackage(models.Model): """ Packages containing quants and/or other packages """ diff --git a/addons/stock/models/stock_scrap.py b/addons/stock/models/stock_scrap.py index 3d3f8eb9116..4eba509a8de 100644 --- a/addons/stock/models/stock_scrap.py +++ b/addons/stock/models/stock_scrap.py @@ -79,15 +79,18 @@ class StockScrap(models.Model): def do_scrap(self): for scrap in self: move = self.env['stock.move'].create(scrap._prepare_move_values()) - quantity_in_stock = self.env['stock.quant']._get_quantity( - self.product_id, self.location_id, lot_id=self.lot_id, - package_id=self.package_id, owner_id=self.owner_id, strict=True - ) - if quantity_in_stock < move.product_qty: # FIXME: float compare - raise UserError(_('You cannot scrap a move without having available stock for %s. You can correct it with an inventory adjustment.') % move.product_id.name) + if self.product_id.type == 'product': + quantity_in_stock = sum(self.env['stock.quant'].search([ + ('product_id', '=', self.product_id.id), + ('lot_id', '=', self.lot_id and self.lot_id.id or False), + ('package_id', '=', self.package_id and self.package_id.id or False), + ('owner_id', '=', self.owner_id and self.owner_id.id or False), + ('location_id', 'child_of', self.location_id.id) + ]).mapped('quantity')) + if quantity_in_stock < move.product_qty: # FIXME: float compare + raise UserError(_('You cannot scrap a move without having available stock for %s. You can correct it with an inventory adjustment.') % move.product_id.name) move.action_done() scrap.write({'move_id': move.id, 'state': 'done'}) - # TODO: unreserve reserved return True def _prepare_move_values(self): @@ -109,7 +112,6 @@ class StockScrap(models.Model): 'package_id': self.package_id.id, 'owner_id': self.owner_id.id, 'lot_id': self.lot_id.id, })], -# 'restrict_lot_id': self.lot_id.id, # FIXME: JCO i asked you x times, should we drop this or not???? # 'restrict_partner_id': self.owner_id.id, 'picking_id': self.picking_id.id } diff --git a/addons/stock/tests/test_inventory.py b/addons/stock/tests/test_inventory.py index c9a40aa9038..2cbd909e064 100644 --- a/addons/stock/tests/test_inventory.py +++ b/addons/stock/tests/test_inventory.py @@ -26,7 +26,7 @@ class TestInventory(TransactionCase): as expected. """ # make some stock - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 100) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 100) self.assertEqual(len(self.env['stock.quant']._gather(self.product1, self.stock_location)), 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location), 100.0) @@ -141,3 +141,27 @@ class TestInventory(TransactionCase): self.assertEqual(len(self.env['stock.quant']._gather(self.product2, self.stock_location, lot_id=lot1, strict=True)), 1.0) self.assertEqual(len(self.env['stock.quant']._gather(self.product2, self.stock_location, strict=True)), 1.0) self.assertEqual(len(self.env['stock.quant']._gather(self.product2, self.stock_location)), 2.0) + + def test_inventory_5(self): + """ Check that assigning an owner does work. + """ + owner1 = self.env['res.partner'].create({'name': 'test_inventory_5'}) + + inventory = self.env['stock.inventory'].create({ + 'name': 'remove product1', + 'filter': 'product', + 'location_id': self.stock_location.id, + 'product_id': self.product1.id, + 'exhausted': True, + }) + inventory.prepare_inventory() + self.assertEqual(len(inventory.line_ids), 1) + self.assertEqual(inventory.line_ids.theoretical_qty, 0) + inventory.line_ids.partner_id = owner1 + inventory.line_ids.product_qty = 5 + inventory.action_done() + + quant = self.env['stock.quant']._gather(self.product1, self.stock_location) + self.assertEqual(len(quant), 1) + self.assertEqual(quant.quantity, 5) + self.assertEqual(quant.owner_id.id, owner1.id) diff --git a/addons/stock/tests/test_move.py b/addons/stock/tests/test_move.py index 3c1a87e1518..a29e2f00e65 100644 --- a/addons/stock/tests/test_move.py +++ b/addons/stock/tests/test_move.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo.tests.common import TransactionCase from odoo.exceptions import UserError +from odoo.tests.common import TransactionCase class StockMove(TransactionCase): @@ -30,6 +30,11 @@ class StockMove(TransactionCase): 'tracking': 'lot', 'categ_id': self.env.ref('product.product_category_all').id, }) + self.product4 = self.env['product.product'].create({ + 'name': 'Product A', + 'type': 'consu', + 'categ_id': self.env.ref('product.product_category_all').id, + }) def test_in_1(self): """ Receive products from a supplier. Check that a move line is created and that the @@ -164,7 +169,7 @@ class StockMove(TransactionCase): stock and that the delivery correctly remove the single quant in stock. """ # make some stock - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 100) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 100) self.assertEqual(len(self.env['stock.quant']._gather(self.product1, self.stock_location)), 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location), 100.0) @@ -265,8 +270,8 @@ class StockMove(TransactionCase): 'name': 'lot1', 'product_id': self.product3.id, }) - self.env['stock.quant']._increase_available_quantity(self.product3, self.stock_location, 2) - self.env['stock.quant']._increase_available_quantity(self.product3, self.stock_location, 3, lot_id=lot1) + self.env['stock.quant']._update_available_quantity(self.product3, self.stock_location, 2) + self.env['stock.quant']._update_available_quantity(self.product3, self.stock_location, 3, lot_id=lot1) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product3, self.stock_location), 5.0) # creation @@ -297,9 +302,9 @@ class StockMove(TransactionCase): 'name': 'lot2', 'product_id': self.product2.id, }) - self.env['stock.quant']._increase_available_quantity(self.product2, self.stock_location, 2) - self.env['stock.quant']._increase_available_quantity(self.product2, self.stock_location, 1, lot_id=lot1) - self.env['stock.quant']._increase_available_quantity(self.product2, self.stock_location, 1, lot_id=lot2) + self.env['stock.quant']._update_available_quantity(self.product2, self.stock_location, 2) + self.env['stock.quant']._update_available_quantity(self.product2, self.stock_location, 1, lot_id=lot1) + self.env['stock.quant']._update_available_quantity(self.product2, self.stock_location, 1, lot_id=lot2) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product2, self.stock_location), 4.0) # creation @@ -363,8 +368,8 @@ class StockMove(TransactionCase): 'name': 'lot2', 'product_id': self.product2.id, }) - self.env['stock.quant']._increase_available_quantity(self.product2, self.stock_location, 1, lot_id=lot1) - self.env['stock.quant']._increase_available_quantity(self.product2, self.stock_location, 1, lot_id=lot2) + self.env['stock.quant']._update_available_quantity(self.product2, self.stock_location, 1, lot_id=lot1) + self.env['stock.quant']._update_available_quantity(self.product2, self.stock_location, 1, lot_id=lot2) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product2, self.stock_location), 2.0) # creation @@ -381,7 +386,7 @@ class StockMove(TransactionCase): move1.move_line_ids.write({'qty_done': 1.0}) move1.action_done() - self.env['stock.quant']._increase_available_quantity(self.product2, self.stock_location, 2) + self.env['stock.quant']._update_available_quantity(self.product2, self.stock_location, 2) lot3 = self.env['stock.production.lot'].create({ 'name': 'lot3', 'product_id': self.product2.id, @@ -430,8 +435,8 @@ class StockMove(TransactionCase): 'name': 'lot2', 'product_id': self.product2.id, }) - self.env['stock.quant']._increase_available_quantity(self.product2, self.stock_location, 1, lot_id=lot1) - self.env['stock.quant']._increase_available_quantity(self.product2, self.stock_location, 1, lot_id=lot2) + self.env['stock.quant']._update_available_quantity(self.product2, self.stock_location, 1, lot_id=lot1) + self.env['stock.quant']._update_available_quantity(self.product2, self.stock_location, 1, lot_id=lot2) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product2, self.stock_location), 2.0) # creation @@ -452,7 +457,7 @@ class StockMove(TransactionCase): self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product2, self.stock_location, lot_id=lot1, strict=True), 0.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product2, self.stock_location, lot_id=lot2, strict=True), 0.0) - self.env['stock.quant']._increase_available_quantity(self.product2, self.stock_location, 1) + self.env['stock.quant']._update_available_quantity(self.product2, self.stock_location, 1) lot3 = self.env['stock.production.lot'].create({ 'name': 'lot3', 'product_id': self.product2.id, @@ -479,7 +484,7 @@ class StockMove(TransactionCase): self.assertEqual(move1.state, 'confirmed') # create an untracked quant - self.env['stock.quant']._increase_available_quantity(self.product2, self.stock_location, 1.0) + self.env['stock.quant']._update_available_quantity(self.product2, self.stock_location, 1.0) lot1 = self.env['stock.production.lot'].create({ 'name': 'lot1', 'product_id': self.product2.id, @@ -505,7 +510,7 @@ class StockMove(TransactionCase): def test_mixed_tracking_reservation_6(self): # create an untracked quant - self.env['stock.quant']._increase_available_quantity(self.product2, self.stock_location, 1.0) + self.env['stock.quant']._update_available_quantity(self.product2, self.stock_location, 1.0) move1 = self.env['stock.move'].create({ 'name': 'test_jenaimarre_1', 'location_id': self.stock_location.id, @@ -586,7 +591,7 @@ class StockMove(TransactionCase): more than enough products in stock. """ # make some stock - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 150.0) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 150.0) self.assertEqual(len(self.env['stock.quant']._gather(self.product1, self.stock_location)), 1.0) move1 = self.env['stock.move'].create({ @@ -607,7 +612,7 @@ class StockMove(TransactionCase): not enough products in stock. """ # make some stock - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 50.0) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 50.0) self.assertEqual(len(self.env['stock.quant']._gather(self.product1, self.stock_location)), 1.0) move1 = self.env['stock.move'].create({ @@ -628,7 +633,7 @@ class StockMove(TransactionCase): set the state back to confirmed. """ # make some stock - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 150.0) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 150.0) # creation move1 = self.env['stock.move'].create({ @@ -666,7 +671,7 @@ class StockMove(TransactionCase): package1 = self.env['stock.quant.package'].create({'name': 'test_unreserve_2_pack'}) # make some stock - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 150.0, package_id=package1) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 150.0, package_id=package1) # creation move1 = self.env['stock.move'].create({ @@ -701,7 +706,7 @@ class StockMove(TransactionCase): """ Similar to `test_unreserve_1` but checking the quants more in details. """ # make some stock - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 2) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 2) self.assertEqual(len(self.env['stock.quant']._gather(self.product1, self.stock_location)), 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location), 2) @@ -742,7 +747,7 @@ class StockMove(TransactionCase): """ Check the unreservation of a partially available stock move. """ # make some stock - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 2) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 2) self.assertEqual(len(self.env['stock.quant']._gather(self.product1, self.stock_location)), 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location), 2) @@ -784,7 +789,7 @@ class StockMove(TransactionCase): untracked product. """ # make some stock - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 1.0) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 1.0) self.assertEqual(len(self.env['stock.quant']._gather(self.product1, self.stock_location)), 1.0) move_stock_pack = self.env['stock.move'].create({ @@ -826,7 +831,7 @@ class StockMove(TransactionCase): }) # make some stock - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 1.0, lot_id=lot1) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 1.0, lot_id=lot1) self.assertEqual(len(self.env['stock.quant']._gather(self.product1, self.stock_location, lot1)), 1.0) move_stock_pack = self.env['stock.move'].create({ @@ -872,7 +877,7 @@ class StockMove(TransactionCase): move multiple units of an untracked product. """ # make some stock - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 2.0) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 2.0) self.assertEqual(len(self.env['stock.quant']._gather(self.product1, self.stock_location)), 1.0) move_stock_pack_1 = self.env['stock.move'].create({ @@ -948,7 +953,7 @@ class StockMove(TransactionCase): }) # make some stock - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 2.0, lot_id=lot1) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 2.0, lot_id=lot1) self.assertEqual(len(self.env['stock.quant']._gather(self.product1, self.stock_location, lot1)), 1.0) move_stock_pack_1 = self.env['stock.move'].create({ @@ -1010,7 +1015,7 @@ class StockMove(TransactionCase): move multiple units of an untracked product. """ # make some stock - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 2.0) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 2.0) move_stock_pack = self.env['stock.move'].create({ 'name': 'test_link_assign_1_1', @@ -1118,7 +1123,7 @@ class StockMove(TransactionCase): correctly unreserves the other one. """ # make some stock - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 1.0) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 1.0) # prepare the conflicting move move1 = self.env['stock.move'].create({ @@ -1179,7 +1184,7 @@ class StockMove(TransactionCase): }) # make some stock - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 1.0, lot_id=lot1) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 1.0, lot_id=lot1) # prepare the conflicting move move1 = self.env['stock.move'].create({ @@ -1245,8 +1250,8 @@ class StockMove(TransactionCase): 'usage': 'internal', 'location_id': self.stock_location.id, }) - self.env['stock.quant']._increase_available_quantity(self.product1, shelf1_location, 1.0) - self.env['stock.quant']._increase_available_quantity(self.product1, shelf2_location, 1.0) + self.env['stock.quant']._update_available_quantity(self.product1, shelf1_location, 1.0) + self.env['stock.quant']._update_available_quantity(self.product1, shelf2_location, 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, shelf1_location), 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, shelf2_location), 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location), 2.0) @@ -1285,8 +1290,8 @@ class StockMove(TransactionCase): 'name': 'lot2', 'product_id': self.product1.id, }) - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 1.0, lot_id=lot1) - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 1.0, lot_id=lot2) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 1.0, lot_id=lot1) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 1.0, lot_id=lot2) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location), 2.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location, lot_id=lot1), 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location, lot_id=lot2), 1.0) @@ -1321,8 +1326,8 @@ class StockMove(TransactionCase): package1 = self.env['stock.quant.package'].create({'name': 'test_edit_reserved_move_line_3'}) package2 = self.env['stock.quant.package'].create({'name': 'test_edit_reserved_move_line_3'}) - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 1.0, package_id=package1) - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 1.0, package_id=package2) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 1.0, package_id=package1) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 1.0, package_id=package2) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location), 2.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location, package_id=package1), 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location, package_id=package2), 1.0) @@ -1356,8 +1361,8 @@ class StockMove(TransactionCase): owner1 = self.env['res.partner'].create({'name': 'test_edit_reserved_move_line_4_1'}) owner2 = self.env['res.partner'].create({'name': 'test_edit_reserved_move_line_4_2'}) - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 1.0, owner_id=owner1) - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 1.0, owner_id=owner2) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 1.0, owner_id=owner1) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 1.0, owner_id=owner2) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location), 2.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location, owner_id=owner1), 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location, owner_id=owner2), 1.0) @@ -1399,8 +1404,8 @@ class StockMove(TransactionCase): }) package1 = self.env['stock.quant.package'].create({'name': 'test_edit_reserved_move_line_5'}) - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 1.0, lot_id=lot1, package_id=package1) - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 1.0, lot_id=lot2) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 1.0, lot_id=lot1, package_id=package1) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 1.0, lot_id=lot2) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location), 2.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location, lot_id=lot1, package_id=package1), 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location, lot_id=lot2), 1.0) @@ -1442,7 +1447,7 @@ class StockMove(TransactionCase): 'usage': 'internal', 'location_id': self.stock_location.id, }) - self.env['stock.quant']._increase_available_quantity(self.product1, shelf1_location, 1.0) + self.env['stock.quant']._update_available_quantity(self.product1, shelf1_location, 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location), 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, shelf1_location), 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, shelf2_location), 0.0) @@ -1481,7 +1486,7 @@ class StockMove(TransactionCase): 'product_id': self.product3.id, }) # make some stock without assigning a lot id - self.env['stock.quant']._increase_available_quantity(self.product3, self.stock_location, 5) + self.env['stock.quant']._update_available_quantity(self.product3, self.stock_location, 5) # creation move1 = self.env['stock.move'].create({ @@ -1533,8 +1538,8 @@ class StockMove(TransactionCase): 'product_id': self.product3.id, }) # make some stock without assigning a lot id - self.env['stock.quant']._increase_available_quantity(self.product3, self.stock_location, 3) - self.env['stock.quant']._increase_available_quantity(self.product3, self.stock_location, 2, lot_id=lot1) + self.env['stock.quant']._update_available_quantity(self.product3, self.stock_location, 3) + self.env['stock.quant']._update_available_quantity(self.product3, self.stock_location, 2, lot_id=lot1) # creation move1 = self.env['stock.move'].create({ @@ -1600,8 +1605,8 @@ class StockMove(TransactionCase): 'usage': 'internal', 'location_id': self.stock_location.id, }) - self.env['stock.quant']._increase_available_quantity(self.product1, shelf1_location, 1.0) - self.env['stock.quant']._increase_available_quantity(self.product1, shelf2_location, 1.0) + self.env['stock.quant']._update_available_quantity(self.product1, shelf1_location, 1.0) + self.env['stock.quant']._update_available_quantity(self.product1, shelf2_location, 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, shelf1_location), 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, shelf2_location), 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location), 2.0) @@ -1643,8 +1648,8 @@ class StockMove(TransactionCase): 'name': 'lot2', 'product_id': self.product1.id, }) - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 1.0, lot_id=lot1) - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 1.0, lot_id=lot2) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 1.0, lot_id=lot1) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 1.0, lot_id=lot2) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location), 2.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location, lot_id=lot1), 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location, lot_id=lot2), 1.0) @@ -1680,8 +1685,8 @@ class StockMove(TransactionCase): package1 = self.env['stock.quant.package'].create({'name': 'test_edit_reserved_move_line_3'}) package2 = self.env['stock.quant.package'].create({'name': 'test_edit_reserved_move_line_3'}) - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 1.0, package_id=package1) - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 1.0, package_id=package2) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 1.0, package_id=package1) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 1.0, package_id=package2) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location), 2.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location, package_id=package1), 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location, package_id=package2), 1.0) @@ -1716,8 +1721,8 @@ class StockMove(TransactionCase): owner1 = self.env['res.partner'].create({'name': 'test_edit_reserved_move_line_4_1'}) owner2 = self.env['res.partner'].create({'name': 'test_edit_reserved_move_line_4_2'}) - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 1.0, owner_id=owner1) - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 1.0, owner_id=owner2) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 1.0, owner_id=owner1) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 1.0, owner_id=owner2) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location), 2.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location, owner_id=owner1), 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location, owner_id=owner2), 1.0) @@ -1760,8 +1765,8 @@ class StockMove(TransactionCase): }) package1 = self.env['stock.quant.package'].create({'name': 'test_edit_reserved_move_line_5'}) - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 1.0, lot_id=lot1, package_id=package1) - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 1.0, lot_id=lot2) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 1.0, lot_id=lot1, package_id=package1) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 1.0, lot_id=lot2) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location), 2.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location, lot_id=lot1, package_id=package1), 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location, lot_id=lot2), 1.0) @@ -1804,7 +1809,7 @@ class StockMove(TransactionCase): 'usage': 'internal', 'location_id': self.stock_location.id, }) - self.env['stock.quant']._increase_available_quantity(self.product1, shelf1_location, 1.0) + self.env['stock.quant']._update_available_quantity(self.product1, shelf1_location, 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location), 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, shelf1_location), 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, shelf2_location), 0.0) @@ -1848,8 +1853,8 @@ class StockMove(TransactionCase): 'usage': 'internal', 'location_id': self.stock_location.id, }) - self.env['stock.quant']._increase_available_quantity(self.product1, shelf1_location, 1.0) - self.env['stock.quant']._increase_available_quantity(self.product1, shelf2_location, 1.0) + self.env['stock.quant']._update_available_quantity(self.product1, shelf1_location, 1.0) + self.env['stock.quant']._update_available_quantity(self.product1, shelf2_location, 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location), 2.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, shelf1_location), 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, shelf2_location), 1.0) @@ -1900,7 +1905,7 @@ class StockMove(TransactionCase): 'usage': 'internal', 'location_id': self.stock_location.id, }) - self.env['stock.quant']._increase_available_quantity(self.product1, shelf1_location, 1.0) + self.env['stock.quant']._update_available_quantity(self.product1, shelf1_location, 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, shelf1_location), 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location), 1.0) @@ -1936,7 +1941,7 @@ class StockMove(TransactionCase): 'usage': 'internal', 'location_id': self.stock_location.id, }) - self.env['stock.quant']._increase_available_quantity(self.product1, shelf1_location, 1.0) + self.env['stock.quant']._update_available_quantity(self.product1, shelf1_location, 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, shelf1_location), 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location), 1.0) @@ -2065,7 +2070,7 @@ class StockMove(TransactionCase): remaining quantity. """ owner = self.env['res.partner'].create({'name': 'Jean'}) - self.env['stock.quant']._increase_available_quantity(self.product1, self.stock_location, 5.0) + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 5.0) picking = self.env['stock.picking'].create({ 'location_id': self.stock_location.id, 'location_dest_id': self.customer_location.id, @@ -2146,7 +2151,7 @@ class StockMove(TransactionCase): 'name': 'lot1', 'product_id': self.product3.id, }) - self.env['stock.quant']._increase_available_quantity(self.product3, self.stock_location, 5.0, lot_id=lot1) + self.env['stock.quant']._update_available_quantity(self.product3, self.stock_location, 5.0, lot_id=lot1) picking = self.env['stock.picking'].create({ 'location_id': self.stock_location.id, 'location_dest_id': self.customer_location.id, @@ -2202,3 +2207,81 @@ class StockMove(TransactionCase): (move1 + move2).write({'quantity_done': 1}) self.assertEqual(move1.quantity_done, 1) self.assertEqual(move2.quantity_done, 1) + + def test_initial_demand_1(self): + """ Check that the initial demand is set to 0 when creating a move by hand, and + that changing the product on the move do not reset the initial demand. + """ + move1 = self.env['stock.move'].create({ + 'name': 'test_in_1', + 'location_id': self.supplier_location.id, + 'location_dest_id': self.stock_location.id, + 'product_id': self.product1.id, + 'product_uom': self.uom_unit.id, + }) + self.assertEqual(move1.state, 'draft') + self.assertEqual(move1.product_uom_qty, 0) + move1.product_uom_qty = 100 + move1.product_id = self.product2 + move1.onchange_product_id() + self.assertEqual(move1.product_uom_qty, 100) + + def test_scrap_1(self): + """ Check the created stock move and the impact on quants when we scrap a + stockable product. + """ + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 1) + scrap = self.env['stock.scrap'].create({ + 'product_id': self.product1.id, + 'product_uom_id':self.product1.uom_id.id, + 'scrap_qty': 1, + }) + self.assertEqual(scrap.state, 'done') + move = scrap.move_id + self.assertEqual(move.state, 'done') + self.assertEqual(move.quantity_done, 1) + self.assertEqual(move.scrapped, True) + self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location), 0) + + def test_scrap_2(self): + """ Check the created stock move and the impact on quants when we scrap a + consumable product. + """ + scrap = self.env['stock.scrap'].create({ + 'product_id': self.product4.id, + 'product_uom_id':self.product4.uom_id.id, + 'scrap_qty': 1, + }) + self.assertEqual(scrap.state, 'done') + move = scrap.move_id + self.assertEqual(move.state, 'done') + self.assertEqual(move.quantity_done, 1) + self.assertEqual(move.scrapped, True) + self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product4, self.stock_location), 0) + + def test_scrap_3(self): + """ Scrap the product of a reserved move line. Check that the move line is + correctly deleted and that the associated stock move is not assigned anymore. + """ + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 1) + move1 = self.env['stock.move'].create({ + 'name': 'test_set_quantity_done_1', + 'location_id': self.stock_location.id, + 'location_dest_id': self.customer_location.id, + 'product_id': self.product1.id, + 'product_uom': self.uom_unit.id, + 'product_uom_qty': 1.0, + }) + move1.action_confirm() + move1.action_assign() + self.assertEqual(move1.state, 'assigned') + self.assertEqual(len(move1.move_line_ids), 1) + + scrap = self.env['stock.scrap'].create({ + 'product_id': self.product1.id, + 'product_uom_id':self.product1.uom_id.id, + 'scrap_qty': 1, + }) + + self.assertEqual(move1.state, 'confirmed') + self.assertEqual(len(move1.move_line_ids), 0) diff --git a/addons/stock/tests/test_move2.py b/addons/stock/tests/test_move2.py index 6a0f6ff86bd..cd362545c86 100644 --- a/addons/stock/tests/test_move2.py +++ b/addons/stock/tests/test_move2.py @@ -52,7 +52,7 @@ class TestPickShip(TestStockCommon): location = self.env['stock.location'].browse(self.stock_location) # make some stock - self.env['stock.quant']._increase_available_quantity(self.productA, location, 10.0) + self.env['stock.quant']._update_available_quantity(self.productA, location, 10.0) picking_pick.action_assign() picking_pick.move_lines[0].move_line_ids[0].qty_done = 10.0 picking_pick.do_transfer() @@ -72,9 +72,9 @@ class TestPickShip(TestStockCommon): """ picking_pick, picking_client = self.create_pick_ship() stock_location = self.env['stock.location'].browse(self.stock_location) - self.env['stock.quant']._increase_available_quantity(self.productA, stock_location, 10.0) + self.env['stock.quant']._update_available_quantity(self.productA, stock_location, 10.0) pack_location = self.env['stock.location'].browse(self.pack_location) - self.env['stock.quant']._increase_available_quantity(self.productA, pack_location, 5.0) + self.env['stock.quant']._update_available_quantity(self.productA, pack_location, 5.0) self.assertEqual(len(self.env['stock.quant']._gather(self.productA, stock_location)), 1.0) self.assertEqual(len(self.env['stock.quant']._gather(self.productA, pack_location)), 1.0) @@ -105,7 +105,7 @@ class TestPickShip(TestStockCommon): def test_mto_moves_return(self): picking_pick, picking_client = self.create_pick_ship() stock_location = self.env['stock.location'].browse(self.stock_location) - self.env['stock.quant']._increase_available_quantity(self.productA, stock_location, 10.0) + self.env['stock.quant']._update_available_quantity(self.productA, stock_location, 10.0) picking_pick.action_assign() picking_pick.move_lines[0].move_line_ids[0].qty_done = 10.0 @@ -135,7 +135,7 @@ class TestPickShip(TestStockCommon): location = self.env['stock.location'].browse(self.stock_location) # make some stock - self.env['stock.quant']._increase_available_quantity(self.productA, location, 10.0) + self.env['stock.quant']._update_available_quantity(self.productA, location, 10.0) picking_pick.action_assign() picking_pick.move_lines[0].move_line_ids[0].qty_done = 5.0 @@ -159,7 +159,7 @@ class TestPickShip(TestStockCommon): location = self.env['stock.location'].browse(self.stock_location) # make some stock - self.env['stock.quant']._increase_available_quantity(self.productA, location, 10.0) + self.env['stock.quant']._update_available_quantity(self.productA, location, 10.0) picking_pick.action_assign() picking_pick.move_lines[0].move_line_ids[0].qty_done = 10.0 picking_pick.action_done() @@ -197,7 +197,7 @@ class TestPickShip(TestStockCommon): location = self.env['stock.location'].browse(self.stock_location) # make some stock - self.env['stock.quant']._increase_available_quantity(self.productA, location, 10.0) + self.env['stock.quant']._update_available_quantity(self.productA, location, 10.0) picking_pick.action_assign() picking_pick.move_lines[0].move_line_ids[0].write({ 'qty_done': 10.0, @@ -246,7 +246,7 @@ class TestSinglePicking(TestStockCommon): # make some stock pack_location = self.env['stock.location'].browse(self.pack_location) - self.env['stock.quant']._increase_available_quantity(self.productA, pack_location, 2) + self.env['stock.quant']._update_available_quantity(self.productA, pack_location, 2) # assign delivery_order.action_confirm() @@ -283,7 +283,7 @@ class TestSinglePicking(TestStockCommon): # make some stock pack_location = self.env['stock.location'].browse(self.pack_location) - self.env['stock.quant']._increase_available_quantity(self.productA, pack_location, 1) + self.env['stock.quant']._update_available_quantity(self.productA, pack_location, 1) # assign to partially available delivery_order.action_confirm() @@ -322,7 +322,7 @@ class TestSinglePicking(TestStockCommon): # make some stock pack_location = self.env['stock.location'].browse(self.pack_location) - self.env['stock.quant']._increase_available_quantity(self.productA, pack_location, 1) + self.env['stock.quant']._update_available_quantity(self.productA, pack_location, 1) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.productA, pack_location), 1.0) # assign to available @@ -377,7 +377,7 @@ class TestSinglePicking(TestStockCommon): # make some stock pack_location = self.env['stock.location'].browse(self.pack_location) - self.env['stock.quant']._increase_available_quantity(self.productA, pack_location, 1) + self.env['stock.quant']._update_available_quantity(self.productA, pack_location, 1) self.assertEqual(self.env['stock.quant']._get_available_quantity(self.productA, pack_location), 1.0) # assign to available @@ -463,7 +463,7 @@ class TestSinglePicking(TestStockCommon): product with one move line. After adding a second unit in stock and recheck availability. The DO should have 2 reserved unit, be in available state and have only one move line. """ - self.env['stock.quant']._increase_available_quantity(self.productA, self.env['stock.location'].browse(self.stock_location), 1.0) + self.env['stock.quant']._update_available_quantity(self.productA, self.env['stock.location'].browse(self.stock_location), 1.0) delivery_order = self.env['stock.picking'].create({ 'location_id': self.stock_location, 'location_dest_id': self.customer_location, @@ -520,7 +520,7 @@ class TestSinglePicking(TestStockCommon): 'product_id': self.productA.id, }) stock_location = self.env['stock.location'].browse(self.stock_location) - self.env['stock.quant']._increase_available_quantity(self.productA, stock_location, 1.0, lot_id=lot1) + self.env['stock.quant']._update_available_quantity(self.productA, stock_location, 1.0, lot_id=lot1) delivery_order = self.env['stock.picking'].create({ 'location_id': self.stock_location, 'location_dest_id': self.customer_location, @@ -580,7 +580,7 @@ class TestSinglePicking(TestStockCommon): 'product_id': self.productA.id, }) stock_location = self.env['stock.location'].browse(self.stock_location) - self.env['stock.quant']._increase_available_quantity(self.productA, stock_location, 1.0, lot_id=lot1) + self.env['stock.quant']._update_available_quantity(self.productA, stock_location, 1.0, lot_id=lot1) delivery_order = self.env['stock.picking'].create({ 'location_id': self.stock_location, 'location_dest_id': self.customer_location, @@ -647,7 +647,7 @@ class TestSinglePicking(TestStockCommon): 'product_id': self.productA.id, }) stock_location = self.env['stock.location'].browse(self.stock_location) - self.env['stock.quant']._increase_available_quantity(self.productA, stock_location, 1.0, lot_id=serial1) + self.env['stock.quant']._update_available_quantity(self.productA, stock_location, 1.0, lot_id=serial1) delivery_order = self.env['stock.picking'].create({ 'location_id': self.stock_location, 'location_dest_id': self.customer_location, diff --git a/addons/stock/tests/test_quant.py b/addons/stock/tests/test_quant.py index a9dae64d77f..d8c377dcc70 100644 --- a/addons/stock/tests/test_quant.py +++ b/addons/stock/tests/test_quant.py @@ -164,7 +164,7 @@ class StockQuant(TransactionCase): self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 0.0) self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 0) with self.assertRaises(ValidationError): - self.env['stock.quant']._increase_available_quantity(product1, stock_location, 1.0) + self.env['stock.quant']._update_available_quantity(product1, stock_location, 1.0) def test_get_available_quantity_9(self): """ Quantity availability by a demo user with access rights/rules. @@ -190,7 +190,7 @@ class StockQuant(TransactionCase): 'name': 'Product A', 'type': 'product', }) - self.env['stock.quant']._increase_available_quantity(product1, stock_location, 1.0) + self.env['stock.quant']._update_available_quantity(product1, stock_location, 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 1.0) def test_increase_available_quantity_2(self): @@ -208,7 +208,7 @@ class StockQuant(TransactionCase): 'quantity': 1.0, }) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 2.0) - self.env['stock.quant']._increase_available_quantity(product1, stock_location, 1.0) + self.env['stock.quant']._update_available_quantity(product1, stock_location, 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 3.0) self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 2) @@ -228,7 +228,7 @@ class StockQuant(TransactionCase): quant_id = cr2.fetchone() cr2.execute("SELECT 1 FROM stock_quant WHERE id=%s FOR UPDATE", quant_id) - self.env['stock.quant']._increase_available_quantity(product, stock_location, 1.0) + self.env['stock.quant']._update_available_quantity(product, stock_location, 1.0) cr2.rollback() cr2.close() self.assertEqual(self.env['stock.quant']._get_available_quantity(product, stock_location), 11.0) @@ -243,7 +243,33 @@ class StockQuant(TransactionCase): 'type': 'product', }) self.env = self.env(user=self.env.ref('base.user_demo')) - self.env['stock.quant']._increase_available_quantity(product1, stock_location, 1.0) + self.env['stock.quant']._update_available_quantity(product1, stock_location, 1.0) + + def test_increase_available_quantity_5(self): + """ Increase the available quantity when no quants are already in stock. + Increase a subLocation and check that quants are in this location. Also test inverse. + """ + stock_location = self.env.ref('stock.stock_location_stock') + stock_sub_location = stock_location.child_ids[0] + product1 = self.env['product.product'].create({ + 'name': 'Product A', + 'type': 'product', + }) + product2 = self.env['product.product'].create({ + 'name': 'Product B', + 'type': 'product', + }) + self.env['stock.quant']._update_available_quantity(product1, stock_location, 1.0) + self.env['stock.quant']._update_available_quantity(product1, stock_sub_location, 1.0) + + self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 2.0) + self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_sub_location), 1.0) + + self.env['stock.quant']._update_available_quantity(product2, stock_sub_location, 1.0) + self.env['stock.quant']._update_available_quantity(product2, stock_location, 1.0) + + self.assertEqual(self.env['stock.quant']._get_available_quantity(product2, stock_location), 2.0) + self.assertEqual(self.env['stock.quant']._get_available_quantity(product2, stock_sub_location), 1.0) def test_decrease_available_quantity_1(self): """ Decrease the available quantity when no quants are already in a location. @@ -253,7 +279,7 @@ class StockQuant(TransactionCase): 'name': 'Product A', 'type': 'product', }) - self.env['stock.quant']._decrease_available_quantity(product1, stock_location, 1.0) + self.env['stock.quant']._update_available_quantity(product1, stock_location, -1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), -1.0) def test_decrease_available_quantity_2(self): @@ -272,7 +298,7 @@ class StockQuant(TransactionCase): }) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 2.0) self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 2) - self.env['stock.quant']._decrease_available_quantity(product1, stock_location, 1.0) + self.env['stock.quant']._update_available_quantity(product1, stock_location, -1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 1.0) self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 1) @@ -290,7 +316,7 @@ class StockQuant(TransactionCase): # quantity increase cr2 = self.registry.cursor() cr2.execute("SELECT 1 FROM stock_quant WHERE id = %s FOR UPDATE", quants.ids) - self.env['stock.quant']._decrease_available_quantity(product, stock_location, 1.0) + self.env['stock.quant']._update_available_quantity(product, stock_location, -1.0) cr2.rollback() cr2.close() self.assertEqual(self.env['stock.quant']._get_available_quantity(product, stock_location), 9.0) @@ -311,7 +337,7 @@ class StockQuant(TransactionCase): 'quantity': 1.0, }) self.env = self.env(user=self.demo_user) - self.env['stock.quant']._decrease_available_quantity(product1, stock_location, 1.0) + self.env['stock.quant']._update_available_quantity(product1, stock_location, -1.0) self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 0) def test_increase_reserved_quantity_1(self): @@ -330,7 +356,7 @@ class StockQuant(TransactionCase): }) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 10.0) self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 1) - self.env['stock.quant']._increase_reserved_quantity(product1, stock_location, 10.0) + self.env['stock.quant']._update_reserved_quantity(product1, stock_location, 10.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 0.0) self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 1) @@ -351,7 +377,7 @@ class StockQuant(TransactionCase): }) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 10.0) self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 2) - self.env['stock.quant']._increase_reserved_quantity(product1, stock_location, 10.0) + self.env['stock.quant']._update_reserved_quantity(product1, stock_location, 10.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 0.0) self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 2) @@ -392,7 +418,7 @@ class StockQuant(TransactionCase): # total reserved quantity: 29 self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 29.0) self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 4) - self.env['stock.quant']._increase_reserved_quantity(product1, stock_location, 10.0) + self.env['stock.quant']._update_reserved_quantity(product1, stock_location, 10.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 19.0) self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 4) @@ -420,7 +446,7 @@ class StockQuant(TransactionCase): self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 0.0) self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 2) with self.assertRaises(UserError): - self.env['stock.quant']._increase_reserved_quantity(product1, stock_location, 10.0) + self.env['stock.quant']._update_reserved_quantity(product1, stock_location, 10.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 0.0) def test_increase_reserved_quantity_5(self): @@ -432,7 +458,7 @@ class StockQuant(TransactionCase): 'type': 'product', }) with self.assertRaises(UserError): - self.env['stock.quant']._increase_reserved_quantity(product1, stock_location, 1.0) + self.env['stock.quant']._update_reserved_quantity(product1, stock_location, 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 0.0) def test_decrease_reserved_quantity_1(self): @@ -449,7 +475,7 @@ class StockQuant(TransactionCase): }) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 0.0) self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 1) - self.env['stock.quant']._decrease_reserved_quantity(product1, stock_location, 10.0) + self.env['stock.quant']._update_reserved_quantity(product1, stock_location, -10.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 10.0) self.assertEqual(len(self.env['stock.quant']._gather(product1, stock_location)), 1) @@ -462,10 +488,10 @@ class StockQuant(TransactionCase): 'type': 'product', }) with self.assertRaises(UserError): - self.env['stock.quant']._increase_reserved_quantity(product1, stock_location, 1.0) + self.env['stock.quant']._update_reserved_quantity(product1, stock_location, 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 0.0) with self.assertRaises(UserError): - self.env['stock.quant']._decrease_reserved_quantity(product1, stock_location, 1.0) + self.env['stock.quant']._update_reserved_quantity(product1, stock_location, -1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 0.0) def test_action_done_1(self): @@ -475,15 +501,15 @@ class StockQuant(TransactionCase): 'name': 'Product A', 'type': 'product', }) - self.env['stock.quant']._increase_available_quantity(product1, stock_location, 2.0) + self.env['stock.quant']._update_available_quantity(product1, stock_location, 2.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 2.0) - self.env['stock.quant']._increase_reserved_quantity(product1, stock_location, 2.0) + self.env['stock.quant']._update_reserved_quantity(product1, stock_location, 2.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 0.0) - self.env['stock.quant']._decrease_reserved_quantity(product1, stock_location, 2.0) + self.env['stock.quant']._update_reserved_quantity(product1, stock_location, -2.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 2.0) - self.env['stock.quant']._decrease_available_quantity(product1, stock_location, 2.0) + self.env['stock.quant']._update_available_quantity(product1, stock_location, -2.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 0.0) - self.env['stock.quant']._increase_available_quantity(product1, pack_location, 2.0) + self.env['stock.quant']._update_available_quantity(product1, pack_location, 2.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, pack_location), 2.0) def test_mix_tracked_untracked_1(self): @@ -499,27 +525,27 @@ class StockQuant(TransactionCase): }) # add one tracked, one untracked - self.env['stock.quant']._increase_available_quantity(product1, stock_location, 1.0) - self.env['stock.quant']._increase_available_quantity(product1, stock_location, 1.0, lot_id=lot1) + self.env['stock.quant']._update_available_quantity(product1, stock_location, 1.0) + self.env['stock.quant']._update_available_quantity(product1, stock_location, 1.0, lot_id=lot1) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 2.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location, strict=True), 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location, lot_id=lot1), 1.0) - self.env['stock.quant']._increase_reserved_quantity(product1, stock_location, 1.0, lot_id=lot1, strict=True) + self.env['stock.quant']._update_reserved_quantity(product1, stock_location, 1.0, lot_id=lot1, strict=True) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location, strict=True), 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location, lot_id=lot1), 0.0) - self.env['stock.quant']._decrease_reserved_quantity(product1, stock_location, 1.0, lot_id=lot1, strict=True) + self.env['stock.quant']._update_reserved_quantity(product1, stock_location, -1.0, lot_id=lot1, strict=True) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 2.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location, strict=True), 1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location, lot_id=lot1), 1.0) with self.assertRaises(UserError): - self.env['stock.quant']._decrease_reserved_quantity(product1, stock_location, 1.0) + self.env['stock.quant']._update_reserved_quantity(product1, stock_location, -1.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location), 2.0) self.assertEqual(self.env['stock.quant']._get_available_quantity(product1, stock_location, strict=True), 1.0) diff --git a/addons/stock/views/product_views.xml b/addons/stock/views/product_views.xml index fcdb6333817..f479bcd5a2c 100644 --- a/addons/stock/views/product_views.xml +++ b/addons/stock/views/product_views.xml @@ -58,47 +58,6 @@ - - - Receipts - stock.move - ir.actions.act_window - form - tree,form - - - - -

- Click to register a receipt for this product. -

- Here you will find the history of all receipts related to - this product, as well as all future receipts you are waiting - from your suppliers. -

-
-
- - - Deliveries - stock.move - ir.actions.act_window - form - tree,form - - - - -

- Click to add a delivery order for this product. -

- Here you will find the history of all past deliveries related to - this product, as well as all the products you must deliver to - customers. -

-
-
- @@ -223,32 +182,6 @@ - - Product Kanban Stock - product.product - - - - - - - - - Receipts - - - Receipt - - - Deliveries - - - Delivery - - - - - product.product.view.form.easy.inherit.stock product.product diff --git a/addons/stock/views/stock_move_views.xml b/addons/stock/views/stock_move_views.xml index 3908dd89520..337a9b287eb 100644 --- a/addons/stock/views/stock_move_views.xml +++ b/addons/stock/views/stock_move_views.xml @@ -175,6 +175,7 @@ + @@ -211,6 +212,7 @@ + diff --git a/addons/stock/views/stock_picking_views.xml b/addons/stock/views/stock_picking_views.xml index 84a2d637ff7..79aa4ed3c73 100644 --- a/addons/stock/views/stock_picking_views.xml +++ b/addons/stock/views/stock_picking_views.xml @@ -244,11 +244,10 @@ - -
- + +
diff --git a/addons/stock/views/stock_scrap_views.xml b/addons/stock/views/stock_scrap_views.xml index 12e74eca51f..fbd2684d80a 100644 --- a/addons/stock/views/stock_scrap_views.xml +++ b/addons/stock/views/stock_scrap_views.xml @@ -43,7 +43,7 @@
- +