Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions sale_order_partials/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.. 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

===================
Partial Sale Orders
===================

Creates related sale orders

Credits
=======

Contributors
------------
* Mikel Arregi <mikelarregi@avanzosc.es>
* Ana Juaristi <anajuaristi@avanzosc.es>
5 changes: 5 additions & 0 deletions sale_order_partials/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Mikel Arregi Etxaniz - AvanzOSC
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
from . import models
from . import wizard
29 changes: 29 additions & 0 deletions sale_order_partials/__openerp__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
# © Copyright 2018 Mikel Arregi Etxaniz - AvanzOSC
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
{
"name": "Partial sale orders",
"version": "8.0.1.0.0",
"license": "AGPL-3",
"depends": [
"sale",
"stock",
"sale_order_type",
],
"author": "OdooMRP team, "
"AvanzOSC, "
"Odoo Community Association (OCA)",
"website": "http://www.odoomrp.com",
"contributors": [
"Mikel Arregi <mikelarregi@avanzosc.es>",
"Ana Juaristi <anajuaristi@avanzosc.es>",
],
"category": "",
"summary": "",
"data": [
"views/sale_order_view.xml",
"views/res_config_view.xml",
"wizard/duplicate_upgradable_sale_view.xml",
],
"installable": True,
}
5 changes: 5 additions & 0 deletions sale_order_partials/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Mikel Arregi Etxaniz - AvanzOSC
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
from . import sale
from . import res_config
40 changes: 40 additions & 0 deletions sale_order_partials/models/res_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Mikel Arregi Etxaniz - AvanzOSC
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
from openerp import api, fields, models


class SaleConfigSettings(models.TransientModel):
_inherit = 'sale.config.settings'

sale_type_id = fields.Many2one(comodel_name='sale.order.type',
string="Partial orders type")

def _get_parameter(self, key, default=False):
param_obj = self.env['ir.config_parameter']
rec = param_obj.search([('key', '=', key)])
return rec or default

def _write_or_create_param(self, key, value):
param_obj = self.env['ir.config_parameter']
rec = self._get_parameter(key)
if rec:
if not value:
rec.unlink()
else:
rec.value = value
elif value:
param_obj.create({'key': key, 'value': value})

@api.multi
def get_default_parameters(self):
def get_value(key, default=''):
rec = self._get_parameter(key)
return rec and rec.value or default
return {
'sale_type_id': get_value('sale.type.id', False),
}

@api.multi
def set_parameters(self):
self._write_or_create_param('sale.type.id', self.sale_type_id.id)
82 changes: 82 additions & 0 deletions sale_order_partials/models/sale.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Mikel Arregi Etxaniz - AvanzOSC
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
from openerp import api, exceptions, fields, models, _
from openerp.addons import decimal_precision as dp


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

child_order_ids = fields.One2many(comodel_name="sale.order",
inverse_name="parent_order_id",
string="Sales")
parent_order_id = fields.Many2one(comodel_name="sale.order")
served_quantity = fields.Float(digits=dp.get_precision('Product Unit of '
'Measure'),
compute="_compute_line_quantities")
not_served_quantity = fields.Float(digits=dp.get_precision(
'Product Unit of Measure'), compute="_compute_line_quantities")
reserved_qty = fields.Float(digits=dp.get_precision(
'Product Unit of Measure'), compute="_compute_line_quantities")
served_quantity_percentage = fields.Float(digits=dp.get_precision(
'Product Unit of Measure'), compute="_compute_line_quantities")
upgrade = fields.Boolean(string="Upgrade", copy=False)

@api.multi
def action_open_partial_sales(self):
template_obj = self.env['product.template']
result = template_obj._get_act_window_dict('sale.action_orders')
result['domain'] = "[('parent_order_id', '=', %d)]" % self.id
result['context'] = {'search_default_internal_loc': 1}
return result

@api.depends("order_line")
def _compute_line_quantities(self):
for record in self:
if record.upgrade and record.order_line:
total = record.order_line[0].product_uom_qty
moves = record.child_order_ids.mapped(
'picking_ids.move_lines').filtered(
lambda x: x.state == 'done')
served_qty = sum(moves.mapped("product_uom_qty"))
not_served_qty = total - served_qty
record.served_quantity = served_qty
record.reserved_qty = record.reserved_child_qty() - served_qty
record.not_served_quantity = not_served_qty
record.served_quantity_percentage = (
served_qty / total * 100)

@api.constrains("order_line", "upgrade")
def check_sale_upgradable_has_one_line(self):
if self.upgrade and len(self.order_line) > 1:
raise exceptions.Warning('Sale upgrades can only have one '
'order line')

@api.multi
def action_create_order_from_upgrade(self, qty=None):
param_obj = self.env['sale.config.settings']
sale_type_param = param_obj._get_parameter('sale.type.id')
sale_type = sale_type_param and sale_type_param.value
for record in self:
if record.upgrade and record.invoiced:
new_record = record.copy({'parent_order_id': record.id,
'type_id': int(sale_type)})
if qty:
new_record.order_line[0].write({'product_uom_qty': qty,
'discount': 100.})
elif not record.upgrade:
raise exceptions.Warning(
_("The order %s is not upgradable. Edit order and check "
"'Upgrade' field") % record.name)
else:
raise exceptions.Warning(_("There are unpaid invoices"))

