[MERGE] forward port branch 12.0 up to 82a8cdd6f2
This commit is contained in:
@@ -591,8 +591,10 @@ class AccountReconcileModel(models.Model):
|
||||
|
||||
if line_residual > total_residual:
|
||||
amount_percentage = (total_residual / line_residual) * 100
|
||||
else:
|
||||
elif total_residual:
|
||||
amount_percentage = (line_residual / total_residual) * 100 if total_residual else 0
|
||||
else:
|
||||
return False
|
||||
return amount_percentage >= self.match_total_amount_param
|
||||
|
||||
@api.multi
|
||||
|
||||
@@ -187,6 +187,70 @@ class TestAccountEntry(TestExpenseCommon):
|
||||
self.assertEquals(expense.total_amount, 9876.0)
|
||||
self.assertTrue(expense.employee_id in user_demo.employee_ids)
|
||||
|
||||
def test_partial_payment_multiexpense(self):
|
||||
bank_journal = self.env['account.journal'].create({
|
||||
'name': 'Payment Journal',
|
||||
'code': 'PAY',
|
||||
'type': 'bank',
|
||||
'company_id': self.env.user.company_id.id,
|
||||
})
|
||||
|
||||
outbound_pay_method = self.env['account.payment.method'].create({
|
||||
'name': 'outbound',
|
||||
'code': 'out',
|
||||
'payment_type': 'outbound',
|
||||
})
|
||||
|
||||
expense = self.env['hr.expense.sheet'].create({
|
||||
'name': 'Expense for John Smith',
|
||||
'employee_id': self.employee.id,
|
||||
})
|
||||
expense_line = self.env['hr.expense'].create({
|
||||
'name': 'Car Travel Expenses',
|
||||
'employee_id': self.employee.id,
|
||||
'product_id': self.product_expense.id,
|
||||
'unit_amount': 200.00,
|
||||
'tax_ids': [(6, 0, [self.tax.id])],
|
||||
'sheet_id': expense.id,
|
||||
'analytic_account_id': self.analytic_account.id,
|
||||
})
|
||||
expense_line.copy({
|
||||
'sheet_id': expense.id
|
||||
})
|
||||
expense.approve_expense_sheets()
|
||||
expense.action_sheet_move_create()
|
||||
|
||||
exp_move_lines = expense.account_move_id.line_ids
|
||||
payable_move_lines = exp_move_lines.filtered(lambda l: l.account_id.internal_type == 'payable')
|
||||
self.assertEquals(len(payable_move_lines), 2)
|
||||
|
||||
WizardRegister = self.env['hr.expense.sheet.register.payment.wizard'].with_context(active_ids=expense.ids)
|
||||
|
||||
register_pay1 = WizardRegister.create({
|
||||
'journal_id': bank_journal.id,
|
||||
'payment_method_id': outbound_pay_method.id,
|
||||
'amount': 300,
|
||||
})
|
||||
register_pay1.expense_post_payment()
|
||||
|
||||
exp_move_lines = expense.account_move_id.line_ids
|
||||
payable_move_lines = exp_move_lines.filtered(lambda l: l.account_id.internal_type == 'payable')
|
||||
self.assertEquals(len(payable_move_lines.filtered(lambda l: l.reconciled)), 1)
|
||||
|
||||
register_pay2 = WizardRegister.create({
|
||||
'journal_id': bank_journal.id,
|
||||
'payment_method_id': outbound_pay_method.id,
|
||||
'amount': 100,
|
||||
})
|
||||
register_pay2.expense_post_payment()
|
||||
exp_move_lines = expense.account_move_id.line_ids
|
||||
payable_move_lines = exp_move_lines.filtered(lambda l: l.account_id.internal_type == 'payable')
|
||||
self.assertEquals(len(payable_move_lines.filtered(lambda l: l.reconciled)), 2)
|
||||
|
||||
full_reconcile = payable_move_lines.mapped('full_reconcile_id')
|
||||
self.assertEquals(len(full_reconcile), 1)
|
||||
|
||||
|
||||
class TestExpenseRights(TestExpenseCommon):
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -109,7 +109,7 @@ class HrExpenseSheetRegisterPaymentWizard(models.TransientModel):
|
||||
# Reconcile the payment and the expense, i.e. lookup on the payable account move lines
|
||||
account_move_lines_to_reconcile = self.env['account.move.line']
|
||||
for line in payment.move_line_ids + expense_sheet.account_move_id.line_ids:
|
||||
if line.account_id.internal_type == 'payable':
|
||||
if line.account_id.internal_type == 'payable' and not line.reconciled:
|
||||
account_move_lines_to_reconcile |= line
|
||||
account_move_lines_to_reconcile.reconcile()
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
import logging
|
||||
import math
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
from datetime import datetime, time
|
||||
from pytz import timezone, UTC
|
||||
|
||||
@@ -18,6 +20,9 @@ from odoo.tools.translate import _
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
# Used to agglomerate the attendances in order to find the hour_from and hour_to
|
||||
# See _onchange_request_parameters
|
||||
DummyAttendance = namedtuple('DummyAttendance', 'hour_from, hour_to, dayofweek, day_period')
|
||||
|
||||
class HolidaysRequest(models.Model):
|
||||
""" Leave Requests Access specifications
|
||||
@@ -287,12 +292,17 @@ class HolidaysRequest(models.Model):
|
||||
return
|
||||
|
||||
domain = [('calendar_id', '=', self.employee_id.resource_calendar_id.id or self.env.user.company_id.resource_calendar_id.id)]
|
||||
attendances = self.env['resource.calendar.attendance'].search(domain, order='dayofweek, day_period DESC')
|
||||
attendances = self.env['resource.calendar.attendance'].read_group(domain, ['ids:array_agg(id)', 'hour_from:min(hour_from)', 'hour_to:max(hour_to)', 'dayofweek', 'day_period'], ['dayofweek', 'day_period'], lazy=False)
|
||||
|
||||
# Must be sorted by dayofweek ASC and day_period DESC
|
||||
attendances = sorted([DummyAttendance(group['hour_from'], group['hour_to'], group['dayofweek'], group['day_period']) for group in attendances], key=lambda att: (att.dayofweek, att.day_period != 'morning'))
|
||||
|
||||
default_value = DummyAttendance(0, 0, 0, 'morning')
|
||||
|
||||
# find first attendance coming after first_day
|
||||
attendance_from = next((att for att in attendances if int(att.dayofweek) >= self.request_date_from.weekday()), attendances[0])
|
||||
attendance_from = next((att for att in attendances if int(att.dayofweek) >= self.request_date_from.weekday()), attendances[0] if attendances else default_value)
|
||||
# find last attendance coming before last_day
|
||||
attendance_to = next((att for att in reversed(attendances) if int(att.dayofweek) <= self.request_date_to.weekday()), attendances[-1])
|
||||
attendance_to = next((att for att in reversed(attendances) if int(att.dayofweek) <= self.request_date_to.weekday()), attendances[-1] if attendances else default_value)
|
||||
|
||||
if self.request_unit_half:
|
||||
if self.request_date_from_period == 'am':
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import test_access_rights
|
||||
from . import test_automatic_leave_dates
|
||||
from . import test_holidays_flow
|
||||
from . import test_hr_leave_type
|
||||
from . import test_accrual_allocations
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from datetime import date, datetime
|
||||
|
||||
from odoo.tests.common import Form, tagged
|
||||
|
||||
from odoo.addons.hr_holidays.tests.common import TestHrHolidaysBase
|
||||
|
||||
|
||||
@tagged('prout')
|
||||
class TestAutomaticLeaveDates(TestHrHolidaysBase):
|
||||
def setUp(self):
|
||||
super(TestAutomaticLeaveDates, self).setUp()
|
||||
|
||||
self.leave_type = self.env['hr.leave.type'].create({
|
||||
'name': 'Automatic Test',
|
||||
'time_type': 'leave',
|
||||
'allocation_type': 'no',
|
||||
'validity_start': False,
|
||||
})
|
||||
|
||||
def test_no_attendances(self):
|
||||
calendar = self.env['resource.calendar'].create({
|
||||
'name': 'No Attendances',
|
||||
'attendance_ids': [(5, 0, 0)],
|
||||
})
|
||||
employee = self.employee_emp
|
||||
employee.resource_calendar_id = calendar
|
||||
|
||||
with Form(self.env['hr.leave']) as leave_form:
|
||||
leave_form.employee_id = employee
|
||||
leave_form.holiday_status_id = self.leave_type
|
||||
leave_form.request_date_from = date(2019, 9, 2)
|
||||
leave_form.request_date_to = date(2019, 9, 2)
|
||||
leave_form.request_unit_half = True
|
||||
leave_form.request_date_from_period = 'am'
|
||||
|
||||
self.assertEqual(leave_form.number_of_days_display, 0)
|
||||
self.assertEqual(leave_form.number_of_hours_display, 0)
|
||||
|
||||
def test_single_attendance_on_morning_and_afternoon(self):
|
||||
calendar = self.env['resource.calendar'].create({
|
||||
'name': 'simple morning + afternoon',
|
||||
'attendance_ids': [(5, 0, 0),
|
||||
(0, 0, {
|
||||
'name': 'monday morning',
|
||||
'hour_from': 8,
|
||||
'hour_to': 12,
|
||||
'day_period': 'morning',
|
||||
'dayofweek': '0',
|
||||
}),
|
||||
(0, 0, {
|
||||
'name': 'monday afternoon',
|
||||
'hour_from': 13,
|
||||
'hour_to': 17,
|
||||
'day_period': 'afternoon',
|
||||
'dayofweek': '0',
|
||||
})]
|
||||
})
|
||||
|
||||
employee = self.employee_emp
|
||||
employee.resource_calendar_id = calendar
|
||||
|
||||
with Form(self.env['hr.leave']) as leave_form:
|
||||
leave_form.employee_id = employee
|
||||
leave_form.holiday_status_id = self.leave_type
|
||||
leave_form.request_date_from = date(2019, 9, 2)
|
||||
leave_form.request_date_to = date(2019, 9, 2)
|
||||
leave_form.request_unit_half = True
|
||||
leave_form.request_date_from_period = 'am'
|
||||
|
||||
self.assertEqual(leave_form.number_of_days_display, .5)
|
||||
self.assertEqual(leave_form.number_of_hours_display, 4)
|
||||
|
||||
leave_form.request_date_from_period = 'pm'
|
||||
|
||||
self.assertEqual(leave_form.number_of_days_display, .5)
|
||||
self.assertEqual(leave_form.number_of_hours_display, 4)
|
||||
|
||||
def test_multiple_attendance_on_morning(self):
|
||||
calendar = self.env['resource.calendar'].create({
|
||||
'name': 'multi morning',
|
||||
'attendance_ids': [(5, 0, 0),
|
||||
(0, 0, {
|
||||
'name': 'monday morning 1',
|
||||
'hour_from': 8,
|
||||
'hour_to': 10,
|
||||
'day_period': 'morning',
|
||||
'dayofweek': '0',
|
||||
}),
|
||||
(0, 0, {
|
||||
'name': 'monday morning 2',
|
||||
'hour_from': 10.25,
|
||||
'hour_to': 12.25,
|
||||
'day_period': 'morning',
|
||||
'dayofweek': '0',
|
||||
}),
|
||||
(0, 0, {
|
||||
'name': 'monday afternoon',
|
||||
'hour_from': 13,
|
||||
'hour_to': 17,
|
||||
'day_period': 'afternoon',
|
||||
'dayofweek': '0',
|
||||
})]
|
||||
})
|
||||
employee = self.employee_emp
|
||||
employee.resource_calendar_id = calendar
|
||||
|
||||
with Form(self.env['hr.leave']) as leave_form:
|
||||
leave_form.employee_id = employee
|
||||
leave_form.holiday_status_id = self.leave_type
|
||||
leave_form.request_date_from = date(2019, 9, 2)
|
||||
leave_form.request_date_to = date(2019, 9, 2)
|
||||
leave_form.request_unit_half = True
|
||||
leave_form.request_date_from_period = 'am'
|
||||
|
||||
self.assertEqual(leave_form.number_of_days_display, .5)
|
||||
self.assertEqual(leave_form.number_of_hours_display, 4)
|
||||
|
||||
leave_form.request_date_from_period = 'pm'
|
||||
|
||||
self.assertEqual(leave_form.number_of_days_display, .5)
|
||||
self.assertEqual(leave_form.number_of_hours_display, 4)
|
||||
|
||||
def test_attendance_on_morning(self):
|
||||
calendar = self.env['resource.calendar'].create({
|
||||
'name': 'Morning only',
|
||||
'attendance_ids': [(5, 0, 0),
|
||||
(0, 0, {
|
||||
'name': 'Monday All day',
|
||||
'hour_from': 8,
|
||||
'hour_to': 16,
|
||||
'day_period': 'morning',
|
||||
'dayofweek': '0',
|
||||
})],
|
||||
})
|
||||
employee = self.employee_emp
|
||||
employee.resource_calendar_id = calendar
|
||||
with Form(self.env['hr.leave']) as leave_form:
|
||||
leave_form.employee_id = employee
|
||||
leave_form.holiday_status_id = self.leave_type
|
||||
leave_form.request_date_from = date(2019, 9, 2)
|
||||
leave_form.request_date_to = date(2019, 9, 2)
|
||||
leave_form.request_unit_half = True
|
||||
# Ask for morning
|
||||
leave_form.request_date_from_period = 'am'
|
||||
|
||||
self.assertEqual(leave_form.number_of_days_display, 1)
|
||||
self.assertEqual(leave_form.number_of_hours_display, 8)
|
||||
|
||||
# Ask for afternoon
|
||||
leave_form.request_date_from_period = 'pm'
|
||||
|
||||
self.assertEqual(leave_form.number_of_days_display, 1)
|
||||
self.assertEqual(leave_form.number_of_hours_display, 8)
|
||||
|
||||
def test_attendance_next_day(self):
|
||||
calendar = self.env['resource.calendar'].create({
|
||||
'name': 'auto next day',
|
||||
'attendance_ids': [(5, 0, 0),
|
||||
(0, 0, {
|
||||
'name': 'tuesday morning',
|
||||
'hour_from': 8,
|
||||
'hour_to': 12,
|
||||
'day_period': 'morning',
|
||||
'dayofweek': '1',
|
||||
})]
|
||||
})
|
||||
employee = self.employee_emp
|
||||
employee.resource_calendar_id = calendar
|
||||
|
||||
with Form(self.env['hr.leave']) as leave_form:
|
||||
leave_form.employee_id = employee
|
||||
leave_form.holiday_status_id = self.leave_type
|
||||
leave_form.request_date_from = date(2019, 9, 2)
|
||||
leave_form.request_date_to = date(2019, 9, 2)
|
||||
leave_form.request_unit_half = True
|
||||
leave_form.request_date_from_period = 'am'
|
||||
|
||||
|
||||
self.assertEqual(leave_form.number_of_days_display, 0)
|
||||
self.assertEqual(leave_form.number_of_hours_display, 0)
|
||||
self.assertEqual(leave_form.date_from, datetime(2019, 9, 2, 6, 0, 0))
|
||||
self.assertEqual(leave_form.date_to, datetime(2019, 9, 2, 10, 0, 0))
|
||||
|
||||
def test_attendance_previous_day(self):
|
||||
calendar = self.env['resource.calendar'].create({
|
||||
'name': 'auto next day',
|
||||
'attendance_ids': [(5, 0, 0),
|
||||
(0, 0, {
|
||||
'name': 'monday morning',
|
||||
'hour_from': 8,
|
||||
'hour_to': 12,
|
||||
'day_period': 'morning',
|
||||
'dayofweek': '0',
|
||||
})]
|
||||
})
|
||||
employee = self.employee_emp
|
||||
employee.resource_calendar_id = calendar
|
||||
|
||||
with Form(self.env['hr.leave']) as leave_form:
|
||||
leave_form.employee_id = employee
|
||||
leave_form.holiday_status_id = self.leave_type
|
||||
leave_form.request_date_from = date(2019, 9, 3)
|
||||
leave_form.request_date_to = date(2019, 9, 3)
|
||||
leave_form.request_unit_half = True
|
||||
leave_form.request_date_from_period = 'am'
|
||||
|
||||
|
||||
self.assertEqual(leave_form.number_of_days_display, 0)
|
||||
self.assertEqual(leave_form.number_of_hours_display, 0)
|
||||
self.assertEqual(leave_form.date_from, datetime(2019, 9, 3, 6, 0, 0))
|
||||
self.assertEqual(leave_form.date_to, datetime(2019, 9, 3, 10, 0, 0))
|
||||
@@ -237,10 +237,6 @@ class StockMove(models.Model):
|
||||
keys = super(StockMove, self)._key_assign_picking()
|
||||
return keys + (self.created_production_id,)
|
||||
|
||||
def _search_picking_for_assignation_domain(self):
|
||||
res = super(StockMove, self)._search_picking_for_assignation_domain()
|
||||
res.append(('move_lines.created_production_id', '=', self.created_production_id.id))
|
||||
return res
|
||||
|
||||
def _compute_kit_quantities(self, product_id, kit_qty, kit_bom, filters):
|
||||
""" Computes the quantity delivered or received when a kit is sold or purchased.
|
||||
@@ -275,4 +271,4 @@ class StockMove(models.Model):
|
||||
# doesn't make sense.
|
||||
return min(qty_ratios) // 1
|
||||
else:
|
||||
return 0.0
|
||||
return 0.0
|
||||
@@ -136,7 +136,8 @@
|
||||
</t>
|
||||
</tbody>
|
||||
</table>
|
||||
<t t-set="has_product_reserved" t-value="o.move_raw_ids.filtered(lambda x: x.product_uom_qty != x.reserved_availability)"/>
|
||||
<t t-set="decimal_precision" t-value="o.env['decimal.precision'].precision_get('Product Unit of Measure')"/>
|
||||
<t t-set="has_product_reserved" t-value="o.move_raw_ids.filtered(lambda x: round(x.product_uom_qty, decimal_precision) != round(x.reserved_availability, decimal_precision))"/>
|
||||
<p t-if="o.state !='done' and (not has_product_available or has_product_reserved)" class="fa fa-exclamation-triangle">
|
||||
All components could not be reserved. Click on the "Check Availability button" to try to reserve components.
|
||||
</p>
|
||||
|
||||
@@ -122,109 +122,6 @@ class TestMultistepManufacturingWarehouse(TestMrpCommon):
|
||||
self.assertEqual(sam_move.picking_type_id, self.warehouse.sam_type_id)
|
||||
self.assertFalse(sam_move.move_dest_ids)
|
||||
|
||||
def test_manufacturing_complex_product_3_steps(self):
|
||||
""" Test MO/picking after manufacturing a complex product which uses
|
||||
manufactured components. Ensure that everything is created and picked
|
||||
correctly.
|
||||
"""
|
||||
# Create manifactured product which uses another manifactured
|
||||
|
||||
product_form = Form(self.env['product.product'])
|
||||
product_form.name = 'Arrow'
|
||||
product_form.type = 'product'
|
||||
product_form.route_ids.clear()
|
||||
product_form.route_ids.add(self.warehouse.manufacture_pull_id.route_id)
|
||||
product_form.route_ids.add(self.warehouse.mto_pull_id.route_id)
|
||||
self.complex_product = product_form.save()
|
||||
|
||||
## Create raw product for manufactured product
|
||||
product_form = Form(self.env['product.product'])
|
||||
product_form.name = 'Raw Iron'
|
||||
product_form.type = 'product'
|
||||
product_form.uom_id = self.uom_unit
|
||||
product_form.uom_po_id = self.uom_unit
|
||||
self.raw_product_2 = product_form.save()
|
||||
|
||||
## Create bom for manufactured product
|
||||
bom_product_form = Form(self.env['mrp.bom'])
|
||||
bom_product_form.product_id = self.complex_product
|
||||
bom_product_form.product_tmpl_id = self.complex_product.product_tmpl_id
|
||||
with bom_product_form.bom_line_ids.new() as line:
|
||||
line.product_id = self.finished_product
|
||||
line.product_qty = 1.0
|
||||
with bom_product_form.bom_line_ids.new() as line:
|
||||
line.product_id = self.raw_product_2
|
||||
line.product_qty = 1.0
|
||||
|
||||
self.complex_bom = bom_product_form.save()
|
||||
|
||||
with Form(self.warehouse) as warehouse:
|
||||
warehouse.manufacture_steps = 'pbm_sam'
|
||||
|
||||
production_form = Form(self.env['mrp.production'])
|
||||
production_form.product_id = self.complex_product
|
||||
production_form.picking_type_id = self.warehouse.manu_type_id
|
||||
production = production_form.save()
|
||||
production.action_confirm()
|
||||
|
||||
move_raw_ids = production.move_raw_ids
|
||||
self.assertEqual(len(move_raw_ids), 2)
|
||||
sfp_move_raw_id, raw_move_raw_id = move_raw_ids
|
||||
self.assertEqual(sfp_move_raw_id.product_id, self.finished_product)
|
||||
self.assertEqual(raw_move_raw_id.product_id, self.raw_product_2)
|
||||
|
||||
for move_raw_id in move_raw_ids:
|
||||
self.assertEqual(move_raw_id.picking_type_id, self.warehouse.manu_type_id)
|
||||
|
||||
pbm_move = move_raw_id.move_orig_ids
|
||||
self.assertEqual(len(pbm_move), 1)
|
||||
self.assertEqual(pbm_move.location_id, self.warehouse.lot_stock_id)
|
||||
self.assertEqual(pbm_move.location_dest_id, self.warehouse.pbm_loc_id)
|
||||
self.assertEqual(pbm_move.picking_type_id, self.warehouse.pbm_type_id)
|
||||
|
||||
move_finished_ids = production.move_finished_ids
|
||||
self.assertEqual(len(move_finished_ids), 1)
|
||||
self.assertEqual(move_finished_ids.product_id, self.complex_product)
|
||||
self.assertEqual(move_finished_ids.picking_type_id, self.warehouse.manu_type_id)
|
||||
sam_move = move_finished_ids.move_dest_ids
|
||||
self.assertEqual(len(sam_move), 1)
|
||||
self.assertEqual(sam_move.location_id, self.warehouse.sam_loc_id)
|
||||
self.assertEqual(sam_move.location_dest_id, self.warehouse.lot_stock_id)
|
||||
self.assertEqual(sam_move.picking_type_id, self.warehouse.sam_type_id)
|
||||
self.assertFalse(sam_move.move_dest_ids)
|
||||
|
||||
pickings = production.picking_ids.sorted('id', reverse=True)
|
||||
self.assertEqual(len(pickings), 3)
|
||||
|
||||
# Picking: SFP PostProcessing -> Stock
|
||||
## Stick from Subprocess
|
||||
picking = self.env['stock.picking'].search([
|
||||
('move_lines.product_id', '=', self.finished_product.id),
|
||||
('location_dest_id', '=', self.warehouse.lot_stock_id.id),
|
||||
('group_id', '=', production.procurement_group_id.id)
|
||||
])
|
||||
self.assertEqual(len(picking.move_lines), 1)
|
||||
|
||||
# Picking: PC Stock -> Preprocessing
|
||||
## Stick
|
||||
## Raw Iron
|
||||
picking = self.env['stock.picking'].search([
|
||||
('move_lines.product_id', 'in', [self.finished_product.id, self.raw_product_2.id]),
|
||||
('location_id', '=', self.warehouse.lot_stock_id.id),
|
||||
('group_id', '=', production.procurement_group_id.id)
|
||||
])
|
||||
self.assertEqual(len(picking.move_lines), 2)
|
||||
|
||||
# Picking: SFP PostProcessing -> Stock
|
||||
## Arrow from this process
|
||||
picking = picking = self.env['stock.picking'].search([
|
||||
('move_lines.product_id', '=', self.complex_product.id),
|
||||
('location_dest_id', '=', self.warehouse.lot_stock_id.id),
|
||||
('group_id', '=', production.procurement_group_id.id)
|
||||
])
|
||||
self.assertEqual(len(picking.move_lines), 1)
|
||||
|
||||
|
||||
def test_manufacturing_flow(self):
|
||||
""" Simulate a pick pack ship delivery combined with a picking before
|
||||
manufacturing and store after manufacturing. Also ensure that the MO and
|
||||
|
||||
@@ -112,6 +112,7 @@ class Pricelist(models.Model):
|
||||
self.ensure_one()
|
||||
if not date:
|
||||
date = self._context.get('date') or fields.Date.context_today(self)
|
||||
date = fields.Date.to_date(date) # handwritten query below does not work with non-dates (e.g. datetimes)
|
||||
if not uom_id and self._context.get('uom'):
|
||||
uom_id = self._context['uom']
|
||||
if uom_id:
|
||||
@@ -319,10 +320,10 @@ class Pricelist(models.Model):
|
||||
return res[partner_id].id
|
||||
|
||||
def _get_partner_pricelist_multi_search_domain_hook(self):
|
||||
return []
|
||||
return [('active', '=', True)]
|
||||
|
||||
def _get_partner_pricelist_multi_filter_hook(self):
|
||||
return self
|
||||
return self.filtered('active')
|
||||
|
||||
def _get_partner_pricelist_multi(self, partner_ids, company_id=None):
|
||||
""" Retrieve the applicable pricelist for given partners in a given company.
|
||||
|
||||
@@ -404,8 +404,6 @@ class PurchaseOrder(models.Model):
|
||||
'default_company_id': self.company_id.id,
|
||||
'company_id': self.company_id.id
|
||||
}
|
||||
if self.user_id:
|
||||
result['context']['default_user_id'] = self.user_id.id
|
||||
# choose the view_mode accordingly
|
||||
if len(self.invoice_ids) > 1 and not create_bill:
|
||||
result['domain'] = "[('id', 'in', " + str(self.invoice_ids.ids) + ")]"
|
||||
|
||||
@@ -682,20 +682,15 @@ class StockMove(models.Model):
|
||||
self.ensure_one()
|
||||
return self.group_id, self.location_id, self.location_dest_id, self.picking_type_id
|
||||
|
||||
def _search_picking_for_assignation_domain(self):
|
||||
return [
|
||||
def _search_picking_for_assignation(self):
|
||||
self.ensure_one()
|
||||
picking = self.env['stock.picking'].search([
|
||||
('group_id', '=', self.group_id.id),
|
||||
('location_id', '=', self.location_id.id),
|
||||
('location_dest_id', '=', self.location_dest_id.id),
|
||||
('picking_type_id', '=', self.picking_type_id.id),
|
||||
('printed', '=', False),
|
||||
('state', 'in', ['draft', 'confirmed', 'waiting',
|
||||
'partially_available', 'assigned'])
|
||||
]
|
||||
|
||||
def _search_picking_for_assignation(self):
|
||||
self.ensure_one()
|
||||
picking = self.env['stock.picking'].search(self._search_picking_for_assignation_domain(), limit=1)
|
||||
('state', 'in', ['draft', 'confirmed', 'waiting', 'partially_available', 'assigned'])], limit=1)
|
||||
return picking
|
||||
|
||||
def _assign_picking(self):
|
||||
|
||||
@@ -131,13 +131,13 @@ class LandedCost(models.Model):
|
||||
prec_digits = self.env.user.company_id.currency_id.decimal_places
|
||||
for landed_cost in self:
|
||||
total_amount = sum(landed_cost.valuation_adjustment_lines.mapped('additional_landed_cost'))
|
||||
if not tools.float_compare(total_amount, landed_cost.amount_total, precision_digits=prec_digits) == 0:
|
||||
if not tools.float_is_zero(total_amount - landed_cost.amount_total, precision_digits=prec_digits):
|
||||
return False
|
||||
|
||||
val_to_cost_lines = defaultdict(lambda: 0.0)
|
||||
for val_line in landed_cost.valuation_adjustment_lines:
|
||||
val_to_cost_lines[val_line.cost_line_id] += val_line.additional_landed_cost
|
||||
if any(tools.float_compare(cost_line.price_unit, val_amount, precision_digits=prec_digits) != 0
|
||||
if any(not tools.float_is_zero(cost_line.price_unit - val_amount, precision_digits=prec_digits)
|
||||
for cost_line, val_amount in val_to_cost_lines.items()):
|
||||
return False
|
||||
return True
|
||||
|
||||
@@ -330,18 +330,19 @@ class View(models.Model):
|
||||
qcontext['main_object'] = self
|
||||
|
||||
cur = Website.get_current_website()
|
||||
qcontext['multi_website_websites_current'] = {'website_id': cur.id, 'name': cur.name, 'domain': cur.domain}
|
||||
qcontext['multi_website_websites'] = [
|
||||
{'website_id': website.id, 'name': website.name, 'domain': website.domain}
|
||||
for website in Website.search([]) if website != cur
|
||||
]
|
||||
if self.env.user.has_group('website.group_website_publisher') and self.env.user.has_group('website.group_multi_website'):
|
||||
qcontext['multi_website_websites_current'] = {'website_id': cur.id, 'name': cur.name, 'domain': cur.domain}
|
||||
qcontext['multi_website_websites'] = [
|
||||
{'website_id': website.id, 'name': website.name, 'domain': website.domain}
|
||||
for website in Website.search([]) if website != cur
|
||||
]
|
||||
|
||||
cur_company = self.env.user.company_id
|
||||
qcontext['multi_website_companies_current'] = {'company_id': cur_company.id, 'name': cur_company.name}
|
||||
qcontext['multi_website_companies'] = [
|
||||
{'company_id': comp.id, 'name': comp.name}
|
||||
for comp in self.env.user.company_ids if comp != cur_company
|
||||
]
|
||||
cur_company = self.env.user.company_id
|
||||
qcontext['multi_website_companies_current'] = {'company_id': cur_company.id, 'name': cur_company.name}
|
||||
qcontext['multi_website_companies'] = [
|
||||
{'company_id': comp.id, 'name': comp.name}
|
||||
for comp in self.env.user.company_ids if comp != cur_company
|
||||
]
|
||||
|
||||
qcontext.update(dict(
|
||||
self._context.copy(),
|
||||
|
||||
@@ -238,9 +238,11 @@ class WebsiteBlog(http.Controller):
|
||||
tags = request.env['blog.tag'].search([])
|
||||
|
||||
# Find next Post
|
||||
all_post = BlogPost.search([('blog_id', '=', blog.id)])
|
||||
blog_post_domain = [('blog_id', '=', blog.id)]
|
||||
if not request.env.user.has_group('website.group_website_designer'):
|
||||
all_post = all_post.filtered(lambda r: r.post_date <= fields.Datetime.now())
|
||||
blog_post_domain += [('post_date', '<=', fields.Datetime.now())]
|
||||
|
||||
all_post = BlogPost.search(blog_post_domain)
|
||||
|
||||
if blog_post not in all_post:
|
||||
return request.redirect("/blog/%s" % (slug(blog_post.blog_id)))
|
||||
|
||||
@@ -76,6 +76,13 @@ class TestFields(common.TransactionCase):
|
||||
field = self.env['test_new_api.message']._fields['x_bool_false_computed']
|
||||
self.assertFalse(field.depends)
|
||||
|
||||
def test_10_display_name(self):
|
||||
""" test definition of automatic field 'display_name' """
|
||||
field = type(self.env['test_new_api.discussion']).display_name
|
||||
self.assertTrue(field.automatic)
|
||||
self.assertTrue(field.compute)
|
||||
self.assertEqual(field.depends, ('name',))
|
||||
|
||||
def test_10_non_stored(self):
|
||||
""" test non-stored fields """
|
||||
# a field declared with store=False should not have a column
|
||||
|
||||
+6
-6
@@ -490,6 +490,10 @@ class Field(MetaField('DummyField', (object,), {})):
|
||||
|
||||
def _setup_regular_base(self, model):
|
||||
""" Setup the attributes of a non-related field. """
|
||||
pass
|
||||
|
||||
def _setup_regular_full(self, model):
|
||||
""" Determine the dependencies and inverse field(s) of ``self``. """
|
||||
if self.depends is not None:
|
||||
return
|
||||
|
||||
@@ -507,10 +511,6 @@ class Field(MetaField('DummyField', (object,), {})):
|
||||
else:
|
||||
self.depends = tuple(get_depends(self.compute))
|
||||
|
||||
def _setup_regular_full(self, model):
|
||||
""" Setup the inverse field(s) of ``self``. """
|
||||
pass
|
||||
|
||||
#
|
||||
# Setup of related fields
|
||||
#
|
||||
@@ -2364,8 +2364,8 @@ class _RelationalMulti(_Relational):
|
||||
for record in records:
|
||||
record[self.name] = record[self.name].filtered(accessible)
|
||||
|
||||
def _setup_regular_base(self, model):
|
||||
super(_RelationalMulti, self)._setup_regular_base(model)
|
||||
def _setup_regular_full(self, model):
|
||||
super(_RelationalMulti, self)._setup_regular_full(model)
|
||||
if isinstance(self.domain, list):
|
||||
self.depends += tuple(
|
||||
self.name + '.' + arg[0]
|
||||
|
||||
+9
-9
@@ -2609,6 +2609,15 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
|
||||
|
||||
cls._setup_done = True
|
||||
|
||||
# 5. determine and validate rec_name
|
||||
if cls._rec_name:
|
||||
assert cls._rec_name in cls._fields, \
|
||||
"Invalid rec_name %s for model %s" % (cls._rec_name, cls._name)
|
||||
elif 'name' in cls._fields:
|
||||
cls._rec_name = 'name'
|
||||
elif 'x_name' in cls._fields:
|
||||
cls._rec_name = 'x_name'
|
||||
|
||||
@api.model
|
||||
def _setup_fields(self):
|
||||
""" Setup the fields, except for recomputation triggers. """
|
||||
@@ -2661,15 +2670,6 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
|
||||
# register constraints and onchange methods
|
||||
cls._init_constraints_onchanges()
|
||||
|
||||
# validate rec_name
|
||||
if cls._rec_name:
|
||||
assert cls._rec_name in cls._fields, \
|
||||
"Invalid rec_name %s for model %s" % (cls._rec_name, cls._name)
|
||||
elif 'name' in cls._fields:
|
||||
cls._rec_name = 'name'
|
||||
elif 'x_name' in cls._fields:
|
||||
cls._rec_name = 'x_name'
|
||||
|
||||
@api.model
|
||||
def fields_get(self, allfields=None, attributes=None):
|
||||
""" fields_get([fields][, attributes])
|
||||
|
||||
Reference in New Issue
Block a user