1
0
forked from Mapan/odoo17e
odoo17e-kedaikipas58/addons/sale_planning/tests/test_sale_planning.py
2024-12-10 09:04:09 +07:00

367 lines
18 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details
import pytz
from math import ceil
from datetime import datetime, timedelta
from freezegun import freeze_time
from psycopg2 import IntegrityError
from odoo.tests import Form, tagged
from odoo.tools import mute_logger, float_compare
from .common import TestCommonSalePlanning
@tagged('post_install', '-at_install')
class TestSalePlanning(TestCommonSalePlanning):
def test_planning_slot_form(self):
slot_form = Form(self.env['planning.slot'])
slot_form.sale_line_id = self.plannable_sol
slot = slot_form.save()
self.assertEqual(slot.sale_line_id, self.plannable_sol, 'Plannable services should have type \'service\'.')
self.assertFalse(not slot.start_datetime, 'Salable slot created from gantt have default date')
self.assertFalse(not slot.end_datetime, 'Salable slot created from gantt have default date')
def test_planning_slot_not_salable(self):
with self.assertRaises(IntegrityError), mute_logger('odoo.sql_db'):
self.env['planning.slot'].create({
'start_datetime': False,
'end_datetime': False,
})
def test_planning_sol_confirmation(self):
so_form = Form(self.env['sale.order'])
so_form.partner_id = self.planning_partner
with so_form.order_line.new() as sol_form:
sol_form.product_id = self.plannable_product
sol_form.product_uom_qty = 50
so = so_form.save()
self.assertEqual(so.planning_hours_to_plan, 0.0, 'There are no hours to plan before SO confirmation.')
self.assertEqual(so.planning_hours_planned, 0.0, 'There are no hours planned before SO confirmation.')
self.assertFalse(so.order_line.planning_slot_ids, 'There should not exists planning slots before SO confirmation')
so.action_confirm()
self.assertEqual(float_compare(so.planning_hours_to_plan, 50.0, precision_digits=2), 0, 'There should be 50.0 to plan after SO confirmation.')
self.assertEqual(so.planning_hours_planned, 0.0, 'There are no hours planned just after SO confirmation.')
self.assertEqual(len(so.order_line.planning_slot_ids), 1, 'There should exist exactly 1 planning slot just after SO confirmation')
slot = so.order_line.planning_slot_ids
self.assertFalse(slot.start_datetime, 'Slot start datetime should be unset.')
self.assertFalse(slot.end_datetime, 'Slot end datetime should be unset.')
self.assertFalse(slot.employee_id, 'Slot should be unassigned.')
self.assertEqual(float_compare(slot.allocated_hours, 50.0, precision_digits=2), 0, 'Slot should have 50.0 hours "allocated"')
self.assertEqual(float_compare(slot.allocated_percentage, 100.0, precision_digits=2), 0, 'Slot should have 100%% allocated percentage')
for field in slot._fields.keys():
try:
slot[field]
except Exception as e:
raise AssertionError("Error raised unexpectedly while computing a field of the slot! Exception: " + e.args[0])
def test_planning_plan_order_no_employee(self):
so_form = Form(self.env['sale.order'])
so_form.partner_id = self.planning_partner
with so_form.order_line.new() as sol_form:
sol_form.product_id = self.plannable_product
sol_form.product_uom_qty = 50
so = so_form.save()
so.action_confirm()
Slot = self.env['planning.slot'].with_context(
default_start_datetime='2021-07-25 00:00:00',
default_end_datetime='2021-07-31 23:59:59',
scale='week',
focus_date='2021-07-31 00:00:00',
planning_gantt_active_sale_order_id=so.id,
)
with freeze_time('2021-07-26'):
Slot.auto_plan_ids(view_domain=[('start_datetime', '=', '2021-07-25 00:00:00'), ('end_datetime', '=', '2021-07-31 23:59:59')])
self.assertFalse(so.order_line.planning_slot_ids.filtered('start_datetime'), 'There should be no employee corresponding to criterias.')
def test_planning_plan_order_default_role(self):
so_form = Form(self.env['sale.order'])
so_form.partner_id = self.planning_partner
with so_form.order_line.new() as sol_form:
sol_form.product_id = self.plannable_product
sol_form.product_uom_qty = 50
so = so_form.save()
so.action_confirm()
self.employee_wout.write({'default_planning_role_id': self.planning_role_junior.id})
Slot = self.env['planning.slot'].with_context(
default_start_datetime='2021-07-25 00:00:00',
default_end_datetime='2021-07-31 23:59:59',
scale='week',
focus_date='2021-07-31 00:00:00',
planning_gantt_active_sale_order_id=so.id,
)
with freeze_time('2021-07-26'):
Slot.auto_plan_ids(view_domain=[('start_datetime', '=', '2021-07-25 00:00:00'), ('end_datetime', '=', '2021-07-31 23:59:59')])
slot = so.order_line.planning_slot_ids.filtered('start_datetime')
self.assertEqual(slot.employee_id, self.employee_wout, 'Planning should be assigned to the employee with sol\'s product role as default role')
def test_planning_plan_order_roles(self):
so_form = Form(self.env['sale.order'])
so_form.partner_id = self.planning_partner
with so_form.order_line.new() as sol_form:
sol_form.product_id = self.plannable_product
sol_form.product_uom_qty = 50
so = so_form.save()
so.action_confirm()
self.employee_wout.write({'planning_role_ids': [(4, self.planning_role_junior.id)]})
Slot = self.env['planning.slot'].with_context(
default_start_datetime='2021-07-25 00:00:00',
default_end_datetime='2021-07-31 23:59:59',
scale='week',
focus_date='2021-07-31 00:00:00',
planning_gantt_active_sale_order_id=so.id,
)
with freeze_time('2021-07-26'):
Slot.auto_plan_ids(view_domain=[('start_datetime', '=', '2021-07-25 00:00:00'), ('end_datetime', '=', '2021-07-31 23:59:59')])
slot = so.order_line.planning_slot_ids.filtered('start_datetime')
self.assertEqual(slot.employee_id, self.employee_wout, 'Planning should be assigned to the employee with one of its role equal to sol\'s product role')
def test_planning_plan_order_previous_slot(self):
so_form = Form(self.env['sale.order'])
so_form.partner_id = self.planning_partner
with so_form.order_line.new() as sol_form:
sol_form.product_id = self.plannable_product
sol_form.product_uom_qty = 150
so = so_form.save()
so.action_confirm()
Slot = self.env['planning.slot'].with_context(
default_start_datetime='2021-07-25 00:00:00',
default_end_datetime='2021-07-31 23:59:59',
scale='week',
focus_date='2021-07-31 00:00:00',
planning_gantt_active_sale_order_id=so.id,
)
self.employee_wout.write({'default_planning_role_id': self.planning_role_junior})
with freeze_time('2021-07-26'):
Slot.auto_plan_ids(view_domain=[('start_datetime', '=', '2021-07-25 00:00:00'), ('end_datetime', '=', '2021-07-31 23:59:59')])
self.employee_wout.write({'default_planning_role_id': False, 'planning_role_ids': [(5, 0, 0)]})
self.employee_joseph.write({'default_planning_role_id': self.planning_role_junior.id})
with freeze_time('2021-07-26'):
Slot.with_context(
default_start_datetime='2021-08-01 00:00:00',
default_end_datetime='2021-08-07 23:59:59'
).auto_plan_ids(view_domain=[('start_datetime', '=', '2021-08-01 00:00:00'), ('end_datetime', '=', '2021-08-07 23:59:59')])
slots = so.order_line.planning_slot_ids.filtered('start_datetime')
self.assertEqual(len(slots), 2, 'It should exists two slots')
for slot in slots:
self.assertEqual(slot.employee_id, self.employee_wout, 'Planning should be assigned to the employee previously assigned to the slot')
# Ensure no one is assigned once again since employee_wout is already planned this week
with freeze_time('2021-07-26'):
Slot.with_context(
default_start_datetime='2021-08-01 00:00:00',
default_end_datetime='2021-08-07 23:59:59'
).auto_plan_ids(view_domain=[('start_datetime', '=', '2021-08-01 00:00:00'), ('end_datetime', '=', '2021-08-07 23:59:59')])
slots = so.order_line.planning_slot_ids.filtered('start_datetime')
self.assertEqual(len(slots), 2, 'It should exists two slots')
for slot in slots:
self.assertEqual(slot.employee_id, self.employee_wout, 'Planning should be assigned to the employee previously assigned to the slot')
def test_planning_plan_slot(self):
so_form = Form(self.env['sale.order'])
so_form.partner_id = self.planning_partner
with so_form.order_line.new() as sol_form:
sol_form.product_id = self.plannable_product
sol_form.product_uom_qty = 50
so = so_form.save()
so.action_confirm()
slot = so.order_line.planning_slot_ids
slot.with_context(
default_start_datetime='2021-07-25 00:00:00',
default_end_datetime='2021-07-31 23:59:59',
scale='week',
focus_date='2021-07-29 00:00:00',
planning_gantt_active_sale_order_id=so.id,
).write({
'start_datetime': '2021-07-27 06:00:00',
'end_datetime': '2021-07-27 15:00:00',
'resource_id': self.employee_wout.resource_id.id,
})
planned_slot_1 = so.order_line.planning_slot_ids.filtered('start_datetime')
self.assertEqual(1, len(planned_slot_1), 'There should be only 1 allocated slot.')
self.assertEqual(self.employee_wout, planned_slot_1.employee_id, 'Planning should be assigned to the employee with one of its role equal to sol\'s product role')
self.assertEqual('2021-07-27 06:00:00', str(planned_slot_1.start_datetime), 'Planning slot should take the start datetime induced by the magnifying glass in gantt')
self.assertEqual('2021-07-30 15:00:00', str(planned_slot_1.end_datetime), 'Planning slot should last for all the week, until friday afternoon.')
self.assertEqual(32.0, planned_slot_1.allocated_hours, 'Planning slot should have 32 allocated hours.')
slot = so.order_line.planning_slot_ids.filtered_domain([('start_datetime', '=', False)])
self.assertEqual(1, len(slot), 'There should exists a slot with the remaining hours to allocate.')
self.assertEqual(18.0, slot.allocated_hours, 'There should exists a slot with the right remaining hours to allocate.')
slot.with_context(
default_start_datetime='2021-08-01 00:00:00',
default_end_datetime='2021-08-07 23:59:59',
scale='week',
focus_date='2021-08-02 00:00:00',
planning_gantt_active_sale_order_id=so.id,
).write({
'start_datetime': '2021-08-02 06:00:00',
'end_datetime': '2021-08-02 15:00:00',
'resource_id': self.employee_wout.resource_id.id,
})
slots = so.order_line.planning_slot_ids.filtered('start_datetime')
for slot in slots:
if slot != planned_slot_1:
self.assertEqual(slot.employee_id, self.employee_wout, 'Planning should be assigned to the employee with one of its role equal to sol\'s product role')
self.assertEqual('2021-08-02 06:00:00', str(slot.start_datetime), 'Planning slot should take the start datetime induced by the magnifying glass in gantt. (Janice has NYC Timezone)')
self.assertEqual('2021-08-04 08:00:00', str(slot.end_datetime), 'Planning slot should last for all the week, until friday afternoon. (Janice has NYC Timezone)')
self.assertEqual(18.0, slot.allocated_hours, 'Planning slot should have 18 allocated hours.')
def test_copy_previous_week(self):
self.resource_bert.default_role_id = self.planning_role_junior
for qty, percent, hours in [(2, 40, 1), (1, 15, 2)]:
so = self.env['sale.order'].create({
"partner_id": self.planning_partner.id,
})
sol = self.env['sale.order.line'].create({
"product_id": self.plannable_product.id,
"product_uom_qty": qty,
"order_id": so.id,
})
so.action_confirm()
PlanningSlot = self.env['planning.slot']
start = datetime(2019, 6, 26, 8, 0)
PlanningSlot.create([{
'start_datetime': start + timedelta(hours=hours * i),
'end_datetime': start + timedelta(hours=hours * (i + 1)),
'allocated_percentage': percent,
'sale_line_id': sol.id,
} for i in range(2)])
can_create = True
while can_create:
start = start + timedelta(weeks=1)
can_create = PlanningSlot.action_copy_previous_week(str(start), [
# dummy domain
('start_datetime', '=', True),
('end_datetime', '=', True),
])
slots = PlanningSlot.search([
('sale_line_id', '=', sol.id),
('start_datetime', '!=', False),
])
self.assertEqual(len(slots), ceil(qty / hours * 100 / percent))
self.assertTrue(
all(slots.mapped(lambda s: s.allocated_percentage == percent)),
'All slots should have the same allocated percentage',
)
self.assertAlmostEqual(
sum(slots.mapped(lambda s: s._get_slot_duration())) * percent / 100, qty,
msg='Total duration * allocated percentage should be 1 hour, as sold',
)
def test_copy_no_allocated_percentage(self):
"""Mostly to test that the copy method does not crash when there is no allocated percentage."""
so = self.env['sale.order'].create({
"partner_id": self.planning_partner.id,
})
sol = self.env['sale.order.line'].create({
"product_id": self.plannable_product.id,
"product_uom_qty": 10,
"order_id": so.id,
})
so.action_confirm()
PlanningSlot = self.env['planning.slot']
start = datetime(2019, 6, 25, 8, 0)
slot = PlanningSlot.create({
'start_datetime': start,
'end_datetime': start + timedelta(hours=1),
'allocated_percentage': 0,
'sale_line_id': sol.id,
})
self.assertEqual(slot.allocated_percentage, 0)
copy_start = start + timedelta(weeks=1)
PlanningSlot.action_copy_previous_week(
str(copy_start), [
# dummy domain
('start_datetime', '=', True),
('end_datetime', '=', True),
]
)
copy = PlanningSlot.search([('start_datetime', '=', copy_start), ('sale_line_id', '=', sol.id)])
self.assertEqual(len(copy), 1)
self.assertEqual(copy.allocated_percentage, 0)
self.assertEqual(copy.allocated_hours, 0)
self.assertEqual(copy.end_datetime, copy_start + timedelta(hours=1))
def test_copy_previous_week_with_slot_to_plan(self):
so = self.env['sale.order'].create({
'partner_id': self.planning_partner.id,
})
sol = self.env['sale.order.line'].create({
'product_id': self.plannable_product.id,
'product_uom_qty': 10,
'order_id': so.id,
})
so.action_confirm()
PlanningSlot = self.env['planning.slot']
slot_to_plan = PlanningSlot.search([('start_datetime', '=', False), ('sale_line_id', '=', sol.id)])
self.assertEqual(len(slot_to_plan), 1)
start = datetime(2019, 6, 25, 8, 0, tzinfo=pytz.utc)
slot = PlanningSlot.create({
'start_datetime': start.replace(tzinfo=None),
'end_datetime': (start + timedelta(hours=5)).replace(tzinfo=None),
'sale_line_id': sol.id,
})
self.assertEqual(slot.allocated_hours, 5)
self.assertEqual(slot_to_plan.allocated_hours, 5)
copy_start = start + timedelta(weeks=1)
PlanningSlot.action_copy_previous_week(
str(copy_start.replace(tzinfo=None)),
[],
)
copy = PlanningSlot.search([
('start_datetime', '=', copy_start),
('sale_line_id', '=', sol.id),
])
self.assertEqual(len(copy), 1)
self.assertFalse(slot_to_plan.exists())
PlanningSlot = PlanningSlot.with_context(
default_start_datetime='2021-07-25 00:00:00',
default_end_datetime='2021-07-31 23:59:59',
scale='week',
focus_date='2021-07-31 00:00:00',
planning_gantt_active_sale_order_id=so.id,
)
shifts = PlanningSlot.auto_plan_ids([('start_datetime', '=', '2019-07-01 00:00:00'), ('end_datetime', '=', '2019-07-07 23:59:59')])
self.assertEqual(len(shifts), 0)
def test_add_to_compute_then_create_field(self):
so = self.env['sale.order'].create({
"partner_id": self.planning_partner.id,
})
sol = self.env['sale.order.line'].create({
"product_id": self.plannable_product.id,
"product_uom_qty": 10,
"order_id": so.id,
})
so.action_confirm()
self.env['planning.slot'].create({
'sale_line_id': sol.id,
})
sol.env.flush_all()
# call Model._setup_base => no error because of add_to_compute in compute should happen
field = self.env['ir.model.fields'].create({
'name': 'x_this_is_a_test',
'model_id': self.env['ir.model'].search([('model', '=', 'planning.slot')]).id,
'field_description': 'foo',
'ttype': 'integer',
})
field.unlink()