Skip to content

Commit

Permalink
[MERGE] forward port branch 12.0 up to 82a8cdd
Browse files Browse the repository at this point in the history
  • Loading branch information
KangOl committed Sep 6, 2019
2 parents e270eff + 82a8cdd commit 9bf0b04
Show file tree
Hide file tree
Showing 18 changed files with 345 additions and 158 deletions.
4 changes: 3 additions & 1 deletion addons/account/models/account_reconcile_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -591,8 +591,10 @@ def _check_rule_propositions(self, statement_line, candidates):

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
Expand Down
64 changes: 64 additions & 0 deletions addons/hr_expense/tests/test_expenses.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,70 @@ def test_expense_from_email_without_product(self):
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def expense_post_payment(self):
# 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()

Expand Down
16 changes: 13 additions & 3 deletions addons/hr_holidays/models/hr_leave.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import logging
import math

from collections import namedtuple

from datetime import datetime, time
from pytz import timezone, UTC

Expand All @@ -18,6 +20,9 @@

_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
Expand Down Expand Up @@ -287,12 +292,17 @@ def _onchange_request_parameters(self):
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':
Expand Down
1 change: 1 addition & 0 deletions addons/hr_holidays/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
212 changes: 212 additions & 0 deletions addons/hr_holidays/tests/test_automatic_leave_dates.py
Original file line number Diff line number Diff line change
@@ -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))
6 changes: 1 addition & 5 deletions addons/mrp/models/stock_move.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,10 +237,6 @@ def _key_assign_picking(self):
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.
Expand Down Expand Up @@ -275,4 +271,4 @@ def _compute_kit_quantities(self, product_id, kit_qty, kit_bom, filters):
# doesn't make sense.
return min(qty_ratios) // 1
else:
return 0.0
return 0.0
3 changes: 2 additions & 1 deletion addons/mrp/report/mrp_production_templates.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
Loading

0 comments on commit 9bf0b04

Please sign in to comment.