Skip to content

Commit

Permalink
Add sale_project_fixed_price_task_completed_invoicing
Browse files Browse the repository at this point in the history
  • Loading branch information
leemannd committed May 31, 2017
1 parent c446efc commit c8b8583
Show file tree
Hide file tree
Showing 10 changed files with 263 additions and 0 deletions.
47 changes: 47 additions & 0 deletions sale_project_fixed_price_task_completed_invoicing/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
.. 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 Project Fixed Price Task Completed Invoicing
=================================================


Usage
=====


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

Bugs are tracked on `GitHub Issues <https://github.com/OCA/sale-workflow/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
=======

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


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

* Clovis Nzouendjou <[email protected]>
* Pierre Verkest <[email protected]>
* Denis Leemann <[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 http://odoo-community.org.
4 changes: 4 additions & 0 deletions sale_project_fixed_price_task_completed_invoicing/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from . import models
21 changes: 21 additions & 0 deletions sale_project_fixed_price_task_completed_invoicing/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{
"name": "Sale project fixed price task completed invoicing",
"version": "10.0.1.0.0",
"depends": [
'product',
'project',
'sale',
'sale_timesheet',
],
"author": "Camptocamp,Odoo Community Association (OCA)",
"website": "http://www.camptocamp.com",
"license": "AGPL-3",
"category": "Sale",
"data": [
'views/project_views.xml',
],
'installable': True,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from . import product
from . import project_task
from . import sale_order
from . import sale_order_line
from . import procurement
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo import models


class ProcurementOrder(models.Model):
_inherit = 'procurement.order'

def _is_procurement_task(self):
return (self.product_id.type == 'service' and
self.product_id.track_service in ('task', 'completed_task'))

def _create_service_task(self):
task = super(ProcurementOrder, self)._create_service_task()
if self.product_id.track_service == 'completed_task':
task.fixed_price = True
return task
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo import api, fields, models


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

track_service = fields.Selection(selection_add=[
('completed_task', 'Completed Task')]
)


class ProductProduct(models.Model):
_inherit = 'product.product'

@api.multi
def _need_procurement(self):
for product in self:
if (product.type == 'service' and
product.track_service == 'completed_task'):
return True
return super(ProductProduct, self)._need_procurement()
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

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


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

invoiceable = fields.Boolean(
string='Invoiceable',
)
fixed_price = fields.Boolean(
string='Fixed Price',
)

@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')):
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
task.sale_line_id._check_delivered_qty()

@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')
)
return super(ProjectTask, self).write(vals)

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'))
return super(ProjectTask, self).create(vals)

@api.onchange('invoiceable')
def _onchange_invoiceable(self):
for task in self:
if not task.invoiceable:
continue
task.sale_line_id._check_delivered_qty()
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo import api, models


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

@api.multi
def action_confirm(self):
res = super(SaleOrder, self).action_confirm()
for order in self:
if not order.project_project_id:
for line in order.order_line:
if (line.product_id.track_service in ('completed_task',
'timesheet')):
if not order.project_id:
order._create_analytic_account(
prefix=line.product_id.default_code or None)
order.project_id.project_create(
{'name': order.project_id.name,
'use_tasks': True})
return res
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

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


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

@api.model
def create(self, vals):
line = super(SaleOrderLine, self).create(vals)
if (line.state == 'sale' and not line.order_id.project_id and
line.product_id.track_service in ('completed_task', )):
line.order_id._create_analytic_account()

@api.constrains('product_id')
def _onchange_product_id(self):
for line in self:
if ('completed_task' == line.product_id.track_service and
line.product_uom_qty != 1.0):
raise ValidationError(_("The quantity for 'Complete Task' "
"products must be exactly one"))

@api.multi
def _check_delivered_qty(self):
for line in self:
tasks_count = self.env['project.task'].search_count(
[('sale_line_id', '=', line.id)])
task_invoiced_count = self.env['project.task'].search_count(
[('sale_line_id', '=', line.id), ('invoiceable', '=', True)])
if tasks_count == task_invoiced_count:
line.qty_delivered = 1.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>

<record id="edit_project_task_track" model="ir.ui.view">
<field name="name">project.task.form.track</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.view_task_form2"/>
<field name="arch" type="xml">

<xpath expr="//field[@name='planned_hours']" position="after">
<field name="invoiceable" readonly="1"/>
<field name="fixed_price" invisible="1"/>
</xpath>

<div name="button_box" position="inside">
<button class="oe_stat_button" name="toggle_invoiceable" type="object" icon="fa-file" attrs="{'invisible': [('fixed_price', '=', False)]}">
<span>Invoiceable</span>
</button>
</div>

</field>
</record>

</odoo>

0 comments on commit c8b8583

Please sign in to comment.