mirror of
https://gitlab.com/hibou-io/hibou-odoo/suite.git
synced 2025-01-20 12:37:31 +02:00
[REM] rma_sale: available in professional
H14528
This commit is contained in:
@@ -1,5 +0,0 @@
|
||||
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
|
||||
|
||||
from . import controllers
|
||||
from . import models
|
||||
from . import wizard
|
||||
@@ -1,30 +0,0 @@
|
||||
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
|
||||
|
||||
{
|
||||
'name': 'Hibou RMAs for Sale Orders',
|
||||
'version': '15.0.1.0.1',
|
||||
'category': 'Sale',
|
||||
'author': 'Hibou Corp.',
|
||||
'license': 'OPL-1',
|
||||
'website': 'https://hibou.io/',
|
||||
'depends': [
|
||||
'hibou_professional',
|
||||
'rma',
|
||||
'sale',
|
||||
'sales_team',
|
||||
],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'views/portal_templates.xml',
|
||||
'views/product_views.xml',
|
||||
'views/rma_views.xml',
|
||||
'views/sale_views.xml',
|
||||
'wizard/rma_lines_views.xml',
|
||||
],
|
||||
'demo': [
|
||||
'data/rma_demo.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'auto_install': True,
|
||||
'application': False,
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
|
||||
|
||||
from . import portal
|
||||
@@ -1,53 +0,0 @@
|
||||
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
|
||||
|
||||
from operator import itemgetter
|
||||
|
||||
import odoo.addons.rma.controllers.portal as rma_portal
|
||||
from odoo.http import request
|
||||
from odoo.tools.translate import _
|
||||
from odoo.osv.expression import OR
|
||||
from odoo.tools import groupby as groupbyelem
|
||||
|
||||
original_rma_portal_searchbar_filters = rma_portal.rma_portal_searchbar_filters
|
||||
original_rma_portal_searchbar_inputs = rma_portal.rma_portal_searchbar_inputs
|
||||
original_rma_portal_search_domain = rma_portal.rma_portal_search_domain
|
||||
original_rma_portal_searchbar_groupby = rma_portal.rma_portal_searchbar_groupby
|
||||
original_rma_portal_group_rmas = rma_portal.rma_portal_group_rmas
|
||||
|
||||
|
||||
def rma_portal_searchbar_filters():
|
||||
res = original_rma_portal_searchbar_filters()
|
||||
res['sale'] = {'label': _('Sale Order'), 'domain': [('sale_order_id', '!=', False)]}
|
||||
return res
|
||||
|
||||
|
||||
def rma_portal_searchbar_inputs():
|
||||
res = original_rma_portal_searchbar_inputs()
|
||||
res['sale'] = {'input': 'sale', 'label': _('Search Sale Order')}
|
||||
return res
|
||||
|
||||
|
||||
def rma_portal_search_domain(search_in, search):
|
||||
search_domain = original_rma_portal_search_domain(search_in, search)
|
||||
if search_in in ('sale', 'all'):
|
||||
search_domain = OR([search_domain, [('sale_order_id', 'ilike', search)]])
|
||||
return search_domain
|
||||
|
||||
|
||||
def rma_portal_searchbar_groupby():
|
||||
res = original_rma_portal_searchbar_groupby()
|
||||
res['sale'] = {'input': 'sale', 'label': _('Sale Order')}
|
||||
return res
|
||||
|
||||
|
||||
def rma_portal_group_rmas(rmas, groupby):
|
||||
if groupby == 'sale':
|
||||
return [request.env['rma.rma'].concat(*g) for k, g in groupbyelem(rmas, itemgetter('sale_order_id'))]
|
||||
return original_rma_portal_group_rmas(rmas, groupby)
|
||||
|
||||
|
||||
rma_portal.rma_portal_searchbar_filters = rma_portal_searchbar_filters
|
||||
rma_portal.rma_portal_searchbar_inputs = rma_portal_searchbar_inputs
|
||||
rma_portal.rma_portal_search_domain = rma_portal_search_domain
|
||||
rma_portal.rma_portal_searchbar_groupby = rma_portal_searchbar_groupby
|
||||
rma_portal.rma_portal_group_rmas = rma_portal_group_rmas
|
||||
@@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
|
||||
<record id="template_sale_return" model="rma.template">
|
||||
<field name="name">Sale Return</field>
|
||||
<field name="usage">sale_order</field>
|
||||
<field name="valid_days" eval="10"/>
|
||||
<field name="create_in_picking" eval="True"/>
|
||||
<field name="in_type_id" ref="stock.picking_type_in"/>
|
||||
<field name="in_location_id" ref="stock.stock_location_customers"/>
|
||||
<field name="in_location_dest_id" ref="stock.stock_location_stock"/>
|
||||
<field name="in_procure_method">make_to_stock</field>
|
||||
<field name="in_to_refund" eval="True"/>
|
||||
<field name="in_require_return" eval="True"/>
|
||||
<field name="so_decrement_order_qty" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -1,470 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * rma_sale
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 15.0+e\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-11-01 18:36+0000\n"
|
||||
"PO-Revision-Date: 2021-11-01 18:36+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: rma_sale
|
||||
#: model_terms:ir.ui.view,arch_db:rma_sale.portal_new_sale_order
|
||||
msgid "- Order Date:"
|
||||
msgstr "Fecha de Pedido"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model_terms:ir.ui.view,arch_db:rma_sale.portal_my_rma_inherit
|
||||
msgid "<em class=\"font-weight-normal text-muted\">RMAs for sale:</em>"
|
||||
msgstr "<em class=\"font-weight-normal text-muted\">RMAs para venta:</em>"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model_terms:ir.ui.view,arch_db:rma_sale.portal_my_rma_inherit
|
||||
msgid "<span>Sale Order</span>"
|
||||
msgstr "<span>Pedido de Venta</span>"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model_terms:ir.ui.view,arch_db:rma_sale.portal_new_sale_order
|
||||
msgid "<strong>Description</strong>"
|
||||
msgstr "<strong>Descripción</strong>"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model_terms:ir.ui.view,arch_db:rma_sale.portal_new_sale_order
|
||||
msgid "<strong>Product</strong>"
|
||||
msgstr "<strong>Producto</strong>"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model_terms:ir.ui.view,arch_db:rma_sale.portal_new_sale_order
|
||||
msgid "<strong>Qty. Delivered</strong>"
|
||||
msgstr "<strong>Cantidad Enviado</strong>"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model_terms:ir.ui.view,arch_db:rma_sale.portal_new_sale_order
|
||||
msgid "<strong>Qty. Ordered</strong>"
|
||||
msgstr "<strong>Cantidad Pedida</strong>"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model_terms:ir.ui.view,arch_db:rma_sale.portal_new_sale_order
|
||||
msgid "<strong>Qty. to Return</strong>"
|
||||
msgstr "<strong>Cantidad a Devolver</strong>"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model_terms:ir.ui.view,arch_db:rma_sale.portal_my_rma_rma_inherit
|
||||
msgid "<strong>Sale Order:</strong>"
|
||||
msgstr "<strong>Pedido de Venta:</strong>"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model_terms:ir.ui.view,arch_db:rma_sale.view_rma_add_lines_form
|
||||
msgid "Add"
|
||||
msgstr "Agregar"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.actions.act_window,name:rma_sale.action_rma_add_lines
|
||||
msgid "Add RMA Lines"
|
||||
msgstr "Agregar Líneas de RMA"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model,name:rma_sale.model_rma_sale_make_lines
|
||||
msgid "Add SO Lines"
|
||||
msgstr "Agregar Líneas de Pedido de Venta"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model_terms:ir.ui.view,arch_db:rma_sale.view_rma_rma_form_sale
|
||||
msgid "Add lines"
|
||||
msgstr "Agregar Líneas"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_template__usage
|
||||
msgid "Applies To"
|
||||
msgstr "Aplica en"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model_terms:ir.ui.view,arch_db:rma_sale.view_rma_add_lines_form
|
||||
msgid "Cancel"
|
||||
msgstr "Cancelar"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_rma__company_id
|
||||
msgid "Company"
|
||||
msgstr "Compañía"
|
||||
|
||||
#. module: rma_sale
|
||||
#: code:addons/rma_sale/models/rma.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Could not reduce all ordered qty:\n"
|
||||
" %s\n"
|
||||
msgstr ""
|
||||
"No se pudo reducir toda la cantidad pedida:\n"
|
||||
" %s\n"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_sale_make_lines__create_uid
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_sale_make_lines_line__create_uid
|
||||
msgid "Created by"
|
||||
msgstr "Creado por"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_sale_make_lines__create_date
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_sale_make_lines_line__create_date
|
||||
msgid "Created on"
|
||||
msgstr "Creado en"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model_terms:ir.ui.view,arch_db:rma_sale.view_rma_template_form_sale
|
||||
msgid "Decrement Ordered Qty"
|
||||
msgstr "Disminuir Cantidad Pedida"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_sale_make_lines_line__qty_delivered
|
||||
msgid "Delivered"
|
||||
msgstr "Enviado"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields,help:rma_sale.field_rma_template__sale_order_warranty
|
||||
msgid ""
|
||||
"Determines if the regular return validity or Warranty validity is used."
|
||||
msgstr ""
|
||||
"Determina si se utiliza la validez de devolución regular o la validez de la "
|
||||
"garantía."
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields,help:rma_sale.field_product_product__rma_sale_warranty_validity
|
||||
#: model:ir.model.fields,help:rma_sale.field_product_template__rma_sale_warranty_validity
|
||||
msgid ""
|
||||
"Determines the number of days from the time of the sale that the product is "
|
||||
"eligible to be returned for warranty claims. 0 (default) will allow the "
|
||||
"product to be returned for an indefinite period of time. A positive number "
|
||||
"will allow the product to be returned up to that number of days. A negative "
|
||||
"number prevents the return of the product."
|
||||
msgstr ""
|
||||
"Determina el número de días a partir del momento de la venta en que el "
|
||||
"producto es elegible para ser devuelto para reclamos de garantía. 0 "
|
||||
"(predeterminado) permitirá devolver el producto por un período de tiempo "
|
||||
"indefinido. Un número positivo permitirá devolver el producto hasta ese "
|
||||
"número de días. Un número negativo impide la devolución del producto."
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields,help:rma_sale.field_product_product__rma_sale_validity
|
||||
#: model:ir.model.fields,help:rma_sale.field_product_template__rma_sale_validity
|
||||
msgid ""
|
||||
"Determines the number of days from the time of the sale that the product is "
|
||||
"eligible to be returned. 0 (default) will allow the product to be returned "
|
||||
"for an indefinite period of time. A positive number will allow the product "
|
||||
"to be returned up to that number of days. A negative number prevents the "
|
||||
"return of the product."
|
||||
msgstr ""
|
||||
"Determina el número de días a partir del momento de la venta en que el producto es "
|
||||
"elegible para ser devuelto. 0 (predeterminado) permitirá devolver el producto por "
|
||||
"un período de tiempo indefinido. Un número positivo permitirá devolver el producto "
|
||||
"hasta ese número de días. Un número negativo impide la devolución del producto."
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_sale_make_lines__display_name
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_sale_make_lines_line__display_name
|
||||
msgid "Display Name"
|
||||
msgstr "Nombre para mostrar"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields.selection,name:rma_sale.selection__rma_sale_make_lines_line__validity__valid
|
||||
msgid "Eligible"
|
||||
msgstr "Elegible"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model_terms:ir.ui.view,arch_db:rma_sale.product_normal_form_view_inherit
|
||||
#: model_terms:ir.ui.view,arch_db:rma_sale.product_template_only_form_view_inherit
|
||||
msgid "Eligible Days"
|
||||
msgstr "Días Elegibles"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields.selection,name:rma_sale.selection__rma_sale_make_lines_line__validity__expired
|
||||
#: model_terms:ir.ui.view,arch_db:rma_sale.portal_new_sale_order
|
||||
msgid "Expired"
|
||||
msgstr "Expirado"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_sale_make_lines__id
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_sale_make_lines_line__id
|
||||
msgid "ID"
|
||||
msgstr "ID"
|
||||
|
||||
#. module: rma_sale
|
||||
#: code:addons/rma_sale/models/rma.py:0
|
||||
#, python-format
|
||||
msgid "Invalid quantity."
|
||||
msgstr "Cantidad Inválida"
|
||||
|
||||
#. module: rma_sale
|
||||
#: code:addons/rma_sale/models/rma.py:0
|
||||
#, python-format
|
||||
msgid "Invalid user for sale order."
|
||||
msgstr "Usuario Inválido para el Pedido de Venta"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_sale_make_lines_line__qty_invoiced
|
||||
msgid "Invoiced"
|
||||
msgstr "Facturado"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_sale_make_lines____last_update
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_sale_make_lines_line____last_update
|
||||
msgid "Last Modified on"
|
||||
msgstr "Última Modificación el"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_sale_make_lines__write_uid
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_sale_make_lines_line__write_uid
|
||||
msgid "Last Updated by"
|
||||
msgstr "Última Actualización por"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_sale_make_lines__write_date
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_sale_make_lines_line__write_date
|
||||
msgid "Last Updated on"
|
||||
msgstr "Última Actualización el"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_sale_make_lines__line_ids
|
||||
msgid "Lines"
|
||||
msgstr "Líneas"
|
||||
|
||||
#. module: rma_sale
|
||||
#: code:addons/rma_sale/models/rma.py:0
|
||||
#, python-format
|
||||
msgid "Missing product quantity."
|
||||
msgstr "Falta la cantidad del producto."
|
||||
|
||||
#. module: rma_sale
|
||||
#: code:addons/rma_sale/models/rma.py:0
|
||||
#, python-format
|
||||
msgid "New"
|
||||
msgstr "Nuevo"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model_terms:ir.ui.view,arch_db:rma_sale.portal_new_sale_order
|
||||
msgid "No Sale Orders to choose from."
|
||||
msgstr "No hay pedidos de ventas para elegir"
|
||||
|
||||
#. module: rma_sale
|
||||
#: code:addons/rma_sale/models/rma.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"No eligible pickings were found to duplicate (you can only return products "
|
||||
"from the same initial picking)."
|
||||
msgstr ""
|
||||
"No se encontraron Picking elegibles para duplicar (Solo se puede devolver "
|
||||
"productos de la misma Picking inicial)"
|
||||
|
||||
#. module: rma_sale
|
||||
#: code:addons/rma_sale/models/rma.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"No eligible pickings were found to return (you can only return products from"
|
||||
" the same initial picking)."
|
||||
msgstr ""
|
||||
"No se encontraron Picking elegibles para devolver (Solo se puede devolver "
|
||||
"productos de la misma Picking inicial)"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields.selection,name:rma_sale.selection__rma_sale_make_lines_line__validity__
|
||||
#: model_terms:ir.ui.view,arch_db:rma_sale.portal_new_sale_order
|
||||
msgid "Not Eligible"
|
||||
msgstr "No es elegible"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_rma__sale_order_rma_count
|
||||
msgid "Number of RMAs for this Sale Order"
|
||||
msgstr "Número de RMAs para este pedido de venta"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_sale_make_lines_line__qty_ordered
|
||||
msgid "Ordered"
|
||||
msgstr "Pedido"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_sale_make_lines_line__product_id
|
||||
msgid "Product"
|
||||
msgstr "Producto"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model_terms:ir.ui.view,arch_db:rma_sale.portal_new_sale_order
|
||||
msgid "Product Image"
|
||||
msgstr "Imagen del Producto"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model,name:rma_sale.model_product_template
|
||||
msgid "Product Template"
|
||||
msgstr "Plantilla de producto"
|
||||
|
||||
#. module: rma_sale
|
||||
#: code:addons/rma_sale/models/rma.py:0
|
||||
#, python-format
|
||||
msgid "Product is not eligible for return."
|
||||
msgstr "El producto no es elegible para devolver"
|
||||
|
||||
#. module: rma_sale
|
||||
#: code:addons/rma_sale/models/rma.py:0
|
||||
#, python-format
|
||||
msgid "Product is past the return period."
|
||||
msgstr "El producto ha pasado el periodo de devolución"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_sale_make_lines_line__product_uom_qty
|
||||
msgid "QTY"
|
||||
msgstr "Cantidad"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model,name:rma_sale.model_rma_rma
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_sale_make_lines__rma_id
|
||||
#: model:ir.ui.menu,name:rma_sale.menu_action_sales_rma_form
|
||||
#: model_terms:ir.ui.view,arch_db:rma_sale.view_order_form_inherit
|
||||
msgid "RMA"
|
||||
msgstr "RMA"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_sale_order__rma_count
|
||||
msgid "RMA Count"
|
||||
msgstr "Recuento de RMA"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_product_product__rma_sale_warranty_validity
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_product_template__rma_sale_warranty_validity
|
||||
msgid "RMA Eligible Days (Sale Warranty)"
|
||||
msgstr "Días elegibles para la RMA (Garantía de Venta)"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_product_product__rma_sale_validity
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_product_template__rma_sale_validity
|
||||
msgid "RMA Eligible Days (Sale)"
|
||||
msgstr "Días Elegibles para la RMA (Ventas)"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model,name:rma_sale.model_rma_sale_make_lines_line
|
||||
msgid "RMA Sale Make Lines Line"
|
||||
msgstr "Venta de RMA Hace líneas línea"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model_terms:ir.ui.view,arch_db:rma_sale.product_normal_form_view_inherit
|
||||
#: model_terms:ir.ui.view,arch_db:rma_sale.product_template_only_form_view_inherit
|
||||
msgid "RMA Sales"
|
||||
msgstr "Ventas de RMA"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.ui.menu,name:rma_sale.menu_action_sales_rma_tag_form
|
||||
msgid "RMA Tag"
|
||||
msgstr "Etiqueta de RMA"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model,name:rma_sale.model_rma_template
|
||||
msgid "RMA Template"
|
||||
msgstr "Plantilla del RMA"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.ui.menu,name:rma_sale.menu_action_sales_rma_template_form
|
||||
msgid "RMA Templates"
|
||||
msgstr "Plantillas del RMA"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_sale_order__rma_ids
|
||||
msgid "RMAs"
|
||||
msgstr "RMAs"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_sale_make_lines_line__rma_make_lines_id
|
||||
msgid "Rma Make Lines"
|
||||
msgstr "RMA crea líneas"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_template__so_decrement_order_qty
|
||||
msgid "SO Decrement Ordered Qty."
|
||||
msgstr "Disminuir cantidad pedida de la Pedida de Venta"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model_terms:ir.ui.view,arch_db:rma_sale.view_rma_rma_form_sale
|
||||
msgid "SO RMAs"
|
||||
msgstr "RMAs de Pedido de Ventas"
|
||||
|
||||
#. module: rma_sale
|
||||
#: code:addons/rma_sale/controllers/portal.py:0
|
||||
#: code:addons/rma_sale/controllers/portal.py:0
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_rma__sale_order_id
|
||||
#: model:ir.model.fields.selection,name:rma_sale.selection__rma_template__usage__sale_order
|
||||
#, python-format
|
||||
msgid "Sale Order"
|
||||
msgstr "Pedido de Venta"
|
||||
|
||||
#. module: rma_sale
|
||||
#: code:addons/rma_sale/models/rma.py:0
|
||||
#, python-format
|
||||
msgid "Sale Order RMAs"
|
||||
msgstr "RMAs de Pedido de Ventas"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_template__sale_order_warranty
|
||||
msgid "Sale Order Warranty"
|
||||
msgstr "Garantía de Pedido de Venta"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model,name:rma_sale.model_sale_order
|
||||
msgid "Sales Order"
|
||||
msgstr "Pedido de venta"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model,name:rma_sale.model_sale_order_line
|
||||
msgid "Sales Order Line"
|
||||
msgstr "Línea de Pedido de Venta"
|
||||
|
||||
#. module: rma_sale
|
||||
#: code:addons/rma_sale/controllers/portal.py:0
|
||||
#, python-format
|
||||
msgid "Search Sale Order"
|
||||
msgstr "Buscar Pedido de Venta"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_sale_make_lines_line__product_uom_id
|
||||
msgid "UOM"
|
||||
msgstr "Unidad de Medida"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields,field_description:rma_sale.field_rma_sale_make_lines_line__validity
|
||||
msgid "Validity"
|
||||
msgstr "Validez"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model_terms:ir.ui.view,arch_db:rma_sale.view_rma_template_form_sale
|
||||
msgid "Warranty"
|
||||
msgstr "Garantía"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model_terms:ir.ui.view,arch_db:rma_sale.product_normal_form_view_inherit
|
||||
#: model_terms:ir.ui.view,arch_db:rma_sale.product_template_only_form_view_inherit
|
||||
msgid "Warranty Eligible Days"
|
||||
msgstr "Días Elegibles para la Garantía"
|
||||
|
||||
#. module: rma_sale
|
||||
#: model:ir.model.fields,help:rma_sale.field_rma_template__so_decrement_order_qty
|
||||
msgid ""
|
||||
"When completing the RMA, the Ordered Quantity will be decremented by the RMA"
|
||||
" qty."
|
||||
msgstr ""
|
||||
"Cuando se completa un RMA, la Cantidad Pedido será disminuida por la "
|
||||
"cantidad del RMA"
|
||||
|
||||
#. module: rma_sale
|
||||
#: code:addons/rma_sale/models/rma.py:0 code:addons/rma_sale/models/rma.py:0
|
||||
#, python-format
|
||||
msgid "You have no lines with positive quantity."
|
||||
msgstr "Usted no tiene líneas con una cantidad positiva"
|
||||
|
||||
#. module: rma_sale
|
||||
#: code:addons/rma_sale/models/rma.py:0 code:addons/rma_sale/models/rma.py:0
|
||||
#, python-format
|
||||
msgid "You must have a sale order for this RMA."
|
||||
msgstr "Usted debe tener un pedido de venta para este RMA"
|
||||
@@ -1,31 +0,0 @@
|
||||
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
|
||||
|
||||
import odoo
|
||||
|
||||
|
||||
def migrate(cr, version):
|
||||
"""
|
||||
Update sale_line_id on existing RMA lines to allow completing the RMA
|
||||
"""
|
||||
cr.execute("""
|
||||
UPDATE rma_line AS rl
|
||||
SET sale_line_id = order_line.id
|
||||
FROM (
|
||||
SELECT rma_line.id, rma_line.rma_id, rma_line.product_id,
|
||||
rank() OVER (PARTITION BY rma_line.rma_id, rma_line.product_id ORDER BY rma_line.id) AS rline
|
||||
FROM rma_line
|
||||
WHERE rma_line.sale_line_id IS NULL
|
||||
) AS rma_line
|
||||
INNER JOIN rma_rma rma
|
||||
ON rma.id = rma_line.rma_id
|
||||
INNER JOIN (
|
||||
SELECT ol.id, ol.order_id, ol.product_id,
|
||||
rank() OVER (PARTITION BY ol.order_id, ol.product_id ORDER BY ol.id) AS oline
|
||||
FROM sale_order_line ol
|
||||
) AS order_line
|
||||
ON order_line.order_id = rma.sale_order_id
|
||||
AND order_line.product_id = rma_line.product_id
|
||||
AND order_line.oline = rma_line.rline
|
||||
WHERE rma.sale_order_id IS NOT NULL
|
||||
AND rma_line.id = rl.id
|
||||
""")
|
||||
@@ -1,5 +0,0 @@
|
||||
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
|
||||
|
||||
from . import product
|
||||
from . import rma
|
||||
from . import sale
|
||||
@@ -1,26 +0,0 @@
|
||||
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ProductTemplate(models.Model):
|
||||
_inherit = 'product.template'
|
||||
|
||||
rma_sale_validity = fields.Integer(string='RMA Eligible Days (Sale)',
|
||||
help='Determines the number of days from the time '
|
||||
'of the sale that the product is eligible to '
|
||||
'be returned. 0 (default) will allow the product '
|
||||
'to be returned for an indefinite period of time. '
|
||||
'A positive number will allow the product to be '
|
||||
'returned up to that number of days. A negative '
|
||||
'number prevents the return of the product.')
|
||||
|
||||
rma_sale_warranty_validity = fields.Integer(string='RMA Eligible Days (Sale Warranty)',
|
||||
help='Determines the number of days from the time '
|
||||
'of the sale that the product is eligible to '
|
||||
'be returned for warranty claims. '
|
||||
'0 (default) will allow the product to be '
|
||||
'returned for an indefinite period of time. '
|
||||
'A positive number will allow the product to be '
|
||||
'returned up to that number of days. A negative '
|
||||
'number prevents the return of the product.')
|
||||
@@ -1,311 +0,0 @@
|
||||
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from datetime import timedelta
|
||||
|
||||
|
||||
class SaleOrderLine(models.Model):
|
||||
_inherit = 'sale.order.line'
|
||||
|
||||
def _get_protected_fields(self):
|
||||
res = super(SaleOrderLine, self)._get_protected_fields()
|
||||
context = self._context or {}
|
||||
if context.get('rma_done'):
|
||||
if 'product_uom_qty' in res:
|
||||
res.remove('product_uom_qty')
|
||||
# technically used by product_cores to update related core pieces
|
||||
if 'product_id' in res:
|
||||
res.remove('product_id')
|
||||
if 'product_uom' in res:
|
||||
res.remove('product_uom')
|
||||
return res
|
||||
|
||||
|
||||
class RMATemplate(models.Model):
|
||||
_inherit = 'rma.template'
|
||||
|
||||
usage = fields.Selection(selection_add=[('sale_order', 'Sale Order')])
|
||||
sale_order_warranty = fields.Boolean(string='Sale Order Warranty',
|
||||
help='Determines if the regular return validity or '
|
||||
'Warranty validity is used.')
|
||||
so_decrement_order_qty = fields.Boolean(string='SO Decrement Ordered Qty.',
|
||||
help='When completing the RMA, the Ordered Quantity will be decremented by '
|
||||
'the RMA qty.')
|
||||
|
||||
def _portal_try_create(self, request_user, res_id, **kw):
|
||||
if self.usage == 'sale_order':
|
||||
prefix = 'line_'
|
||||
line_map = {int(key[len(prefix):]): float(kw[key]) for key in kw if key.find(prefix) == 0 and kw[key]}
|
||||
if line_map:
|
||||
sale_order = self.env['sale.order'].with_user(request_user).browse(res_id)
|
||||
if not sale_order.exists():
|
||||
raise ValidationError(_('Invalid user for sale order.'))
|
||||
lines = []
|
||||
sale_order_sudo = sale_order.sudo()
|
||||
for line_id, qty in line_map.items():
|
||||
line = sale_order_sudo.order_line.filtered(lambda l: l.id == line_id)
|
||||
if line:
|
||||
if not qty:
|
||||
continue
|
||||
if qty < 0.0 or line.qty_delivered < qty:
|
||||
raise ValidationError(_('Invalid quantity.'))
|
||||
validity = self._rma_sale_line_validity(line)
|
||||
if not validity:
|
||||
raise ValidationError(_('Product is not eligible for return.'))
|
||||
if validity == 'expired':
|
||||
raise ValidationError(_('Product is past the return period.'))
|
||||
lines.append((0, 0, {
|
||||
'product_id': line.product_id.id,
|
||||
'sale_line_id': line.id,
|
||||
'product_uom_id': line.product_uom.id,
|
||||
'product_uom_qty': qty,
|
||||
}))
|
||||
if not lines:
|
||||
raise ValidationError(_('Missing product quantity.'))
|
||||
rma = self.env['rma.rma'].create({
|
||||
'name': _('New'),
|
||||
'sale_order_id': sale_order.id,
|
||||
'template_id': self.id,
|
||||
'partner_id': sale_order.partner_id.id,
|
||||
'partner_shipping_id': sale_order.partner_shipping_id.id,
|
||||
'lines': lines,
|
||||
})
|
||||
return rma
|
||||
return super(RMATemplate, self)._portal_try_create(request_user, res_id, **kw)
|
||||
|
||||
def _portal_template(self, res_id=None):
|
||||
if self.usage == 'sale_order':
|
||||
return 'rma_sale.portal_new_sale_order'
|
||||
return super(RMATemplate, self)._portal_template(res_id=res_id)
|
||||
|
||||
def _portal_values(self, request_user, res_id=None):
|
||||
if self.usage == 'sale_order':
|
||||
sale_orders = None
|
||||
sale_order = None
|
||||
if res_id:
|
||||
sale_order = self.env['sale.order'].with_user(request_user).browse(res_id)
|
||||
if sale_order:
|
||||
sale_order = sale_order.sudo()
|
||||
else:
|
||||
sale_orders = self.env['sale.order'].with_user(request_user).search([], limit=100)
|
||||
return {
|
||||
'rma_template': self,
|
||||
'rma_sale_orders': sale_orders,
|
||||
'rma_sale_order': sale_order,
|
||||
}
|
||||
return super(RMATemplate, self)._portal_values(request_user, res_id=res_id)
|
||||
|
||||
def _rma_sale_line_validity(self, so_line):
|
||||
if self.sale_order_warranty:
|
||||
validity_days = so_line.product_id.rma_sale_warranty_validity
|
||||
else:
|
||||
validity_days = so_line.product_id.rma_sale_validity
|
||||
if validity_days < 0:
|
||||
return ''
|
||||
elif validity_days > 0:
|
||||
sale_date = so_line.order_id.date_order
|
||||
now = fields.Datetime.now()
|
||||
if sale_date < (now - timedelta(days=validity_days)):
|
||||
return 'expired'
|
||||
return 'valid'
|
||||
|
||||
def _values_for_in_picking(self, rma):
|
||||
values = super()._values_for_in_picking(rma)
|
||||
if self.usage == 'sale_order':
|
||||
values['move_lines'] = [(0, None, {
|
||||
'name': rma.name + ' IN: ' + l.product_id.name_get()[0][1],
|
||||
'product_id': l.product_id.id,
|
||||
'product_uom_qty': l.product_uom_qty,
|
||||
'product_uom': l.product_uom_id.id,
|
||||
'procure_method': self.in_procure_method,
|
||||
'to_refund': self.in_to_refund,
|
||||
'location_id': self.in_location_id.id,
|
||||
'location_dest_id': self.in_location_dest_id.id,
|
||||
'sale_line_id': l.sale_line_id.id,
|
||||
}) for l in rma.lines.filtered(lambda l: l.product_id.type != 'service')]
|
||||
return values
|
||||
|
||||
def _values_for_out_picking(self, rma):
|
||||
values = super()._values_for_out_picking(rma)
|
||||
if self.usage == 'sale_order':
|
||||
values['move_lines'] = [(0, None, {
|
||||
'name': rma.name + ' OUT: ' + l.product_id.name_get()[0][1],
|
||||
'product_id': l.product_id.id,
|
||||
'product_uom_qty': l.product_uom_qty,
|
||||
'product_uom': l.product_uom_id.id,
|
||||
'procure_method': self.out_procure_method,
|
||||
'to_refund': self.out_to_refund,
|
||||
'location_id': self.out_location_id.id,
|
||||
'location_dest_id': self.out_location_dest_id.id,
|
||||
'sale_line_id': l.sale_line_id.id,
|
||||
}) for l in rma.lines.filtered(lambda l: l.product_id.type != 'service')]
|
||||
return values
|
||||
|
||||
|
||||
class RMA(models.Model):
|
||||
_inherit = 'rma.rma'
|
||||
|
||||
sale_order_id = fields.Many2one('sale.order', string='Sale Order')
|
||||
sale_order_rma_count = fields.Integer('Number of RMAs for this Sale Order', compute='_compute_sale_order_rma_count')
|
||||
company_id = fields.Many2one('res.company', 'Company',
|
||||
default=lambda self: self.env.company)
|
||||
|
||||
@api.depends('sale_order_id')
|
||||
def _compute_sale_order_rma_count(self):
|
||||
for rma in self:
|
||||
if rma.sale_order_id:
|
||||
rma_data = self.read_group([('sale_order_id', '=', rma.sale_order_id.id), ('state', '!=', 'cancel')],
|
||||
['sale_order_id'], ['sale_order_id'])
|
||||
if rma_data:
|
||||
rma.sale_order_rma_count = rma_data[0]['sale_order_id_count']
|
||||
else:
|
||||
rma.sale_order_rma_count = 0.0
|
||||
else:
|
||||
rma.sale_order_rma_count = 0.0
|
||||
|
||||
def open_sale_order_rmas(self):
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': _('Sale Order RMAs'),
|
||||
'res_model': 'rma.rma',
|
||||
'view_mode': 'tree,form',
|
||||
'context': {'search_default_sale_order_id': self[0].sale_order_id.id}
|
||||
}
|
||||
|
||||
@api.onchange('template_usage')
|
||||
def _onchange_template_usage(self):
|
||||
res = super(RMA, self)._onchange_template_usage()
|
||||
for rma in self.filtered(lambda rma: rma.template_usage != 'sale_order'):
|
||||
rma.sale_order_id = False
|
||||
return res
|
||||
|
||||
@api.onchange('sale_order_id')
|
||||
def _onchange_sale_order_id(self):
|
||||
for rma in self.filtered(lambda rma: rma.sale_order_id):
|
||||
rma.partner_id = rma.sale_order_id.partner_id
|
||||
rma.partner_shipping_id = rma.sale_order_id.partner_shipping_id
|
||||
|
||||
def action_done(self):
|
||||
res = super(RMA, self).action_done()
|
||||
res2 = self._so_action_done()
|
||||
if isinstance(res, dict) and isinstance(res2, dict):
|
||||
if 'warning' in res and 'warning' in res2:
|
||||
res['warning'] = '\n'.join([res['warning'], res2['warning']])
|
||||
return res
|
||||
if 'warning' in res2:
|
||||
res['warning'] = res2['warning']
|
||||
return res
|
||||
elif isinstance(res2, dict):
|
||||
return res2
|
||||
return res
|
||||
|
||||
def _so_action_done(self):
|
||||
warnings = []
|
||||
for rma in self:
|
||||
if rma.template_id.so_decrement_order_qty:
|
||||
for rma_line in rma.lines:
|
||||
sale_line = rma_line.sale_line_id
|
||||
if sale_line:
|
||||
sale_line_qty = sale_line.product_uom_qty - rma_line.product_uom_qty
|
||||
if sale_line_qty < 0:
|
||||
warnings.append((rma, rma.sale_order_id, rma_line, abs(sale_line_qty)))
|
||||
sale_line_qty = 0
|
||||
sale_line.with_context(rma_done=True).write({'product_uom_qty': sale_line_qty})
|
||||
# Try to invoice if we don't already have an invoice (e.g. from resetting to draft)
|
||||
if rma.sale_order_id and rma.template_id.invoice_done and not rma.invoice_ids:
|
||||
rma.invoice_ids |= rma._sale_invoice_done(rma.sale_order_id)
|
||||
if warnings:
|
||||
return {'warning': _('Could not reduce all ordered qty:\n %s' % '\n'.join(
|
||||
['%s %s %s : %s' % (w[0].name, w[1].name, w[2].product_id.display_name, w[3]) for w in warnings]))}
|
||||
return True
|
||||
|
||||
def _sale_invoice_done(self, sale_orders):
|
||||
original_invoices = sale_orders.mapped('invoice_ids')
|
||||
try:
|
||||
wiz = self.env['sale.advance.payment.inv'].with_context(active_ids=sale_orders.ids).create({})
|
||||
wiz.create_invoices()
|
||||
except UserError:
|
||||
pass
|
||||
return sale_orders.mapped('invoice_ids') - original_invoices
|
||||
|
||||
def _invoice_values_sale_order(self):
|
||||
# the RMA invoice API will not be used as invoicing will happen at the SO level
|
||||
return False
|
||||
|
||||
def action_add_so_lines(self):
|
||||
make_line_obj = self.env['rma.sale.make.lines']
|
||||
for rma in self:
|
||||
lines = make_line_obj.create({
|
||||
'rma_id': rma.id,
|
||||
})
|
||||
action = self.env['ir.actions.act_window']._for_xml_id('rma_sale.action_rma_add_lines')
|
||||
action['res_id'] = lines.id
|
||||
return action
|
||||
|
||||
def _create_in_picking_sale_order(self):
|
||||
if not self.sale_order_id:
|
||||
raise UserError(_('You must have a sale order for this RMA.'))
|
||||
if not self.template_id.in_require_return:
|
||||
group_id = self.sale_order_id.procurement_group_id.id if self.sale_order_id.procurement_group_id else 0
|
||||
sale_id = self.sale_order_id.id
|
||||
values = self.template_id._values_for_in_picking(self)
|
||||
update = {'sale_id': sale_id, 'group_id': group_id}
|
||||
update_lines = {'to_refund': self.template_id.in_to_refund, 'group_id': group_id}
|
||||
return self._picking_from_values(values, update, update_lines)
|
||||
|
||||
lines = self.lines.filtered(lambda l: l.product_uom_qty >= 1 and l.product_id.type != 'service')
|
||||
if not lines:
|
||||
raise UserError(_('You have no lines with positive quantity.'))
|
||||
product_ids = lines.mapped('product_id.id')
|
||||
|
||||
old_picking = self._find_candidate_return_picking(product_ids, self.sale_order_id.picking_ids, self.template_id.in_location_id.id)
|
||||
if not old_picking:
|
||||
raise UserError(_('No eligible pickings were found to return (you can only return products from the same initial picking).'))
|
||||
|
||||
new_picking = self._new_in_picking(old_picking)
|
||||
self._new_in_moves(old_picking, new_picking, {})
|
||||
return new_picking
|
||||
|
||||
def _create_out_picking_sale_order(self):
|
||||
if not self.sale_order_id:
|
||||
raise UserError(_('You must have a sale order for this RMA.'))
|
||||
if not self.template_id.out_require_return:
|
||||
group_id = self.sale_order_id.procurement_group_id.id if self.sale_order_id.procurement_group_id else 0
|
||||
sale_id = self.sale_order_id.id
|
||||
values = self.template_id._values_for_out_picking(self)
|
||||
update = {'sale_id': sale_id, 'group_id': group_id}
|
||||
update_lines = {'group_id': group_id}
|
||||
return self._picking_from_values(values, update, update_lines)
|
||||
|
||||
lines = self.lines.filtered(lambda l: l.product_uom_qty >= 1 and l.product_id.type != 'service')
|
||||
if not lines:
|
||||
raise UserError(_('You have no lines with positive quantity.'))
|
||||
product_ids = lines.mapped('product_id.id')
|
||||
|
||||
old_picking = self._find_candidate_return_picking(product_ids, self.sale_order_id.picking_ids, self.template_id.out_location_dest_id.id)
|
||||
if not old_picking:
|
||||
raise UserError(_(
|
||||
'No eligible pickings were found to duplicate (you can only return products from the same initial picking).'))
|
||||
|
||||
new_picking = self._new_out_picking(old_picking)
|
||||
self._new_out_moves(old_picking, new_picking, {})
|
||||
return new_picking
|
||||
|
||||
def _get_old_move(self, old_picking, line):
|
||||
if self.template_usage != 'sale_order':
|
||||
return super(RMA, self)._get_old_move(old_picking, line)
|
||||
return old_picking.move_lines.filtered(
|
||||
lambda ol: ol.state == 'done' and
|
||||
ol.product_id == line.product_id and
|
||||
ol.sale_line_id == line.sale_line_id
|
||||
)[0]
|
||||
|
||||
|
||||
class RMALine(models.Model):
|
||||
_inherit = 'rma.line'
|
||||
|
||||
sale_line_id = fields.Many2one('sale.order.line', 'Sale Order Line')
|
||||
sale_line_product_uom_qty = fields.Float('Ordered', related='sale_line_id.product_uom_qty')
|
||||
sale_line_qty_delivered = fields.Float('Delivered', related='sale_line_id.qty_delivered')
|
||||
sale_line_qty_invoiced = fields.Float('Invoiced', related='sale_line_id.qty_invoiced')
|
||||
@@ -1,15 +0,0 @@
|
||||
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class SaleOrder(models.Model):
|
||||
_inherit = 'sale.order'
|
||||
|
||||
rma_count = fields.Integer(string='RMA Count', compute='_compute_rma_count', compute_sudo=True)
|
||||
rma_ids = fields.One2many('rma.rma', 'sale_order_id', string='RMAs')
|
||||
|
||||
@api.depends('rma_ids')
|
||||
def _compute_rma_count(self):
|
||||
for so in self:
|
||||
so.rma_count = len(so.rma_ids)
|
||||
@@ -1,9 +0,0 @@
|
||||
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
|
||||
"manage_rma_sale","manage rma","rma.model_rma_rma","sales_team.group_sale_salesman",1,1,1,1
|
||||
"manage_rma_line_sale","manage rma line","rma.model_rma_line","sales_team.group_sale_salesman",1,1,1,1
|
||||
"manage_rma_template_sale","manage rma template","rma.model_rma_template","sales_team.group_sale_manager",1,1,1,1
|
||||
"manage_rma_tag_sale","manage rma tag","rma.model_rma_tag","sales_team.group_sale_manager",1,1,1,1
|
||||
"access_rma_template_sale","access rma template","rma.model_rma_template","sales_team.group_sale_salesman",1,1,0,0
|
||||
"access_rma_tag_sale","access rma tag","rma.model_rma_tag","sales_team.group_sale_salesman",1,0,0,0
|
||||
"access_rma_sale_make_lines","access rma.sale.make.lines","rma_sale.model_rma_sale_make_lines","sales_team.group_sale_salesman",1,1,1,1
|
||||
"access_rma_sale_make_lines_line","access rma.sale.make.lines.line","rma_sale.model_rma_sale_make_lines_line","sales_team.group_sale_salesman",1,1,1,1
|
||||
|
@@ -1,3 +0,0 @@
|
||||
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
|
||||
|
||||
from . import test_rma
|
||||
@@ -1,498 +0,0 @@
|
||||
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
|
||||
|
||||
from odoo.addons.rma.tests.test_rma import TestRMA
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from datetime import timedelta
|
||||
|
||||
|
||||
class TestRMASale(TestRMA):
|
||||
|
||||
def setUp(self):
|
||||
super(TestRMASale, self).setUp()
|
||||
self.template_sale_return = self.env.ref('rma_sale.template_sale_return')
|
||||
# Make it possible to "see all sale orders", but not be a manager (as managers can RMA ineligible lines)
|
||||
self.user1.groups_id += self.env.ref('sales_team.group_sale_salesman_all_leads')
|
||||
|
||||
def test_20_sale_return(self):
|
||||
self.template_sale_return.write({
|
||||
'usage': 'sale_order',
|
||||
'invoice_done': True,
|
||||
})
|
||||
self.product1.write({
|
||||
'type': 'product',
|
||||
'invoice_policy': 'delivery',
|
||||
'tracking': 'serial',
|
||||
})
|
||||
order = self.env['sale.order'].create({
|
||||
'partner_id': self.partner1.id,
|
||||
'partner_invoice_id': self.partner1.id,
|
||||
'partner_shipping_id': self.partner1.id,
|
||||
'order_line': [(0, 0, {
|
||||
'product_id': self.product1.id,
|
||||
'product_uom_qty': 1.0,
|
||||
'product_uom': self.product1.uom_id.id,
|
||||
'price_unit': 10.0,
|
||||
})]
|
||||
})
|
||||
order.action_confirm()
|
||||
self.assertTrue(order.state in ('sale', 'done'))
|
||||
self.assertEqual(len(order.picking_ids), 1, 'Tests only run with single stage delivery.')
|
||||
|
||||
# Try to RMA item not delivered yet
|
||||
rma = self.env['rma.rma'].create({
|
||||
'template_id': self.template_sale_return.id,
|
||||
'partner_id': self.partner1.id,
|
||||
'partner_shipping_id': self.partner1.id,
|
||||
'sale_order_id': order.id,
|
||||
})
|
||||
self.assertEqual(rma.state, 'draft')
|
||||
# Do not allow return.
|
||||
self.product1.rma_sale_validity = -1
|
||||
wizard = self.env['rma.sale.make.lines'].with_user(self.user1).create({'rma_id': rma.id})
|
||||
self.assertEqual(wizard.line_ids.qty_delivered, 0.0)
|
||||
wizard.line_ids.product_uom_qty = 1.0
|
||||
|
||||
with self.assertRaises(UserError):
|
||||
wizard.add_lines()
|
||||
|
||||
# Allows returns, but not forever
|
||||
self.product1.rma_sale_validity = 5
|
||||
original_date_order = order.date_order
|
||||
order.write({'date_order': original_date_order - timedelta(days=6)})
|
||||
wizard = self.env['rma.sale.make.lines'].with_user(self.user1).create({'rma_id': rma.id})
|
||||
self.assertEqual(wizard.line_ids.qty_delivered, 0.0)
|
||||
wizard.line_ids.product_uom_qty = 1.0
|
||||
with self.assertRaises(UserError):
|
||||
wizard.add_lines()
|
||||
|
||||
# Allows returns due to date
|
||||
order.write({'date_order': original_date_order})
|
||||
wizard = self.env['rma.sale.make.lines'].with_user(self.user1).create({'rma_id': rma.id})
|
||||
self.assertEqual(wizard.line_ids.qty_delivered, 0.0)
|
||||
wizard.line_ids.product_uom_qty = 1.0
|
||||
wizard.add_lines()
|
||||
|
||||
self.assertEqual(len(rma.lines), 1)
|
||||
with self.assertRaises(UserError):
|
||||
rma.action_confirm()
|
||||
|
||||
order.picking_ids.action_assign()
|
||||
if not order.picking_ids.move_line_ids:
|
||||
p = order.picking_ids
|
||||
sm = p.move_lines
|
||||
order.picking_ids.write({
|
||||
'move_line_ids': [(0, 0, {
|
||||
'picking_id': p.id,
|
||||
'move_id': sm.id,
|
||||
'product_id': sm.product_id.id,
|
||||
'product_uom_id': sm.product_uom.id,
|
||||
'location_id': sm.location_id.id,
|
||||
'location_dest_id': sm.location_dest_id.id,
|
||||
})]
|
||||
})
|
||||
pack_opt = order.picking_ids.move_line_ids[0]
|
||||
lot = self.env['stock.production.lot'].create({
|
||||
'product_id': self.product1.id,
|
||||
'name': 'X100',
|
||||
'product_uom_id': self.product1.uom_id.id,
|
||||
'company_id': self.env.user.company_id.id,
|
||||
})
|
||||
pack_opt.qty_done = 1.0
|
||||
pack_opt.lot_id = lot
|
||||
order.picking_ids.button_validate()
|
||||
self.assertEqual(order.picking_ids.state, 'done')
|
||||
|
||||
# Invoice order so that the return is invoicable
|
||||
wiz = self.env['sale.advance.payment.inv'].with_context(active_ids=order.ids).create({})
|
||||
wiz.create_invoices()
|
||||
# Odoo 13 Not flushing the order here will cause delivered_qty to be incorrect later
|
||||
order.flush()
|
||||
self.assertTrue(order.invoice_ids, 'Order did not create an invoice.')
|
||||
|
||||
wizard = self.env['rma.sale.make.lines'].create({
|
||||
'rma_id': rma.id,
|
||||
})
|
||||
self.assertEqual(wizard.line_ids.qty_delivered, 1.0)
|
||||
|
||||
# Confirm RMA
|
||||
rma.action_confirm()
|
||||
self.assertEqual(rma.in_picking_id.state, 'assigned')
|
||||
pack_opt = rma.in_picking_id.move_line_ids[0]
|
||||
|
||||
with self.assertRaises(UserError):
|
||||
rma.action_done()
|
||||
|
||||
pack_opt.lot_id = lot
|
||||
pack_opt.qty_done = 1.0
|
||||
rma.in_picking_id.button_validate()
|
||||
self.assertEqual(rma.in_picking_id.move_lines.sale_line_id, order.order_line)
|
||||
self.assertEqual(rma.in_picking_id.state, 'done')
|
||||
for move in order.order_line.mapped('move_ids'):
|
||||
# Additional testing like this may not be needed in the future. Was added troubleshooting new 13 ORM
|
||||
self.assertEqual(move.state, 'done', 'Move not done ' + str(move.name))
|
||||
self.assertEqual(order.order_line.qty_delivered, 0.0)
|
||||
rma.action_done()
|
||||
self.assertEqual(order.order_line.qty_delivered, 0.0)
|
||||
|
||||
# Finishing the RMA should have made an invoice
|
||||
self.assertTrue(rma.invoice_ids, 'Finishing RMA did not create an invoice(s).')
|
||||
|
||||
# Test Ordered Qty was decremented.
|
||||
self.assertEqual(order.order_line.product_uom_qty, 0.0)
|
||||
self.assertEqual(order.order_line.qty_delivered, 0.0)
|
||||
|
||||
# Make another RMA for the same sale order
|
||||
rma2 = self.env['rma.rma'].create({
|
||||
'template_id': self.template_sale_return.id,
|
||||
'partner_id': self.partner1.id,
|
||||
'partner_shipping_id': self.partner1.id,
|
||||
'sale_order_id': order.id,
|
||||
})
|
||||
wizard = self.env['rma.sale.make.lines'].create({
|
||||
'rma_id': rma2.id,
|
||||
})
|
||||
# The First completed RMA will have "un-delivered" it for invoicing purposes.
|
||||
self.assertEqual(wizard.line_ids.qty_delivered, 0.0)
|
||||
wizard.line_ids.product_uom_qty = 1.0
|
||||
wizard.add_lines()
|
||||
self.assertEqual(len(rma2.lines), 1)
|
||||
|
||||
rma2.action_confirm()
|
||||
|
||||
# In Odoo 10, this would not have been able to reserve.
|
||||
# In Odoo 11, reservation can still happen, but at least we can't move the same lot twice!
|
||||
#self.assertEqual(rma2.in_picking_id.state, 'confirmed')
|
||||
|
||||
# Requires Lot
|
||||
with self.assertRaises(UserError):
|
||||
rma2.in_picking_id.move_line_ids.write({'qty_done': 1.0})
|
||||
rma2.in_picking_id.button_validate()
|
||||
|
||||
self.assertTrue(rma2.in_picking_id.move_line_ids)
|
||||
self.assertFalse(rma2.in_picking_id.move_line_ids.lot_id.name)
|
||||
|
||||
# Assign existing lot
|
||||
rma2.in_picking_id.move_line_ids.write({
|
||||
'lot_id': lot.id,
|
||||
'qty_done': 1.0,
|
||||
})
|
||||
|
||||
# # Existing lot cannot be re-used.
|
||||
# with self.assertRaises(ValidationError):
|
||||
# rma2.in_picking_id.button_validate()
|
||||
|
||||
# RMA cannot be completed because the inbound picking state is confirmed
|
||||
with self.assertRaises(UserError):
|
||||
rma2.action_done()
|
||||
|
||||
def test_30_product_sale_return_warranty(self):
|
||||
self.template_sale_return.write({
|
||||
'usage': 'sale_order',
|
||||
'invoice_done': True,
|
||||
'sale_order_warranty': True,
|
||||
'in_to_refund': True,
|
||||
'so_decrement_order_qty': True,
|
||||
'next_rma_template_id': self.template_rtv.id,
|
||||
})
|
||||
|
||||
validity = 100 # eligible for 100 days
|
||||
warranty_validity = validity + 100 # eligible for 200 days
|
||||
|
||||
(self.product1 + self.product2).write({
|
||||
'rma_sale_validity': validity,
|
||||
'rma_sale_warranty_validity': warranty_validity,
|
||||
'type': 'product',
|
||||
'invoice_policy': 'order',
|
||||
'tracking': 'serial',
|
||||
'standard_price': 1.5,
|
||||
})
|
||||
|
||||
order = self.env['sale.order'].create({
|
||||
'partner_id': self.partner1.id,
|
||||
'partner_invoice_id': self.partner1.id,
|
||||
'partner_shipping_id': self.partner1.id,
|
||||
'user_id': self.user1.id,
|
||||
'order_line': [
|
||||
(0, 0, {
|
||||
'product_id': self.product1.id,
|
||||
'product_uom_qty': 1.0,
|
||||
'product_uom': self.product1.uom_id.id,
|
||||
'price_unit': 10.0,
|
||||
}),
|
||||
(0, 0, {
|
||||
'product_id': self.product2.id,
|
||||
'product_uom_qty': 1.0,
|
||||
'product_uom': self.product2.uom_id.id,
|
||||
'price_unit': 10.0,
|
||||
}),
|
||||
],
|
||||
})
|
||||
order.action_confirm()
|
||||
self.assertTrue(order.state in ('sale', 'done'))
|
||||
self.assertEqual(len(order.picking_ids), 1, 'Tests only run with single stage delivery.')
|
||||
|
||||
# Try to RMA item not delivered yet
|
||||
rma = self.env['rma.rma'].create({
|
||||
'template_id': self.template_sale_return.id,
|
||||
'partner_id': self.partner1.id,
|
||||
'partner_shipping_id': self.partner1.id,
|
||||
'sale_order_id': order.id,
|
||||
})
|
||||
self.assertEqual(rma.state, 'draft')
|
||||
# Do not allow warranty return.
|
||||
self.product1.rma_sale_warranty_validity = -1
|
||||
wizard = self.env['rma.sale.make.lines'].with_user(self.user1).create({'rma_id': rma.id})
|
||||
self.assertEqual(wizard.line_ids.mapped('qty_delivered'), [0.0, 0.0])
|
||||
wizard.line_ids.write({'product_uom_qty': 1.0})
|
||||
|
||||
with self.assertRaises(UserError):
|
||||
wizard.add_lines()
|
||||
|
||||
# Allows returns, but not forever
|
||||
self.product1.rma_sale_warranty_validity = warranty_validity
|
||||
original_date_order = order.date_order
|
||||
order.write({'date_order': original_date_order - timedelta(days=warranty_validity+1)})
|
||||
wizard = self.env['rma.sale.make.lines'].with_user(self.user1).create({'rma_id': rma.id})
|
||||
self.assertEqual(wizard.line_ids.mapped('qty_delivered'), [0.0, 0.0])
|
||||
wizard.line_ids.write({'product_uom_qty': 1.0})
|
||||
with self.assertRaises(UserError):
|
||||
wizard.add_lines()
|
||||
|
||||
# Allows returns due to date, due to warranty option
|
||||
order.write({'date_order': original_date_order - timedelta(days=validity+1)})
|
||||
wizard = self.env['rma.sale.make.lines'].with_user(self.user1).create({'rma_id': rma.id})
|
||||
self.assertEqual(wizard.line_ids.mapped('qty_delivered'), [0.0, 0.0])
|
||||
wizard.line_ids.write({'product_uom_qty': 1.0})
|
||||
wizard.add_lines()
|
||||
|
||||
# finish outbound so that we can invoice.
|
||||
order.picking_ids.action_assign()
|
||||
lots_created = self.env['stock.production.lot']
|
||||
for stock_move in order.picking_ids.move_lines:
|
||||
move_line = stock_move.move_line_ids
|
||||
if not move_line:
|
||||
stock_move.write({
|
||||
'move_line_ids': [(0, 0, {
|
||||
'picking_id': stock_move.picking_id.id,
|
||||
'move_id': stock_move.id,
|
||||
'location_id': stock_move.location_id.id,
|
||||
'location_dest_id': stock_move.location_dest_id.id,
|
||||
'product_uom_id': stock_move.product_id.uom_id.id,
|
||||
'product_id': stock_move.product_id.id,
|
||||
})]
|
||||
})
|
||||
move_line = stock_move.move_line_ids
|
||||
self.assertTrue(move_line)
|
||||
lot = lots_created.create({
|
||||
'product_id': move_line.product_id.id,
|
||||
'name': 'X100-%s' % (move_line.id, ),
|
||||
'product_uom_id': move_line.product_id.uom_id.id,
|
||||
'company_id': self.env.user.company_id.id,
|
||||
})
|
||||
lots_created += lot
|
||||
move_line.qty_done = 1.0
|
||||
move_line.lot_id = lot
|
||||
|
||||
self.assertIn(order.picking_ids.state, ('assigned', 'confirmed'))
|
||||
order.picking_ids.button_validate()
|
||||
self.assertEqual(order.picking_ids.state, 'done')
|
||||
self.assertEqual(order.order_line.mapped('qty_delivered'), [1.0, 1.0])
|
||||
|
||||
# Invoice the order so that only the core product is invoiced at the end...
|
||||
self.assertFalse(order.invoice_ids)
|
||||
wiz = self.env['sale.advance.payment.inv'].with_context(active_ids=order.ids).create({})
|
||||
wiz.create_invoices()
|
||||
order.flush()
|
||||
self.assertTrue(order.invoice_ids)
|
||||
order_invoice = order.invoice_ids
|
||||
|
||||
self.assertEqual(rma.lines.product_id, (self.product1 + self.product2))
|
||||
rma.action_confirm()
|
||||
self.assertTrue(rma.in_picking_id)
|
||||
self.assertEqual(rma.in_picking_id.state, 'assigned')
|
||||
|
||||
for pack_opt, lot in zip(rma.in_picking_id.move_line_ids, lots_created):
|
||||
pack_opt.qty_done = 1.0
|
||||
pack_opt.lot_id = lot
|
||||
|
||||
rma.in_picking_id.button_validate()
|
||||
self.assertEqual(rma.in_picking_id.state, 'done')
|
||||
order.flush()
|
||||
# self.assertEqual(order.order_line.qty_delivered, 0.0)
|
||||
rma.action_done()
|
||||
self.assertEqual(rma.state, 'done')
|
||||
order.flush()
|
||||
|
||||
rma_invoice = rma.invoice_ids
|
||||
self.assertTrue(rma_invoice)
|
||||
sale_line = rma_invoice.invoice_line_ids.filtered(lambda l: l.sale_line_ids)
|
||||
so_line = sale_line.sale_line_ids
|
||||
self.assertTrue(sale_line)
|
||||
self.assertEqual(sale_line.mapped('price_unit'), so_line.mapped('price_unit'))
|
||||
self.assertEqual(sale_line.mapped('quantity'), [1.0, 1.0])
|
||||
|
||||
# Invoices do not have their anglo-saxon cost lines until they post
|
||||
order_invoice._post(soft=False)
|
||||
rma_invoice._post(soft=False)
|
||||
|
||||
# Find the return to vendor RMA
|
||||
rtv_rma = self.env['rma.rma'].search([('parent_id', '=', rma.id)])
|
||||
self.assertTrue(rtv_rma)
|
||||
self.assertFalse(rtv_rma.out_picking_id)
|
||||
|
||||
wiz = self.env['rma.make.rtv'].with_context(active_model='rma.rma', active_ids=rtv_rma.ids).create({})
|
||||
self.assertTrue(wiz.rma_line_ids)
|
||||
wiz.partner_id = self.partner2
|
||||
wiz.create_batch()
|
||||
self.assertTrue(rtv_rma.out_picking_id)
|
||||
self.assertEqual(rtv_rma.out_picking_id.partner_id, self.partner2)
|
||||
|
||||
def test_40_product_on_multiple_lines(self):
|
||||
self.template_sale_return.write({
|
||||
'usage': 'sale_order',
|
||||
'so_decrement_order_qty': True,
|
||||
'invoice_done': True,
|
||||
})
|
||||
self.assertTrue(self.template_sale_return.in_require_return, "Inbound Require return not set")
|
||||
|
||||
self.product1.write({
|
||||
'type': 'product',
|
||||
'invoice_policy': 'delivery',
|
||||
})
|
||||
order = self.env['sale.order'].create({
|
||||
'partner_id': self.partner1.id,
|
||||
'partner_invoice_id': self.partner1.id,
|
||||
'partner_shipping_id': self.partner1.id,
|
||||
'order_line': [
|
||||
(0, 0, {
|
||||
'product_id': self.product1.id,
|
||||
'product_uom_qty': 3.0,
|
||||
'product_uom': self.product1.uom_id.id,
|
||||
'price_unit': 10.0,
|
||||
}),
|
||||
(0, 0, {
|
||||
'product_id': self.product1.id,
|
||||
'product_uom_qty': 2.0,
|
||||
'product_uom': self.product1.uom_id.id,
|
||||
'price_unit': 13.0,
|
||||
}),
|
||||
]
|
||||
})
|
||||
order.action_confirm()
|
||||
self.assertTrue(order.state in ('sale', 'done'))
|
||||
self.assertEqual(len(order.picking_ids), 1, 'Tests only run with single stage delivery.')
|
||||
|
||||
order.picking_ids.action_assign()
|
||||
out_moves = order.picking_ids.move_ids_without_package
|
||||
out_moves[0].quantity_done = 3.0
|
||||
out_moves[1].quantity_done = 2.0
|
||||
order.picking_ids.button_validate()
|
||||
self.assertEqual(order.picking_ids.state, 'done')
|
||||
|
||||
rma = self.env['rma.rma'].create({
|
||||
'template_id': self.template_sale_return.id,
|
||||
'partner_id': self.partner1.id,
|
||||
'partner_shipping_id': self.partner1.id,
|
||||
'sale_order_id': order.id,
|
||||
})
|
||||
self.assertEqual(rma.state, 'draft')
|
||||
|
||||
wizard = self.env['rma.sale.make.lines'].with_user(self.user1).create({'rma_id': rma.id})
|
||||
self.assertEqual(wizard.line_ids.mapped('qty_delivered'), [3.0, 2.0])
|
||||
# Partially return line 1 to make sure delivered/order qty get decremented properly on second line
|
||||
wizard.line_ids[0].product_uom_qty = 1.0
|
||||
wizard.line_ids[1].product_uom_qty = 2.0
|
||||
wizard.add_lines()
|
||||
|
||||
self.assertEqual(len(rma.lines), 2)
|
||||
rma.action_confirm()
|
||||
|
||||
self.assertEqual(rma.in_picking_id.state, 'assigned')
|
||||
in_moves = rma.in_picking_id.move_ids_without_package
|
||||
in_moves[0].quantity_done = 1
|
||||
in_moves[1].quantity_done = 2
|
||||
rma.in_picking_id.button_validate()
|
||||
self.assertEqual(in_moves.mapped('sale_line_id'), order.order_line, "Inbound stock moves not linked to SO")
|
||||
self.assertEqual(rma.in_picking_id.state, 'done')
|
||||
self.assertEqual(order.order_line.mapped('qty_delivered'), [2.0, 0.0])
|
||||
|
||||
rma.action_done()
|
||||
self.assertEqual(order.order_line.mapped('product_uom_qty'), [2.0, 0.0])
|
||||
self.assertEqual(order.order_line.mapped('qty_delivered'), [2.0, 0.0])
|
||||
|
||||
def test_50_so_line_link_replace(self):
|
||||
# setup the template to do a swap
|
||||
# NOTE that I did not specify require outbound template
|
||||
out_type = self.env['stock.picking.type'].search([('name', '=', 'Delivery Orders')], limit=1)
|
||||
self.assertTrue(out_type)
|
||||
self.assertTrue(out_type.default_location_src_id)
|
||||
self.template_sale_return.write({
|
||||
'usage': 'sale_order',
|
||||
'so_decrement_order_qty': False,
|
||||
'invoice_done': False,
|
||||
'create_out_picking': True,
|
||||
'out_type_id': out_type.id,
|
||||
'out_location_id': out_type.default_location_src_id.id,
|
||||
'out_location_dest_id': self.template_sale_return.in_location_id.id,
|
||||
})
|
||||
|
||||
self.product1.write({
|
||||
'type': 'product',
|
||||
'invoice_policy': 'delivery',
|
||||
})
|
||||
order = self.env['sale.order'].create({
|
||||
'partner_id': self.partner1.id,
|
||||
'partner_invoice_id': self.partner1.id,
|
||||
'partner_shipping_id': self.partner1.id,
|
||||
'order_line': [
|
||||
(0, 0, {
|
||||
'product_id': self.product1.id,
|
||||
'product_uom_qty': 3.0,
|
||||
'product_uom': self.product1.uom_id.id,
|
||||
'price_unit': 10.0,
|
||||
}),
|
||||
]
|
||||
})
|
||||
order.action_confirm()
|
||||
self.assertTrue(order.state in ('sale', 'done'))
|
||||
self.assertEqual(len(order.picking_ids), 1, 'Tests only run with single stage delivery.')
|
||||
|
||||
order.picking_ids.action_assign()
|
||||
out_moves = order.picking_ids.move_ids_without_package
|
||||
self.assertEqual(len(out_moves), 1)
|
||||
out_moves.quantity_done = 3.0
|
||||
order.picking_ids.button_validate()
|
||||
self.assertEqual(order.picking_ids.state, 'done')
|
||||
|
||||
rma = self.env['rma.rma'].create({
|
||||
'template_id': self.template_sale_return.id,
|
||||
'partner_id': self.partner1.id,
|
||||
'partner_shipping_id': self.partner1.id,
|
||||
'sale_order_id': order.id,
|
||||
})
|
||||
self.assertEqual(rma.state, 'draft')
|
||||
|
||||
wizard = self.env['rma.sale.make.lines'].with_user(self.user1).create({'rma_id': rma.id})
|
||||
wizard.line_ids.product_uom_qty = 1.0
|
||||
wizard.add_lines()
|
||||
|
||||
self.assertEqual(len(rma.lines), 1)
|
||||
rma.action_confirm()
|
||||
|
||||
self.assertEqual(rma.in_picking_id.state, 'assigned')
|
||||
in_moves = rma.in_picking_id.move_ids_without_package
|
||||
in_moves.quantity_done = 1
|
||||
rma.in_picking_id.button_validate()
|
||||
self.assertEqual(in_moves.sale_line_id, order.order_line, "Inbound stock moves not linked to SO")
|
||||
self.assertEqual(rma.in_picking_id.state, 'done')
|
||||
self.assertEqual(order.order_line.mapped('qty_delivered'), [2.0, ])
|
||||
|
||||
self.assertIn(rma.out_picking_id.state, ('assigned', 'confirmed'))
|
||||
out_moves = rma.out_picking_id.move_ids_without_package
|
||||
out_moves.quantity_done = 1
|
||||
rma.out_picking_id.button_validate()
|
||||
self.assertEqual(order.order_line.mapped('qty_delivered'), [3.0, ])
|
||||
|
||||
rma.action_done()
|
||||
self.assertEqual(order.order_line.mapped('product_uom_qty'), [3.0, ])
|
||||
self.assertEqual(order.order_line.mapped('qty_delivered'), [3.0, ])
|
||||
@@ -1,114 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<template id="portal_my_rma_inherit" inherit_id="rma.portal_my_rma">
|
||||
<xpath expr="//th[hasclass('rma-state')]" position="before">
|
||||
<th class="rma-sale">
|
||||
<t t-if="groupby == 'sale'">
|
||||
<em class="font-weight-normal text-muted">RMAs for sale:</em>
|
||||
<span t-field="rmas[0].sale_order_id"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span>Sale Order</span>
|
||||
</t>
|
||||
</th>
|
||||
</xpath>
|
||||
<xpath expr="//td[hasclass('rma-state')]" position="before">
|
||||
<td class="rma-sale">
|
||||
<span t-if="groupby != 'sale'" t-field="rma.sale_order_id"/>
|
||||
</td>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="portal_my_rma_rma_inherit" inherit_id="rma.portal_my_rma_rma">
|
||||
<xpath expr="//div[hasclass('rma-details')]" position="inside">
|
||||
<div t-if="rma.sale_order_id" class="mb8">
|
||||
<strong>Sale Order:</strong>
|
||||
<span t-esc="rma.sale_order_id.name"/>
|
||||
</div>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<!-- New -->
|
||||
<template id="portal_new_sale_order" name="New Sale Order RMA">
|
||||
<t t-call="portal.portal_layout">
|
||||
<div id="optional_placeholder"></div>
|
||||
<div class="container">
|
||||
<t t-call="rma.portal_rma_error"/>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<h4>
|
||||
<span t-esc="rma_template.name"/>
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul t-if="rma_sale_orders" class="list-group">
|
||||
<li class="list-group-item" t-foreach="rma_sale_orders" t-as="s">
|
||||
<a t-attf-href="/my/rma/new/#{rma_template.id}/res/#{s.id}">
|
||||
<span t-esc="s.name"/> - Order Date: <span t-field="s.date_order"/>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<p t-if="not rma_sale_orders and not rma_sale_order">No Sale Orders to choose from.</p>
|
||||
<form t-if="rma_sale_order" method="post" t-attf-action="/my/rma/new/#{rma_template.id}/res/#{rma_sale_order.id}">
|
||||
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
<strong>Product</strong>
|
||||
</div>
|
||||
<div class="col-lg-3">
|
||||
<strong>Description</strong>
|
||||
</div>
|
||||
<div class="col-lg-2 text-right">
|
||||
<strong>Qty. Ordered</strong>
|
||||
</div>
|
||||
<div class="col-lg-2 text-right">
|
||||
<strong>Qty. Delivered</strong>
|
||||
</div>
|
||||
<div class="col-lg-1 text-right">
|
||||
<strong>Qty. to Return</strong>
|
||||
</div>
|
||||
</div>
|
||||
<t t-foreach="rma_sale_order.order_line" t-as="line">
|
||||
<t t-set="validity" t-value="rma_template._rma_sale_line_validity(line)"/>
|
||||
<div class="row" t-attf-class="row #{'' if validity == 'valid' else 'text-muted'}">
|
||||
<div class="col-lg-1 text-center">
|
||||
<img class="mr4 float-left o_portal_product_img" t-if="line.product_id.image_128" t-att-src="image_data_uri(line.product_id.image_128)" alt="Product Image" width="64"/>
|
||||
<img class="mr4 float-left o_portal_product_img" t-if="not line.product_id.image_128" src="/web/static/src/img/placeholder.png" alt="Product Image" width="64"/>
|
||||
</div>
|
||||
<div class="col-lg-3">
|
||||
<span t-esc="line.product_id.name"/>
|
||||
</div>
|
||||
<div class="col-lg-3">
|
||||
<span t-esc="line.name"/>
|
||||
</div>
|
||||
<div class="col-lg-2 text-right">
|
||||
<span t-esc="line.product_uom_qty"/>
|
||||
</div>
|
||||
<div class="col-lg-2 text-right">
|
||||
<span t-esc="line.qty_delivered"/>
|
||||
</div>
|
||||
<div class="col-lg-1 text-right" t-if="validity == 'valid'">
|
||||
<input type="text" t-attf-name="line_#{line.id}" class="form-control"/>
|
||||
</div>
|
||||
<div class="col-lg-1 text-left" t-else="">
|
||||
<span t-if="validity == 'expired'">Expired</span>
|
||||
<span t-else="">Not Eligible</span>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<input type="submit" class="btn btn-primary mt16 float-right" name="submit"/>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oe_structure mb32"/>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
|
||||
</odoo>
|
||||
@@ -1,32 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
|
||||
<record id="product_template_only_form_view_inherit" model="ir.ui.view">
|
||||
<field name="name">product.template.product.form.inherit</field>
|
||||
<field name="model">product.template</field>
|
||||
<field name="inherit_id" ref="product.product_template_only_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//page[@name='sales']/group[@name='sale']" position="inside">
|
||||
<group name="rma_sale" string="RMA Sales">
|
||||
<field name="rma_sale_validity" string="Eligible Days"/>
|
||||
<field name="rma_sale_warranty_validity" string="Warranty Eligible Days"/>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="product_normal_form_view_inherit" model="ir.ui.view">
|
||||
<field name="name">product.product.form.inherit</field>
|
||||
<field name="model">product.product</field>
|
||||
<field name="inherit_id" ref="product.product_normal_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//page[@name='sales']/group[@name='sale']" position="inside">
|
||||
<group name="rma_sale" string="RMA Sales">
|
||||
<field name="rma_sale_validity" string="Eligible Days"/>
|
||||
<field name="rma_sale_warranty_validity" string="Warranty Eligible Days"/>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -1,83 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<!-- RMA Template -->
|
||||
<record id="view_rma_template_form_sale" model="ir.ui.view">
|
||||
<field name="name">rma.template.form.sale</field>
|
||||
<field name="model">rma.template</field>
|
||||
<field name="inherit_id" ref="rma.view_rma_template_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='usage']" position="after">
|
||||
<field name="so_decrement_order_qty" string="Decrement Ordered Qty" attrs="{'invisible': [('usage', '!=', 'sale_order')]}"/>
|
||||
<field name="sale_order_warranty" string="Warranty" attrs="{'invisible': [('usage', '!=', 'sale_order')]}"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- RMA -->
|
||||
<record id="view_rma_rma_form_sale" model="ir.ui.view">
|
||||
<field name="name">rma.rma.form.sale</field>
|
||||
<field name="model">rma.rma</field>
|
||||
<field name="inherit_id" ref="rma.view_rma_rma_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//div[@name='button_box']" position="inside">
|
||||
<button class="oe_stat_button" name="open_sale_order_rmas" icon="fa-cubes"
|
||||
type="object" attrs="{'invisible': ['|', ('sale_order_id', '=', False), ('sale_order_rma_count', '<=', 1)]}">
|
||||
<field name="sale_order_rma_count" string="SO RMAs" widget="statinfo" />
|
||||
</button>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='template_id']" position="after">
|
||||
<field name="sale_order_id" options="{'no_create': True}" attrs="{'invisible': [('template_usage', '!=', 'sale_order')], 'required': [('template_usage', '=', 'sale_order')], 'readonly': [('state', 'in', ('confirmed', 'done', 'cancel'))]}"/>
|
||||
<br/>
|
||||
<button string="Add lines" type="object" name="action_add_so_lines" attrs="{'invisible': ['|', ('sale_order_id', '=', False), ('state', '!=', 'draft')]}"/>
|
||||
</xpath>
|
||||
<xpath expr="//page/field[@name='lines']/tree/field[@name='product_uom_qty']" position="before">
|
||||
<field name="sale_line_product_uom_qty" attrs="{'column_invisible': [('parent.sale_order_id', '=', False)]}"/>
|
||||
<field name="sale_line_qty_delivered" attrs="{'column_invisible': [('parent.sale_order_id', '=', False)]}"/>
|
||||
<field name="sale_line_qty_invoiced" attrs="{'column_invisible': [('parent.sale_order_id', '=', False)]}"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_rma_rma_tree_sale" model="ir.ui.view">
|
||||
<field name="name">rma.rma.tree.sale</field>
|
||||
<field name="model">rma.rma</field>
|
||||
<field name="inherit_id" ref="rma.view_rma_rma_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='template_id']" position="after">
|
||||
<field name="sale_order_id"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_rma_rma_search_sale" model="ir.ui.view">
|
||||
<field name="name">rma.rma.tree.sale</field>
|
||||
<field name="model">rma.rma</field>
|
||||
<field name="inherit_id" ref="rma.view_rma_rma_search"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='template_id']" position="after">
|
||||
<field name="sale_order_id"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
action="rma.action_rma_rma"
|
||||
id="menu_action_sales_rma_form"
|
||||
parent="sale.sale_order_menu"
|
||||
sequence="12"
|
||||
/>
|
||||
|
||||
<menuitem
|
||||
action="rma.action_rma_template_form"
|
||||
id="menu_action_sales_rma_template_form"
|
||||
parent="sale.menu_sale_config"
|
||||
sequence="12"
|
||||
/>
|
||||
<menuitem
|
||||
action="rma.action_rma_tag_form"
|
||||
id="menu_action_sales_rma_tag_form"
|
||||
parent="sale.menu_sale_config"
|
||||
sequence="12"
|
||||
/>
|
||||
</odoo>
|
||||
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<record id="view_order_form_inherit" model="ir.ui.view">
|
||||
<field name="name">sale.order.form.inherit</field>
|
||||
<field name="model">sale.order</field>
|
||||
<field name="inherit_id" ref="sale.view_order_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//div[@name='button_box']" position="inside">
|
||||
<button name="%(rma.action_rma_rma)d" type="action" class="oe_stat_button" icon="fa-cubes"
|
||||
attrs="{'invisible': [('rma_count', '=', 0), ('state', 'not in', ('sale', 'done', 'cancel'))]}"
|
||||
context="{'search_default_sale_order_id': active_id, 'default_sale_order_id': active_id}">
|
||||
<div class="o_field_widget o_stat_info">
|
||||
<span class="o_stat_value"><field name="rma_count"/></span> RMA
|
||||
</div>
|
||||
</button>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -1,3 +0,0 @@
|
||||
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
|
||||
|
||||
from . import rma_lines
|
||||
@@ -1,76 +0,0 @@
|
||||
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class RMASaleMakeLines(models.TransientModel):
|
||||
_name = 'rma.sale.make.lines'
|
||||
_description = 'Add SO Lines'
|
||||
|
||||
rma_id = fields.Many2one('rma.rma', string='RMA')
|
||||
line_ids = fields.One2many('rma.sale.make.lines.line', 'rma_make_lines_id', string='Lines')
|
||||
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
maker = super(RMASaleMakeLines, self).create(vals)
|
||||
maker._create_lines()
|
||||
return maker
|
||||
|
||||
def _line_values(self, so_line):
|
||||
return {
|
||||
'rma_make_lines_id': self.id,
|
||||
'sale_line_id': so_line.id,
|
||||
'product_id': so_line.product_id.id,
|
||||
'qty_ordered': so_line.product_uom_qty,
|
||||
'qty_delivered': so_line.qty_delivered,
|
||||
'qty_invoiced': so_line.qty_invoiced,
|
||||
'product_uom_qty': 0.0,
|
||||
'product_uom_id': so_line.product_uom.id,
|
||||
'validity': self.rma_id.template_id._rma_sale_line_validity(so_line),
|
||||
}
|
||||
|
||||
def _create_lines(self):
|
||||
make_lines_obj = self.env['rma.sale.make.lines.line']
|
||||
|
||||
if self.rma_id.template_usage == 'sale_order' and self.rma_id.sale_order_id:
|
||||
for l in self.rma_id.sale_order_id.order_line:
|
||||
self.line_ids |= make_lines_obj.create(self._line_values(l))
|
||||
|
||||
def add_lines(self):
|
||||
rma_line_obj = self.env['rma.line']
|
||||
for o in self:
|
||||
lines = o.line_ids.filtered(lambda l: l.product_uom_qty > 0.0)
|
||||
if not self.env.user.has_group('sales_team.group_sale_manager'):
|
||||
if lines.filtered(lambda l: not l.validity):
|
||||
raise UserError('One or more items are not eligible for return.')
|
||||
if lines.filtered(lambda l: l.validity == 'expired'):
|
||||
raise UserError('One or more items are past their return period.')
|
||||
for l in lines:
|
||||
rma_line_obj.create({
|
||||
'rma_id': o.rma_id.id,
|
||||
'sale_line_id': l.sale_line_id.id,
|
||||
'product_id': l.product_id.id,
|
||||
'product_uom_id': l.product_uom_id.id,
|
||||
'product_uom_qty': l.product_uom_qty,
|
||||
})
|
||||
|
||||
|
||||
class RMASOMakeLinesLine(models.TransientModel):
|
||||
_name = 'rma.sale.make.lines.line'
|
||||
_description = 'RMA Sale Make Lines Line'
|
||||
|
||||
rma_make_lines_id = fields.Many2one('rma.sale.make.lines')
|
||||
sale_line_id = fields.Many2one('sale.order.line', string="Sale Order Line")
|
||||
product_id = fields.Many2one('product.product', string="Product")
|
||||
qty_ordered = fields.Float(string='Ordered')
|
||||
qty_invoiced = fields.Float(string='Invoiced')
|
||||
qty_delivered = fields.Float(string='Delivered')
|
||||
product_uom_qty = fields.Float(string='QTY')
|
||||
product_uom_id = fields.Many2one('uom.uom', 'UOM')
|
||||
validity = fields.Selection([
|
||||
('', 'Not Eligible'),
|
||||
('valid', 'Eligible'),
|
||||
('expired', 'Expired'),
|
||||
], string='Validity')
|
||||
@@ -1,39 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<record id="view_rma_add_lines_form" model="ir.ui.view">
|
||||
<field name="name">view.rma.add.lines.form</field>
|
||||
<field name="model">rma.sale.make.lines</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<field name="line_ids">
|
||||
<tree editable="top" create="false" delete="false" decoration-muted="validity != 'valid'">
|
||||
<field name="product_id" readonly="1"/>
|
||||
<field name="qty_ordered" readonly="1"/>
|
||||
<field name="qty_delivered" readonly="1"/>
|
||||
<field name="qty_invoiced" readonly="1"/>
|
||||
<field name="product_uom_qty"/>
|
||||
<field name="product_uom_id" readonly="1"/>
|
||||
<field name="validity" readonly="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
<footer>
|
||||
<button class="oe_highlight"
|
||||
name="add_lines"
|
||||
type="object"
|
||||
string="Add" />
|
||||
<button class="oe_link"
|
||||
special="cancel"
|
||||
string="Cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="action_rma_add_lines" model="ir.actions.act_window">
|
||||
<field name="name">Add RMA Lines</field>
|
||||
<field name="res_model">rma.sale.make.lines</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="view_rma_add_lines_form" />
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user