def test_transfert_project(self): """ Transfert task with timesheet to another project. """ Timesheet = self.env['account.analytic.line'] Task = self.env['project.task'] today = Date.context_today(self.env.user) task = Task.with_context( default_project_id=self.project_global.id).create({ 'name': 'first task', 'partner_id': self.partner_a.id, 'planned_hours': 10, }) Timesheet.create({ 'project_id': self.project_global.id, 'task_id': task.id, 'name': 'my first timesheet', 'unit_amount': 4, }) timesheet_count1 = Timesheet.search_count([('project_id', '=', self.project_global.id)]) timesheet_count2 = Timesheet.search_count([('project_id', '=', self.project_template.id)]) self.assertEqual(timesheet_count1, 1, "One timesheet in project_global") self.assertEqual(timesheet_count2, 0, "No timesheet in project_template") self.assertEqual(len(task.timesheet_ids), 1, "The timesheet should be linked to task") # change project of task, as the timesheet is not yet invoiced, the timesheet will change his project task.write({'project_id': self.project_template.id}) timesheet_count1 = Timesheet.search_count([('project_id', '=', self.project_global.id)]) timesheet_count2 = Timesheet.search_count([('project_id', '=', self.project_template.id)]) self.assertEqual(timesheet_count1, 0, "No timesheet in project_global") self.assertEqual(timesheet_count2, 1, "One timesheet in project_template") self.assertEqual(len(task.timesheet_ids), 1, "The timesheet still should be linked to task") wizard = self.env['project.task.create.sale.order'].with_context( active_id=task.id, active_model='project.task').create( {'product_id': self.product_delivery_timesheet3.id}) # We create the SO and the invoice action = wizard.action_create_sale_order() sale_order = self.env['sale.order'].browse(action['res_id']) self.context = { 'active_model': 'sale.order', 'active_ids': [sale_order.id], 'active_id': sale_order.id, 'default_journal_id': self.company_data['default_journal_sale'].id } wizard = self.env['sale.advance.payment.inv'].with_context( self.context).create({ 'advance_payment_method': 'delivered', 'date_start_invoice_timesheet': today - timedelta(days=4), 'date_end_invoice_timesheet': today }) wizard.create_invoices() Timesheet.create({ 'project_id': self.project_template.id, 'task_id': task.id, 'name': 'my second timesheet', 'unit_amount': 6, }) self.assertEqual( Timesheet.search_count([ ('project_id', '=', self.project_template.id) ]), 2, "2 timesheets in project_template") # change project of task, the timesheet not yet invoiced will change its project. The timesheet already invoiced will not change his project. task.write({'project_id': self.project_global.id}) timesheet_count1 = Timesheet.search_count([('project_id', '=', self.project_global.id)]) timesheet_count2 = Timesheet.search_count([('project_id', '=', self.project_template.id)]) self.assertEqual(timesheet_count1, 1, "One timesheet in project_global") self.assertEqual(timesheet_count2, 1, "Still one timesheet in project_template") self.assertEqual(len(task.timesheet_ids), 2, "The 2 timesheet still should be linked to task")
def test_reversed_invoice_reinvoice_with_period(self): """ Tests that when reversing an invoice of timesheet and selecting a time period, the qty to invoice is correctly found Business flow: Create a sale order and deliver some hours (invoiced = 0) Create an invoice Confirm (invoiced = 1) Add Credit Note Confirm (invoiced = 0) Go back to the SO Create an invoice Select a time period [1 week ago, 1 week in the future] Confirm -> Fails if there is nothing to invoice """ product = self.env['product.product'].create({ 'name': "Service delivered, create task in global project", 'standard_price': 30, 'list_price': 90, 'type': 'service', 'service_policy': 'delivered_timesheet', 'invoice_policy': 'delivery', 'default_code': 'SERV-DELI2', 'service_type': 'timesheet', 'service_tracking': 'task_global_project', 'project_id': self.project_global.id, 'taxes_id': False, 'property_account_income_id': self.account_sale.id, }) today = Date.context_today(self.env.user) # Creates a sales order for quantity 3 so_form = Form(self.env['sale.order']) so_form.partner_id = self.env['res.partner'].create({'name': 'Toto'}) with so_form.order_line.new() as line: line.product_id = product line.product_uom_qty = 3.0 sale_order = so_form.save() sale_order.action_confirm() # "Deliver" 1 of 3 task = sale_order.tasks_ids self.env['account.analytic.line'].create({ 'name': 'Test Line', 'project_id': task.project_id.id, 'task_id': task.id, 'unit_amount': 1, 'employee_id': self.employee_user.id, 'company_id': self.company_data['company'].id, }) context = { "active_model": 'sale.order', "active_ids": [sale_order.id], "active_id": sale_order.id, 'open_invoices': True, } # Invoice the 1 wizard = self.env['sale.advance.payment.inv'].with_context( context).create({'advance_payment_method': 'delivered'}) invoice_dict = wizard.create_invoices() # Confirm the invoice invoice = self.env['account.move'].browse(invoice_dict['res_id']) invoice.action_post() # Refund the invoice refund_invoice_wiz = self.env['account.move.reversal'].with_context( active_model="account.move", active_ids=[invoice.id]).create({ 'reason': 'please reverse :c', 'refund_method': 'refund', 'date': today, }) refund_invoice = self.env['account.move'].browse( refund_invoice_wiz.reverse_moves()['res_id']) refund_invoice.action_post() # reversing with action_reverse and then action_post does not reset the invoice_status to 'to invoice' in tests # Recreate wizard to get the new invoices created wizard = self.env['sale.advance.payment.inv'].with_context( context).create({ 'advance_payment_method': 'delivered', 'date_start_invoice_timesheet': today - timedelta(days=7), 'date_end_invoice_timesheet': today + timedelta(days=7) }) # The actual test : wizard.create_invoices( ) # No exception should be raised, there is indeed something to be invoiced since it was reversed
def test_timesheet_invoice(self): """ Test to create invoices for the sale order with timesheets 1) create sale order 2) try to create an invoice for the timesheets 10 days before 3) create invoice for the timesheets 6 days before 4) create invoice for the timesheets 4 days before 5) create invoice for the timesheets from today """ today = Date.context_today(self.env.user) sale_order = self.env['sale.order'].create({ 'partner_id': self.partner_a.id, 'partner_invoice_id': self.partner_a.id, 'partner_shipping_id': self.partner_a.id, 'pricelist_id': self.company_data['default_pricelist'].id, }) # Section Line so_line_ordered_project_only = self.env['sale.order.line'].create({ 'name': "Section Name", 'order_id': sale_order.id, 'display_type': 'line_section', }) so_line_deliver_global_project = self.env['sale.order.line'].create({ 'name': self.product_delivery_timesheet2.name, 'product_id': self.product_delivery_timesheet2.id, 'product_uom_qty': 50, 'product_uom': self.product_delivery_timesheet2.uom_id.id, 'price_unit': self.product_delivery_timesheet2.list_price, 'order_id': sale_order.id, }) so_line_deliver_task_project = self.env['sale.order.line'].create({ 'name': self.product_delivery_timesheet3.name, 'product_id': self.product_delivery_timesheet3.id, 'product_uom_qty': 20, 'product_uom': self.product_delivery_timesheet3.uom_id.id, 'price_unit': self.product_delivery_timesheet3.list_price, 'order_id': sale_order.id, }) so_line_deliver_global_project.product_id_change() so_line_deliver_task_project.product_id_change() # confirm SO sale_order.action_confirm() task_serv1 = self.env['project.task'].search([ ('sale_line_id', '=', so_line_deliver_global_project.id) ]) task_serv2 = self.env['project.task'].search([ ('sale_line_id', '=', so_line_deliver_task_project.id) ]) project_serv2 = self.env['project.project'].search([ ('sale_line_id', '=', so_line_deliver_task_project.id) ]) timesheet1 = self.env['account.analytic.line'].create({ 'name': 'Test Line', 'project_id': task_serv1.project_id.id, 'task_id': task_serv1.id, 'unit_amount': 10, 'employee_id': self.employee_manager.id, 'date': today - timedelta(days=6) }) timesheet2 = self.env['account.analytic.line'].create({ 'name': 'Test Line 2', 'project_id': task_serv1.project_id.id, 'task_id': task_serv1.id, 'unit_amount': 20, 'employee_id': self.employee_manager.id, 'date': today - timedelta(days=1) }) timesheet3 = self.env['account.analytic.line'].create({ 'name': 'Test Line 3', 'project_id': task_serv1.project_id.id, 'task_id': task_serv1.id, 'unit_amount': 10, 'employee_id': self.employee_manager.id, 'date': today - timedelta(days=5) }) timesheet4 = self.env['account.analytic.line'].create({ 'name': 'Test Line 4', 'project_id': task_serv2.project_id.id, 'task_id': task_serv2.id, 'unit_amount': 30, 'employee_id': self.employee_manager.id }) self.assertEqual(so_line_deliver_global_project.invoice_status, 'to invoice') self.assertEqual(so_line_deliver_task_project.invoice_status, 'to invoice') self.assertEqual(sale_order.invoice_status, 'to invoice') # Context for sale.advance.payment.inv wizard self.context = { 'active_model': 'sale.order', 'active_ids': [sale_order.id], 'active_id': sale_order.id, 'default_journal_id': self.company_data['default_journal_sale'].id } # invoice SO wizard = self.env['sale.advance.payment.inv'].with_context( self.context).create({ 'advance_payment_method': 'delivered', 'date_start_invoice_timesheet': today - timedelta(days=16), 'date_end_invoice_timesheet': today - timedelta(days=10) }) self.assertTrue( wizard.invoicing_timesheet_enabled, 'The "date_start_invoice_timesheet" and "date_end_invoice_timesheet" field should be visible in the wizard because a product in sale order has service_policy to "Timesheet on Task"' ) with self.assertRaises(UserError): wizard.create_invoices() self.assertFalse( sale_order.invoice_ids, 'Normally, no invoice will be created because the timesheet logged is after the period defined in date_start_invoice_timesheet and date_end_invoice_timesheet field' ) wizard.write({ 'date_start_invoice_timesheet': today - timedelta(days=10), 'date_end_invoice_timesheet': today - timedelta(days=6) }) wizard.create_invoices() self.assertTrue( sale_order.invoice_ids, 'One invoice should be created because the timesheet logged is between the period defined in wizard' ) invoice = sale_order.invoice_ids[0] self.assertEqual(so_line_deliver_global_project.qty_invoiced, timesheet1.unit_amount) # validate invoice invoice.action_post() wizard.write({ 'date_start_invoice_timesheet': today - timedelta(days=16), 'date_end_invoice_timesheet': today - timedelta(days=4) }) wizard.create_invoices() self.assertEqual(len(sale_order.invoice_ids), 2) invoice2 = sale_order.invoice_ids[-1] self.assertEqual( so_line_deliver_global_project.qty_invoiced, timesheet1.unit_amount + timesheet3.unit_amount, "The last invoice done should have the quantity of the timesheet 3, because the date this timesheet is the only one before the 'date_end_invoice_timesheet' field in the wizard." ) wizard.write({ 'date_start_invoice_timesheet': today - timedelta(days=4), 'date_end_invoice_timesheet': today }) wizard.create_invoices() self.assertEqual(len(sale_order.invoice_ids), 3) invoice3 = sale_order.invoice_ids[-1] # Check if all timesheets have been invoiced self.assertEqual( so_line_deliver_global_project.qty_invoiced, timesheet1.unit_amount + timesheet2.unit_amount + timesheet3.unit_amount) self.assertTrue(so_line_deliver_task_project.invoice_lines) self.assertEqual(so_line_deliver_task_project.qty_invoiced, timesheet4.unit_amount)