@api.multi
def reserved_child_qty(self):
self.ensure_one()
not_canceled_children = self.child_order_ids.filtered(
lambda x: x.state != "cancel")
reserved_qty = sum(not_canceled_children.mapped(
"order_line.product_uom_qty"))
return reserved_qty
4 changes: 4 additions & 0 deletions sale_order_partials/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Mikel Arregi Etxaniz - AvanzOSC
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
from . import test_sale_order_partials
33 changes: 33 additions & 0 deletions sale_order_partials/tests/test_sale_order_partials.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Mikel Arregi Etxaniz - AvanzOSC
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html

import openerp.tests.common as common
from openerp import exceptions


class SaleOrderPartials(common.SavepointCase):

@classmethod
def setUpClass(cls):
super(SaleOrderPartials, cls).setUpClass()
cls.wiz_obj = cls.env['duplicate.upgradable.sale']
cls.partner = cls.env['res.partner'].create({
'name': 'Partner to test',
})
cls.product = cls.env['product.product'].create({
'name': 'Product to test'
})
cls.sale_order = cls.env['sale.order'].create({
'partner_id': cls.partner.id,
'upgrade': True,
'order_line': [(0, 0, {'product_id': cls.product.id,
'product_uom_qty': 100}, )],
})

def test_partials(self):
wiz = self.wiz_obj.with_context(active_ids=[
self.sale_order.id]).create({
'quantity': 5})
with self.assertRaises(exceptions.Warning):
wiz.action_duplicate()
18 changes: 18 additions & 0 deletions sale_order_partials/views/res_config_view.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="0">
<record id="view_sale_conf_upgradable_type" model="ir.ui.view">
<field name="name">view.sale.upgradable.type</field>
<field name="model">sale.config.settings</field>
<field name="inherit_id" ref="sale.view_sales_config"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='Sale Features']" position="inside">
<div>
<label for="sale_type_id"/>
<field name="sale_type_id" class="oe_inline"/>
</div>
</xpath>
</field>
</record>
</data>
</openerp>
122 changes: 122 additions & 0 deletions sale_order_partials/views/sale_order_view.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>

<record model="ir.ui.view" id="upgradable_sale_order_search">
<field name="name">upgradable.sale.order.search</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_sales_order_filter" />
<field name="arch" type="xml">
<field name="product_id" position="after">
<field name="parent_order_id"/>
</field>
<filter string="Done" position="after">
<filter string="Upgrade" domain="[('upgrade','=',True)]"
help="Upgradable sale orders"/>
</filter>
<filter string="Order Month" position="after">
<filter string="Grouped partials" domain="[]"
context="{'group_by':'parent_order_id'}"/>
<filter string="Sale type" domain="[]"
context="{'group_by':'type_id'}"/>
</filter>
</field>
</record>

<record model="ir.ui.view" id="upgradable_sale_order_form">
<field name="name">upgradable.sale.order.form</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form" />
<field name="arch" type="xml">
<field name="partner_id" position="before">
<field name="child_order_ids" invisible="True"/>
<field name="parent_order_id" readonly="True"
attrs="{'invisible': [('parent_order_id', '=', False)]}"/>
</field>
<xpath expr="//notebook[1]" position="before">
<group colspan="2">
<field name="upgrade"
attrs="{'invisible': [('parent_order_id', '!=', False)]}"/>
<field name="served_quantity" attrs="{'invisible': [('upgrade', '=', False)]}"/>
<label for="not_served_quantity" attrs="{'invisible': [('upgrade', '=', False)]}"/>
<div attrs="{'invisible': [('upgrade', '=', False)]}">
<field name="not_served_quantity"
class="oe_inline"/>
(<field name="reserved_qty"
class="oe_inline"
/>)
</div>
<field name="served_quantity_percentage"
attrs="{'invisible': [('upgrade', '=', False)]}"
widget="progressbar"/>
</group>
</xpath>
</field>
</record>

<record model="ir.ui.view" id="sale.sale_order_buttons">
<field name="name">sale.order.buttons</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form" />
<field name="arch" type="xml">
<h1 position="after">
<div class="oe_right oe_button_box" name="buttons">
</div>
</h1>
</field>
</record>

<record model="ir.ui.view" id="upgradable_sale_order_button_form">
<field name="name">upgradable.sale.order.button.form</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.sale_order_buttons" />
<field name="arch" type="xml">
<div name="buttons" position="inside">
<button class="oe_stat_button"
name="action_open_partial_sales"
icon="fa-archive" type="object"
string="Partial sales"
attrs="{'invisible': [('upgrade', '=', False)]}">
</button>
</div>
</field>
</record>



<record model="ir.ui.view" id="upgradable_sale_order_tree">
<field name="name">upgradable.sale.order.tree</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_tree" />
<field name="arch" type="xml">
<field name="state" position="before">
<field name="upgrade" />
<field name="served_quantity"/>
<field name="reserved_qty"/>
<field name="not_served_quantity"/>
<field name="served_quantity_percentage"
widget="progressbar"/>
</field>
</field>
</record>

<record model="ir.ui.view" id="tf_view_picking_search">
<field name="name">tf.view.picking.search</field>
<field name="model">stock.picking</field>
<field name="inherit_id" ref="stock.view_picking_internal_search"/>
<field name="arch" type="xml">
<filter name="backorder" position="after">
<filter string="Delivery Day" domain="[]"
context="{'group_by': 'tf_fecha_entrega:year'}" />
<filter string="Delivery Day" domain="[]"
context="{'group_by': 'tf_fecha_entrega:month'}" />
<filter string="Day" domain="[]"
context="{'group_by': 'tf_fecha_entrega:day'}" />
</filter>
</field>
</record>



</data>
</openerp>
4 changes: 4 additions & 0 deletions sale_order_partials/wizard/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Mikel Arregi Etxaniz - AvanzOSC
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
from . import duplicate_upgradable_sal
Loading