Merge pull request #9 from guewen/rma-stock-location

crm_rma_stock_location: adds a RMA location on warehouses
This commit is contained in:
Pedro M. Baeza
2014-11-16 10:17:40 +01:00
14 changed files with 452 additions and 11 deletions

View File

@@ -23,7 +23,8 @@
{'name': 'RMA Claims Advance Location',
'version': '1.0',
'category': 'Generic Modules/CRM & SRM',
'depends': ['crm_claim_rma'
'depends': ['crm_claim_rma',
'crm_rma_stock_location',
],
'author': 'Akretion',
'license': 'AGPL-3',

View File

@@ -27,7 +27,6 @@ class stock_warehouse(orm.Model):
_inherit = "stock.warehouse"
_columns = {
'lot_rma_id': fields.many2one('stock.location', 'Location RMA'),
'lot_carrier_loss_id': fields.many2one(
'stock.location',
'Location Carrier Loss'),

View File

@@ -9,11 +9,6 @@
<field name="usage">internal</field>
<field name="location_id" ref="stock.stock_location_company"/>
</record>
<record id="stock_location_rma" model="stock.location">
<field name="name">RMA</field>
<field name="usage">internal</field>
<field name="location_id" ref="stock.stock_location_company"/>
</record>
<record id="stock_location_breakage_loss" model="stock.location">
<field name="name">Breakage Loss</field>
<field name="usage">internal</field>
@@ -33,7 +28,6 @@
Default Values for : Stock Warehouse
-->
<record id="stock.warehouse0" model="stock.warehouse">
<field name="lot_rma_id" ref="stock_location_rma"/>
<field name="lot_breakage_loss_id" ref="stock_location_breakage_loss"/>
<field name="lot_carrier_loss_id" ref="stock_location_carrier_loss"/>
<field name="lot_refurbish_id" ref="stock_location_refurbish"/>

View File

@@ -32,10 +32,9 @@
<record id="warehouse_form" model="ir.ui.view">
<field name="name">crm_claim_rma.warehouse_form</field>
<field name="model">stock.warehouse</field>
<field name="inherit_id" ref="stock.view_warehouse" />
<field name="inherit_id" ref="crm_rma_stock_location.view_warehouse_form" />
<field name="arch" type="xml">
<xpath expr="/form/group/group/field[@name='lot_output_id']" position="after">
<field name="lot_rma_id"/>
<xpath expr="/form/group/group/field[@name='lot_rma_id']" position="after">
<field name="lot_carrier_loss_id"/>
<field name="lot_breakage_loss_id"/>
<field name="lot_refurbish_id"/>

View File

@@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Guewen Baconnier
# Copyright 2014 Camptocamp SA
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from . import stock_warehouse
from . import product

View File

@@ -0,0 +1,49 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Guewen Baconnier
# Copyright 2014 Camptocamp SA
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
{'name': 'RMA Stock Location',
'version': '1.0',
'author': 'Camptocamp',
'maintainer': 'Camptocamp',
'license': 'AGPL-3',
'category': 'Generic Modules/CRM & SRM',
'depends': ['stock',
'procurement',
],
'description': """
RMA Stock Location
==================
A RMA location can be selected on the warehouses.
The product views displays the quantity available and virtual in this
RMA location (including the children locations).
""",
'website': 'http://www.camptocamp.com',
'data': ['stock_data.xml',
'stock_warehouse_view.xml',
'product_view.xml',
],
'test': ['test/quantity.yml',
],
'installable': True,
'auto_install': False,
}

View File

@@ -0,0 +1,54 @@
# Translation of OpenERP Server.
# This file contains the translation of the following modules:
# * crm_rma_stock_location
#
msgid ""
msgstr ""
"Project-Id-Version: OpenERP Server 7.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-09-12 11:27+0000\n"
"PO-Revision-Date: 2014-09-12 11:27+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: crm_rma_stock_location
#: model:ir.model.fields,field_description:crm_rma_stock_location.field_stock_warehouse_lot_rma_id
#: field:stock.warehouse,lot_rma_id:0
msgid "Location RMA"
msgstr ""
#. module: crm_rma_stock_location
#: code:_description:0
#: model:ir.model,name:crm_rma_stock_location.model_product_product
#, python-format
msgid "Product"
msgstr ""
#. module: crm_rma_stock_location
#: model:stock.location,name:crm_rma_stock_location.stock_location_rma
msgid "RMA"
msgstr ""
#. module: crm_rma_stock_location
#: model:ir.model.fields,field_description:crm_rma_stock_location.field_product_product_rma_virtual_available
#: field:product.product,rma_virtual_available:0
msgid "RMA Forecasted Quantity"
msgstr ""
#. module: crm_rma_stock_location
#: model:ir.model.fields,field_description:crm_rma_stock_location.field_product_product_rma_qty_available
#: field:product.product,rma_qty_available:0
msgid "RMA Quantity On Hand"
msgstr ""
#. module: crm_rma_stock_location
#: code:_description:0
#: model:ir.model,name:crm_rma_stock_location.model_stock_warehouse
#, python-format
msgid "Warehouse"
msgstr ""

View File

@@ -0,0 +1,54 @@
# Translation of OpenERP Server.
# This file contains the translation of the following modules:
# * crm_rma_stock_location
#
msgid ""
msgstr ""
"Project-Id-Version: OpenERP Server 7.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-09-12 11:28+0000\n"
"PO-Revision-Date: 2014-09-12 11:28+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: crm_rma_stock_location
#: model:ir.model.fields,field_description:crm_rma_stock_location.field_stock_warehouse_lot_rma_id
#: field:stock.warehouse,lot_rma_id:0
msgid "Location RMA"
msgstr "Emplacement RMA"
#. module: crm_rma_stock_location
#: code:_description:0
#: model:ir.model,name:crm_rma_stock_location.model_product_product
#, python-format
msgid "Product"
msgstr "Article"
#. module: crm_rma_stock_location
#: model:stock.location,name:crm_rma_stock_location.stock_location_rma
msgid "RMA"
msgstr "RMA"
#. module: crm_rma_stock_location
#: model:ir.model.fields,field_description:crm_rma_stock_location.field_product_product_rma_virtual_available
#: field:product.product,rma_virtual_available:0
msgid "RMA Forecasted Quantity"
msgstr "Quantité RMA prévue"
#. module: crm_rma_stock_location
#: model:ir.model.fields,field_description:crm_rma_stock_location.field_product_product_rma_qty_available
#: field:product.product,rma_qty_available:0
msgid "RMA Quantity On Hand"
msgstr "Quantité RMA en stock"
#. module: crm_rma_stock_location
#: code:_description:0
#: model:ir.model,name:crm_rma_stock_location.model_stock_warehouse
#, python-format
msgid "Warehouse"
msgstr "Entrepôt"

View File

@@ -0,0 +1,106 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Guewen Baconnier
# Copyright 2014 Camptocamp SA
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.osv import orm, fields
import openerp.addons.decimal_precision as dp
class ProductProduct(orm.Model):
_inherit = 'product.product'
def _rma_product_available(self, cr, uid, ids, field_names=None, arg=False,
context=None):
""" Finds the incoming and outgoing quantity of product for the RMA
locations.
"""
if field_names is None:
field_names = []
if context is None:
context = {}
warehouse_obj = self.pool['stock.warehouse']
res = {}
for id in ids:
res[id] = {}.fromkeys(field_names, 0.0)
for field in field_names:
ctx = context.copy()
warehouse_id = ctx.get('warehouse_id')
# no dependency on 'sale', the same oddness is done in
# 'stock' so I kept it here
if ctx.get('shop') and self.pool.get('sale.shop'):
shop_obj = self.pool['sale.shop']
shop_id = ctx['shop']
warehouse = shop_obj.read(cr, uid, shop_id,
['warehouse_id'],
context=ctx)
warehouse_id = warehouse['warehouse_id'][0]
if warehouse_id:
rma_id = warehouse_obj.read(cr, uid,
warehouse_id,
['lot_rma_id'],
context=ctx)['lot_rma_id'][0]
if rma_id:
ctx['location'] = rma_id
else:
location_ids = set()
wids = warehouse_obj.search(cr, uid, [], context=context)
if not wids:
return res
for wh in warehouse_obj.browse(cr, uid, wids, context=context):
if wh.lot_rma_id:
location_ids.add(wh.lot_rma_id.id)
if not location_ids:
return res
ctx['location'] = list(location_ids)
ctx['compute_child'] = True
compute = {
'rma_qty_available': {
'states': ('done', ),
'what': ('in', 'out')
},
'rma_virtual_available': {
'states': ('confirmed', 'waiting', 'assigned', 'done'),
'what': ('in', 'out')
}
}
ctx.update(compute[field])
stock = self.get_product_available(cr, uid, ids, context=ctx)
for id in ids:
res[id][field] = stock.get(id, 0.0)
return res
_columns = {
'rma_qty_available': fields.function(
_rma_product_available,
type='float',
multi='rma_qty',
digits_compute=dp.get_precision('Product Unit of Measure'),
string='RMA Quantity On Hand'),
'rma_virtual_available': fields.function(
_rma_product_available,
type='float',
multi='rma_qty',
digits_compute=dp.get_precision('Product Unit of Measure'),
string='RMA Forecasted Quantity'),
}

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="0">
<record id="product_product_tree_view" model="ir.ui.view">
<field name="name">product.product.tree</field>
<field name="model">product.product</field>
<field name="inherit_id" ref="product.product_product_tree_view"/>
<field name="arch" type="xml">
<field name="virtual_available" position="after">
<field name="rma_qty_available"/>
<field name="rma_virtual_available"/>
</field>
</field>
</record>
<record id="view_normal_procurement_locations_form" model="ir.ui.view">
<field name="name">product.normal.procurement.locations.inherit</field>
<field name="model">product.product</field>
<field name="inherit_id" ref="stock.view_normal_procurement_locations_form"/>
<field name="arch" type="xml">
<field name="virtual_available" position="after">
<field name="rma_qty_available" class="oe_inline"/>
<field name="rma_virtual_available" class="oe_inline"/>
</field>
</field>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0"?>
<openerp>
<data noupdate="1">
<record id="stock_location_rma" model="stock.location">
<field name="name">RMA</field>
<field name="usage">internal</field>
<field name="location_id" ref="stock.stock_location_company"/>
</record>
<record id="stock.warehouse0" model="stock.warehouse">
<field name="lot_rma_id" ref="stock_location_rma"/>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Guewen Baconnier
# Copyright 2014 Camptocamp SA
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.osv import orm, fields
class StockWarehouse(orm.Model):
_inherit = 'stock.warehouse'
_columns = {
'lot_rma_id': fields.many2one('stock.location', 'Location RMA'),
}

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="0">
<record id="view_warehouse_form" model="ir.ui.view">
<field name="name">view_warehouse_form</field>
<field name="model">stock.warehouse</field>
<field name="inherit_id" ref="stock.view_warehouse" />
<field name="arch" type="xml">
<xpath expr="/form/group/group/field[@name='lot_output_id']" position="after">
<field name="lot_rma_id"/>
</xpath>
</field>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,72 @@
-
I create RMA locations
-
!record {model: stock.location, id: location_rma}:
name: RMA
usage: view
-
!record {model: stock.location, id: location_rma_a}:
name: RMA - Box A
usage: internal
location_id: location_rma
-
!record {model: stock.location, id: location_rma_b}:
name: RMA - Box B
usage: internal
location_id: location_rma
-
I set the RMA location on the warehouse
-
!record {model: stock.warehouse, id: stock.warehouse0}:
lot_rma_id: location_rma
-
I create a product
-
!record {model: product.product, id: product_socket}:
default_code: 002
name: Sockets
type: product
categ_id: product.product_category_1
list_price: 100.0
standard_price: 70.0
uom_id: product.product_uom_unit
uom_po_id: product.product_uom_unit
-
I create a physical inventory with 50 units in Box A and 30 in Box B
-
!record {model: stock.inventory, id: stock_inventory_socket}:
name: Inventory for Sockets
-
!record {model: stock.inventory.line, id: stock_inventory_line_socket_1}:
product_id: product_socket
product_uom: product.product_uom_unit
inventory_id: stock_inventory_socket
product_qty: 50.0
location_id: location_rma_a
-
!record {model: stock.inventory.line, id: stock_inventory_line_socket_2}:
product_id: product_socket
product_uom: product.product_uom_unit
inventory_id: stock_inventory_socket
product_qty: 30.0
location_id: location_rma_b
-
I confirm the physical inventory
-
!python {model: stock.inventory}: |
self.action_confirm(cr, uid, [ref('stock_inventory_socket')], context=context)
-
I confirm the move in Box A
-
!python {model: stock.inventory}: |
inventory = self.browse(cr, uid, ref('stock_inventory_socket'), context=context)
assert len(inventory.move_ids) == len(inventory.inventory_line_id), "moves are not correspond."
for move in inventory.move_ids:
if move.location_dest_id.id == ref('location_rma_a'):
move.action_done()
-
I check my RMA quantities, I should have 50 on hands and 80 forecasted
-
!assert {model: product.product, id: product_socket, string: RMA quantity is wrong}:
- rma_qty_available == 50
- rma_virtual_available == 80