[IMP] sale_timesheet: timesheet_invoice_type computed field

As we plan to remove the timesheet_revenue field, we can
make 'timesheet_invoice_type' a computed field, to simplify
code and readability.
Before, this field was readonly, and set automatically on
timesheet creation.
To allow searching on it, we keep it stored.

Task #1857652
This commit is contained in:
jem-odoo
2018-08-02 16:12:39 +02:00
parent a628d80d5e
commit cb7e6ce338
2 changed files with 32 additions and 12 deletions
+17 -6
View File
@@ -17,10 +17,26 @@ class AccountAnalyticLine(models.Model):
('billable_time', 'Billable Time'),
('billable_fixed', 'Billable Fixed'),
('non_billable', 'Non Billable'),
('non_billable_project', 'No task found')], string="Billable Type", readonly=True, copy=False)
('non_billable_project', 'No task found')], string="Billable Type", compute='_compute_timesheet_invoice_type', store=True, readonly=True)
timesheet_invoice_id = fields.Many2one('account.invoice', string="Invoice", readonly=True, copy=False, help="Invoice created from the timesheet")
timesheet_revenue = fields.Monetary("Revenue", default=0.0, readonly=True, copy=False)
@api.multi
@api.depends('so_line.product_id', 'project_id', 'task_id')
def _compute_timesheet_invoice_type(self):
for timesheet in self:
if timesheet.project_id: # AAL will be set to False
invoice_type = 'non_billable_project' if not timesheet.task_id else 'non_billable'
if timesheet.task_id and timesheet.so_line.product_id.type == 'service':
if timesheet.so_line.product_id.invoice_policy == 'delivery':
if timesheet.so_line.product_id.service_type == 'timesheet':
invoice_type = 'billable_time'
else:
invoice_type = 'billable_fixed'
elif timesheet.so_line.product_id.invoice_policy == 'order':
invoice_type = 'billable_fixed'
timesheet.timesheet_invoice_type = invoice_type
@api.multi
def write(self, values):
# prevent to update invoiced timesheets if one line is of type delivery
@@ -92,7 +108,6 @@ class AccountAnalyticLine(models.Model):
so_line = timesheet.so_line
values = {
'timesheet_revenue': 0.0,
'timesheet_invoice_type': 'non_billable_project' if not timesheet.task_id else 'non_billable',
}
# set the revenue and billable type according to the product and the SO line
if timesheet.task_id and so_line.product_id.type == 'service':
@@ -106,7 +121,6 @@ class AccountAnalyticLine(models.Model):
# calculate the revenue on the timesheet
if so_line.product_id.invoice_policy == 'delivery':
values['timesheet_revenue'] = analytic_account.currency_id.round(unit_amount * sale_price * (1-(so_line.discount/100)))
values['timesheet_invoice_type'] = 'billable_time' if so_line.product_id.service_type == 'timesheet' else 'billable_fixed'
elif so_line.product_id.invoice_policy == 'order' and so_line.product_id.service_type == 'timesheet':
quantity_hour = unit_amount
if so_line.product_uom.category_id == timesheet_uom.category_id:
@@ -125,11 +139,8 @@ class AccountAnalyticLine(models.Model):
so_line.price_unit, analytic_account.currency_id, so_line.company_id, fields.Date.today()) * (1-so_line.discount)),
total_revenue_so - total_revenue_invoiced
)
values['timesheet_invoice_type'] = 'billable_fixed'
# if the so line is already invoiced, and the delivered qty is still smaller than the ordered, then link the timesheet to the invoice
if so_line.invoice_status == 'invoiced':
values['timesheet_invoice_id'] = so_line.invoice_lines and so_line.invoice_lines[0].invoice_id.id
elif so_line.product_id.invoice_policy == 'order' and so_line.product_id.service_type != 'timesheet':
values['timesheet_invoice_type'] = 'billable_fixed'
return values
@@ -66,7 +66,7 @@ class TestSaleTimesheet(TestCommonSaleTimesheetNoChart):
sale_order.action_invoice_create()
# let's log some timesheets (on the project created by so_line_ordered_project_only)
self.env['account.analytic.line'].create({
timesheet1 = self.env['account.analytic.line'].create({
'name': 'Test Line',
'project_id': task_serv2.project_id.id,
'task_id': task_serv2.id,
@@ -75,8 +75,9 @@ class TestSaleTimesheet(TestCommonSaleTimesheetNoChart):
})
self.assertEqual(so_line_ordered_global_project.qty_delivered, 10.5, 'Timesheet directly on project does not increase delivered quantity on so line')
self.assertEqual(sale_order.invoice_status, 'invoiced', 'Sale Timesheet: "invoice on order" timesheets should not modify the invoice_status of the so')
self.assertEqual(timesheet1.timesheet_invoice_type, 'billable_fixed', "Timesheets linked to SO line with ordered product shoulbe be billable fixed")
self.env['account.analytic.line'].create({
timesheet2 = self.env['account.analytic.line'].create({
'name': 'Test Line',
'project_id': task_serv2.project_id.id,
'task_id': task_serv2.id,
@@ -85,14 +86,16 @@ class TestSaleTimesheet(TestCommonSaleTimesheetNoChart):
})
self.assertEqual(so_line_ordered_global_project.qty_delivered, 50, 'Sale Timesheet: timesheet does not increase delivered quantity on so line')
self.assertEqual(sale_order.invoice_status, 'invoiced', 'Sale Timesheet: "invoice on order" timesheets should not modify the invoice_status of the so')
self.assertEqual(timesheet2.timesheet_invoice_type, 'billable_fixed', "Timesheets linked to SO line with ordered product shoulbe be billable fixed")
self.env['account.analytic.line'].create({
timesheet3 = self.env['account.analytic.line'].create({
'name': 'Test Line',
'project_id': task_serv2.project_id.id,
'unit_amount': 10,
'employee_id': self.employee_user.id,
})
self.assertEqual(so_line_ordered_project_only.qty_delivered, 0.0, 'Timesheet directly on project does not increase delivered quantity on so line')
self.assertEqual(timesheet3.timesheet_invoice_type, 'non_billable_project', "Timesheets without task shoulbe be 'no project found'")
# log timesheet on task in global project (higher than the initial ordrered qty)
self.env['account.analytic.line'].create({
@@ -175,7 +178,7 @@ class TestSaleTimesheet(TestCommonSaleTimesheetNoChart):
self.assertEqual(sale_order.analytic_account_id, project_serv2.analytic_account_id, "The created project should be linked to the analytic account of the SO")
# let's log some timesheets
self.env['account.analytic.line'].create({
timesheet1 = self.env['account.analytic.line'].create({
'name': 'Test Line',
'project_id': task_serv1.project_id.id, # global project
'task_id': task_serv1.id,
@@ -185,6 +188,7 @@ class TestSaleTimesheet(TestCommonSaleTimesheetNoChart):
self.assertEqual(so_line_deliver_global_project.invoice_status, 'to invoice', 'Sale Timesheet: "invoice on delivery" timesheets should set the so line in "to invoice" status when logged')
self.assertEqual(so_line_deliver_task_project.invoice_status, 'no', 'Sale Timesheet: so line invoice status should not change when no timesheet linked to the line')
self.assertEqual(sale_order.invoice_status, 'to invoice', 'Sale Timesheet: "invoice on delivery" timesheets should set the so in "to invoice" status when logged')
self.assertEqual(timesheet1.timesheet_invoice_type, 'billable_time', "Timesheets linked to SO line with delivered product shoulbe be billable time")
# invoice SO
invoice_id = sale_order.action_invoice_create()
@@ -192,7 +196,7 @@ class TestSaleTimesheet(TestCommonSaleTimesheetNoChart):
self.assertTrue(float_is_zero(invoice.amount_total - so_line_deliver_global_project.price_unit * 10.5, precision_digits=2), 'Sale: invoice generation on timesheets product is wrong')
# log some timesheets again
self.env['account.analytic.line'].create({
timesheet2 = self.env['account.analytic.line'].create({
'name': 'Test Line',
'project_id': task_serv1.project_id.id, # global project
'task_id': task_serv1.id,
@@ -202,6 +206,7 @@ class TestSaleTimesheet(TestCommonSaleTimesheetNoChart):
self.assertEqual(so_line_deliver_global_project.invoice_status, 'to invoice', 'Sale Timesheet: "invoice on delivery" timesheets should set the so line in "to invoice" status when logged')
self.assertEqual(so_line_deliver_task_project.invoice_status, 'no', 'Sale Timesheet: so line invoice status should not change when no timesheet linked to the line')
self.assertEqual(sale_order.invoice_status, 'to invoice', 'Sale Timesheet: "invoice on delivery" timesheets should not modify the invoice_status of the so')
self.assertEqual(timesheet2.timesheet_invoice_type, 'billable_time', "Timesheets linked to SO line with delivered product shoulbe be billable time")
# create a second invoice
sale_order.action_invoice_create()
@@ -220,7 +225,7 @@ class TestSaleTimesheet(TestCommonSaleTimesheetNoChart):
self.assertEqual(len(sale_order.project_ids), 2, "No new project should have been created by the SO, when selling 'project only' product, since it reuse the one from 'new task in new project'.")
# let's log some timesheets on the project
self.env['account.analytic.line'].create({
timesheet3 = self.env['account.analytic.line'].create({
'name': 'Test Line',
'project_id': project_serv2.id, # global project
'unit_amount': 7,
@@ -228,6 +233,7 @@ class TestSaleTimesheet(TestCommonSaleTimesheetNoChart):
})
self.assertTrue(float_is_zero(so_line_deliver_only_project.qty_delivered, precision_digits=2), "Timesheeting on project should not incremented the delivered quantity on the SO line")
self.assertEqual(sale_order.invoice_status, 'no', 'Sale Timesheet: "invoice on delivery" timesheets should be invoiced completely by now')
self.assertEqual(timesheet3.timesheet_invoice_type, 'non_billable_project', "Timesheets without task shoulbe be 'no project found'")
def test_timesheet_manual(self):
""" Test timesheet invoicing with 'invoice on delivery' timetracked products
@@ -288,3 +294,6 @@ class TestSaleTimesheet(TestCommonSaleTimesheetNoChart):
self.assertEqual(so_line_manual_global_project.qty_to_invoice, 0.0, "Manual service should not be affected by timesheet on their created task.")
self.assertEqual(so_line_manual_only_project.qty_to_invoice, 0.0, "Manual service should not be affected by timesheet on their created project.")
self.assertEqual(sale_order.invoice_status, 'no', 'Sale Timesheet: "invoice on delivery" should not need to be invoiced on so confirmation')
self.assertEqual(timesheet1.timesheet_invoice_type, 'billable_fixed', "Timesheets linked to SO line with ordered product shoulbe be billable fixed since it is a milestone")
self.assertEqual(timesheet2.timesheet_invoice_type, 'non_billable_project', "Timesheets without task shoulbe be 'no project found'")