Merge pull request #45 from vauxoo-dev/8.0-squash_crm_rma_lot_mass_return_oca_vauxoo

[WIP] new module crm_rma_lot_mass_return that adds possibility to ret…
This commit is contained in:
Nhomar Hernández [Vauxoo]
2015-11-19 17:14:24 -05:00
27 changed files with 2263 additions and 413 deletions

View File

@@ -0,0 +1,86 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:alt: License: AGPL-3
============================
RMA Claim Mass Return by Lot
============================
This module adds possibility to return a whole lot of product from an invoice
and create a incoming shipment for them based on serial/lot for a product or
invoice number.
Installation
============
To install this module, just select it from availables modules
Configuration
=============
No configuration is need for this module
Usage
=====
To use this module, you need to:
* Go into Sales > After-Sale services > Claims
* A button named "Mass return from serial/lot or invoice" will appear in the
form view when creating or editing an existing claim.
* Enter into the wizard and introduce serial/lot for an invoiced product or
invoice number and press enter.
* A list of selectable items it will show below or next to the input box
depending upon is introduced either invoice number or serial/lot number
respectively. When finish adding, click on Validate button and then Ok
to exit of wizard and continue editing the claim.
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/145/8.0
For further information, please visit:
* https://www.odoo.com/forum/help-1
Known issues / Roadmap
======================
* No issues are registered
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_lot_mass_return%0Aversion:%208.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Credits
=======
Contributors
------------
* 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,9 +1,11 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright 2015 Vauxoo
# Copyright 2013 Camptocamp
# Copyright 2009-2013 Akretion,
# Author: Emmanuel Samyn, Raphaël Valyi, Sébastien Beau, Joel Grand-Guillaume
# 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
@@ -19,4 +21,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from . import wizard
from . import models
from . import wizards

View File

