[IMP] sale_{project,timesheet}: remove 'delivered_milestone' in invoice_policy
Before this commit, when the `Milestones` feature is disable, the user can always defined a service product with invoice policy equals to 'Based on Milestones' but since the feature is disabled he cannot add this product on a milestone and so this configuratiom is useless without the feature. This commit removes the item into the invoice_policy field Selection when the feature is disabled. Moreover, when the feature is disabled, the existing products with this setting should be updated to be a service product with `invoice_policy='delivered_manual'`. The quantity delivered method of the existing SOLs containing those products should also be updated to allow the user to manually edit the quantity delivered of those SOLs when the `Milestones` feature is disabled. However, when the `Milestones` feature is enabled again, only the products contained in SOL linked to a milestone will be updated because we cannot assume all service products with `invoice_policy='delivered_manual'` were a service products with invoice policy based on Milestones. Also the existing SOLs containing the products updated will not be updated too to not impact the quantity delivered. task-2829542
This commit is contained in:
@@ -7,6 +7,11 @@
|
||||
<field name="groups_id" eval="[Command.link(ref('group_project_user'))]"/>
|
||||
</record>
|
||||
|
||||
<!-- Groups : Add milestones feature by default -->
|
||||
<record id="base.group_user" model="res.groups">
|
||||
<field name="implied_ids" eval="[Command.link(ref('group_project_milestone'))]"/>
|
||||
</record>
|
||||
|
||||
<!-- Categories -->
|
||||
<record id="project_tags_00" model="project.tags">
|
||||
<field name="name">Bug</field>
|
||||
|
||||
@@ -5,3 +5,4 @@ from . import project
|
||||
from . import project_milestone
|
||||
from . import sale_order
|
||||
from . import sale_order_line
|
||||
from . import res_config_settings
|
||||
|
||||
@@ -5,17 +5,20 @@ from odoo import api, fields, models, _
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
SERVICE_POLICY = [
|
||||
# (service_policy, string)
|
||||
('ordered_prepaid', 'Prepaid/Fixed Price'),
|
||||
('delivered_milestones', 'Based on Milestones'),
|
||||
('delivered_manual', 'Based on Delivered Quantity (Manual)'),
|
||||
]
|
||||
|
||||
|
||||
class ProductTemplate(models.Model):
|
||||
_inherit = 'product.template'
|
||||
|
||||
@api.model
|
||||
def _selection_service_policy(self):
|
||||
service_policies = [
|
||||
# (service_policy, string)
|
||||
('ordered_prepaid', 'Prepaid/Fixed Price'),
|
||||
('delivered_manual', 'Based on Delivered Quantity (Manual)'),
|
||||
]
|
||||
if self.user_has_groups('project.group_project_milestone'):
|
||||
service_policies.insert(1, ('delivered_milestones', 'Based on Milestones'))
|
||||
return service_policies
|
||||
|
||||
service_tracking = fields.Selection(
|
||||
selection=[
|
||||
('no', 'Nothing'),
|
||||
@@ -36,7 +39,7 @@ class ProductTemplate(models.Model):
|
||||
'project.project', 'Project Template', company_dependent=True, copy=True,
|
||||
domain="[('company_id', '=', current_company_id)]",
|
||||
help='Select a billable project to be the skeleton of the new created project when selling the current product. Its stages and tasks will be duplicated.')
|
||||
service_policy = fields.Selection(SERVICE_POLICY, string="Service Invoicing Policy", compute='_compute_service_policy', inverse='_inverse_service_policy')
|
||||
service_policy = fields.Selection('_selection_service_policy', string="Service Invoicing Policy", compute='_compute_service_policy', inverse='_inverse_service_policy')
|
||||
service_type = fields.Selection(selection_add=[
|
||||
('milestones', 'Project Milestones'),
|
||||
])
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import models
|
||||
|
||||
|
||||
class ResConfigSettings(models.TransientModel):
|
||||
_inherit = 'res.config.settings'
|
||||
|
||||
def set_values(self):
|
||||
super().set_values()
|
||||
if self.group_project_milestone:
|
||||
# Search the milestones containing a SOL and change the qty_delivered_method field of the SOL and the
|
||||
# service_policy field set on the product to convert from manual to milestones.
|
||||
milestone_read_group = self.env['project.milestone'].read_group(
|
||||
[('sale_line_id', '!=', False)],
|
||||
['sale_line_ids:array_agg(sale_line_id)'],
|
||||
[],
|
||||
)
|
||||
sale_line_ids = milestone_read_group[0]['sale_line_ids'] if milestone_read_group else []
|
||||
sale_lines = self.env['sale.order.line'].browse(sale_line_ids)
|
||||
sale_lines.product_id.service_policy = 'delivered_milestones'
|
||||
else:
|
||||
product_domain = [('type', '=', 'service'), ('service_type', '=', 'milestones')]
|
||||
products = self.env['product.product'].search(product_domain)
|
||||
products.service_policy = 'delivered_manual'
|
||||
self.env['sale.order.line'].search([('product_id', 'in', products.ids)]).qty_delivered_method = 'manual'
|
||||
@@ -1,7 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import common
|
||||
from . import test_child_tasks
|
||||
from . import test_project_profitability
|
||||
from . import test_res_config_settings
|
||||
from . import test_sale_project
|
||||
from . import test_so_line_milestones
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.addons.sale.tests.common import TestSaleCommon
|
||||
|
||||
|
||||
class TestSaleProjectCommon(TestSaleCommon):
|
||||
@classmethod
|
||||
def setUpClass(cls, chart_template_ref=None):
|
||||
super().setUpClass(chart_template_ref=chart_template_ref)
|
||||
|
||||
cls.env['res.config.settings'] \
|
||||
.create({'group_project_milestone': True}) \
|
||||
.execute()
|
||||
|
||||
cls.uom_hour = cls.env.ref('uom.product_uom_hour')
|
||||
cls.account_sale = cls.company_data['default_account_revenue']
|
||||
|
||||
cls.analytic_account_sale = cls.env['account.analytic.account'].create({
|
||||
'name': 'Project for selling timesheet - AA',
|
||||
'code': 'AA-2030',
|
||||
'company_id': cls.company_data['company'].id,
|
||||
})
|
||||
Project = cls.env['project.project'].with_context(tracking_disable=True)
|
||||
cls.project_global = Project.create({
|
||||
'name': 'Project Global',
|
||||
'analytic_account_id': cls.analytic_account_sale.id,
|
||||
'allow_billable': True,
|
||||
})
|
||||
cls.project_template = Project.create({
|
||||
'name': 'Project TEMPLATE for services',
|
||||
})
|
||||
cls.project_template_state = cls.env['project.task.type'].create({
|
||||
'name': 'Only stage in project template',
|
||||
'sequence': 1,
|
||||
'project_ids': [(4, cls.project_template.id)]
|
||||
})
|
||||
|
||||
# -- manual (delivered, manual)
|
||||
cls.product_delivery_manual1 = cls.env['product.product'].create({
|
||||
'name': "Service delivered, create no task",
|
||||
'standard_price': 11,
|
||||
'list_price': 13,
|
||||
'type': 'service',
|
||||
'invoice_policy': 'delivery',
|
||||
'uom_id': cls.uom_hour.id,
|
||||
'uom_po_id': cls.uom_hour.id,
|
||||
'default_code': 'SERV-DELI1',
|
||||
'service_type': 'manual',
|
||||
'service_tracking': 'no',
|
||||
'project_id': False,
|
||||
'taxes_id': False,
|
||||
'property_account_income_id': cls.account_sale.id,
|
||||
})
|
||||
cls.product_delivery_manual2 = cls.env['product.product'].create({
|
||||
'name': "Service delivered, create task in global project",
|
||||
'standard_price': 30,
|
||||
'list_price': 90,
|
||||
'type': 'service',
|
||||
'invoice_policy': 'delivery',
|
||||
'uom_id': cls.uom_hour.id,
|
||||
'uom_po_id': cls.uom_hour.id,
|
||||
'default_code': 'SERV-DELI2',
|
||||
'service_type': 'manual',
|
||||
'service_tracking': 'task_global_project',
|
||||
'project_id': cls.project_global.id,
|
||||
'taxes_id': False,
|
||||
'property_account_income_id': cls.account_sale.id,
|
||||
})
|
||||
cls.product_delivery_manual3 = cls.env['product.product'].create({
|
||||
'name': "Service delivered, create task in new project",
|
||||
'standard_price': 10,
|
||||
'list_price': 20,
|
||||
'type': 'service',
|
||||
'invoice_policy': 'delivery',
|
||||
'uom_id': cls.uom_hour.id,
|
||||
'uom_po_id': cls.uom_hour.id,
|
||||
'default_code': 'SERV-DELI3',
|
||||
'service_type': 'manual',
|
||||
'service_tracking': 'task_in_project',
|
||||
'project_id': False, # will create a project
|
||||
'taxes_id': False,
|
||||
'property_account_income_id': cls.account_sale.id,
|
||||
})
|
||||
cls.product_delivery_manual4 = cls.env['product.product'].create({
|
||||
'name': "Service delivered, create project only",
|
||||
'standard_price': 15,
|
||||
'list_price': 30,
|
||||
'type': 'service',
|
||||
'invoice_policy': 'delivery',
|
||||
'uom_id': cls.uom_hour.id,
|
||||
'uom_po_id': cls.uom_hour.id,
|
||||
'default_code': 'SERV-DELI4',
|
||||
'service_type': 'manual',
|
||||
'service_tracking': 'project_only',
|
||||
'project_id': False,
|
||||
'taxes_id': False,
|
||||
'property_account_income_id': cls.account_sale.id,
|
||||
})
|
||||
cls.product_delivery_manual5 = cls.env['product.product'].create({
|
||||
'name': "Service delivered, create project only with template",
|
||||
'standard_price': 17,
|
||||
'list_price': 34,
|
||||
'type': 'service',
|
||||
'invoice_policy': 'delivery',
|
||||
'uom_id': cls.uom_hour.id,
|
||||
'uom_po_id': cls.uom_hour.id,
|
||||
'default_code': 'SERV-DELI4',
|
||||
'service_type': 'manual',
|
||||
'service_tracking': 'project_only',
|
||||
'project_id': False,
|
||||
'project_template_id': cls.project_template.id,
|
||||
'taxes_id': False,
|
||||
'property_account_income_id': cls.account_sale.id,
|
||||
})
|
||||
|
||||
# -- devliered_milestones (delivered, milestones)
|
||||
product_milestone_vals = {
|
||||
'type': 'service',
|
||||
'invoice_policy': 'delivery',
|
||||
'uom_id': cls.uom_hour.id,
|
||||
'uom_po_id': cls.uom_hour.id,
|
||||
'default_code': 'SERV-MILES',
|
||||
'service_type': 'milestones',
|
||||
'service_tracking': 'no',
|
||||
'property_account_income_id': cls.account_sale.id,
|
||||
}
|
||||
cls.product_milestone, cls.product_milestone2 = cls.env['product.product'].create([
|
||||
{**product_milestone_vals, 'name': 'Milestone Product', 'list_price': 20},
|
||||
{**product_milestone_vals, 'name': 'Milestone Product 2', 'list_price': 15},
|
||||
])
|
||||
|
||||
def set_project_milestone_feature(self, value):
|
||||
self.env['res.config.settings'] \
|
||||
.create({'group_project_milestone': value}) \
|
||||
.execute()
|
||||
@@ -0,0 +1,88 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import Command
|
||||
from odoo.tests import tagged
|
||||
|
||||
from .common import TestSaleProjectCommon
|
||||
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class TestResConfigSettings(TestSaleProjectCommon):
|
||||
@classmethod
|
||||
def setUpClass(cls, chart_template_ref=None):
|
||||
super().setUpClass(chart_template_ref=chart_template_ref)
|
||||
|
||||
cls.sale_order = cls.env['sale.order'].with_context(mail_notrack=True, mail_create_nolog=True).create({
|
||||
'partner_id': cls.partner_b.id,
|
||||
'partner_invoice_id': cls.partner_b.id,
|
||||
'partner_shipping_id': cls.partner_b.id,
|
||||
'order_line': [
|
||||
Command.create({
|
||||
'product_id': cls.product_milestone.id,
|
||||
'product_uom_qty': 3,
|
||||
}),
|
||||
Command.create({
|
||||
'product_id': cls.product_delivery_manual1.id,
|
||||
'product_uom_qty': 2,
|
||||
})
|
||||
]
|
||||
})
|
||||
cls.product_milestone_sale_line = cls.sale_order.order_line.filtered(lambda sol: sol.product_id == cls.product_milestone)
|
||||
cls.product_delivery_manual1_sale_line = cls.sale_order.order_line.filtered(lambda sol: sol.product_id == cls.product_delivery_manual1)
|
||||
cls.sale_order.action_confirm()
|
||||
|
||||
cls.milestone = cls.env['project.milestone'].create({
|
||||
'name': 'Test Milestone',
|
||||
'sale_line_id': cls.product_milestone_sale_line.id,
|
||||
'project_id': cls.project_global.id,
|
||||
})
|
||||
|
||||
def test_disable_and_enable_project_milestone_feature(self):
|
||||
self.assertTrue(self.env.user.has_group('project.group_project_milestone'), 'The Project Milestones feature should be enabled.')
|
||||
|
||||
self.set_project_milestone_feature(False)
|
||||
self.assertFalse(self.env.user.has_group('project.group_project_milestone'), 'The Project Milestones feature should be disabled.')
|
||||
product_milestones = self.product_milestone + self.product_milestone2
|
||||
self.assertEqual(
|
||||
product_milestones.mapped('service_policy'),
|
||||
['delivered_manual'] * 2,
|
||||
'Both milestone products should become a manual product when the project milestones feature is disabled')
|
||||
self.assertEqual(
|
||||
product_milestones.mapped('service_type'),
|
||||
['manual'] * 2,
|
||||
'Both milestone products should become a manual product when the project milestones feature is disabled')
|
||||
self.assertEqual(
|
||||
self.product_milestone_sale_line.qty_delivered_method,
|
||||
'manual',
|
||||
'The quantity delivered method of SOL containing milestone product should be changed to manual when the project milestones feature is disabled')
|
||||
|
||||
# Since the quantity delivered manual is manual then the user can manually change the quantity delivered
|
||||
self.product_milestone_sale_line.qty_delivered = 2
|
||||
|
||||
# Enable the project milestones feature
|
||||
self.set_project_milestone_feature(True)
|
||||
|
||||
self.assertEqual(
|
||||
self.product_milestone.service_policy,
|
||||
'delivered_milestones',
|
||||
'The product has been updated and considered as milestones product since a SOL containing this product is linked to a milestone.')
|
||||
self.assertEqual(
|
||||
self.product_milestone.service_type,
|
||||
'milestones',
|
||||
'The product has been updated and considered as milestones product since a SOL containing this product is linked to a milestone.')
|
||||
self.assertEqual(
|
||||
self.product_milestone2.service_policy,
|
||||
'delivered_manual',
|
||||
'The product should not be updated since we cannot assume this product was a milestone when the feature'
|
||||
' was enabled because no SOL with this product is linked to a milestone.')
|
||||
self.assertEqual(
|
||||
self.product_milestone2.service_type,
|
||||
'manual',
|
||||
'The product should not be updated since we cannot assume this product was a milestone when the feature'
|
||||
' was enabled because no SOL with this product is linked to a milestone.')
|
||||
self.assertEqual(
|
||||
self.product_milestone_sale_line.qty_delivered_method,
|
||||
'manual',
|
||||
'The quantity delivered method of SOL containing milestone product should keep the same quantity delivered method even if the project milestones feature is renabled.')
|
||||
self.assertEqual(self.product_milestone_sale_line.qty_delivered, 2, 'The quantity delivered should be the one set by the user.')
|
||||
@@ -111,7 +111,7 @@
|
||||
<field name="type">service</field>
|
||||
<field name="uom_id" ref="uom.product_uom_unit"/>
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit"/>
|
||||
<field name="service_policy">delivered_milestones</field>
|
||||
<field name="service_type">milestones</field>
|
||||
<field name="service_tracking">no</field>
|
||||
</record>
|
||||
|
||||
|
||||
@@ -6,16 +6,15 @@ import threading
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
from odoo.addons.sale_project.models.product import SERVICE_POLICY
|
||||
|
||||
SERVICE_POLICY = [policy[:1] for policy in SERVICE_POLICY]
|
||||
SERVICE_POLICY.insert(1, ('delivered_timesheet', 'Based on Timesheets'))
|
||||
|
||||
|
||||
class ProductTemplate(models.Model):
|
||||
_inherit = 'product.template'
|
||||
|
||||
service_policy = fields.Selection(selection_add=SERVICE_POLICY)
|
||||
def _selection_service_policy(self):
|
||||
service_policies = super()._selection_service_policy()
|
||||
service_policies.insert(1, ('delivered_timesheet', 'Based on Timesheets'))
|
||||
return service_policies
|
||||
|
||||
service_type = fields.Selection(selection_add=[
|
||||
('timesheet', 'Timesheets on project (one fare per SO/Project)'),
|
||||
], ondelete={'timesheet': 'set manual'})
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.addons.mail.tests.common import mail_new_test_user
|
||||
from odoo.addons.sale.tests.common import TestSaleCommon
|
||||
from odoo.addons.sale_project.tests.common import TestSaleProjectCommon
|
||||
|
||||
|
||||
class TestCommonSaleTimesheet(TestSaleCommon):
|
||||
class TestCommonSaleTimesheet(TestSaleProjectCommon):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls, chart_template_ref=None):
|
||||
@@ -54,12 +54,7 @@ class TestCommonSaleTimesheet(TestSaleCommon):
|
||||
})
|
||||
|
||||
# Account and project
|
||||
cls.account_sale = cls.company_data['default_account_revenue']
|
||||
cls.analytic_account_sale = cls.env['account.analytic.account'].create({
|
||||
'name': 'Project for selling timesheet - AA',
|
||||
'code': 'AA-2030',
|
||||
'company_id': cls.company_data['company'].id,
|
||||
})
|
||||
cls.analytic_account_sale.name = 'Project for selling timesheet - AA'
|
||||
cls.analytic_account_sale_company_B = cls.env['account.analytic.account'].create({
|
||||
'name': 'Project for selling timesheet Company B - AA',
|
||||
'code': 'AA-2030',
|
||||
@@ -68,20 +63,12 @@ class TestCommonSaleTimesheet(TestSaleCommon):
|
||||
|
||||
# Create projects
|
||||
Project = cls.env['project.project'].with_context(tracking_disable=True)
|
||||
cls.project_global = Project.create({
|
||||
cls.project_global.write({
|
||||
'name': 'Project for selling timesheets',
|
||||
'allow_timesheets': True,
|
||||
'analytic_account_id': cls.analytic_account_sale.id,
|
||||
'allow_billable': True,
|
||||
})
|
||||
cls.project_template = Project.create({
|
||||
cls.project_template.write({
|
||||
'name': 'Project TEMPLATE for services',
|
||||
'allow_timesheets': True,
|
||||
})
|
||||
cls.project_template_state = cls.env['project.task.type'].create({
|
||||
'name': 'Only stage in project template',
|
||||
'sequence': 1,
|
||||
'project_ids': [(4, cls.project_template.id)]
|
||||
})
|
||||
# Projects: at least one per billable type
|
||||
cls.project_task_rate = Project.create({
|
||||
@@ -106,7 +93,6 @@ class TestCommonSaleTimesheet(TestSaleCommon):
|
||||
})
|
||||
|
||||
# Create service products
|
||||
uom_hour = cls.env.ref('uom.product_uom_hour')
|
||||
|
||||
# -- ordered quantities (ordered, timesheet)
|
||||
cls.product_order_timesheet1 = cls.env['product.product'].create({
|
||||
@@ -115,8 +101,8 @@ class TestCommonSaleTimesheet(TestSaleCommon):
|
||||
'list_price': 13,
|
||||
'type': 'service',
|
||||
'invoice_policy': 'order',
|
||||
'uom_id': uom_hour.id,
|
||||
'uom_po_id': uom_hour.id,
|
||||
'uom_id': cls.uom_hour.id,
|
||||
'uom_po_id': cls.uom_hour.id,
|
||||
'default_code': 'SERV-ORDERED1',
|
||||
'service_type': 'timesheet',
|
||||
'service_tracking': 'no',
|
||||
@@ -130,8 +116,8 @@ class TestCommonSaleTimesheet(TestSaleCommon):
|
||||
'list_price': 90,
|
||||
'type': 'service',
|
||||
'invoice_policy': 'order',
|
||||
'uom_id': uom_hour.id,
|
||||
'uom_po_id': uom_hour.id,
|
||||
'uom_id': cls.uom_hour.id,
|
||||
'uom_po_id': cls.uom_hour.id,
|
||||
'default_code': 'SERV-ORDERED2',
|
||||
'service_type': 'timesheet',
|
||||
'service_tracking': 'task_global_project',
|
||||
@@ -145,8 +131,8 @@ class TestCommonSaleTimesheet(TestSaleCommon):
|
||||
'list_price': 20,
|
||||
'type': 'service',
|
||||
'invoice_policy': 'order',
|
||||
'uom_id': uom_hour.id,
|
||||
'uom_po_id': uom_hour.id,
|
||||
'uom_id': cls.uom_hour.id,
|
||||
'uom_po_id': cls.uom_hour.id,
|
||||
'default_code': 'SERV-ORDERED3',
|
||||
'service_type': 'timesheet',
|
||||
'service_tracking': 'task_in_project',
|
||||
@@ -160,8 +146,8 @@ class TestCommonSaleTimesheet(TestSaleCommon):
|
||||
'list_price': 30,
|
||||
'type': 'service',
|
||||
'invoice_policy': 'order',
|
||||
'uom_id': uom_hour.id,
|
||||
'uom_po_id': uom_hour.id,
|
||||
'uom_id': cls.uom_hour.id,
|
||||
'uom_po_id': cls.uom_hour.id,
|
||||
'default_code': 'SERV-ORDERED4',
|
||||
'service_type': 'timesheet',
|
||||
'service_tracking': 'project_only',
|
||||
@@ -175,8 +161,8 @@ class TestCommonSaleTimesheet(TestSaleCommon):
|
||||
'list_price': 34,
|
||||
'type': 'service',
|
||||
'invoice_policy': 'order',
|
||||
'uom_id': cls.env.ref('uom.product_uom_hour').id,
|
||||
'uom_po_id': cls.env.ref('uom.product_uom_hour').id,
|
||||
'uom_id': cls.uom_hour.id,
|
||||
'uom_po_id': cls.uom_hour.id,
|
||||
'default_code': 'SERV-ORDERED4',
|
||||
'service_type': 'timesheet',
|
||||
'service_tracking': 'project_only',
|
||||
@@ -193,8 +179,8 @@ class TestCommonSaleTimesheet(TestSaleCommon):
|
||||
'list_price': 13,
|
||||
'type': 'service',
|
||||
'invoice_policy': 'delivery',
|
||||
'uom_id': uom_hour.id,
|
||||
'uom_po_id': uom_hour.id,
|
||||
'uom_id': cls.uom_hour.id,
|
||||
'uom_po_id': cls.uom_hour.id,
|
||||
'default_code': 'SERV-DELI1',
|
||||
'service_type': 'timesheet',
|
||||
'service_tracking': 'no',
|
||||
@@ -208,8 +194,8 @@ class TestCommonSaleTimesheet(TestSaleCommon):
|
||||
'list_price': 90,
|
||||
'type': 'service',
|
||||
'invoice_policy': 'delivery',
|
||||
'uom_id': uom_hour.id,
|
||||
'uom_po_id': uom_hour.id,
|
||||
'uom_id': cls.uom_hour.id,
|
||||
'uom_po_id': cls.uom_hour.id,
|
||||
'default_code': 'SERV-DELI2',
|
||||
'service_type': 'timesheet',
|
||||
'service_tracking': 'task_global_project',
|
||||
@@ -223,8 +209,8 @@ class TestCommonSaleTimesheet(TestSaleCommon):
|
||||
'list_price': 20,
|
||||
'type': 'service',
|
||||
'invoice_policy': 'delivery',
|
||||
'uom_id': uom_hour.id,
|
||||
'uom_po_id': uom_hour.id,
|
||||
'uom_id': cls.uom_hour.id,
|
||||
'uom_po_id': cls.uom_hour.id,
|
||||
'default_code': 'SERV-DELI3',
|
||||
'service_type': 'timesheet',
|
||||
'service_tracking': 'task_in_project',
|
||||
@@ -238,8 +224,8 @@ class TestCommonSaleTimesheet(TestSaleCommon):
|
||||
'list_price': 30,
|
||||
'type': 'service',
|
||||
'invoice_policy': 'delivery',
|
||||
'uom_id': uom_hour.id,
|
||||
'uom_po_id': uom_hour.id,
|
||||
'uom_id': cls.uom_hour.id,
|
||||
'uom_po_id': cls.uom_hour.id,
|
||||
'default_code': 'SERV-DELI4',
|
||||
'service_type': 'timesheet',
|
||||
'service_tracking': 'project_only',
|
||||
@@ -253,8 +239,8 @@ class TestCommonSaleTimesheet(TestSaleCommon):
|
||||
'list_price': 34,
|
||||
'type': 'service',
|
||||
'invoice_policy': 'delivery',
|
||||
'uom_id': cls.env.ref('uom.product_uom_hour').id,
|
||||
'uom_po_id': cls.env.ref('uom.product_uom_hour').id,
|
||||
'uom_id': cls.uom_hour.id,
|
||||
'uom_po_id': cls.uom_hour.id,
|
||||
'default_code': 'SERV-DELI5',
|
||||
'service_type': 'timesheet',
|
||||
'service_tracking': 'project_only',
|
||||
@@ -264,96 +250,6 @@ class TestCommonSaleTimesheet(TestSaleCommon):
|
||||
'property_account_income_id': cls.account_sale.id,
|
||||
})
|
||||
|
||||
# -- manual (delivered, manual)
|
||||
cls.product_delivery_manual1 = cls.env['product.product'].create({
|
||||
'name': "Service delivered, create no task",
|
||||
'standard_price': 11,
|
||||
'list_price': 13,
|
||||
'type': 'service',
|
||||
'invoice_policy': 'delivery',
|
||||
'uom_id': uom_hour.id,
|
||||
'uom_po_id': uom_hour.id,
|
||||
'default_code': 'SERV-DELI1',
|
||||
'service_type': 'manual',
|
||||
'service_tracking': 'no',
|
||||
'project_id': False,
|
||||
'taxes_id': False,
|
||||
'property_account_income_id': cls.account_sale.id,
|
||||
})
|
||||
cls.product_delivery_manual2 = cls.env['product.product'].create({
|
||||
'name': "Service delivered, create task in global project",
|
||||
'standard_price': 30,
|
||||
'list_price': 90,
|
||||
'type': 'service',
|
||||
'invoice_policy': 'delivery',
|
||||
'uom_id': uom_hour.id,
|
||||
'uom_po_id': uom_hour.id,
|
||||
'default_code': 'SERV-DELI2',
|
||||
'service_type': 'manual',
|
||||
'service_tracking': 'task_global_project',
|
||||
'project_id': cls.project_global.id,
|
||||
'taxes_id': False,
|
||||
'property_account_income_id': cls.account_sale.id,
|
||||
})
|
||||
cls.product_delivery_manual3 = cls.env['product.product'].create({
|
||||
'name': "Service delivered, create task in new project",
|
||||
'standard_price': 10,
|
||||
'list_price': 20,
|
||||
'type': 'service',
|
||||
'invoice_policy': 'delivery',
|
||||
'uom_id': uom_hour.id,
|
||||
'uom_po_id': uom_hour.id,
|
||||
'default_code': 'SERV-DELI3',
|
||||
'service_type': 'manual',
|
||||
'service_tracking': 'task_in_project',
|
||||
'project_id': False, # will create a project
|
||||
'taxes_id': False,
|
||||
'property_account_income_id': cls.account_sale.id,
|
||||
})
|
||||
cls.product_delivery_manual4 = cls.env['product.product'].create({
|
||||
'name': "Service delivered, create project only",
|
||||
'standard_price': 15,
|
||||
'list_price': 30,
|
||||
'type': 'service',
|
||||
'invoice_policy': 'delivery',
|
||||
'uom_id': uom_hour.id,
|
||||
'uom_po_id': uom_hour.id,
|
||||
'default_code': 'SERV-DELI4',
|
||||
'service_type': 'manual',
|
||||
'service_tracking': 'project_only',
|
||||
'project_id': False,
|
||||
'taxes_id': False,
|
||||
'property_account_income_id': cls.account_sale.id,
|
||||
})
|
||||
cls.product_delivery_manual5 = cls.env['product.product'].create({
|
||||
'name': "Service delivered, create project only with template",
|
||||
'standard_price': 17,
|
||||
'list_price': 34,
|
||||
'type': 'service',
|
||||
'invoice_policy': 'delivery',
|
||||
'uom_id': uom_hour.id,
|
||||
'uom_po_id': uom_hour.id,
|
||||
'default_code': 'SERV-DELI4',
|
||||
'service_type': 'manual',
|
||||
'service_tracking': 'project_only',
|
||||
'project_id': False,
|
||||
'project_template_id': cls.project_template.id,
|
||||
'taxes_id': False,
|
||||
'property_account_income_id': cls.account_sale.id,
|
||||
})
|
||||
cls.product_milestone = cls.env['product.product'].create({
|
||||
'name': 'Milestone Product',
|
||||
'list_price': 20,
|
||||
'type': 'service',
|
||||
'invoice_policy': 'delivery',
|
||||
'uom_id': uom_hour.id,
|
||||
'uom_po_id': uom_hour.id,
|
||||
'default_code': 'SERV-MILES',
|
||||
'service_type': 'milestones',
|
||||
'service_tracking': 'no',
|
||||
'property_account_income_id': cls.account_sale.id,
|
||||
})
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.so = self.env['sale.order'].with_context(mail_notrack=True, mail_create_nolog=True).create({
|
||||
|
||||
Reference in New Issue
Block a user