[IMP] crm_rma_stock_location: adapt to Odoo v8.0, include view section for product quantities on hand and forecasted, add unittest, add i18n terms

This commit is contained in:
Osval Reyes
2015-11-26 14:39:52 -04:30
parent d9a4f106d2
commit 72ec97c461
32 changed files with 1700 additions and 300 deletions

View File

@@ -0,0 +1,96 @@
.. 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
==================
RMA Stock Location
==================
Allow the user to know how much for a product is available 'On Hand' and how much
is virtually (expected to be) available for RMA locations. Adding for the
different product views (Tree, Form and Kanban) information about it.
Both quantities are computed and includes its children locations.
It is useful use it as a quick snapshot for RMA from product perspective.
It also adds the following location on warehouses :
* Loss
* Refurbish
Various wizards on incoming deliveries that allow you to move your
goods easily in those new locations from a done reception.
Using this module make the logistic flow of return a bit more complex:
* Returning product goes into RMA location with a incoming shipment
* From the incoming shipment, forward them to another places (stock, loss, refurbish)
Installation
============
To install this module, just select it from availables modules.
Configuration
=============
No configuration is needed
Usage
=====
* Go to Sales > After-sale Services and note that 'RMA Quantity On Hand' and
'RMA Forecasted Quantity' had been included and it'll be shown when at least
a product has either a on hand or forecasted quantities available.
* In the other hand, it provides three wizards to make stock moves (transfers)
allowing to do product returns (incoming), send a product to loss or, to a refurbish
location.
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/8.0/145
For further information, please visit:
* https://www.odoo.com/forum/help-1
Known issues / Roadmap
======================
* Optimization is possible when searching virtual quantities in the search function
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/rma/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
`here <https://github.com/OCA/rma/issues/new?body=module:%20crm_rma_stock_location%0Aversion:%208.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Credits
=======
Contributors
------------
* Guewen Baconnier <guewen.baconnier@camptocamp.com>
* Yanina Aular <yanina.aular@vauxoo.com>
* Osval Reyes <osval@vauxoo.com>
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.

View File

@@ -1,8 +1,10 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Guewen Baconnier
# Copyright 2015 Vauxoo
# Copyright 2014 Camptocamp SA
# Author: Guewen Baconnier,
# Osval Reyes
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -19,5 +21,14 @@
#
##############################################################################
from . import stock_warehouse
from . import product
from . import models
from . import wizards
from openerp import SUPERUSER_ID
def post_init_hook(cr, registry):
stock_wh = registry['stock.warehouse']
for wh_id in stock_wh.browse(cr, SUPERUSER_ID,
stock_wh.search(cr, SUPERUSER_ID, [])):
vals = stock_wh.create_locations_rma(cr, SUPERUSER_ID, wh_id)
stock_wh.write(cr, SUPERUSER_ID, wh_id.id, vals)

View File

@@ -1,8 +1,13 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Guewen Baconnier
# Copyright 2014 Camptocamp SA
# Copyright 2015 Vauxoo
# Copyright 2013-2014 Camptocamp SA
# Copyright 2009-2013 Akretion,
# Author: Guewen Baconnier,
# Emmanuel Samyn, Raphaël Valyi, Sébastien Beau,
# Joel Grand-Guillaume,
# Yanina Aular, Osval Reyes
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -19,31 +24,35 @@
#
##############################################################################
{'name': 'RMA Stock Location',
'version': '1.0',
'author': "Camptocamp,Odoo Community Association (OCA)",
'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': False,
'auto_install': False,
}
{
'name': 'RMA Stock Location',
'version': '8.0.1.0.0',
'author': "Akretion,Vauxoo,Camptocamp,Odoo Community Association (OCA)",
'maintainer': 'Camptocamp',
'website': 'http://www.camptocamp.com,http://www.vauxoo.com',
'license': 'AGPL-3',
'category': 'Generic Modules/CRM & SRM',
'depends': [
'crm_claim_rma',
'crm_claim',
'stock_account',
'procurement',
'crm_rma_location',
],
'data': [
'wizards/claim_make_picking_from_picking_view.xml',
'wizards/claim_make_picking_view.xml',
'views/product_product.xml',
'views/product_template.xml',
'views/crm_claim.xml',
'views/stock_picking.xml',
'views/stock_warehouse.xml',
],
'demo': [
'demo/stock_location.xml',
'demo/stock_inventory.xml',
],
'post_init_hook': 'post_init_hook',
'installable': True,
'auto_install': False,
}

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="1">
<record id="rma_stock_location_move_01" model="stock.move">
<field name="name">Demo Stock Move: Customer > RMA</field>
<field name="product_id" ref="product.product_product_24"/>
<field name="product_uom">1</field>
<field name="product_uom_qty">1000</field>
<field name="company_id" ref="base.main_company"/>
<field name="priority">1</field> <!-- Normal -->
<field name="picking_type_id" ref="stock.picking_type_in"/>
<field name="location_id" ref="stock.stock_location_customers"/>
<field name="location_dest_id" search="[('name', '=', 'RMA'), ('location_id.name', '=', 'WH')]"/>
</record>
<record id="rma_stock_location_move_03" model="stock.move">
<field name="name">Demo Stock Move: RMA > Loss</field>
<field name="product_id" ref="product.product_product_24"/>
<field name="product_uom">1</field>
<field name="product_uom_qty">1000</field>
<field name="company_id" ref="base.main_company"/>
<field name="priority">1</field> <!-- Normal -->
<field name="picking_type_id" ref="stock.picking_type_internal"/>
<field name="location_id" search="[('name', '=', 'RMA'), ('location_id.name', '=', 'WH')]"/>
<field name="location_dest_id" ref="stock.stock_location_stock"/>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="1">
<record id="location_rma" model="stock.location">
<field name="name">RMA Demo</field>
<field name="usage">internal</field>
</record>
<record id="stock.stock_warehouse_shop0" model="stock.warehouse">
<field name="lot_rma_id" ref="location_rma"/>
</record>
<record id="location_rma_a" model="stock.location">
<field name="name">RMA - Box A</field>
<field name="location_id" ref="location_rma"/>
<field name="usage">internal</field>
</record>
<record id="location_rma_b" model="stock.location">
<field name="name">RMA - Box B</field>
<field name="location_id" ref="location_rma"/>
<field name="usage">internal</field>
</record>
<record id="product_socket" model="product.product">
<field name="name">Socket</field>
<field name="categ_id" ref="product.product_category_1"/>
<field name="standard_price">70.0</field>
<field name="list_price">100.0</field>
<field name="type">product</field>
<field name="uom_id" ref="product.product_uom_unit"/>
<field name="uom_po_id" ref="product.product_uom_unit"/>
</record>
</data>
</openerp>

View File

@@ -1,13 +1,13 @@
# Translation of OpenERP Server.
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * crm_rma_stock_location
# * crm_rma_stock_location
#
msgid ""
msgstr ""
"Project-Id-Version: OpenERP Server 7.0\n"
"Project-Id-Version: Odoo Server 8.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"
"POT-Creation-Date: 2015-11-25 21:48+0000\n"
"PO-Revision-Date: 2015-11-25 21:48+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
@@ -16,39 +16,221 @@ msgstr ""
"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"
#: view:claim.make.picking.from.picking.wizard:crm_rma_stock_location.view_claim_picking_from_picking
msgid "Cancel"
msgstr ""
#. module: crm_rma_stock_location
#: code:_description:0
#: model:ir.model,name:crm_rma_stock_location.model_product_product
#: model:ir.actions.act_window,name:crm_rma_stock_location.action_loss_picking_from_claim_picking
msgid "Create Incoming Shipment to Breakage Loss Location"
msgstr ""
#. module: crm_rma_stock_location
#: model:ir.actions.act_window,name:crm_rma_stock_location.action_used_picking_from_claim_picking
msgid "Create Incoming Shipment to Refurbish Location"
msgstr ""
#. module: crm_rma_stock_location
#: model:ir.actions.act_window,name:crm_rma_stock_location.action_stock_picking_from_claim_picking
msgid "Create Incoming Shipment to Stock"
msgstr ""
#. module: crm_rma_stock_location
#: model:ir.actions.act_window,name:crm_rma_stock_location.action_claim_picking_loss
msgid "Create a Product Loss"
msgstr ""
#. module: crm_rma_stock_location
#: view:claim.make.picking.from.picking.wizard:crm_rma_stock_location.view_claim_picking_from_picking
msgid "Create picking"
msgstr ""
#. module: crm_rma_stock_location
#: field:claim.make.picking.from.picking.wizard,create_uid:0
msgid "Created by"
msgstr ""
#. module: crm_rma_stock_location
#: field:claim.make.picking.from.picking.wizard,create_date:0
msgid "Created on"
msgstr ""
#. module: crm_rma_stock_location
#: code:addons/crm_rma_stock_location/wizards/claim_make_picking_from_picking.py:89
#: field:claim.make.picking.from.picking.wizard,picking_line_dest_location:0
#, python-format
msgid "Dest. Location"
msgstr ""
#. module: crm_rma_stock_location
#: field:claim.make.picking.from.picking.wizard,id:0
msgid "ID"
msgstr ""
#. module: crm_rma_stock_location
#: field:claim.make.picking.from.picking.wizard,write_uid:0
msgid "Last Updated by"
msgstr ""
#. module: crm_rma_stock_location
#: field:claim.make.picking.from.picking.wizard,write_date:0
msgid "Last Updated on"
msgstr ""
#. module: crm_rma_stock_location
#: help:claim.make.picking.from.picking.wizard,picking_line_source_location:0
msgid "Source location where the returned products are"
msgstr ""
#. module: crm_rma_stock_location
#: help:claim.make.picking.from.picking.wizard,picking_line_dest_location:0
msgid "Target location to send returned products"
msgstr ""
#. module: crm_rma_stock_location
#: view:claim.make.picking.from.picking.wizard:crm_rma_stock_location.view_claim_picking_from_picking
msgid "Locations"
msgstr ""
#. module: crm_rma_stock_location
#: code:addons/crm_rma_stock_location/models/stock_warehouse.py:62
#, python-format
msgid "Loss"
msgstr ""
#. module: crm_rma_stock_location
#: field:stock.warehouse,loss_loc_id:0
msgid "Loss Location"
msgstr ""
#. module: crm_rma_stock_location
#: view:crm.claim:crm_rma_stock_location.crm_claim_rma_form_view_loss
msgid "New Product Loss"
msgstr ""
#. module: crm_rma_stock_location
#: field:claim.make.picking.from.picking.wizard,picking_line_ids:0
msgid "Picking lines"
msgstr ""
#. module: crm_rma_stock_location
#: model:ir.model,name:crm_rma_stock_location.model_product_product
msgid "Product"
msgstr ""
#. module: crm_rma_stock_location
#: model:stock.location,name:crm_rma_stock_location.stock_location_rma
msgid "RMA"
#: model:ir.model,name:crm_rma_stock_location.model_product_template
msgid "Product Template"
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
#: view:product.product:crm_rma_stock_location.rma_product_product_tree_view
msgid "Product Variants"
msgstr ""
#. module: crm_rma_stock_location
#: view:stock.picking:crm_rma_stock_location.picking_in_form
msgid "Product to Loss"
msgstr ""
#. module: crm_rma_stock_location
#: view:stock.picking:crm_rma_stock_location.picking_in_form
msgid "Product to refurbish stock"
msgstr ""
#. module: crm_rma_stock_location
#: view:stock.picking:crm_rma_stock_location.picking_in_form
msgid "Product to stock"
msgstr ""
#. module: crm_rma_stock_location
#: model:stock.location,name:crm_rma_stock_location.location_rma_a
msgid "RMA - Box A"
msgstr ""
#. module: crm_rma_stock_location
#: model:stock.location,name:crm_rma_stock_location.location_rma_b
msgid "RMA - Box B"
msgstr ""
#. module: crm_rma_stock_location
#: view:product.product:crm_rma_stock_location.rma_product_search_view
msgid "RMA Available Products"
msgstr ""
#. module: crm_rma_stock_location
#: model:stock.location,name:crm_rma_stock_location.location_rma
msgid "RMA Demo"
msgstr ""
#. module: crm_rma_stock_location
#: code:addons/crm_rma_stock_location/models/product_product.py:42
#, python-format
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
#: view:product.product:crm_rma_stock_location.rma_product_search_view
msgid "RMA Products"
msgstr ""
#. module: crm_rma_stock_location
#: code:addons/crm_rma_stock_location/models/product_product.py:36
#, python-format
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
#: code:addons/crm_rma_stock_location/models/stock_warehouse.py:56
#, python-format
msgid "Refurbish"
msgstr ""
#. module: crm_rma_stock_location
#: field:stock.warehouse,lot_refurbish_id:0
msgid "Refurbish Location"
msgstr ""
#. module: crm_rma_stock_location
#: view:claim.make.picking.from.picking.wizard:crm_rma_stock_location.view_claim_picking_from_picking
msgid "Select lines for picking"
msgstr ""
#. module: crm_rma_stock_location
#: view:claim.make.picking.from.picking.wizard:crm_rma_stock_location.view_claim_picking_from_picking
msgid "Select lines to add in picking"
msgstr ""
#. module: crm_rma_stock_location
#: model:product.template,name:crm_rma_stock_location.product_socket_product_template
msgid "Socket"
msgstr ""
#. module: crm_rma_stock_location
#: code:addons/crm_rma_stock_location/wizards/claim_make_picking_from_picking.py:85
#: field:claim.make.picking.from.picking.wizard,picking_line_source_location:0
#, python-format
msgid "Source Location"
msgstr ""
#. module: crm_rma_stock_location
#: model:ir.actions.act_window,name:crm_rma_stock_location.rma_product_variant_action
#: model:ir.ui.menu,name:crm_rma_stock_location.menu_stock_rma
msgid "RMA Stock"
msgstr ""
#. module: crm_rma_stock_location
#: model:ir.model,name:crm_rma_stock_location.model_stock_warehouse
msgid "Warehouse"
msgstr ""
#. module: crm_rma_stock_location
#: model:ir.model,name:crm_rma_stock_location.model_claim_make_picking_wizard
msgid "Wizard to create pickings from claim lines"
msgstr ""
#. module: crm_rma_stock_location
#: model:ir.model,name:crm_rma_stock_location.model_claim_make_picking_from_picking_wizard
msgid "Wizard to create pickings from picking lines"
msgstr ""

View File

@@ -0,0 +1,239 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * crm_rma_stock_location
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-11-25 21:48+0000\n"
"PO-Revision-Date: 2015-11-25 21:48+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
#: view:claim.make.picking.from.picking.wizard:crm_rma_stock_location.view_claim_picking_from_picking
msgid "Cancel"
msgstr "Cancelar"
#. module: crm_rma_stock_location
#: model:ir.actions.act_window,name:crm_rma_stock_location.action_loss_picking_from_claim_picking
msgid "Create Incoming Shipment to Breakage Loss Location"
msgstr "Crear un envío de entrada hacia la ubicación de pérdida de productos dañados"
#. module: crm_rma_stock_location
#: model:ir.actions.act_window,name:crm_rma_stock_location.action_used_picking_from_claim_picking
msgid "Create Incoming Shipment to Refurbish Location"
msgstr "Crear un envío de entrada hacia la ubicación de productos restaurados"
#. module: crm_rma_stock_location
#: model:ir.actions.act_window,name:crm_rma_stock_location.action_stock_picking_from_claim_picking
msgid "Create Incoming Shipment to Stock"
msgstr "Crear un envío de entrada a Existencias"
#. module: crm_rma_stock_location
#: model:ir.actions.act_window,name:crm_rma_stock_location.action_claim_picking_loss
msgid "Create a Product Loss"
msgstr "Registrar una pérdida de producto"
#. module: crm_rma_stock_location
#: view:claim.make.picking.from.picking.wizard:crm_rma_stock_location.view_claim_picking_from_picking
msgid "Create picking"
msgstr "Crear un albarán"
#. module: crm_rma_stock_location
#: field:claim.make.picking.from.picking.wizard,create_uid:0
msgid "Created by"
msgstr "Creado por"
#. module: crm_rma_stock_location
#: field:claim.make.picking.from.picking.wizard,create_date:0
msgid "Created on"
msgstr "Creado el"
#. module: crm_rma_stock_location
#: code:addons/crm_rma_stock_location/wizards/claim_make_picking_from_picking.py:89
#: field:claim.make.picking.from.picking.wizard,picking_line_dest_location:0
#, python-format
msgid "Dest. Location"
msgstr "Ubicación destino"
#. module: crm_rma_stock_location
#: field:claim.make.picking.from.picking.wizard,id:0
msgid "ID"
msgstr ""
#. module: crm_rma_stock_location
#: field:claim.make.picking.from.picking.wizard,write_uid:0
msgid "Last Updated by"
msgstr "Actualizado por"
#. module: crm_rma_stock_location
#: field:claim.make.picking.from.picking.wizard,write_date:0
msgid "Last Updated on"
msgstr "Actualizado el"
#. module: crm_rma_stock_location
#: help:claim.make.picking.from.picking.wizard,picking_line_source_location:0
msgid "Source location where the returned products are"
msgstr "Ubicación origen de los productos devueltos"
#. module: crm_rma_stock_location
#: help:claim.make.picking.from.picking.wizard,picking_line_dest_location:0
msgid "Target location to send returned products"
msgstr "Ubicación destino de los productos devueltos"
#. module: crm_rma_stock_location
#: view:claim.make.picking.from.picking.wizard:crm_rma_stock_location.view_claim_picking_from_picking
msgid "Locations"
msgstr "Ubicaciones"
#. module: crm_rma_stock_location
#: code:addons/crm_rma_stock_location/models/stock_warehouse.py:62
#, python-format
msgid "Loss"
msgstr "Pérdida"
#. module: crm_rma_stock_location
#: field:stock.warehouse,loss_loc_id:0
msgid "Loss Location"
msgstr "Ubicación de Pérdida"
#. module: crm_rma_stock_location
#: view:crm.claim:crm_rma_stock_location.crm_claim_rma_form_view_loss
msgid "New Product Loss"
msgstr "Nueva Pérdida de Producto"
#. module: crm_rma_stock_location
#: field:claim.make.picking.from.picking.wizard,picking_line_ids:0
msgid "Picking lines"
msgstr "Líneas de albarán"
#. module: crm_rma_stock_location
#: model:ir.model,name:crm_rma_stock_location.model_product_product
msgid "Product"
msgstr "Producto"
#. module: crm_rma_stock_location
#: model:ir.model,name:crm_rma_stock_location.model_product_template
msgid "Product Template"
msgstr "Producto Plantilla"
#. module: crm_rma_stock_location
#: view:product.product:crm_rma_stock_location.rma_product_product_tree_view
msgid "Product Variants"
msgstr "Variantes del Producto"
#. module: crm_rma_stock_location
#: view:stock.picking:crm_rma_stock_location.picking_in_form
msgid "Product to Loss"
msgstr "Producto a Pérdida"
#. module: crm_rma_stock_location
#: view:stock.picking:crm_rma_stock_location.picking_in_form
msgid "Product to refurbish stock"
msgstr "Producto a Existencias de restaurados"
#. module: crm_rma_stock_location
#: view:stock.picking:crm_rma_stock_location.picking_in_form
msgid "Product to stock"
msgstr "Producto a Existencias"
#. module: crm_rma_stock_location
#: model:stock.location,name:crm_rma_stock_location.location_rma_a
msgid "RMA - Box A"
msgstr "RMA - Caja A"
#. module: crm_rma_stock_location
#: model:stock.location,name:crm_rma_stock_location.location_rma_b
msgid "RMA - Box B"
msgstr "RMA - Caja B"
#. module: crm_rma_stock_location
#: view:product.product:crm_rma_stock_location.rma_product_search_view
msgid "RMA Available Products"
msgstr "Productos disponibles en RMA"
#. module: crm_rma_stock_location
#: model:stock.location,name:crm_rma_stock_location.location_rma
msgid "RMA Demo"
msgstr "Demostración RMA"
#. module: crm_rma_stock_location
#: code:addons/crm_rma_stock_location/models/product_product.py:42
#: code:addons/crm_rma_stock_location/models/product_template.py:42
#, python-format
msgid "RMA Forecasted Quantity"
msgstr "Pronóstico de Cantidades en RMA"
#. module: crm_rma_stock_location
#: view:product.product:crm_rma_stock_location.rma_product_search_view
msgid "RMA Products"
msgstr "Productos en RMA"
#. module: crm_rma_stock_location
#: code:addons/crm_rma_stock_location/models/product_product.py:36
#: code:addons/crm_rma_stock_location/models/product_template.py:36
#, python-format
msgid "RMA Quantity On Hand"
msgstr "Cantidades Disponibles en RMA"
#. module: crm_rma_stock_location
#: code:addons/crm_rma_stock_location/models/stock_warehouse.py:56
#, python-format
msgid "Refurbish"
msgstr "Restaurar"
#. module: crm_rma_stock_location
#: field:stock.warehouse,lot_refurbish_id:0
msgid "Refurbish Location"
msgstr "Ubicación de Restaurados"
#. module: crm_rma_stock_location
#: view:claim.make.picking.from.picking.wizard:crm_rma_stock_location.view_claim_picking_from_picking
msgid "Select lines for picking"
msgstr "Seleccionar lineas para albarán"
#. module: crm_rma_stock_location
#: view:claim.make.picking.from.picking.wizard:crm_rma_stock_location.view_claim_picking_from_picking
msgid "Select lines to add in picking"
msgstr "Seleccionar lineas a agregar en albarán"
#. module: crm_rma_stock_location
#: model:product.template,name:crm_rma_stock_location.product_socket_product_template
msgid "Socket"
msgstr "Sócate"
#. module: crm_rma_stock_location
#: code:addons/crm_rma_stock_location/wizards/claim_make_picking_from_picking.py:85
#: field:claim.make.picking.from.picking.wizard,picking_line_source_location:0
#, python-format
msgid "Source Location"
msgstr "Ubicación origen"
#. module: crm_rma_stock_location
#: model:ir.actions.act_window,name:crm_rma_stock_location.rma_product_variant_action
#: model:ir.ui.menu,name:crm_rma_stock_location.menu_stock_rma
msgid "RMA Stock"
msgstr "Existencias en RMA"
#. module: crm_rma_stock_location
#: model:ir.model,name:crm_rma_stock_location.model_stock_warehouse
msgid "Warehouse"
msgstr "Almacén"
#. module: crm_rma_stock_location
#: model:ir.model,name:crm_rma_stock_location.model_claim_make_picking_wizard
msgid "Wizard to create pickings from claim lines"
msgstr "Asistente para create albaranes desde lineas de reclamo"
#. module: crm_rma_stock_location
#: model:ir.model,name:crm_rma_stock_location.model_claim_make_picking_from_picking_wizard
msgid "Wizard to create pickings from picking lines"
msgstr "Asistente para create albaranes desde lineas de albaranes"

View File

@@ -0,0 +1,16 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * crm_rma_stock_location
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-07-18 00:48+0000\n"
"PO-Revision-Date: 2015-07-18 00:48+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"

View File

@@ -0,0 +1,16 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * crm_rma_stock_location
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-07-18 00:48+0000\n"
"PO-Revision-Date: 2015-07-18 00:48+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"

View File

@@ -0,0 +1,16 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * crm_rma_stock_location
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-07-18 00:48+0000\n"
"PO-Revision-Date: 2015-07-18 00:48+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"

View File

@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright 2015 Vauxoo
# Copyright 2013-2014 Camptocamp SA
# Copyright 2009-2013 Akretion,
# Author: Guewen Baconnier,
# Emmanuel Samyn, Raphaël Valyi, Sébastien Beau,
# Joel Grand-Guillaume,
# Osval Reyes
#
# 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 product_product
from . import product_template
from . import stock_warehouse

View File

@@ -0,0 +1,131 @@
# -*- 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 import _, models, fields
import openerp.addons.decimal_precision as dp
from openerp.tools.float_utils import float_round
from openerp.tools.safe_eval import safe_eval as eval
class ProductProduct(models.Model):
_inherit = 'product.product'
rma_qty_available = fields.Float(
compute='_rma_product_available',
digits_compute=dp.get_precision('Product Unit of Measure'),
search='_search_rma_product_quantity',
string=_('RMA Quantity On Hand'))
rma_virtual_available = fields.Float(
compute='_rma_product_available',
digits_compute=dp.get_precision('Product Unit of Measure'),
search='_search_rma_product_quantity',
string=_('RMA Forecasted Quantity'))
def _search_rma_product_quantity(self, operator, value):
res = []
# to prevent sql injections
assert operator in ('<', '>', '=', '!=',
'<=', '>='), 'Invalid domain operator'
assert isinstance(value, (float, int)), 'Invalid domain right operand'
if operator == '=':
operator = '=='
ids = []
product_ids = self.search([])
if product_ids:
for element in product_ids:
localdict = {'virtual': element.rma_virtual_available,
'qty': element.rma_qty_available,
'value': value}
if eval('qty %s value or virtual %s value' %
(operator, operator), localdict):
ids.append(element.id)
res.append(('id', 'in', ids))
return res
def _rma_product_available(self):
"""
Finds the incoming and outgoing quantity of product for the RMA
locations.
"""
context = self.env.context
warehouse_id = context.get('warehouse_id')
ctx = context.copy()
location_ids = set()
for product in self:
if warehouse_id and warehouse_id.lot_rma_id:
location_ids.add(warehouse_id.lot_rma_id.id)
else:
warehouse_ids = self.env['stock.warehouse'].search([])
if not warehouse_ids:
return
for warehouse_id in warehouse_ids:
if warehouse_id.lot_rma_id:
location_ids.add(warehouse_id.lot_rma_id.id)
if not location_ids:
return
ctx['location'] = list(location_ids)
domain_products = [('product_id', 'in', [product.id])]
domain_quant, domain_move_in, domain_move_out = \
product.with_context(ctx)._get_domain_locations()
domain_move_in += product.with_context(ctx)._get_domain_dates() + \
[('state', 'not in', ('done', 'cancel', 'draft'))] + \
domain_products
domain_move_out += product.with_context(ctx).\
_get_domain_dates() + \
[('state', 'not in', ('done', 'cancel', 'draft'))] + \
domain_products
domain_quant += domain_products
moves_in = []
moves_out = []
lot_id = context.get('lot_id')
if lot_id:
domain_quant.append(('lot_id', '=', lot_id))
else:
moves_in = self.env['stock.move'].\
with_context(ctx).read_group(domain_move_in,
['product_id', 'product_qty'],
['product_id'])
moves_out = self.env['stock.move'].\
with_context(ctx).read_group(domain_move_out,
['product_id', 'product_qty'],
['product_id'])
quants = self.env['stock.quant'].with_context(ctx).read_group(
domain_quant, ['product_id', 'qty'], ['product_id'])
quants = dict([(item.get('product_id')[0],
item.get('qty')) for item in quants])
moves_in = dict([(item.get('product_id')[0],
item.get('product_qty')) for item in moves_in])
moves_out = dict([(item.get('product_id')[0],
item.get('product_qty')) for item in moves_out])
product.rma_qty_available = \
float_round(quants.get(product.id, 0.0),
precision_rounding=product.uom_id.rounding)
product.rma_virtual_available = \
float_round(quants.get(product.id, 0.0) +
moves_in.get(product.id, 0.0) -
moves_out.get(product.id, 0.0),
precision_rounding=product.uom_id.rounding)

View File

@@ -0,0 +1,49 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright 2015 Vauxoo
# Copyright 2014 Camptocamp SA
# Author: Guewen Baconnier,
# Osval Reyes
#
# 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 import _, models, fields
import openerp.addons.decimal_precision as dp
class ProductTemplate(models.Model):
_inherit = 'product.template'
rma_qty_available = fields.Float(compute='_rma_product_available',
digits_compute=dp.
get_precision('Product Unit '
'of Measure'),
string=_('RMA Quantity On Hand'))
rma_virtual_available = fields.Float(compute='_rma_product_available',
digits_compute=dp.
get_precision('Product Unit'
' of Measure'),
string=_('RMA Forecasted Quantity'))
def _rma_product_available(self):
for product in self:
product.rma_qty_available = sum(
[p.rma_qty_available for p in product.product_variant_ids])
product.rma_virtual_available = sum(
[p.rma_virtual_available for p in product.product_variant_ids])

View File

@@ -0,0 +1,68 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright 2013 Camptocamp
# Copyright 2009-2013 Akretion,
# Author: Emmanuel Samyn, Raphaël Valyi, Sébastien Beau,
# Joel Grand-Guillaume
#
# 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 import _, api, fields, models
class StockWarehouse(models.Model):
_inherit = "stock.warehouse"
loss_loc_id = fields.Many2one('stock.location', 'Loss Location')
lot_refurbish_id = fields.Many2one('stock.location', 'Refurbish Location')
@api.model
def create_locations_rma(self, wh_id):
vals = {}
location_obj = self.env['stock.location']
context_with_inactive = self.env.context.copy()
context_with_inactive['active_test'] = False
wh_loc_id = wh_id.view_location_id.id
vals_new = super(StockWarehouse, self).create_locations_rma(wh_id)
loc_vals = {
'usage': 'internal',
'location_id': wh_loc_id,
'active': True,
}
if vals.get('company_id'):
loc_vals['company_id'] = vals.get('company_id')
if not wh_id.lot_refurbish_id:
loc_vals.update({'name': _('Refurbish')})
location_id = location_obj.with_context(context_with_inactive).\
create(loc_vals)
vals['lot_refurbish_id'] = location_id.id
if not wh_id.loss_loc_id:
loc_vals.update({'name': _('Loss')})
location_id = location_obj.with_context(context_with_inactive).\
create(loc_vals)
vals['loss_loc_id'] = location_id.id
vals.update(vals_new)
return vals

View File

@@ -1,106 +0,0 @@
# -*- 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

@@ -1,28 +0,0 @@
<?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

@@ -1,15 +0,0 @@
<?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

@@ -1,17 +0,0 @@
<?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

@@ -1,72 +0,0 @@
-
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

View File

@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Guewen Baconnier
# Copyright 2014 Camptocamp SA
# Copyright 2015 Vauxoo
# Author: Yanina Aular, Osval Reyes
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -19,12 +19,5 @@
#
##############################################################################
from openerp.osv import orm, fields
class StockWarehouse(orm.Model):
_inherit = 'stock.warehouse'
_columns = {
'lot_rma_id': fields.many2one('stock.location', 'Location RMA'),
}
from . import test_crm_rma_stock_location
from . import test_make_picking_from_picking

View File

@@ -0,0 +1,78 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright 2015 Vauxoo
# Author: Osval Reyes
#
# 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.tests.common import TransactionCase
class TestCrmRmaStockLocation(TransactionCase):
def setUp(self):
super(TestCrmRmaStockLocation, self).setUp()
self.inventory = self.env['stock.inventory']
self.inventory_line = self.env['stock.inventory.line']
self.location_id = self.env['stock.location'].search(
[('name', '=', 'RMA'), ('location_id.name', '=', 'WH')])
self.warehouse_id = self.env['stock.warehouse'].browse(
self.ref('stock.warehouse0'))
self.lot_rma_id = self.warehouse_id.lot_rma_id
self.product_uom_id = self.ref('product.product_uom_unit')
self.product_socket_id = self.env['product.product'].browse(
self.ref('crm_rma_stock_location.product_socket'))
def test_01_test(self):
inventory_id = self.inventory.create({
'name': 'Test Inventory 001',
'location_id': self.location_id.id,
'filter': 'product',
'product_id': self.product_socket_id.id,
})
inventory_line_id_a = self.inventory_line.create({
'inventory_id': inventory_id.id,
'product_id': self.product_socket_id.id,
'product_uom_id': self.product_uom_id,
'product_qty': 100,
'location_id': self.lot_rma_id.id
})
inventory_line_id_b = self.inventory_line.create({
'inventory_id': inventory_id.id,
'product_id': self.product_socket_id.id,
'product_uom_id': self.product_uom_id,
'product_qty': 10,
'location_id': self.lot_rma_id.id
})
inventory_id.prepare_inventory()
inventory_id.action_done()
qty = inventory_line_id_a.product_qty + inventory_line_id_b.product_qty
self.assertEquals(self.product_socket_id.rma_qty_available, qty)
self.assertEquals(self.product_socket_id.rma_virtual_available, qty)
self.assertEquals(
self.product_socket_id.product_tmpl_id.rma_qty_available, qty)
self.assertEquals(
self.product_socket_id.product_tmpl_id.rma_virtual_available, qty)
res = self.product_socket_id._search_rma_product_quantity(
'=',
inventory_line_id_a.product_qty + inventory_line_id_b.product_qty)
self.assertEquals(self.product_socket_id.id, res[0][2][0])

View File

@@ -0,0 +1,159 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Yanina Aular
# Copyright 2015 Vauxoo
#
# 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.tests.common import TransactionCase
class TestPickingFromPicking(TransactionCase):
def setUp(self):
super(TestPickingFromPicking, self).setUp()
self.stock_warehouse = self.env['stock.warehouse']
self.claim_id = self.create_claim()
self.wizardmakepicking = self.env['claim_make_picking.wizard']
self.claim_picking_wizard = \
self.env['claim.make.picking.from.picking.wizard']
self.get_default_locations()
def create_claim(self):
claim_id = self.env['crm.claim'].browse(
self.ref("crm_claim.crm_claim_6"))
claim_id.write({
'claim_line_ids': [(0, 0, {
'name': str(claim_id.id) + 'test 1',
'claim_origin': u'damaged',
'product_id': self.ref('product.product_product_8')
}), (0, 0, {
'name': str(claim_id.id) + 'test 2',
'claim_origin': u'none',
'product_id': self.ref('product.product_product_6')
})]
})
return claim_id
def get_default_locations(self):
"""
Return locations for RMA, Loss and Refurbish
"""
self.main_warehouse_id = self.stock_warehouse.browse(
self.ref("stock.warehouse0"))
self.loc_rma = self.main_warehouse_id.lot_rma_id
self.loss_loc = self.main_warehouse_id.loss_loc_id
self.loc_refurbish = self.main_warehouse_id.lot_refurbish_id
def test_01_get_dest_loc(self):
# Create Picking from Customers to RMA
# with button New Products Return
wiz_context = {
'active_id': self.claim_id.id,
'warehouse_id': self.claim_id.warehouse_id.id,
'partner_id': self.claim_id.partner_id.id,
'picking_type': self.claim_id.warehouse_id.rma_in_type_id.id,
}
wizard_id = self.wizardmakepicking.with_context(wiz_context).create({})
res = wizard_id.action_create_picking()
stock_picking_id = res.get('res_id')
# Create Picking 'Product to stock'
context = {
'active_id': stock_picking_id,
'picking_type': 'picking_stock',
}
claim_wizard = self.claim_picking_wizard.\
with_context(context).create({})
self.assertEquals(claim_wizard.picking_line_source_location.id,
self.loc_rma.id)
self.assertEquals(claim_wizard.picking_line_dest_location.id,
self.main_warehouse_id.lot_stock_id.id)
self.assertEquals(len(claim_wizard.picking_line_ids),
len(self.claim_id.claim_line_ids))
# Review number of picking lines with claim lines
picking_lines = claim_wizard.picking_line_ids
claim_lines = self.claim_id.claim_line_ids
for num in xrange(0, len(picking_lines)):
band = False
for num2 in xrange(0, len(claim_lines)):
if claim_lines[num].product_id.id == \
picking_lines[num2].product_id.id:
band = True
self.assertEquals(True, band)
claim_wizard.with_context(context).action_create_picking_from_picking()
# Create Picking 'Product to Loss'
claim_wizard = self.claim_picking_wizard.\
with_context({
'active_id': stock_picking_id,
'picking_type': 'picking_loss',
}).create({})
self.assertEquals(claim_wizard.picking_line_source_location.id,
self.loc_rma.id)
self.assertEquals(claim_wizard.picking_line_dest_location.id,
self.loss_loc.id)
def assert_picking_type(self, picking_type_str=''):
new_context = {
'active_id': self.claim_id.id,
'warehouse_id': self.claim_id.warehouse_id.id,
'partner_id': self.claim_id.partner_id.id,
'picking_type': picking_type_str,
}
wizard_id = self.wizardmakepicking.with_context(new_context).create({})
default_location_dest_id = eval(
'self.claim_id.warehouse_id.'
'rma_%s_type_id.default_location_dest_id' % picking_type_str)
self.assertEquals(
wizard_id.claim_line_dest_location_id, default_location_dest_id)
def test_02_picking_types_in_out_int(self):
self.assert_picking_type('in')
self.assert_picking_type('out')
self.assert_picking_type('int')
def test_03_picking_type_loss(self):
new_context = {
'active_id': self.claim_id.id,
'warehouse_id': self.claim_id.warehouse_id.id,
'partner_id': self.claim_id.partner_id.id,
'picking_type': 'loss',
}
wizard_id = self.wizardmakepicking.with_context(new_context).create({})
default_location_dest_id = eval(
'self.claim_id.warehouse_id.loss_loc_id')
self.assertEquals(
wizard_id.claim_line_dest_location_id, default_location_dest_id)

View File

@@ -0,0 +1,19 @@
<?xml version="1.0"?>
<openerp>
<data>
<record model="ir.ui.view" id="crm_claim_rma_form_view_loss">
<field name="name">CRM - Claim product return Form</field>
<field name="model">crm.claim</field>
<field name="inherit_id" ref="crm_claim_rma.crm_claim_rma_form_view"/>
<field name="arch" type="xml">
<xpath expr="//button[@string='New Delivery']" position="after">
<button name="%(action_claim_picking_loss)d"
string="New Product Loss"
type="action" target="new"
context="{'warehouse_id': warehouse_id,
'partner_id': partner_id}"/>
</xpath>
</field>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="rma_product_product_tree_view" model="ir.ui.view">
<field name="name">product.stock.tree.inherit</field>
<field name="model">product.product</field>
<field name="arch" type="xml">
<tree string="Product Variants" create="false">
<field name="default_code"/>
<field name="name"/>
<field name="attribute_value_ids" widget="many2many_tags"/>
<field name="rma_qty_available"/>
<field name="rma_virtual_available"/>
</tree>
</field>
</record>
<record id="rma_product_search_view" model="ir.ui.view">
<field name="name">product.product.search</field>
<field name="model">product.product</field>
<field name="arch" type="xml">
<search string="RMA Products">
<separator/>
<filter name="rma_available" string="RMA Available Products"
domain="['|', ('rma_qty_available','&gt;',0), ('rma_virtual_available','&gt;',0)]"/>
</search>
</field>
</record>
<record id="rma_product_variant_action" model="ir.actions.act_window">
<field name="name">RMA Stock</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">product.product</field>
<field name="view_mode">tree</field>
<field name="view_type">form</field>
<field name="view_id" ref="rma_product_product_tree_view"/>
<field name="search_view_id" ref="rma_product_search_view"/>
<field name="context">{'search_default_rma_available': 1}</field>
</record>
<menuitem action="rma_product_variant_action"
id="menu_stock_rma" parent="base.menu_aftersale"
name="RMA Stock"
sequence="100"/>
</data>
</openerp>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_template_property_form" model="ir.ui.view">
<field name="name">product.normal.procurement.locations.inherit</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="stock.view_template_property_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='virtual_available']" position="after">
<field name="rma_qty_available"/>
<field name="rma_virtual_available"/>
</xpath>
</field>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- INHERITED VIEW FOR THE OBJECT : stock_picking -->
<record id="picking_in_form" model="ir.ui.view">
<field name="name">crm_claim_rma.picking_in_form</field>
<field name="model">stock.picking</field>
<field name="inherit_id" ref="stock.view_picking_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='state']" position="before">
<button name="%(action_stock_picking_from_claim_picking)d"
string="Product to stock" type="action"
attrs="{'invisible':['|',
('state','&lt;&gt;','done'),
('claim_id', '=', False)]}"/>
<button name="%(action_loss_picking_from_claim_picking)d"
string="Product to Loss" type="action"
attrs="{'invisible':['|',
('state','&lt;&gt;','done'),
('claim_id', '=', False)]}"/>
<button name="%(action_used_picking_from_claim_picking)d"
string="Product to refurbish stock" type="action"
attrs="{'invisible':['|',
('state','&lt;&gt;','done'),
('claim_id', '=', False)]}"/>
</xpath>
</field>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<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="crm_rma_location.view_warehouse_form" />
<field name="arch" type="xml">
<xpath expr="//field[@name='lot_rma_id']" position="after">
<field name="loss_loc_id"/>
<field name="lot_refurbish_id"/>
</xpath>
</field>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright 2013 Camptocamp
# Copyright 2009-2013 Akretion,
# Author: Emmanuel Samyn, Raphaël Valyi, Sébastien Beau,
# Joel Grand-Guillaume
#
# 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 claim_make_picking_from_picking
from . import claim_make_picking

View File

@@ -0,0 +1,63 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright 2015 Vauxoo
# Copyright (C) 2009-2012 Akretion
# Author: Emmanuel Samyn, Benoît GUILLOT <benoit.guillot@akretion.com>,
# Osval Reyes
#
# 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 import models, fields
class ClaimMakePicking(models.TransientModel):
_inherit = 'claim_make_picking.wizard'
_description = 'Wizard to create pickings from claim lines'
def _default_claim_line_dest_location_id(self):
"""Return the location_id to use as destination.
If it's an outgoing shipment: take the customer stock property
If it's an incoming shipment take the location_dest_id common to all
lines, or if different, return None.
"""
picking_type = self.env.context.get('picking_type')
claim_id = self.env.context.get('active_id')
claim_record = self.env['crm.claim'].browse(claim_id)
if isinstance(picking_type, int):
picking_obj = self.env['stock.picking.type']
return picking_obj.browse(picking_type)\
.default_location_dest_id
if picking_type == 'out':
return claim_record.warehouse_id.rma_out_type_id.\
default_location_dest_id
elif picking_type == 'in':
return claim_record.warehouse_id.rma_in_type_id.\
default_location_dest_id
elif picking_type == 'int':
return claim_record.warehouse_id.rma_int_type_id.\
default_location_dest_id
elif picking_type == 'loss':
return claim_record.warehouse_id.loss_loc_id
return self.env['stock.location']
claim_line_dest_location_id = fields.Many2one(
default=_default_claim_line_dest_location_id)

View File

@@ -0,0 +1,178 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright 2015 Vauxoo
# Copyright (C) 2009-2012 Akretion
# Author: Emmanuel Samyn, Benoît GUILLOT <benoit.guillot@akretion.com>,
# Osval Reyes
#
# 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 import _, models, fields, api
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
from openerp import workflow
import time
class ClaimMakePickingFromPicking(models.TransientModel):
_name = 'claim.make.picking.from.picking.wizard'
_description = 'Wizard to create pickings from picking lines'
@api.model
def _get_default_warehouse(self):
warehouse_id = self.env['crm.claim']._get_default_warehouse()
return warehouse_id
@api.model
def _get_picking_lines(self):
move_lines = self.env['stock.picking'].\
browse(self.env.context.get('active_id')).move_lines
return [mov.id for mov in move_lines]
@api.model
def _get_source_loc(self):
"""
Get default source location
"""
warehouse_id = self._get_default_warehouse()
picking_obj = self.env['stock.picking']
picking_id = self.env.context.get('active_id')
picking_rec = picking_obj.browse(picking_id)
if picking_rec.location_dest_id:
return picking_rec.location_dest_id.id
else:
return warehouse_id.lot_rma_id.id
@api.model
def _get_dest_loc(self):
"""
Get default destination location
"""
warehouse_id = self._get_default_warehouse()
loc_id = self.env['stock.location']
picking_type = self.env.context.get('picking_type')
picking_type_obj = self.env['stock.picking.type']
if isinstance(picking_type, int):
pick_t = picking_type_obj.browse(picking_type)
loc_id = pick_t.default_location_dest_id
else:
if picking_type == 'picking_stock':
loc_id = warehouse_id.lot_stock_id.id
if picking_type == 'picking_loss':
loc_id = warehouse_id.loss_loc_id.id
if picking_type == 'picking_refurbish':
loc_id = warehouse_id.lot_refurbish_id.id
return loc_id
picking_line_source_location = fields.Many2one(
'stock.location', _('Source Location'),
help=_("Source location where the returned products are"),
required=True, default=_get_source_loc)
picking_line_dest_location = fields.Many2one(
'stock.location', _('Dest. Location'),
help=_("Target location to send returned products"),
required=True, default=_get_dest_loc)
picking_line_ids = fields.Many2many(
'stock.move', 'claim_picking_line_picking', 'claim_picking_id',
'picking_line_id', 'Picking lines', default=_get_picking_lines)
@api.multi
def action_cancel(self):
return {'type': 'ir.actions.act_window_close'}
@api.multi
def action_create_picking_from_picking(self):
"""
If "Create" button pressed
"""
picking_obj = self.env['stock.picking']
move_obj = self.env['stock.move']
view_obj = self.env['ir.ui.view']
if self.env.context.get('picking_type'):
context_type = self.env.context.get('picking_type')[8:]
note = 'Internal picking from RMA to %s' % context_type
name = 'Internal picking to %s' % context_type
view_id = view_obj.search([
('model', '=', 'stock.picking'),
('type', '=', 'form'),
('name', '=', 'stock.picking.form')
])[0]
prev_picking = picking_obj.browse(self.env.context.get('active_id'))
partner_id = prev_picking.partner_id.id
# create picking
picking_id = picking_obj.create({
'origin': prev_picking.origin,
'move_type': 'one',
'state': 'draft',
'date': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
'partner_id': prev_picking.partner_id.id,
'invoice_state': "none",
'company_id': prev_picking.company_id.id,
'location_id': self.picking_line_source_location.id,
'location_dest_id': self.picking_line_dest_location.id,
'note': note,
'claim_id': prev_picking.claim_id.id,
'picking_type_id': prev_picking.claim_id.warehouse_id.id,
})
# Create picking lines
for wizard_picking_line in self.picking_line_ids:
move_id = move_obj.create({
'name': wizard_picking_line.product_id.name_template,
'priority': '0',
'date': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
'date_expected': time.strftime(
DEFAULT_SERVER_DATETIME_FORMAT),
'product_id': wizard_picking_line.product_id.id,
'product_uom_qty': wizard_picking_line.product_uom_qty,
'product_uom': wizard_picking_line.product_uom.id,
'partner_id': prev_picking.partner_id.id,
'picking_id': picking_id.id,
'state': 'draft',
'price_unit': wizard_picking_line.price_unit,
'company_id': prev_picking.company_id.id,
'location_id': self.picking_line_source_location.id,
'location_dest_id': self.picking_line_dest_location.id,
'note': note,
'invoice_state': 'none',
})
wizard_picking_line.write(
{'move_dest_id': move_id.id})
wf_service = workflow
if picking_id:
wf_service.trg_validate(
self._uid, 'stock.picking',
picking_id.id,
'button_confirm',
self._cr)
picking_id.action_assign()
domain = "[('picking_type_id','=','%s'),('partner_id','=',%s)]" % (
prev_picking.claim_id.warehouse_id.rma_int_type_id.id, partner_id)
return {
'name': '%s' % name,
'view_type': 'form',
'view_mode': 'form',
'view_id': view_id.id,
'domain': domain,
'res_model': 'stock.picking',
'res_id': picking_id.id,
'type': 'ir.actions.act_window',
}

View File

@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
crm_claim_rma for OpenERP
Copyright (C) 2011 Akretion Benoît GUILLOT <benoit.guillot@akretion.com>
The licence is in the file __openerp__.py
-->
<openerp>
<data>
<record id="view_claim_picking_from_picking" model="ir.ui.view">
<field name="name">claim_picking</field>
<field name="model">claim.make.picking.from.picking.wizard</field>
<field name="arch" type="xml">
<form string="Select lines to add in picking">
<separator string="Locations" colspan="4"/>
<field name="picking_line_source_location" nolabel="1" />
<field name="picking_line_dest_location" nolabel="1" />
<separator string="Select lines for picking" colspan="4"/>
<field name="picking_line_ids" nolabel="1" colspan="4"/>
<group col="4" colspan="2">
<button special="cancel" string="Cancel"
name="action_cancel" type="object"
icon='gtk-cancel'/>
<button name="action_create_picking_from_picking"
string="Create picking"
icon='gtk-ok' type="object"/>
</group>
</form>
</field>
</record>
<record id="action_stock_picking_from_claim_picking"
model="ir.actions.act_window">
<field name="name">Create Incoming Shipment to Stock</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">claim.make.picking.from.picking.wizard</field>
<field name="src_model">stock.picking</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="context">{'picking_type': 'picking_stock'}</field>
</record>
<record id="action_loss_picking_from_claim_picking"
model="ir.actions.act_window">
<field name="name">Create Incoming Shipment to Breakage Loss Location</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">claim.make.picking.from.picking.wizard</field>
<field name="src_model">stock.picking</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="context">{'picking_type': 'picking_loss'}
</field>
</record>
<record id="action_used_picking_from_claim_picking"
model="ir.actions.act_window">
<field name="name">Create Incoming Shipment to Refurbish Location</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">claim.make.picking.from.picking.wizard</field>
<field name="src_model">stock.picking</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="context">{'picking_type': 'picking_refurbish'}</field>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
crm_claim_rma for OpenERP
Copyright (C) 2011 Akretion Benoît GUILLOT <benoit.guillot@akretion.com>
The licence is in the file __openerp__.py
-->
<openerp>
<data>
<record id="action_claim_picking_loss" model="ir.actions.act_window">
<field name="name">Create a Product Loss</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">claim_make_picking.wizard</field>
<field name="src_model">crm.claim</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="context">{'picking_type': 'loss'}</field>
</record>
</data>
</openerp>