@@ -1,9 +1,12 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright 2015 Vauxoo
# Copyright 2013 Camptocamp
# Copyright 2009-2013 Akretion,
# Author: Emmanuel Samyn, Raphaël Valyi, Sébastien Beau, Joel Grand-Guillaume
# Copyright 2009-2013 Akretion,
# Author: 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
@@ -20,31 +23,29 @@
#
##############################################################################
{'name': 'RMA Claims Mass Return by Lot',
'version': '1.0',
'category': 'Generic Modules/CRM & SRM',
'depends': ['crm_claim_rma'
],
'author': "Akretion,Odoo Community Association (OCA)",
'license': 'AGPL-3',
'website': 'http://www.akretion.com',
'description': """
RMA Claim Mass Return by Lot
============================
This module adds possibility to return a whole lot of product from a Claim
and create a incoming shipment for them.
WARNING: This module is currently not yet completely debugged and is waiting his author to be.
""",
'images': [],
'demo': [],
'data': [
'wizard/returned_lines_from_serial_wizard_view.xml',
'crm_rma_view.xml',
],
'installable': False,
'application': True,
{
'name': 'RMA Claims Mass Return by Lot',
'version': '8.0.1.0.0',
'category': 'Generic Modules/CRM & SRM',
'author': 'Vauxoo,Akretion,Odoo Community Association (OCA)',
'license': 'AGPL-3',
'website': 'http://www.vauxoo.com, http://www.akretion.com',
'depends': [
'crm_claim_rma',
'crm_rma_prodlot_invoice',
'crm_rma_prodlot_supplier',
],
'data': [
'wizards/returned_lines_from_serial_wizard.xml',
'views/crm_claim.xml',
'templates/search_view.xml'
],
'demo': [
'demo/stock_production_lot.xml',
'demo/purchase_order.xml',
'demo/sale_order.xml',
'demo/transfer_details.xml',
],
'installable': True,
'auto_install': False
}

View File

@@ -1,16 +0,0 @@
<?xml version="1.0"?>
<openerp>
<data>
<record model="ir.ui.view" id="crm_claim_rma_form_view">
<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="//page[@string='Product Return']/group/group[2]" position="inside">
<button name="%(action_create_return_serial)d" string="Mass return from serial/lot" states="draft,open" type="action" target="new"/>
</xpath>
</field>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,69 @@
<?xml version="1.0"?>
<openerp>
<data noupdate="1">
<!-- Purchase Order -->
<record id="po_wizard_rma_1" model="purchase.order">
<field name="name">POWIZARDCLAIM001</field>
<field name="date_order">2015-05-08 18:17:05</field>
<field name="invoice_method">order</field>
<field name="partner_id" ref="base.res_partner_21"/>
<field name="currency_id" ref="base.EUR"/>
<field name="pricelist_id" ref="purchase.list0"/>
<field name="location_id" ref="stock.stock_location_stock"/>
</record>
<!-- Purchase Order Lines-->
<record id="po_wizard_rma_1_line_1" model="purchase.order.line">
<field name="name">POWIZARDCLAIM001 Line 1</field>
<field name="order_id" ref="po_wizard_rma_1"/>
<field name="product_id" ref="product.product_product_38"/>
<field name="product_qty">10</field>
<field name="price_unit">60.0</field>
<field name="date_planned">2015-05-08</field>
</record>
<record id="po_wizard_rma_1_line_2" model="purchase.order.line">
<field name="name">POWIZARDCLAIM001 Line 2</field>
<field name="order_id" ref="po_wizard_rma_1"/>
<field name="product_id" ref="product.product_product_39"/>
<field name="product_qty">10</field>
<field name="price_unit">66.0</field>
<field name="date_planned">2015-05-08</field>
</record>
<record id="po_wizard_rma_1_line_3" model="purchase.order.line">
<field name="name">POWIZARDCLAIM001 Line 3</field>
<field name="order_id" ref="po_wizard_rma_1"/>
<field name="product_id" ref="product.product_product_6"/>
<field name="product_qty">10</field>
<field name="price_unit">800.0</field>
<field name="date_planned">2015-05-08</field>
</record>
<record id="po_wizard_rma_1_line_4" model="purchase.order.line">
<field name="name">POWIZARDCLAIM001 Line 4</field>
<field name="order_id" ref="po_wizard_rma_1"/>
<field name="product_id" ref="product.product_product_8"/>
<field name="product_qty">7</field>
<field name="price_unit">1299.0</field>
<field name="date_planned">2015-05-08</field>
</record>
<!-- Confirm Purchase Order, (Invoice and Picking is created automatically) -->
<workflow action="purchase_confirm"
model="purchase.order"
ref="po_wizard_rma_1"/>
<workflow action="purchase_approve"
model="purchase.order"
ref="po_wizard_rma_1"/>
<workflow action="invoice_open" model="account.invoice">
<value eval="obj(ref('po_wizard_rma_1')).invoice_ids[0].id" model="purchase.order"/>
</workflow>
</data>
</openerp>

View File

@@ -0,0 +1,67 @@
<?xml version="1.0"?>
<openerp>
<data noupdate="1">
<record id="so_wizard_rma_1" model="sale.order">
<field name="name">SOWIZARDCLAIM001</field>
<field name="date_order">2015-05-08 18:17:05</field>
<field name="partner_id" ref="base.res_partner_12"/>
<field name="currency_id" ref="base.EUR"/>
<field name="pricelist_id" ref="product.list0"/>
</record>
<record id="so_wizard_rma_1_line_1" model="sale.order.line">
<field name="name">SOWIZARDCLAIM001 Line 1</field>
<field name="order_id" ref="so_wizard_rma_1"/>
<field name="product_id" ref="product.product_product_38"/>
<field name="product_uom_qty">1</field>
<field name="price_unit">65.0</field>
</record>
<record id="so_wizard_rma_1_line_2" model="sale.order.line">
<field name="name">SOWIZARDCLAIM001 Line 2</field>
<field name="order_id" ref="so_wizard_rma_1"/>
<field name="product_id" ref="product.product_product_39"/>
<field name="product_uom_qty">2</field>
<field name="price_unit">66.0</field>
</record>
<record id="so_wizard_rma_1_line_3" model="sale.order.line">
<field name="name">SOWIZARDCLAIM001 Line 3</field>
<field name="order_id" ref="so_wizard_rma_1"/>
<field name="product_id" ref="product.product_product_6"/>
<field name="product_uom_qty">1</field>
<field name="price_unit">800.0</field>
</record>
<record id="so_wizard_rma_1_line_4" model="sale.order.line">
<field name="name">SOWIZARDCLAIM001 Line 4</field>
<field name="order_id" ref="so_wizard_rma_1"/>
<field name="product_id" ref="product.product_product_8"/>
<field name="product_uom_qty">5</field>
<field name="price_unit">1299.0</field>
</record>
<workflow action="order_confirm" model="sale.order" ref="so_wizard_rma_1"/>
<workflow action="manual_invoice" model="sale.order" ref="so_wizard_rma_1" uid="base.user_root"/>
<workflow action="invoice_open" model="account.invoice">
<value eval="obj(ref('so_wizard_rma_1')).invoice_ids[0].id" model="sale.order"/>
</workflow>
<function model="account.invoice" name="pay_and_reconcile">
<!-- ids = --> <value eval="obj(ref('so_wizard_rma_1')).invoice_ids[0].id" model="sale.order"/>
<!-- amount = --> <value eval="30000"/>
<!-- account_id = --> <value eval="ref('account.cash')"/>
<!-- period_id = --> <value eval="ref('account.period_10')"/>
<!-- journal_id = --> <value eval="ref('account.bank_journal')"/>
<!-- writeoff_acc_id = --> <value eval="ref('account.cash')"/>
<!-- writeoff_period_id = --> <value eval="ref('account.period_10')"/>
<!-- writeoff_journal_id = --> <value eval="ref('account.bank_journal')"/>
<!-- context = --> <value eval="{}"/>
<!-- name = --> <value eval="str('Payment WIzard RMA')"/>
</function>
</data>
</openerp>

View File

@@ -0,0 +1,37 @@
<?xml version="1.0"?>
<openerp>
<data noupdate="1">
<record id="lot_purchase_wizard_rma_item_1" model="stock.production.lot">
<field name="name">MAC0001</field>
<field name="ref">MAC0001</field>
<field name="product_id" ref="product.product_product_8"/>
</record>
<record id="lot_purchase_wizard_rma_item_2" model="stock.production.lot">
<field name="name">MAC0002</field>
<field name="ref">MAC0002</field>
<field name="product_id" ref="product.product_product_8"/>
</record>
<record id="lot_purchase_wizard_rma_item_3" model="stock.production.lot">
<field name="name">MAC0003</field>
<field name="ref">MAC0003</field>
<field name="product_id" ref="product.product_product_8"/>
</record>
<record id="lot_purchase_wizard_rma_item_4" model="stock.production.lot">
<field name="name">MAC0004</field>
<field name="ref">MAC0004</field>
<field name="product_id" ref="product.product_product_8"/>
</record>
<record id="lot_purchase_wizard_rma_item_5" model="stock.production.lot">
<field name="name">IPAD0001</field>
<field name="ref">IPAD0001</field>
<field name="product_id" ref="product.product_product_6"/>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,196 @@
<?xml version="1.0"?>
<openerp>
<data noupdate="1">
<!--Transfer of Products in the Picking of Purchase Order -->
<record id="transfer_purchase_wizard_rma" model="stock.transfer_details">
<field name="picking_id" model="stock.picking" search="[('origin', '=', 'POWIZARDCLAIM001')]"/>
<field name="picking_source_location_id" ref="stock.stock_location_suppliers"/>
<field name="picking_destination_location_id" ref="stock.stock_location_stock"/>
</record>
<!-- Transfer Detail Items of Product Transfer -->
<record id="transfer_purchase_wizard_rma_item_1" model="stock.transfer_details_items">
<field name="transfer_id" ref="transfer_purchase_wizard_rma"/>
<field name="product_id" ref="product.product_product_8"/>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="quantity">1</field>
<field name="sourceloc_id" ref="stock.stock_location_suppliers"/>
<field name="destinationloc_id" ref="stock.stock_location_stock"/>
<field name="lot_id" ref="lot_purchase_wizard_rma_item_1"/>
</record>
<record id="transfer_purchase_wizard_rma_item_2" model="stock.transfer_details_items">
<field name="transfer_id" ref="transfer_purchase_wizard_rma"/>
<field name="product_id" ref="product.product_product_8"/>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="quantity">1</field>
<field name="sourceloc_id" ref="stock.stock_location_suppliers"/>
<field name="destinationloc_id" ref="stock.stock_location_stock"/>
<field name="lot_id" ref="lot_purchase_wizard_rma_item_2"/>
</record>
<record id="transfer_purchase_wizard_rma_item_3" model="stock.transfer_details_items">
<field name="transfer_id" ref="transfer_purchase_wizard_rma"/>
<field name="product_id" ref="product.product_product_8"/>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="quantity">1</field>
<field name="sourceloc_id" ref="stock.stock_location_suppliers"/>
<field name="destinationloc_id" ref="stock.stock_location_stock"/>
<field name="lot_id" ref="lot_purchase_wizard_rma_item_3"/>
</record>
<record id="transfer_purchase_wizard_rma_item_4" model="stock.transfer_details_items">
<field name="transfer_id" ref="transfer_purchase_wizard_rma"/>
<field name="product_id" ref="product.product_product_8"/>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="quantity">1</field>
<field name="sourceloc_id" ref="stock.stock_location_suppliers"/>
<field name="destinationloc_id" ref="stock.stock_location_stock"/>
<field name="lot_id" ref="lot_purchase_wizard_rma_item_4"/>
</record>
<record id="transfer_purchase_wizard_rma_item_5" model="stock.transfer_details_items">
<field name="transfer_id" ref="transfer_purchase_wizard_rma"/>
<field name="product_id" ref="product.product_product_6"/>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="quantity">1</field>
<field name="sourceloc_id" ref="stock.stock_location_suppliers"/>
<field name="destinationloc_id" ref="stock.stock_location_stock"/>
<field name="lot_id" ref="lot_purchase_wizard_rma_item_5"/>
</record>
<!-- two MAC without lot -->
<record id="transfer_purchase_wizard_rma_item_6" model="stock.transfer_details_items">
<field name="transfer_id" ref="transfer_purchase_wizard_rma"/>
<field name="product_id" ref="product.product_product_8"/>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="quantity">2</field>
<field name="sourceloc_id" ref="stock.stock_location_suppliers"/>
<field name="destinationloc_id" ref="stock.stock_location_stock"/>
</record>
<record id="transfer_purchase_wizard_rma_item_7" model="stock.transfer_details_items">
<field name="transfer_id" ref="transfer_purchase_wizard_rma"/>
<field name="product_id" ref="product.product_product_39"/>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="quantity">1</field>
<field name="sourceloc_id" ref="stock.stock_location_suppliers"/>
<field name="destinationloc_id" ref="stock.stock_location_stock"/>
</record>
<record id="transfer_purchase_wizard_rma_item_8" model="stock.transfer_details_items">
<field name="transfer_id" ref="transfer_purchase_wizard_rma"/>
<field name="product_id" ref="product.product_product_39"/>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="quantity">1</field>
<field name="sourceloc_id" ref="stock.stock_location_suppliers"/>
<field name="destinationloc_id" ref="stock.stock_location_stock"/>
</record>
<record id="transfer_purchase_wizard_rma_item_9" model="stock.transfer_details_items">
<field name="transfer_id" ref="transfer_purchase_wizard_rma"/>
<field name="product_id" ref="product.product_product_38"/>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="quantity">1</field>
<field name="sourceloc_id" ref="stock.stock_location_suppliers"/>
<field name="destinationloc_id" ref="stock.stock_location_stock"/>
</record>
<!-- Make transfer of product -->
<function model="stock.transfer_details"
name="do_detailed_transfer" eval="[ref('transfer_purchase_wizard_rma')]"/>
<!-- Transfer of Products in the Picking of Purchase Order 2 -->
<record id="transfer_sale_wizard_rma" model="stock.transfer_details">
<field name="picking_id" model="stock.picking" search="[('origin', '=', 'SOWIZARDCLAIM001')]"/>
<field name="picking_source_location_id" ref="stock.stock_location_stock"/>
<field name="picking_destination_location_id" ref="stock.stock_location_customers"/>
</record>
<!-- Transfer Detail Items Part 2 of Product Transfer -->
<record id="transfer_sale_wizard_rma_item_1" model="stock.transfer_details_items">
<field name="transfer_id" ref="transfer_sale_wizard_rma"/>
<field name="product_id" ref="product.product_product_38"/>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="quantity">1</field>
<field name="sourceloc_id" ref="stock.stock_location_stock"/>
<field name="destinationloc_id" ref="stock.stock_location_customers"/>
</record>
<record id="transfer_sale_wizard_rma_item_2" model="stock.transfer_details_items">
<field name="transfer_id" ref="transfer_sale_wizard_rma"/>
<field name="product_id" ref="product.product_product_39"/>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="quantity">2</field>
<field name="sourceloc_id" ref="stock.stock_location_stock"/>
<field name="destinationloc_id" ref="stock.stock_location_customers"/>
</record>
<record id="transfer_sale_wizard_rma_item_3" model="stock.transfer_details_items">
<field name="transfer_id" ref="transfer_sale_wizard_rma"/>
<field name="product_id" ref="product.product_product_6"/>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="quantity">1</field>
<field name="sourceloc_id" ref="stock.stock_location_stock"/>
<field name="destinationloc_id" ref="stock.stock_location_customers"/>
<field name="lot_id" ref="lot_purchase_wizard_rma_item_5"/>
</record>
<record id="transfer_sale_wizard_rma_item_4" model="stock.transfer_details_items">
<field name="transfer_id" ref="transfer_sale_wizard_rma"/>
<field name="product_id" ref="product.product_product_8"/>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="quantity">1</field>
<field name="sourceloc_id" ref="stock.stock_location_stock"/>
<field name="destinationloc_id" ref="stock.stock_location_customers"/>
<field name="lot_id" ref="lot_purchase_wizard_rma_item_1"/>
</record>
<record id="transfer_sale_wizard_rma_item_5" model="stock.transfer_details_items">
<field name="transfer_id" ref="transfer_sale_wizard_rma"/>
<field name="product_id" ref="product.product_product_8"/>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="quantity">1</field>
<field name="sourceloc_id" ref="stock.stock_location_stock"/>
<field name="destinationloc_id" ref="stock.stock_location_customers"/>
<field name="lot_id" ref="lot_purchase_wizard_rma_item_2"/>
</record>
<record id="transfer_sale_wizard_rma_item_6" model="stock.transfer_details_items">
<field name="transfer_id" ref="transfer_sale_wizard_rma"/>
<field name="product_id" ref="product.product_product_8"/>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="quantity">1</field>
<field name="sourceloc_id" ref="stock.stock_location_stock"/>
<field name="destinationloc_id" ref="stock.stock_location_customers"/>
<field name="lot_id" ref="lot_purchase_wizard_rma_item_3"/>
</record>
<record id="transfer_sale_wizard_rma_item_7" model="stock.transfer_details_items">
<field name="transfer_id" ref="transfer_sale_wizard_rma"/>
<field name="product_id" ref="product.product_product_8"/>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="quantity">1</field>
<field name="sourceloc_id" ref="stock.stock_location_stock"/>
<field name="destinationloc_id" ref="stock.stock_location_customers"/>
<field name="lot_id" ref="lot_purchase_wizard_rma_item_4"/>
</record>
<!-- Make transfer of product -->
<function model="stock.transfer_details"
name="do_detailed_transfer" eval="[ref('transfer_sale_wizard_rma')]"/>
</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_lot_mass_return
#
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: 2013-11-15 13:30+0000\n"
"PO-Revision-Date: 2013-11-15 13:30+0000\n"
"POT-Creation-Date: 2015-10-16 03:32+0000\n"
"PO-Revision-Date: 2015-10-16 03:32+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
@@ -16,52 +16,160 @@ msgstr ""
"Plural-Forms: \n"
#. module: crm_rma_lot_mass_return
#: view:crm.claim:0
msgid "Mass return from serial/lot"
#. openerp-web
#: code:addons/crm_rma_lot_mass_return/static/src/js/barcode_text.js:90
#, python-format
msgid "-->"
msgstr ""
#. module: crm_rma_lot_mass_return
#: view:returned_lines_from_serial.wizard:0
msgid "Claim short description"
#: model:ir.model,name:crm_rma_lot_mass_return.model_crm_claim
msgid "Claim"
msgstr ""
#. module: crm_rma_lot_mass_return
#: view:returned_lines_from_serial.wizard:0
msgid "Select serial numbers to create"
#: field:returned.lines.from.serial.wizard,create_uid:0
msgid "Created by"
msgstr ""
#. module: crm_rma_lot_mass_return
#: model:ir.actions.act_window,name:crm_rma_lot_mass_return.action_create_return_serial
msgid "action_create_return_serial"
#: field:returned.lines.from.serial.wizard,create_date:0
msgid "Created on"
msgstr ""
#. module: crm_rma_lot_mass_return
#: help:returned.lines.from.serial.wizard,scan_data:0
msgid "Field used to load and show the products"
msgstr ""
#. module: crm_rma_lot_mass_return
#: help:returned.lines.from.serial.wizard,lines_id:0
msgid "Field used to load the ids of invoice lines in invoices writed"
msgstr ""
#. module: crm_rma_lot_mass_return
#: help:returned.lines.from.serial.wizard,scaned_data:0
msgid "Field used to load the ids of products loaded"
msgstr ""
#. module: crm_rma_lot_mass_return
#: help:returned.lines.from.serial.wizard,lines_list_id:0
msgid "Field used to show the current status of the lots loaded"
msgstr ""
#. module: crm_rma_lot_mass_return
#: help:returned.lines.from.serial.wizard,current_status:0
msgid "Field used to show the current status of the product loaded(Name and quantity)"
msgstr ""
#. module: crm_rma_lot_mass_return
#: field:returned.lines.from.serial.wizard,id:0
msgid "ID"
msgstr ""
#. module: crm_rma_lot_mass_return
#: field:returned.lines.from.serial.wizard,lines_id:0
msgid "Invoice Lines to Select"
msgstr ""
#. module: crm_rma_lot_mass_return
#: field:returned.lines.from.serial.wizard,write_uid:0
msgid "Last Updated by"
msgstr ""
#. module: crm_rma_lot_mass_return
#: field:returned.lines.from.serial.wizard,write_date:0
msgid "Last Updated on"
msgstr ""
#. module: crm_rma_lot_mass_return
#: field:returned.lines.from.serial.wizard,lines_list_id:0
msgid "Lots selected"
msgstr ""
#. module: crm_rma_lot_mass_return
#: view:crm.claim:crm_rma_lot_mass_return.crm_claim_rma_form_view_meta
msgid "Mass return from serial/lot or invoice"
msgstr ""
#. module: crm_rma_lot_mass_return
#. openerp-web
#: code:addons/crm_rma_lot_mass_return/static/src/js/barcode_text.js:93
#, python-format
msgid "Ok"
msgstr ""
#. module: crm_rma_lot_mass_return
#: field:returned.lines.from.serial.wizard,partner_id:0
msgid "Partner"
msgstr ""
#. module: crm_rma_lot_mass_return
#: field:returned.lines.from.serial.wizard,scan_data:0
#: field:returned.lines.from.serial.wizard,scaned_data:0
msgid "Products"
msgstr ""
#. module: crm_rma_lot_mass_return
#: code:addons/crm_rma_lot_mass_return/wizards/returned_lines_from_serial.py:141
#, python-format
msgid "Search Product"
msgstr ""
#. module: crm_rma_lot_mass_return
#: field:returned.lines.from.serial.wizard,current_status:0
msgid "Status"
msgstr ""
#. module: crm_rma_lot_mass_return
#: code:addons/crm_rma_lot_mass_return/wizards/returned_lines_from_serial.py:299
#, python-format
msgid "The following Serial/Lot numbers were not added, because all of them (listed below) are currently in use:\n"
msgstr ""
#. module: crm_rma_lot_mass_return
#: code:addons/crm_rma_lot_mass_return/wizards/returned_lines_from_serial.py:221
#, python-format
msgid "The product or invoice %s was not found"
msgstr ""
#. module: crm_rma_lot_mass_return
#: view:crm.claim:crm_rma_lot_mass_return.crm_claim_rma_form_view_meta
msgid "True"
msgstr ""
#. module: crm_rma_lot_mass_return
#: view:returned.lines.from.serial.wizard:crm_rma_lot_mass_return.view_enter_product
msgid "Validate the actual picking, it will execute all the validations and the inventory will be affected"
msgstr ""
#. module: crm_rma_lot_mass_return
#: model:ir.model,name:crm_rma_lot_mass_return.model_returned_lines_from_serial_wizard
msgid "Wizard to create product return lines from serial numbers"
msgid "Wizard to create product return lines"
msgstr ""
#. module: crm_rma_lot_mass_return
#: view:returned_lines_from_serial.wizard:0
msgid "Quantity returned"
#: view:returned.lines.from.serial.wizard:crm_rma_lot_mass_return.view_enter_product
msgid "Write the Invoice Number to search the products in lines"
msgstr ""
#. module: crm_rma_lot_mass_return
#: view:returned_lines_from_serial.wizard:0
msgid "Save and close"
#: view:returned.lines.from.serial.wizard:crm_rma_lot_mass_return.view_enter_product
msgid "Write the Serial/Lot Number to search the product"
msgstr ""
#. module: crm_rma_lot_mass_return
#: view:returned_lines_from_serial.wizard:0
msgid "Save and new"
#: view:returned.lines.from.serial.wizard:crm_rma_lot_mass_return.view_enter_product
msgid "You add new returns in claim, are you sure?."
msgstr ""
#. module: crm_rma_lot_mass_return
#: view:returned_lines_from_serial.wizard:0
msgid "Cancel"
#: view:returned.lines.from.serial.wizard:crm_rma_lot_mass_return.view_enter_product
msgid "You should use this windows on this way."
msgstr ""
#. module: crm_rma_lot_mass_return
#: view:returned_lines_from_serial.wizard:0
msgid "Serial / Lot Number"
#: view:returned.lines.from.serial.wizard:crm_rma_lot_mass_return.view_enter_product
msgid "_Validate"
msgstr ""

View File

@@ -0,0 +1,181 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * crm_rma_lot_mass_return
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-07-21 01:59+0000\n"
"PO-Revision-Date: 2015-07-21 01:59+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_lot_mass_return
#. openerp-web
#: code:addons/crm_rma_lot_mass_return/static/src/js/barcode_text.js:89
#, python-format
msgid "-->"
msgstr "-->"
#. module: crm_rma_lot_mass_return
#: model:ir.model,name:crm_rma_lot_mass_return.model_crm_claim
msgid "Claim"
msgstr "Reclamo"
#. module: crm_rma_lot_mass_return
#: field:returned.lines.from.serial.wizard,create_uid:0
msgid "Created by"
msgstr "Creado por"
#. module: crm_rma_lot_mass_return
#: field:returned.lines.from.serial.wizard,create_date:0
msgid "Created on"
msgstr "Creado en"
#. module: crm_rma_lot_mass_return
#: code:addons/crm_rma_lot_mass_return/wizards/returned_lines_from_serial.py:111
#, python-format
msgid "Error!"
msgstr "Error!"
#. module: crm_rma_lot_mass_return
#: help:returned.lines.from.serial.wizard,scan_data:0
msgid "Field used to load and show the products"
msgstr "Campo usado para cargar y ver los productos"
#. module: crm_rma_lot_mass_return
#: help:returned.lines.from.serial.wizard,lines_id:0
msgid "Field used to load the ids of invoice lines in invoices writed"
msgstr "Campo usado para cargar los ids de las líneas de factura en facturas editadas"
#. module: crm_rma_lot_mass_return
#: help:returned.lines.from.serial.wizard,scaned_data:0
msgid "Field used to load the ids of products loaded"
msgstr "Campo usado para cargar los ids de los productos cargados"
#. module: crm_rma_lot_mass_return
#: help:returned.lines.from.serial.wizard,lines_list_id:0
msgid "Field used to show the current status of the invoice lines loaded"
msgstr "Campo usado para visualizar el estado actual de las línea de factura cargadas"
#. module: crm_rma_lot_mass_return
#: help:returned.lines.from.serial.wizard,current_status:0
msgid "Field used to show the current status of the product loaded(Name and quantity)"
msgstr "Campo usado para visualizar el estado actual de los productos cargados (Nombre y cantidad)"
#. module: crm_rma_lot_mass_return
#: field:returned.lines.from.serial.wizard,id:0
msgid "ID"
msgstr "ID"
#. module: crm_rma_lot_mass_return
#: field:returned.lines.from.serial.wizard,lines_list_id:0
msgid "Invoice Lines selected"
msgstr "Líneas de factura seleccionadas"
#. module: crm_rma_lot_mass_return
#: field:returned.lines.from.serial.wizard,lines_id:0
msgid "Invoice Lines to Select"
msgstr "Líneas de factura a seleccionar"
#. module: crm_rma_lot_mass_return
#: field:returned.lines.from.serial.wizard,write_uid:0
msgid "Last Updated by"
msgstr "Última actualización hecha por"
#. module: crm_rma_lot_mass_return
#: field:returned.lines.from.serial.wizard,write_date:0
msgid "Last Updated on"
msgstr "Última actualización hecha en"
#. module: crm_rma_lot_mass_return
#: view:crm.claim:crm_rma_lot_mass_return.crm_claim_rma_form_view_meta
msgid "Add claim lines using serial or invoice number"
msgstr "Agregar devoluciones usando número de serial o de factura"
#. module: crm_rma_lot_mass_return
#. openerp-web
#: code:addons/crm_rma_lot_mass_return/static/src/js/barcode_text.js:90
#, python-format
msgid "Ok"
msgstr "Ok"
#. module: crm_rma_lot_mass_return
#: field:returned.lines.from.serial.wizard,partner_id:0
msgid "Partner"
msgstr "Socio"
#. module: crm_rma_lot_mass_return
#: field:returned.lines.from.serial.wizard,scan_data:0
#: field:returned.lines.from.serial.wizard,scaned_data:0
msgid "Products"
msgstr "Productos"
#. module: crm_rma_lot_mass_return
#: code:addons/crm_rma_lot_mass_return/wizard/returned_lines_from_serial.py:213
#, python-format
msgid "Search Product"
msgstr "Buscar producto"
#. module: crm_rma_lot_mass_return
#: field:returned.lines.from.serial.wizard,current_status:0
msgid "Status"
msgstr "Estado"
#. module: crm_rma_lot_mass_return
#: code:addons/crm_rma_lot_mass_return/wizard/returned_lines_from_serial.py:285
#, python-format
msgid "The product or invoice %s was not found"
msgstr "El producto o factura %s no fué encontrado"
#. module: crm_rma_lot_mass_return
#: code:addons/crm_rma_lot_mass_return/wizard/returned_lines_from_serial.py:112
#, python-format
msgid "There is no warehouse for the current user's company."
msgstr "No existe un almacén para la compañia del usuario actual"
#. module: crm_rma_lot_mass_return
#: view:returned.lines.from.serial.wizard:crm_rma_lot_mass_return.view_enter_product
msgid "Validate the actual picking, it will execute all the validations and the inventory will be affected"
msgstr "Validar el albarán actual, ejecutará todas las validaciones y el inventario será afectado."
#. module: crm_rma_lot_mass_return
#: model:ir.model,name:crm_rma_lot_mass_return.model_returned_lines_from_serial_wizard
msgid "Wizard to create product return lines from serial numbers"
msgstr "Wizard para crear líneas de devolución de productos usando el número de serie o lote"
#. module: crm_rma_lot_mass_return
#: view:returned.lines.from.serial.wizard:crm_rma_lot_mass_return.view_enter_product
msgid "Write the Invoice Number to search the products in lines"
msgstr "Escribir el número de factura para buscar los productos en las líneas"
#. module: crm_rma_lot_mass_return
#: view:returned.lines.from.serial.wizard:crm_rma_lot_mass_return.view_enter_product
msgid "Write the Serial/Lot Number to search the product"
msgstr "Escribir el número de serie o lote para buscar el producto."
#. module: crm_rma_lot_mass_return
#: view:returned.lines.from.serial.wizard:crm_rma_lot_mass_return.view_enter_product
msgid "You are about to add new lines to the claim, Do you want to continue?."
msgstr "Se agregarán nuevas líneas a la reclamación, ¿Desea continuar?"
#. module: crm_rma_lot_mass_return
#: view:returned.lines.from.serial.wizard:crm_rma_lot_mass_return.view_enter_product
msgid "You should use this windows on this way."
msgstr "Deberías usar ésta ventana"
#. module: crm_rma_lot_mass_return
#: view:returned.lines.from.serial.wizard:crm_rma_lot_mass_return.view_enter_product
msgid "Add items to the claim"
msgstr "Añadir productos a la reclamación"
#. module: crm_rma_lot_mass_return
#: code:addons/crm_rma_lot_mass_return/wizards/returned_lines_from_serial.py:585
#, python-format
msgid "The following Serial/Lot numbers won't be added, because all of them (listed below) are currently in use:\n\n %s"
msgstr "los siguientes números de seriales no pueden ser agregados, porque todos ellos (listados abajo) están actualmente en uso:\n\n %s"

View File

@@ -0,0 +1,16 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * crm_rma_lot_mass_return
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-07-17 19:54+0000\n"
"PO-Revision-Date: 2015-07-17 19:54+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_lot_mass_return
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-07-17 19:54+0000\n"
"PO-Revision-Date: 2015-07-17 19:54+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_lot_mass_return
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-07-17 19:54+0000\n"
"PO-Revision-Date: 2015-07-17 19:54+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,22 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright 2015 Vauxoo
# Author: Osval Reyes, Yanina Aular
#
# 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 crm_claim

View File

@@ -0,0 +1,58 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright 2015 Vauxoo
# Author: Osval Reyes, Yanina Aular
#
# 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, models
class CrmClaim(models.Model):
_inherit = 'crm.claim'
@api.model
def _get_stock_moves_with_code(self, code='incoming'):
"""
@code: Type of operation code.
Returns all stock_move with filtered by type of
operation.
"""
stockmove = self.env['stock.move']
receipts = self.env['stock.picking.type']
spt_receipts = receipts.search([('code',
'=',
code)])
spt_receipts = [spt.id for spt in spt_receipts]
sm_receipts = stockmove.search([('picking_type_id',
'in',
spt_receipts)])
return sm_receipts
@api.multi
def render_metasearch_view(self):
context = self._context.copy()
context.update({
'active_model': self._name,
'active_ids': self.ids,
'active_id': self.id or False,
})
wizard = self.env['returned.lines.from.serial.wizard'].\
with_context(context).create({})
return wizard.render_metasearch_view()

View File

@@ -0,0 +1,115 @@
openerp.crm_rma_lot_mass_return = function(openerp) {
var _t = openerp.web._t,
_lt = openerp.web._lt;
var QWeb = openerp.web.qweb;
/*
This widget is suposed to be used only in places where you need to load several
barcodes at same time. In order to save locally information and trigger save
data "ala onchange" but without lose the focus.
*/
openerp.web.form.BarcodeText = openerp.web.form.FieldText.extend({
events: {
'keyup': function(e) {
if (e.which === $.ui.keyCode.ENTER) {
this.store_dom_value();
e.stopPropagation();
}
},
'keypress': function(e) {
if (e.which === $.ui.keyCode.ENTER) {
this.store_dom_value();
e.stopPropagation();
}
},
'change textarea': function(e) {
this.store_dom_value();
e.stopPropagation();
$('textarea[name="scan_data"]').focus();
$('textarea[name="scan_data"]').trigger('focus');
},
},
});
openerp.web.form.ChangeFocus = openerp.web.form.FieldChar.extend({
events: {
'keyup': function(e) {
if (e.which === $.ui.keyCode.ENTER) {
$('textarea[name="scan_data"]').focus();
this.store_dom_value();
e.stopPropagation();
}
},
'keypress': function(e) {
if (e.which === 0 || e.which === $.ui.keyCode.TAB) {
$('textarea[name="scan_data"]').focus();
this.store_dom_value();
e.stopPropagation();
}
},
'change input': function(e) {
this.store_dom_value();
e.stopPropagation();
$('.packing_cache_button').click(function(e) {
$('body').off("keypress");
});
$('body').keypress(function(p) {
if ($._data($('body')[0], 'events').keypress.length > 1) {
$._data($('body')[0], 'events').keypress.pop();
}
var search = p.target.parentElement.className.search('pack_search');
if (p.target.name != 'scan_data' && search < 0 && p.keyCode === $.ui.keyCode.ENTER){
playAlert.volume(0.9);
playAlert('purr');
}
});
$('textarea[name="scan_data"]').focus();
$('textarea[name="scan_data"]').trigger('focus');
},
},
});
openerp.web.FormView.include({
on_processed_onchange: function(result){
try {
var result2 = result;
if (!_.isEmpty(result2.warning) && this.model == 'returned.lines.from.serial.wizard') {
playAlert.volume(0.9);
playAlert('purr');
new openerp.web.Dialog(this, {
size: 'medium',
title: result2.warning.title,
buttons: [{
text: _t("-->"),
click: function() {}
}, {
text: _t("Ok"),
click: function() {
this.parents('.modal').modal('hide');
}
}]
}, QWeb.render("CrashManager.warning", result2.warning)).open();
$("span:contains('-->')").focus();
} else {
this._super.apply(this, arguments);
}
} catch (e) {
console.error(e);
openerp.webclient.crashmanager.show_message(e);
return $.Deferred().reject();
}
},
});
openerp.web.form.widgets.add('barcode_text', 'openerp.web.form.BarcodeText');
openerp.web.form.widgets.add('change_focus', 'openerp.web.form.ChangeFocus');
};

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<template id="assets_backend" name="search_product assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/crm_rma_lot_mass_return/static/lib/alert.js"></script>
<script type="text/javascript" src="/crm_rma_lot_mass_return/static/src/js/barcode_text.js"></script>
</xpath>
</template>
</data>
</openerp>

View File

@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright 2015 Vauxoo
# Author: Osval Reyes,
# Yanina Aular
#
# 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 test_crm_rma_lot_mass_return
from . import test_crm_rma_lot_mass_return_2
from . import test_constrains

View File

@@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright 2015 Vauxoo
# Author: Yanina Aular
#
# 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
from openerp.exceptions import ValidationError
class TestConstrains(TransactionCase):
"""
- The product in claim.line.wizard must be the same
that product of invoice line
"""
def setUp(self):
super(TestConstrains, self).setUp()
self.claim_line_wizard = self.env['claim.line.wizard']
def test_product_constrain(self):
msg = "The product of the invoice .* is not same that product .*"
with self.assertRaisesRegexp(ValidationError, msg):
self.claim_line_wizard.\
create({
'product_id': self.env.ref('product.'
'product_product_8').id,
'invoice_line_id':
self.env.ref('account.demo_invoice_0_'
'line_rpanrearpanelshe0').id,
})

View File

@@ -0,0 +1,199 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright 2015 Vauxoo
# Author: Osval Reyes,
# Yanina Aular
#
# 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 datetime import date
from openerp.tests.common import TransactionCase
class TestCrmRmaLotMassReturn(TransactionCase):
"""
Test cases for CRM RMA Lot Mass Return Module
"""
def setUp(self):
super(TestCrmRmaLotMassReturn, self).setUp()
self.metasearch_wizard = self.env['returned.lines.from.serial.wizard']
self.partner_id = self.env['res.partner'].browse(
self.ref('base.res_partner_2'))
self.invoice_id, self.lot_ids = self.create_sale_invoice()
self.claim_id = self.env['crm.claim'].\
create({
'name': 'Test',
'claim_type': self.ref('crm_claim_type.'
'crm_claim_type_customer'),
'partner_id': self.invoice_id.partner_id.id,
'pick': True
})
def create_sale_order(self, order_policy='manual'):
sale_order_id = self.env['sale.order'].create({
'partner_id': self.partner_id.id,
'note': 'Sale Order Test',
'order_policy': order_policy,
'payment_term': self.ref('account.account_payment_term'),
'order_line': [(0, 0, {
'name': 'Test',
'product_id': self.ref('product.product_product_8'),
'product_uom_qty': 2
})]
})
sale_order_id.action_button_confirm()
return sale_order_id
def test_01_render_metasearch_view(self):
res = self.claim_id.render_metasearch_view()
self.assertEqual(res['res_model'], self.metasearch_wizard._name)
def test_02_load_products(self):
wizard_id = self.metasearch_wizard.with_context({
'active_model': self.claim_id._name,
'active_id': self.claim_id.id,
'active_ids': [self.claim_id.id]
}).create({})
# Get ids for invoice lines
lines_list_id = wizard_id.onchange_load_products(
self.invoice_id.number +
'*5*description here' + '\n' + self.lot_ids[0].name,
[(6, 0, [])])
lines_list_id = lines_list_id['domain']['lines_list_id'][0][2]
option_ids = wizard_id.onchange_load_products(
self.invoice_id.number, [(6, 0, [])])['value']['option_ids'][0][2]
wizard_id.option_ids = option_ids
wizard_id.lines_list_id = [(6, 0, lines_list_id)]
# the invoice lines are two
self.assertEqual(len(lines_list_id), 2)
# Validate it has exactly as much records as the taken invoice has
self.assertEqual(len(lines_list_id),
int(self.invoice_id.invoice_line.quantity))
wizard_id._set_message()
wizard_id.add_claim_lines()
# Claim record it must have same line count as the invoice
qty = 0
for inv_line in self.invoice_id.invoice_line:
qty += inv_line.quantity
self.assertEqual(len(self.claim_id.claim_line_ids),
int(qty))
def sale_validate_invoice(self, sale):
sale_advance_obj = self.env['sale.advance.payment.inv']
context = {
'active_model': 'sale.order',
'active_ids': [sale.id],
'active_id': sale.id,
}
wizard_invoice_id = sale_advance_obj.with_context(context).create({
'advance_payment_method': 'all',
})
wizard_invoice_id.with_context(context).create_invoices()
invoice_id = sale.invoice_ids[0]
invoice_id.signal_workflow('invoice_open')
# check if invoice is open
self.assertEqual(invoice_id.state, 'open')
pay_account_id = self.env['account.account'].\
browse(self.ref("account.cash"))
journal_id = self.env['account.journal'].\
browse(self.ref("account.bank_journal"))
date_start = date.today().replace(day=1, month=1).strftime('%Y-%m-%d')
period_id = self.env['account.fiscalyear'].search(
[('date_start', '=', date_start)]).period_ids[8]
invoice_id.pay_and_reconcile(
invoice_id.amount_total, pay_account_id.id,
period_id.id, journal_id.id, pay_account_id.id,
period_id.id, journal_id.id,
name="Payment for Invoice")
# in order to proceed is necessary to get the sale order invoiced
# and the invoice paid as well
self.assertTrue(sale.invoiced)
self.assertEqual(invoice_id.state, 'paid')
return invoice_id
def create_sale_invoice(self):
sale_order_id = self.create_sale_order('manual')
lot_ids = []
for picking_id in sale_order_id.picking_ids:
picking_id.force_assign()
# create wizard
wizard_id = self.env['stock.transfer_details'].create({
'picking_id': picking_id.id,
})
# make the transfers
for move_id in picking_id.move_lines:
wizard_item_id = self.env['stock.transfer_details_items'].\
create({
'transfer_id': wizard_id.id,
'product_id': move_id.product_id.id,
'quantity': move_id.product_qty,
'sourceloc_id': move_id.location_id.id,
'destinationloc_id':
self.ref('stock.stock_location_stock'),
'lot_id': False,
'product_uom_id': move_id.product_uom.id,
})
lot_id = self.env['stock.production.lot'].create({
'product_id': move_id.product_id.id,
'name': 'Test Lot %s%s' % (move_id.id,
move_id.product_id.id)
})
# keep lot_id for later check
lot_ids.append(lot_id)
wizard_item_id.write({
'lot_id': lot_id.id
})
wizard_id.do_detailed_transfer()
# Before continue, invoice must be open to get a number value
# and this is needed by the wizard
invoice_id = self.sale_validate_invoice(sale_order_id)
return invoice_id, lot_ids

View File

@@ -0,0 +1,209 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright 2015 Vauxoo
# Author: Osval Reyes,
# Yanina Aular
#
# 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
import re
class TestCrmRmaLotMassReturn2(TransactionCase):
"""
Test cases for CRM RMA Lot Mass Return Module
"""
def setUp(self):
super(TestCrmRmaLotMassReturn2, self).setUp()
self.metasearch_wizard = self.env['returned.lines.from.serial.wizard']
self.sale_order = self.env.ref('crm_rma_lot_mass_return.'
'so_wizard_rma_1')
self.lot_ids_mac0001 = self.env.ref('crm_rma_lot_mass_return.'
'lot_purchase_wizard_rma_item_1')
self.lot_ids_mac0003 = self.env.ref('crm_rma_lot_mass_return.'
'lot_purchase_wizard_rma_item_3')
self.claim_id_1 = self.env['crm.claim'].\
create({
'name': 'CLAIM001',
'claim_type': self.ref('crm_claim_type.'
'crm_claim_type_customer'),
'partner_id': self.sale_order.partner_id.id,
'pick': True
})
self.claim_id_2 = self.env['crm.claim'].\
create({
'name': 'CLAIM002',
'claim_type': self.ref('crm_claim_type.'
'crm_claim_type_customer'),
'partner_id': self.sale_order.partner_id.id,
'pick': True
})
def test_01_load_products(self):
wizard_id = self.metasearch_wizard.with_context({
'active_model': self.claim_id_1._name,
'active_id': self.claim_id_1.id,
'active_ids': [self.claim_id_1.id]
}).create({})
# Get ids for invoice lines
lines_list_id = wizard_id.onchange_load_products(
self.sale_order.invoice_ids[0].number +
'*5*description here' + '\n' + self.lot_ids_mac0001.name,
[(6, 0, [])])['domain']['lines_list_id'][0][2]
option_ids = wizard_id.onchange_load_products(
self.sale_order.invoice_ids[0].number +
'*5*description here' + '\n' + self.lot_ids_mac0001.name,
[(6, 0, [])])['value']['option_ids'][0][2]
wizard_id.option_ids = option_ids
items_to_select = self.env['claim.line.wizard'].browse(lines_list_id)
mac0001 = items_to_select.search([('lot_id.name', '=', 'MAC0001')])
mac0002 = items_to_select.search([('lot_id.name', '=', 'MAC0002')])
wizard_id.lines_list_id = [(6, 0, [mac0001.id, mac0002.id])]
# 1 Ink Cartridge, 2 Toner Cartridge, 1 iPad, 5 iMac
self.assertEqual(len(lines_list_id), 9)
qty = 0
for inv_line in self.sale_order.invoice_ids[0].invoice_line:
qty += inv_line.quantity
# Validate it has exactly as much records as the taken invoice has
self.assertEqual(len(lines_list_id), int(qty))
wizard_id._set_message()
wizard_id.add_claim_lines()
# 2 Macs
self.assertEqual(len(self.claim_id_1.claim_line_ids), 2)
def test_02_load_products(self):
wizard_id = self.metasearch_wizard.with_context({
'active_model': self.claim_id_2._name,
'active_id': self.claim_id_2.id,
'active_ids': [self.claim_id_2.id]
}).create({})
line_str = self.sale_order.invoice_ids[0].number + '*5*A description\n'
# Get ids for invoice lines
lines_list_id = wizard_id.onchange_load_products(
line_str, [(6, 0, [])])['domain']['lines_list_id'][0][2]
option_ids = wizard_id.onchange_load_products(
line_str, [(6, 0, [])])['value']['option_ids'][0][2]
wizard_id.option_ids = option_ids
cl_wizard = self.env['claim.line.wizard'].browse(lines_list_id)
mac0001 = cl_wizard.search([('lot_id.name', '=', 'MAC0001')])
mac0003 = cl_wizard.search([('lot_id.name', '=', 'MAC0003')])
toner0001 = cl_wizard.search([('product_id.name',
'=', 'Toner Cartridge')])
toner0002 = toner0001[1]
toner0001 = toner0001[0]
ink0001 = cl_wizard.search([('product_id.name', '=', 'Ink Cartridge')])
wizard_id.lines_list_id = [(6, 0, [mac0001.id, mac0003.id,
toner0001.id, toner0002.id,
ink0001.id])]
# 1 Ink Cartridge, 2 Toner Cartridge, 1 iPad, 5 iMac
self.assertEqual(len(lines_list_id), 9)
qty = 0
for inv_line in self.sale_order.invoice_ids[0].invoice_line:
qty += inv_line.quantity
# Validate it has exactly as much records as the taken invoice has
self.assertEqual(len(lines_list_id), int(qty))
wizard_id.add_claim_lines()
# 2 Macs
self.assertEqual(len(self.claim_id_2.claim_line_ids), 5)
def test_03_claim_line_creation_and_error_message(self):
"""
Challenge the wizard when a claim line is created, to set claim_origin
and the name correctly in a claim line itself, and also it tests the
message displayed to the user when is introduced an Serial/Lot numbers
that already is part of another claim.
"""
subject_list = self.env['claim.line'].SUBJECT_LIST
lot_name = "MAC0001"
subject_index = 3
scanned_data = lot_name + '*' + \
str(subject_index) + '*A short description to test\n'
wizard_id = self.metasearch_wizard.with_context({
'active_model': self.claim_id_2._name,
'active_id': self.claim_id_2.id,
'active_ids': [self.claim_id_2.id]
}).create({})
wizard_id.scan_data = scanned_data
# Get ids for invoice lines
lines_list_id = wizard_id.onchange_load_products(
scanned_data, [(6, 0, [])])['domain']['lines_list_id'][0][2]
wizard_id.option_id = wizard_id.onchange_load_products(
scanned_data, [(6, 0, [])])['value']['option_ids'][0][2]
items_to_select = self.env['claim.line.wizard'].browse(lines_list_id)
mac0001 = items_to_select.search([('lot_id.name', '=', lot_name)])
wizard_id.lines_list_id = [(6, 0, [mac0001.id])]
self.assertEqual(len(lines_list_id), 1)
wizard_id.add_claim_lines()
self.assertEqual(len(self.claim_id_2.claim_line_ids), 1)
line_id = self.claim_id_2.claim_line_ids
self.assertEqual(
subject_list[subject_index - 1][0], line_id.claim_origin)
self.assertEqual(scanned_data, line_id.prodlot_id.name + '*' +
str(subject_index) + '*' + line_id.name + '\n')
# create again the wizard
wizard_id = self.metasearch_wizard.with_context({
'active_model': self.claim_id_2._name,
'active_id': self.claim_id_2.id,
'active_ids': [self.claim_id_2.id]
}).create({})
wizard_id.scan_data = scanned_data
# Get ids for invoice lines
lines_list_id = wizard_id.onchange_load_products(
scanned_data, [(6, 0, [])])['domain']['lines_list_id'][0][2]
wizard_id.option_id = wizard_id.onchange_load_products(
scanned_data, [(6, 0, [])])['value']['option_ids'][0][2]
cl_wizard = self.env['claim.line.wizard'].browse(lines_list_id)
clw_id = cl_wizard.search([('lot_id.name', '=', lot_name)])
wizard_id.lines_list_id = [(6, 0, [clw_id.id])]
self.assertEqual(len(lines_list_id), 1)
wizard_id._set_message()
wizard_id.add_claim_lines()
self.assertEqual(len(self.claim_id_2.claim_line_ids), 1)
# if the message exists, then it's being displayed
regex = re.compile(".*" + lot_name + ".*")
self.assertTrue(regex.search(wizard_id.message))

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record id="crm_claim_rma_form_view_meta" model="ir.ui.view">
<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="//page[@string='Claim Description']//div[@name='serial']" position="inside">
<button name="render_metasearch_view"
string="Add claim lines using serial or invoice number" type="object"/>
</xpath>
<xpath expr="//field[@name='invoice_id']" position="attributes">
<attribute name="invisible">True</attribute>
</xpath>
</field>
</record>
</data>
</openerp>

View File

@@ -1,267 +0,0 @@
# -*- coding: utf-8 -*-
#########################################################################
# #
# #
#########################################################################
# #
# Copyright (C) 2009-2011 Akretion, Emmanuel Samyn #
# #
#This program is free software: you can redistribute it and/or modify #
#it under the terms of the GNU 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 General Public License for more details. #
# #
#You should have received a copy of the GNU General Public License #
#along with this program. If not, see <http://www.gnu.org/licenses/>. #
#########################################################################
from openerp.osv import fields, orm
class returned_lines_from_serial(orm.TransientModel):
_name = 'returned_lines_from_serial.wizard'
_description = 'Wizard to create product return lines from serial numbers'
_columns = {
'prodlot_id_1': fields.many2one('stock.production.lot',
'Serial / Lot Number 1', required=True),
'prodlot_id_2': fields.many2one('stock.production.lot',
'Serial / Lot Number 2'),
'prodlot_id_3': fields.many2one('stock.production.lot',
'Serial / Lot Number 3'),
'prodlot_id_4': fields.many2one('stock.production.lot',
'Serial / Lot Number 4'),
'prodlot_id_5': fields.many2one('stock.production.lot',
'Serial / Lot Number 5'),
'qty_1' : fields.float('Quantity 1', digits=(12,2), required=True),
'qty_2' : fields.float('Quantity 2', digits=(12,2)),
'qty_3' : fields.float('Quantity 3', digits=(12,2)),
'qty_4' : fields.float('Quantity 4', digits=(12,2)),
'qty_5' : fields.float('Quantity 5', digits=(12,2)),
'claim_1': fields.selection([('none','Not specified'),
('legal','Legal retractation'),
('cancellation','Order cancellation'),
('damaged','Damaged delivered product'),
('error','Shipping error'),
('exchange','Exchange request'),
('lost','Lost during transport'),
('other','Other')], 'Claim Subject',
required=True,
help="To describe the product problem"),
'claim_2': fields.selection([('none','Not specified'),
('legal','Legal retractation'),
('cancellation','Order cancellation'),
('damaged','Damaged delivered product'),
('error','Shipping error'),
('exchange','Exchange request'),
('lost','Lost during transport'),
('other','Other')], 'Claim Subject',
required=True,
help="To describe the line product problem"),
'claim_3': fields.selection([('none','Not specified'),
('legal','Legal retractation'),
('cancellation','Order cancellation'),
('damaged','Damaged delivered product'),
('error','Shipping error'),
('exchange','Exchange request'),
('lost','Lost during transport'),
('other','Other')], 'Claim Subject',
required=True,
help="To describe the line product problem"),
'claim_4': fields.selection([('none','Not specified'),
('legal','Legal retractation'),
('cancellation','Order cancellation'),
('damaged','Damaged delivered product'),
('error','Shipping error'),
('exchange','Exchange request'),
('lost','Lost during transport'),
('other','Other')], 'Claim Subject',
required=True,
help="To describe the line product problem"),
'claim_5': fields.selection([('none','Not specified'),
('legal','Legal retractation'),
('cancellation','Order cancellation'),
('damaged','Damaged delivered product'),
('error','Shipping error'),
('exchange','Exchange request'),
('lost','Lost during transport'),
('other','Other')], 'Claim Subject',
required=True,
help="To describe the line product problem"),
'partner_id': fields.many2one('res.partner', 'Partner'),
}
# Get partner from case is set to filter serials
def _get_default_partner_id(self, cr, uid, context):
return self.pool.get('crm.claim').read(cr, uid,
context['active_id'], ['partner_id'])['partner_id'][0]
_defaults = {
'qty_1': lambda *a: 1.0,
'qty_2': lambda *a: 1.0,
'qty_3': lambda *a: 1.0,
'qty_4': lambda *a: 1.0,
'qty_5': lambda *a: 1.0,
'claim_1': lambda *a: "none",
'claim_2': lambda *a: "none",
'claim_3': lambda *a: "none",
'claim_4': lambda *a: "none",
'claim_5': lambda *a: "none",
'partner_id': _get_default_partner_id,
}
# If "Cancel" button pressed
def action_cancel(self,cr,uid,ids,conect=None):
return {'type': 'ir.actions.act_window_close',}
# If "Add & close" button pressed
def action_add_and_close(self, cr, uid, ids, context=None):
self.add_return_lines(cr, uid, ids, context)
return {'type': 'ir.actions.act_window_close',}
# If "Add & new" button pressed
def action_add_and_new(self, cr, uid, ids, context=None):
self.add_return_lines(cr, uid, ids, context)
return {
'context': context,
'view_type': 'form',
'view_mode': 'form',
'res_model': 'returned_lines_from_serial.wizard',
'view_id': False,
'type': 'ir.actions.act_window',
'target': 'new',
}
# Method to get the product id from set
def get_product_id(self, cr, uid,ids,product_set, context=None):
product_id = False
for product in self.prodlot_2_product(cr, uid,[product_set]):
product_id = product
return product_id
# Method to create return lines
def add_return_lines(self, cr, uid, ids, context=None):
result = self.browse(cr,uid,ids)[0]
return_line = self.pool.get('claim.line')
# Refactor code : create 1 "createmethode" called by each if with values as parameters
return_line.create(cr, uid, {
'claim_id': context['active_id'],
'claim_origine': result.claim_1,
'product_id' : self.get_product_id(cr, uid, ids,
result.prodlot_id_1.id, context=context),
#'invoice_id' : self.prodlot_2_invoice(cr, uid,[result.prodlot_id_1.id],[result.prodlot_id_1.product_id.id]), #PRODLOT_ID can be in many invoice !!
'product_returned_quantity' : result.qty_1,
'prodlot_id' : result.prodlot_id_1.id,
'selected' : False,
'state' : 'draft',
#'guarantee_limit' : warranty['value']['guarantee_limit'],
#'warning' : warranty['value']['warning'],
})
if result.prodlot_id_2.id :
return_line.create(cr, uid, {
'claim_id': context['active_id'],
'claim_origine': result.claim_2,
'product_id' : self.get_product_id(cr, uid, ids,
result.prodlot_id_2.id, context=context),
# 'invoice_id' : self.prodlot_2_invoice(cr, uid,[result.prodlot_id_1.id]),
'product_returned_quantity' : result.qty_2,
'prodlot_id' : result.prodlot_id_2.id,
'selected' : False,
'state' : 'draft',
#'guarantee_limit' : warranty['value']['guarantee_limit'],
#'warning' : warranty['value']['warning'],
})
if result.prodlot_id_3.id :
return_line.create(cr, uid, {
'claim_id': context['active_id'],
'claim_origine': result.claim_3,
'product_id' : self.get_product_id(cr, uid, ids,
result.prodlot_id_3.id, context=context),
# 'invoice_id' : self.prodlot_2_invoice(cr, uid,[result.prodlot_id_1.id]),
'product_returned_quantity' : result.qty_3,
'prodlot_id' : result.prodlot_id_3.id,
'selected' : False,
'state' : 'draft',
#'guarantee_limit' : warranty['value']['guarantee_limit'],
#'warning' : warranty['value']['warning'],
})
if result.prodlot_id_4.id :
return_line.create(cr, uid, {
'claim_id': context['active_id'],
'claim_origine': result.claim_4,
'product_id' : self.get_product_id(cr, uid, ids,
result.prodlot_id_4.id, context=context),
# 'invoice_id' : self.prodlot_2_invoice(cr, uid,[result.prodlot_id_1.id]),
'product_returned_quantity' : result.qty_4,
'prodlot_id' : result.prodlot_id_4.id,
'selected' : False,
'state' : 'draft',
#'guarantee_limit' : warranty['value']['guarantee_limit'],
#'warning' : warranty['value']['warning'],
})
if result.prodlot_id_5.id :
return_line.create(cr, uid, {
'claim_id': context['active_id'],
'claim_origine': result.claim_5,
'product_id' : self.get_product_id(cr, uid, ids,
result.prodlot_id_5.id, context=context),
# 'invoice_id' : self.prodlot_2_invoice(cr, uid,[result.prodlot_id_1.id],[result.prodlot_id_1.product_id.id]),
'product_returned_quantity' : result.qty_5,
'prodlot_id' : result.prodlot_id_5.id,
'selected' : False,
'state' : 'draft',
#'guarantee_type':
#'guarantee_limit' : warranty['value']['guarantee_limit'],
#'warning' : warranty['value']['warning'],
})
return True
def prodlot_2_product(self,cr, uid, prodlot_ids):
stock_move_ids = self.pool.get('stock.move').search(cr, uid,
[('prodlot_id', 'in', prodlot_ids)])
res = self.pool.get('stock.move').read(cr, uid,
stock_move_ids, ['product_id'])
return set([x['product_id'][0] for x in res if x['product_id']])
def prodlot_2_invoice(self,cr, uid, prodlot_id,product_id):
# get stock_move_ids
stock_move_ids = self.pool.get('stock.move').search(cr, uid,
[('prodlot_id', 'in', prodlot_id)])
# if 1 id
# (get stock picking (filter on out ?))
# get invoice_ids from stock_move_id where invoice.line.product = prodlot_product and invoice customer = claim_partner
# if 1 id
# return invoice_id
# else
# else : move_in / move_out ; 1 move per order line so if many order lines with same lot, ...
#
#return set(self.stock_move_2_invoice(cr, uid, stock_move_ids))
return True
def stock_move_2_invoice(self, cr, uid, stock_move_ids):
inv_line_ids = []
res = self.pool.get('stock.move').read(cr, uid,
stock_move_ids, ['sale_line_id'])
sale_line_ids = [x['sale_line_id'][0] for x in res if x['sale_line_id']]
if not sale_line_ids:
return []
sql_base = "select invoice_id from sale_order_line_invoice_rel where \
order_line_id in ("
cr.execute(sql_base + ','.join(map(lambda x: str(x),sale_line_ids))+')')
res = cr.fetchall()
for i in res:
for j in i:
inv_line_ids.append(j)
res = self.pool.get('account.invoice.line').read(cr, uid,
inv_line_ids,['invoice_id'])
return [x['invoice_id'][0] for x in res if x['invoice_id']]

View File

@@ -1,73 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
#########################################################################
# #
# #
#########################################################################
# #
# Copyright (C) 2009-2011 Akretion, Emmanuel Samyn #
# #
#This program is free software: you can redistribute it and/or modify #
#it under the terms of the GNU 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 General Public License for more details. #
# #
#You should have received a copy of the GNU General Public License #
#along with this program. If not, see <http://www.gnu.org/licenses/>. #
#########################################################################
-->
<openerp>
<data>
<!-- SELECT FORM VIEW -->
<record id="view_create_return_serial_form" model="ir.ui.view">
<field name="name">returned_lines_from_serial_wiew</field>
<field name="model">returned_lines_from_serial.wizard</field>
<field name="arch" type="xml">
<form string="Select serial numbers to create">
<group col="3" colspan="4">
<separator string="Serial / Lot Number" colspan="1"/>
<separator string="Quantity returned" colspan="1"/>
<separator string="Claim short description" colspan="1"/>
<field name="prodlot_id_1" nolabel="1"/>
<field name="qty_1" nolabel="1"/>
<field name="claim_1" nolabel="1"/>
<field name="prodlot_id_2" nolabel="1"/>
<field name="qty_2" nolabel="1"/>
<field name="claim_2" nolabel="1"/>
<field name="prodlot_id_3" nolabel="1"/>
<field name="qty_3" nolabel="1"/>
<field name="claim_3" nolabel="1"/>
<field name="prodlot_id_4" nolabel="1"/>
<field name="qty_4" nolabel="1"/>
<field name="claim_4" nolabel="1"/>
<field name="prodlot_id_5" nolabel="1"/>
<field name="qty_5" nolabel="1"/>
<field name="claim_5" nolabel="1"/>
</group>
<group col="4" colspan="2">
<button special="cancel" string="Cancel" name="action_cancel" type="object" icon='gtk-cancel'/>
<button name="action_add_and_close" string="Save and close" icon='gtk-ok' type="object"/>
<button name="action_add_and_new" string="Save and new" icon='gtk-add' type="object"/>
</group>
</form>
</field>
</record>
<!-- SELECT ACTION -->
<record id="action_create_return_serial" model="ir.actions.act_window">
<field name="name">action_create_return_serial</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">returned_lines_from_serial.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>
</record>
</data>
</openerp>

View File

@@ -1,9 +1,12 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright 2015 Vauxoo
# Copyright 2013 Camptocamp
# Copyright 2009-2013 Akretion,
# Author: Emmanuel Samyn, Raphaël Valyi, Sébastien Beau, Joel Grand-Guillaume
# Copyright 2009-2013 Akretion,
# Author: 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,4 +22,5 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from . import returned_lines_from_serial

View File

@@ -0,0 +1,595 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright 2015 Vauxoo
# Copyright (C) 2009-2011 Akretion
# Author: Emmanuel Samyn,
# 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
# 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
from openerp.exceptions import ValidationError
class ClaimLineWizard(models.TransientModel):
_name = "claim.line.wizard"
product_id = fields.Many2one("product.product",
string="Product",
help="Product to claim")
lot_id = fields.Many2one("stock.production.lot",
string="Lot",
help="Product to claim")
invoice_line_id = fields.Many2one("account.invoice.line",
required=True,
string="Invoice Line",
help="Invoice Line")
name = fields.Char(compute="_get_complete_name",
string="Complete Lot Name",)
@api.constrains('product_id', 'invoice_line_id')
def _check_product_id(self):
for record in self:
if record.product_id != \
record.invoice_line_id.product_id:
raise ValidationError("The product of the"
" invoice %s is not same"
" that product %s" %
(record.invoice_line_id.product_id.name,
record.product_id.name))
@api.depends('invoice_line_id', 'lot_id', 'product_id')
def _get_complete_name(self):
for wizard in self:
invoice_number = wizard.invoice_line_id.invoice_id.number
product_name = wizard.product_id.name
lot_name = False
if wizard.lot_id:
lot_name = wizard.lot_id.name
if not lot_name:
name = _("(ID: %s) - %s - %s") % \
(wizard.id,
product_name,
invoice_number)
else:
name = _("(ID: %s) - %s - %s - %s") % \
(wizard.id,
product_name,
invoice_number,
lot_name)
wizard.name = name
class ReturnedLinesFromSerial(models.TransientModel):
_name = 'returned.lines.from.serial.wizard'
_description = 'Wizard to create product return lines'
' from serial numbers or invoices'
# Get partner from case is set to filter serials
@api.model
def _get_default_partner_id(self):
"""
Obtain partner from the claim
"""
crm_claim_model = self.env['crm.claim']
claim_id = self.env.context.get('active_id')
partner_record = crm_claim_model.browse(claim_id).\
partner_id
return partner_record and partner_record[0] or \
self.env['res.partner']
@api.model
def create_claim_line(self, claim_id, claim_origin,
product_record, claim_line_wizard,
qty, name):
clima_line = self.env['claim.line']
if claim_line_wizard.lot_id:
inv_line = self.prodlot_2_invoice_line(
claim_line_wizard.lot_id.name)
lot_id = claim_line_wizard.lot_id.id
else:
inv_line = claim_line_wizard.invoice_line_id
lot_id = False
line_rec = clima_line.create({
'claim_id': claim_id,
'claim_origin': claim_origin,
'product_id': product_record and product_record.id or False,
'name': name and name or (product_record and
product_record.name or
inv_line.name),
'invoice_line_id': inv_line.id,
'product_returned_quantity': qty,
'prodlot_id': lot_id,
})
line_rec.set_warranty()
# If "Cancel" button pressed
@api.multi
def action_cancel(self):
return {'type': 'ir.actions.act_window_close'}
partner_id = fields.Many2one('res.partner',
'Partner',
default=_get_default_partner_id)
def _get_claim_type(self):
claim_id = self.env.context.get('active_id')
claim_record = self.env['crm.claim'].browse(claim_id)
current_claim_type = claim_record.claim_type
customer_claim_type = \
self.env.ref('crm_claim_type.crm_claim_type_customer')
supplier_claim_type = \
self.env.ref('crm_claim_type.crm_claim_type_supplier')
return current_claim_type, customer_claim_type, supplier_claim_type
@api.model
def prodlot_2_invoice_line(self, prodlot):
"""
Return the last line of customer invoice
based in serial/lot number
"""
lot_obj = self.env['stock.production.lot']
current_claim_type, customer_claim_type, supplier_claim_type = \
self._get_claim_type()
prodlot = lot_obj.search([('name', '=', str(prodlot))])
if supplier_claim_type == current_claim_type:
if prodlot.supplier_invoice_line_id:
return prodlot.supplier_invoice_line_id
elif customer_claim_type == current_claim_type:
if prodlot.invoice_line_id:
return prodlot.invoice_line_id
else:
if prodlot.invoice_line_id:
return prodlot.invoice_line_id
elif prodlot.supplier_invoice_line_id:
return prodlot.supplier_invoice_line_id
return False
lines_list_id = fields.Many2many('claim.line.wizard',
'claim_line_wizard_returned',
'wizard_id',
'claim_line_wizard_id',
string='Products selected',
help='Field used to show the current '
'status of the lots '
'loaded')
option_ids = fields.Many2many('claim.line.wizard',
string='Invoice Lines to Select',
help='Field used to load the ids of '
'invoice lines in invoices writed')
scan_data = fields.Text('Products',
help='Field used to load and show the '
'products')
scaned_data = fields.Text('Products',
help='Field used to load the ids of '
'products loaded')
current_status = fields.Text('Status',
help='Field used to show the current '
'status of the product '
'loaded(Name and quantity)')
@api.multi
def get_metasearch_view_brw(self):
"""
@return: view with metasearch field
"""
view_id = self.env.\
ref('crm_rma_lot_mass_return.view_enter_product')
return view_id
@api.multi
def render_metasearch_view(self):
"""
Render wizard view with metasearch field
"""
view = self.get_metasearch_view_brw()
if view:
return {
'name': _('Search Product'),
'type': 'ir.actions.act_window',
'view_type': 'form',
'view_mode': 'form',
'res_model': 'returned.lines.from.serial.wizard',
'view_id': view.id,
'views': [(view.id, 'form')],
'target': 'new',
'res_id': self.id,
}
@api.model
def get_data_of_products(self, input_data):
data_line = []
for item in input_data and input_data.split('\n') or []:
if '*' in item:
comput = item.split('*')
data_it_1 = '0'
data_it_2 = ''
if len(comput) >= 2:
data_it_1 = comput[1]
if len(comput) >= 3:
data_it_2 = comput[2]
if comput[0]:
data_line.append((comput[0], (data_it_1, data_it_2)))
else:
if item.strip():
data_line.append((item.strip(), ('0', '')))
return data_line
def _get_lots_from_scan_data(self, input_data):
input_lines = self.get_data_of_products(input_data)
invoice = self.env['account.invoice']
lot = self.env['stock.production.lot']
prodlot_set_ids = set()
lot_set_ids = []
lots_lot_set_ids = []
if not input_lines:
return False, False, False
current_claim_type, customer_claim_type, supplier_claim_type = \
self._get_claim_type()
claim_line_wizard = self.env['claim.line.wizard']
for line in input_lines:
# if there is no invoice/serial in it
if not line[0]:
continue
number_serial = line[0].encode('utf8')
# search invoices first
invoice_ids = invoice.search([('number', '=', number_serial)])
element_searched = False
if invoice_ids:
if supplier_claim_type == current_claim_type:
invoice_field = 'supplier_invoice_line_id'
elif customer_claim_type == current_claim_type:
invoice_field = 'invoice_line_id'
for inv in invoice_ids:
for inv_line in inv.invoice_line:
clw = claim_line_wizard.\
search([('invoice_line_id', '=', inv_line.id)])
enter = False
lot_ids = lot.\
search([(invoice_field, '=',
inv_line.id)])
if len(clw) < int(inv_line.quantity):
for asd in clw:
if asd not in lot_set_ids:
lot_set_ids.append(asd)
lot_ids = lot_ids - asd.lot_id
num_to_create = int(inv_line.quantity) - len(clw)
for num in xrange(0, num_to_create):
clw = \
claim_line_wizard.\
create({
'product_id':
inv_line.product_id.id,
'invoice_line_id': inv_line.id,
})
if lot_ids:
lot = lot_ids[0]
clw.write({'lot_id': lot.id})
lot_ids = lot_ids - lot
for asd in clw:
if asd not in lot_set_ids:
lot_set_ids.append(asd)
enter = True
if not enter:
for asd in clw:
if asd not in lot_set_ids:
if lot_ids:
lot = lot_ids[0]
asd.write({'lot_id': lot.id})
lot_ids = lot_ids - lot
lot_set_ids.append(asd)
element_searched = lot_set_ids
else:
# if not, it must be a serial lot number
prodlot_ids = lot
if supplier_claim_type == current_claim_type:
prodlot_ids = \
lot.search([('name', '=', number_serial),
('supplier_invoice_line_id', '!=', False)])
invoice_line = prodlot_ids.supplier_invoice_line_id
elif customer_claim_type == current_claim_type:
prodlot_ids = \
lot.search([('name', '=', number_serial),
('invoice_line_id', '!=', False)])
invoice_line = prodlot_ids.invoice_line_id
else:
prodlot_ids = \
lot.search([('name', '=', number_serial), '|',
('supplier_invoice_line_id', '!=', False),
('invoice_line_id', '!=', False),
])
if prodlot_ids.invoice_line_id:
invoice_line = prodlot_ids.invoice_line_id
else:
invoice_line = prodlot_ids.supplier_invoice_line_id
if prodlot_ids:
for lot_id in prodlot_ids:
clw = claim_line_wizard.\
search([('lot_id', '=', lot_id.id)])
if not clw:
clw = \
claim_line_wizard.\
create({
'product_id': lot_id.product_id.id,
'lot_id': lot_id.id,
'invoice_line_id': invoice_line.id,
})
for asd in clw:
if asd not in lot_set_ids:
lot_set_ids.append(asd)
element_searched = True
for item in prodlot_ids:
item_name = item.product_id \
and item.product_id.name.encode('utf8') or False
prodlot_set_ids |= {'%s+%s' % (item.id, item_name)}
for asd in lot_set_ids:
if asd not in lots_lot_set_ids:
lots_lot_set_ids.append(asd)
# if at least one line is not found, then return error
if not element_searched:
return False, line[0], False
# all lines were found, then return those lots
return lot_set_ids, prodlot_set_ids, lots_lot_set_ids
@api.multi
def onchange_load_products(self, input_data, lines_list_id):
"""
Load claim lines from partner invoices or related production lots
into the current claim massively
"""
lot_lots_ids = []
prodlot_set_ids = set()
lines_set_ids = []
current_status = scaned_data = ''
elements_searched, line_found, lot_lots_ids = \
self._get_lots_from_scan_data(input_data)
if not elements_searched and not line_found:
return {
'value': {
'option_ids': [],
'current_status': current_status,
'scaned_data': scaned_data,
},
'domain': {
'lines_list_id': [('id', 'in', [])]
}
}
if not elements_searched and not lot_lots_ids and line_found:
return {
'warning': {
'message': (_('The product or invoice %s'
' was not found') % line_found)},
}
else:
lines_set_ids = elements_searched
prodlot_set_ids = line_found
for line in prodlot_set_ids:
name = line.split('+')
current_status += name[1] + '\n'
scaned_data += name[0] + '\n'
lines_set_ids = [asd.id for asd in lines_set_ids]
return {
'value': {
'option_ids': [(6, 0, lines_set_ids)],
'current_status': current_status,
'scaned_data': scaned_data,
},
'domain': {
'lines_list_id': [('id', 'in', lines_set_ids)]
}
}
def _get_lot_ids(self):
lot = self.env['stock.production.lot']
lot_ids = set()
if self.scaned_data:
lot_ids |= {lot_id
for lid in self.scaned_data.strip().split('\n')
for lot_id in lot.browse(int(lid))}
claim_line_wizard = self.env['claim.line.wizard']
lot_ids_2 = []
for wizard_id in lot_ids:
clws = claim_line_wizard.search([('lot_id', '=', wizard_id.id)])
for clw in clws:
lot_ids_2.append(clw)
lot_ids = set(lot_ids_2)
if self.lines_list_id:
lot_ids |= {lid for lid in self.lines_list_id}
return lot_ids
@api.model
def _get_invalid_lots_set(self, claim_line_wizard_ids, add=False):
"""
Return only those lots are related to claim lines
"""
claim_line_wizard = self.env['claim.line.wizard']
valid = claim_line_wizard.browse(claim_line_wizard_ids)
invalid_lots = []
for clw in claim_line_wizard.browse(claim_line_wizard_ids):
if clw.lot_id:
invalid_lot = self.env['claim.line'].search([
('invoice_line_id', '=', clw.invoice_line_id.id),
('product_id', '=', clw.product_id.id),
('prodlot_id', '=', clw.lot_id.id),
])
if not invalid_lot:
valid = valid - clw
if invalid_lot:
invalid_lots.append(clw)
for clw in valid.mapped('invoice_line_id'):
# mac1, None -> claim.line
invalid_lot = self.env['claim.line'].search([
('invoice_line_id', '=', clw.id),
('product_id', '=', clw.product_id.id),
])
# mac1, mac2, mac3, mac4, None -> breaked down
clws = self.env['claim.line.wizard'].\
search([('invoice_line_id', '=', clw.id),
])
if invalid_lot:
for item in invalid_lot:
if item.prodlot_id:
add = clws.search([
('lot_id', '=', item.prodlot_id.id),
('id', 'in', clws.mapped('id')),
('id', 'not in', [rdy.id for rdy in invalid_lots]),
])
else:
add = clws.search([
('lot_id', '=', False),
('id', 'in', clws.mapped('id')),
('id', 'not in', [rdy.id for rdy in invalid_lots]),
])
if add:
invalid_lots.append(add[0])
# mac1, None -> like claim.line.wizard
return invalid_lots and invalid_lots or []
@api.multi
def add_claim_lines(self):
info = self.get_data_of_products(self.scan_data)
lot_ids = self._get_lot_ids()
lot_ids = [lid.id for lid in lot_ids]
clw_ids = set(self._get_lot_ids()) - \
set(self._get_invalid_lots_set(lot_ids, True))
clw_ids = list(clw_ids)
# It creates only those claim lines that have a valid production lot,
# i. e. not using in others claims
info = dict(info)
if clw_ids:
for clw_id in clw_ids:
product_id = clw_id.product_id
claim_line_info = False
if clw_id.lot_id.name in info:
claim_line_info = info.get(clw_id.lot_id.name, False)
elif clw_id.invoice_line_id.invoice_id.number in info:
claim_line_info = \
info.get(clw_id.invoice_line_id.invoice_id.number,
False)
num = claim_line_info and claim_line_info[0] or '0'
name = claim_line_info and claim_line_info[1] or ''
if num.isdigit():
num = int(num)
else:
num = 0
current_claim_type, customer_claim_type, \
supplier_claim_type = \
self._get_claim_type()
self.create_claim_line(self.env.context.get('active_id'),
self.env[
'claim.line']._get_subject(num),
product_id, clw_id, 1, name)
# Clean items in wizard model
if len(clw_ids) == 1:
ids_to_delete = "(%s)" % str(clw_ids[0].id)
else:
ids_to_delete = "%s" % str(tuple([clw.id for clw in clw_ids]))
self._cr.execute("DELETE FROM claim_line_wizard where id IN %s"
% ids_to_delete)
# normal execution
self.action_cancel()
@api.multi
def change_list(self, lines):
return {
'value': {
'lines_list_id': lines,
}
}
message = fields.Text(string='Message',
compute='_set_message'
)
@api.depends('current_status', 'lines_list_id', 'scan_data')
def _set_message(self):
"""
Notify for missing (not added) claim lines that are in use in others
claims
"""
for wizard in self:
msg = ''
all_lots = wizard._get_lots_from_scan_data(wizard.scan_data)
not_valid_lot_ids = set()
if all_lots[0]:
all_lots_0 = [item for item in all_lots[0]]
not_valid_lot_ids = set(all_lots_0)
if all_lots[2]:
all_lots_2 = [item for item in all_lots[2]]
not_valid_lot_ids |= set(all_lots_2)
if not_valid_lot_ids:
not_valid_lot_ids = [item.id for
item in list(not_valid_lot_ids)]
not_valid_lot_ids = wizard.\
_get_invalid_lots_set(not_valid_lot_ids)
not_valid_lot_ids = list(set(not_valid_lot_ids))
claim_with_lots_msg = ""
for line_id in not_valid_lot_ids:
claim_with_lots_msg += "\t- %s\n" % \
line_id.name
if claim_with_lots_msg:
msg = _("The following Serial/Lot numbers won't be added,"
" because all of them (listed below)"
" are currently in"
" use:\n\n %s") % (claim_with_lots_msg) or ''
wizard.message = msg

View File

@@ -0,0 +1,104 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_enter_product" model="ir.ui.view">
<field name="name">returned_lines_from_serial_wiew</field>
<field name="model">returned.lines.from.serial.wizard</field>
<field name="arch" type="xml">
<form>
<div class='row'>
<div class="col-md-10 col-sm-10 col-lg-10">
<div class="panel panel-default">
<div class="panel-heading">
<h2><field name="partner_id" readonly="1"/></h2>
<field class="oe_form_box_info oe_text_center"
name='message'
readonly="1"
attrs="{'invisible':[('message', '=', '')]}"/>
<group>
<field name="scaned_data" invisible="1"/>
</group>
</div>
</div>
<table class="table table-hover">
<tbody>
<td>
<field name="current_status" readonly="1" widget="barcode_text" nolabel='1'/>
</td>
<td>
<field name="scan_data"
widget='barcode_text'
on_change="onchange_load_products(scan_data, option_ids)"
nolabel='1'/>
</td>
</tbody>
</table>
</div>
<div class="col-md-10 col-sm-10 col-lg-10">
<div class="row">
<div class="pull-right" name="buttons">
<button name="add_claim_lines"
help="All the valid lines will be added to the claim"
confirm="You are about to add new lines to the claim, Do you want to continue?."
string="Add items to the claim" colspan="1" type="object" class="oe_highlight"/>
</div>
</div>
</div>
</div>
<div class="row">
<div class='col-md-4 col-sm-4 col-lg-4'>
<div class="row">
<field name="option_ids" invisible="1"/>
<field name="lines_list_id"
domain="[('id', 'in', [])]"
widget="many2many_checkboxes" on_change="change_list(lines_list_id)"/>
</div>
</div>
<div class='col-md-16 col-sm-16 col-lg-16'>
<div class="row">
<!-- Invoice lines list -->
</div>
</div>
<div class='col-md-4 col-sm-4 col-lg-4'>
<div class="row">
</div>
</div>
</div>
<footer>
<p class="oe_help">
You should use this windows on this way.
<ol>
<li>Write the Serial/Lot Number to search the product</li>
or
<li>Write the Invoice Number to search the products in lines</li>
<li>Example: A4JD6JHS</li>
</ol>
The format for writing the reason for the claim and
the description is:
<ol>
<li>Serial/Lot Number*reason number*Description here</li>
<li>Example: A4JD6JHS*4*The display is break</li>
</ol>
The reasons for the claim can be
<ol>
<li>Not specified</li>
<li>Legal retractation</li>
<li>Order Cancellation</li>
<li>Damaged Delivered Product</li>
<li>Shipping error</li>
<li>Exchange request</li>
<li>Lost during transport</li>
<li>Perfect Conditions</li>
<li>Imperfection</li>
<li>Physical Damage by Client</li>
<li>Physical Damage by Company</li>
<li>Other</li>
</ol>
</p>
</footer>
</form>
</field>
</record>
</data>
</openerp>