Add modules sale_from_private_stock and sale_order_add_bom
Port base_company_extension to v10 Avoid blockage on l10n_fr_infogreffe_connector
This commit is contained in:
@@ -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,
|
||||
}
|
||||
@@ -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',
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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:
|
||||
|
||||
3
sale_from_private_stock/__init__.py
Normal file
3
sale_from_private_stock/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import sale_private_stock
|
||||
33
sale_from_private_stock/__manifest__.py
Normal file
33
sale_from_private_stock/__manifest__.py
Normal 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,
|
||||
}
|
||||
27
sale_from_private_stock/partner_view.xml
Normal file
27
sale_from_private_stock/partner_view.xml
Normal 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>
|
||||
83
sale_from_private_stock/sale_private_stock.py
Normal file
83
sale_from_private_stock/sale_private_stock.py
Normal 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 ?
|
||||
29
sale_from_private_stock/stock_data.xml
Normal file
29
sale_from_private_stock/stock_data.xml
Normal 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>
|
||||
23
sale_from_private_stock/stock_view.xml
Normal file
23
sale_from_private_stock/stock_view.xml
Normal 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>
|
||||
4
sale_order_add_bom/__init__.py
Normal file
4
sale_order_add_bom/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import mrp_bom
|
||||
from . import wizard
|
||||
25
sale_order_add_bom/__manifest__.py
Normal file
25
sale_order_add_bom/__manifest__.py
Normal 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,
|
||||
}
|
||||
12
sale_order_add_bom/mrp_bom.py
Normal file
12
sale_order_add_bom/mrp_bom.py
Normal 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)
|
||||
23
sale_order_add_bom/sale_view.xml
Normal file
23
sale_order_add_bom/sale_view.xml
Normal 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>
|
||||
3
sale_order_add_bom/wizard/__init__.py
Normal file
3
sale_order_add_bom/wizard/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import sale_add_phantom_bom
|
||||
69
sale_order_add_bom/wizard/sale_add_phantom_bom.py
Normal file
69
sale_order_add_bom/wizard/sale_add_phantom_bom.py
Normal 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
|
||||
36
sale_order_add_bom/wizard/sale_add_phantom_bom_view.xml
Normal file
36
sale_order_add_bom/wizard/sale_add_phantom_bom_view.xml
Normal 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>
|
||||
Reference in New Issue
Block a user