Skip to content

Commit

Permalink
[10.0][ADD] sale_order_invoicing_finished_task: New module (OCA#500)
Browse files Browse the repository at this point in the history
* [10.0][ADD] sale_order_invoicing_finished_task: New module

* [10.0][IMP] sale_order_invoicing_finished_task: Toggle invoiceable flag in task.

* [10.0][FIX] sale_order_invoicing_finished_task: Not invoiceable status

* [10.0][IMP] sale_order_invoicing_finished_task: check invoice policy

* Add files for README

* Update README.rst

* Change some format issues in README

* Change license to AGPL and improve readme

* Update __manifest__.py

Add Camptocamp as author

* [10.0][FIX] sale_order_invoicing_finished_task: Overwrite create and write methods because the stage_id field onchange not trigger in a form view with statusbar widget

* [10.0][IMP] sale_order_invoicing_finished_task: Add tests
  • Loading branch information
sergio-teruel authored and ThomasBinsfeld committed Mar 23, 2021
1 parent f18e687 commit 6223c3c
Show file tree
Hide file tree
Showing 15 changed files with 500 additions and 0 deletions.
82 changes: 82 additions & 0 deletions sale_order_invoicing_finished_task/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3

==================================
Sale Order Invoicing Finished Task
==================================

The requirement of this module is to give the possibility in the task to indicate if a task is available to invoice or not. This means by default even the task is not finished you could set it as invoiceable.

As an option you can relate to a Proyect Stage ( ``project.task.type`` ) this control. For example if you want to assign Invoiceable to stage ``Done`` always

Usage
=====

To use this module, you need to:

1. Go to Sales -> Product and create a service product

2. In the product go to Invoicing tab and select (1) An invocing policy (2) Track
service must be create a task and tack hours (3) Set Invoicing finished task
checkbox and save


.. image:: static/description/product_view_invoicefinishedtask.png


3. Go to Sales -> Sale orders -> Create a new one. Add a customer y the product
you have created
4. Confirm the sales order, it will create you a proyect and a task
5. Go to the task and you will find a smartbutton called Not invoiceable, when
you press the button you will indicate that the task can be invoiced

.. image:: static/description/task_view_invoicefinishedtask.png

6. Optional: if you want to use project stages to control this Go To Proyect -> Settings -> Stage -> You have to set true the field Invoiceable in the stages that you consider are invoiceable. Event to use stages for this functionality you can also set it manually in the task whenever you want.

You can try it in:'

.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/167/10.0

Bug Tracker
===========

Bugs are tracked on `GitHub Issues
<https://github.com/OCA/167/issues>`_. In case of trouble, please
check there if your issue has already been reported. If you spotted it first,
help us smashing it by providing a detailed and welcomed feedback.

Credits
=======

Images
------

* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/
blob/master/template/module/static/description/icon.svg>`_.


Contributors
------------

* Denis Leemann <[email protected]>
* Sergio Teruel <[email protected]>
* Carlos Dauden <[email protected]>

Maintainer
----------

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

This module is maintained by the OCA.

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

To contribute to this module, please visit https://odoo-community.org.
3 changes: 3 additions & 0 deletions sale_order_invoicing_finished_task/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-

from . import models
26 changes: 26 additions & 0 deletions sale_order_invoicing_finished_task/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Sergio Teruel <[email protected]>
# Copyright 2017 Carlos Dauden <[email protected]>
# Copyright 2017 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).

{
"name": "Sale Order Invoicing Finished Task",
"summary": "Control invoice order lines if his task has been finished",
"version": "10.0.1.0.0",
"category": "Sales",
"website": "https://github.com/OCA/sale-workflow",
"author": "Tecnativa, "
"Camptocamp, "
"Odoo Community Association (OCA)",
"license": "AGPL-3",
"application": False,
"installable": True,
"depends": [
"sale_timesheet",
],
"data": [
"views/product_view.xml",
"views/project_view.xml",
],
}
5 changes: 5 additions & 0 deletions sale_order_invoicing_finished_task/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-

from . import product
from . import project
from . import sale_order
14 changes: 14 additions & 0 deletions sale_order_invoicing_finished_task/models/product.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Sergio Teruel <[email protected]>
# Copyright 2017 Carlos Dauden <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import fields, models


class ProductTemplate(models.Model):
_inherit = 'product.template'

invoicing_finished_task = fields.Boolean(
help='Invoice the order lines only when the task is in folded stage',
)
78 changes: 78 additions & 0 deletions sale_order_invoicing_finished_task/models/project.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Camptocamp SA
# Copyright 2017 Sergio Teruel <[email protected]>
# Copyright 2017 Carlos Dauden <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import _, api, fields, models
from odoo.exceptions import ValidationError, UserError


class ProjectTaskType(models.Model):
_inherit = 'project.task.type'

invoiceable = fields.Boolean(
string='Invoiceable',
)


class ProjectTask(models.Model):
_inherit = 'project.task'

invoiceable = fields.Boolean(
string='Invoiceable',
)
invoicing_finished_task = fields.Boolean(
related='sale_line_id.product_id.invoicing_finished_task',
readonly=True,
)

@api.onchange('stage_id')
def _onchange_stage_id(self):
for task in self:
if task.invoicing_finished_task and \
task.stage_id.invoiceable and\
not task.invoiceable:
task.invoiceable = True

@api.multi
def toggle_invoiceable(self):
for task in self:
# We dont' want to modify when the related SOLine is invoiced
if (not task.sale_line_id or
task.sale_line_id.state in ('done', 'cancel') or
task.sale_line_id.invoice_status in ('invoiced',)):
raise UserError(_("You cannot modify the status if there is "
"no Sale Order Line or if it has been "
"invoiced."))
task.invoiceable = not task.invoiceable

@api.multi
def write(self, vals):
for task in self:
if (vals.get('sale_line_id') and
task.sale_line_id.state in ('done', 'cancel')):
raise ValidationError(_('You cannot modify the Sale Order '
'Line of the task once it is invoiced')
)
res = super(ProjectTask, self).write(vals)
# Onchange stage_id field is not triggered with statusbar widget
if 'stage_id' in vals:
self._onchange_stage_id()
return res

@api.model
def create(self, vals):
SOLine = self.env['sale.order.line']
so_line = SOLine.browse(vals.get('sale_line_id'))
# We don't want to add a project.task to an already invoiced line
if so_line and so_line.state in ('done', 'cancel'):
raise ValidationError(_('You cannot add a task to and invoiced '
'Sale Order Line'))
# Onchange stage_id field is not triggered with statusbar widget
if 'sale_line_id' in vals:
stage = self.env['project.task.type'].browse(vals['stage_id'])
if so_line.product_id.invoicing_finished_task and \
stage.invoiceable:
vals['invoiceable'] = True
return super(ProjectTask, self).create(vals)
50 changes: 50 additions & 0 deletions sale_order_invoicing_finished_task/models/sale_order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Sergio Teruel <[email protected]>
# Copyright 2017 Carlos Dauden <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import api, fields, models


class SaleOrder(models.Model):
_inherit = 'sale.order'

@api.depends('state', 'order_line.invoice_status',
'order_line.task_ids.invoiceable')
def _get_invoiced(self):
super(SaleOrder, self)._get_invoiced()
for order in self:
if not all(order.tasks_ids.mapped('invoiceable')):
order.update({
'invoice_status': 'no',
})


class SaleOrderLine(models.Model):
_inherit = 'sale.order.line'

task_ids = fields.One2many(
comodel_name='project.task',
inverse_name='sale_line_id',
string='Tasks',
)

@api.depends('qty_invoiced', 'qty_delivered', 'product_uom_qty',
'order_id.state', 'task_ids.invoiceable')
def _get_to_invoice_qty(self):
lines = self.filtered(
lambda x: (x.product_id.type == 'service' and
x.product_id.invoicing_finished_task and
x.product_id.track_service == 'task')
)
for line in lines:
if all(line.task_ids.mapped('invoiceable')):
if line.product_id.invoice_policy == 'order':
line.qty_to_invoice = (
line.product_uom_qty - line.qty_invoiced)
else:
line.qty_to_invoice = (
line.qty_delivered - line.qty_invoiced)
else:
line.qty_to_invoice = 0.0
super(SaleOrderLine, self - lines)._get_to_invoice_qty()
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions sale_order_invoicing_finished_task/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Sergio Teruel <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from . import test_sale_order_invoicing_finished_task
Loading

0 comments on commit 6223c3c

Please sign in to comment.