Merge branch '10.0' of github.com:akretion/odoo-usability into 10.0

This commit is contained in:
Alexis de Lattre
2016-10-12 22:18:32 +02:00
17 changed files with 386 additions and 19 deletions

View File

@@ -35,11 +35,11 @@ This module adds 2 fields on the Company :
* *Capital Amount*
* *Legal Form* (technical name: title, configured as a related field of res.partner)
* *Legal Form*
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['base'],
'data': ['company_view.xml'],
'installable': False,
'installable': True,
}

View File

@@ -26,10 +26,10 @@ from openerp import models, fields
class ResCompany(models.Model):
_inherit = "res.company"
capital_amount = fields.Integer(string='Capital Amount')
title = fields.Many2one(
'res.partner.title', related='partner_id.title',
string='Legal Form')
capital_amount = fields.Monetary(string='Capital Amount')
# in v9, title is only for contacts, not for companies
legal_type = fields.Char(
string="Legal Type", help="Type of Company, e.g. SARL, SAS, ...")
_sql_constraints = [(
'capital_amount_positive',

View File

@@ -6,7 +6,7 @@
The licence is in the file __openerp__.py
-->
<openerp>
<odoo>
<data>
<record id="view_company_form" model="ir.ui.view">
@@ -15,13 +15,12 @@
<field name="inherit_id" ref="base.view_company_form" />
<field name="arch" type="xml">
<field name="company_registry" position="after">
<field name="capital_amount" widget="monetary"
options="{'currency_field': 'currency_id'}"/>
<field name="title" domain="[('domain', '=', 'partner')]"/>
<field name="capital_amount"/>
<field name="legal_type"/>
</field>
</field>
</record>
</data>
</openerp>
</odoo>

View File

@@ -22,7 +22,7 @@
#
##############################################################################
from openerp.osv import orm, fields
from openerp import models, fields
from openerp.tools.translate import _
import requests
from datetime import datetime
@@ -38,15 +38,13 @@ logger = logging.getLogger(__name__)
URL = 'https://www.infogreffe.fr'
class res_partner(orm.Model):
class res_partner(models.Model):
_inherit = 'res.partner'
_columns = {
'infogreffe_date': fields.date('Date', readonly=True),
'infogreffe_turnover': fields.integer(u'Turnover (€)', readonly=True),
'infogreffe_profit': fields.integer(u'Profit (€)', readonly=True),
'infogreffe_headcount': fields.integer('Headcount', readonly=True),
}
infogreffe_date = fields.Date(string='Date', readonly=True)
infogreffe_turnover = fields.Integer(string=u'Turnover (€)', readonly=True)
infogreffe_profit = fields.Integer(string=u'Profit (€)', readonly=True)
infogreffe_headcount = fields.Integer(string='Headcount', readonly=True)
def copy(self, cr, uid, id, default=None, context=None):
if default is None:

View File

@@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import sale_private_stock

View File

@@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
# © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'Sale from Private Stock',
'version': '10.0.1.0.0',
'category': 'Sales Management',
'license': 'AGPL-3',
'summary': 'Sell from private stock',
'description': '''
Sale from Private Stock
=======================
This module is particularly useful for companies that lend stock to their distributors and when it's too heavy to create a new warehouse for each distributor.
This module allows to define a private stock location on a customer.
On a sale order, there is a new optional field to define the source stock location. On a sale order, if you select a customer that has a private stock location, this private stock location will be set as the source stock location of the sale order (but you can change it).
This module has been written by Alexis de Lattre from Akretion
<alexis.delattre@akretion.com>.
''',
'author': 'Akretion',
'depends': ['sale_stock'],
'data': [
'stock_view.xml',
'stock_data.xml',
'partner_view.xml',
],
'installable': True,
}

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2016 Akretion (http://www.akretion.com/)
@author Alexis de Lattre <alexis.delattre@akretion.com>
-->
<odoo>
<data>
<record id="view_partner_stock_form" model="ir.ui.view">
<field name="name">sale_from_private_stock.partner.form</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="stock.view_partner_stock_form" />
<field name="arch" type="xml">
<field name="property_stock_supplier" position="after">
<field name="default_sale_route_id"
attrs="{'invisible': ['|', ('customer', '=', False), ('parent_id', '!=', False)]}"/>
<button name="create_private_location_route" type="object"
string="Create Private Stock"
attrs="{'invisible': ['|', '|', ('default_sale_route_id', '!=', False), ('customer', '=', False), ('parent_id', '!=', False)]}"/>
</field>
</field>
</record>
</data>
</odoo>

View File

@@ -0,0 +1,83 @@
# -*- coding: utf-8 -*-
# © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, fields, api, _
from openerp.exceptions import UserError
class StockWarehouse(models.Model):
_inherit = 'stock.warehouse'
private_stock_out_type_id = fields.Many2one(
'stock.picking.type', string='Private Stock Out Type')
class ResPartner(models.Model):
_inherit = 'res.partner'
default_sale_route_id = fields.Many2one(
'stock.location.route', string="Default Stock Location Route",
company_dependent=True,
domain=[('usage', '=', 'internal')],
help="Stock location route used by default in sale order lines"
"for this customer.")
@api.multi
def create_private_location_route(self):
self.ensure_one()
assert not self.default_sale_route_id,\
'Already has a default_sale_route_id'
slo = self.env['stock.location']
swo = self.env['stock.warehouse']
pro = self.env['procurement.rule']
slro = self.env['stock.location.route']
company = self.env.user.company_id
warehouses = swo.search([
('company_id', '=', company.id),
('private_stock_out_type_id', '!=', False)])
if not warehouses:
raise UserError(_(
"No warehouse with a 'Private Stock Out Type' in the "
"company %s") % company.name)
warehouse = warehouses[0]
private_stock_loc = slo.create({
'name': _('Private stock %s') % self.name,
'location_id': warehouse.view_location_id.id,
'usage': 'internal',
'company_id': company.id,
})
rule = pro.create({
'name': _('From private stock %s to customer') % self.name,
'company_id': company.id,
'warehouse_id': warehouse.id,
'action': 'move',
'location_id': self.property_stock_customer.id,
'location_src_id': private_stock_loc.id,
'procure_method': 'make_to_stock',
'picking_type_id': warehouse.private_stock_out_type_id.id,
})
route = slro.create({
'name': _('Take from %s') % self.name,
'sequence': 1000,
'pull_ids': [(6, 0, [rule.id])],
'product_selectable': False,
'product_categ_selectable': False,
'warehouse_selectable': False,
'sale_selectable': True,
})
self.default_sale_route_id = route.id
class SaleOrderLine(models.Model):
_inherit = 'sale.order.line'
@api.onchange('product_id')
def _set_default_sale_route(self):
print "DO NOT EXECUTE"
commercial_partner = self.order_id.partner_id.commercial_partner_id
if commercial_partner.default_sale_route_id:
self.route_id = commercial_partner.default_sale_route_id
# TODO: check compat between warehouse and route ?

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="ship_from_private_stock_seq" model="ir.sequence">
<field name="name">Picking OUT from private stock</field>
<field name="code">stock.picking</field>
<field name="prefix">OUT/PRIV/</field>
<field name="padding">5</field>
<field name="company_id" eval="False"/>
</record>
<record id="private_stock_picking_type" model="stock.picking.type">
<field name="name">Delivery from private stock</field>
<field name="warehouse_id" ref="stock.warehouse0"/>
<field name="code">outgoing</field>
<field name="use_create_lots" eval="False"/>
<field name="use_existing_lots" eval="True"/>
<field name="return_picking_type_id" ref="stock.picking_type_in"/>
<field name="sequence_id" ref="ship_from_private_stock_seq"/>
</record>
<record id="stock.warehouse0" model="stock.warehouse">
<field name="private_stock_out_type_id" ref="private_stock_picking_type"/>
</record>
</data>
</odoo>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2016 Akretion (http://www.akretion.com/)
@author Alexis de Lattre <alexis.delattre@akretion.com>
-->
<odoo>
<data>
<record id="view_warehouse" model="ir.ui.view">
<field name="name">sale_from_private_stock.warehouse.form</field>
<field name="model">stock.warehouse</field>
<field name="inherit_id" ref="stock.view_warehouse" />
<field name="arch" type="xml">
<field name="out_type_id" position="after">
<field name="private_stock_out_type_id"/>
</field>
</field>
</record>
</data>
</odoo>

View File

@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
from . import mrp_bom
from . import wizard

View File

@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'Sale Order Add Bom',
'version': '9.0.1.0.0',
'category': 'Sales Management',
'license': 'AGPL-3',
'summary': 'Wizard to select a bom from a sale order',
'description': """
This module adds a wizard *Add Kit* on the form view of a quotation that allows the user to select a 'kit' BOM: Odoo will automatically add the components of the kit as sale order lines.
This module has been written by Alexis de Lattre from Akretion
<alexis.delattre@akretion.com>.
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['sale', 'mrp'],
'data': [
'wizard/sale_add_phantom_bom_view.xml',
'sale_view.xml',
],
'installable': True,
}

View File

@@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-
# © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, fields
class MrpBom(models.Model):
_inherit = 'mrp.bom'
_rec_name = 'product_id'
sale_ok = fields.Boolean(related='product_id.sale_ok', store=True)

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<data>
<record id="view_order_form" model="ir.ui.view">
<field name="name">add.bom.sale.order.form</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<button name="action_quotation_send" position="before">
<button name="%(sale_add_phantom_bom_action)d" type="action"
string="Add Kit" states="draft,sent"/>
</button>
</field>
</record>
</data>
</odoo>

View File

@@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import sale_add_phantom_bom

View File

@@ -0,0 +1,69 @@
# -*- coding: utf-8 -*-
# © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, fields, api, _
from openerp.exceptions import UserError
from openerp.tools import float_is_zero
class SaleAddPhantomBom(models.TransientModel):
_name = 'sale.add.phantom.bom'
_description = 'Add Kit to Quotation'
@api.model
def _default_sale_id(self):
assert self._context.get('active_model') == 'sale.order'
return self.env['sale.order'].browse(self._context['active_id'])
bom_id = fields.Many2one(
'mrp.bom', 'Kit', required=True,
domain=[('type', '=', 'phantom'), ('sale_ok', '=', True)])
qty = fields.Integer(
string='Number of Kits to Add', default=1, required=True)
# I can 't put the sale_id fields required=True because
# it may block the deletion of a sale order
sale_id = fields.Many2one(
'sale.order', string='Quotation', default=_default_sale_id)
@api.model
def _prepare_sale_order_line(self, bom_line, sale_order, wizard_qty):
qty_in_product_uom = self.env['product.uom']._compute_qty_obj(
bom_line.product_uom,
bom_line.product_qty,
bom_line.product_id.uom_id)
vals = {
'product_id': bom_line.product_id.id,
'product_uom_qty': qty_in_product_uom * wizard_qty,
'order_id': sale_order.id,
}
return vals
@api.multi
def add(self):
self.ensure_one()
assert self.sale_id, 'No related sale_id'
if self.qty < 1:
raise UserError(_(
"The number of kits to add must be 1 or superior"))
assert self.bom_id.type == 'phantom', 'The BOM is not a kit'
if not self.bom_id.bom_line_ids:
raise UserError(_("The selected kit is empty !"))
prec = self.env['decimal.precision'].precision_get(
'Product Unit of Measure')
today = fields.Date.context_today(self)
solo = self.env['sale.order.line']
for line in self.bom_id.bom_line_ids:
if float_is_zero(line.product_qty, precision_digits=prec):
continue
if line.date_start and line.date_start > today:
continue
if line.date_stop and line.date_stop < today:
continue
# The onchange is played in the inherit of the create()
# of sale order line in the 'sale' module
# TODO: if needed, we could increment existing order lines
# with the same product instead of always creating new lines
vals = self._prepare_sale_order_line(line, self.sale_id, self.qty)
solo.create(vals)
return True

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<data>
<record id="sale_add_phantom_bom_form" model="ir.ui.view">
<field name="name">sale.add.phantom.bom.form</field>
<field name="model">sale.add.phantom.bom</field>
<field name="arch" type="xml">
<form string="Add Phantom BOM to the Quotation">
<group name="main">
<field name="bom_id"/>
<field name="qty"/>
</group>
<footer>
<button name="add" type="object"
class="oe_highlight" string="Add to Quotation"/>
<button special="cancel" string="Cancel" class="oe_link"/>
</footer>
</form>
</field>
</record>
<record id="sale_add_phantom_bom_action" model="ir.actions.act_window">
<field name="name">Add Kit</field>
<field name="res_model">sale.add.phantom.bom</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</data>
</odoo>